NoahJosephHall icon

s2.asm

NoahJosephHall | PRO | 02/13/17 12:01:39 PM UTC | 0 ⭐ | 596 👁️ | Never ⏰ | []
M68000 Assembler |

0 B

|

None

|

0 👍

/

0 👎

; Sonic the Hedgehog 2 disassembled binary
 
; Nemesis,   2004: Created original disassembly for SNASM68K
; Aurochs,   2005: Translated to AS and annotated
; Xenowhirl, 2007: More annotation, overall cleanup, Z80 disassembly
; ---------------------------------------------------------------------------
; NOTES:
;
; Set your editor's tab width to 8 characters wide for viewing this file.
;
; It is highly suggested that you read the AS User's Manual before diving too
; far into this disassembly. At least read the section on nameless temporary
; symbols. Your brain may melt if you don't know how those work.
;
; See s2.notes.txt for more comments about this disassembly and other useful info.
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; ASSEMBLY OPTIONS:
;
padToPowerOfTwo = 1
;   | If 1, pads the end of the ROM to the next power of two bytes (for real hardware)
;
allOptimizations = 0
;   | If 1, enables all optimizations
;
skipChecksumCheck = 0|allOptimizations
;   | If 1, disables the unnecessary (and slow) bootup checksum calculation
;
zeroOffsetOptimization = 0|allOptimizations
;   | If 1, makes a handful of zero-offset instructions smaller
;
removeJmpTos = 0|allOptimizations
;   | If 1, many unnecessary JmpTos are removed, improving performance
;
addsubOptimize = 0|allOptimizations
;   | If 1, some add/sub instructions are optimized to addq/subq
;
relativeLea = 1|allOptimizations
;   | If 1, makes some instructions use pc-relative addressing, instead of absolute long
;
useFullWaterTables = 0
;   | If 1, zone offset tables for water levels cover all level slots instead of only slots 8-$F
;   | Set to 1 if you've shifted level IDs around or you want water in levels with a level slot below 8
gameRevision = 1
;   | If 0, a REV00 ROM is built
;   | If 1, a REV01 ROM is built, which contains some fixes
;   | If 2, a (probable) REV02 ROM is built, which contains more fixes
;   | (Bit-perfect REV02 requires removeJmpTos & addsubOptimize be set to 1,
;   | and also requires relativeLea to be 0)
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; AS-specific macros and assembler settings
    CPU 68000
    include "s2.macrosetup.asm"
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equates section - Names for variables.
    include "s2.constants.asm"
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; simplifying macros and functions
    include "s2.macros.asm"
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; start of ROM
 
StartOfRom:
    if * <> 0
    fatal "StartOfRom was $\{*} but it should be 0"
    endif
;Vectors:
    dc.l System_Stack, EntryPoint, ErrorTrap, ErrorTrap; 4
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 8
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 12
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 16
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 20
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 24
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 28
    dc.l H_Int,     ErrorTrap, V_Int,     ErrorTrap; 32
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 36
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 40
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 44
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 48
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 52
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 56
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 60
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap; 64
; byte_100:
Header:
    dc.b "SEGA GENESIS    " ; Console name
    dc.b "(C)SEGA 1992.SEP" ; Copyright/Date
    dc.b "SONIC THE             HEDGEHOG 2                " ; Domestic name
    dc.b "SONIC THE             HEDGEHOG 2                " ; International name
    if gameRevision=0
    dc.b "GM 00001051-00"   ; Version (REV00)
    elseif gameRevision=1
    dc.b "GM 00001051-01"   ; Version (REV01)
    else;if gameRevision=2
    dc.b "GM 00001051-02"   ; Version (REV02)
    endif
; word_18E
Checksum:
    dc.w $D951      ; Checksum (patched later if incorrect)
    dc.b "J               " ; I/O Support
    dc.l StartOfRom     ; ROM Start
; dword_1A4
ROMEndLoc:
    dc.l EndOfRom-1     ; ROM End
    dc.l RAM_Start&$FFFFFF      ; RAM Start
    dc.l (RAM_End-1)&$FFFFFF        ; RAM End
    dc.b "    "     ; Backup RAM ID
    dc.l $20202020      ; Backup RAM start address
    dc.l $20202020      ; Backup RAM end address
    dc.b "            " ; Modem support
    dc.b "                                        " ; Notes
    dc.b "JUE             " ; Country
EndOfHeader:
 
; ===========================================================================
; Crash/Freeze the 68000. Note that the Z80 continues to run, so the music keeps playing.
; loc_200:
ErrorTrap:
    nop
    nop
    bra.s   ErrorTrap
 
; ===========================================================================
; loc_206:
EntryPoint:
    tst.l   (HW_Port_1_Control-1).l ; test ports A and B control
    bne.s   PortA_Ok
    tst.w   (HW_Expansion_Control-1).l  ; test port C control
; loc_214:
PortA_Ok:
    bne.s   PortC_OK ; skip the VDP and Z80 setup code if port A, B or C is ok...?
    lea SetupValues(pc),a5
    movem.w (a5)+,d5-d7
    movem.l (a5)+,a0-a4
    move.b  HW_Version-Z80_Bus_Request(a1),d0   ; get hardware version
    andi.b  #$F,d0
    beq.s   SkipSecurity ; branch if hardware is older than Genesis III
    move.l  #'SEGA',Security_Addr-Z80_Bus_Request(a1) ; satisfy the TMSS
; loc_234:
SkipSecurity:
    move.w  (a4),d0 ; check if VDP works
    moveq   #0,d0
    movea.l d0,a6
    move.l  a6,usp  ; set usp to $0
    moveq   #VDPInitValues_End-VDPInitValues-1,d1 ; run the following loop $18 times
; loc_23E:
VDPInitLoop:
    move.b  (a5)+,d5    ; add $8000 to value
    move.w  d5,(a4) ; move value to VDP register
    add.w   d7,d5   ; next register
    dbf d1,VDPInitLoop
 
    move.l  (a5)+,(a4)  ; set VRAM write mode
    move.w  d0,(a3) ; clear the screen
    move.w  d7,(a1) ; stop the Z80
    move.w  d7,(a2) ; reset the Z80
; loc_250:
WaitForZ80:
    btst    d0,(a1) ; has the Z80 stopped?
    bne.s   WaitForZ80  ; if not, branch
    moveq   #Z80StartupCodeEnd-Z80StartupCodeBegin-1,d2
; loc_256:
Z80InitLoop:
    move.b  (a5)+,(a0)+
    dbf d2,Z80InitLoop
 
    move.w  d0,(a2)
    move.w  d0,(a1) ; start the Z80
    move.w  d7,(a2) ; reset the Z80
; loc_262:
ClrRAMLoop:
    move.l  d0,-(a6)
    dbf d6,ClrRAMLoop   ; clear the entire RAM
    move.l  (a5)+,(a4)  ; set VDP display mode and increment
    move.l  (a5)+,(a4)  ; set VDP to CRAM write
    moveq   #bytesToLcnt($80),d3
; loc_26E:
ClrCRAMLoop:
    move.l  d0,(a3)
    dbf d3,ClrCRAMLoop  ; clear the CRAM
    move.l  (a5)+,(a4)
    moveq   #bytesToLcnt($50),d4
; loc_278: ClrVDPStuff:
ClrVSRAMLoop:
    move.l  d0,(a3)
    dbf d4,ClrVSRAMLoop
    moveq   #PSGInitValues_End-PSGInitValues-1,d5
; loc_280:
PSGInitLoop:
    move.b  (a5)+,PSG_input-VDP_data_port(a3) ; reset the PSG
    dbf d5,PSGInitLoop
    move.w  d0,(a2)
    movem.l (a6),d0-a6  ; clear all registers
    move    #$2700,sr   ; set the sr
 ; loc_292:
PortC_OK: ;;
    bra.s   GameProgram
; ===========================================================================
; byte_294:
SetupValues:
    dc.w    $8000,bytesToLcnt($10000),$100
 
    dc.l    Z80_RAM
    dc.l    Z80_Bus_Request
    dc.l    Z80_Reset
    dc.l    VDP_data_port, VDP_control_port
 
VDPInitValues:  ; values for VDP registers
    dc.b 4          ; Command $8004 - HInt off, Enable HV counter read
    dc.b $14        ; Command $8114 - Display off, VInt off, DMA on, PAL off
    dc.b $30        ; Command $8230 - Scroll A Address $C000
    dc.b $3C        ; Command $833C - Window Address $F000
    dc.b 7          ; Command $8407 - Scroll B Address $E000
    dc.b $6C        ; Command $856C - Sprite Table Address $D800
    dc.b 0          ; Command $8600 - Null
    dc.b 0          ; Command $8700 - Background color Pal 0 Color 0
    dc.b 0          ; Command $8800 - Null
    dc.b 0          ; Command $8900 - Null
    dc.b $FF        ; Command $8AFF - Hint timing $FF scanlines
    dc.b 0          ; Command $8B00 - Ext Int off, VScroll full, HScroll full
    dc.b $81        ; Command $8C81 - 40 cell mode, shadow/highlight off, no interlace
    dc.b $37        ; Command $8D37 - HScroll Table Address $DC00
    dc.b 0          ; Command $8E00 - Null
    dc.b 1          ; Command $8F01 - VDP auto increment 1 byte
    dc.b 1          ; Command $9001 - 64x32 cell scroll size
    dc.b 0          ; Command $9100 - Window H left side, Base Point 0
    dc.b 0          ; Command $9200 - Window V upside, Base Point 0
    dc.b $FF        ; Command $93FF - DMA Length Counter $FFFF
    dc.b $FF        ; Command $94FF - See above
    dc.b 0          ; Command $9500 - DMA Source Address $0
    dc.b 0          ; Command $9600 - See above
    dc.b $80        ; Command $9780 - See above + VRAM fill mode
VDPInitValues_End:
 
    dc.l    vdpComm($0000,VRAM,DMA) ; value for VRAM write mode
 
    ; Z80 instructions (not the sound driver; that gets loaded later)
Z80StartupCodeBegin: ; loc_2CA:
    if (*)+$26 < $10000
    save
    CPU Z80 ; start assembling Z80 code
    phase 0 ; pretend we're at address 0
    xor a   ; clear a to 0
    ld  bc,((Z80_RAM_End-Z80_RAM)-zStartupCodeEndLoc)-1 ; prepare to loop this many times
    ld  de,zStartupCodeEndLoc+1 ; initial destination address
    ld  hl,zStartupCodeEndLoc   ; initial source address
    ld  sp,hl   ; set the address the stack starts at
    ld  (hl),a  ; set first byte of the stack to 0
    ldir        ; loop to fill the stack (entire remaining available Z80 RAM) with 0
    pop ix  ; clear ix
    pop iy  ; clear iy
    ld  i,a ; clear i
    ld  r,a ; clear r
    pop de  ; clear de
    pop hl  ; clear hl
    pop af  ; clear af
    ex  af,af'  ; swap af with af'
    exx     ; swap bc/de/hl with their shadow registers too
    pop bc  ; clear bc
    pop de  ; clear de
    pop hl  ; clear hl
    pop af  ; clear af
    ld  sp,hl   ; clear sp
    di      ; clear iff1 (for interrupt handler)
    im  1   ; interrupt handling mode = 1
    ld  (hl),0E9h ; replace the first instruction with a jump to itself
    jp  (hl)      ; jump to the first instruction (to stay there forever)
zStartupCodeEndLoc:
    dephase ; stop pretending
    restore
    padding off ; unfortunately our flags got reset so we have to set them again...
    else ; due to an address range limitation I could work around but don't think is worth doing so:
    message "Warning: using pre-assembled Z80 startup code."
    dc.w $AF01,$D91F,$1127,$0021,$2600,$F977,$EDB0,$DDE1,$FDE1,$ED47,$ED4F,$D1E1,$F108,$D9C1,$D1E1,$F1F9,$F3ED,$5636,$E9E9
    endif
Z80StartupCodeEnd:
 
    dc.w    $8104   ; value for VDP display mode
    dc.w    $8F02   ; value for VDP increment
    dc.l    vdpComm($0000,CRAM,WRITE)   ; value for CRAM write mode
    dc.l    vdpComm($0000,VSRAM,WRITE)  ; value for VSRAM write mode
 
PSGInitValues:
    dc.b    $9F,$BF,$DF,$FF ; values for PSG channel volumes
PSGInitValues_End:
; ===========================================================================
 
    even
; loc_300:
GameProgram:
    tst.w   (VDP_control_port).l
; loc_306:
CheckSumCheck:
    if gameRevision>0
    move.w  (VDP_control_port).l,d1
    btst    #1,d1
    bne.s   CheckSumCheck   ; wait until DMA is completed
    endif
    btst    #6,(HW_Expansion_Control).l
    beq.s   ChecksumTest
    cmpi.l  #'init',(Checksum_fourcc).w ; has checksum routine already run?
    beq.w   GameInit
 
; loc_328:
ChecksumTest:
    if skipChecksumCheck=0  ; checksum code
    movea.l #EndOfHeader,a0 ; start checking bytes after the header ($200)
    movea.l #ROMEndLoc,a1   ; stop at end of ROM
    move.l  (a1),d0
    moveq   #0,d1
; loc_338:
ChecksumLoop:
    add.w   (a0)+,d1
    cmp.l   a0,d0
    bhs.s   ChecksumLoop
    movea.l #Checksum,a1    ; read the checksum
    cmp.w   (a1),d1 ; compare correct checksum to the one in ROM
    bne.w   ChecksumError   ; if they don't match, branch
    endif
;checksum_good:
    lea (System_Stack).w,a6
    moveq   #0,d7
 
    move.w  #bytesToLcnt($200),d6
-   move.l  d7,(a6)+
    dbf d6,-
 
    move.b  (HW_Version).l,d0
    andi.b  #$C0,d0
    move.b  d0,(Graphics_Flags).w
    move.l  #'init',(Checksum_fourcc).w ; set flag so checksum won't be run again
; loc_370:
GameInit:
    lea (RAM_Start&$FFFFFF).l,a6
    moveq   #0,d7
    move.w  #bytesToLcnt(System_Stack&$FFFF),d6
; loc_37C:
GameClrRAM:
    move.l  d7,(a6)+
    dbf d6,GameClrRAM
 
    bsr.w   VDPSetupGame
    bsr.w   JmpTo_SoundDriverLoad
    bsr.w   JoypadInit
    move.b  #GameModeID_SegaScreen,(Game_Mode).w    ; => SegaScreen
; loc_394:
MainGameLoop:
    move.b  (Game_Mode).w,d0
    andi.w  #$3C,d0
    jsr GameModesArray(pc,d0.w)
    bra.s   MainGameLoop
; ===========================================================================
; loc_3A2:
GameModesArray: ;;
GameMode_SegaScreen:    bra.w   SegaScreen      ; SEGA screen mode
GameMode_TitleScreen:   bra.w   TitleScreen     ; Title screen mode
GameMode_Demo:      bra.w   Level           ; Demo mode
GameMode_Level:     bra.w   Level           ; Zone play mode
GameMode_SpecialStage:  bra.w   SpecialStage        ; Special stage play mode
GameMode_ContinueScreen:bra.w   ContinueScreen      ; Continue mode
GameMode_2PResults: bra.w   TwoPlayerResults    ; 2P results mode
GameMode_2PLevelSelect: bra.w   LevelSelectMenu2P   ; 2P level select mode
GameMode_EndingSequence:bra.w   JmpTo_EndingSequence    ; End sequence mode
GameMode_OptionsMenu:   bra.w   OptionsMenu     ; Options mode
GameMode_LevelSelect:   bra.w   LevelSelectMenu     ; Level select mode
; ===========================================================================
    if skipChecksumCheck=0  ; checksum error code
; loc_3CE:
ChecksumError:
    move.l  d1,-(sp)
    bsr.w   VDPSetupGame
    move.l  (sp)+,d1
    move.l  #vdpComm($0000,CRAM,WRITE),(VDP_control_port).l
    moveq   #$3F,d7
; loc_3E2:
Checksum_Red:
    move.w  #$E,(VDP_data_port).l
    dbf d7,Checksum_Red
; loc_3EE:
ChecksumFailed_Loop:
    bra.s   ChecksumFailed_Loop
    endif
; ===========================================================================
; loc_3F0:
LevelSelectMenu2P: ;;
    jmp (MenuScreen).l
; ===========================================================================
; loc_3F6:
JmpTo_EndingSequence 
    jmp (EndingSequence).l
; ===========================================================================
; loc_3FC:
OptionsMenu: ;;
    jmp (MenuScreen).l
; ===========================================================================
; loc_402:
LevelSelectMenu: ;;
    jmp (MenuScreen).l
; ===========================================================================
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; vertical and horizontal interrupt handlers
; VERTICAL INTERRUPT HANDLER:
V_Int:
    movem.l d0-a6,-(sp)
    tst.b   (Vint_routine).w
    beq.w   Vint_Lag
 
-   move.w  (VDP_control_port).l,d0
    andi.w  #8,d0
    beq.s   -
 
    move.l  #vdpComm($0000,VSRAM,WRITE),(VDP_control_port).l
    move.l  (Vscroll_Factor).w,(VDP_data_port).l
    btst    #6,(Graphics_Flags).w
    beq.s   +
 
    move.w  #$700,d0
-   dbf d0,- ; wait here in a loop doing nothing for a while...
+
    move.b  (Vint_routine).w,d0
    move.b  #VintID_Lag,(Vint_routine).w
    move.w  #1,(Hint_flag).w
    andi.w  #$3E,d0
    move.w  Vint_SwitchTbl(pc,d0.w),d0
    jsr Vint_SwitchTbl(pc,d0.w)
 
VintRet:
    addq.l  #1,(Vint_runcount).w
    movem.l (sp)+,d0-a6
    rte
; ===========================================================================
Vint_SwitchTbl: offsetTable
Vint_Lag_ptr        offsetTableEntry.w Vint_Lag         ;   0
Vint_SEGA_ptr:      offsetTableEntry.w Vint_SEGA        ;   2
Vint_Title_ptr:     offsetTableEntry.w Vint_Title       ;   4
Vint_Unused6_ptr:   offsetTableEntry.w Vint_Unused6     ;   6
Vint_Level_ptr:     offsetTableEntry.w Vint_Level       ;   8
Vint_S2SS_ptr:      offsetTableEntry.w Vint_S2SS        ;  $A
Vint_TitleCard_ptr: offsetTableEntry.w Vint_TitleCard   ;  $C
Vint_UnusedE_ptr:   offsetTableEntry.w Vint_UnusedE     ;  $E
Vint_Pause_ptr:     offsetTableEntry.w Vint_Pause       ; $10
Vint_Fade_ptr:      offsetTableEntry.w Vint_Fade        ; $12
Vint_PCM_ptr:       offsetTableEntry.w Vint_PCM         ; $14
Vint_Menu_ptr:      offsetTableEntry.w Vint_Menu        ; $16
Vint_Ending_ptr:    offsetTableEntry.w Vint_Ending      ; $18
Vint_CtrlDMA_ptr:   offsetTableEntry.w Vint_CtrlDMA     ; $1A
; ===========================================================================
;VintSub0
Vint_Lag:
    cmpi.b  #GameModeID_TitleCard|GameModeID_Demo,(Game_Mode).w ; pre-level Demo Mode?
    beq.s   loc_4C4
    cmpi.b  #GameModeID_TitleCard|GameModeID_Level,(Game_Mode).w    ; pre-level Zone play mode?
    beq.s   loc_4C4
    cmpi.b  #GameModeID_Demo,(Game_Mode).w  ; Demo Mode?
    beq.s   loc_4C4
    cmpi.b  #GameModeID_Level,(Game_Mode).w ; Zone play mode?
    beq.s   loc_4C4
 
    stopZ80         ; stop the Z80
    bsr.w   sndDriverInput  ; give input to the sound driver
    startZ80        ; start the Z80
 
    bra.s   VintRet
; ---------------------------------------------------------------------------
 
loc_4C4:
    tst.b   (Water_flag).w
    beq.w   Vint0_noWater
    move.w  (VDP_control_port).l,d0
    btst    #6,(Graphics_Flags).w
    beq.s   +
 
    move.w  #$700,d0
-   dbf d0,- ; do nothing for a while...
+
    move.w  #1,(Hint_flag).w
 
    stopZ80
 
    tst.b   (Water_fullscreen_flag).w
    bne.s   loc_526
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
 
    bra.s   loc_54A
; ---------------------------------------------------------------------------
 
loc_526:
    dma68kToVDP Underwater_palette,$0000,palette_line_size*4,CRAM
 
loc_54A:
    move.w  (Hint_counter_reserve).w,(a5)
    move.w  #$8200|(VRAM_Plane_A_Name_Table/$400),(VDP_control_port).l  ; Set scroll A PNT base to $C000
    bsr.w   sndDriverInput
 
    startZ80
 
    bra.w   VintRet
; ---------------------------------------------------------------------------
 
Vint0_noWater:
    move.w  (VDP_control_port).l,d0
    move.l  #vdpComm($0000,VSRAM,WRITE),(VDP_control_port).l
    move.l  (Vscroll_Factor).w,(VDP_data_port).l
    btst    #6,(Graphics_Flags).w
    beq.s   +
 
    move.w  #$700,d0
-   dbf d0,- ; do nothing for a while...
+
    move.w  #1,(Hint_flag).w
    move.w  (Hint_counter_reserve).w,(VDP_control_port).l
    move.w  #$8200|(VRAM_Plane_A_Name_Table/$400),(VDP_control_port).l  ; Set scroll A PNT base to $C000
    move.l  (Vscroll_Factor_P2).w,(Vscroll_Factor_P2_HInt).w
 
    stopZ80
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
    bsr.w   sndDriverInput
    startZ80
 
    bra.w   VintRet
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
; This subroutine copies the H scroll table buffer (in main RAM) to the H scroll
; table (in VRAM).
;VintSub2
Vint_SEGA:
    bsr.w   Do_ControllerPal
 
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
    jsrto   (SegaScr_VInt).l, JmpTo_SegaScr_VInt
    tst.w   (Demo_Time_left).w
    beq.w   +   ; rts
    subq.w  #1,(Demo_Time_left).w
+
    rts
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;VintSub14
Vint_PCM:
    move.b  (Vint_runcount+3).w,d0
    andi.w  #$F,d0
    bne.s   +
 
    stopZ80
    bsr.w   ReadJoypads
    startZ80
+
    tst.w   (Demo_Time_left).w
    beq.w   +   ; rts
    subq.w  #1,(Demo_Time_left).w
+
    rts
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;VintSub4
Vint_Title:
    bsr.w   Do_ControllerPal
    bsr.w   ProcessDPLC
    tst.w   (Demo_Time_left).w
    beq.w   +   ; rts
    subq.w  #1,(Demo_Time_left).w
+
    rts
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;VintSub6
Vint_Unused6:
    bsr.w   Do_ControllerPal
    rts
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;VintSub10
Vint_Pause:
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w  ; Special Stage?
    beq.w   Vint_Pause_specialStage
;VintSub8
Vint_Level:
    stopZ80
 
    bsr.w   ReadJoypads
    tst.b   (Teleport_timer).w
    beq.s   loc_6F8
    lea (VDP_control_port).l,a5
    tst.w   (Game_paused).w
    bne.w   loc_748
    subq.b  #1,(Teleport_timer).w
    bne.s   +
    move.b  #0,(Teleport_flag).w
+
    cmpi.b  #$10,(Teleport_timer).w
    blo.s   loc_6F8
    lea (VDP_data_port).l,a6
    move.l  #vdpComm($0000,CRAM,WRITE),(VDP_control_port).l
    move.w  #$EEE,d0
 
    move.w  #$1F,d1
-   move.w  d0,(a6)
    dbf d1,-
 
    move.l  #vdpComm($0042,CRAM,WRITE),(VDP_control_port).l
 
    move.w  #$1F,d1
-   move.w  d0,(a6)
    dbf d1,-
 
    bra.s   loc_748
; ---------------------------------------------------------------------------
 
loc_6F8:
    tst.b   (Water_fullscreen_flag).w
    bne.s   loc_724
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    bra.s   loc_748
; ---------------------------------------------------------------------------
 
loc_724:
 
    dma68kToVDP Underwater_palette,$0000,palette_line_size*4,CRAM
 
loc_748:
    move.w  (Hint_counter_reserve).w,(a5)
    move.w  #$8200|(VRAM_Plane_A_Name_Table/$400),(VDP_control_port).l  ; Set scroll A PNT base to $C000
 
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
 
    bsr.w   ProcessDMAQueue
    bsr.w   sndDriverInput
 
    startZ80
 
    movem.l (Camera_RAM).w,d0-d7
    movem.l d0-d7,(Camera_RAM_copy).w
    movem.l (Camera_X_pos_P2).w,d0-d7
    movem.l d0-d7,(Camera_P2_copy).w
    movem.l (Scroll_flags).w,d0-d3
    movem.l d0-d3,(Scroll_flags_copy).w
    move.l  (Vscroll_Factor_P2).w,(Vscroll_Factor_P2_HInt).w
    cmpi.b  #$5C,(Hint_counter_reserve+1).w
    bhs.s   Do_Updates
    move.b  #1,(Do_Updates_in_H_int).w
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to run a demo for an amount of time
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_7E6: Demo_Time:
Do_Updates:
    jsrto   (LoadTilesAsYouMove).l, JmpTo_LoadTilesAsYouMove
    jsr (HudUpdate).l
    bsr.w   ProcessDPLC2
    tst.w   (Demo_Time_left).w  ; is there time left on the demo?
    beq.w   +       ; if not, branch
    subq.w  #1,(Demo_Time_left).w   ; subtract 1 from time left
+
    rts
; End of function Do_Updates
 
; ---------------------------------------------------------------------------
;Vint10_specialStage
Vint_Pause_specialStage:
    stopZ80
 
    bsr.w   ReadJoypads
    jsr (sndDriverInput).l
    tst.b   (SS_Last_Alternate_HorizScroll_Buf).w
    beq.s   loc_84A
 
    dma68kToVDP SS_Horiz_Scroll_Buf_2,VRAM_SS_Horiz_Scroll_Table,VRAM_SS_Horiz_Scroll_Table_Size,VRAM
    bra.s   loc_86E
; ---------------------------------------------------------------------------
loc_84A:
    dma68kToVDP SS_Horiz_Scroll_Buf_1,VRAM_SS_Horiz_Scroll_Table,VRAM_SS_Horiz_Scroll_Table_Size,VRAM
 
loc_86E:
    startZ80
    rts
; ========================================================================>>>
;VintSubA
Vint_S2SS:
    stopZ80
 
    bsr.w   ReadJoypads
    bsr.w   SSSet_VScroll
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    dma68kToVDP SS_Sprite_Table,VRAM_SS_Sprite_Attribute_Table,VRAM_SS_Sprite_Attribute_Table_Size,VRAM
 
    tst.b   (SS_Alternate_HorizScroll_Buf).w
    beq.s   loc_906
 
    dma68kToVDP SS_Horiz_Scroll_Buf_2,VRAM_SS_Horiz_Scroll_Table,VRAM_SS_Horiz_Scroll_Table_Size,VRAM
    bra.s   loc_92A
; ---------------------------------------------------------------------------
 
loc_906:
    dma68kToVDP SS_Horiz_Scroll_Buf_1,VRAM_SS_Horiz_Scroll_Table,VRAM_SS_Horiz_Scroll_Table_Size,VRAM
 
loc_92A:
    tst.b   (SSTrack_Orientation).w         ; Is the current track frame flipped?
    beq.s   ++                              ; Branch if not
    moveq   #0,d0
    move.b  (SSTrack_drawing_index).w,d0    ; Get drawing position
    cmpi.b  #4,d0                           ; Have we finished drawing and streaming track frame?
    bge.s   ++                              ; Branch if yes (nothing to draw)
    add.b   d0,d0                           ; Convert to index
    tst.b   (SS_Alternate_PNT).w            ; [(SSTrack_drawing_index) * 2] = subroutine
    beq.s   +                               ; Branch if not using the alternate Plane A name table
    addi_.w #8,d0                           ; ([(SSTrack_drawing_index) * 2] + 8) = subroutine
+
    move.w  SS_PNTA_Transfer_Table(pc,d0.w),d0
    jsr SS_PNTA_Transfer_Table(pc,d0.w)
+
    bsr.w   SSRun_Animation_Timers
    addi_.b #1,(SSTrack_drawing_index).w    ; Run track timer
    move.b  (SSTrack_drawing_index).w,d0    ; Get new timer value
    cmp.b   d1,d0                           ; Is it less than the player animation timer?
    blt.s   +++                             ; Branch if so
    move.b  #0,(SSTrack_drawing_index).w    ; Start drawing new frame
    lea (VDP_control_port).l,a6
    tst.b   (SS_Alternate_PNT).w            ; Are we using the alternate address for plane A?
    beq.s   +                               ; Branch if not
    move.w  #$8200|(VRAM_SS_Plane_A_Name_Table1/$400),(a6)  ; Set PNT A base to $C000
    bra.s   ++
; ===========================================================================
;off_97A
SS_PNTA_Transfer_Table: offsetTable
        offsetTableEntry.w loc_A50  ; 0
        offsetTableEntry.w loc_A76  ; 1
        offsetTableEntry.w loc_A9C  ; 2
        offsetTableEntry.w loc_AC2  ; 3
        offsetTableEntry.w loc_9B8  ; 4
        offsetTableEntry.w loc_9DE  ; 5
        offsetTableEntry.w loc_A04  ; 6
        offsetTableEntry.w loc_A2A  ; 7
; ===========================================================================
+
    move.w  #$8200|(VRAM_SS_Plane_A_Name_Table2/$400),(a6)  ; Set PNT A base to $8000
+
    eori.b  #1,(SS_Alternate_PNT).w         ; Toggle flag
+
    bsr.w   ProcessDMAQueue
    jsr (sndDriverInput).l
 
    startZ80
 
    bsr.w   ProcessDPLC2
    tst.w   (Demo_Time_left).w
    beq.w   +   ; rts
    subq.w  #1,(Demo_Time_left).w
+
    rts
; ---------------------------------------------------------------------------
; (!)
; Each of these functions copies one fourth of pattern name table A into VRAM
; from a buffer in main RAM. $700 bytes are copied each frame, with the target
; are in VRAM depending on the current drawing position.
loc_9B8:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table1 + 0 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_9DE:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table1 + 1 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_A04:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table1 + 2 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_A2A:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table1 + 3 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_A50:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table2 + 0 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_A76:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table2 + 1 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_A9C:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table2 + 2 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ---------------------------------------------------------------------------
loc_AC2:
    dma68kToVDP PNT_Buffer,VRAM_SS_Plane_A_Name_Table2 + 3 * (PNT_Buffer_End-PNT_Buffer),PNT_Buffer_End-PNT_Buffer,VRAM
    rts
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_AE8
SSSet_VScroll:
    move.w  (VDP_control_port).l,d0
    move.l  #vdpComm($0000,VSRAM,WRITE),(VDP_control_port).l
    move.l  (Vscroll_Factor).w,(VDP_data_port).l
    rts
; End of function SSSet_VScroll
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_B02
SSRun_Animation_Timers:
    move.w  (SS_Cur_Speed_Factor).w,d0      ; Get current speed factor
    cmp.w   (SS_New_Speed_Factor).w,d0      ; Has the speed factor changed?
    beq.s   +                               ; Branch if yes
    move.l  (SS_New_Speed_Factor).w,(SS_Cur_Speed_Factor).w ; Save new speed factor
    move.b  #0,(SSTrack_duration_timer).w   ; Reset timer
+
    subi_.b #1,(SSTrack_duration_timer).w   ; Run track timer
    bgt.s   +                               ; Branch if not expired yet
    lea (SSAnim_Base_Duration).l,a0
    move.w  (SS_Cur_Speed_Factor).w,d0      ; The current speed factor is an index
    lsr.w   #1,d0
    move.b  (a0,d0.w),d1
    move.b  d1,(SS_player_anim_frame_timer).w   ; New player animation length (later halved)
    move.b  d1,(SSTrack_duration_timer).w       ; New track timer
    subq.b  #1,(SS_player_anim_frame_timer).w   ; Subtract one
    rts
; ---------------------------------------------------------------------------
+
    move.b  (SS_player_anim_frame_timer).w,d1   ; Get current player animatino length
    addq.b  #1,d1       ; Increase it
    rts
; End of function SSRun_Animation_Timers
 
; ===========================================================================
;byte_B46
SSAnim_Base_Duration:
    dc.b 60
    dc.b 30 ; 1
    dc.b 15 ; 2
    dc.b 10 ; 3
    dc.b  8 ; 4
    dc.b  6 ; 5
    dc.b  5 ; 6
    dc.b  0 ; 7
; ===========================================================================
;VintSub1A
Vint_CtrlDMA:
    stopZ80
    jsr (ProcessDMAQueue).l
    startZ80
    rts
; ===========================================================================
;VintSubC
Vint_TitleCard:
    stopZ80
 
    bsr.w   ReadJoypads
    tst.b   (Water_fullscreen_flag).w
    bne.s   loc_BB2
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    bra.s   loc_BD6
; ---------------------------------------------------------------------------
 
loc_BB2:
    dma68kToVDP Underwater_palette,$0000,palette_line_size*4,CRAM
 
loc_BD6:
    move.w  (Hint_counter_reserve).w,(a5)
 
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
 
    bsr.w   ProcessDMAQueue
    jsr (DrawLevelTitleCard).l
    jsr (sndDriverInput).l
 
    startZ80
 
    movem.l (Camera_RAM).w,d0-d7
    movem.l d0-d7,(Camera_RAM_copy).w
    movem.l (Scroll_flags).w,d0-d1
    movem.l d0-d1,(Scroll_flags_copy).w
    move.l  (Vscroll_Factor_P2).w,(Vscroll_Factor_P2_HInt).w
    bsr.w   ProcessDPLC
    rts
; ===========================================================================
;VintSubE
Vint_UnusedE:
    bsr.w   Do_ControllerPal
    addq.b  #1,(VIntSubE_RunCount).w
    move.b  #VintID_UnusedE,(Vint_routine).w
    rts
; ===========================================================================
;VintSub12
Vint_Fade:
    bsr.w   Do_ControllerPal
    move.w  (Hint_counter_reserve).w,(a5)
    bra.w   ProcessDPLC
; ===========================================================================
;VintSub18
Vint_Ending:
    stopZ80
 
    bsr.w   ReadJoypads
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
 
    bsr.w   ProcessDMAQueue
    bsr.w   sndDriverInput
    movem.l (Camera_RAM).w,d0-d7
    movem.l d0-d7,(Camera_RAM_copy).w
    movem.l (Scroll_flags).w,d0-d3
    movem.l d0-d3,(Scroll_flags_copy).w
    jsrto   (LoadTilesAsYouMove).l, JmpTo_LoadTilesAsYouMove
 
    startZ80
 
    move.w  (Ending_VInt_Subrout).w,d0
    beq.s   +   ; rts
    clr.w   (Ending_VInt_Subrout).w
    move.w  off_D3C-2(pc,d0.w),d0
    jsr off_D3C(pc,d0.w)
+
    rts
; ===========================================================================
off_D3C:    offsetTable
        offsetTableEntry.w (+)  ; 1
        offsetTableEntry.w (++) ; 2
; ===========================================================================
+
    dmaFillVRAM 0,VRAM_EndSeq_Plane_A_Name_Table,VRAM_EndSeq_Plane_Table_Size   ; VRAM Fill $C000 with $2000 zeros
    rts
; ---------------------------------------------------------------------------
+
    dmaFillVRAM 0,VRAM_EndSeq_Plane_B_Name_Table2,VRAM_EndSeq_Plane_Table_Size
    dmaFillVRAM 0,VRAM_EndSeq_Plane_A_Name_Table,VRAM_EndSeq_Plane_Table_Size
 
    lea (VDP_control_port).l,a6
    move.w  #$8B00,(a6)     ; EXT-INT off, V scroll by screen, H scroll by screen
    move.w  #$8400|(VRAM_EndSeq_Plane_B_Name_Table2/$2000),(a6) ; PNT B base: $4000
    move.w  #$9011,(a6)     ; Scroll table size: 64x64
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_EndSeq_Plane_A_Name_Table + planeLocH40($16,$21),VRAM,WRITE),d0   ;$50AC0003
    moveq   #$16,d1
    moveq   #$E,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
    rts
; ===========================================================================
;VintSub16
Vint_Menu:
    stopZ80
 
    bsr.w   ReadJoypads
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
 
    bsr.w   ProcessDMAQueue
    bsr.w   sndDriverInput
 
    startZ80
 
    bsr.w   ProcessDPLC
    tst.w   (Demo_Time_left).w
    beq.w   +   ; rts
    subq.w  #1,(Demo_Time_left).w
+
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_E98
Do_ControllerPal:
    stopZ80
 
    bsr.w   ReadJoypads
    tst.b   (Water_fullscreen_flag).w
    bne.s   loc_EDA
 
    dma68kToVDP Normal_palette,$0000,palette_line_size*4,CRAM
    bra.s   loc_EFE
; ---------------------------------------------------------------------------
 
loc_EDA:
    dma68kToVDP Underwater_palette,$0000,palette_line_size*4,CRAM
 
loc_EFE:
    dma68kToVDP Sprite_Table,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
    dma68kToVDP Horiz_Scroll_Buf,VRAM_Horiz_Scroll_Table,VRAM_Horiz_Scroll_Table_Size,VRAM
 
    bsr.w   sndDriverInput
 
    startZ80
 
    rts
; End of function sub_E98
; ||||||||||||||| E N D   O F   V - I N T |||||||||||||||||||||||||||||||||||
 
; ===========================================================================
; Start of H-INT code
H_Int:
    tst.w   (Hint_flag).w
    beq.w   +
    tst.w   (Two_player_mode).w
    beq.w   PalToCRAM
    move.w  #0,(Hint_flag).w
    move.l  a5,-(sp)
    move.l  d0,-(sp)
 
-   move.w  (VDP_control_port).l,d0 ; loop start: Make sure V_BLANK is over
    andi.w  #4,d0
    beq.s   -   ; loop end
 
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l     ; Display disable
    move.w  #$8200|(VRAM_Plane_A_Name_Table_2P/$400),(VDP_control_port).l   ; PNT A base: $A000
    move.l  #vdpComm($0000,VSRAM,WRITE),(VDP_control_port).l
    move.l  (Vscroll_Factor_P2_HInt).w,(VDP_data_port).l
 
    stopZ80
    dma68kToVDP Sprite_Table_2,VRAM_Sprite_Attribute_Table,VRAM_Sprite_Attribute_Table_Size,VRAM
    startZ80
 
-   move.w  (VDP_control_port).l,d0
    andi.w  #4,d0
    beq.s   -
 
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l     ; Display enable
    move.l  (sp)+,d0
    movea.l (sp)+,a5
+
    rte
 
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; game code
 
; ---------------------------------------------------------------------------
; loc_1000:
PalToCRAM:
    move    #$2700,sr
    move.w  #0,(Hint_flag).w
    movem.l a0-a1,-(sp)
    lea (VDP_data_port).l,a1
    lea (Underwater_palette).w,a0   ; load palette from RAM
    move.l  #vdpComm($0000,CRAM,WRITE),4(a1)    ; set VDP to write to CRAM address $00
    rept 32
    move.l  (a0)+,(a1)  ; move palette to CRAM (all 64 colors at once)
    endm
    move.w  #$8ADF,4(a1)    ; Write %1101 %1111 to register 10 (interrupt every 224th line)
    movem.l (sp)+,a0-a1
    tst.b   (Do_Updates_in_H_int).w
    bne.s   loc_1072
    rte
; ===========================================================================
 
loc_1072:
    clr.b   (Do_Updates_in_H_int).w
    movem.l d0-a6,-(sp)
    bsr.w   Do_Updates
    movem.l (sp)+,d0-a6
    rte
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Input our music/sound selection to the sound driver.
 
sndDriverInput:
    lea (Music_to_play&$00FFFFFF).l,a0
    lea (Z80_RAM+zComRange).l,a1 ; $A01B80
    cmpi.b  #$80,zAbsVar.QueueToPlay-zComRange(a1)  ; If this (zReadyFlag) isn't $80, the driver is processing a previous sound request.
    bne.s   loc_10C4    ; So we'll wait until at least the next frame before putting anything in there.
    _move.b 0(a0),d0
    beq.s   loc_10A4
    _clr.b  0(a0)
    bra.s   loc_10AE
; ---------------------------------------------------------------------------
 
loc_10A4:
    move.b  4(a0),d0    ; If there was something in Music_to_play_2, check what that was. Else, just go to the loop.
    beq.s   loc_10C4
    clr.b   4(a0)
 
loc_10AE:       ; Check that the sound is not FE or FF
    move.b  d0,d1   ; If it is, we need to put it in $A01B83 as $7F or $80 respectively
    subi.b  #MusID_Pause,d1
    bcs.s   loc_10C0
    addi.b  #$7F,d1
    move.b  d1,zAbsVar.StopMusic-zComRange(a1)
    bra.s   loc_10C4
; ---------------------------------------------------------------------------
 
loc_10C0:
    move.b  d0,zAbsVar.QueueToPlay-zComRange(a1)
 
loc_10C4:
    moveq   #4-1,d1
                ; FFE4 (Music_to_play_2) goes to 1B8C (zMusicToPlay),
-   move.b  1(a0,d1.w),d0   ; FFE3 (unk_FFE3) goes to 1B8B, (unknown)
    beq.s   +       ; FFE2 (SFX_to_play_2) goes to 1B8A (zSFXToPlay2),
    tst.b   zAbsVar.SFXToPlay-zComRange(a1,d1.w)    ; FFE1 (SFX_to_play) goes to 1B89 (zSFXToPlay).
    bne.s   +
    clr.b   1(a0,d1.w)
    move.b  d0,zAbsVar.SFXToPlay-zComRange(a1,d1.w)
+
    dbf d1,-
    rts
; End of function sndDriverInput
 
    if ~~removeJmpTos
; sub_10E0:
JmpTo_LoadTilesAsYouMove 
    jmp (LoadTilesAsYouMove).l
JmpTo_SegaScr_VInt 
    jmp (SegaScr_VInt).l
 
    align 4
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to initialize joypads
; ---------------------------------------------------------------------------
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_10EC:
JoypadInit:
    stopZ80
    moveq   #$40,d0
    move.b  d0,(HW_Port_1_Control).l    ; init port 1 (joypad 1)
    move.b  d0,(HW_Port_2_Control).l    ; init port 2 (joypad 2)
    move.b  d0,(HW_Expansion_Control).l ; init port 3 (extra)
    startZ80
    rts
; End of function JoypadInit
 
; ---------------------------------------------------------------------------
; Subroutine to read joypad input, and send it to the RAM
; ---------------------------------------------------------------------------
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_111C:
ReadJoypads:
    lea (Ctrl_1).w,a0   ; address where joypad states are written
    lea (HW_Port_1_Data).l,a1   ; first joypad port
    bsr.s   Joypad_Read     ; do the first joypad
    addq.w  #2,a1           ; do the second joypad
; End of function ReadJoypads
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_112A:
Joypad_Read:
    move.b  #0,(a1)
    nop
    nop
    move.b  (a1),d0
    lsl.b   #2,d0
    andi.b  #$C0,d0
    move.b  #$40,(a1)
    nop
    nop
    move.b  (a1),d1
    andi.b  #$3F,d1
    or.b    d1,d0
    not.b   d0
    move.b  (a0),d1
    eor.b   d0,d1
    move.b  d0,(a0)+
    and.b   d0,d1
    move.b  d1,(a0)+
    rts
; End of function Joypad_Read
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1158:
VDPSetupGame:
    lea (VDP_control_port).l,a0
    lea (VDP_data_port).l,a1
    lea (VDPSetupArray).l,a2
    moveq   #bytesToWcnt(VDPSetupArray_End-VDPSetupArray),d7
; loc_116C:
VDP_Loop:
    move.w  (a2)+,(a0)
    dbf d7,VDP_Loop ; set the VDP registers
 
    move.w  (VDPSetupArray+2).l,d0
    move.w  d0,(VDP_Reg1_val).w
    move.w  #$8ADF,(Hint_counter_reserve).w ; H-INT every 224th scanline
    moveq   #0,d0
 
    move.l  #vdpComm($0000,VSRAM,WRITE),(VDP_control_port).l
    move.w  d0,(a1)
    move.w  d0,(a1)
 
    move.l  #vdpComm($0000,CRAM,WRITE),(VDP_control_port).l
 
    move.w  #bytesToWcnt(palette_line_size*4),d7
; loc_11A0:
VDP_ClrCRAM:
    move.w  d0,(a1)
    dbf d7,VDP_ClrCRAM
 
    clr.l   (Vscroll_Factor).w
    clr.l   (unk_F61A).w
    move.l  d1,-(sp)
 
    dmaFillVRAM 0,$0000,$10000  ; fill entire VRAM with 0
 
    move.l  (sp)+,d1
    rts
; End of function VDPSetupGame
 
; ===========================================================================
; word_11E2:
VDPSetupArray:
    dc.w $8004      ; H-INT disabled
    dc.w $8134      ; Genesis mode, DMA enabled, VBLANK-INT enabled
    dc.w $8200|(VRAM_Plane_A_Name_Table/$400)   ; PNT A base: $C000
    dc.w $8328      ; PNT W base: $A000
    dc.w $8400|(VRAM_Plane_B_Name_Table/$2000)  ; PNT B base: $E000
    dc.w $8500|(VRAM_Sprite_Attribute_Table/$200)   ; Sprite attribute table base: $F800
    dc.w $8600
    dc.w $8700      ; Background palette/color: 0/0
    dc.w $8800
    dc.w $8900
    dc.w $8A00      ; H-INT every scanline
    dc.w $8B00      ; EXT-INT off, V scroll by screen, H scroll by screen
    dc.w $8C81      ; H res 40 cells, no interlace, S/H disabled
    dc.w $8D00|(VRAM_Horiz_Scroll_Table/$400)   ; H scroll table base: $FC00
    dc.w $8E00
    dc.w $8F02      ; VRAM pointer increment: $0002
    dc.w $9001      ; Scroll table size: 64x32
    dc.w $9100      ; Disable window
    dc.w $9200      ; Disable window
VDPSetupArray_End:
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1208:
ClearScreen:
    stopZ80
 
    dmaFillVRAM 0,$0000,$40     ; Fill first $40 bytes of VRAM with 0
    dmaFillVRAM 0,VRAM_Plane_A_Name_Table,VRAM_Plane_Table_Size ; Clear Plane A pattern name table
    dmaFillVRAM 0,VRAM_Plane_B_Name_Table,VRAM_Plane_Table_Size ; Clear Plane B pattern name table
 
    tst.w   (Two_player_mode).w
    beq.s   +
 
    dmaFillVRAM 0,VRAM_Plane_A_Name_Table_2P,VRAM_Plane_Table_Size
+
    clr.l   (Vscroll_Factor).w
    clr.l   (unk_F61A).w
 
    ; Bug: These '+4's shouldn't be here; clearRAM accidentally clears an additional 4 bytes
    clearRAM Sprite_Table,Sprite_Table_End+4
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End+4
 
    startZ80
    rts
; End of function ClearScreen
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; JumpTo load the sound driver
; sub_130A:
JmpTo_SoundDriverLoad 
    nop
    jmp (SoundDriverLoad).l
; End of function JmpTo_SoundDriverLoad
 
; ===========================================================================
; unused mostly-leftover subroutine to load the sound driver
; SoundDriverLoadS1:
    move.w  #$100,(Z80_Bus_Request).l ; stop the Z80
    move.w  #$100,(Z80_Reset).l ; reset the Z80
    lea (Z80_RAM).l,a1
    move.b  #$F3,(a1)+  ; di
    move.b  #$F3,(a1)+  ; di
    move.b  #$C3,(a1)+  ; jp
    move.b  #0,(a1)+    ; jp address low byte
    move.b  #0,(a1)+    ; jp address high byte
    move.w  #0,(Z80_Reset).l
    nop
    nop
    nop
    nop
    move.w  #$100,(Z80_Reset).l ; reset the Z80
    move.w  #0,(Z80_Bus_Request).l ; start the Z80
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; If Music_to_play is clear, move d0 into Music_to_play,
; else move d0 into Music_to_play_2.
; sub_135E:
PlayMusic:
    tst.b   (Music_to_play).w
    bne.s   +
    move.b  d0,(Music_to_play).w
    rts
+
    move.b  d0,(Music_to_play_2).w
    rts
; End of function PlayMusic
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1370
PlaySound:
    move.b  d0,(SFX_to_play).w
    rts
; End of function PlaySound
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; play a sound in alternating speakers (as in the ring collection sound)
; sub_1376:
PlaySoundStereo:
    move.b  d0,(SFX_to_play_2).w
    rts
; End of function PlaySoundStereo
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; play a sound if the source is onscreen
; sub_137C:
PlaySoundLocal:
    tst.b   render_flags(a0)
    bpl.s   +   ; rts
    move.b  d0,(SFX_to_play).w
+
    rts
; End of function PlaySoundLocal
 
; ---------------------------------------------------------------------------
; Subroutine to pause the game
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1388:
PauseGame:
    nop
    tst.b   (Life_count).w  ; do you have any lives left?
    beq.w   Unpause     ; if not, branch
    tst.w   (Game_paused).w ; is game already paused?
    bne.s   +       ; if yes, branch
    move.b  (Ctrl_1_Press).w,d0 ; is Start button pressed?
    or.b    (Ctrl_2_Press).w,d0 ; (either player)
    andi.b  #button_start_mask,d0
    beq.s   Pause_DoNothing ; if not, branch
+
    move.w  #1,(Game_paused).w  ; freeze time
    move.b  #MusID_Pause,(Music_to_play).w  ; pause music
; loc_13B2:
Pause_Loop:
    move.b  #VintID_Pause,(Vint_routine).w
    bsr.w   WaitForVint
    tst.b   (Slow_motion_flag).w    ; is slow-motion cheat on?
    beq.s   Pause_ChkStart      ; if not, branch
    btst    #button_A,(Ctrl_1_Press).w  ; is button A pressed?
    beq.s   Pause_ChkBC     ; if not, branch
    move.b  #GameModeID_TitleScreen,(Game_Mode).w   ; => TitleScreen
    nop
    bra.s   Pause_Resume
; ===========================================================================
; loc_13D4:
Pause_ChkBC:
    btst    #button_B,(Ctrl_1_Held).w ; is button B pressed?
    bne.s   Pause_SlowMo        ; if yes, branch
    btst    #button_C,(Ctrl_1_Press).w ; is button C pressed?
    bne.s   Pause_SlowMo        ; if yes, branch
; loc_13E4:
Pause_ChkStart:
    move.b  (Ctrl_1_Press).w,d0 ; is Start button pressed?
    or.b    (Ctrl_2_Press).w,d0 ; (either player)
    andi.b  #button_start_mask,d0
    beq.s   Pause_Loop  ; if not, branch
; loc_13F2:
Pause_Resume:
    move.b  #MusID_Unpause,(Music_to_play).w
; loc_13F8:
Unpause:
    move.w  #0,(Game_paused).w
; return_13FE:
Pause_DoNothing:
    rts
; ===========================================================================
; loc_1400:
Pause_SlowMo:
    move.w  #1,(Game_paused).w
    move.b  #MusID_Unpause,(Music_to_play).w
    rts
; End of function PauseGame
 
; ---------------------------------------------------------------------------
; Subroutine to transfer a plane map to VRAM
; ---------------------------------------------------------------------------
 
; control register:
;    CD1 CD0 A13 A12 A11 A10 A09 A08     (D31-D24)
;    A07 A06 A05 A04 A03 A02 A01 A00     (D23-D16)
;     ?   ?   ?   ?   ?   ?   ?   ?      (D15-D8)
;    CD5 CD4 CD3 CD2  ?   ?  A15 A14     (D7-D0)
;
;   A00-A15 - address
;   CD0-CD3 - code
;   CD4 - 1 if VRAM copy DMA mode. 0 otherwise.
;   CD5 - DMA operation
;   
;   Bits CD3-CD0:
;   0000 - VRAM read
;   0001 - VRAM write
;   0011 - CRAM write
;   0100 - VSRAM read
;   0101 - VSRAM write
;   1000 - CRAM read
;
; d0 = control register
; d1 = width
; d2 = heigth
; a1 = source address
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_140E: ShowVDPGraphics: PlaneMapToVRAM:
PlaneMapToVRAM_H40:
    lea (VDP_data_port).l,a6
    move.l  #vdpCommDelta(planeLocH40(0,1)),d4  ; $800000
-   move.l  d0,VDP_control_port-VDP_data_port(a6)   ; move d0 to VDP_control_port
    move.w  d1,d3
-   move.w  (a1)+,(a6)  ; from source address to destination in VDP
    dbf d3,-        ; next tile
    add.l   d4,d0       ; increase destination address by $80 (1 line)
    dbf d2,--       ; next line
    rts
; End of function PlaneMapToVRAM_H40
 
; ---------------------------------------------------------------------------
; Alternate subroutine to transfer a plane map to VRAM
; (used for Special Stage background)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_142E: ShowVDPGraphics2: PlaneMapToVRAM2:
PlaneMapToVRAM_H80_SpecialStage:
    lea (VDP_data_port).l,a6
    move.l  #vdpCommDelta(planeLocH80(0,1)),d4  ; $1000000
-   move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.w  d1,d3
-   move.w  (a1)+,(a6)
    dbf d3,-
    add.l   d4,d0
    dbf d2,--
    rts
; End of function PlaneMapToVRAM_H80_SpecialStage
 
 
; ---------------------------------------------------------------------------
; Subroutine for queueing VDP commands (seems to only queue transfers to VRAM),
; to be issued the next time ProcessDMAQueue is called.
; Can be called a maximum of 18 times before the buffer needs to be cleared
; by issuing the commands (this subroutine DOES check for overflow)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_144E: DMA_68KtoVRAM: QueueCopyToVRAM: QueueVDPCommand: Add_To_DMA_Queue:
QueueDMATransfer:
    movea.l (VDP_Command_Buffer_Slot).w,a1
    cmpa.w  #VDP_Command_Buffer_Slot,a1
    beq.s   QueueDMATransfer_Done ; return if there's no more room in the buffer
 
    ; piece together some VDP commands and store them for later...
    move.w  #$9300,d0 ; command to specify DMA transfer length & $00FF
    move.b  d3,d0
    move.w  d0,(a1)+ ; store command
 
    move.w  #$9400,d0 ; command to specify DMA transfer length & $FF00
    lsr.w   #8,d3
    move.b  d3,d0
    move.w  d0,(a1)+ ; store command
 
    move.w  #$9500,d0 ; command to specify source address & $0001FE
    lsr.l   #1,d1
    move.b  d1,d0
    move.w  d0,(a1)+ ; store command
 
    move.w  #$9600,d0 ; command to specify source address & $01FE00
    lsr.l   #8,d1
    move.b  d1,d0
    move.w  d0,(a1)+ ; store command
 
    move.w  #$9700,d0 ; command to specify source address & $FE0000
    lsr.l   #8,d1
    ;andi.b #$7F,d1     ; this instruction safely allows source to be in RAM; S3K added this
    move.b  d1,d0
    move.w  d0,(a1)+ ; store command
 
    andi.l  #$FFFF,d2 ; command to specify destination address and begin DMA
    lsl.l   #2,d2
    lsr.w   #2,d2
    swap    d2
    ori.l   #vdpComm($0000,VRAM,DMA),d2 ; set bits to specify VRAM transfer
    move.l  d2,(a1)+ ; store command
 
    move.l  a1,(VDP_Command_Buffer_Slot).w ; set the next free slot address
    cmpa.w  #VDP_Command_Buffer_Slot,a1
    beq.s   QueueDMATransfer_Done ; return if there's no more room in the buffer
    move.w  #0,(a1) ; put a stop token at the end of the used part of the buffer
; return_14AA:
QueueDMATransfer_Done:
    rts
; End of function QueueDMATransfer
 
 
; ---------------------------------------------------------------------------
; Subroutine for issuing all VDP commands that were queued
; (by earlier calls to QueueDMATransfer)
; Resets the queue when it's done
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_14AC: CopyToVRAM: IssueVDPCommands: Process_DMA: Process_DMA_Queue:
ProcessDMAQueue:
    lea (VDP_control_port).l,a5
    lea (VDP_Command_Buffer).w,a1
; loc_14B6:
ProcessDMAQueue_Loop:
    move.w  (a1)+,d0
    beq.s   ProcessDMAQueue_Done ; branch if we reached a stop token
    ; issue a set of VDP commands...
    move.w  d0,(a5)     ; transfer length
    move.w  (a1)+,(a5)  ; transfer length
    move.w  (a1)+,(a5)  ; source address
    move.w  (a1)+,(a5)  ; source address
    move.w  (a1)+,(a5)  ; source address
    move.w  (a1)+,(a5)  ; destination
    move.w  (a1)+,(a5)  ; destination
    cmpa.w  #VDP_Command_Buffer_Slot,a1
    bne.s   ProcessDMAQueue_Loop ; loop if we haven't reached the end of the buffer
; loc_14CE:
ProcessDMAQueue_Done:
    move.w  #0,(VDP_Command_Buffer).w
    move.l  #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w
    rts
; End of function ProcessDMAQueue
 
 
 
; ---------------------------------------------------------------------------
; START OF NEMESIS DECOMPRESSOR
 
; For format explanation see http://info.sonicretro.org/Nemesis_compression
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Nemesis decompression to VRAM
; sub_14DE: NemDecA:
NemDec:
    movem.l d0-a1/a3-a5,-(sp)
    lea (NemDec_WriteAndStay).l,a3 ; write all data to the same location
    lea (VDP_data_port).l,a4       ; specifically, to the VDP data port
    bra.s   NemDecMain
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Nemesis decompression to RAM
; input: a4 = starting address of destination
; sub_14F0: NemDecB:
NemDecToRAM:
    movem.l d0-a1/a3-a5,-(sp)
    lea (NemDec_WriteAndAdvance).l,a3 ; advance to the next location after each write
 
 
; sub_14FA:
NemDecMain:
    lea (Decomp_Buffer).w,a1
    move.w  (a0)+,d2
    lsl.w   #1,d2
    bcc.s   +
    adda.w  #NemDec_WriteAndStay_XOR-NemDec_WriteAndStay,a3
+   lsl.w   #2,d2
    movea.w d2,a5
    moveq   #8,d3
    moveq   #0,d2
    moveq   #0,d4
    bsr.w   NemDecPrepare
    move.b  (a0)+,d5
    asl.w   #8,d5
    move.b  (a0)+,d5
    move.w  #$10,d6
    bsr.s   NemDecRun
    movem.l (sp)+,d0-a1/a3-a5
    rts
; End of function NemDec
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; part of the Nemesis decompressor
; sub_1528:
NemDecRun:
    move.w  d6,d7
    subq.w  #8,d7
    move.w  d5,d1
    lsr.w   d7,d1
    cmpi.b  #-4,d1
    bhs.s   loc_1574
    andi.w  #$FF,d1
    add.w   d1,d1
    move.b  (a1,d1.w),d0
    ext.w   d0
    sub.w   d0,d6
    cmpi.w  #9,d6
    bhs.s   +
    addq.w  #8,d6
    asl.w   #8,d5
    move.b  (a0)+,d5
+   move.b  1(a1,d1.w),d1
    move.w  d1,d0
    andi.w  #$F,d1
    andi.w  #$F0,d0
 
loc_155E:
    lsr.w   #4,d0
 
loc_1560:
    lsl.l   #4,d4
    or.b    d1,d4
    subq.w  #1,d3
    bne.s   NemDec_WriteIter_Part2
    jmp (a3) ; dynamic jump! to NemDec_WriteAndStay, NemDec_WriteAndAdvance, NemDec_WriteAndStay_XOR, or NemDec_WriteAndAdvance_XOR
; ===========================================================================
; loc_156A:
NemDec_WriteIter:
    moveq   #0,d4
    moveq   #8,d3
; loc_156E:
NemDec_WriteIter_Part2:
    dbf d0,loc_1560
    bra.s   NemDecRun
; ===========================================================================
 
loc_1574:
    subq.w  #6,d6
    cmpi.w  #9,d6
    bhs.s   +
    addq.w  #8,d6
    asl.w   #8,d5
    move.b  (a0)+,d5
+
    subq.w  #7,d6
    move.w  d5,d1
    lsr.w   d6,d1
    move.w  d1,d0
    andi.w  #$F,d1
    andi.w  #$70,d0
    cmpi.w  #9,d6
    bhs.s   loc_155E
    addq.w  #8,d6
    asl.w   #8,d5
    move.b  (a0)+,d5
    bra.s   loc_155E
; End of function NemDecRun
 
; ===========================================================================
; loc_15A0:
NemDec_WriteAndStay:
    move.l  d4,(a4)
    subq.w  #1,a5
    move.w  a5,d4
    bne.s   NemDec_WriteIter
    rts
; ---------------------------------------------------------------------------
; loc_15AA:
NemDec_WriteAndStay_XOR:
    eor.l   d4,d2
    move.l  d2,(a4)
    subq.w  #1,a5
    move.w  a5,d4
    bne.s   NemDec_WriteIter
    rts
; ===========================================================================
; loc_15B6:
NemDec_WriteAndAdvance:
    move.l  d4,(a4)+
    subq.w  #1,a5
    move.w  a5,d4
    bne.s   NemDec_WriteIter
    rts
 
    if *-NemDec_WriteAndAdvance > NemDec_WriteAndStay_XOR-NemDec_WriteAndStay
    fatal "the code in NemDec_WriteAndAdvance must not be larger than the code in NemDec_WriteAndStay"
    endif
    org NemDec_WriteAndAdvance+NemDec_WriteAndStay_XOR-NemDec_WriteAndStay
 
; ---------------------------------------------------------------------------
; loc_15C0:
NemDec_WriteAndAdvance_XOR:
    eor.l   d4,d2
    move.l  d2,(a4)+
    subq.w  #1,a5
    move.w  a5,d4
    bne.s   NemDec_WriteIter
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Part of the Nemesis decompressor
 
; sub_15CC:
NemDecPrepare:
    move.b  (a0)+,d0
 
-   cmpi.b  #$FF,d0
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+   move.w  d0,d7
 
loc_15D8:
    move.b  (a0)+,d0
    cmpi.b  #$80,d0
    bhs.s   -
 
    move.b  d0,d1
    andi.w  #$F,d7
    andi.w  #$70,d1
    or.w    d1,d7
    andi.w  #$F,d0
    move.b  d0,d1
    lsl.w   #8,d1
    or.w    d1,d7
    moveq   #8,d1
    sub.w   d0,d1
    bne.s   loc_1606
    move.b  (a0)+,d0
    add.w   d0,d0
    move.w  d7,(a1,d0.w)
    bra.s   loc_15D8
; ---------------------------------------------------------------------------
loc_1606:
    move.b  (a0)+,d0
    lsl.w   d1,d0
    add.w   d0,d0
    moveq   #1,d5
    lsl.w   d1,d5
    subq.w  #1,d5
 
-   move.w  d7,(a1,d0.w)
    addq.w  #2,d0
    dbf d5,-
 
    bra.s   loc_15D8
; End of function NemDecPrepare
 
; ---------------------------------------------------------------------------
; END OF NEMESIS DECOMPRESSOR
; ---------------------------------------------------------------------------
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; ---------------------------------------------------------------------------
; Subroutine to load pattern load cues (aka to queue pattern load requests)
; ---------------------------------------------------------------------------
 
; ARGUMENTS
; d0 = index of PLC list (see ArtLoadCues)
 
; NOTICE: This subroutine does not check for buffer overruns. The programmer
;     (or hacker) is responsible for making sure that no more than
;     16 load requests are copied into the buffer.
;    _________DO NOT PUT MORE THAN 16 LOAD REQUESTS IN A LIST!__________
;         (or if you change the size of Plc_Buffer, the limit becomes (Plc_Buffer_Only_End-Plc_Buffer)/6)
 
; sub_161E: PLCLoad:
LoadPLC:
    movem.l a1-a2,-(sp)
    lea (ArtLoadCues).l,a1
    add.w   d0,d0
    move.w  (a1,d0.w),d0
    lea (a1,d0.w),a1
    lea (Plc_Buffer).w,a2
 
-   tst.l   (a2)
    beq.s   + ; if it's zero, exit this loop
    addq.w  #6,a2
    bra.s   -
+
    move.w  (a1)+,d0
    bmi.s   + ; if it's negative, skip the next loop
 
-   move.l  (a1)+,(a2)+
    move.w  (a1)+,(a2)+
    dbf d0,-
+
    movem.l (sp)+,a1-a2 ; a1=object
    rts
; End of function LoadPLC
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Queue pattern load requests, but clear the PLQ first
 
; ARGUMENTS
; d0 = index of PLC list (see ArtLoadCues)
 
; NOTICE: This subroutine does not check for buffer overruns. The programmer
;     (or hacker) is responsible for making sure that no more than
;     16 load requests are copied into the buffer.
;     _________DO NOT PUT MORE THAN 16 LOAD REQUESTS IN A LIST!__________
;         (or if you change the size of Plc_Buffer, the limit becomes (Plc_Buffer_Only_End-Plc_Buffer)/6)
; sub_1650:
LoadPLC2:
    movem.l a1-a2,-(sp)
    lea (ArtLoadCues).l,a1
    add.w   d0,d0
    move.w  (a1,d0.w),d0
    lea (a1,d0.w),a1
    bsr.s   ClearPLC
    lea (Plc_Buffer).w,a2
    move.w  (a1)+,d0
    bmi.s   + ; if it's negative, skip the next loop
 
-   move.l  (a1)+,(a2)+
    move.w  (a1)+,(a2)+
    dbf d0,-
+
    movem.l (sp)+,a1-a2
    rts
; End of function LoadPLC2
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Clear the pattern load queue ($FFF680 - $FFF700)
 
ClearPLC:
    lea (Plc_Buffer).w,a2
 
    moveq   #bytesToLcnt(Plc_Buffer_End-Plc_Buffer),d0
-   clr.l   (a2)+
    dbf d0,-
 
    rts
; End of function ClearPLC
 
; ---------------------------------------------------------------------------
; Subroutine to use graphics listed in a pattern load cue
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_168A:
RunPLC_RAM:
    tst.l   (Plc_Buffer).w
    beq.s   ++  ; rts
    tst.w   (Plc_Buffer_Reg18).w
    bne.s   ++  ; rts
    movea.l (Plc_Buffer).w,a0
    lea_    NemDec_WriteAndStay,a3
    nop
    lea (Decomp_Buffer).w,a1
    move.w  (a0)+,d2
    bpl.s   +
    adda.w  #NemDec_WriteAndStay_XOR-NemDec_WriteAndStay,a3
+
    andi.w  #$7FFF,d2
    move.w  d2,(Plc_Buffer_Reg18).w
    bsr.w   NemDecPrepare
    move.b  (a0)+,d5
    asl.w   #8,d5
    move.b  (a0)+,d5
    moveq   #$10,d6
    moveq   #0,d0
    move.l  a0,(Plc_Buffer).w
    move.l  a3,(Plc_Buffer_Reg0).w
    move.l  d0,(Plc_Buffer_Reg4).w
    move.l  d0,(Plc_Buffer_Reg8).w
    move.l  d0,(Plc_Buffer_RegC).w
    move.l  d5,(Plc_Buffer_Reg10).w
    move.l  d6,(Plc_Buffer_Reg14).w
+
    rts
; End of function RunPLC_RAM
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Process one PLC from the queue
 
; sub_16E0:
ProcessDPLC:
    tst.w   (Plc_Buffer_Reg18).w
    beq.w   +   ; rts
    move.w  #6,(Plc_Buffer_Reg1A).w
    moveq   #0,d0
    move.w  (Plc_Buffer+4).w,d0
    addi.w  #$C0,(Plc_Buffer+4).w
    bra.s   ProcessDPLC_Main
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Process one PLC from the queue
 
; loc_16FC:
ProcessDPLC2:
    tst.w   (Plc_Buffer_Reg18).w
    beq.s   +   ; rts
    move.w  #3,(Plc_Buffer_Reg1A).w
    moveq   #0,d0
    move.w  (Plc_Buffer+4).w,d0
    addi.w  #$60,(Plc_Buffer+4).w
 
; loc_1714:
ProcessDPLC_Main:
    lea (VDP_control_port).l,a4
    lsl.l   #2,d0       ; set up target VRAM address
    lsr.w   #2,d0
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d0
    swap    d0
    move.l  d0,(a4)
    subq.w  #4,a4
    movea.l (Plc_Buffer).w,a0
    movea.l (Plc_Buffer_Reg0).w,a3
    move.l  (Plc_Buffer_Reg4).w,d0
    move.l  (Plc_Buffer_Reg8).w,d1
    move.l  (Plc_Buffer_RegC).w,d2
    move.l  (Plc_Buffer_Reg10).w,d5
    move.l  (Plc_Buffer_Reg14).w,d6
    lea (Decomp_Buffer).w,a1
 
-   movea.w #8,a5
    bsr.w   NemDec_WriteIter
    subq.w  #1,(Plc_Buffer_Reg18).w
    beq.s   ProcessDPLC_Pop
    subq.w  #1,(Plc_Buffer_Reg1A).w
    bne.s   -
 
    move.l  a0,(Plc_Buffer).w
    move.l  a3,(Plc_Buffer_Reg0).w
    move.l  d0,(Plc_Buffer_Reg4).w
    move.l  d1,(Plc_Buffer_Reg8).w
    move.l  d2,(Plc_Buffer_RegC).w
    move.l  d5,(Plc_Buffer_Reg10).w
    move.l  d6,(Plc_Buffer_Reg14).w
+
    rts
 
; ===========================================================================
; pop one request off the buffer so that the next one can be filled
 
; loc_177A:
ProcessDPLC_Pop:
    lea (Plc_Buffer).w,a0
    moveq   #bytesToLcnt(Plc_Buffer_Only_End-Plc_Buffer-6),d0
-   move.l  6(a0),(a0)+
    dbf d0,-
    rts
 
; End of function ProcessDPLC
 
 
; ---------------------------------------------------------------------------
; Subroutine to execute a pattern load cue directly from the ROM
; rather than loading them into the queue first
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
RunPLC_ROM:
    lea (ArtLoadCues).l,a1
    add.w   d0,d0
    move.w  (a1,d0.w),d0
    lea (a1,d0.w),a1
 
    move.w  (a1)+,d1
-   movea.l (a1)+,a0
    moveq   #0,d0
    move.w  (a1)+,d0
    lsl.l   #2,d0
    lsr.w   #2,d0
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d0
    swap    d0
    move.l  d0,(VDP_control_port).l
    bsr.w   NemDec
    dbf d1,-
 
    rts
; End of function RunPLC_ROM
 
; ---------------------------------------------------------------------------
; Enigma Decompression Algorithm
 
; ARGUMENTS:
; d0 = starting art tile (added to each 8x8 before writing to destination)
; a0 = source address
; a1 = destination address
 
; For format explanation see http://info.sonicretro.org/Enigma_compression
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; EniDec_17BC:
EniDec:
    movem.l d0-d7/a1-a5,-(sp)
    movea.w d0,a3       ; store starting art tile
    move.b  (a0)+,d0
    ext.w   d0
    movea.w d0,a5       ; store first byte, extended to word
    move.b  (a0)+,d4    ; store second byte
    lsl.b   #3,d4       ; multiply by 8
    movea.w (a0)+,a2    ; store third and fourth byte
    adda.w  a3,a2       ; add starting art tile
    movea.w (a0)+,a4    ; store fifth and sixth byte
    adda.w  a3,a4       ; add starting art tile
    move.b  (a0)+,d5    ; store seventh byte
    asl.w   #8,d5       ; shift up by a byte
    move.b  (a0)+,d5    ; store eighth byte in lower register byte
    moveq   #16,d6      ; 16 bits = 2 bytes
 
EniDec_Loop:
    moveq   #7,d0       ; process 7 bits at a time
    move.w  d6,d7
    sub.w   d0,d7
    move.w  d5,d1
    lsr.w   d7,d1
    andi.w  #$7F,d1     ; keep only lower 7 bits
    move.w  d1,d2
    cmpi.w  #$40,d1     ; is bit 6 set?
    bhs.s   +       ; if it is, branch
    moveq   #6,d0       ; if not, process 6 bits instead of 7
    lsr.w   #1,d2       ; bitfield now becomes TTSSSS instead of TTTSSSS
+
    bsr.w   EniDec_ChkGetNextByte
    andi.w  #$F,d2  ; keep only lower nybble
    lsr.w   #4,d1   ; store upper nybble (max value = 7)
    add.w   d1,d1
    jmp EniDec_JmpTable(pc,d1.w)
; End of function EniDec
 
; ===========================================================================
 
EniDec_Sub0:
    move.w  a2,(a1)+    ; write to destination
    addq.w  #1,a2       ; increment
    dbf d2,EniDec_Sub0  ; repeat
    bra.s   EniDec_Loop
; ===========================================================================
 
EniDec_Sub4:
    move.w  a4,(a1)+    ; write to destination
    dbf d2,EniDec_Sub4  ; repeat
    bra.s   EniDec_Loop
; ===========================================================================
 
EniDec_Sub8:
    bsr.w   EniDec_GetInlineCopyVal
 
-   move.w  d1,(a1)+
    dbf d2,-
 
    bra.s   EniDec_Loop
; ===========================================================================
 
EniDec_SubA:
    bsr.w   EniDec_GetInlineCopyVal
 
-   move.w  d1,(a1)+
    addq.w  #1,d1
    dbf d2,-
 
    bra.s   EniDec_Loop
; ===========================================================================
 
EniDec_SubC:
    bsr.w   EniDec_GetInlineCopyVal
 
-   move.w  d1,(a1)+
    subq.w  #1,d1
    dbf d2,-
 
    bra.s   EniDec_Loop
; ===========================================================================
 
EniDec_SubE:
    cmpi.w  #$F,d2
    beq.s   EniDec_End
 
-   bsr.w   EniDec_GetInlineCopyVal
    move.w  d1,(a1)+
    dbf d2,-
 
    bra.s   EniDec_Loop
; ===========================================================================
; Enigma_JmpTable:
EniDec_JmpTable:
    bra.s   EniDec_Sub0
    bra.s   EniDec_Sub0
    bra.s   EniDec_Sub4
    bra.s   EniDec_Sub4
    bra.s   EniDec_Sub8
    bra.s   EniDec_SubA
    bra.s   EniDec_SubC
    bra.s   EniDec_SubE
; ===========================================================================
 
EniDec_End:
    subq.w  #1,a0
    cmpi.w  #16,d6      ; were we going to start on a completely new byte?
    bne.s   +       ; if not, branch
    subq.w  #1,a0
+
    move.w  a0,d0
    lsr.w   #1,d0       ; are we on an odd byte?
    bcc.s   +       ; if not, branch
    addq.w  #1,a0       ; ensure we're on an even byte
+
    movem.l (sp)+,d0-d7/a1-a5
    rts
 
;  S U B R O U T I N E 
 
 
EniDec_GetInlineCopyVal:
    move.w  a3,d3       ; store starting art tile
    move.b  d4,d1
    add.b   d1,d1
    bcc.s   +       ; if d4 was < $80
    subq.w  #1,d6       ; get next bit number
    btst    d6,d5       ; is the bit set?
    beq.s   +       ; if not, branch
    ori.w   #high_priority,d3   ; set high priority bit
+
    add.b   d1,d1
    bcc.s   +       ; if d4 was < $40
    subq.w  #1,d6       ; get next bit number
    btst    d6,d5
    beq.s   +
    addi.w  #palette_line_2,d3  ; set second palette line bit
+
    add.b   d1,d1
    bcc.s   +       ; if d4 was < $20
    subq.w  #1,d6       ; get next bit number
    btst    d6,d5
    beq.s   +
    addi.w  #palette_line_1,d3  ; set first palette line bit
+
    add.b   d1,d1
    bcc.s   +       ; if d4 was < $10
    subq.w  #1,d6       ; get next bit number
    btst    d6,d5
    beq.s   +
    ori.w   #flip_y,d3  ; set Y-flip bit
+
    add.b   d1,d1
    bcc.s   +       ; if d4 was < 8
    subq.w  #1,d6
    btst    d6,d5
    beq.s   +
    ori.w   #flip_x,d3  ; set X-flip bit
+
    move.w  d5,d1
    move.w  d6,d7       ; get remaining bits
    sub.w   a5,d7       ; subtract minimum bit number
    bcc.s   +       ; if we're beyond that, branch
    move.w  d7,d6
    addi.w  #16,d6      ; 16 bits = 2 bytes
    neg.w   d7      ; calculate bit deficit
    lsl.w   d7,d1       ; make space for this many bits
    move.b  (a0),d5     ; get next byte
    rol.b   d7,d5       ; make the upper X bits the lower X bits
    add.w   d7,d7
    and.w   EniDec_AndVals-2(pc,d7.w),d5    ; only keep X lower bits
    add.w   d5,d1       ; compensate for the bit deficit
-
    move.w  a5,d0
    add.w   d0,d0
    and.w   EniDec_AndVals-2(pc,d0.w),d1    ; only keep as many bits as required
    add.w   d3,d1       ; add starting art tile
    move.b  (a0)+,d5    ; get current byte, move onto next byte
    lsl.w   #8,d5       ; shift up by a byte
    move.b  (a0)+,d5    ; store next byte in lower register byte
    rts
; ===========================================================================
+
    beq.s   +       ; if the exact number of bits are leftover, branch
    lsr.w   d7,d1       ; remove unneeded bits
    move.w  a5,d0
    add.w   d0,d0
    and.w   EniDec_AndVals-2(pc,d0.w),d1    ; only keep as many bits as required
    add.w   d3,d1       ; add starting art tile
    move.w  a5,d0       ; store number of bits used up by inline copy
    bra.s   EniDec_ChkGetNextByte   ; move onto next byte
; ===========================================================================
+
    moveq   #16,d6  ; 16 bits = 2 bytes
    bra.s   -
; End of function EniDec_GetInlineCopyVal
 
; ===========================================================================
; word_190A:
EniDec_AndVals:
    dc.w     1,    3,    7,   $F
    dc.w   $1F,  $3F,  $7F,  $FF
    dc.w  $1FF, $3FF, $7FF, $FFF
    dc.w $1FFF,$3FFF,$7FFF,$FFFF
; ===========================================================================
 
EniDec_ChkGetNextByte:
    sub.w   d0,d6
    cmpi.w  #9,d6
    bhs.s   +   ; rts
    addq.w  #8,d6   ; 8 bits = 1 byte
    asl.w   #8,d5   ; shift up by a byte
    move.b  (a0)+,d5    ; store next byte in lower register byte
+
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; ---------------------------------------------------------------------------
; KOSINSKI DECOMPRESSION PROCEDURE
; (sometimes called KOZINSKI decompression)
 
; This is the only procedure in the game that stores variables on the stack.
 
; ARGUMENTS:
; a0 = source address
; a1 = destination address
 
; For format explanation see http://info.sonicretro.org/Kosinski_compression
; ---------------------------------------------------------------------------
; KozDec_193A:
KosDec:
    subq.l  #2,sp
    move.b  (a0)+,1(sp)
    move.b  (a0)+,(sp)
    move.w  (sp),d5
    moveq   #$F,d4
 
-
    lsr.w   #1,d5
    move    sr,d6
    dbf d4,+
    move.b  (a0)+,1(sp)
    move.b  (a0)+,(sp)
    move.w  (sp),d5
    moveq   #$F,d4
+
    move    d6,ccr
    bcc.s   +
    move.b  (a0)+,(a1)+
    bra.s   -
; ---------------------------------------------------------------------------
+
    moveq   #0,d3
    lsr.w   #1,d5
    move    sr,d6
    dbf d4,+
    move.b  (a0)+,1(sp)
    move.b  (a0)+,(sp)
    move.w  (sp),d5
    moveq   #$F,d4
+
    move    d6,ccr
    bcs.s   +++
    lsr.w   #1,d5
    dbf d4,+
    move.b  (a0)+,1(sp)
    move.b  (a0)+,(sp)
    move.w  (sp),d5
    moveq   #$F,d4
+
    roxl.w  #1,d3
    lsr.w   #1,d5
    dbf d4,+
    move.b  (a0)+,1(sp)
    move.b  (a0)+,(sp)
    move.w  (sp),d5
    moveq   #$F,d4
+
    roxl.w  #1,d3
    addq.w  #1,d3
    moveq   #-1,d2
    move.b  (a0)+,d2
    bra.s   ++
; ---------------------------------------------------------------------------
+
    move.b  (a0)+,d0
    move.b  (a0)+,d1
    moveq   #-1,d2
    move.b  d1,d2
    lsl.w   #5,d2
    move.b  d0,d2
    andi.w  #7,d1
    beq.s   ++
    move.b  d1,d3
    addq.w  #1,d3
/
    move.b  (a1,d2.w),d0
    move.b  d0,(a1)+
    dbf d3,-
    bra.s   --
; ---------------------------------------------------------------------------
+
    move.b  (a0)+,d1
    beq.s   +
    cmpi.b  #1,d1
    beq.w   --
    move.b  d1,d3
    bra.s   -
; ---------------------------------------------------------------------------
+
    addq.l  #2,sp
    rts
; End of function KosDec
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_19DC:
PalCycle_Load:
    bsr.w   PalCycle_SuperSonic
    moveq   #0,d2
    moveq   #0,d0
    move.b  (Current_Zone).w,d0 ; use level number as index into palette cycles
    add.w   d0,d0           ; (multiply by element size = 2 bytes)
    move.w  PalCycle(pc,d0.w),d0    ; load animated palettes offset index into d0
    jmp PalCycle(pc,d0.w)   ; jump to PalCycle + offset index
; ---------------------------------------------------------------------------
    rts
; End of function PalCycle_Load
 
; ===========================================================================
; off_19F4:
PalCycle: zoneOrderedOffsetTable 2,1
    zoneOffsetTableEntry.w PalCycle_EHZ ; 0
    zoneOffsetTableEntry.w PalCycle_Null    ; 1
    zoneOffsetTableEntry.w PalCycle_WZ  ; 2
    zoneOffsetTableEntry.w PalCycle_Null    ; 3
    zoneOffsetTableEntry.w PalCycle_MTZ ; 4
    zoneOffsetTableEntry.w PalCycle_MTZ ; 5
    zoneOffsetTableEntry.w PalCycle_WFZ ; 6
    zoneOffsetTableEntry.w PalCycle_HTZ ; 7
    zoneOffsetTableEntry.w PalCycle_HPZ ; 8
    zoneOffsetTableEntry.w PalCycle_Null    ; 9
    zoneOffsetTableEntry.w PalCycle_OOZ ; 10
    zoneOffsetTableEntry.w PalCycle_MCZ ; 11
    zoneOffsetTableEntry.w PalCycle_CNZ ; 12
    zoneOffsetTableEntry.w PalCycle_CPZ ; 13
    zoneOffsetTableEntry.w PalCycle_CPZ ; 14
    zoneOffsetTableEntry.w PalCycle_ARZ ; 15
    zoneOffsetTableEntry.w PalCycle_WFZ ; 16
    zoneTableEnd
 
; ===========================================================================
; return_1A16:
PalCycle_Null:
    rts
; ===========================================================================
 
PalCycle_EHZ:
    lea (CyclingPal_EHZ_ARZ_Water).l,a0
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +   ; rts
    move.w  #7,(PalCycle_Timer).w
    move.w  (PalCycle_Frame).w,d0
    addq.w  #1,(PalCycle_Frame).w
    andi.w  #3,d0
    lsl.w   #3,d0
    move.l  (a0,d0.w),(Normal_palette_line2+6).w
    move.l  4(a0,d0.w),(Normal_palette_line2+$1C).w
+   rts
; ===========================================================================
 
; PalCycle_Level2:
PalCycle_WZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   ++  ; rts
    move.w  #2,(PalCycle_Timer).w
    lea (CyclingPal_WoodConveyor).l,a0
    move.w  (PalCycle_Frame).w,d0
    subq.w  #2,(PalCycle_Frame).w
    bcc.s   +
    move.w  #6,(PalCycle_Frame).w
+   lea (Normal_palette_line4+6).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
+   rts
; ===========================================================================
 
PalCycle_MTZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   ++
    move.w  #$11,(PalCycle_Timer).w
    lea (CyclingPal_MTZ1).l,a0
    move.w  (PalCycle_Frame).w,d0
    addq.w  #2,(PalCycle_Frame).w
    cmpi.w  #$C,(PalCycle_Frame).w
    blo.s   +
    move.w  #0,(PalCycle_Frame).w
+   lea (Normal_palette_line3+$A).w,a1
    move.w  (a0,d0.w),(a1)
+
    subq.w  #1,(PalCycle_Timer2).w
    bpl.s   ++
    move.w  #2,(PalCycle_Timer2).w
    lea (CyclingPal_MTZ2).l,a0
    move.w  (PalCycle_Frame2).w,d0
    addq.w  #2,(PalCycle_Frame2).w
    cmpi.w  #6,(PalCycle_Frame2).w
    blo.s   +
    move.w  #0,(PalCycle_Frame2).w
+   lea (Normal_palette_line3+2).w,a1
    move.l  (a0,d0.w),(a1)+
    move.w  4(a0,d0.w),(a1)
+
    subq.w  #1,(PalCycle_Timer3).w
    bpl.s   ++  ; rts
    move.w  #9,(PalCycle_Timer3).w
    lea (CyclingPal_MTZ3).l,a0
    move.w  (PalCycle_Frame3).w,d0
    addq.w  #2,(PalCycle_Frame3).w
    cmpi.w  #$14,(PalCycle_Frame3).w
    blo.s   +
    move.w  #0,(PalCycle_Frame3).w
+   lea (Normal_palette_line3+$1E).w,a1
    move.w  (a0,d0.w),(a1)
+   rts
; ===========================================================================
 
PalCycle_HTZ:
    lea (CyclingPal_Lava).l,a0
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +   ; rts
    move.w  #0,(PalCycle_Timer).w
    move.w  (PalCycle_Frame).w,d0
    addq.w  #1,(PalCycle_Frame).w
    andi.w  #$F,d0
    move.b  PalCycle_HTZ_LavaDelayData(pc,d0.w),(PalCycle_Timer+1).w
    lsl.w   #3,d0
    move.l  (a0,d0.w),(Normal_palette_line2+6).w
    move.l  4(a0,d0.w),(Normal_palette_line2+$1C).w
+   rts
; ===========================================================================
; byte_1B40:
PalCycle_HTZ_LavaDelayData: ; number of frames between changes of the lava palette
    dc.b    $B, $B, $B, $A
    dc.b     8, $A, $B, $B
    dc.b    $B, $B, $D, $F
    dc.b    $D, $B, $B, $B
; ===========================================================================
 
PalCycle_HPZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   ++  ; rts
    move.w  #4,(PalCycle_Timer).w
    lea (CyclingPal_HPZWater).l,a0
    move.w  (PalCycle_Frame).w,d0
    subq.w  #2,(PalCycle_Frame).w
    bcc.s   +
    move.w  #6,(PalCycle_Frame).w
+   lea (Normal_palette_line4+$12).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    lea (CyclingPal_HPZUnderwater).l,a0
    lea (Underwater_palette_line4+$12).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
+   rts
; ===========================================================================
 
PalCycle_OOZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +   ; rts
    move.w  #7,(PalCycle_Timer).w
    lea (CyclingPal_Oil).l,a0
    move.w  (PalCycle_Frame).w,d0
    addq.w  #2,(PalCycle_Frame).w
    andi.w  #6,(PalCycle_Frame).w
    lea (Normal_palette_line3+$14).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
+   rts
; ===========================================================================
 
PalCycle_MCZ:
    tst.b   (Current_Boss_ID).w
    bne.s   +   ; rts
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +   ; rts
    move.w  #1,(PalCycle_Timer).w
    lea (CyclingPal_Lantern).l,a0
    move.w  (PalCycle_Frame).w,d0
    addq.w  #2,(PalCycle_Frame).w
    andi.w  #6,(PalCycle_Frame).w
    move.w  (a0,d0.w),(Normal_palette_line2+$16).w
+   rts
; ===========================================================================
 
PalCycle_CNZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.w   CNZ_SkipToBossPalCycle
    move.w  #7,(PalCycle_Timer).w
    lea (CyclingPal_CNZ1).l,a0
    move.w  (PalCycle_Frame).w,d0
    addq.w  #2,(PalCycle_Frame).w
    cmpi.w  #6,(PalCycle_Frame).w
    blo.s   +
    move.w  #0,(PalCycle_Frame).w
+
    lea (a0,d0.w),a0
    lea (Normal_palette).w,a1
    _move.w 0(a0),$4A(a1)
    move.w  6(a0),$4C(a1)
    move.w  $C(a0),$4E(a1)
    move.w  $12(a0),$56(a1)
    move.w  $18(a0),$58(a1)
    move.w  $1E(a0),$5A(a1)
    lea (CyclingPal_CNZ3).l,a0
    lea (a0,d0.w),a0
    _move.w 0(a0),$64(a1)
    move.w  6(a0),$66(a1)
    move.w  $C(a0),$68(a1)
    lea (CyclingPal_CNZ4).l,a0
    move.w  (PalCycle_Frame_CNZ).w,d0
    addq.w  #2,(PalCycle_Frame_CNZ).w
    cmpi.w  #$24,(PalCycle_Frame_CNZ).w
    blo.s   +
    move.w  #0,(PalCycle_Frame_CNZ).w
+
    lea (Normal_palette_line4+$12).w,a1
    move.w  4(a0,d0.w),(a1)+
    move.w  2(a0,d0.w),(a1)+
    move.w  (a0,d0.w),(a1)+
    
CNZ_SkipToBossPalCycle:
    tst.b   (Current_Boss_ID).w
    beq.w   +++ ; rts
    subq.w  #1,(PalCycle_Timer2).w
    bpl.w   +++ ; rts
    move.w  #3,(PalCycle_Timer2).w
    move.w  (PalCycle_Frame2).w,d0
    addq.w  #2,(PalCycle_Frame2).w
    cmpi.w  #6,(PalCycle_Frame2).w
    blo.s   +
    move.w  #0,(PalCycle_Frame2).w
+   lea (CyclingPal_CNZ1_B).l,a0
    lea (a0,d0.w),a0
    lea (Normal_palette).w,a1
    _move.w 0(a0),$24(a1)
    move.w  6(a0),$26(a1)
    move.w  $C(a0),$28(a1)
    lea (CyclingPal_CNZ2_B).l,a0
    move.w  (PalCycle_Frame3).w,d0
    addq.w  #2,(PalCycle_Frame3).w
    cmpi.w  #$14,(PalCycle_Frame3).w
    blo.s   +
    move.w  #0,(PalCycle_Frame3).w
+   move.w  (a0,d0.w),$3C(a1)
    lea (CyclingPal_CNZ3_B).l,a0
    move.w  (PalCycle_Frame2_CNZ).w,d0
    addq.w  #2,(PalCycle_Frame2_CNZ).w
    andi.w  #$E,(PalCycle_Frame2_CNZ).w
    move.w  (a0,d0.w),$3E(a1)
+   rts
; ===========================================================================
 
PalCycle_CPZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +++ ; rts
    move.w  #7,(PalCycle_Timer).w
    lea (CyclingPal_CPZ1).l,a0
    move.w  (PalCycle_Frame).w,d0
    addq.w  #6,(PalCycle_Frame).w
    cmpi.w  #$36,(PalCycle_Frame).w
    blo.s   +
    move.w  #0,(PalCycle_Frame).w
+   lea (Normal_palette_line4+$18).w,a1
    move.l  (a0,d0.w),(a1)+
    move.w  4(a0,d0.w),(a1)
    lea (CyclingPal_CPZ2).l,a0
    move.w  (PalCycle_Frame2).w,d0
    addq.w  #2,(PalCycle_Frame2).w
    cmpi.w  #$2A,(PalCycle_Frame2).w
    blo.s   +
    move.w  #0,(PalCycle_Frame2).w
+   move.w  (a0,d0.w),(Normal_palette_line4+$1E).w
    lea (CyclingPal_CPZ3).l,a0
    move.w  (PalCycle_Frame3).w,d0
    addq.w  #2,(PalCycle_Frame3).w
    andi.w  #$1E,(PalCycle_Frame3).w
    move.w  (a0,d0.w),(Normal_palette_line3+$1E).w
+   rts
; ===========================================================================
 
PalCycle_ARZ:
    lea (CyclingPal_EHZ_ARZ_Water).l,a0
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +   ; rts
    move.w  #5,(PalCycle_Timer).w
    move.w  (PalCycle_Frame).w,d0
    addq.w  #1,(PalCycle_Frame).w
    andi.w  #3,d0
    lsl.w   #3,d0
    lea (Normal_palette_line3+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
+   rts
; ===========================================================================
 
PalCycle_WFZ:
    subq.w  #1,(PalCycle_Timer).w
    bpl.s   +++
    move.w  #1,(PalCycle_Timer).w
    lea (CyclingPal_WFZFire).l,a0
    tst.b   (WFZ_SCZ_Fire_Toggle).w
    beq.s   +
    move.w  #5,(PalCycle_Timer).w
    lea (CyclingPal_WFZBelt).l,a0
+   move.w  (PalCycle_Frame).w,d0
    addq.w  #8,(PalCycle_Frame).w
    cmpi.w  #$20,(PalCycle_Frame).w
    blo.s   +
    move.w  #0,(PalCycle_Frame).w
+   lea (Normal_palette_line3+$E).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
+   subq.w  #1,(PalCycle_Timer2).w
    bpl.s   ++  ; subq.w
    move.w  #3,(PalCycle_Timer2).w
    lea (CyclingPal_WFZ1).l,a0
    move.w  (PalCycle_Frame2).w,d0
    addq.w  #2,(PalCycle_Frame2).w
    cmpi.w  #$44,(PalCycle_Frame2).w
    blo.s   +   ; move.w
    move.w  #0,(PalCycle_Frame2).w
+   move.w  (a0,d0.w),(Normal_palette_line3+$1C).w
+
    subq.w  #1,(PalCycle_Timer3).w
    bpl.s   ++  ; rts
    move.w  #5,(PalCycle_Timer3).w
    lea (CyclingPal_WFZ2).l,a0
    move.w  (PalCycle_Frame3).w,d0
    addq.w  #2,(PalCycle_Frame3).w
    cmpi.w  #$18,(PalCycle_Frame3).w
    blo.s   +
    move.w  #0,(PalCycle_Frame3).w
+   move.w  (a0,d0.w),(Normal_palette_line3+$1E).w
+   rts
; ===========================================================================
 
; ----------------------------------------------------------------------------
; word_1E5A:
    BINCLUDE "art/palettes/Title Water.bin"; S1 Title Screen Water palette (unused)
; word_1E7A:
CyclingPal_EHZ_ARZ_Water:
    BINCLUDE "art/palettes/EHZ ARZ Water.bin"; Emerald Hill/Aquatic Ruin Rotating Water palette
; word_1E9A:
CyclingPal_Lava:
    BINCLUDE "art/palettes/Hill Top Lava.bin"; Hill Top Lava palette
; word_1F1A:
CyclingPal_WoodConveyor:
    BINCLUDE "art/palettes/Wood Conveyor.bin"; Wood Conveyor Belts palette
; byte_1F2A:
CyclingPal_MTZ1:
    BINCLUDE "art/palettes/MTZ Cycle 1.bin"; Metropolis Cycle #1 palette
; word_1F36:
CyclingPal_MTZ2:
    BINCLUDE "art/palettes/MTZ Cycle 2.bin"; Metropolis Cycle #2 palette
; word_1F42:
CyclingPal_MTZ3:
    BINCLUDE "art/palettes/MTZ Cycle 3.bin"; Metropolis Cycle #3 palette
; word_1F56:
CyclingPal_HPZWater:
    BINCLUDE "art/palettes/HPZ Water Cycle.bin"; Hidden Palace Water Cycle
; word_1F66:
CyclingPal_HPZUnderwater:
    BINCLUDE "art/palettes/HPZ Underwater Cycle.bin"; Hidden Palace Underwater Cycle
; word_1F76:
CyclingPal_Oil:
    BINCLUDE "art/palettes/OOZ Oil.bin"; Oil Ocean Oil palette
; word_1F86:
CyclingPal_Lantern:
    BINCLUDE "art/palettes/MCZ Lantern.bin"; Mystic Cave Lanterns
; word_1F8E:
CyclingPal_CNZ1:
    BINCLUDE "art/palettes/CNZ Cycle 1.bin"; Casino Night Cycles 1 & 2
; word_1FB2:
CyclingPal_CNZ3:
    BINCLUDE "art/palettes/CNZ Cycle 3.bin"; Casino Night Cycle 3
; word_1FC4:
CyclingPal_CNZ4:
    BINCLUDE "art/palettes/CNZ Cycle 4.bin"; Casino Night Cycle 4
; word_1FEC:
CyclingPal_CNZ1_B:
    BINCLUDE "art/palettes/CNZ Boss Cycle 1.bin"; Casino Night Boss Cycle 1
; word_1FFE:
CyclingPal_CNZ2_B:
    BINCLUDE "art/palettes/CNZ Boss Cycle 2.bin"; Casino Night Boss Cycle 2
; word_2012:
CyclingPal_CNZ3_B:
    BINCLUDE "art/palettes/CNZ Boss Cycle 3.bin"; Casino Night Boss Cycle 3
; word_2022:
CyclingPal_CPZ1:
    BINCLUDE "art/palettes/CPZ Cycle 1.bin"; Chemical Plant Cycle 1
; word_2058:
CyclingPal_CPZ2:
    BINCLUDE "art/palettes/CPZ Cycle 2.bin"; Chemical Plant Cycle 2
; word_2082:
CyclingPal_CPZ3:
    BINCLUDE "art/palettes/CPZ Cycle 3.bin"; Chemical Plant Cycle 3
; word_20A2:
CyclingPal_WFZFire:
    BINCLUDE "art/palettes/WFZ Fire Cycle.bin"; Wing Fortress Fire Cycle palette
; word_20C2:
CyclingPal_WFZBelt:
    BINCLUDE "art/palettes/WFZ Conveyor Cycle.bin"; Wing Fortress Conveyor Belt Cycle palette
; word_20E2: CyclingPal_CPZ4:
CyclingPal_WFZ1:
    BINCLUDE "art/palettes/WFZ Cycle 1.bin"; Wing Fortress Flashing Light Cycle 1
; word_2126:
CyclingPal_WFZ2:
    BINCLUDE "art/palettes/WFZ Cycle 2.bin"; Wing Fortress Flashing Light Cycle 2
; ----------------------------------------------------------------------------
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_213E:
PalCycle_SuperSonic:
    move.b  (Super_Sonic_palette).w,d0
    beq.s   ++  ; rts   ; return, if Sonic isn't super
    bmi.w   PalCycle_SuperSonic_normal  ; branch, if fade-in is done
    subq.b  #1,d0
    bne.s   PalCycle_SuperSonic_revert  ; branch for values greater than 1
 
    ; fade from Sonic's to Super Sonic's palette
    ; run frame timer
    subq.b  #1,(Palette_timer).w
    bpl.s   ++  ; rts
    move.b  #3,(Palette_timer).w
 
    ; increment palette frame and update Sonic's palette
    lea (CyclingPal_SSTransformation).l,a0
    move.w  (Palette_frame).w,d0
    addq.w  #8,(Palette_frame).w    ; 1 palette entry = 1 word, Sonic uses 4 shades of blue
    cmpi.w  #$30,(Palette_frame).w  ; has palette cycle reached the 6th frame?
    blo.s   +           ; if not, branch
    move.b  #-1,(Super_Sonic_palette).w ; mark fade-in as done
    move.b  #0,(MainCharacter+obj_control).w    ; restore Sonic's movement
+
    lea (Normal_palette+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    ; note: the fade in for Sonic's underwater palette is missing.
    ; branch to the code below (*) to fix this
/   rts
; ===========================================================================
; loc_2188:
PalCycle_SuperSonic_revert: ; runs the fade in transition backwards
    ; run frame timer
    subq.b  #1,(Palette_timer).w
    bpl.s   -   ; rts
    move.b  #3,(Palette_timer).w
 
    ; decrement palette frame and update Sonic's palette
    lea (CyclingPal_SSTransformation).l,a0
    move.w  (Palette_frame).w,d0
    subq.w  #8,(Palette_frame).w    ; previous frame
    bcc.s   +           ; branch, if it isn't the first frame
    move.b  #0,(Palette_frame).w
    move.b  #0,(Super_Sonic_palette).w  ; stop palette cycle
+
    lea (Normal_palette+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    ; underwater palettes (*)
    lea (CyclingPal_CPZUWTransformation).l,a0
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.s   +
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   -   ; rts
    lea (CyclingPal_ARZUWTransformation).l,a0
+   lea (Underwater_palette+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    rts
; ===========================================================================
; loc_21E6:
PalCycle_SuperSonic_normal:
    ; run frame timer
    subq.b  #1,(Palette_timer).w
    bpl.s   -   ; rts
    move.b  #7,(Palette_timer).w
 
    ; increment palette frame and update Sonic's palette
    lea (CyclingPal_SSTransformation).l,a0
    move.w  (Palette_frame).w,d0
    addq.w  #8,(Palette_frame).w    ; next frame
    cmpi.w  #$78,(Palette_frame).w  ; is it the last frame?
    blo.s   +           ; if not, branch
    move.w  #$30,(Palette_frame).w  ; reset frame counter (Super Sonic's normal palette cycle starts at $30. Everything before that is for the palette fade)
+
    lea (Normal_palette+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    ; underwater palettes
    lea (CyclingPal_CPZUWTransformation).l,a0
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.s   +
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.w   -   ; rts
    lea (CyclingPal_ARZUWTransformation).l,a0
+   lea (Underwater_palette+4).w,a1
    move.l  (a0,d0.w),(a1)+
    move.l  4(a0,d0.w),(a1)
    rts
; End of function PalCycle_SuperSonic
 
; ===========================================================================
;----------------------------------------------------------------------------
;Palette for transformation to Super Sonic
;----------------------------------------------------------------------------
; Pal_2246:
CyclingPal_SSTransformation:
    BINCLUDE    "art/palettes/Super Sonic transformation.bin"
;----------------------------------------------------------------------------
;Palette for transformation to Super Sonic while underwater in CPZ
;----------------------------------------------------------------------------
; Pal_22C6:
CyclingPal_CPZUWTransformation:
    BINCLUDE    "art/palettes/CPZWater SS transformation.bin"
;----------------------------------------------------------------------------
;Palette for transformation to Super Sonic while underwater in ARZ
;----------------------------------------------------------------------------
; Pal_2346:
CyclingPal_ARZUWTransformation:
    BINCLUDE    "art/palettes/ARZWater SS transformation.bin"
 
; ---------------------------------------------------------------------------
; Subroutine to fade in from black
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_23C6: Pal_FadeTo:
Pal_FadeFromBlack:
    move.w  #$3F,(Palette_fade_range).w
    moveq   #0,d0
    lea (Normal_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    moveq   #0,d1
    move.b  (Palette_fade_length).w,d0
; loc_23DE: Pal_ToBlack:
.palettewrite:
    move.w  d1,(a0)+
    dbf d0,.palettewrite    ; fill palette with $000 (black)
 
    move.w  #$15,d4
.nextframe:
    move.b  #VintID_Fade,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.s   .UpdateAllColours
    bsr.w   RunPLC_RAM
    dbf d4,.nextframe
 
    rts
; End of function Pal_FadeFromBlack
 
; ---------------------------------------------------------------------------
; Subroutine to update all colours once
; ---------------------------------------------------------------------------
; sub_23FE: Pal_FadeIn:
.UpdateAllColours:
    ; Update above-water palette
    moveq   #0,d0
    lea (Normal_palette).w,a0
    lea (Target_palette).w,a1
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    adda.w  d0,a1
 
    move.b  (Palette_fade_length).w,d0
.nextcolour:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour
 
    tst.b   (Water_flag).w
    beq.s   .skipunderwater
    ; Update underwater palette
    moveq   #0,d0
    lea (Underwater_palette).w,a0
    lea (Underwater_target_palette).w,a1
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    adda.w  d0,a1
 
    move.b  (Palette_fade_length).w,d0
.nextcolour2:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour2
 
.skipunderwater:
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to update a single colour once
; ---------------------------------------------------------------------------
; sub_243E: Pal_AddColor:
.UpdateColour:
    move.w  (a1)+,d2
    move.w  (a0),d3
    cmp.w   d2,d3
    beq.s   .updatenone
;.updateblue:
    move.w  d3,d1
    addi.w  #$200,d1    ; increase blue value
    cmp.w   d2,d1       ; has blue reached threshold level?
    bhi.s   .updategreen    ; if yes, branch
    move.w  d1,(a0)+    ; update palette
    rts
 
; loc_2454: Pal_AddGreen:
.updategreen:
    move.w  d3,d1
    addi.w  #$20,d1     ; increase green value
    cmp.w   d2,d1
    bhi.s   .updatered
    move.w  d1,(a0)+    ; update palette
    rts
 
; loc_2462: Pal_AddRed:
.updatered:
    addq.w  #2,(a0)+    ; increase red value
    rts
 
; loc_2466: Pal_AddNone:
.updatenone:
    addq.w  #2,a0
    rts
 
 
; ---------------------------------------------------------------------------
; Subroutine to fade out to black
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_246A: Pal_FadeFrom:
Pal_FadeToBlack:
    move.w  #$3F,(Palette_fade_range).w
 
    move.w  #$15,d4
.nextframe:
    move.b  #VintID_Fade,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.s   .UpdateAllColours
    bsr.w   RunPLC_RAM
    dbf d4,.nextframe
 
    rts
; End of function Pal_FadeToBlack
 
; ---------------------------------------------------------------------------
; Subroutine to update all colours once
; ---------------------------------------------------------------------------
; sub_248A: Pal_FadeOut:
.UpdateAllColours:
    ; Update above-water palette
    moveq   #0,d0
    lea (Normal_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
 
    move.b  (Palette_fade_length).w,d0
.nextcolour:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour
 
    ; Notice how this one lacks a check for
    ; if Water_flag is set, unlike Pal_FadeFromBlack?
 
    ; Update underwater palette
    moveq   #0,d0
    lea (Underwater_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
 
    move.b  (Palette_fade_length).w,d0
.nextcolour2:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour2
 
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to update a single colour once
; ---------------------------------------------------------------------------
; sub_24B8: Pal_DecColor:
.UpdateColour:
    move.w  (a0),d2
    beq.s   .updatenone
;.updatered:
    move.w  d2,d1
    andi.w  #$E,d1
    beq.s   .updategreen
    subq.w  #2,(a0)+    ; decrease red value
    rts
 
; loc_24C8: Pal_DecGreen:
.updategreen:
    move.w  d2,d1
    andi.w  #$E0,d1
    beq.s   .updateblue
    subi.w  #$20,(a0)+  ; decrease green value
    rts
 
; loc_24D6: Pal_DecBlue:
.updateblue:
    move.w  d2,d1
    andi.w  #$E00,d1
    beq.s   .updatenone
    subi.w  #$200,(a0)+ ; decrease blue value
    rts
 
; loc_24E4: Pal_DecNone:
.updatenone:
    addq.w  #2,a0
    rts
 
 
; ---------------------------------------------------------------------------
; Subroutine to fade in from white
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_24E8: Pal_MakeWhite:
Pal_FadeFromWhite:
    move.w  #$3F,(Palette_fade_range).w
    moveq   #0,d0
    lea (Normal_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    move.w  #$EEE,d1
 
    move.b  (Palette_fade_length).w,d0
.palettewrite:
    move.w  d1,(a0)+
    dbf d0,.palettewrite
 
    move.w  #$15,d4
.nextframe:
    move.b  #VintID_Fade,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.s   .UpdateAllColours
    bsr.w   RunPLC_RAM
    dbf d4,.nextframe
 
    rts
; End of function Pal_FadeFromWhite
 
; ---------------------------------------------------------------------------
; Subroutine to update all colours once
; ---------------------------------------------------------------------------
; sub_2522: Pal_WhiteToBlack:
.UpdateAllColours:
    ; Update above-water palette
    moveq   #0,d0
    lea (Normal_palette).w,a0
    lea (Target_palette).w,a1
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    adda.w  d0,a1
 
    move.b  (Palette_fade_length).w,d0
.nextcolour:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour
 
    tst.b   (Water_flag).w
    beq.s   .skipunderwater
    ; Update underwater palette
    moveq   #0,d0
    lea (Underwater_palette).w,a0
    lea (Underwater_target_palette).w,a1
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
    adda.w  d0,a1
 
    move.b  (Palette_fade_length).w,d0
.nextcolour2:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour2
 
.skipunderwater:
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to update a single colour once
; ---------------------------------------------------------------------------
; sub_2562: Pal_DecColor2:
.UpdateColour:
    move.w  (a1)+,d2
    move.w  (a0),d3
    cmp.w   d2,d3
    beq.s   .updatenone
;.updateblue:
    move.w  d3,d1
    subi.w  #$200,d1    ; decrease blue value
    bcs.s   .updategreen
    cmp.w   d2,d1
    blo.s   .updategreen
    move.w  d1,(a0)+
    rts
 
; loc_257A: Pal_DecGreen2:
.updategreen:
    move.w  d3,d1
    subi.w  #$20,d1 ; decrease green value
    bcs.s   .updatered
    cmp.w   d2,d1
    blo.s   .updatered
    move.w  d1,(a0)+
    rts
 
; loc_258A: Pal_DecRed2:
.updatered:
    subq.w  #2,(a0)+    ; decrease red value
    rts
 
; loc_258E: Pal_DecNone2:
.updatenone:
    addq.w  #2,a0
    rts
 
 
; ---------------------------------------------------------------------------
; Subroutine to fade out to white (used when you enter a special stage)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_2592: Pal_MakeFlash:
Pal_FadeToWhite:
    move.w  #$3F,(Palette_fade_range).w
 
    move.w  #$15,d4
.nextframe:
    move.b  #VintID_Fade,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.s   .UpdateAllColours
    bsr.w   RunPLC_RAM
    dbf d4,.nextframe
 
    rts
; End of function Pal_FadeToWhite
 
; ---------------------------------------------------------------------------
; Subroutine to update all colours once
; ---------------------------------------------------------------------------
; sub_25B2: Pal_ToWhite:
.UpdateAllColours:
    ; Update above-water palette
    moveq   #0,d0
    lea (Normal_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
 
    move.b  (Palette_fade_length).w,d0
.nextcolour:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour
 
    ; Notice how this one lacks a check for
    ; if Water_flag is set, unlike Pal_FadeFromWhite?
 
    ; Update underwater palette
    moveq   #0,d0
    lea (Underwater_palette).w,a0
    move.b  (Palette_fade_start).w,d0
    adda.w  d0,a0
 
    move.b  (Palette_fade_length).w,d0
.nextcolour2:
    bsr.s   .UpdateColour
    dbf d0,.nextcolour2
 
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to update a single colour once
; ---------------------------------------------------------------------------
; sub_25E0: Pal_AddColor2:
.UpdateColour:
    move.w  (a0),d2
    cmpi.w  #$EEE,d2
    beq.s   .updatenone
;.updatered:
    move.w  d2,d1
    andi.w  #$E,d1
    cmpi.w  #$E,d1
    beq.s   .updategreen
    addq.w  #2,(a0)+    ; increase red value
    rts
 
; loc_25F8: Pal_AddGreen2:
.updategreen:
    move.w  d2,d1
    andi.w  #$E0,d1
    cmpi.w  #$E0,d1
    beq.s   .updateblue
    addi.w  #$20,(a0)+  ; increase green value
    rts
 
; loc_260A: Pal_AddBlue2:
.updateblue:
    move.w  d2,d1
    andi.w  #$E00,d1
    cmpi.w  #$E00,d1
    beq.s   .updatenone
    addi.w  #$200,(a0)+ ; increase blue value
    rts
 
; loc_261C: Pal_AddNone2:
.updatenone:
    addq.w  #2,a0
    rts
; End of function Pal_AddColor2
 
 
; Unused - dead code/data for old SEGA screen:
 
; ===========================================================================
; PalCycle_Sega:
    tst.b   (PalCycle_Timer+1).w
    bne.s   loc_2680
    lea (Normal_palette_line2).w,a1
    lea (Pal_Sega1).l,a0
    moveq   #5,d1
    move.w  (PalCycle_Frame).w,d0
 
loc_2636:
    bpl.s   loc_2640
    addq.w  #2,a0
    subq.w  #1,d1
    addq.w  #2,d0
    bra.s   loc_2636
; ===========================================================================
 
loc_2640:
    move.w  d0,d2
    andi.w  #$1E,d2
    bne.s   loc_264A
    addq.w  #2,d0
 
loc_264A:
    cmpi.w  #$60,d0
    bhs.s   loc_2654
    move.w  (a0)+,(a1,d0.w)
 
loc_2654:
    addq.w  #2,d0
    dbf d1,loc_2640
    move.w  (PalCycle_Frame).w,d0
    addq.w  #2,d0
    move.w  d0,d2
    andi.w  #$1E,d2
    bne.s   loc_266A
    addq.w  #2,d0
 
loc_266A:
    cmpi.w  #$64,d0
    blt.s   loc_2678
    move.w  #$401,(PalCycle_Timer).w
    moveq   #-$C,d0
 
loc_2678:
    move.w  d0,(PalCycle_Frame).w
    moveq   #1,d0
    rts
; ===========================================================================
 
loc_2680:
    subq.b  #1,(PalCycle_Timer).w
    bpl.s   loc_26D2
    move.b  #4,(PalCycle_Timer).w
    move.w  (PalCycle_Frame).w,d0
    addi.w  #$C,d0
    cmpi.w  #$30,d0
    blo.s   loc_269E
    moveq   #0,d0
    rts
; ===========================================================================
 
loc_269E:
    move.w  d0,(PalCycle_Frame).w
    lea (Pal_Sega2).l,a0
    lea (a0,d0.w),a0
    lea (Normal_palette+4).w,a1
    move.l  (a0)+,(a1)+
    move.l  (a0)+,(a1)+
    move.w  (a0)+,(a1)
    lea (Normal_palette_line2).w,a1
    moveq   #0,d0
    moveq   #$2C,d1
 
loc_26BE:
    move.w  d0,d2
    andi.w  #$1E,d2
    bne.s   loc_26C8
    addq.w  #2,d0
 
loc_26C8:
    move.w  (a0),(a1,d0.w)
    addq.w  #2,d0
    dbf d1,loc_26BE
 
loc_26D2:
    moveq   #1,d0
    rts
 
; ===========================================================================
;----------------------------------------------------------------------------
; Unused palette for the Sega logo
;----------------------------------------------------------------------------
; Pal_26D6:
Pal_Sega1:  BINCLUDE    "art/palettes/Unused Sega logo.bin"
;----------------------------------------------------------------------------
; Unused palette for the Sega logo (fading?)
;----------------------------------------------------------------------------
; Pal_26E2:
Pal_Sega2:  BINCLUDE    "art/palettes/Unused Sega logo 2.bin"
 
; end of dead code/data
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_2712: PalLoad1:
PalLoad_ForFade:
    lea (PalPointers).l,a1
    lsl.w   #3,d0
    adda.w  d0,a1
    movea.l (a1)+,a2
    movea.w (a1)+,a3
    adda.w  #Target_palette-Normal_palette,a3
 
    move.w  (a1)+,d7
-   move.l  (a2)+,(a3)+
    dbf d7,-
 
    rts
; End of function PalLoad_ForFade
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_272E: PalLoad2:
PalLoad_Now:
    lea (PalPointers).l,a1
    lsl.w   #3,d0
    adda.w  d0,a1
    movea.l (a1)+,a2
    movea.w (a1)+,a3
 
    move.w  (a1)+,d7
-   move.l  (a2)+,(a3)+
    dbf d7,-
 
    rts
; End of function PalLoad_Now
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_2746: PalLoad3_Water:
PalLoad_Water_Now:
    lea (PalPointers).l,a1
    lsl.w   #3,d0
    adda.w  d0,a1
    movea.l (a1)+,a2
    movea.w (a1)+,a3
    suba.l  #Normal_palette-Underwater_palette,a3
 
    move.w  (a1)+,d7
-   move.l  (a2)+,(a3)+
    dbf d7,-
 
    rts
; End of function PalLoad_Water_Now
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_2764: PalLoad4_Water:
PalLoad_Water_ForFade:
    lea (PalPointers).l,a1
    lsl.w   #3,d0
    adda.w  d0,a1
    movea.l (a1)+,a2
    movea.w (a1)+,a3
    suba.l  #Normal_palette-Underwater_target_palette,a3
 
    move.w  (a1)+,d7
-   move.l  (a2)+,(a3)+
    dbf d7,-
 
    rts
; End of function PalLoad_Water_ForFade
 
; ===========================================================================
;----------------------------------------------------------------------------
; Palette pointers
; (PALETTE DESCRIPTOR ARRAY)
; This struct array defines the palette to use for each level.
;----------------------------------------------------------------------------
 
palptr  macro   ptr,lineno
    dc.l ptr    ; Pointer to palette
    dc.w (Normal_palette+lineno*palette_line_size)&$FFFF    ; Location in ram to load palette into
    dc.w bytesToLcnt(ptr_End-ptr)   ; Size of palette in (bytes / 4)
    endm
 
PalPointers:
PalPtr_SEGA:    palptr Pal_SEGA,  0
PalPtr_Title:   palptr Pal_Title, 1
PalPtr_MenuB:   palptr Pal_MenuB, 0
PalPtr_BGND:    palptr Pal_BGND,  0
PalPtr_EHZ: palptr Pal_EHZ,   1
PalPtr_EHZ2:    palptr Pal_EHZ,   1
PalPtr_WZ:  palptr Pal_WZ,    1
PalPtr_EHZ3:    palptr Pal_EHZ,   1
PalPtr_MTZ: palptr Pal_MTZ,   1
PalPtr_MTZ2:    palptr Pal_MTZ,   1
PalPtr_WFZ: palptr Pal_WFZ,   1
PalPtr_HTZ: palptr Pal_HTZ,   1
PalPtr_HPZ: palptr Pal_HPZ,   1
PalPtr_EHZ4:    palptr Pal_EHZ,   1
PalPtr_OOZ: palptr Pal_OOZ,   1
PalPtr_MCZ: palptr Pal_MCZ,   1
PalPtr_CNZ: palptr Pal_CNZ,   1
PalPtr_CPZ: palptr Pal_CPZ,   1
PalPtr_DEZ: palptr Pal_DEZ,   1
PalPtr_ARZ: palptr Pal_ARZ,   1
PalPtr_SCZ: palptr Pal_SCZ,   1
PalPtr_HPZ_U:   palptr Pal_HPZ_U, 0
PalPtr_CPZ_U:   palptr Pal_CPZ_U, 0
PalPtr_ARZ_U:   palptr Pal_ARZ_U, 0
PalPtr_SS:  palptr Pal_SS,    0
PalPtr_MCZ_B:   palptr Pal_MCZ_B, 1
PalPtr_CNZ_B:   palptr Pal_CNZ_B, 1
PalPtr_SS1: palptr Pal_SS1,   3
PalPtr_SS2: palptr Pal_SS2,   3
PalPtr_SS3: palptr Pal_SS3,   3
PalPtr_SS4: palptr Pal_SS4,   3
PalPtr_SS5: palptr Pal_SS5,   3
PalPtr_SS6: palptr Pal_SS6,   3
PalPtr_SS7: palptr Pal_SS7,   3
PalPtr_SS1_2p:  palptr Pal_SS1_2p,3
PalPtr_SS2_2p:  palptr Pal_SS2_2p,3
PalPtr_SS3_2p:  palptr Pal_SS3_2p,3
PalPtr_OOZ_B:   palptr Pal_OOZ_B, 1
PalPtr_Menu:    palptr Pal_Menu,  0
PalPtr_Result:  palptr Pal_Result,0
 
; ----------------------------------------------------------------------------
; This macro defines Pal_ABC and Pal_ABC_End, so palptr can compute the size of
; the palette automatically
; path2 is used for the Sonic and Tails palette, which has 2 palette lines
palette macro {INTLABEL},path,path2
__LABEL__ label *
    BINCLUDE "art/palettes/path"
    if "path2"<>""
    BINCLUDE "art/palettes/path2"
    endif
__LABEL___End label *
    endm
 
Pal_SEGA:  palette Sega screen.bin ; SEGA screen palette (Sonic and initial background)
Pal_Title: palette Title screen.bin ; Title screen Palette
Pal_MenuB: palette S2B Level Select.bin ; Leftover S2B level select palette
Pal_BGND:  palette SonicAndTails.bin,SonicAndTails2.bin ; "Sonic and Miles" background palette (also usually the primary palette line)
Pal_EHZ:   palette EHZ.bin ; Emerald Hill Zone palette
Pal_WZ:    palette Wood Zone.bin ; Wood Zone palette
Pal_MTZ:   palette MTZ.bin ; Metropolis Zone palette
Pal_WFZ:   palette WFZ.bin ; Wing Fortress Zone palette
Pal_HTZ:   palette HTZ.bin ; Hill Top Zone palette
Pal_HPZ:   palette HPZ.bin ; Hidden Palace Zone palette
Pal_HPZ_U: palette HPZ underwater.bin ; Hidden Palace Zone underwater palette
Pal_OOZ:   palette OOZ.bin ; Oil Ocean Zone palette
Pal_MCZ:   palette MCZ.bin ; Mystic Cave Zone palette
Pal_CNZ:   palette CNZ.bin ; Casino Night Zone palette
Pal_CPZ:   palette CPZ.bin ; Chemical Plant Zone palette
Pal_CPZ_U: palette CPZ underwater.bin ; Chemical Plant Zone underwater palette
Pal_DEZ:   palette DEZ.bin ; Death Egg Zone palette
Pal_ARZ:   palette ARZ.bin ; Aquatic Ruin Zone palette
Pal_ARZ_U: palette ARZ underwater.bin ; Aquatic Ruin Zone underwater palette
Pal_SCZ:   palette SCZ.bin ; Sky Chase Zone palette
Pal_MCZ_B: palette MCZ Boss.bin ; Mystic Cave Zone boss palette
Pal_CNZ_B: palette CNZ Boss.bin ; Casino Night Zone boss palette
Pal_OOZ_B: palette OOZ Boss.bin ; Oil Ocean Zone boss palette
Pal_Menu:  palette Menu.bin ; Menu palette
Pal_SS:    palette Special Stage Main.bin ; Special Stage palette
Pal_SS1:   palette Special Stage 1.bin ; Special Stage 1 palette
Pal_SS2:   palette Special Stage 2.bin ; Special Stage 2 palette
Pal_SS3:   palette Special Stage 3.bin ; Special Stage 3 palette
Pal_SS4:   palette Special Stage 4.bin ; Special Stage 4 palette
Pal_SS5:   palette Special Stage 5.bin ; Special Stage 5 palette
Pal_SS6:   palette Special Stage 6.bin ; Special Stage 6 palette
Pal_SS7:   palette Special Stage 7.bin ; Special Stage 7 palette
Pal_SS1_2p:palette Special Stage 1 2p.bin ; Special Stage 1 2p palette
Pal_SS2_2p:palette Special Stage 2 2p.bin ; Special Stage 2 2p palette
Pal_SS3_2p:palette Special Stage 3 2p.bin ; Special Stage 3 2p palette
Pal_Result:palette Special Stage Results Screen.bin ; Special Stage Results Screen palette
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to perform vertical synchronization
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_3384: DelayProgram:
WaitForVint:
    move    #$2300,sr
 
-   tst.b   (Vint_routine).w
    bne.s   -
    rts
; End of function WaitForVint
 
 
; ---------------------------------------------------------------------------
; Subroutine to generate a pseudo-random number in d0
; d0 = (RNG & $FFFF0000) | ((RNG*41 & $FFFF) + ((RNG*41 & $FFFF0000) >> 16))
; RNG = ((RNG*41 + ((RNG*41 & $FFFF) << 16)) & $FFFF0000) | (RNG*41 & $FFFF)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_3390:
RandomNumber:
    move.l  (RNG_seed).w,d1
    bne.s   +
    move.l  #$2A6D365A,d1 ; if the RNG is 0, reset it to this crazy number
 
    ; set the high word of d0 to be the high word of the RNG
    ; and multiply the RNG by 41
+   move.l  d1,d0
    asl.l   #2,d1
    add.l   d0,d1
    asl.l   #3,d1
    add.l   d0,d1
 
    ; add the low word of the RNG to the high word of the RNG
    ; and set the low word of d0 to be the result
    move.w  d1,d0
    swap    d1
    add.w   d1,d0
    move.w  d0,d1
    swap    d1
 
    move.l  d1,(RNG_seed).w
    rts
; End of function RandomNumber
 
 
; ---------------------------------------------------------------------------
; Subroutine to calculate sine and cosine of an angle
; d0 = input byte = angle (360 degrees == 256)
; d0 = output word = 255 * sine(angle)
; d1 = output word = 255 * cosine(angle)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_33B6:
CalcSine:
    andi.w  #$FF,d0
    add.w   d0,d0
    addi.w  #$80,d0
    move.w  Sine_Data(pc,d0.w),d1 ; cos
    subi.w  #$80,d0
    move.w  Sine_Data(pc,d0.w),d0 ; sin
    rts
; End of function CalcSine
 
; ===========================================================================
; word_33CE:
Sine_Data:  BINCLUDE    "misc/sinewave.bin"
 
 
; ---------------------------------------------------------------------------
; Subroutine to calculate arctangent of y/x
; d1 = input x
; d2 = input y
; d0 = output angle (360 degrees == 256)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_364E:
CalcAngle:
    movem.l d3-d4,-(sp)
    moveq   #0,d3
    moveq   #0,d4
    move.w  d1,d3
    move.w  d2,d4
    or.w    d3,d4
    beq.s   CalcAngle_Zero ; special case return if x and y are both 0
    move.w  d2,d4
 
    absw.w  d3  ; calculate absolute value of x
    absw.w  d4  ; calculate absolute value of y
    cmp.w   d3,d4
    bhs.w   +
    lsl.l   #8,d4
    divu.w  d3,d4
    moveq   #0,d0
    move.b  Angle_Data(pc,d4.w),d0
    bra.s   ++
+
    lsl.l   #8,d3
    divu.w  d4,d3
    moveq   #$40,d0
    sub.b   Angle_Data(pc,d3.w),d0
+
    tst.w   d1
    bpl.w   +
    neg.w   d0
    addi.w  #$80,d0
+
    tst.w   d2
    bpl.w   +
    neg.w   d0
    addi.w  #$100,d0
+
    movem.l (sp)+,d3-d4
    rts
; ===========================================================================
; loc_36AA:
CalcAngle_Zero:
    move.w  #$40,d0
    movem.l (sp)+,d3-d4
    rts
; End of function CalcAngle
 
; ===========================================================================
; byte_36B4:
Angle_Data: BINCLUDE    "misc/angles.bin"
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; loc_37B8:
SegaScreen:
    move.b  #MusID_Stop,d0
    bsr.w   PlayMusic ; stop music
    bsr.w   ClearPLC
    bsr.w   Pal_FadeToBlack
 
    clearRAM Misc_Variables,Misc_Variables_End
 
    clearRAM SegaScr_Object_RAM,SegaScr_Object_RAM_End ; fill object RAM with 0
 
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8200|(VRAM_SegaScr_Plane_A_Name_Table/$400),(a6)  ; PNT A base: $C000
    move.w  #$8400|(VRAM_SegaScr_Plane_B_Name_Table/$2000),(a6) ; PNT B base: $A000
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    move.w  #$9003,(a6)     ; Scroll table size: 128x32 ($2000 bytes)
    clr.b   (Water_fullscreen_flag).w
    clr.w   (Two_player_mode).w
    move    #$2700,sr
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   ClearScreen
 
    dmaFillVRAM 0,VRAM_SegaScr_Plane_A_Name_Table,VRAM_SegaScr_Plane_Table_Size ; clear Plane A pattern name table
 
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Sega_Logo),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_SEGA).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Trails),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_IntroTrails).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtUnc_Giant_Sonic),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_SilverSonic).l,a0 ; ?? seems unused here
    bsr.w   NemDec
    lea (Chunk_Table).l,a1
    lea (MapEng_SEGA).l,a0
    move.w  #make_art_tile(ArtTile_VRAM_Start,0,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_SegaScr_Plane_B_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1     ; 40 cells wide
    moveq   #$1B,d2     ; 28 cells tall
    bsr.w   PlaneMapToVRAM_H80_Sega
    tst.b   (Graphics_Flags).w ; are we on a Japanese Mega Drive?
    bmi.s   SegaScreen_Contin ; if not, branch
    ; load an extra sprite to hide the TM (trademark) symbol on the SEGA screen
    lea (SegaHideTM).w,a1
    move.b  #ObjID_SegaHideTM,id(a1)    ; load objB1 at $FFFFB080
    move.b  #$4E,subtype(a1) ; <== ObjB1_SubObjData
; loc_38CE:
SegaScreen_Contin:
    moveq   #PalID_SEGA,d0
    bsr.w   PalLoad_Now
    move.w  #-$A,(PalCycle_Frame).w
    move.w  #0,(PalCycle_Timer).w
    move.w  #0,(SegaScr_VInt_Subrout).w
    move.w  #0,(SegaScr_PalDone_Flag).w
    lea (SegaScreenObject).w,a1
    move.b  #ObjID_SonicOnSegaScr,id(a1) ; load objB0 (sega screen?) at $FFFFB040
    move.b  #$4C,subtype(a1) ; <== ObjB0_SubObjData
    move.w  #4*60,(Demo_Time_left).w    ; 4 seconds
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
; loc_390E:
Sega_WaitPalette:
    move.b  #VintID_SEGA,(Vint_routine).w
    bsr.w   WaitForVint
    jsrto   (RunObjects).l, JmpTo_RunObjects
    jsr (BuildSprites).l
    tst.b   (SegaScr_PalDone_Flag).w
    beq.s   Sega_WaitPalette
    move.b  #SndID_SegaSound,d0
    bsr.w   PlaySound   ; play "SEGA" sound
    move.b  #VintID_SEGA,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  #3*60,(Demo_Time_left).w    ; 3 seconds
; loc_3940:
Sega_WaitEnd:
    move.b  #VintID_PCM,(Vint_routine).w
    bsr.w   WaitForVint
    tst.w   (Demo_Time_left).w
    beq.s   Sega_GotoTitle
    move.b  (Ctrl_1_Press).w,d0 ; is Start button pressed?
    or.b    (Ctrl_2_Press).w,d0 ; (either player)
    andi.b  #button_start_mask,d0
    beq.s   Sega_WaitEnd        ; if not, branch
; loc_395E:
Sega_GotoTitle:
    clr.w   (SegaScr_PalDone_Flag).w
    clr.w   (SegaScr_VInt_Subrout).w
    move.b  #GameModeID_TitleScreen,(Game_Mode).w   ; => TitleScreen
    rts
 
; ---------------------------------------------------------------------------
; Subroutine that does the exact same thing as PlaneMapToVRAM_H80_SpecialStage
; (this one is used at the Sega screen)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_396E: ShowVDPGraphics3: PlaneMapToVRAM3:
PlaneMapToVRAM_H80_Sega:
    lea (VDP_data_port).l,a6
    move.l  #vdpCommDelta(planeLocH80(0,1)),d4  ; $1000000
-   move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.w  d1,d3
-   move.w  (a1)+,(a6)
    dbf d3,-
    add.l   d4,d0
    dbf d2,--
    rts
; End of function PlaneMapToVRAM_H80_Sega
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
; sub_3990:
JmpTo_RunObjects 
    jmp (RunObjects).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; loc_3998:
TitleScreen:
    move.b  #MusID_Stop,d0
    bsr.w   PlayMusic
    bsr.w   ClearPLC
    bsr.w   Pal_FadeToBlack
    move    #$2700,sr
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8200|(VRAM_TtlScr_Plane_A_Name_Table/$400),(a6)   ; PNT A base: $C000
    move.w  #$8400|(VRAM_TtlScr_Plane_B_Name_Table/$2000),(a6)  ; PNT B base: $E000
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
    move.w  #$9200,(a6)     ; Disable window
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8720,(a6)     ; Background palette/color: 2/0
    clr.b   (Water_fullscreen_flag).w
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    bsr.w   ClearScreen
 
    clearRAM Sprite_Table_Input,Sprite_Table_Input_End ; fill $AC00-$AFFF with $0
    clearRAM TtlScr_Object_RAM,TtlScr_Object_RAM_End ; fill object RAM ($B000-$D5FF) with $0
    clearRAM Misc_Variables,Misc_Variables_End ; clear CPU player RAM and following variables
    clearRAM Camera_RAM,Camera_RAM_End ; clear camera RAM and following variables
 
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_CreditText),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_CreditText).l,a0
    bsr.w   NemDec
    lea (off_B2B0).l,a1
    jsr (loc_B272).l
 
    clearRAM Target_palette,Target_palette_End  ; fill palette with 0 (black)
    moveq   #PalID_BGND,d0
    bsr.w   PalLoad_ForFade
    bsr.w   Pal_FadeFromBlack
    move    #$2700,sr
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Title),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Title).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_TitleSprites),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_TitleSprites).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_MenuJunk),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_MenuJunk).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Player1VS2),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Player1VS2).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_FontStuff_TtlScr),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_FontStuff).l,a0
    bsr.w   NemDec
    move.b  #0,(Last_star_pole_hit).w
    move.b  #0,(Last_star_pole_hit_2P).w
    move.w  #0,(Debug_placement_mode).w
    move.w  #0,(Demo_mode_flag).w
    move.w  #0,(unk_FFDA).w
    move.w  #0,(PalCycle_Timer).w
    move.w  #0,(Two_player_mode).w
    move.b  #0,(Level_started_flag).w
    bsr.w   Pal_FadeToBlack
    move    #$2700,sr
    lea (Chunk_Table).l,a1
    lea (MapEng_TitleScreen).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_Title,2,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_TtlScr_Plane_B_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
    lea (Chunk_Table).l,a1
    lea (MapEng_TitleBack).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_Title,2,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_TtlScr_Plane_B_Name_Table + planeLocH40($28,0),VRAM,WRITE),d0
    moveq   #$17,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
    lea (Chunk_Table).l,a1
    lea (MapEng_TitleLogo).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_Title,3,1),d0
    bsr.w   EniDec
 
    lea (Chunk_Table+$858).l,a1
    lea (CopyrightText).l,a2
 
    moveq   #bytesToWcnt(CopyrightText_End-CopyrightText),d6
-   move.w  (a2)+,(a1)+ ; load mappings for copyright 1992 sega message
    dbf d6,-
 
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_TtlScr_Plane_A_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
 
    clearRAM Normal_palette,Target_palette_End  ; fill two palettes with 0 (black)
 
    moveq   #PalID_Title,d0
    bsr.w   PalLoad_ForFade
    move.b  #0,(Debug_mode_flag).w
    move.w  #0,(Two_player_mode).w
    move.w  #$280,(Demo_Time_left).w
    clr.w   (Ctrl_1).w
    move.b  #ObjID_IntroStars,(IntroSonic+id).w ; load Obj0E (flashing intro star)
    move.b  #2,(IntroSonic+subtype).w               ; Sonic
    jsr (RunObjects).l
    jsr (BuildSprites).l
    moveq   #PLCID_Std1,d0
    bsr.w   LoadPLC2
    move.w  #0,(Correct_cheat_entries).w
    move.w  #0,(Correct_cheat_entries_2).w
    nop
    nop
    nop
    nop
    nop
    nop
    move.w  #4,(Sonic_Pos_Record_Index).w
    move.w  #0,(Sonic_Pos_Record_Buf).w
 
    lea (Results_Data_2P).w,a1
 
    moveq   #bytesToWcnt(Results_Data_2P_End-Results_Data_2P),d0
-   move.w  #-1,(a1)+
    dbf d0,-
 
    move.w  #-$280,(Camera_X_pos).w
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromBlack
 
; loc_3C14:
TitleScreen_Loop:
    move.b  #VintID_Title,(Vint_routine).w
    bsr.w   WaitForVint
    jsr (RunObjects).l
    jsrto   (SwScrl_Title).l, JmpTo_SwScrl_Title
    jsr (BuildSprites).l
 
    ; write alternating 0s and 4s, 80 times, at every 4th word,
    ; starting at Sprite_Table+6
    lea (Sprite_Table+4).w,a1
    moveq   #0,d0
 
    moveq   #79,d6
-   tst.w   (a1)
    bne.s   +
    bchg    #2,d0
    move.w  d0,2(a1)
+   addq.w  #8,a1
    dbf d6,-
 
    bsr.w   RunPLC_RAM
    bsr.w   TailsNameCheat
    tst.w   (Demo_Time_left).w
    beq.w   TitleScreen_Demo
    tst.b   (IntroSonic+objoff_2F).w
    beq.w   TitleScreen_Loop
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0
    beq.w   TitleScreen_Loop ; loop until Start is pressed
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
    moveq   #0,d0
    move.w  d0,(Ring_count).w
    move.l  d0,(Timer).w
    move.l  d0,(Score).w
    move.w  d0,(Ring_count_2P).w
    move.l  d0,(Timer_2P).w
    move.l  d0,(Score_2P).w
    move.b  d0,(Continue_count).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    move.b  #MusID_FadeOut,d0 ; prepare to stop music (fade out)
    bsr.w   PlaySound
    moveq   #0,d0
    move.b  (Title_screen_option).w,d0
    bne.s   TitleScreen_CheckIfChose2P  ; branch if not a 1-player game
 
    moveq   #0,d0
    move.w  d0,(Two_player_mode_copy).w
    move.w  d0,(Two_player_mode).w
    if emerald_hill_zone_act_1=0
    move.w  d0,(Current_ZoneAndAct).w ; emerald_hill_zone_act_1
    else
    move.w #emerald_hill_zone_act_1,(Current_ZoneAndAct).w
    endif
    tst.b   (Level_select_flag).w   ; has level select cheat been entered?
    beq.s   +           ; if not, branch
    btst    #button_A,(Ctrl_1_Held).w ; is A held down?
    beq.s   +           ; if not, branch
    move.b  #GameModeID_LevelSelect,(Game_Mode).w ; => LevelSelectMenu
    rts
; ---------------------------------------------------------------------------
+
    move.w  d0,(Current_Special_StageAndAct).w
    move.w  d0,(Got_Emerald).w
    move.l  d0,(Got_Emeralds_array).w
    move.l  d0,(Got_Emeralds_array+4).w
    rts
; ===========================================================================
; loc_3CF6:
TitleScreen_CheckIfChose2P:
    subq.b  #1,d0
    bne.s   TitleScreen_ChoseOptions
 
    moveq   #1,d1
    move.w  d1,(Two_player_mode_copy).w
    move.w  d1,(Two_player_mode).w
    moveq   #0,d0
    move.w  d0,(Got_Emerald).w
    move.l  d0,(Got_Emeralds_array).w
    move.l  d0,(Got_Emeralds_array+4).w
    move.b  #GameModeID_2PLevelSelect,(Game_Mode).w ; => LevelSelectMenu2P
    move.b  #emerald_hill_zone,(Current_Zone_2P).w
    rts
; ---------------------------------------------------------------------------
; loc_3D20:
TitleScreen_ChoseOptions:
    move.b  #GameModeID_OptionsMenu,(Game_Mode).w ; => OptionsMenu
    move.b  #0,(Options_menu_box).w
    rts
; ===========================================================================
; loc_3D2E:
TitleScreen_Demo:
    move.b  #MusID_FadeOut,d0
    bsr.w   PlaySound
    move.w  (Demo_number).w,d0
    andi.w  #7,d0
    add.w   d0,d0
    move.w  DemoLevels(pc,d0.w),d0
    move.w  d0,(Current_ZoneAndAct).w
    addq.w  #1,(Demo_number).w
    cmpi.w  #(DemoLevels_End-DemoLevels)/2,(Demo_number).w
    blo.s   +
    move.w  #0,(Demo_number).w
+
    move.w  #1,(Demo_mode_flag).w
    move.b  #GameModeID_Demo,(Game_Mode).w ; => Level (Demo mode)
    cmpi.w  #emerald_hill_zone_act_1,(Current_ZoneAndAct).w
    bne.s   +
    move.w  #1,(Two_player_mode).w
+
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
    moveq   #0,d0
    move.w  d0,(Ring_count).w
    move.l  d0,(Timer).w
    move.l  d0,(Score).w
    move.w  d0,(Ring_count_2P).w
    move.l  d0,(Timer_2P).w
    move.l  d0,(Score_2P).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    rts
; ===========================================================================
; word_3DAC:
DemoLevels:
    dc.w    emerald_hill_zone_act_1     ; EHZ (2P)
    dc.w    chemical_plant_zone_act_1   ; CPZ
    dc.w    aquatic_ruin_zone_act_1     ; ARZ
    dc.w    casino_night_zone_act_1     ; CNZ
DemoLevels_End:
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_3DB4:
TailsNameCheat:
    lea (TailsNameCheat_Buttons).l,a0
    move.w  (Correct_cheat_entries).w,d0
    adda.w  d0,a0
    move.b  (Ctrl_1_Press).w,d0
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask,d0
    beq.s   ++  ; rts
    cmp.b   (a0),d0
    bne.s   +
    addq.w  #1,(Correct_cheat_entries).w
    tst.b   1(a0)       ; read the next entry
    bne.s   ++      ; if it's not zero, return
    bchg    #7,(Graphics_Flags).w ; turn on the cheat that changes MILES to "TAILS"
    move.b  #SndID_Ring,d0 ; play the ring sound for a successfully entered cheat
    bsr.w   PlaySound
+   move.w  #0,(Correct_cheat_entries).w
+   rts
; End of function TailsNameCheat
 
; ===========================================================================
; byte_3DEE:
TailsNameCheat_Buttons:
    dc.b    button_up_mask
    dc.b    button_down_mask
    dc.b    button_down_mask
    dc.b    button_down_mask
    dc.b    button_up_mask
    dc.b    0   ; end
; ---------------------------------------------------------------------------------
; Nemesis compressed art
; 10 blocks
; Player 1 2 VS Text
; ---------------------------------------------------------------------------------
; ArtNem_3DF4:
ArtNem_Player1VS2:  BINCLUDE    "art/nemesis/1Player2VS.bin"
 
    charset '0','9',0 ; Add character set for numbers
    charset '*',$A ; Add character for star
    charset '@',$B ; Add character for copyright symbol
    charset ':',$C ; Add character for colon
    charset '.',$D ; Add character for period
    charset 'A','Z',$E ; Add character set for letters
 
; word_3E82:
CopyrightText:
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + '@',0,0)  ; (C)
    dc.w  make_art_tile(ArtTile_VRAM_Start,0,0) ;
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + '1',0,0)  ; 1
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + '9',0,0)  ; 9
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + '9',0,0)  ; 9
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + '2',0,0)  ; 2
    dc.w  make_art_tile(ArtTile_VRAM_Start,0,0) ;
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + 'S',0,0)  ; S
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + 'E',0,0)  ; E
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + 'G',0,0)  ; G
    dc.w  make_art_tile(ArtTile_ArtNem_FontStuff_TtlScr + 'A',0,0)  ; A
CopyrightText_End:
 
    charset ; Revert character set
 
    if ~~removeJmpTos
; sub_3E98:
JmpTo_SwScrl_Title 
    jmp (SwScrl_Title).l
 
    align 4
    endif
 
 
 
 
;----------------------------------------------------------------------------
; 1P Music Playlist
;----------------------------------------------------------------------------
; byte_3EA0:
MusicList: zoneOrderedTable 1,1
    zoneTableEntry.b MusID_EHZ  ; 0 ; EHZ
    zoneTableEntry.b MusID_EHZ  ; 1
    zoneTableEntry.b MusID_MTZ  ; 2
    zoneTableEntry.b MusID_OOZ  ; 3
    zoneTableEntry.b MusID_MTZ  ; 4 ; MTZ1,2
    zoneTableEntry.b MusID_MTZ  ; 5 ; MTZ3
    zoneTableEntry.b MusID_WFZ  ; 6 ; WFZ
    zoneTableEntry.b MusID_HTZ  ; 7 ; HTZ
    zoneTableEntry.b MusID_HPZ  ; 8
    zoneTableEntry.b MusID_SCZ  ; 9
    zoneTableEntry.b MusID_OOZ  ; 10 ; OOZ
    zoneTableEntry.b MusID_MCZ  ; 11 ; MCZ
    zoneTableEntry.b MusID_CNZ  ; 12 ; CNZ
    zoneTableEntry.b MusID_CPZ  ; 13 ; CPZ
    zoneTableEntry.b MusID_DEZ  ; 14 ; DEZ
    zoneTableEntry.b MusID_ARZ  ; 15 ; ARZ
    zoneTableEntry.b MusID_SCZ  ; 16 ; SCZ
    zoneTableEnd
    even
;----------------------------------------------------------------------------
; 2P Music Playlist
;----------------------------------------------------------------------------
; byte_3EB2:
MusicList2: zoneOrderedTable 1,1
    zoneTableEntry.b MusID_EHZ_2P   ; 0  ; EHZ 2P
    zoneTableEntry.b MusID_EHZ  ; 1
    zoneTableEntry.b MusID_MTZ  ; 2
    zoneTableEntry.b MusID_OOZ  ; 3
    zoneTableEntry.b MusID_MTZ  ; 4
    zoneTableEntry.b MusID_MTZ  ; 5
    zoneTableEntry.b MusID_WFZ  ; 6
    zoneTableEntry.b MusID_HTZ  ; 7
    zoneTableEntry.b MusID_HPZ  ; 8
    zoneTableEntry.b MusID_SCZ  ; 9
    zoneTableEntry.b MusID_OOZ  ; 10
    zoneTableEntry.b MusID_MCZ_2P   ; 11 ; MCZ 2P
    zoneTableEntry.b MusID_CNZ_2P   ; 12 ; CNZ 2P
    zoneTableEntry.b MusID_CPZ  ; 13
    zoneTableEntry.b MusID_DEZ  ; 14
    zoneTableEntry.b MusID_ARZ  ; 15
    zoneTableEntry.b MusID_SCZ  ; 16
    zoneTableEnd
    even
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Level
; DEMO AND ZONE LOOP (MLS values $08, $0C; bit 7 set indicates that load routine is running)
; ---------------------------------------------------------------------------
; loc_3EC4:
Level:
    bset    #GameModeFlag_TitleCard,(Game_Mode).w ; add $80 to screen mode (for pre level sequence)
    tst.w   (Demo_mode_flag).w  ; test the old flag for the credits demos (now unused)
    bmi.s   +
    move.b  #MusID_FadeOut,d0
    bsr.w   PlaySound   ; fade out music
+
    bsr.w   ClearPLC
    bsr.w   Pal_FadeToBlack
    tst.w   (Demo_mode_flag).w
    bmi.s   Level_ClrRam
    move    #$2700,sr
    bsr.w   ClearScreen
    jsr (LoadTitleCard).l ; load title card patterns
    move    #$2300,sr
    moveq   #0,d0
    move.w  d0,(Timer_frames).w
    move.b  (Current_Zone).w,d0
 
    ; multiply d0 by 12, the size of a level art load block
    add.w   d0,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
 
    lea (LevelArtPointers).l,a2
    lea (a2,d0.w),a2
    moveq   #0,d0
    move.b  (a2),d0 ; PLC1 ID
    beq.s   +
    bsr.w   LoadPLC
+
    moveq   #PLCID_Std2,d0
    bsr.w   LoadPLC
    bsr.w   Level_SetPlayerMode
    moveq   #PLCID_Miles1up,d0
    tst.w   (Two_player_mode).w
    bne.s   +
    cmpi.w  #2,(Player_mode).w
    bne.s   Level_ClrRam
    addq.w  #PLCID_MilesLife-PLCID_Miles1up,d0
+
    tst.b   (Graphics_Flags).w
    bpl.s   +
    addq.w  #PLCID_Tails1up-PLCID_Miles1up,d0
+
    bsr.w   LoadPLC
; loc_3F48:
Level_ClrRam:
    clearRAM Sprite_Table_Input,Sprite_Table_Input_End
    clearRAM Object_RAM,Object_RAM_End ; clear object RAM
    clearRAM MiscLevelVariables,MiscLevelVariables_End
    clearRAM Misc_Variables,Misc_Variables_End
    clearRAM Oscillating_Data,Oscillating_variables_End
    ; Bug: The '+C0' shouldn't be here; CNZ_saucer_data is only $40 bytes large
    clearRAM CNZ_saucer_data,CNZ_saucer_data_End+$C0
 
    cmpi.w  #chemical_plant_zone_act_2,(Current_ZoneAndAct).w ; CPZ 2
    beq.s   Level_InitWater
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w ; ARZ
    beq.s   Level_InitWater
    cmpi.b  #hidden_palace_zone,(Current_Zone).w ; HPZ
    bne.s   +
 
Level_InitWater:
    move.b  #1,(Water_flag).w
    move.w  #0,(Two_player_mode).w
+
    lea (VDP_control_port).l,a6
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8200|(VRAM_Plane_A_Name_Table/$400),(a6)  ; PNT A base: $C000
    move.w  #$8400|(VRAM_Plane_B_Name_Table/$2000),(a6) ; PNT B base: $E000
    move.w  #$8500|(VRAM_Sprite_Attribute_Table/$200),(a6)  ; Sprite attribute table base: $F800
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8720,(a6)     ; Background palette/color: 2/0
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace
    tst.b   (Debug_options_flag).w
    beq.s   ++
    btst    #button_C,(Ctrl_1_Held).w
    beq.s   +
    move.w  #$8C89,(a6) ; H res 40 cells, no interlace, S/H enabled
+
    btst    #button_A,(Ctrl_1_Held).w
    beq.s   +
    move.b  #1,(Debug_mode_flag).w
+
    move.w  #$8ADF,(Hint_counter_reserve).w ; H-INT every 223rd scanline
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  #$8A6B,(Hint_counter_reserve).w ; H-INT every 108th scanline
    move.w  #$8014,(a6)         ; H-INT enabled
    move.w  #$8C87,(a6)         ; H res 40 cells, double res interlace
+
    move.w  (Hint_counter_reserve).w,(a6)
    clr.w   (VDP_Command_Buffer).w
    move.l  #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w
    tst.b   (Water_flag).w  ; does level have water?
    beq.s   Level_LoadPal   ; if not, branch
    move.w  #$8014,(a6) ; H-INT enabled
    moveq   #0,d0
    move.w  (Current_ZoneAndAct).w,d0
    if ~~useFullWaterTables
    subi.w  #hidden_palace_zone_act_1,d0
    endif
    ror.b   #1,d0
    lsr.w   #6,d0
    andi.w  #$FFFE,d0
    lea (WaterHeight).l,a1  ; load water height array
    move.w  (a1,d0.w),d0
    move.w  d0,(Water_Level_1).w ; set water heights
    move.w  d0,(Water_Level_2).w
    move.w  d0,(Water_Level_3).w
    clr.b   (Water_routine).w   ; clear water routine counter
    clr.b   (Water_fullscreen_flag).w   ; clear water movement
    move.b  #1,(Water_on).w ; enable water
; loc_407C:
Level_LoadPal:
    moveq   #PalID_BGND,d0
    bsr.w   PalLoad_Now ; load Sonic's palette line
    tst.b   (Water_flag).w  ; does level have water?
    beq.s   Level_GetBgm    ; if not, branch
    moveq   #PalID_HPZ_U,d0 ; palette number $15
    cmpi.b  #hidden_palace_zone,(Current_Zone).w
    beq.s   Level_WaterPal ; branch if level is HPZ
    moveq   #PalID_CPZ_U,d0 ; palette number $16
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.s   Level_WaterPal ; branch if level is CPZ
    moveq   #PalID_ARZ_U,d0 ; palette number $17
; loc_409E:
Level_WaterPal:
    bsr.w   PalLoad_Water_Now   ; load underwater palette (with d0)
    tst.b   (Last_star_pole_hit).w ; is it the start of the level?
    beq.s   Level_GetBgm    ; if yes, branch
    move.b  (Saved_Water_move).w,(Water_fullscreen_flag).w
; loc_40AE:
Level_GetBgm:
    tst.w   (Demo_mode_flag).w
    bmi.s   +
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    lea_    MusicList,a1
    tst.w   (Two_player_mode).w
    beq.s   Level_PlayBgm
    lea_    MusicList2,a1
; loc_40C8:
Level_PlayBgm:
    move.b  (a1,d0.w),d0        ; load from music playlist
    move.w  d0,(Level_Music).w  ; store level music
    bsr.w   PlayMusic       ; play level music
    move.b  #ObjID_TitleCard,(TitleCard+id).w ; load Obj34 (level title card) at $FFFFB080
; loc_40DA:
Level_TtlCard:
    move.b  #VintID_TitleCard,(Vint_routine).w
    bsr.w   WaitForVint
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    move.w  (TitleCard_ZoneName+x_pos).w,d0
    cmp.w   (TitleCard_ZoneName+titlecard_x_target).w,d0 ; has title card sequence finished?
    bne.s   Level_TtlCard       ; if not, branch
    tst.l   (Plc_Buffer).w      ; are there any items in the pattern load cue?
    bne.s   Level_TtlCard       ; if yes, branch
    move.b  #VintID_TitleCard,(Vint_routine).w
    bsr.w   WaitForVint
    jsr (Hud_Base).l
+
    moveq   #PalID_BGND,d0
    bsr.w   PalLoad_ForFade ; load Sonic's palette line
    bsr.w   LevelSizeLoad
    jsrto   (DeformBgLayer).l, JmpTo_DeformBgLayer
    clr.w   (Vscroll_Factor_FG).w
    move.w  #-$E0,(Vscroll_Factor_P2_FG).w
 
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End
 
    bsr.w   LoadZoneTiles
    jsrto   (loadZoneBlockMaps).l, JmpTo_loadZoneBlockMaps
    jsr (loc_402D4).l
    jsrto   (DrawInitialBG).l, JmpTo_DrawInitialBG
    jsr (FloorLog_Unk).l
    bsr.w   LoadCollisionIndexes
    bsr.w   WaterEffects
    bsr.w   InitPlayers
    move.w  #0,(Ctrl_1_Logical).w
    move.w  #0,(Ctrl_2_Logical).w
    move.w  #0,(Ctrl_1).w
    move.w  #0,(Ctrl_2).w
    move.b  #1,(Control_Locked).w
    move.b  #1,(Control_Locked_P2).w
    move.b  #0,(Level_started_flag).w
; Level_ChkWater:
    tst.b   (Water_flag).w  ; does level have water?
    beq.s   +   ; if not, branch
    move.b  #ObjID_WaterSurface,(WaterSurface1+id).w ; load Obj04 (water surface) at $FFFFB380
    move.w  #$60,(WaterSurface1+x_pos).w ; set horizontal offset
    move.b  #ObjID_WaterSurface,(WaterSurface2+id).w ; load Obj04 (water surface) at $FFFFB3C0
    move.w  #$120,(WaterSurface2+x_pos).w ; set different horizontal offset
+
    cmpi.b  #chemical_plant_zone,(Current_Zone).w   ; check if zone == CPZ
    bne.s   +           ; branch if not
    move.b  #ObjID_CPZPylon,(CPZPylon+id).w ; load Obj7C (CPZ pylon) at $FFFFB340
+
    cmpi.b  #oil_ocean_zone,(Current_Zone).w    ; check if zone == OOZ
    bne.s   Level_ClrHUD        ; branch if not
    move.b  #ObjID_Oil,(Oil+id).w ; load Obj07 (OOZ oil) at $FFFFB380
; Level_LoadObj: misnomer now
Level_ClrHUD:
    moveq   #0,d0
    tst.b   (Last_star_pole_hit).w  ; are you starting from a lamppost?
    bne.s   Level_FromCheckpoint    ; if yes, branch
    move.w  d0,(Ring_count).w   ; clear rings
    move.l  d0,(Timer).w        ; clear time
    move.b  d0,(Extra_life_flags).w ; clear extra lives counter
    move.w  d0,(Ring_count_2P).w    ; ditto for player 2
    move.l  d0,(Timer_2P).w
    move.b  d0,(Extra_life_flags_2P).w
; loc_41E4:
Level_FromCheckpoint:
    move.b  d0,(Time_Over_flag).w
    move.b  d0,(Time_Over_flag_2P).w
    move.b  d0,(SlotMachine_Routine).w
    move.w  d0,(SlotMachineInUse).w
    move.w  d0,(Debug_placement_mode).w
    move.w  d0,(Level_Inactive_flag).w
    move.b  d0,(Teleport_timer).w
    move.b  d0,(Teleport_flag).w
    move.w  d0,(Rings_Collected).w
    move.w  d0,(Rings_Collected_2P).w
    move.w  d0,(Monitors_Broken).w
    move.w  d0,(Monitors_Broken_2P).w
    move.w  d0,(Loser_Time_Left).w
    bsr.w   OscillateNumInit
    move.b  #1,(Update_HUD_score).w
    move.b  #1,(Update_HUD_rings).w
    move.b  #1,(Update_HUD_timer).w
    move.b  #1,(Update_HUD_timer_2P).w
    jsr (ObjectsManager).l
    jsr (RingsManager).l
    jsr (SpecialCNZBumpers).l
    jsr (RunObjects).l
    jsr (BuildSprites).l
    jsrto   (AniArt_Load).l, JmpTo_AniArt_Load
    bsr.w   SetLevelEndType
    move.w  #0,(Demo_button_index).w
    move.w  #0,(Demo_button_index_2P).w
    lea (DemoScriptPointers).l,a1
    moveq   #0,d0
    move.b  (Current_Zone).w,d0 ; load zone value
    lsl.w   #2,d0
    movea.l (a1,d0.w),a1
    tst.w   (Demo_mode_flag).w
    bpl.s   +
    lea (EndingDemoScriptPointers).l,a1
    move.w  (Ending_demo_number).w,d0
    subq.w  #1,d0
    lsl.w   #2,d0
    movea.l (a1,d0.w),a1
+
    move.b  1(a1),(Demo_press_counter).w
    tst.b   (Current_Zone).w    ; emerald_hill_zone
    bne.s   +
    lea (Demo_EHZ_Tails).l,a1
    move.b  1(a1),(Demo_press_counter_2P).w
+
    move.w  #$668,(Demo_Time_left).w
    tst.w   (Demo_mode_flag).w
    bpl.s   +
    move.w  #$21C,(Demo_Time_left).w
    cmpi.w  #4,(Ending_demo_number).w
    bne.s   +
    move.w  #$1FE,(Demo_Time_left).w
+
    tst.b   (Water_flag).w
    beq.s   ++
    moveq   #PalID_HPZ_U,d0
    cmpi.b  #hidden_palace_zone,(Current_Zone).w
    beq.s   +
    moveq   #PalID_CPZ_U,d0
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.s   +
    moveq   #PalID_ARZ_U,d0
+
    bsr.w   PalLoad_Water_ForFade
+
    move.w  #-1,(TitleCard_ZoneName+titlecard_leaveflag).w
    move.b  #$E,(TitleCard_Left+routine).w  ; make the left part move offscreen
    move.w  #$A,(TitleCard_Left+titlecard_location).w
 
-   move.b  #VintID_TitleCard,(Vint_routine).w
    bsr.w   WaitForVint
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    tst.b   (TitleCard_Background+id).w
    bne.s   -   ; loop while the title card background is still loaded
 
    lea (TitleCard).w,a1
    move.b  #$16,TitleCard_ZoneName-TitleCard+routine(a1)
    move.w  #$2D,TitleCard_ZoneName-TitleCard+anim_frame_duration(a1)
    move.b  #$16,TitleCard_Zone-TitleCard+routine(a1)
    move.w  #$2D,TitleCard_Zone-TitleCard+anim_frame_duration(a1)
    tst.b   TitleCard_ActNumber-TitleCard+id(a1)
    beq.s   +   ; branch if the act number has been unloaded
    move.b  #$16,TitleCard_ActNumber-TitleCard+routine(a1)
    move.w  #$2D,TitleCard_ActNumber-TitleCard+anim_frame_duration(a1)
+   move.b  #0,(Control_Locked).w
    move.b  #0,(Control_Locked_P2).w
    move.b  #1,(Level_started_flag).w
 
; Level_StartGame: loc_435A:
    bclr    #GameModeFlag_TitleCard,(Game_Mode).w ; clear $80 from the game mode
 
; ---------------------------------------------------------------------------
; Main level loop (when all title card and loading sequences are finished)
; ---------------------------------------------------------------------------
; loc_4360:
Level_MainLoop:
    bsr.w   PauseGame
    move.b  #VintID_Level,(Vint_routine).w
    bsr.w   WaitForVint
    addq.w  #1,(Timer_frames).w ; add 1 to level timer
    bsr.w   MoveSonicInDemo
    bsr.w   WaterEffects
    jsr (RunObjects).l
    tst.w   (Level_Inactive_flag).w
    bne.w   Level
    jsrto   (DeformBgLayer).l, JmpTo_DeformBgLayer
    bsr.w   UpdateWaterSurface
    jsr (RingsManager).l
    cmpi.b  #casino_night_zone,(Current_Zone).w ; is it CNZ?
    bne.s   +           ; if not, branch past jsr
    jsr (SpecialCNZBumpers).l
+
    jsrto   (AniArt_Load).l, JmpTo_AniArt_Load
    bsr.w   PalCycle_Load
    bsr.w   RunPLC_RAM
    bsr.w   OscillateNumDo
    bsr.w   ChangeRingFrame
    bsr.w   CheckLoadSignpostArt
    jsr (BuildSprites).l
    jsr (ObjectsManager).l
    cmpi.b  #GameModeID_Demo,(Game_Mode).w  ; check if in demo mode
    beq.s   +
    cmpi.b  #GameModeID_Level,(Game_Mode).w ; check if in normal play mode
    beq.w   Level_MainLoop
    rts
; ---------------------------------------------------------------------------
+
    tst.w   (Level_Inactive_flag).w
    bne.s   +
    tst.w   (Demo_Time_left).w
    beq.s   +
    cmpi.b  #GameModeID_Demo,(Game_Mode).w
    beq.w   Level_MainLoop
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
; ---------------------------------------------------------------------------
+
    cmpi.b  #GameModeID_Demo,(Game_Mode).w
    bne.s   +
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
+
    move.w  #1*60,(Demo_Time_left).w    ; 1 second
    move.w  #$3F,(Palette_fade_range).w
    clr.w   (PalChangeSpeed).w
-
    move.b  #VintID_Level,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.w   MoveSonicInDemo
    jsr (RunObjects).l
    jsr (BuildSprites).l
    jsr (ObjectsManager).l
    subq.w  #1,(PalChangeSpeed).w
    bpl.s   +
    move.w  #2,(PalChangeSpeed).w
    bsr.w   Pal_FadeToBlack.UpdateAllColours
+
    tst.w   (Demo_Time_left).w
    bne.s   -
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to set the player mode, which is forced to Sonic and Tails in
; the demo mode and in 2P mode
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4450:
Level_SetPlayerMode:
    cmpi.b  #GameModeID_TitleCard|GameModeID_Demo,(Game_Mode).w ; pre-level demo mode?
    beq.s   +           ; if yes, branch
    tst.w   (Two_player_mode).w ; 2P mode?
    bne.s   +           ; if yes, branch
    move.w  (Player_option).w,(Player_mode).w ; use the option chosen in the Options screen
    rts
; ---------------------------------------------------------------------------
+   move.w  #0,(Player_mode).w  ; force Sonic and Tails
    rts
; End of function Level_SetPlayerMode
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_446E:
InitPlayers:
    move.w  (Player_mode).w,d0
    bne.s   InitPlayers_Alone ; branch if this isn't a Sonic and Tails game
 
    move.b  #ObjID_Sonic,(MainCharacter+id).w ; load Obj01 Sonic object at $FFFFB000
    move.b  #ObjID_SpindashDust,(Sonic_Dust+id).w ; load Obj08 Sonic's spindash dust/splash object at $FFFFD100
 
    cmpi.b  #wing_fortress_zone,(Current_Zone).w
    beq.s   + ; skip loading Tails if this is WFZ
    cmpi.b  #death_egg_zone,(Current_Zone).w
    beq.s   + ; skip loading Tails if this is DEZ
    cmpi.b  #sky_chase_zone,(Current_Zone).w
    beq.s   + ; skip loading Tails if this is SCZ
 
    move.b  #ObjID_Tails,(Sidekick+id).w ; load Obj02 Tails object at $FFFFB040
    move.w  (MainCharacter+x_pos).w,(Sidekick+x_pos).w
    move.w  (MainCharacter+y_pos).w,(Sidekick+y_pos).w
    subi.w  #$20,(Sidekick+x_pos).w
    addi_.w #4,(Sidekick+y_pos).w
    move.b  #ObjID_SpindashDust,(Tails_Dust+id).w ; load Obj08 Tails' spindash dust/splash object at $FFFFD140
+
    rts
; ===========================================================================
; loc_44BE:
InitPlayers_Alone: ; either Sonic or Tails but not both
    subq.w  #1,d0
    bne.s   InitPlayers_TailsAlone ; branch if this is a Tails alone game
 
    move.b  #ObjID_Sonic,(MainCharacter+id).w ; load Obj01 Sonic object at $FFFFB000
    move.b  #ObjID_SpindashDust,(Sonic_Dust+id).w ; load Obj08 Sonic's spindash dust/splash object at $FFFFD100
    rts
; ===========================================================================
; loc_44D0:
InitPlayers_TailsAlone:
    move.b  #ObjID_Tails,(MainCharacter+id).w ; load Obj02 Tails object at $FFFFB000
    move.b  #ObjID_SpindashDust,(Tails_Dust+id).w ; load Obj08 Tails' spindash dust/splash object at $FFFFD100
    addi_.w #4,(MainCharacter+y_pos).w
    rts
; End of function InitPlayers
 
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to move the water or oil surface sprites to where the screen is at
; (the closest match I could find to this subroutine in Sonic 1 is Obj1B_Action)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_44E4:
UpdateWaterSurface:
    tst.b   (Water_flag).w
    beq.s   ++  ; rts
    move.w  (Camera_X_pos).w,d1
    btst    #0,(Timer_frames+1).w
    beq.s   +
    addi.w  #$20,d1
+       ; match obj x-position to screen position
    move.w  d1,d0
    addi.w  #$60,d0
    move.w  d0,(WaterSurface1+x_pos).w
    addi.w  #$120,d1
    move.w  d1,(WaterSurface2+x_pos).w
+
    rts
; End of function UpdateWaterSurface
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; ---------------------------------------------------------------------------
; Subroutine to do special water effects
; ---------------------------------------------------------------------------
; sub_450E: ; LZWaterEffects:
WaterEffects:
    tst.b   (Water_flag).w  ; does level have water?
    beq.s   NonWaterEffects ; if not, branch
    tst.b   (Deform_lock).w
    bne.s   MoveWater
    cmpi.b  #6,(MainCharacter+routine).w    ; is player dead?
    bhs.s   MoveWater           ; if yes, branch
    bsr.w   DynamicWater
; loc_4526: ; LZMoveWater:
MoveWater:
    clr.b   (Water_fullscreen_flag).w
    moveq   #0,d0
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w ; is level ARZ?
    beq.s   +       ; if yes, branch
    move.b  (Oscillating_Data).w,d0
    lsr.w   #1,d0
+
    add.w   (Water_Level_2).w,d0
    move.w  d0,(Water_Level_1).w
        ; calculate distance between water surface and top of screen
    move.w  (Water_Level_1).w,d0
    sub.w   (Camera_Y_pos).w,d0
    bhs.s   +
    tst.w   d0
    bpl.s   +
    move.b  #$DF,(Hint_counter_reserve+1).w ; H-INT every 224th scanline
    move.b  #1,(Water_fullscreen_flag).w
+
    cmpi.w  #$DF,d0
    blo.s   +
    move.w  #$DF,d0
+
    move.b  d0,(Hint_counter_reserve+1).w   ; H-INT every d0 scanlines
; loc_456A:
NonWaterEffects:
    cmpi.b  #oil_ocean_zone,(Current_Zone).w    ; is the level OOZ?
    bne.s   +           ; if not, branch
    bsr.w   OilSlides       ; call oil slide routine
+
    cmpi.b  #wing_fortress_zone,(Current_Zone).w    ; is the level WFZ?
    bne.s   +           ; if not, branch
    bsr.w   WindTunnel      ; call wind and block break routine
+
    rts
; End of function WaterEffects
 
; ===========================================================================
    if useFullWaterTables
WaterHeight: zoneOrderedTable 2,2
    zoneTableEntry.w  $600, $600    ; EHZ
    zoneTableEntry.w  $600, $600    ; Zone 1
    zoneTableEntry.w  $600, $600    ; WZ
    zoneTableEntry.w  $600, $600    ; Zone 3
    zoneTableEntry.w  $600, $600    ; MTZ
    zoneTableEntry.w  $600, $600    ; MTZ
    zoneTableEntry.w  $600, $600    ; WFZ
    zoneTableEntry.w  $600, $600    ; HTZ
    zoneTableEntry.w  $600, $600    ; HPZ
    zoneTableEntry.w  $600, $600    ; Zone 9
    zoneTableEntry.w  $600, $600    ; OOZ
    zoneTableEntry.w  $600, $600    ; MCZ
    zoneTableEntry.w  $600, $600    ; CNZ
    zoneTableEntry.w  $600, $710    ; CPZ
    zoneTableEntry.w  $600, $600    ; DEZ
    zoneTableEntry.w  $410, $510    ; ARZ
    zoneTableEntry.w  $600, $600    ; SCZ
    zoneTableEnd
    else
; word_4584:
WaterHeight:
    dc.w  $600, $600    ; HPZ
    dc.w  $600, $600    ; Zone 9
    dc.w  $600, $600    ; OOZ
    dc.w  $600, $600    ; MCZ
    dc.w  $600, $600    ; CNZ
    dc.w  $600, $710    ; CPZ
    dc.w  $600, $600    ; DEZ
    dc.w  $410, $510    ; ARZ
    endif
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_45A4: ; LZDynamicWater:
DynamicWater:
    moveq   #0,d0
    move.w  (Current_ZoneAndAct).w,d0
    if ~~useFullWaterTables
    subi.w  #hidden_palace_zone_act_1,d0
    endif
    ror.b   #1,d0
    lsr.w   #6,d0
    andi.w  #$FFFE,d0
    move.w  Dynamic_water_routine_table(pc,d0.w),d0
    jsr Dynamic_water_routine_table(pc,d0.w)
    moveq   #0,d1
    move.b  (Water_on).w,d1
    move.w  (Water_Level_3).w,d0
    sub.w   (Water_Level_2).w,d0
    beq.s   ++  ; rts
    bcc.s   +
    neg.w   d1
+
    add.w   d1,(Water_Level_2).w
+
    rts
; End of function DynamicWater
 
; ===========================================================================
    if useFullWaterTables
Dynamic_water_routine_table: zoneOrderedOffsetTable 2,2
    zoneOffsetTableEntry.w DynamicWaterNull ; EHZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; EHZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 1
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 1
    zoneOffsetTableEntry.w DynamicWaterNull ; WZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; WZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 3
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 3
    zoneOffsetTableEntry.w DynamicWaterNull ; MTZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; MTZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; MTZ 3
    zoneOffsetTableEntry.w DynamicWaterNull ; MTZ 4
    zoneOffsetTableEntry.w DynamicWaterNull ; WFZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; WFZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; HTZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; HTZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; HPZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; HPZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 9
    zoneOffsetTableEntry.w DynamicWaterNull ; Zone 9
    zoneOffsetTableEntry.w DynamicWaterNull ; OOZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; OOZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; MCZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; MCZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; CNZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; CNZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; CPZ 1
    zoneOffsetTableEntry.w DynamicWaterCPZ2 ; CPZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; DEZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; DEZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; ARZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; ARZ 2
    zoneOffsetTableEntry.w DynamicWaterNull ; SCZ 1
    zoneOffsetTableEntry.w DynamicWaterNull ; SCZ 2
    zoneTableEnd
    else
; off_45D8:
Dynamic_water_routine_table: offsetTable
    offsetTableEntry.w DynamicWaterNull ; HPZ 1
    offsetTableEntry.w DynamicWaterNull ; HPZ 2
    offsetTableEntry.w DynamicWaterNull ; Zone 9
    offsetTableEntry.w DynamicWaterNull ; Zone 9
    offsetTableEntry.w DynamicWaterNull ; OOZ 1
    offsetTableEntry.w DynamicWaterNull ; OOZ 2
    offsetTableEntry.w DynamicWaterNull ; MCZ 1
    offsetTableEntry.w DynamicWaterNull ; MCZ 2
    offsetTableEntry.w DynamicWaterNull ; CNZ 1
    offsetTableEntry.w DynamicWaterNull ; CNZ 2
    offsetTableEntry.w DynamicWaterNull ; CPZ 1
    offsetTableEntry.w DynamicWaterCPZ2 ; CPZ 2
    offsetTableEntry.w DynamicWaterNull ; DEZ 1
    offsetTableEntry.w DynamicWaterNull ; DEZ 2
    offsetTableEntry.w DynamicWaterNull ; ARZ 1
    offsetTableEntry.w DynamicWaterNull ; ARZ 2
    endif
; ===========================================================================
; return_45F8:
DynamicWaterNull:
    rts
; ===========================================================================
; loc_45FA:
DynamicWaterCPZ2:
    cmpi.w  #$1DE0,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$510,(Water_Level_3).w
+   rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Equates:
windtunnel_min_x_pos    = 0
windtunnel_max_x_pos    = 4
windtunnel_min_y_pos    = 2
windtunnel_max_y_pos    = 6
 
; sub_460A:
WindTunnel:
    tst.w   (Debug_placement_mode).w
    bne.w   WindTunnel_End  ; don't interact with wind tunnels while in debug mode
    lea (WindTunnelsCoordinates).l,a2
    moveq   #(WindTunnelsCoordinates_End-WindTunnelsCoordinates)/8-1,d1
    lea (MainCharacter).w,a1 ; a1=character
-   ; check for current wind tunnel if the main character is inside it
    move.w  x_pos(a1),d0
    cmp.w   windtunnel_min_x_pos(a2),d0
    blo.w   WindTunnel_Leave    ; branch, if main character is too far left
    cmp.w   windtunnel_max_x_pos(a2),d0
    bhs.w   WindTunnel_Leave    ; branch, if main character is too far right
    move.w  y_pos(a1),d2
    cmp.w   windtunnel_min_y_pos(a2),d2
    blo.w   WindTunnel_Leave    ; branch, if main character is too far up
    cmp.w   windtunnel_max_y_pos(a2),d2
    bhs.s   WindTunnel_Leave    ; branch, if main character is too far down
    tst.b   (WindTunnel_holding_flag).w
    bne.w   WindTunnel_End
    cmpi.b  #4,routine(a1)      ; is the main character hurt, dying, etc. ?
    bhs.s   WindTunnel_LeaveHurt    ; if yes, branch
    move.b  #1,(WindTunnel_flag).w  ; affects character animation and bubble movement
    subi_.w #4,x_pos(a1)    ; move main character to the left
    move.w  #-$400,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.b  #AniIDSonAni_Float2,anim(a1)
    bset    #1,status(a1)   ; set "in-air" bit
    btst    #button_up,(Ctrl_1_Held).w  ; is Up being pressed?
    beq.s   +               ; if not, branch
    subq.w  #1,y_pos(a1)    ; move up
+
    btst    #button_down,(Ctrl_1_Held).w    ; is Down being pressed?
    beq.s   +               ; if not, branch
    addq.w  #1,y_pos(a1)    ; move down
+
    rts
; ===========================================================================
; loc_4690:
WindTunnel_Leave:
    addq.w  #8,a2
    dbf d1,-    ; check next tunnel
    ; when all wind tunnels have been checked
    tst.b   (WindTunnel_flag).w
    beq.s   WindTunnel_End
    move.b  #AniIDSonAni_Walk,anim(a1)
; loc_46A2:
WindTunnel_LeaveHurt:   ; the main character is hurt or dying, leave the tunnel and don't check the other
    clr.b   (WindTunnel_flag).w
; return_46A6:
WindTunnel_End:
    rts
; End of function WindTunnel
 
; ===========================================================================
; word_46A8:
WindTunnelsCoordinates:
    dc.w $1510,$400,$1AF0,$580
    dc.w $20F0,$618,$2500,$680
WindTunnelsCoordinates_End:
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_46B8:
OilSlides:
    lea (MainCharacter).w,a1 ; a1=character
    move.b  (Ctrl_1_Held_Logical).w,d2
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    move.b  (Ctrl_2_Held_Logical).w,d2
+
    btst    #1,status(a1)
    bne.s   +
    move.w  y_pos(a1),d0
    add.w   d0,d0
    andi.w  #$F00,d0
    move.w  x_pos(a1),d1
    lsr.w   #7,d1
    andi.w  #$7F,d1
    add.w   d1,d0
    lea (Level_Layout).w,a2
    move.b  (a2,d0.w),d0
    lea OilSlides_Chunks_End(pc),a2
 
    moveq   #OilSlides_Chunks_End-OilSlides_Chunks-1,d1
-   cmp.b   -(a2),d0
    dbeq    d1,-
 
    beq.s   loc_4712
+
    if status_sec_isSliding = 7
    tst.b   status_secondary(a1)
    bpl.s   +   ; rts
    else
    btst    #status_sec_isSliding,status_secondary(a1)
    beq.s   +   ; rts
    endif
    move.w  #5,move_lock(a1)
    andi.b  #(~status_sec_isSliding_mask)&$FF,status_secondary(a1)
+   rts
; ===========================================================================
 
loc_4712:
    lea (OilSlides_Speeds).l,a2
    move.b  (a2,d1.w),d0
    beq.s   loc_476E
    move.b  inertia(a1),d1
    tst.b   d0
    bpl.s   +
    cmp.b   d0,d1
    ble.s   ++
    subi.w  #$40,inertia(a1)
    bra.s   ++
; ===========================================================================
+
    cmp.b   d0,d1
    bge.s   +
    addi.w  #$40,inertia(a1)
+
    bclr    #0,status(a1)
    tst.b   d1
    bpl.s   +
    bset    #0,status(a1)
+
    move.b  #AniIDSonAni_Slide,anim(a1)
    ori.b   #status_sec_isSliding_mask,status_secondary(a1)
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +   ; rts
    move.w  #SndID_OilSlide,d0
    jsr (PlaySound).l
+
    rts
; ===========================================================================
 
loc_476E:
    move.w  #4,d1
    move.w  inertia(a1),d0
    btst    #button_left,d2
    beq.s   +
    move.b  #AniIDSonAni_Walk,anim(a1)
    bset    #0,status(a1)
    sub.w   d1,d0
    tst.w   d0
    bpl.s   +
    sub.w   d1,d0
+
    btst    #button_right,d2
    beq.s   +
    move.b  #AniIDSonAni_Walk,anim(a1)
    bclr    #0,status(a1)
    add.w   d1,d0
    tst.w   d0
    bmi.s   +
    add.w   d1,d0
+
    move.w  #4,d1
    tst.w   d0
    beq.s   +++
    bmi.s   ++
    sub.w   d1,d0
    bhi.s   +
    move.w  #0,d0
    move.b  #AniIDSonAni_Wait,anim(a1)
+   bra.s   ++
; ===========================================================================
+
    add.w   d1,d0
    bhi.s   +
    move.w  #0,d0
    move.b  #AniIDSonAni_Wait,anim(a1)
+
    move.w  d0,inertia(a1)
    ori.b   #status_sec_isSliding_mask,status_secondary(a1)
    rts
; End of function OilSlides
 
; ===========================================================================
OilSlides_Speeds:
    dc.b  -8, -8, -8,  8,  8,  0,  0,  0, -8, -8,  0,  8,  8,  8,  0,  8
    dc.b   8,  8,  0, -8,  0,  0, -8,  8, -8, -8, -8,  8,  8,  8, -8, -8 ; 16
 
; These are the IDs of the chunks where Sonic and Tails will slide
OilSlides_Chunks:
    dc.b $2F,$30,$31,$33,$35,$38,$3A,$3C,$63,$64,$83,$90,$91,$93,$A1,$A3
    dc.b $BD,$C7,$C8,$CE,$D7,$D8,$E6,$EB,$EC,$ED,$F1,$F2,$F3,$F4,$FA,$FD ; 16
OilSlides_Chunks_End:
    even
 
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_481E:
MoveSonicInDemo:
    tst.w   (Demo_mode_flag).w  ; is demo mode on?
    bne.w   MoveDemo_On ; if yes, branch
    rts
; ---------------------------------------------------------------------------
; demo recording routine
; (unused/dead code, but obviously used during development)
; ---------------------------------------------------------------------------
; MoveDemo_Record: loc_4828:
    ; calculate output location of recorded player 1 demo?
    lea (DemoScriptPointers).l,a1
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    lsl.w   #2,d0
    movea.l (a1,d0.w),a1
    move.w  (Demo_button_index).w,d0
    adda.w  d0,a1
 
    move.b  (Ctrl_1_Held).w,d0  ; load input of player 1
    cmp.b   (a1),d0         ; is same button held?
    bne.s   +           ; if not, branch
    addq.b  #1,1(a1)        ; increment press length counter
    cmpi.b  #$FF,1(a1)      ; is button held too long?
    beq.s   +           ; if yes, branch
    bra.s   MoveDemo_Record_P2  ; go to player 2
; ===========================================================================
+
    move.b  d0,2(a1)        ; store last button press
    move.b  #0,3(a1)        ; reset hold length counter
    addq.w  #2,(Demo_button_index).w ; advance to next button press
    andi.w  #$3FF,(Demo_button_index).w ; wrap at max button press changes 1024
; loc_486A:
MoveDemo_Record_P2:
    cmpi.b  #emerald_hill_zone,(Current_Zone).w
    bne.s   ++  ; rts
    lea ($FEC000).l,a1      ; output location of recorded player 2 demo? (unknown)
    move.w  (Demo_button_index_2P).w,d0
    adda.w  d0,a1
    move.b  (Ctrl_2_Held).w,d0  ; load input of player 2
    cmp.b   (a1),d0         ; is same button held?
    bne.s   +           ; if not, branch
    addq.b  #1,1(a1)        ; increment press length counter
    cmpi.b  #$FF,1(a1)      ; is button held too long?
    beq.s   +           ; if yes, branch
    bra.s   ++          ; if not, return
; ===========================================================================
+
    move.b  d0,2(a1)        ; store last button press
    move.b  #0,3(a1)        ; reset hold length counter
    addq.w  #2,(Demo_button_index_2P).w ; advance to next button press
    andi.w  #$3FF,(Demo_button_index_2P).w ; wrap at max button press changes 1024
+   rts
    ; end of inactive recording code
; ===========================================================================
    ; continue with MoveSonicInDemo:
 
; loc_48AA:
MoveDemo_On:
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0
    beq.s   +
    tst.w   (Demo_mode_flag).w
    bmi.s   +
    move.b  #GameModeID_TitleScreen,(Game_Mode).w ; => TitleScreen
+
    lea (DemoScriptPointers).l,a1 ; load pointer to input data
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w ; special stage mode?
    bne.s   MoveDemo_On_P1      ; if yes, branch
    moveq   #6,d0
; loc_48DA:
MoveDemo_On_P1:
    lsl.w   #2,d0
    movea.l (a1,d0.w),a1
 
    move.w  (Demo_button_index).w,d0
    adda.w  d0,a1   ; a1 now points to the current button press data
    move.b  (a1),d0 ; load button press
    lea (Ctrl_1_Held).w,a0
    move.b  d0,d1
    moveq   #0,d2 ; this was modified from (a0) to #0 in Rev01 of Sonic 1 to nullify the following line
    eor.b   d2,d0   ; does nothing now (used to let you hold a button to prevent Sonic from jumping in demos)
    move.b  d1,(a0)+ ; save button press data from demo to Ctrl_1_Held
    and.b   d1,d0   ; does nothing now
    move.b  d0,(a0)+ ; save the same thing to Ctrl_1_Press
    subq.b  #1,(Demo_press_counter).w  ; decrement counter until next press
    bcc.s   MoveDemo_On_P2     ; if it isn't 0 yet, branch
    move.b  3(a1),(Demo_press_counter).w ; reset counter to length of next press
    addq.w  #2,(Demo_button_index).w ; advance to next button press
; loc_4908:
MoveDemo_On_P2:
    if emerald_hill_zone_act_1<$100 ; will it fit within a byte?
    cmpi.b  #emerald_hill_zone_act_1,(Current_Zone).w
    else
    cmpi.w #emerald_hill_zone_act_1,(Current_ZoneAndAct).w ; avoid a range overflow error
    endif
    bne.s   MoveDemo_On_SkipP2 ; if it's not the EHZ demo, branch to skip player 2
    lea (Demo_EHZ_Tails).l,a1
 
    ; same as the corresponding remainder of MoveDemo_On_P1, but for player 2
    move.w  (Demo_button_index_2P).w,d0
    adda.w  d0,a1
    move.b  (a1),d0
    lea (Ctrl_2_Held).w,a0
    move.b  d0,d1
    moveq   #0,d2
    eor.b   d2,d0
    move.b  d1,(a0)+
    and.b   d1,d0
    move.b  d0,(a0)+
    subq.b  #1,(Demo_press_counter_2P).w
    bcc.s   +   ; rts
    move.b  3(a1),(Demo_press_counter_2P).w
    addq.w  #2,(Demo_button_index_2P).w
+
    rts
; ===========================================================================
; loc_4940:
MoveDemo_On_SkipP2:
    move.w  #0,(Ctrl_2).w
    rts
; End of function MoveSonicInDemo
 
; ===========================================================================
; ---------------------------------------------------------------------------
; DEMO SCRIPT POINTERS
 
; Contains an array of pointers to the script controlling the players actions
; to use for each level.
; ---------------------------------------------------------------------------
; off_4948:
DemoScriptPointers: zoneOrderedTable 4,1
    zoneTableEntry.l Demo_EHZ   ; $00
    zoneTableEntry.l Demo_EHZ   ; $01
    zoneTableEntry.l Demo_EHZ   ; $02
    zoneTableEntry.l Demo_EHZ   ; $03
    zoneTableEntry.l Demo_EHZ   ; $04
    zoneTableEntry.l Demo_EHZ   ; $05
    zoneTableEntry.l Demo_EHZ   ; $06
    zoneTableEntry.l Demo_EHZ   ; $07
    zoneTableEntry.l Demo_EHZ   ; $08
    zoneTableEntry.l Demo_EHZ   ; $09
    zoneTableEntry.l Demo_EHZ   ; $0A
    zoneTableEntry.l Demo_EHZ   ; $0B
    zoneTableEntry.l Demo_CNZ   ; $0C
    zoneTableEntry.l Demo_CPZ   ; $0D
    zoneTableEntry.l Demo_EHZ   ; $0E
    zoneTableEntry.l Demo_ARZ   ; $0F
    zoneTableEntry.l Demo_EHZ   ; $10
    zoneTableEnd
; ---------------------------------------------------------------------------
; dword_498C:
EndingDemoScriptPointers:
    ; these values are invalid addresses, but they were used for the ending
    ; demos, which aren't present in Sonic 2
    dc.l   $8B0837
    dc.l   $42085C  ; 1
    dc.l   $6A085F  ; 2
    dc.l   $2F082C  ; 3
    dc.l   $210803  ; 4
    dc.l $28300808  ; 5
    dc.l   $2E0815  ; 6
    dc.l    $F0846  ; 7
    dc.l   $1A08FF  ; 8
    dc.l  $8CA0000  ; 9
    dc.l         0  ; 10
    dc.l         0  ; 11
 
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_49BC:
LoadCollisionIndexes:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    lsl.w   #2,d0
    move.l  #Primary_Collision,(Collision_addr).w
    move.w  d0,-(sp)
    movea.l Off_ColP(pc,d0.w),a0
    lea (Primary_Collision).w,a1
    bsr.w   KosDec
    move.w  (sp)+,d0
    movea.l Off_ColS(pc,d0.w),a0
    lea (Secondary_Collision).w,a1
    bra.w   KosDec
; End of function LoadCollisionIndexes
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Pointers to primary collision indexes
 
; Contains an array of pointers to the primary collision index data for each
; level. 1 pointer for each level, pointing the primary collision index.
; ---------------------------------------------------------------------------
Off_ColP: zoneOrderedTable 4,1
    zoneTableEntry.l ColP_EHZHTZ
    zoneTableEntry.l ColP_Invalid   ; 1
    zoneTableEntry.l ColP_MTZ   ; 2
    zoneTableEntry.l ColP_Invalid   ; 3
    zoneTableEntry.l ColP_MTZ   ; 4
    zoneTableEntry.l ColP_MTZ   ; 5
    zoneTableEntry.l ColP_WFZSCZ    ; 6
    zoneTableEntry.l ColP_EHZHTZ    ; 7
    zoneTableEntry.l ColP_HPZ   ; 8
    zoneTableEntry.l ColP_Invalid   ; 9
    zoneTableEntry.l ColP_OOZ   ; 10
    zoneTableEntry.l ColP_MCZ   ; 11
    zoneTableEntry.l ColP_CNZ   ; 12
    zoneTableEntry.l ColP_CPZDEZ    ; 13
    zoneTableEntry.l ColP_CPZDEZ    ; 14
    zoneTableEntry.l ColP_ARZ   ; 15
    zoneTableEntry.l ColP_WFZSCZ    ; 16
    zoneTableEnd
 
; ---------------------------------------------------------------------------
; Pointers to secondary collision indexes
 
; Contains an array of pointers to the secondary collision index data for
; each level. 1 pointer for each level, pointing the secondary collision
; index.
; ---------------------------------------------------------------------------
Off_ColS: zoneOrderedTable 4,1
    zoneTableEntry.l ColS_EHZHTZ
    zoneTableEntry.l ColP_Invalid   ; 1
    zoneTableEntry.l ColP_MTZ   ; 2
    zoneTableEntry.l ColP_Invalid   ; 3
    zoneTableEntry.l ColP_MTZ   ; 4
    zoneTableEntry.l ColP_MTZ   ; 5
    zoneTableEntry.l ColS_WFZSCZ    ; 6
    zoneTableEntry.l ColS_EHZHTZ    ; 7
    zoneTableEntry.l ColS_HPZ   ; 8
    zoneTableEntry.l ColP_Invalid   ; 9
    zoneTableEntry.l ColP_OOZ   ; 10
    zoneTableEntry.l ColP_MCZ   ; 11
    zoneTableEntry.l ColS_CNZ   ; 12
    zoneTableEntry.l ColS_CPZDEZ    ; 13
    zoneTableEntry.l ColS_CPZDEZ    ; 14
    zoneTableEntry.l ColS_ARZ   ; 15
    zoneTableEntry.l ColS_WFZSCZ    ; 16
    zoneTableEnd
 
 
; ---------------------------------------------------------------------------
; Oscillating number subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4A70:
OscillateNumInit:
    lea (Oscillating_Numbers).w,a1
    lea (Osc_Data).l,a2
    moveq   #bytesToWcnt(Osc_Data_End-Osc_Data),d1
; loc_4A7C:
Osc_Loop:
    move.w  (a2)+,(a1)+
    dbf d1,Osc_Loop
    rts
; End of function OscillateNumInit
 
; ===========================================================================
; word_4A84:
Osc_Data:
    dc.w %0000000001111101      ; oscillation direction bitfield
    dc.w   $80,   0 ; baseline values
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w   $80,   0
    dc.w $3848, $EE
    dc.w $2080, $B4
    dc.w $3080,$10E
    dc.w $5080,$1C2
    dc.w $7080,$276
    dc.w   $80,   0
    dc.w $4000, $FE
Osc_Data_End:
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4AC6:
OscillateNumDo:
    tst.w   (Two_player_mode).w
    bne.s   +
    cmpi.b  #6,(MainCharacter+routine).w
    bhs.s   OscillateNumDo_Return
+
    lea (Oscillating_Numbers).w,a1
    lea (Osc_Data2).l,a2
    move.w  (a1)+,d3
    moveq   #bytesToLcnt(Osc_Data2_End-Osc_Data2),d1
 
-   move.w  (a2)+,d2
    move.w  (a2)+,d4
    btst    d1,d3
    bne.s   +
    move.w  2(a1),d0
    add.w   d2,d0
    move.w  d0,2(a1)
    _add.w  d0,0(a1)
    _cmp.b  0(a1),d4
    bhi.s   ++
    bset    d1,d3
    bra.s   ++
; ===========================================================================
+
    move.w  2(a1),d0
    sub.w   d2,d0
    move.w  d0,2(a1)
    _add.w  d0,0(a1)
    _cmp.b  0(a1),d4
    bls.s   +
    bclr    d1,d3
+
    addq.w  #4,a1
    dbf d1,-
 
    move.w  d3,(Oscillation_Control).w
; return_4B22:
OscillateNumDo_Return:
    rts
; End of function OscillateNumDo
 
; ===========================================================================
; word_4B24:
Osc_Data2:
    dc.w     2, $10
    dc.w     2, $18
    dc.w     2, $20
    dc.w     2, $30
    dc.w     4, $20
    dc.w     8,   8
    dc.w     8, $40
    dc.w     4, $40
    dc.w     2, $38
    dc.w     2, $38
    dc.w     2, $20
    dc.w     3, $30
    dc.w     5, $50
    dc.w     7, $70
    dc.w     2, $40
    dc.w     2, $40
Osc_Data2_End:
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to change global object animation variables (like rings)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4B64:
ChangeRingFrame:
    subq.b  #1,(Logspike_anim_counter).w
    bpl.s   +
    move.b  #$B,(Logspike_anim_counter).w
    subq.b  #1,(Logspike_anim_frame).w ; animate unused log spikes
    andi.b  #7,(Logspike_anim_frame).w
+
    subq.b  #1,(Rings_anim_counter).w
    bpl.s   +
    move.b  #7,(Rings_anim_counter).w
    addq.b  #1,(Rings_anim_frame).w ; animate rings in the level (obj25)
    andi.b  #3,(Rings_anim_frame).w
+
    subq.b  #1,(Unknown_anim_counter).w
    bpl.s   +
    move.b  #7,(Unknown_anim_counter).w
    addq.b  #1,(Unknown_anim_frame).w ; animate nothing (deleted special stage object is my best guess)
    cmpi.b  #6,(Unknown_anim_frame).w
    blo.s   +
    move.b  #0,(Unknown_anim_frame).w
+
    tst.b   (Ring_spill_anim_counter).w
    beq.s   +   ; rts
    moveq   #0,d0
    move.b  (Ring_spill_anim_counter).w,d0
    add.w   (Ring_spill_anim_accum).w,d0
    move.w  d0,(Ring_spill_anim_accum).w
    rol.w   #7,d0
    andi.w  #3,d0
    move.b  d0,(Ring_spill_anim_frame).w ; animate scattered rings (obj37)
    subq.b  #1,(Ring_spill_anim_counter).w
+
    rts
; End of function ChangeRingFrame
 
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
nosignpost macro actid
    cmpi.w  #actid,(Current_ZoneAndAct).w
    beq.ATTRIBUTE   +   ; rts
    endm
 
; sub_4BD2:
SetLevelEndType:
    move.w  #0,(Level_Has_Signpost).w   ; set level type to non-signpost
    tst.w   (Two_player_mode).w ; is it two-player competitive mode?
    bne.s   LevelEnd_SetSignpost    ; if yes, branch
    nosignpost.w emerald_hill_zone_act_2
    nosignpost.w metropolis_zone_act_3
    nosignpost.w wing_fortress_zone_act_1
    nosignpost.w hill_top_zone_act_2
    nosignpost.w oil_ocean_zone_act_2
    nosignpost.s mystic_cave_zone_act_2
    nosignpost.s casino_night_zone_act_2
    nosignpost.s chemical_plant_zone_act_2
    nosignpost.s death_egg_zone_act_1
    nosignpost.s aquatic_ruin_zone_act_2
    nosignpost.s sky_chase_zone_act_1
 
; loc_4C40:
LevelEnd_SetSignpost:
    move.w  #1,(Level_Has_Signpost).w   ; set level type to signpost
+   rts
; End of function SetLevelEndType
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4C48:
CheckLoadSignpostArt:
    tst.w   (Level_Has_Signpost).w
    beq.s   +   ; rts
    tst.w   (Debug_placement_mode).w
    bne.s   +   ; rts
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Max_X_pos).w,d1
    subi.w  #$100,d1
    cmp.w   d1,d0
    blt.s   SignpostUpdateTailsBounds
    tst.b   (Update_HUD_timer).w
    beq.s   SignpostUpdateTailsBounds
    cmp.w   (Camera_Min_X_pos).w,d1
    beq.s   SignpostUpdateTailsBounds
    move.w  d1,(Camera_Min_X_pos).w ; prevent camera from scrolling back to the left
    tst.w   (Two_player_mode).w
    bne.s   +   ; rts
    moveq   #PLCID_Signpost,d0 ; <== PLC_1F
    bra.w   LoadPLC2        ; load signpost art
; ---------------------------------------------------------------------------
; loc_4C80:
SignpostUpdateTailsBounds:
    tst.w   (Two_player_mode).w
    beq.s   +   ; rts
    move.w  (Camera_X_pos_P2).w,d0
    move.w  (Tails_Max_X_pos).w,d1
    subi.w  #$100,d1
    cmp.w   d1,d0
    blt.s   +   ; rts
    tst.b   (Update_HUD_timer_2P).w
    beq.s   +   ; rts
    cmp.w   (Tails_Min_X_pos).w,d1
    beq.s   +   ; rts
    move.w  d1,(Tails_Min_X_pos).w ; prevent Tails from going past new left boundary
+   rts
; End of function CheckLoadSignpostArt
 
 
 
 
; ===========================================================================
; macro to simplify editing the demo scripts
demoinput macro buttons,duration
btns_mask := 0
idx := 0
  rept strlen("buttons")
btn := substr("buttons",idx,1)
    switch btn
    case "U"
btns_mask := btns_mask|button_up_mask
    case "D"
btns_mask := btns_mask|button_down_mask
    case "L"
btns_mask := btns_mask|button_left_mask
    case "R"
btns_mask := btns_mask|button_right_mask
    case "A"
btns_mask := btns_mask|button_A_mask
    case "B"
btns_mask := btns_mask|button_B_mask
    case "C"
btns_mask := btns_mask|button_C_mask
    case "S"
btns_mask := btns_mask|button_start_mask
    endcase
idx := idx+1
  endm
    dc.b    btns_mask,duration-1
 endm
; ---------------------------------------------------------------------------
; EHZ Demo Script (Sonic)
; ---------------------------------------------------------------------------
; byte_4CA8: Demo_Def:
Demo_EHZ:
    demoinput , $4C
    demoinput R,    $43
    demoinput RC,   9
    demoinput R,    $3F
    demoinput RC,   6
    demoinput R,    $B0
    demoinput RC,   $A
    demoinput R,    $46
    demoinput , $1E
    demoinput L,    $F
    demoinput , 5
    demoinput L,    5
    demoinput , 9
    demoinput L,    $3F
    demoinput , 5
    demoinput R,    $67
    demoinput , $62
    demoinput R,    $12
    demoinput , $22
    demoinput D,    8
    demoinput DC,   7
    demoinput D,    $E
    demoinput , $3C
    demoinput R,    $A
    demoinput , $1E
    demoinput D,    7
    demoinput DC,   7
    demoinput D,    2
    demoinput , $F
    demoinput R,    $100
    demoinput R,    $2F
    demoinput , $23
    demoinput C,    8
    demoinput RC,   $10
    demoinput R,    3
    demoinput , $30
    demoinput RC,   $24
    demoinput R,    $BE
    demoinput , $C
    demoinput L,    $14
    demoinput , $17
    demoinput D,    3
    demoinput DC,   7
    demoinput D,    3
    demoinput , $64
    demoinput S,    1
    demoinput A,    1
    demoinput , 1
; ---------------------------------------------------------------------------
; EHZ Demo Script (Tails)
; ---------------------------------------------------------------------------
; byte_4D08:
Demo_EHZ_Tails:
    demoinput , $3C
    demoinput R,    $10
    demoinput UR,   $44
    demoinput URC,  $7
    demoinput UR,   $7
    demoinput R,    $CA
    demoinput , $12
    demoinput R,    $2
    demoinput RC,   $9
    demoinput R,    $53
    demoinput , $12
    demoinput R,    $B
    demoinput RC,   $F
    demoinput R,    $24
    demoinput , $B
    demoinput C,    $5
    demoinput , $E
    demoinput R,    $56
    demoinput , $1F
    demoinput R,    $5B
    demoinput , $11
    demoinput R,    $100
    demoinput R,    $C1
    demoinput , $21
    demoinput L,    $E
    demoinput , $E
    demoinput C,    $5
    demoinput RC,   $10
    demoinput C,    $6
    demoinput , $D
    demoinput L,    $6
    demoinput , $5F
    demoinput R,    $74
    demoinput , $19
    demoinput L,    $45
    demoinput , $9
    demoinput D,    $31
    demoinput , $9
    demoinput R,    $E
    demoinput , $24
    demoinput R,    $28
    demoinput , $5
    demoinput R,    $1
    demoinput , $1
    demoinput , $1
    demoinput , $1
    demoinput , $1
    demoinput , $1
; ---------------------------------------------------------------------------
; CNZ Demo Script
; ---------------------------------------------------------------------------
Demo_CNZ:
    demoinput , $49
    demoinput R,    $11
    demoinput UR,   1
    demoinput R,    2
    demoinput UR,   7
    demoinput R,    $61
    demoinput RC,   6
    demoinput C,    2
    demoinput , 9
    demoinput L,    3
    demoinput DL,   4
    demoinput L,    2
    demoinput , $1A
    demoinput R,    $12
    demoinput RC,   $1A
    demoinput C,    5
    demoinput RC,   $24
    demoinput R,    $1B
    demoinput , 8
    demoinput L,    $11
    demoinput , $F
    demoinput R,    $78
    demoinput RC,   $17
    demoinput C,    1
    demoinput , $10
    demoinput L,    $12
    demoinput , 8
    demoinput R,    $53
    demoinput , $70
    demoinput R,    $75
    demoinput , $38
    demoinput R,    $17
    demoinput , 5
    demoinput L,    $27
    demoinput , $D
    demoinput L,    $13
    demoinput , $6A
    demoinput C,    $11
    demoinput RC,   3
    demoinput DRC,  6
    demoinput DR,   $15
    demoinput R,    6
    demoinput , 6
    demoinput L,    $D
    demoinput , $49
    demoinput L,    $A
    demoinput , $1F
    demoinput R,    7
    demoinput , $30
    demoinput L,    2
    demoinput , $100
    demoinput , $50
    demoinput R,    1
    demoinput RC,   $C
    demoinput R,    $2B
    demoinput , $5F
; ---------------------------------------------------------------------------
; CPZ Demo Script
; ---------------------------------------------------------------------------
Demo_CPZ:
    demoinput , $47
    demoinput R,    $1C
    demoinput RC,   8
    demoinput R,    $A
    demoinput , $1C
    demoinput R,    $E
    demoinput RC,   $29
    demoinput R,    $100
    demoinput R,    $E8
    demoinput DR,   5
    demoinput D,    2
    demoinput L,    $34
    demoinput DL,   $68
    demoinput L,    1
    demoinput , $16
    demoinput C,    1
    demoinput LC,   8
    demoinput L,    $F
    demoinput , $18
    demoinput R,    2
    demoinput DR,   2
    demoinput R,    $D
    demoinput , $20
    demoinput RC,   7
    demoinput R,    $B
    demoinput , $1C
    demoinput L,    $E
    demoinput , $1D
    demoinput L,    7
    demoinput , $100
    demoinput , $E0
    demoinput R,    $F
    demoinput , $1D
    demoinput L,    3
    demoinput , $26
    demoinput R,    7
    demoinput , 7
    demoinput C,    5
    demoinput , $29
    demoinput L,    $12
    demoinput , $18
    demoinput R,    $1A
    demoinput , $11
    demoinput L,    $2E
    demoinput , $14
    demoinput S,    1
    demoinput A,    1
    demoinput , 1
; ---------------------------------------------------------------------------
; ARZ Demo Script
; ---------------------------------------------------------------------------
Demo_ARZ:
    demoinput , $43
    demoinput R,    $4B
    demoinput RC,   9
    demoinput R,    $50
    demoinput RC,   $C
    demoinput R,    6
    demoinput , $1B
    demoinput R,    $61
    demoinput RC,   $15
    demoinput R,    $55
    demoinput , $41
    demoinput R,    5
    demoinput UR,   1
    demoinput R,    $5C
    demoinput , $47
    demoinput R,    $3C
    demoinput RC,   9
    demoinput R,    $28
    demoinput , $B
    demoinput R,    $93
    demoinput RC,   $33
    demoinput R,    $23
    demoinput , $23
    demoinput R,    $4D
    demoinput , $1F
    demoinput L,    2
    demoinput UL,   3
    demoinput L,    1
    demoinput , $B
    demoinput L,    $D
    demoinput , $11
    demoinput R,    6
    demoinput , $62
    demoinput R,    4
    demoinput RC,   6
    demoinput R,    $17
    demoinput , $1C
    demoinput R,    $57
    demoinput RC,   $B
    demoinput R,    $17
    demoinput , $16
    demoinput R,    $D
    demoinput , $2C
    demoinput C,    2
    demoinput RC,   $1B
    demoinput R,    $83
    demoinput , $C
    demoinput S,    1
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
 
;sub_4E98:
LoadZoneTiles:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    lea (LevelArtPointers).l,a2
    lea (a2,d0.w),a2
    move.l  (a2)+,d0
    andi.l  #$FFFFFF,d0 ; 8x8 tile pointer
    movea.l d0,a0
    lea (Chunk_Table).l,a1
    bsr.w   KosDec
    move.w  a1,d3
    cmpi.b  #hill_top_zone,(Current_Zone).w
    bne.s   +
    lea (ArtKos_HTZ).l,a0
    lea (Chunk_Table+tiles_to_bytes(ArtTile_ArtKos_NumTiles_HTZ_Main)).l,a1
    bsr.w   KosDec  ; patch for HTZ
    move.w  #tiles_to_bytes(ArtTile_ArtKos_NumTiles_HTZ),d3
+
    cmpi.b  #wing_fortress_zone,(Current_Zone).w
    bne.s   +
    lea (ArtKos_WFZ).l,a0
    lea (Chunk_Table+tiles_to_bytes(ArtTile_ArtKos_NumTiles_WFZ_Main)).l,a1
    bsr.w   KosDec  ; patch for WFZ
    move.w  #tiles_to_bytes(ArtTile_ArtKos_NumTiles_WFZ),d3
+
    cmpi.b  #death_egg_zone,(Current_Zone).w
    bne.s   +
    move.w  #tiles_to_bytes(ArtTile_ArtKos_NumTiles_DEZ),d3
+
    move.w  d3,d7
    andi.w  #$FFF,d3
    lsr.w   #1,d3
    rol.w   #4,d7
    andi.w  #$F,d7
 
-   move.w  d7,d2
    lsl.w   #7,d2
    lsl.w   #5,d2
    move.l  #$FFFFFF,d1
    move.w  d2,d1
    jsr (QueueDMATransfer).l
    move.w  d7,-(sp)
    move.b  #VintID_TitleCard,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.w   RunPLC_RAM
    move.w  (sp)+,d7
    move.w  #$800,d3
    dbf d7,-
 
    rts
; End of function LoadZoneTiles
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_loadZoneBlockMaps 
    jmp (loadZoneBlockMaps).l
JmpTo_DeformBgLayer 
    jmp (DeformBgLayer).l
JmpTo_AniArt_Load 
    jmp (AniArt_Load).l
JmpTo_DrawInitialBG 
    jmp (DrawInitialBG).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; loc_4F64:
SpecialStage:
    cmpi.b  #7,(Current_Special_Stage).w
    blo.s   +
    move.b  #0,(Current_Special_Stage).w
+
    move.w  #SndID_SpecStageEntry,d0 ; play that funky special stage entry sound
    bsr.w   PlaySound
    move.b  #MusID_FadeOut,d0 ; fade out the music
    bsr.w   PlayMusic
    bsr.w   Pal_FadeToWhite
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  #0,(Two_player_mode).w
    st.b    (SS_2p_Flag).w ; set to -1
    bra.s   ++
; ===========================================================================
+
    sf.b    (SS_2p_Flag).w ; set to 0
; (!)
+
    move    #$2700,sr       ; Mask all interrupts
    lea (VDP_control_port).l,a6
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8ADF,(Hint_counter_reserve).w ; H-INT every 224th scanline
    move.w  #$8200|(VRAM_SS_Plane_A_Name_Table1/$400),(a6)  ; PNT A base: $C000
    move.w  #$8400|(VRAM_SS_Plane_B_Name_Table/$2000),(a6)  ; PNT B base: $A000
    move.w  #$8C08,(a6)     ; H res 32 cells, no interlace, S/H enabled
    move.w  #$9003,(a6)     ; Scroll table size: 128x32
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    move.w  #$8D00|(VRAM_SS_Horiz_Scroll_Table/$400),(a6)       ; H scroll table base: $FC00
    move.w  #$8500|(VRAM_SS_Sprite_Attribute_Table/$200),(a6)   ; Sprite attribute table base: $F800
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
 
; /------------------------------------------------------------------------\
; | We're gonna zero-fill a bunch of VRAM regions. This was done by macro, |
; | so there's gonna be a lot of wasted cycles.                            |
; \------------------------------------------------------------------------/
    
    dmaFillVRAM 0,VRAM_SS_Plane_A_Name_Table2,VRAM_SS_Plane_Table_Size ; clear Plane A pattern name table 1
    dmaFillVRAM 0,VRAM_SS_Plane_A_Name_Table1,VRAM_SS_Plane_Table_Size ; clear Plane A pattern name table 2
    dmaFillVRAM 0,VRAM_SS_Plane_B_Name_Table,VRAM_SS_Plane_Table_Size ; clear Plane B pattern name table
    dmaFillVRAM 0,VRAM_SS_Horiz_Scroll_Table,VRAM_SS_Horiz_Scroll_Table_Size  ; clear Horizontal scroll table
 
    clr.l   (Vscroll_Factor).w
    clr.l   (unk_F61A).w
    clr.b   (SpecialStage_Started).w
 
; /------------------------------------------------------------------------\
; | Now we clear out some regions in main RAM where we want to store some  |
; | of our data structures.                                                |
; \------------------------------------------------------------------------/
    ; Bug: These '+4's shouldn't be here; clearRAM accidentally clears an additional 4 bytes
    clearRAM SS_Sprite_Table,SS_Sprite_Table_End+4
    clearRAM SS_Horiz_Scroll_Buf_1,SS_Horiz_Scroll_Buf_1_End+4
    clearRAM SS_Misc_Variables,SS_Misc_Variables_End+4
    clearRAM SS_Sprite_Table_Input,SS_Sprite_Table_Input_End
    clearRAM SS_Object_RAM,SS_Object_RAM_End
 
    move    #$2300,sr
    lea (VDP_control_port).l,a6
    move.w  #$8F02,(a6)     ; VRAM pointer increment: $0002
    bsr.w   ssInitTableBuffers
    bsr.w   ssLdComprsdData
    move.w  #0,(SpecialStage_CurrentSegment).w
    moveq   #PLCID_SpecialStage,d0
    bsr.w   RunPLC_ROM
    clr.b   (Level_started_flag).w
    move.l  #0,(Camera_X_pos).w ; probably means something else in this context
    move.l  #0,(Camera_Y_pos).w
    move.l  #0,(Camera_X_pos_copy).w
    move.l  #0,(Camera_Y_pos_copy).w
    cmpi.w  #1,(Player_mode).w  ; is this a Tails alone game?
    bgt.s   +           ; if yes, branch
    move.b  #ObjID_SonicSS,(MainCharacter+id).w ; load Obj09 (special stage Sonic)
    tst.w   (Player_mode).w     ; is this a Sonic and Tails game?
    bne.s   ++          ; if not, branch
+   move.b  #ObjID_TailsSS,(Sidekick+id).w ; load Obj10 (special stage Tails)
+   move.b  #ObjID_SSHUD,(SpecialStageHUD+id).w ; load Obj5E (special stage HUD)
    move.b  #ObjID_StartBanner,(SpecialStageStartBanner+id).w ; load Obj5F (special stage banner)
    move.b  #ObjID_SSNumberOfRings,(SpecialStageNumberOfRings+id).w ; load Obj87 (special stage ring count)
    move.w  #$80,(SS_Offset_X).w
    move.w  #$36,(SS_Offset_Y).w
    bsr.w   SSPlaneB_Background
    bsr.w   SSDecompressPlayerArt
    bsr.w   SSInitPalAndData
    move.l  #$C0000,(SS_New_Speed_Factor).w
    clr.w   (Ctrl_1_Logical).w
    clr.w   (Ctrl_2_Logical).w
 
-   move.b  #VintID_S2SS,(Vint_routine).w
    bsr.w   WaitForVint
    move.b  (SSTrack_drawing_index).w,d0
    bne.s   -
 
    bsr.w   SSTrack_Draw
 
-   move.b  #VintID_S2SS,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.w   SSTrack_Draw
    bsr.w   SSLoadCurrentPerspective
    bsr.w   SSObjectsManager
    move.b  (SSTrack_duration_timer).w,d0
    subq.w  #1,d0
    bne.s   -
 
    jsr (Obj5A_CreateRingsToGoText).l
    bsr.w   SS_ScrollBG
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    move.b  #VintID_CtrlDMA,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  #MusID_SpecStage,d0
    bsr.w   PlayMusic
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromWhite
 
-   bsr.w   PauseGame
    move.w  (Ctrl_1).w,(Ctrl_1_Logical).w
    move.w  (Ctrl_2).w,(Ctrl_2_Logical).w
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w ; special stage mode?
    bne.w   SpecialStage_Unpause        ; if not, branch
    move.b  #VintID_S2SS,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.w   SSTrack_Draw
    bsr.w   SSSetGeometryOffsets
    bsr.w   SSLoadCurrentPerspective
    bsr.w   SSObjectsManager
    bsr.w   SS_ScrollBG
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    tst.b   (SpecialStage_Started).w
    beq.s   -
 
    moveq   #PLCID_SpecStageBombs,d0
    bsr.w   LoadPLC
 
-   bsr.w   PauseGame
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w ; special stage mode?
    bne.w   SpecialStage_Unpause        ; if not, branch
    move.b  #VintID_S2SS,(Vint_routine).w
    bsr.w   WaitForVint
    bsr.w   SSTrack_Draw
    bsr.w   SSSetGeometryOffsets
    bsr.w   SSLoadCurrentPerspective
    bsr.w   SSObjectsManager
    bsr.w   SS_ScrollBG
    bsr.w   PalCycle_SS
    tst.b   (SS_Pause_Only_flag).w
    beq.s   +
    move.w  (Ctrl_1).w,d0
    andi.w  #(button_start_mask<<8)|button_start_mask,d0
    move.w  d0,(Ctrl_1_Logical).w
    move.w  (Ctrl_2).w,d0
    andi.w  #(button_start_mask<<8)|button_start_mask,d0
    move.w  d0,(Ctrl_2_Logical).w
    bra.s   ++
; ===========================================================================
+
    move.w  (Ctrl_1).w,(Ctrl_1_Logical).w
    move.w  (Ctrl_2).w,(Ctrl_2_Logical).w
+
    jsr (RunObjects).l
    tst.b   (SS_Check_Rings_flag).w
    bne.s   +
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    bra.s   -
; ===========================================================================
+
    andi.b  #7,(Emerald_count).w
    tst.b   (SS_2p_Flag).w
    beq.s   +
    lea (SS2p_RingBuffer).w,a0
    move.w  (a0)+,d0
    add.w   (a0)+,d0
    add.w   (a0)+,d0
    add.w   (a0)+,d0
    add.w   (a0)+,d0
    add.w   (a0)+,d0
    bra.s   ++
; ===========================================================================
+
    move.w  (Ring_count).w,d0
    add.w   (Ring_count_2P).w,d0
+
    cmp.w   (SS_Perfect_rings_left).w,d0
    bne.s   +
    st.b    (Perfect_rings_flag).w
+
    bsr.w   Pal_FadeToWhite
    tst.w   (Two_player_mode_copy).w
    bne.w   loc_540C
    move    #$2700,sr
    lea (VDP_control_port).l,a6
    move.w  #$8200|(VRAM_Menu_Plane_A_Name_Table/$400),(a6)     ; PNT A base: $C000
    move.w  #$8400|(VRAM_Menu_Plane_B_Name_Table/$2000),(a6)    ; PNT B base: $E000
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    bsr.w   ClearScreen
    jsrto   (Hud_Base).l, JmpTo_Hud_Base
    clr.w   (VDP_Command_Buffer).w
    move.l  #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w
    move    #$2300,sr
    moveq   #PalID_Result,d0
    bsr.w   PalLoad_Now
    moveq   #PLCID_Std1,d0
    bsr.w   LoadPLC2
    move.l  #vdpComm(tiles_to_bytes(ArtTile_VRAM_Start+2),VRAM,WRITE),d0
    lea SpecialStage_ResultsLetters(pc),a0
    jsrto   (LoadTitleCardSS).l, JmpTo_LoadTitleCardSS
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_SpecialStageResults),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_SpecialStageResults).l,a0
    bsr.w   NemDec
    move.w  (Player_mode).w,d0
    beq.s   ++
    subq.w  #1,d0
    beq.s   +
    clr.w   (Ring_count).w
    bra.s   ++
; ===========================================================================
+
    clr.w   (Ring_count_2P).w
+
    move.w  (Ring_count).w,(Bonus_Countdown_1).w
    move.w  (Ring_count_2P).w,(Bonus_Countdown_2).w
    clr.w   (Total_Bonus_Countdown).w
    tst.b   (Got_Emerald).w
    beq.s   +
    move.w  #1000,(Total_Bonus_Countdown).w
+
    move.b  #1,(Update_HUD_score).w
    move.b  #1,(Update_Bonus_score).w
    move.w  #MusID_EndLevel,d0
    jsr (PlaySound).l
 
    clearRAM SS_Sprite_Table_Input,SS_Sprite_Table_Input_End
    clearRAM SS_Object_RAM,SS_Object_RAM_End
 
    move.b  #ObjID_SSResults,(SpecialStageResults+id).w ; load Obj6F (special stage results) at $FFFFB800
-
    move.b  #VintID_Level,(Vint_routine).w
    bsr.w   WaitForVint
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    tst.w   (Level_Inactive_flag).w
    beq.s   -
    tst.l   (Plc_Buffer).w
    bne.s   -
    move.w  #SndID_SpecStageEntry,d0
    bsr.w   PlaySound
    bsr.w   Pal_FadeToWhite
    tst.w   (Two_player_mode_copy).w
    bne.s   loc_540C
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    rts
; ===========================================================================
 
loc_540C:
    move.w  #VsRSID_SS,(Results_Screen_2P).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    rts
; ===========================================================================
 
; loc_541A:
SpecialStage_Unpause:
    move.b  #MusID_Unpause,(Music_to_play).w
    move.b  #VintID_Level,(Vint_routine).w
    bra.w   WaitForVint
 
 
 
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Animated color of the twinkling stars in the special stage background
; ---------------------------------------------------------------------------
; loc_542A: Pal_UNK8:
Pal_SpecialStageStars:  dc.w  $EEE, $CCC, $AAA, $888, $888, $AAA, $CCC, $EEE
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_543A
PalCycle_SS:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #3,d0
    bne.s   +
    move.b  (SS_Star_color_1).w,d0
    addi_.b #1,(SS_Star_color_1).w
    andi.w  #7,d0
    add.w   d0,d0
    move.w  Pal_SpecialStageStars(pc,d0.w),(Normal_palette+$1C).w
    move.b  (SS_Star_color_2).w,d0
    addi_.b #1,(SS_Star_color_2).w
    andi.w  #7,d0
    add.w   d0,d0
    move.w  Pal_SpecialStageStars(pc,d0.w),(Normal_palette+$1E).w
+
    cmpi.b  #6,(Current_Special_Stage).w
    bne.s   +
    cmpi.b  #3,(Current_Special_Act).w
    beq.w   SSCheckpoint_rainbow
/
    tst.b   (SS_Checkpoint_Rainbow_flag).w
    beq.s   +   ; rts
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    bne.s   +   ; rts
    move.b  (SS_Rainbow_palette).w,d0
    addi_.b #1,(SS_Rainbow_palette).w
    andi.b  #3,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    move.w  word_54C4(pc,d0.w),(Normal_palette_line4+$16).w
    move.w  word_54C6(pc,d0.w),(Normal_palette_line4+$18).w
    move.w  word_54C8(pc,d0.w),(Normal_palette_line4+$1A).w
+
    rts
; ===========================================================================
; special stage rainbow blinking sprite palettes... (chaos emerald colors?)
;word_54BC:
        dc.w   $0EE, $0C0, $0EE, $0C0
word_54C4:  dc.w   $0EE
word_54C6:  dc.w   $0CC
word_54C8:  dc.w   $088, $0E0, $0C0, $080, $EE0, $CC0, $880, $E0E, $C0C, $808
; ===========================================================================
 
;loc_54DC
SSCheckpoint_rainbow:
    tst.b   (SS_Pause_Only_flag).w
    beq.s   -
    moveq   #0,d0
    move.b  (Vint_runcount+3).w,d0
    andi.b  #1,d0
    bne.w   -
    move.w  (Ring_count).w,d2
    add.w   (Ring_count_2P).w,d2
    cmp.w   (SS_Ring_Requirement).w,d2
    blt.w   -
    lea (Normal_palette+2).w,a0
    movea.l a0,a1
    move.w  (a0)+,d0
 
    moveq   #$B,d1
-   move.w  (a0)+,(a1)+
    dbf d1,-
 
    move.w  d0,(a1)
    rts
; End of function PalCycle_SS
 
 
;|||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_5514
SSLoadCurrentPerspective:
    cmpi.b  #4,(SSTrack_drawing_index).w
    bne.s   +   ; rts
    movea.l #SSRAM_MiscKoz_SpecialPerspective,a0
    moveq   #0,d0
    move.b  (SSTrack_mapping_frame).w,d0
    add.w   d0,d0
    adda.w  (a0,d0.w),a0
    move.l  a0,(SS_CurrentPerspective).w
+   rts
; End of function SSLoadCurrentPerspective
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_5534
SSObjectsManager:
    cmpi.b  #4,(SSTrack_drawing_index).w
    bne.w   return_55DC
    moveq   #0,d0
    move.b  (SpecialStage_CurrentSegment).w,d0
    cmp.b   (SpecialStage_LastSegment2).w,d0
    beq.w   return_55DC
    move.b  d0,(SpecialStage_LastSegment2).w
    movea.l (SS_CurrentLevelLayout).w,a1
    move.b  (a1,d0.w),d3
    andi.w  #$7F,d3
    lea (Ani_SSTrack_Len).l,a0
    move.b  (a0,d3.w),d3
    add.w   d3,d3
    add.w   d3,d3
    movea.l (SS_CurrentLevelObjectLocations).w,a0
-
    bsr.w   SSSingleObjLoad
    bne.s   return_55DC
    moveq   #0,d0
    move.b  (a0)+,d0
    bmi.s   ++
    move.b  d0,d1
    andi.b  #$40,d1
    bne.s   +
    addq.w  #1,(SS_Perfect_rings_left).w
    move.b  #ObjID_SSRing,id(a1)
    add.w   d0,d0
    add.w   d0,d0
    add.w   d3,d0
    move.w  d0,objoff_30(a1)
    move.b  (a0)+,angle(a1)
    bra.s   -
; ===========================================================================
+
    andi.w  #$3F,d0
    move.b  #ObjID_SSBomb,id(a1)
    add.w   d0,d0
    add.w   d0,d0
    add.w   d3,d0
    move.w  d0,objoff_30(a1)
    move.b  (a0)+,angle(a1)
    bra.s   -
; ===========================================================================
+
    move.l  a0,(SS_CurrentLevelObjectLocations).w
    addq.b  #1,d0
    beq.s   return_55DC
    addq.b  #1,d0
    beq.s   ++
    addq.b  #1,d0
    beq.s   +
    st.b    (SS_NoCheckpoint_flag).w
    sf.b    (SS_NoCheckpointMsg_flag).w
    bra.s   ++
; ===========================================================================
+
    tst.b   (SS_2p_Flag).w
    bne.s   +
    move.b  #ObjID_SSEmerald,id(a1)
    rts
; ===========================================================================
+
    move.b  #ObjID_SSMessage,id(a1)
 
return_55DC:
    rts
; End of function SSObjectsManager
 
; ===========================================================================
SSTrackPNTCommands:
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table2 + 0 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table2 + 1 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table2 + 2 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table2 + 3 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table1 + 0 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table1 + 1 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table1 + 2 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
    dc.l vdpComm(VRAM_SS_Plane_A_Name_Table1 + 3 * (PNT_Buffer_End-PNT_Buffer),VRAM,WRITE)
Ani_SSTrack_Len:
    dc.b SSTrackAni_TurnThenRise_End - SSTrackAni_TurnThenRise  ; 0
    dc.b SSTrackAni_TurnThenDrop_End - SSTrackAni_TurnThenDrop  ; 1
    dc.b SSTrackAni_TurnThenStraight_End - SSTrackAni_TurnThenStraight  ; 2
    dc.b SSTrackAni_Straight_End - SSTrackAni_Straight  ; 3
    dc.b SSTrackAni_StraightThenTurn_End - SSTrackAni_StraightThenTurn  ; 4
    dc.b   0    ; 5
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_5604
SSTrack_Draw:
    moveq   #0,d0
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    cmpi.b  #4,d0                                           ; Is it time to draw a new frame?
    bge.w   SSTrackSetOrientation                           ; Branch if not
    add.w   d0,d0                                           ; Multiply by 4
    add.w   d0,d0
    bne.w   SSTrack_BeginDraw                               ; Branch if we don't need to start a new segment
    move.l  (SSTrack_last_mappings).w,(SSTrack_last_mappings_copy).w    ; Save last mappings
    move.b  (SSTrack_mapping_frame).w,(SSTrack_last_mapping_frame).w    ; Save last frame
    moveq   #0,d1
    moveq   #0,d2
    moveq   #0,d3
    moveq   #0,d4
    move.b  (SpecialStage_CurrentSegment).w,d1              ; Get current segment ID
    move.b  (SSTrack_anim_frame).w,d2                       ; Get current frame
    movea.l (SS_CurrentLevelLayout).w,a1                    ; Pointer to level layout
    move.b  (a1,d1.w),d3                                    ; Get segment geometry type
    andi.b  #$7F,d3                                         ; Strip flip flag
    move.b  d3,(SSTrack_anim).w                             ; Set this as new animation
    move.w  d3,d1                                           ; Copy to d1
    add.w   d3,d3                                           ; Turn it into an index
    lea (Ani_SpecialStageTrack).l,a1                        ; Animation table
    adda.w  (a1,d3.w),a1                                    ; Add offset so a1 points to animation data
    adda.w  d2,a1                                           ; Offset into current animation frame
    moveq   #0,d4
    move.b  (a1),d4                                         ; d4 = animation frame to draw
    move.b  d4,(SSTrack_mapping_frame).w                    ; Save to RAM
    lsl.w   #2,d4
    lea (Map_SpecialStageTrack).l,a1                        ; Mappings table
    movea.l (a1,d4.w),a0                                    ; a0 = pointer to mappings for current track frame
    movea.l a0,a1                                           ; Copy to a1
    moveq   #0,d2
    move.b  (a0)+,d2                                        ; Skip the first 2 bytes
    move.b  (a0)+,d2                                        ; Why not 'addq.l   #2,a0'?
    move.b  (a0)+,d2                                        ; Get byte
    lsl.w   #8,d2                                           ; Shift it up to be the high byte of a word
    move.b  (a0)+,d2                                        ; Read another byte; why not 'move.w    (a0)+,d2'?
    addq.w  #4,d2                                           ; Add 4
    adda.w  d2,a1                                           ; Use as offset from start of file
    movea.l a1,a2                                           ; Save to a2
    moveq   #0,d2
    move.b  (a1)+,d2                                        ; Skip the first 2 bytes
    move.b  (a1)+,d2                                        ; Why not 'addq.l   #2,a1'?
    move.b  (a1)+,d2                                        ; Get byte
    lsl.w   #8,d2                                           ; Shift it up to be the high byte of a word
    move.b  (a1)+,d2                                        ; Read another byte; why not 'move.w    (a1)+,d2'?
    addq.w  #4,d2                                           ; Add 4
    adda.w  d2,a2                                           ; Use as offset from previous offset
    move.b  (a2)+,d2                                        ; Ignore the first 3 bytes
    move.b  (a2)+,d2                                        ; Why not 'addq.l   #3,a2'?
    move.b  (a2)+,d2
    move.b  (a2)+,d2                                        ; Get byte (unused)
    move.l  a0,(SSTrack_mappings_bitflags).w                ; Save pointer to bit flags mappings
    move.l  a0,(SSTrack_last_mappings).w                    ; ... twice
    move.l  a1,(SSTrack_mappings_uncompressed).w            ; Save pointer to uncompressed mappings
    move.l  a2,(SSTrack_mappings_RLE).w                     ; Save pointer to RLE mappings
    lea_    Ani_SSTrack_Len,a4                              ; Pointer to animation lengths
    move.b  (a4,d1.w),d2                                    ; Get length of current animation
    move.b  (SSTrack_anim_frame).w,(SSTrack_last_anim_frame).w  ; Save old frame
    addi_.b #1,(SSTrack_anim_frame).w                       ; Increment current frame
    cmp.b   (SSTrack_anim_frame).w,d2                       ; Compare with animation length
    bne.s   SSTrack_BeginDraw                               ; If not equal, branch
    move.b  #0,(SSTrack_anim_frame).w                       ; Reset to start
    move.b  (SpecialStage_CurrentSegment).w,(SpecialStage_LastSegment).w    ; Save old segment
    addi_.b #1,(SpecialStage_CurrentSegment).w              ; Increment current segment
 
;loc_56D2
SSTrack_BeginDraw:
    tst.b   (SS_Alternate_PNT).w                            ; Are we using the alternate PNT?
    beq.s   +                                               ; Branch if not
    addi.w  #$10,d0                                         ; Change where we will be drawing
+
    lea_    SSTrackPNTCommands,a3                           ; Table of VRAM commands
    movea.l (a3,d0.w),a3                                    ; Get command to set destination in VRAM for current frame
    move.l  a3,(VDP_control_port).l                         ; Send it to VDP
    lea (VDP_data_port).l,a6
    bsr.w   SSTrackSetOrientation                           ; Set oriantation flags
    movea.l (SSTrack_mappings_bitflags).w,a0                ; Get pointer to bit flags mappings
    movea.l (SSTrack_mappings_uncompressed).w,a1            ; Get pointer to uncompressed mappings
    movea.l (SSTrack_mappings_RLE).w,a2                     ; Get pointer to RLE mappings
    lea (SSDrawRegBuffer).w,a3                              ; Pointer to register buffer from last draw
    movem.w (a3)+,d2-d7                                     ; Restore registers from previous call (or set them to zero)
    lea (SSPNT_UncLUT).l,a3                                 ; Pattern name list for drawing routines
    lea (SSPNT_RLELUT).l,a4                                 ; RLE-encoded pattern name list for drawing routines
    movea.w #-8,a5                                          ; Initialize loop counter: draws 7 lines
    moveq   #0,d0
    tst.b   (SSTrack_Orientation).w                         ; Is the current segment flipped?
    bne.w   SSTrackDrawLineFlipLoop                         ; Branch if yes
 
;loc_5722
SSTrackDrawLineLoop:
    adda_.w #1,a5                                           ; Increment loop counter
    cmpa.w  #0,a5                                           ; Have all 7 lines been drawn?
    beq.w   SSTrackDraw_return                              ; If yes, return
 
;loc_572E
SSTrackDrawLoop_Inner:
    moveq   #0,d1
    subq.w  #1,d7                                           ; Subtract 1 from bit counter
    bpl.s   +                                               ; Branch if we still have bits we can use
    move.b  (a0)+,d6                                        ; Get a new byte from bit flags
    moveq   #7,d7                                           ; We now have 8 fresh new bits
+
    add.b   d6,d6                                           ; Do we have to use RLE compression?
    bcc.s   SSTrackDrawRLE                                  ; Branch if yes
    subq.b  #1,d5                                           ; Subtract 1 from bit counter
    bpl.s   +                                               ; Branch if we still have bits we can use
    move.b  (a1)+,d4                                        ; Get a new byte from uncompressed mappings pointer
    moveq   #7,d5                                           ; We now have 8 fresh new bits
+
    add.b   d4,d4                                           ; Do we need a 10-bit index?
    bcc.s   +                                               ; Branch if not
    moveq   #$A,d0                                          ; d0 = 10 bits
    sub.b   d5,d0                                           ; d0 = 10 - d5
    subq.b  #3,d0                                           ; d0 =  7 - d5; why not shorten it to 'moveq    #7,d0 \n    sub.b   d5,d0'?
    add.w   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawUnc_Read10LUT(pc,d0.w),d0
    jmp SSTrackDrawUnc_Read10LUT(pc,d0.w)
; ===========================================================================
;off_5758
SSTrackDrawUnc_Read10LUT:   offsetTable
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got7   ; 0
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got6   ; 1
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got5   ; 2
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got4   ; 3
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got3   ; 4
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got2   ; 5
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got1   ; 6
        offsetTableEntry.w SSTrackDrawUnc_Read10_Got0   ; 7
; ===========================================================================
+
    moveq   #6,d0                                           ; d0 = 6
    sub.b   d5,d0                                           ; d0 = 6 - d5
    addq.b  #1,d0                                           ; d0 = 7 - d5; why not shorten it to 'moveq #7,d0 \n    sub.b   d5,d0'?
    add.w   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawUnc_Read6LUT(pc,d0.w),d0
    jmp SSTrackDrawUnc_Read6LUT(pc,d0.w)
; ===========================================================================
;off_5778
SSTrackDrawUnc_Read6LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got7    ; 0
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got6    ; 1
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got5    ; 2
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got4    ; 3
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got3    ; 4
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got2    ; 5
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got1    ; 6
        offsetTableEntry.w SSTrackDrawUnc_Read6_Got0    ; 7
; ===========================================================================
 
SSTrackDrawRLE:
    subq.b  #1,d3                                           ; Subtract 1 from bit counter
    bpl.s   ++                                              ; Branch if we still have bits we can use
    move.b  (a2)+,d2                                        ; Get a new byte from RLE mappings pointer
    cmpi.b  #-1,d2                                          ; Is d2 equal to -1?
    bne.s   +                                               ; Branch if not
    moveq   #0,d3                                           ; Set bit counter to zero
    bra.w   SSTrackDrawLineLoop
; ===========================================================================
+
    moveq   #7,d3                                           ; We now have 8 fresh new bits
+
    add.b   d2,d2                                           ; Do we need a 7-bit index?
    bcc.s   +                                               ; Branch if not
    moveq   #7,d0                                           ; d0 = 7
    sub.b   d3,d0                                           ; d0 = 10 - d3
    add.b   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawRLE_Read7LUT(pc,d0.w),d0
    jmp SSTrackDrawRLE_Read7LUT(pc,d0.w)
; ===========================================================================
;off_57AE
SSTrackDrawRLE_Read7LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got7    ; 0
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got6    ; 1
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got5    ; 2
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got4    ; 3
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got3    ; 4
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got2    ; 5
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got1    ; 6
        offsetTableEntry.w SSTrackDrawRLE_Read7_Got0    ; 7
; ===========================================================================
+
    moveq   #6,d0                                           ; d0 = 6
    sub.b   d3,d0                                           ; d0 = 6 - d3
    addq.b  #1,d0                                           ; d0 = 7 - d3; why not shorten it to 'moveq #7,d0 \n    sub.b   d3,d0'?
    add.b   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawRLE_Read6LUT(pc,d0.w),d0
    jmp SSTrackDrawRLE_Read6LUT(pc,d0.w)
; ===========================================================================
;off_57CE
SSTrackDrawRLE_Read6LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got7    ; 0
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got6    ; 1
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got5    ; 2
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got4    ; 3
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got3    ; 4
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got2    ; 5
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got1    ; 6
        offsetTableEntry.w SSTrackDrawRLE_Read6_Got0    ; 7
; ===========================================================================
;loc_57DE
SSTrackDrawUnc_Read10_Got0:
    ; Reads 10 bits from uncompressed mappings, 0 bits in bit buffer
    moveq   #0,d0
    move.b  (a1)+,d0
    lsl.w   #2,d0
    move.b  (a1)+,d4
    rol.b   #2,d4
    move.b  d4,d1
    andi.b  #3,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #6,d5
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5806
SSTrackDrawUnc_Read10_Got1:
    ; Reads 10 bits from uncompressed mappings, 1 bit in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$200,d0
    move.b  (a1)+,d1
    lsl.w   #1,d1
    or.w    d1,d0
    move.b  (a1)+,d4
    rol.b   #1,d4
    move.b  d4,d1
    andi.b  #1,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #7,d5
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5836
SSTrackDrawUnc_Read10_Got2:
    ; Reads 10 bits from uncompressed mappings, 2 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$300,d0
    move.b  (a1)+,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #0,d5                                           ; Bit buffer now empty
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5856
SSTrackDrawUnc_Read10_Got3:
    ; Reads 10 bits from uncompressed mappings, 3 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$380,d0
    move.b  (a1)+,d4
    ror.b   #1,d4
    move.b  d4,d1
    andi.b  #$7F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #1,d5                                           ; Bit buffer now has 1 bit
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5880
SSTrackDrawUnc_Read10_Got4:
    ; Reads 10 bits from uncompressed mappings, 4 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3C0,d0
    move.b  (a1)+,d4
    ror.b   #2,d4
    move.b  d4,d1
    andi.b  #$3F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #2,d5                                           ; Bit buffer now has 2 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_58AA
SSTrackDrawUnc_Read10_Got5:
    ; Reads 10 bits from uncompressed mappings, 5 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3E0,d0
    move.b  (a1)+,d4
    ror.b   #3,d4
    move.b  d4,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #3,d5                                           ; Bit buffer now has 3 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_58D4
SSTrackDrawUnc_Read10_Got6:
    ; Reads 10 bits from uncompressed mappings, 6 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3F0,d0
    move.b  (a1)+,d4
    ror.b   #4,d4
    move.b  d4,d1
    andi.b  #$F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #4,d5                                           ; Bit buffer now has 4 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_58FE
SSTrackDrawUnc_Read10_Got7:
    ; Reads 10 bits from uncompressed mappings, 7 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3F8,d0
    move.b  (a1)+,d4
    rol.b   #3,d4
    move.b  d4,d1
    andi.b  #7,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #5,d5                                           ; Bit buffer now has 5 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5928
SSTrackDrawUnc_Read6_Got0:
    ; Reads 6 bits from uncompressed mappings, 0 bits in bit buffer
    move.b  (a1)+,d4
    ror.b   #2,d4
    move.b  d4,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #2,d5                                           ; Bit buffer now has 2 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5944
SSTrackDrawUnc_Read6_Got1:
    ; Reads 6 bits from uncompressed mappings, 1 bit in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$20,d0
    move.b  (a1)+,d4
    ror.b   #3,d4
    move.b  d4,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #3,d5                                           ; Bit buffer now has 3 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_596A
SSTrackDrawUnc_Read6_Got2:
    ; Reads 6 bits from uncompressed mappings, 2 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$30,d0
    move.b  (a1)+,d4
    ror.b   #4,d4
    move.b  d4,d1
    andi.b  #$F,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #4,d5                                           ; Bit buffer now has 4 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5990
SSTrackDrawUnc_Read6_Got3:
    ; Reads 6 bits from uncompressed mappings, 3 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$38,d0
    move.b  (a1)+,d4
    rol.b   #3,d4
    move.b  d4,d1
    andi.b  #7,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #5,d5                                           ; Bit buffer now has 5 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_59B6
SSTrackDrawUnc_Read6_Got4:
    ; Reads 6 bits from uncompressed mappings, 4 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$3C,d0
    move.b  (a1)+,d4
    rol.b   #2,d4
    move.b  d4,d1
    andi.b  #3,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #6,d5                                           ; Bit buffer now has 6 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_59DC
SSTrackDrawUnc_Read6_Got5:
    ; Reads 6 bits from uncompressed mappings, 5 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$3E,d0
    move.b  (a1)+,d4
    rol.b   #1,d4
    move.b  d4,d1
    andi.b  #1,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #7,d5                                           ; Bit buffer now has 7 bits
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5A02
SSTrackDrawUnc_Read6_Got6:
    ; Reads 6 bits from uncompressed mappings, 6 bits in bit buffer
    lsr.b   #2,d4
    andi.w  #$3F,d4
    add.w   d4,d4
    move.w  (a3,d4.w),d4
    ori.w   #palette_line_3,d4
    move.w  d4,(a6)
    moveq   #0,d5                                           ; Bit buffer now empty
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5A1A
SSTrackDrawUnc_Read6_Got7:
    ; Reads 6 bits from uncompressed mappings, 7 bits in bit buffer
    ror.b   #2,d4
    move.b  d4,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    ori.w   #palette_line_3,d0
    move.w  d0,(a6)
    moveq   #1,d5                                           ; Bit buffer now has 1 bit
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5A34
SSTrackDrawRLE_Read7_Got0:
    ; Reads 7 bits from RLE-compressed mappings, 0 bits in bit buffer
    move.b  (a2)+,d2
    ror.b   #1,d2
    move.b  d2,d0
    andi.w  #$7F,d0
    moveq   #1,d3                                           ; Bit buffer now has 1 bit
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5A66
SSTrackDrawRLE_Read7_Got1:
    ; Reads 7 bits from RLE-compressed mappings, 1 bit in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$40,d1
    move.b  (a2)+,d2
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    or.b    d1,d0
    moveq   #2,d3                                           ; Bit buffer now has 2 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5AA2
SSTrackDrawRLE_Read7_Got2:
    ; Reads 7 bits from RLE-compressed mappings, 2 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$60,d1
    move.b  (a2)+,d2
    ror.b   #3,d2
    move.b  d2,d0
    andi.w  #$1F,d0
    or.b    d1,d0
    moveq   #3,d3                                           ; Bit buffer now has 3 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5ADE
SSTrackDrawRLE_Read7_Got3:
    ; Reads 7 bits from RLE-compressed mappings, 3 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$70,d1
    move.b  (a2)+,d2
    ror.b   #4,d2
    move.b  d2,d0
    andi.w  #$F,d0
    or.b    d1,d0
    moveq   #4,d3                                           ; Bit buffer now has 4 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5B1A
SSTrackDrawRLE_Read7_Got4:
    ; Reads 7 bits from RLE-compressed mappings, 4 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$78,d1
    move.b  (a2)+,d2
    rol.b   #3,d2
    move.b  d2,d0
    andi.w  #7,d0
    or.b    d1,d0
    moveq   #5,d3                                           ; Bit buffer now has 5 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5B56
SSTrackDrawRLE_Read7_Got5:
    ; Reads 7 bits from RLE-compressed mappings, 5 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$7C,d1
    move.b  (a2)+,d2
    rol.b   #2,d2
    move.b  d2,d0
    andi.w  #3,d0
    or.b    d1,d0
    moveq   #6,d3                                           ; Bit buffer now has 6 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5B92
SSTrackDrawRLE_Read7_Got6:
    ; Reads 7 bits from RLE-compressed mappings, 6 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$7E,d1
    move.b  (a2)+,d2
    rol.b   #1,d2
    move.b  d2,d0
    andi.w  #1,d0
    or.b    d1,d0
    moveq   #7,d3                                           ; Bit buffer now has 7 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5BCE
SSTrackDrawRLE_Read7_Got7:
    ; Reads 7 bits from RLE-compressed mappings, 7 bits in bit buffer
    lsr.b   #1,d2
    andi.w  #$7F,d2
    moveq   #0,d3                                           ; Bit buffer now empty
    cmpi.b  #$7F,d2
    beq.w   SSTrackDrawLineLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d2
    add.w   d2,d2
    add.w   d2,d2
    move.w  (a4,d2.w),d1
    move.w  2(a4,d2.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5BFC
SSTrackDrawRLE_Read6_Got0:
    ; Reads 6 bits from RLE-compressed mappings, 0 bits in bit buffer
    move.b  (a2)+,d2
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #2,d3                                           ; Bit buffer now has 2 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5C22
SSTrackDrawRLE_Read6_Got1:
    ; Reads 6 bits from RLE-compressed mappings, 1 bit in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$20,d0
    move.b  (a2)+,d2
    ror.b   #3,d2
    move.b  d2,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    moveq   #3,d3                                           ; Bit buffer now has 3 bits
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5C52
SSTrackDrawRLE_Read6_Got2:
    ; Reads 6 bits from RLE-compressed mappings, 2 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$30,d0
    move.b  (a2)+,d2
    ror.b   #4,d2
    move.b  d2,d1
    andi.b  #$F,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #4,d3                                           ; Bit buffer now has 4 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5C82
SSTrackDrawRLE_Read6_Got3:
    ; Reads 6 bits from RLE-compressed mappings, 3 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$38,d0
    move.b  (a2)+,d2
    rol.b   #3,d2
    move.b  d2,d1
    andi.b  #7,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #5,d3                                           ; Bit buffer now has 5 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5CB2
SSTrackDrawRLE_Read6_Got4:
    ; Reads 6 bits from RLE-compressed mappings, 4 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$3C,d0
    move.b  (a2)+,d2
    rol.b   #2,d2
    move.b  d2,d1
    andi.b  #3,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #6,d3                                           ; Bit buffer now has 6 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5CE2
SSTrackDrawRLE_Read6_Got5:
    ; Reads 6 bits from RLE-compressed mappings, 5 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$3E,d0
    move.b  (a2)+,d2
    rol.b   #1,d2
    move.b  d2,d1
    andi.b  #1,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #7,d3                                           ; Bit buffer now has 7 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5D12
SSTrackDrawRLE_Read6_Got6:
    ; Reads 6 bits from RLE-compressed mappings, 6 bits in bit buffer
    lsr.b   #2,d2
    andi.w  #$3F,d2
    add.w   d2,d2
    add.w   d2,d2
    moveq   #0,d3                                           ; Bit buffer now empty
    move.w  (a4,d2.w),d1
    move.w  2(a4,d2.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
;loc_5D34
SSTrackDrawRLE_Read6_Got7:
    ; Reads 6 bits from RLE-compressed mappings, 7 bits in bit buffer
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #1,d3                                           ; Bit buffer now has 1 bit
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawLoop_Inner
; ===========================================================================
 
;loc_5D58
SSTrackDraw_return:
    cmpi.b  #3,(SSTrack_drawing_index).w                    ; Have we drawed a full frame?
    beq.s   +                                               ; Branch if yes
    move.l  a0,(SSTrack_mappings_bitflags).w                ; Save pointer
    move.l  a1,(SSTrack_mappings_uncompressed).w            ; Save pointer
    move.l  a2,(SSTrack_mappings_RLE).w                     ; Save pointer
    lea (SSDrawRegBuffer_End).w,a3                          ; Pointer to end of registry buffer
    movem.w d2-d7,-(a3)                                     ; Save the bit buffers and bit counters
    rts
; ===========================================================================
+
    lea (SSDrawRegBuffer).w,a2                              ; Pointer to registry buffer
    moveq   #0,d0
    rept 6
    move.w  d0,(a2)+                                        ; Clear bit buffers and bit counters
    endm
    rts
; ===========================================================================
 
;loc_5D8A
SSTrackDrawLineFlipLoop:
    adda_.w #1,a5                                           ; Increment loop counter
    cmpa.w  #0,a5                                           ; Have all 8 lines been drawn?
    beq.w   SSTrackDraw_return                              ; If yes, return
    lea (PNT_Buffer).w,a6                                   ; Destination buffer
    swap    d0                                              ; High word starts at 0
    addi.w  #$100,d0                                        ; Adding $100 means seek to end of current line/start of next line
    andi.w  #$F00,d0                                        ; Keep to confines
    adda.w  d0,a6                                           ; Seek to end of current line
    swap    d0                                              ; Leaves the low word of d0 free for use
 
;loc_5DA8
SSTrackDrawFlipLoop_Inner:
    moveq   #0,d1
    subq.w  #1,d7                                           ; Subtract 1 from bit counter
    bpl.s   +                                               ; Branch if we still have bits we can use
    move.b  (a0)+,d6                                        ; Get a new byte from bit flags
    moveq   #7,d7                                           ; We now have 8 fresh new bits
+
    add.b   d6,d6                                           ; Do we have to use RLE compression?
    bcc.s   SSTrackDrawFlipRLE                              ; Branch if yes
    subq.b  #1,d5                                           ; Subtract 1 from bit counter
    bpl.s   +                                               ; Branch if we still have bits we can use
    move.b  (a1)+,d4                                        ; Get a new byte from uncompressed mappings pointer
    moveq   #7,d5                                           ; We now have 8 fresh new bits
+
    add.b   d4,d4                                           ; Do we need a 10-bit index?
    bcc.s   +                                               ; Branch if not
    move.w  #$A,d0                                          ; d0 = 10 bits
    sub.b   d5,d0                                           ; d0 = 10 - d5
    subq.b  #3,d0                                           ; d0 =  7 - d5; why not shorten it to 'moveq    #7,d0 \n    sub.b   d5,d0'?
    add.w   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawFlipUnc_Read10LUT(pc,d0.w),d0
    jmp SSTrackDrawFlipUnc_Read10LUT(pc,d0.w)
; ===========================================================================
;off_5DD4
SSTrackDrawFlipUnc_Read10LUT:   offsetTable
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got7   ; 0
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got6   ; 1
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got5   ; 2
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got4   ; 3
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got3   ; 4
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got2   ; 5
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got1   ; 6
        offsetTableEntry.w SSTrackDrawFlipUnc_Read10_Got0   ; 7
; ===========================================================================
+
    move.w  #6,d0                                           ; d0 = 6
    sub.b   d5,d0                                           ; d0 = 6 - d5
    addq.b  #1,d0                                           ; d0 = 7 - d5; why not shorten it to 'moveq #7,d0 \n    sub.b   d5,d0'?
    add.w   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawFlipUnc_Read6LUT(pc,d0.w),d0
    jmp SSTrackDrawFlipUnc_Read6LUT(pc,d0.w)
; ===========================================================================
;off_5DF6
SSTrackDrawFlipUnc_Read6LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got7    ; 0
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got6    ; 1
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got5    ; 2
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got4    ; 3
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got3    ; 4
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got2    ; 5
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got1    ; 6
        offsetTableEntry.w SSTrackDrawFlipUnc_Read6_Got0    ; 7
; ===========================================================================
;loc_5E06
SSTrackDrawFlipRLE:
    subq.b  #1,d3                                           ; Subtract 1 from bit counter
    bpl.s   ++                                              ; Branch if we still have bits we can use
    move.b  (a2)+,d2                                        ; Get a new byte from RLE mappings pointer
    cmpi.b  #-1,d2                                          ; Is d2 equal to -1?
    bne.s   +                                               ; Branch if not
    moveq   #0,d3                                           ; Set bit counter to zero
    bra.w   SSTrackDrawLineFlipLoop
; ===========================================================================
+
    moveq   #7,d3                                           ; We now have 8 fresh new bits
+
    add.b   d2,d2                                           ; Do we need a 7-bit index?
    bcc.s   +                                               ; Branch if not
    move.w  #7,d0                                           ; d0 = 7
    sub.b   d3,d0                                           ; d0 = 10 - d3
    add.b   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawFlipRLE_Read7LUT(pc,d0.w),d0
    jmp SSTrackDrawFlipRLE_Read7LUT(pc,d0.w)
; ===========================================================================
;off_5E2E
SSTrackDrawFlipRLE_Read7LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got7    ; 0
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got6    ; 1
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got5    ; 2
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got4    ; 3
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got3    ; 4
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got2    ; 5
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got1    ; 6
        offsetTableEntry.w SSTrackDrawFlipRLE_Read7_Got0    ; 7
; ===========================================================================
+
    move.w  #6,d0                                           ; d0 = 6
    sub.b   d3,d0                                           ; d0 = 6 - d3
    addq.b  #1,d0                                           ; d0 = 7 - d3; why not shorten it to 'moveq #7,d0 \n    sub.b   d3,d0'?
    add.b   d0,d0                                           ; Convert into table index
    move.w  SSTrackDrawFlipRLE_Read6LUT(pc,d0.w),d0
    jmp SSTrackDrawFlipRLE_Read6LUT(pc,d0.w)
; ===========================================================================
;off_5E50
SSTrackDrawFlipRLE_Read6LUT:    offsetTable
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got7    ; 0
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got6    ; 1
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got5    ; 2
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got4    ; 3
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got3    ; 4
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got2    ; 5
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got1    ; 6
        offsetTableEntry.w SSTrackDrawFlipRLE_Read6_Got0    ; 7
; ===========================================================================
;loc_5E60
SSTrackDrawFlipUnc_Read10_Got0:
    ; Reads 10 bits from uncompressed mappings, 0 bits in bit buffer
    move.w  #0,d0
    move.b  (a1)+,d0
    lsl.w   #2,d0
    move.b  (a1)+,d4
    rol.b   #2,d4
    move.b  d4,d1
    andi.b  #3,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #6,d5                                           ; Bit buffer now has 6 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5E8A
SSTrackDrawFlipUnc_Read10_Got1:
    ; Reads 10 bits from uncompressed mappings, 1 bit in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$200,d0
    move.b  (a1)+,d1
    lsl.w   #1,d1
    or.w    d1,d0
    move.b  (a1)+,d4
    rol.b   #1,d4
    move.b  d4,d1
    andi.b  #1,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #7,d5                                           ; Bit buffer now has 7 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5EBA
SSTrackDrawFlipUnc_Read10_Got2:
    ; Reads 10 bits from uncompressed mappings, 2 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$300,d0
    move.b  (a1)+,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #0,d5                                           ; Bit buffer now empty
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5EDA
SSTrackDrawFlipUnc_Read10_Got3:
    ; Reads 10 bits from uncompressed mappings, 3 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$380,d0
    move.b  (a1)+,d4
    ror.b   #1,d4
    move.b  d4,d1
    andi.b  #$7F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #1,d5                                           ; Bit buffer now has 1 bit
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5F04
SSTrackDrawFlipUnc_Read10_Got4:
    ; Reads 10 bits from uncompressed mappings, 4 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3C0,d0
    move.b  (a1)+,d4
    ror.b   #2,d4
    move.b  d4,d1
    andi.b  #$3F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #2,d5                                           ; Bit buffer now has 2 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5F2E
SSTrackDrawFlipUnc_Read10_Got5:
    ; Reads 10 bits from uncompressed mappings, 5 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3E0,d0
    move.b  (a1)+,d4
    ror.b   #3,d4
    move.b  d4,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #3,d5                                           ; Bit buffer now has 3 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5F58
SSTrackDrawFlipUnc_Read10_Got6:
    ; Reads 10 bits from uncompressed mappings, 6 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3F0,d0
    move.b  (a1)+,d4
    ror.b   #4,d4
    move.b  d4,d1
    andi.b  #$F,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #4,d5                                           ; Bit buffer now has 4 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5F82
SSTrackDrawFlipUnc_Read10_Got7:
    ; Reads 10 bits from uncompressed mappings, 7 bits in bit buffer
    move.b  d4,d0
    lsl.w   #2,d0
    andi.w  #$3F8,d0
    move.b  (a1)+,d4
    rol.b   #3,d4
    move.b  d4,d1
    andi.b  #7,d1
    or.b    d1,d0
    addi.w  #(SSPNT_UncLUT_Part2-SSPNT_UncLUT)/2,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #5,d5                                           ; Bit buffer now has 5 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5FAC
SSTrackDrawFlipUnc_Read6_Got0:
    ; Reads 6 bits from uncompressed mappings, 0 bits in bit buffer
    move.b  (a1)+,d4
    ror.b   #2,d4
    move.b  d4,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #2,d5                                           ; Bit buffer now has 2 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5FC8
SSTrackDrawFlipUnc_Read6_Got1:
    ; Reads 6 bits from uncompressed mappings, 1 bit in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$20,d0
    move.b  (a1)+,d4
    ror.b   #3,d4
    move.b  d4,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #3,d5                                           ; Bit buffer now has 3 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_5FEE
SSTrackDrawFlipUnc_Read6_Got2:
    ; Reads 6 bits from uncompressed mappings, 2 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$30,d0
    move.b  (a1)+,d4
    ror.b   #4,d4
    move.b  d4,d1
    andi.b  #$F,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #4,d5                                           ; Bit buffer now has 4 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6014
SSTrackDrawFlipUnc_Read6_Got3:
    ; Reads 6 bits from uncompressed mappings, 3 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$38,d0
    move.b  (a1)+,d4
    rol.b   #3,d4
    move.b  d4,d1
    andi.b  #7,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #5,d5                                           ; Bit buffer now has 5 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_603A
SSTrackDrawFlipUnc_Read6_Got4:
    ; Reads 6 bits from uncompressed mappings, 4 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$3C,d0
    move.b  (a1)+,d4
    rol.b   #2,d4
    move.b  d4,d1
    andi.b  #3,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #6,d5                                           ; Bit buffer now has 6 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6060
SSTrackDrawFlipUnc_Read6_Got5:
    ; Reads 6 bits from uncompressed mappings, 5 bits in bit buffer
    move.b  d4,d0
    lsr.b   #2,d0
    andi.w  #$3E,d0
    move.b  (a1)+,d4
    rol.b   #1,d4
    move.b  d4,d1
    andi.b  #1,d1
    or.b    d1,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #7,d5                                           ; Bit buffer now has 7 bits
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6086
SSTrackDrawFlipUnc_Read6_Got6:
    ; Reads 6 bits from uncompressed mappings, 6 bits in bit buffer
    lsr.b   #2,d4
    andi.w  #$3F,d4
    add.w   d4,d4
    move.w  (a3,d4.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #0,d5                                           ; Bit buffer now empty
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_609E
SSTrackDrawFlipUnc_Read6_Got7:
    ; Reads 6 bits from uncompressed mappings, 7 bits in bit buffer
    ror.b   #2,d4
    move.b  d4,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    move.w  (a3,d0.w),d0
    eori.w  #flip_x|palette_line_3,d0
    move.w  d0,-(a6)
    moveq   #1,d5                                           ; Bit buffer now has 1 bit
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_60B8
SSTrackDrawFlipRLE_Read7_Got0:
    ; Reads 7 bits from RLE-compressed mappings, 0 bits in bit buffer
    move.b  (a2)+,d2
    ror.b   #1,d2
    move.b  d2,d0
    andi.w  #$7F,d0
    moveq   #1,d3                                           ; Bit buffer now has 1 bit
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_60EA
SSTrackDrawFlipRLE_Read7_Got1:
    ; Reads 7 bits from RLE-compressed mappings, 1 bit in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$40,d1
    move.b  (a2)+,d2
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    or.b    d1,d0
    moveq   #2,d3                                           ; Bit buffer now has 2 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6126
SSTrackDrawFlipRLE_Read7_Got2:
    ; Reads 7 bits from RLE-compressed mappings, 2 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$60,d1
    move.b  (a2)+,d2
    ror.b   #3,d2
    move.b  d2,d0
    andi.w  #$1F,d0
    or.b    d1,d0
    moveq   #3,d3                                           ; Bit buffer now has 3 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6162
SSTrackDrawFlipRLE_Read7_Got3:
    ; Reads 7 bits from RLE-compressed mappings, 3 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$70,d1
    move.b  (a2)+,d2
    ror.b   #4,d2
    move.b  d2,d0
    andi.w  #$F,d0
    or.b    d1,d0
    moveq   #4,d3                                           ; Bit buffer now has 4 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_619E
SSTrackDrawFlipRLE_Read7_Got4:
    ; Reads 7 bits from RLE-compressed mappings, 4 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$78,d1
    move.b  (a2)+,d2
    rol.b   #3,d2
    move.b  d2,d0
    andi.w  #7,d0
    or.b    d1,d0
    moveq   #5,d3                                           ; Bit buffer now has 5 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_61DA
SSTrackDrawFlipRLE_Read7_Got5:
    ; Reads 7 bits from RLE-compressed mappings, 5 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$7C,d1
    move.b  (a2)+,d2
    rol.b   #2,d2
    move.b  d2,d0
    andi.w  #3,d0
    or.b    d1,d0
    moveq   #6,d3                                           ; Bit buffer now has 6 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6216
SSTrackDrawFlipRLE_Read7_Got6:
    ; Reads 7 bits from RLE-compressed mappings, 6 bits in bit buffer
    move.b  d2,d1
    lsr.b   #1,d1
    andi.b  #$7E,d1
    move.b  (a2)+,d2
    rol.b   #1,d2
    move.b  d2,d0
    andi.w  #1,d0
    or.b    d1,d0
    moveq   #7,d3                                           ; Bit buffer now has 7 bits
    cmpi.b  #$7F,d0
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6252
SSTrackDrawFlipRLE_Read7_Got7:
    ; Reads 7 bits from RLE-compressed mappings, 7 bits in bit buffer
    lsr.b   #1,d2
    andi.w  #$7F,d2
    moveq   #0,d3                                           ; Bit buffer now empty
    cmpi.b  #$7F,d2
    beq.w   SSTrackDrawLineFlipLoop
    addi.w  #(SSPNT_RLELUT_Part2-SSPNT_RLELUT)/4,d2
    add.w   d2,d2
    add.w   d2,d2
    move.w  (a4,d2.w),d1
    move.w  2(a4,d2.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6280
SSTrackDrawFlipRLE_Read6_Got0:
    ; Reads 6 bits from RLE-compressed mappings, 0 bits in bit buffer
    move.b  (a2)+,d2
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #2,d3                                           ; Bit buffer now has 2 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_62A6
SSTrackDrawFlipRLE_Read6_Got1:
    ; Reads 6 bits from RLE-compressed mappings, 1 bit in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$20,d0
    move.b  (a2)+,d2
    ror.b   #3,d2
    move.b  d2,d1
    andi.b  #$1F,d1
    or.b    d1,d0
    moveq   #3,d3                                           ; Bit buffer now has 3 bits
    add.w   d0,d0
    add.w   d0,d0
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_62D6
SSTrackDrawFlipRLE_Read6_Got2:
    ; Reads 6 bits from RLE-compressed mappings, 2 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$30,d0
    move.b  (a2)+,d2
    ror.b   #4,d2
    move.b  d2,d1
    andi.b  #$F,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #4,d3                                           ; Bit buffer now has 4 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6306
SSTrackDrawFlipRLE_Read6_Got3:
    ; Reads 6 bits from RLE-compressed mappings, 3 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$38,d0
    move.b  (a2)+,d2
    rol.b   #3,d2
    move.b  d2,d1
    andi.b  #7,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #5,d3                                           ; Bit buffer now has 5 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6336
SSTrackDrawFlipRLE_Read6_Got4:
    ; Reads 6 bits from RLE-compressed mappings, 4 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$3C,d0
    move.b  (a2)+,d2
    rol.b   #2,d2
    move.b  d2,d1
    andi.b  #3,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #6,d3                                           ; Bit buffer now has 6 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6366
SSTrackDrawFlipRLE_Read6_Got5:
    ; Reads 6 bits from RLE-compressed mappings, 5 bits in bit buffer
    move.b  d2,d0
    lsr.b   #2,d0
    andi.w  #$3E,d0
    move.b  (a2)+,d2
    rol.b   #1,d2
    move.b  d2,d1
    andi.b  #1,d1
    or.b    d1,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #7,d3                                           ; Bit buffer now has 7 bits
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_6396
SSTrackDrawFlipRLE_Read6_Got6:
    ; Reads 6 bits from RLE-compressed mappings, 6 bits in bit buffer
    lsr.b   #2,d2
    andi.w  #$3F,d2
    add.w   d2,d2
    add.w   d2,d2
    moveq   #0,d3                                           ; Bit buffer now empty
    move.w  (a4,d2.w),d1
    move.w  2(a4,d2.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
; ===========================================================================
;loc_63B8
SSTrackDrawFlipRLE_Read6_Got7:
    ; Reads 6 bits from RLE-compressed mappings, 7 bits in bit buffer
    ror.b   #2,d2
    move.b  d2,d0
    andi.w  #$3F,d0
    add.w   d0,d0
    add.w   d0,d0
    moveq   #1,d3                                           ; Bit buffer now has 1 bit
    move.w  (a4,d0.w),d1
    move.w  2(a4,d0.w),d0
    ori.w   #palette_line_3|high_priority,d1
 
-   move.w  d1,-(a6)
    dbf d0,-
 
    bra.w   SSTrackDrawFlipLoop_Inner
 
; ===========================================================================
; frames of animation of the special stage track
; this chooses how objects curve along the track as well as which track frame to draw
; off_63DC:
Ani_SpecialStageTrack:  offsetTable
    offsetTableEntry.w SSTrackAni_TurnThenRise  ; 0
    offsetTableEntry.w SSTrackAni_TurnThenDrop  ; 1
    offsetTableEntry.w SSTrackAni_TurnThenStraight  ; 2
    offsetTableEntry.w SSTrackAni_Straight      ; 3
    offsetTableEntry.w SSTrackAni_StraightThenTurn  ; 4
; byte_63E6:
SSTrackAni_TurnThenRise:
    dc.b $26,$27,$28,$29,$2A,$2B,$26 ; turning
    dc.b   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, $A, $B, $C, $D, $E, $F,$10 ; rise
SSTrackAni_TurnThenRise_End:
; byte_63FE:
SSTrackAni_TurnThenDrop:
    dc.b $26,$27,$28,$29,$2A,$2B,$26 ; turning
    dc.b $15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,$20,$21,$22,$23,$24,$25 ; drop
SSTrackAni_TurnThenDrop_End:
; byte_6416:
SSTrackAni_TurnThenStraight:
    dc.b $26,$27,$28,$29,$2A,$2B,$26 ; turning
    dc.b $2C,$2D,$2E,$2F,$30 ; exit turn
SSTrackAni_TurnThenStraight_End:
; byte_6422:
SSTrackAni_Straight:
    dc.b $11,$12,$13,$14,$11,$12,$13,$14 ; straight
    dc.b $11,$12,$13,$14,$11,$12,$13,$14 ; straight
SSTrackAni_Straight_End:
; byte_6432:
SSTrackAni_StraightThenTurn:
    dc.b $11,$12,$13,$14 ; straight
    dc.b $31,$32,$33,$34,$35,$36,$37 ; enter turn
SSTrackAni_StraightThenTurn_End:
 
    even
 
; ===========================================================================
; pointers to the mappings for each frame of the special stage track
; indexed into by the numbers used in the above animations
;
; Format of each mappings file:
;   File is divided in 3 segments, with the same structure:
;   Segment structure:
;       4-byte unsigned length of segment (not counting the 4 bytes used for length);
;       the first 2 bytes of each length is ignored, and only the last 2 bytes are
;       actually used.
;       Rest of the segment is mappings data, as follows:
;   1st segment:
;       Mappings data is a bitstream indicating whether to draw a single tile at
;       a time using the uncompressed mappings (see 2nd segment) or a sequence of
;       tiles using the RLE mappings (see 3rd segment).
;   2nd segment:
;       Mappings data is a bitstream: the first bit in each cycle determines how
;       many bits from the stream are to be used as an index to the uncompressed
;       pattern name list SSPNT_UncLUT: if the first bit is set, 10 bits form an
;       index into SSPNT_UncLUT_Part2, otherwise 6 bits are used as an index into
;       SSPNT_UncLUT.
;       These tiles are drawn in palette line 3.
;   3nd segment:
;       Mappings data is a bitstream: the first bit in each cycle determines how
;       many bits from the stream are to be used as an index to the RLE-compressed
;       pattern name list SSPNT_RLELUT: if the first bit is set, 7 bits form an
;       index into SSPNT_RLELUT_Part2, otherwise 6 bits are used as an index into
;       SSPNT_RLELUT.
;       These tiles are drawn in palette line 3, with the high priority bit set.
; off_643E:
Map_SpecialStageTrack:
    dc.l MapSpec_Rise1      ;   0
    dc.l MapSpec_Rise2      ;   1
    dc.l MapSpec_Rise3      ;   2
    dc.l MapSpec_Rise4      ;   3
    dc.l MapSpec_Rise5      ;   4
    dc.l MapSpec_Rise6      ;   5
    dc.l MapSpec_Rise7      ;   6
    dc.l MapSpec_Rise8      ;   7
    dc.l MapSpec_Rise9      ;   8
    dc.l MapSpec_Rise10     ;   9
    dc.l MapSpec_Rise11     ;  $A
    dc.l MapSpec_Rise12     ;  $B
    dc.l MapSpec_Rise13     ;  $C
    dc.l MapSpec_Rise14     ;  $D   ; This may flip the special stage's horizontal orientation
    dc.l MapSpec_Rise15     ;  $E
    dc.l MapSpec_Rise16     ;  $F
    dc.l MapSpec_Rise17     ; $10
    dc.l MapSpec_Straight1  ; $11
    dc.l MapSpec_Straight2  ; $12   ; This may flip the special stage's horizontal orientation
    dc.l MapSpec_Straight3  ; $13
    dc.l MapSpec_Straight4  ; $14
    dc.l MapSpec_Drop1      ; $15
    dc.l MapSpec_Drop2      ; $16
    dc.l MapSpec_Drop3      ; $17
    dc.l MapSpec_Drop4      ; $18
    dc.l MapSpec_Drop5      ; $19
    dc.l MapSpec_Drop6      ; $1A   ; This may flip the special stage's horizontal orientation
    dc.l MapSpec_Drop7      ; $1B
    dc.l MapSpec_Drop8      ; $1C
    dc.l MapSpec_Drop9      ; $1D
    dc.l MapSpec_Drop10     ; $1E
    dc.l MapSpec_Drop11     ; $1F
    dc.l MapSpec_Drop12     ; $20
    dc.l MapSpec_Drop13     ; $21
    dc.l MapSpec_Drop14     ; $22
    dc.l MapSpec_Drop15     ; $23
    dc.l MapSpec_Drop16     ; $24
    dc.l MapSpec_Drop17     ; $25
    dc.l MapSpec_Turning1   ; $26
    dc.l MapSpec_Turning2   ; $27
    dc.l MapSpec_Turning3   ; $28
    dc.l MapSpec_Turning4   ; $29
    dc.l MapSpec_Turning5   ; $2A
    dc.l MapSpec_Turning6   ; $2B
    dc.l MapSpec_Unturn1    ; $2C
    dc.l MapSpec_Unturn2    ; $2D
    dc.l MapSpec_Unturn3    ; $2E
    dc.l MapSpec_Unturn4    ; $2F
    dc.l MapSpec_Unturn5    ; $30
    dc.l MapSpec_Turn1      ; $31
    dc.l MapSpec_Turn2      ; $32
    dc.l MapSpec_Turn3      ; $33
    dc.l MapSpec_Turn4      ; $34
    dc.l MapSpec_Turn5      ; $35
    dc.l MapSpec_Turn6      ; $36
    dc.l MapSpec_Turn7      ; $37
 
; These are pattern names. They get sent to either the pattern name table
; buffer or one region of one of the plane A name tables in the special stage.
; They are indexed by the second segment of the mappings in Map_SpecialStageTrack, above.
;word_651E
SSPNT_UncLUT:
    dc.w make_block_tile($0001,0,0,0,1), make_block_tile($0007,0,0,0,1), make_block_tile($002C,0,0,0,1), make_block_tile($000B,0,0,0,1) ; $00
    dc.w make_block_tile($0024,0,0,0,1), make_block_tile($0024,1,0,0,1), make_block_tile($0039,0,0,0,1), make_block_tile($002B,1,0,0,1) ; $04
    dc.w make_block_tile($005D,0,0,0,1), make_block_tile($005D,1,0,0,1), make_block_tile($002B,0,0,0,1), make_block_tile($004A,0,0,0,1) ; $08
    dc.w make_block_tile($0049,0,0,0,1), make_block_tile($0037,0,0,0,1), make_block_tile($0049,1,0,0,1), make_block_tile($0045,0,0,0,1) ; $0C
    dc.w make_block_tile($0045,1,0,0,1), make_block_tile($003A,1,0,0,1), make_block_tile($0048,0,0,0,1), make_block_tile($0050,1,0,0,1) ; $10
    dc.w make_block_tile($0036,0,0,0,1), make_block_tile($0037,1,0,0,1), make_block_tile($003A,0,0,0,1), make_block_tile($0050,0,0,0,1) ; $14
    dc.w make_block_tile($0042,1,0,0,1), make_block_tile($0042,0,0,0,1), make_block_tile($0015,1,0,0,1), make_block_tile($001D,0,0,0,1) ; $18
    dc.w make_block_tile($004B,0,0,0,1), make_block_tile($0017,1,0,0,1), make_block_tile($0048,1,0,0,1), make_block_tile($0036,1,0,0,1) ; $1C
    dc.w make_block_tile($0038,0,0,0,1), make_block_tile($004B,1,0,0,1), make_block_tile($0015,0,0,0,1), make_block_tile($0021,0,0,0,1) ; $20
    dc.w make_block_tile($0017,0,0,0,1), make_block_tile($0033,0,0,0,1), make_block_tile($001A,0,0,0,1), make_block_tile($002A,0,0,0,1) ; $24
    dc.w make_block_tile($005E,0,0,0,1), make_block_tile($0028,0,0,0,1), make_block_tile($0030,0,0,0,1), make_block_tile($0021,1,0,0,1) ; $28
    dc.w make_block_tile($0038,1,0,0,1), make_block_tile($001A,1,0,0,1), make_block_tile($0025,0,0,0,1), make_block_tile($005E,1,0,0,1) ; $2C
    dc.w make_block_tile($0025,1,0,0,1), make_block_tile($0033,1,0,0,1), make_block_tile($0003,0,0,0,1), make_block_tile($0014,1,0,0,1) ; $30
    dc.w make_block_tile($0014,0,0,0,1), make_block_tile($0004,0,0,0,1), make_block_tile($004E,0,0,0,1), make_block_tile($0003,1,0,0,1) ; $34
    dc.w make_block_tile($000C,0,0,0,1), make_block_tile($002A,1,0,0,1), make_block_tile($0002,0,0,0,1), make_block_tile($0051,0,0,0,1) ; $38
    dc.w make_block_tile($0040,0,0,0,1), make_block_tile($003D,0,0,0,1), make_block_tile($0019,0,0,0,1), make_block_tile($0052,0,0,0,1) ; $3C
;word_659E
SSPNT_UncLUT_Part2:
    dc.w make_block_tile($0009,0,0,0,1), make_block_tile($005A,0,0,0,1), make_block_tile($0030,1,0,0,1), make_block_tile($004E,1,0,0,1) ; $40
    dc.w make_block_tile($0052,1,0,0,1), make_block_tile($0051,1,0,0,1), make_block_tile($0009,1,0,0,1), make_block_tile($0040,1,0,0,1) ; $44
    dc.w make_block_tile($002F,0,0,0,1), make_block_tile($005A,1,0,0,1), make_block_tile($0018,1,0,0,1), make_block_tile($0034,0,0,0,1) ; $48
    dc.w make_block_tile($0019,1,0,0,1), make_block_tile($002F,1,0,0,1), make_block_tile($003D,1,0,0,1), make_block_tile($003E,0,0,0,1) ; $4C
    dc.w make_block_tile($0018,0,0,0,1), make_block_tile($000C,1,0,0,1), make_block_tile($0012,0,0,0,1), make_block_tile($0004,1,0,0,1) ; $50
    dc.w make_block_tile($0026,0,0,0,1), make_block_tile($0034,1,0,0,1), make_block_tile($0005,1,0,0,1), make_block_tile($003B,0,0,0,1) ; $54
    dc.w make_block_tile($003E,1,0,0,1), make_block_tile($003B,1,0,0,1), make_block_tile($0000,0,0,0,1), make_block_tile($0002,1,0,0,1) ; $58
    dc.w make_block_tile($0005,0,0,0,1), make_block_tile($000D,0,0,0,1), make_block_tile($0055,0,0,0,1), make_block_tile($00AF,0,0,0,1) ; $5C
    dc.w make_block_tile($001C,0,0,0,1), make_block_tile($001B,0,0,0,1), make_block_tile($000D,1,0,0,1), make_block_tile($0016,0,0,0,1) ; $60
    dc.w make_block_tile($0012,1,0,0,1), make_block_tile($001F,0,0,0,1), make_block_tile($0032,1,0,0,1), make_block_tile($0013,0,0,0,1) ; $64
    dc.w make_block_tile($0092,0,0,0,1), make_block_tile($0026,1,0,0,1), make_block_tile($0010,0,0,0,1), make_block_tile($004D,0,0,0,1) ; $68
    dc.w make_block_tile($0047,0,0,0,1), make_block_tile($0092,1,0,0,1), make_block_tile($0000,1,0,0,1), make_block_tile($0062,0,0,0,1) ; $6C
    dc.w make_block_tile($0066,0,0,0,1), make_block_tile($0090,0,0,0,1), make_block_tile($0008,0,0,0,1), make_block_tile($007C,1,0,0,1) ; $70
    dc.w make_block_tile($0067,1,0,0,1), make_block_tile($00F7,1,0,0,1), make_block_tile($000E,0,0,0,1), make_block_tile($0060,0,0,0,1) ; $74
    dc.w make_block_tile($0032,0,0,0,1), make_block_tile($0094,0,0,0,1), make_block_tile($001C,1,0,0,1), make_block_tile($0105,1,0,0,1) ; $78
    dc.w make_block_tile($00B0,1,0,0,1), make_block_tile($0059,0,0,0,1), make_block_tile($000F,0,0,0,1), make_block_tile($0067,0,0,0,1) ; $7C
    dc.w make_block_tile($0068,0,0,0,1), make_block_tile($0094,1,0,0,1), make_block_tile($007C,0,0,0,1), make_block_tile($00B0,0,0,0,1) ; $80
    dc.w make_block_tile($00B1,0,0,0,1), make_block_tile($0006,0,0,0,1), make_block_tile($0041,1,0,0,1), make_block_tile($0087,0,0,0,1) ; $84
    dc.w make_block_tile($0093,0,0,0,1), make_block_tile($00CC,0,0,0,1), make_block_tile($001F,1,0,0,1), make_block_tile($0068,1,0,0,1) ; $88
    dc.w make_block_tile($0041,0,0,0,1), make_block_tile($008F,0,0,0,1), make_block_tile($0090,1,0,0,1), make_block_tile($00C2,0,0,0,1) ; $8C
    dc.w make_block_tile($0013,1,0,0,1), make_block_tile($00C2,1,0,0,1), make_block_tile($005C,0,0,0,1), make_block_tile($0064,0,0,0,1) ; $90
    dc.w make_block_tile($00D8,0,0,0,1), make_block_tile($001B,1,0,0,1), make_block_tile($00CC,1,0,0,1), make_block_tile($0011,1,0,0,1) ; $94
    dc.w make_block_tile($0055,1,0,0,1), make_block_tile($00E2,1,0,0,1), make_block_tile($00F3,1,0,0,1), make_block_tile($0044,0,0,0,1) ; $98
    dc.w make_block_tile($00D8,1,0,0,1), make_block_tile($0085,0,0,0,1), make_block_tile($00A1,0,0,0,1), make_block_tile($00C1,0,0,0,1) ; $9C
    dc.w make_block_tile($0119,0,0,0,1), make_block_tile($0089,1,0,0,1), make_block_tile($000A,1,0,0,1), make_block_tile($0022,1,0,0,1) ; $A0
    dc.w make_block_tile($003F,0,0,0,1), make_block_tile($005B,0,0,0,1), make_block_tile($007F,0,0,0,1), make_block_tile($0086,1,0,0,1) ; $A4
    dc.w make_block_tile($0008,1,0,0,1), make_block_tile($0080,0,0,0,1), make_block_tile($0066,1,0,0,1), make_block_tile($00E0,1,0,0,1) ; $A8
    dc.w make_block_tile($00C1,1,0,0,1), make_block_tile($0020,0,0,0,1), make_block_tile($0022,0,0,0,1), make_block_tile($0054,0,0,0,1) ; $AC
    dc.w make_block_tile($00D2,0,0,0,1), make_block_tile($0059,1,0,0,1), make_block_tile($00B1,1,0,0,1), make_block_tile($0060,1,0,0,1) ; $B0
    dc.w make_block_tile($0119,1,0,0,1), make_block_tile($00A4,1,0,0,1), make_block_tile($008F,1,0,0,1), make_block_tile($000A,0,0,0,1) ; $B4
    dc.w make_block_tile($0061,0,0,0,1), make_block_tile($0075,0,0,0,1), make_block_tile($0095,0,0,0,1), make_block_tile($00B6,0,0,0,1) ; $B8
    dc.w make_block_tile($00E0,0,0,0,1), make_block_tile($0010,1,0,0,1), make_block_tile($0098,1,0,0,1), make_block_tile($005B,1,0,0,1) ; $BC
    dc.w make_block_tile($00D2,1,0,0,1), make_block_tile($0016,1,0,0,1), make_block_tile($0053,0,0,0,1), make_block_tile($0091,0,0,0,1) ; $C0
    dc.w make_block_tile($0096,0,0,0,1), make_block_tile($00A4,0,0,0,1), make_block_tile($00DD,0,0,0,1), make_block_tile($00E6,0,0,0,1) ; $C4
    dc.w make_block_tile($007A,1,0,0,1), make_block_tile($004D,1,0,0,1), make_block_tile($00E6,1,0,0,1), make_block_tile($0011,0,0,0,1) ; $C8
    dc.w make_block_tile($0057,0,0,0,1), make_block_tile($007A,0,0,0,1), make_block_tile($0086,0,0,0,1), make_block_tile($009E,0,0,0,1) ; $CC
    dc.w make_block_tile($00DA,0,0,0,1), make_block_tile($0058,0,0,0,1), make_block_tile($00DC,0,0,0,1), make_block_tile($00E3,0,0,0,1) ; $D0
    dc.w make_block_tile($0063,1,0,0,1), make_block_tile($003C,0,0,0,1), make_block_tile($0056,0,0,0,1), make_block_tile($0069,0,0,0,1) ; $D4
    dc.w make_block_tile($007E,0,0,0,1), make_block_tile($00AE,0,0,0,1), make_block_tile($00B5,0,0,0,1), make_block_tile($00B8,0,0,0,1) ; $D8
    dc.w make_block_tile($00CD,0,0,0,1), make_block_tile($00FB,0,0,0,1), make_block_tile($00FF,0,0,0,1), make_block_tile($005C,1,0,0,1) ; $DC
    dc.w make_block_tile($00CD,1,0,0,1), make_block_tile($0074,1,0,0,1), make_block_tile($00EA,1,0,0,1), make_block_tile($00FF,1,0,0,1) ; $E0
    dc.w make_block_tile($00B5,1,0,0,1), make_block_tile($0043,0,0,0,1), make_block_tile($006C,0,0,0,1), make_block_tile($0074,0,0,0,1) ; $E4
    dc.w make_block_tile($0077,0,0,0,1), make_block_tile($0089,0,0,0,1), make_block_tile($0097,0,0,0,1), make_block_tile($009F,0,0,0,1) ; $E8
    dc.w make_block_tile($00A0,0,0,0,1), make_block_tile($0113,0,0,0,1), make_block_tile($011B,0,0,0,1), make_block_tile($0078,1,0,0,1) ; $EC
    dc.w make_block_tile($000F,1,0,0,1), make_block_tile($00E1,1,0,0,1), make_block_tile($00FB,1,0,0,1), make_block_tile($0128,1,0,0,1) ; $F0
    dc.w make_block_tile($0063,0,0,0,1), make_block_tile($0084,0,0,0,1), make_block_tile($008D,0,0,0,1), make_block_tile($00CB,0,0,0,1) ; $F4
    dc.w make_block_tile($00D7,0,0,0,1), make_block_tile($00E9,0,0,0,1), make_block_tile($0128,0,0,0,1), make_block_tile($0138,0,0,0,1) ; $F8
    dc.w make_block_tile($00AE,1,0,0,1), make_block_tile($00EC,1,0,0,1), make_block_tile($0031,0,0,0,1), make_block_tile($004C,0,0,0,1) ; $FC
    dc.w make_block_tile($00E2,0,0,0,1), make_block_tile($00EA,0,0,0,1), make_block_tile($0064,1,0,0,1), make_block_tile($0029,0,0,0,1) ; $100
    dc.w make_block_tile($002D,0,0,0,1), make_block_tile($006D,0,0,0,1), make_block_tile($0078,0,0,0,1), make_block_tile($0088,0,0,0,1) ; $104
    dc.w make_block_tile($00B4,0,0,0,1), make_block_tile($00BE,0,0,0,1), make_block_tile($00CF,0,0,0,1), make_block_tile($00E1,0,0,0,1) ; $108
    dc.w make_block_tile($00E4,0,0,0,1), make_block_tile($0054,1,0,0,1), make_block_tile($00D6,1,0,0,1), make_block_tile($00D7,1,0,0,1) ; $10C
    dc.w make_block_tile($0061,1,0,0,1), make_block_tile($012B,1,0,0,1), make_block_tile($0047,1,0,0,1), make_block_tile($0035,0,0,0,1) ; $110
    dc.w make_block_tile($006A,0,0,0,1), make_block_tile($0072,0,0,0,1), make_block_tile($0073,0,0,0,1), make_block_tile($0098,0,0,0,1) ; $114
    dc.w make_block_tile($00D5,0,0,0,1), make_block_tile($00D6,0,0,0,1), make_block_tile($0116,0,0,0,1), make_block_tile($011E,0,0,0,1) ; $118
    dc.w make_block_tile($0126,0,0,0,1), make_block_tile($0127,0,0,0,1), make_block_tile($012F,0,0,0,1), make_block_tile($015D,0,0,0,1) ; $11C
    dc.w make_block_tile($0069,1,0,0,1), make_block_tile($0088,1,0,0,1), make_block_tile($0075,1,0,0,1), make_block_tile($0097,1,0,0,1) ; $120
    dc.w make_block_tile($00B4,1,0,0,1), make_block_tile($00D1,1,0,0,1), make_block_tile($00D4,1,0,0,1), make_block_tile($00D5,1,0,0,1) ; $124
    dc.w make_block_tile($00CB,1,0,0,1), make_block_tile($00E4,1,0,0,1), make_block_tile($0091,1,0,0,1), make_block_tile($0062,1,0,0,1) ; $128
    dc.w make_block_tile($0006,1,0,0,1), make_block_tile($00B8,1,0,0,1), make_block_tile($0065,0,0,0,1), make_block_tile($006E,0,0,0,1) ; $12C
    dc.w make_block_tile($0071,0,0,0,1), make_block_tile($007D,0,0,0,1), make_block_tile($00D1,0,0,0,1), make_block_tile($00E7,0,0,0,1) ; $130
    dc.w make_block_tile($00F9,0,0,0,1), make_block_tile($0108,0,0,0,1), make_block_tile($012E,0,0,0,1), make_block_tile($014B,0,0,0,1) ; $134
    dc.w make_block_tile($0081,1,0,0,1), make_block_tile($0085,1,0,0,1), make_block_tile($0077,1,0,0,1), make_block_tile($007E,1,0,0,1) ; $138
    dc.w make_block_tile($0095,1,0,0,1), make_block_tile($00DF,1,0,0,1), make_block_tile($0087,1,0,0,1), make_block_tile($006C,1,0,0,1) ; $13C
    dc.w make_block_tile($00F5,1,0,0,1), make_block_tile($0108,1,0,0,1), make_block_tile($0079,1,0,0,1), make_block_tile($006D,1,0,0,1) ; $140
    dc.w make_block_tile($012A,1,0,0,1), make_block_tile($00AA,1,0,0,1), make_block_tile($001E,0,0,0,1), make_block_tile($0027,0,0,0,1) ; $144
    dc.w make_block_tile($0046,0,0,0,1), make_block_tile($005F,0,0,0,1), make_block_tile($0070,0,0,0,1), make_block_tile($0079,0,0,0,1) ; $148
    dc.w make_block_tile($009A,0,0,0,1), make_block_tile($00AA,0,0,0,1), make_block_tile($00C3,0,0,0,1), make_block_tile($00D3,0,0,0,1) ; $14C
    dc.w make_block_tile($00D4,0,0,0,1), make_block_tile($00DE,0,0,0,1), make_block_tile($00DF,0,0,0,1), make_block_tile($00F8,0,0,0,1) ; $150
    dc.w make_block_tile($0100,0,0,0,1), make_block_tile($0101,0,0,0,1), make_block_tile($012B,0,0,0,1), make_block_tile($0133,0,0,0,1) ; $154
    dc.w make_block_tile($0136,0,0,0,1), make_block_tile($0143,0,0,0,1), make_block_tile($0151,0,0,0,1), make_block_tile($002E,1,0,0,1) ; $158
    dc.w make_block_tile($009E,1,0,0,1), make_block_tile($0099,1,0,0,1), make_block_tile($00D3,1,0,0,1), make_block_tile($00DD,1,0,0,1) ; $15C
    dc.w make_block_tile($00DE,1,0,0,1), make_block_tile($00E9,1,0,0,1), make_block_tile($00EF,1,0,0,1), make_block_tile($00F0,1,0,0,1) ; $160
    dc.w make_block_tile($00F8,1,0,0,1), make_block_tile($0127,1,0,0,1), make_block_tile($00BE,1,0,0,1), make_block_tile($0096,1,0,0,1) ; $164
    dc.w make_block_tile($004F,0,0,0,1), make_block_tile($006F,0,0,0,1), make_block_tile($0081,0,0,0,1), make_block_tile($008B,0,0,0,1) ; $168
    dc.w make_block_tile($008E,0,0,0,1), make_block_tile($009C,0,0,0,1), make_block_tile($00A3,0,0,0,1), make_block_tile($00B3,0,0,0,1) ; $16C
    dc.w make_block_tile($00C0,0,0,0,1), make_block_tile($00CE,0,0,0,1), make_block_tile($00F0,0,0,0,1), make_block_tile($00F1,0,0,0,1) ; $170
    dc.w make_block_tile($00F5,0,0,0,1), make_block_tile($00F7,0,0,0,1), make_block_tile($0102,0,0,0,1), make_block_tile($0104,0,0,0,1) ; $174
    dc.w make_block_tile($0105,0,0,0,1), make_block_tile($0109,0,0,0,1), make_block_tile($010C,0,0,0,1), make_block_tile($0114,0,0,0,1) ; $178
    dc.w make_block_tile($0118,0,0,0,1), make_block_tile($0120,0,0,0,1), make_block_tile($0124,0,0,0,1), make_block_tile($0125,0,0,0,1) ; $17C
    dc.w make_block_tile($012A,0,0,0,1), make_block_tile($0130,0,0,0,1), make_block_tile($0132,0,0,0,1), make_block_tile($0137,0,0,0,1) ; $180
    dc.w make_block_tile($0159,0,0,0,1), make_block_tile($0165,0,0,0,1), make_block_tile($003F,1,0,0,1), make_block_tile($006B,1,0,0,1) ; $184
    dc.w make_block_tile($0080,1,0,0,1), make_block_tile($0053,1,0,0,1), make_block_tile($00C6,1,0,0,1), make_block_tile($00CF,1,0,0,1) ; $188
    dc.w make_block_tile($00D9,1,0,0,1), make_block_tile($00DC,1,0,0,1), make_block_tile($0056,1,0,0,1), make_block_tile($00B6,1,0,0,1) ; $18C
    dc.w make_block_tile($00F9,1,0,0,1), make_block_tile($0102,1,0,0,1), make_block_tile($0104,1,0,0,1), make_block_tile($0115,1,0,0,1) ; $190
    dc.w make_block_tile($006A,1,0,0,1), make_block_tile($0113,1,0,0,1), make_block_tile($0072,1,0,0,1), make_block_tile($0035,1,0,0,1) ; $194
    dc.w make_block_tile($0138,1,0,0,1), make_block_tile($015D,1,0,0,1), make_block_tile($0143,1,0,0,1), make_block_tile($0023,0,0,0,1) ; $198
    dc.w make_block_tile($0076,0,0,0,1), make_block_tile($007B,0,0,0,1), make_block_tile($008A,0,0,0,1), make_block_tile($009D,0,0,0,1) ; $19C
    dc.w make_block_tile($00A6,0,0,0,1), make_block_tile($00A8,0,0,0,1), make_block_tile($00AC,0,0,0,1), make_block_tile($00B2,0,0,0,1) ; $1A0
    dc.w make_block_tile($00B7,0,0,0,1), make_block_tile($00BB,0,0,0,1), make_block_tile($00BC,0,0,0,1), make_block_tile($00BD,0,0,0,1) ; $1A4
    dc.w make_block_tile($00C6,0,0,0,1), make_block_tile($00E5,0,0,0,1), make_block_tile($00E8,0,0,0,1), make_block_tile($00EE,0,0,0,1) ; $1A8
    dc.w make_block_tile($00F4,0,0,0,1), make_block_tile($010A,0,0,0,1), make_block_tile($010D,0,0,0,1), make_block_tile($0111,0,0,0,1) ; $1AC
    dc.w make_block_tile($0115,0,0,0,1), make_block_tile($011A,0,0,0,1), make_block_tile($011F,0,0,0,1), make_block_tile($0122,0,0,0,1) ; $1B0
    dc.w make_block_tile($0123,0,0,0,1), make_block_tile($0139,0,0,0,1), make_block_tile($013A,0,0,0,1), make_block_tile($013C,0,0,0,1) ; $1B4
    dc.w make_block_tile($0142,0,0,0,1), make_block_tile($0144,0,0,0,1), make_block_tile($0147,0,0,0,1), make_block_tile($0148,0,0,0,1) ; $1B8
    dc.w make_block_tile($015E,0,0,0,1), make_block_tile($015F,0,0,0,1), make_block_tile($0163,0,0,0,1), make_block_tile($0168,0,0,0,1) ; $1BC
    dc.w make_block_tile($016A,0,0,0,1), make_block_tile($016C,0,0,0,1), make_block_tile($0170,0,0,0,1), make_block_tile($00E5,1,0,0,1) ; $1C0
    dc.w make_block_tile($00CE,1,0,0,1), make_block_tile($00EE,1,0,0,1), make_block_tile($00F1,1,0,0,1), make_block_tile($0084,1,0,0,1) ; $1C4
    dc.w make_block_tile($00FD,1,0,0,1), make_block_tile($0100,1,0,0,1), make_block_tile($00B9,1,0,0,1), make_block_tile($0117,1,0,0,1) ; $1C8
    dc.w make_block_tile($0071,1,0,0,1), make_block_tile($0109,1,0,0,1), make_block_tile($010D,1,0,0,1), make_block_tile($0065,1,0,0,1) ; $1CC
    dc.w make_block_tile($0125,1,0,0,1), make_block_tile($0122,1,0,0,1), make_block_tile($0031,1,0,0,1), make_block_tile($003C,1,0,0,1) ; $1D0
    dc.w make_block_tile($010F,1,0,0,1), make_block_tile($00C5,1,0,0,1), make_block_tile($0133,1,0,0,1), make_block_tile($0137,1,0,0,1) ; $1D4
    dc.w make_block_tile($011F,1,0,0,1), make_block_tile($002E,0,0,0,1), make_block_tile($006B,0,0,0,1), make_block_tile($0082,0,0,0,1) ; $1D8
    dc.w make_block_tile($0083,0,0,0,1), make_block_tile($008C,0,0,0,1), make_block_tile($0099,0,0,0,1), make_block_tile($009B,0,0,0,1) ; $1DC
    dc.w make_block_tile($00A2,0,0,0,1), make_block_tile($00A5,0,0,0,1), make_block_tile($00A7,0,0,0,1), make_block_tile($00A9,0,0,0,1) ; $1E0
    dc.w make_block_tile($00AB,0,0,0,1), make_block_tile($00AD,0,0,0,1), make_block_tile($00B9,0,0,0,1), make_block_tile($00BA,0,0,0,1) ; $1E4
    dc.w make_block_tile($00BF,0,0,0,1), make_block_tile($00C4,0,0,0,1), make_block_tile($00C5,0,0,0,1), make_block_tile($00C7,0,0,0,1) ; $1E8
    dc.w make_block_tile($00C8,0,0,0,1), make_block_tile($00C9,0,0,0,1), make_block_tile($00CA,0,0,0,1), make_block_tile($00D0,0,0,0,1) ; $1EC
    dc.w make_block_tile($00D9,0,0,0,1), make_block_tile($00DB,0,0,0,1), make_block_tile($00EB,0,0,0,1), make_block_tile($00EC,0,0,0,1) ; $1F0
    dc.w make_block_tile($00ED,0,0,0,1), make_block_tile($00EF,0,0,0,1), make_block_tile($00F2,0,0,0,1), make_block_tile($00F3,0,0,0,1) ; $1F4
    dc.w make_block_tile($00F6,0,0,0,1), make_block_tile($00FA,0,0,0,1), make_block_tile($00FC,0,0,0,1), make_block_tile($00FD,0,0,0,1) ; $1F8
    dc.w make_block_tile($00FE,0,0,0,1), make_block_tile($0103,0,0,0,1), make_block_tile($0106,0,0,0,1), make_block_tile($0107,0,0,0,1) ; $2FC
    dc.w make_block_tile($010B,0,0,0,1), make_block_tile($010E,0,0,0,1), make_block_tile($010F,0,0,0,1), make_block_tile($0110,0,0,0,1) ; $200
    dc.w make_block_tile($0112,0,0,0,1), make_block_tile($0117,0,0,0,1), make_block_tile($011C,0,0,0,1), make_block_tile($011D,0,0,0,1) ; $204
    dc.w make_block_tile($0121,0,0,0,1), make_block_tile($0129,0,0,0,1), make_block_tile($012C,0,0,0,1), make_block_tile($012D,0,0,0,1) ; $208
    dc.w make_block_tile($0131,0,0,0,1), make_block_tile($0134,0,0,0,1), make_block_tile($0135,0,0,0,1), make_block_tile($013B,0,0,0,1) ; $20C
    dc.w make_block_tile($013D,0,0,0,1), make_block_tile($013E,0,0,0,1), make_block_tile($013F,0,0,0,1), make_block_tile($0140,0,0,0,1) ; $210
    dc.w make_block_tile($0141,0,0,0,1), make_block_tile($0145,0,0,0,1), make_block_tile($0146,0,0,0,1), make_block_tile($0149,0,0,0,1) ; $214
    dc.w make_block_tile($014A,0,0,0,1), make_block_tile($014C,0,0,0,1), make_block_tile($014D,0,0,0,1), make_block_tile($014E,0,0,0,1) ; $218
    dc.w make_block_tile($014F,0,0,0,1), make_block_tile($0150,0,0,0,1), make_block_tile($0152,0,0,0,1), make_block_tile($0153,0,0,0,1) ; $21C
    dc.w make_block_tile($0154,0,0,0,1), make_block_tile($0155,0,0,0,1), make_block_tile($0156,0,0,0,1), make_block_tile($0157,0,0,0,1) ; $220
    dc.w make_block_tile($0158,0,0,0,1), make_block_tile($015A,0,0,0,1), make_block_tile($015B,0,0,0,1), make_block_tile($015C,0,0,0,1) ; $224
    dc.w make_block_tile($0160,0,0,0,1), make_block_tile($0161,0,0,0,1), make_block_tile($0162,0,0,0,1), make_block_tile($0164,0,0,0,1) ; $228
    dc.w make_block_tile($0166,0,0,0,1), make_block_tile($0167,0,0,0,1), make_block_tile($0169,0,0,0,1), make_block_tile($016B,0,0,0,1) ; $22C
    dc.w make_block_tile($016D,0,0,0,1), make_block_tile($016E,0,0,0,1), make_block_tile($016F,0,0,0,1), make_block_tile($0171,0,0,0,1) ; $230
    dc.w make_block_tile($0172,0,0,0,1), make_block_tile($0173,0,0,0,1), make_block_tile($006E,1,0,0,1), make_block_tile($007D,1,0,0,1) ; $234
    dc.w make_block_tile($00C3,1,0,0,1), make_block_tile($00DB,1,0,0,1), make_block_tile($00E7,1,0,0,1), make_block_tile($00E8,1,0,0,1) ; $238
    dc.w make_block_tile($00EB,1,0,0,1), make_block_tile($00ED,1,0,0,1), make_block_tile($00F2,1,0,0,1), make_block_tile($00F6,1,0,0,1) ; $23C
    dc.w make_block_tile($00FA,1,0,0,1), make_block_tile($00FC,1,0,0,1), make_block_tile($00FE,1,0,0,1), make_block_tile($002D,1,0,0,1) ; $240
    dc.w make_block_tile($0103,1,0,0,1), make_block_tile($0106,1,0,0,1), make_block_tile($0107,1,0,0,1), make_block_tile($010B,1,0,0,1) ; $244
    dc.w make_block_tile($0073,1,0,0,1), make_block_tile($009A,1,0,0,1), make_block_tile($0129,1,0,0,1), make_block_tile($012C,1,0,0,1) ; $248
    dc.w make_block_tile($012D,1,0,0,1), make_block_tile($0111,1,0,0,1), make_block_tile($013C,1,0,0,1), make_block_tile($0120,1,0,0,1) ; $24C
    dc.w make_block_tile($0146,1,0,0,1), make_block_tile($00A9,1,0,0,1), make_block_tile($009C,1,0,0,1), make_block_tile($0116,1,0,0,1) ; $250
    dc.w make_block_tile($014F,1,0,0,1), make_block_tile($014C,1,0,0,1), make_block_tile($006F,1,0,0,1), make_block_tile($0158,1,0,0,1) ; $254
    dc.w make_block_tile($0156,1,0,0,1), make_block_tile($0159,1,0,0,1), make_block_tile($015A,1,0,0,1), make_block_tile($0161,1,0,0,1) ; $258
    dc.w make_block_tile($007B,1,0,0,1), make_block_tile($0166,1,0,0,1), make_block_tile($011C,1,0,0,1), make_block_tile($0118,1,0,0,1) ; $25C
    dc.w make_block_tile($00A0,1,0,0,1), make_block_tile($00A3,1,0,0,1), make_block_tile($0167,1,0,0,1), make_block_tile($00A1,1,0,0,1) ; $260
 
; These are run-length encoded pattern names. They get sent to either the
; pattern name table buffer or one region of one of the plane A name tables
; in the special stage.
; They are indexed by the third segment of the mappings in Map_SpecialStageTrack, above.
; Format: PNT,count
;word_69E6
SSPNT_RLELUT:
    dc.w    make_block_tile($0007,0,0,0,0),$0001,   make_block_tile($0001,0,0,0,0),$0001    ; $00
    dc.w    make_block_tile($004A,0,0,0,0),$0001,   make_block_tile($0039,0,0,0,0),$0003    ; $02
    dc.w    make_block_tile($0001,0,0,0,0),$0005,   make_block_tile($0028,0,0,0,0),$0007    ; $04
    dc.w    make_block_tile($002C,0,0,0,0),$0001,   make_block_tile($0001,0,0,0,0),$0002    ; $06
    dc.w    make_block_tile($0028,0,0,0,0),$0005,   make_block_tile($0039,0,0,0,0),$0001    ; $08
    dc.w    make_block_tile($0028,0,0,0,0),$0009,   make_block_tile($0001,0,0,0,0),$0004    ; $0A
    dc.w    make_block_tile($0028,0,0,0,0),$0006,   make_block_tile($0028,0,0,0,0),$0003    ; $0C
    dc.w    make_block_tile($004A,0,0,0,0),$0002,   make_block_tile($0001,0,0,0,0),$0003    ; $0E
    dc.w    make_block_tile($0028,0,0,0,0),$0004,   make_block_tile($0039,0,0,0,0),$0002    ; $10
    dc.w    make_block_tile($0039,0,0,0,0),$0004,   make_block_tile($0001,0,0,0,0),$0006    ; $12
    dc.w    make_block_tile($0007,0,0,0,0),$0002,   make_block_tile($002C,0,0,0,0),$0002    ; $14
    dc.w    make_block_tile($0028,0,0,0,0),$0001,   make_block_tile($001D,0,0,0,0),$0001    ; $16
    dc.w    make_block_tile($0028,0,0,0,0),$0008,   make_block_tile($0028,0,0,0,0),$0002    ; $18
    dc.w    make_block_tile($0007,0,0,0,0),$0003,   make_block_tile($0001,0,0,0,0),$0007    ; $1A
    dc.w    make_block_tile($0028,0,0,0,0),$000B,   make_block_tile($0039,0,0,0,0),$0005    ; $1C
    dc.w    make_block_tile($001D,0,0,0,0),$0003,   make_block_tile($001D,0,0,0,0),$0004    ; $1E
    dc.w    make_block_tile($001D,0,0,0,0),$0002,   make_block_tile($001D,0,0,0,0),$0005    ; $20
    dc.w    make_block_tile($0028,0,0,0,0),$000D,   make_block_tile($000B,0,0,0,0),$0001    ; $22
    dc.w    make_block_tile($0028,0,0,0,0),$000A,   make_block_tile($0039,0,0,0,0),$0006    ; $24
    dc.w    make_block_tile($0039,0,0,0,0),$0007,   make_block_tile($002C,0,0,0,0),$0003    ; $26
    dc.w    make_block_tile($001D,0,0,0,0),$0009,   make_block_tile($004A,0,0,0,0),$0003    ; $28
    dc.w    make_block_tile($001D,0,0,0,0),$0007,   make_block_tile($0028,0,0,0,0),$000F    ; $2A
    dc.w    make_block_tile($001D,0,0,0,0),$000B,   make_block_tile($001D,0,0,0,0),$0011    ; $2C
    dc.w    make_block_tile($001D,0,0,0,0),$000D,   make_block_tile($001D,0,0,0,0),$0008    ; $2E
    dc.w    make_block_tile($0028,0,0,0,0),$0011,   make_block_tile($001D,0,0,0,0),$0006    ; $30
    dc.w    make_block_tile($000B,0,0,0,0),$0002,   make_block_tile($001D,0,0,0,0),$0015    ; $32
    dc.w    make_block_tile($0028,0,0,0,0),$000C,   make_block_tile($001D,0,0,0,0),$000A    ; $34
    dc.w    make_block_tile($0028,0,0,0,0),$000E,   make_block_tile($0001,0,0,0,0),$0008    ; $36
    dc.w    make_block_tile($001D,0,0,0,0),$000F,   make_block_tile($0028,0,0,0,0),$0010    ; $38
    dc.w    make_block_tile($0007,0,0,0,0),$0006,   make_block_tile($001D,0,0,0,0),$0013    ; $3A
    dc.w    make_block_tile($004A,0,0,0,0),$0004,   make_block_tile($001D,0,0,0,0),$0017    ; $3C
    dc.w    make_block_tile($0007,0,0,0,0),$0004,   make_block_tile($000B,0,0,0,0),$0003    ; $3E
;word_6AE6
SSPNT_RLELUT_Part2:
    dc.w    make_block_tile($001D,0,0,0,0),$001B,   make_block_tile($004A,0,0,0,0),$0006    ; $40
    dc.w    make_block_tile($001D,0,0,0,0),$001D,   make_block_tile($004A,0,0,0,0),$0005    ; $42
    dc.w    make_block_tile($0001,0,0,0,0),$0009,   make_block_tile($0007,0,0,0,0),$0005    ; $44
    dc.w    make_block_tile($001D,0,0,0,0),$001E,   make_block_tile($001D,0,0,0,0),$0019    ; $46
    dc.w    make_block_tile($0001,0,0,0,0),$0011,   make_block_tile($001D,0,0,0,0),$000C    ; $48
    dc.w    make_block_tile($001D,0,0,0,0),$007F,   make_block_tile($002C,0,0,0,0),$0004    ; $4A
    dc.w    make_block_tile($001D,0,0,0,0),$000E,   make_block_tile($001D,0,0,0,0),$001C    ; $4C
    dc.w    make_block_tile($004A,0,0,0,0),$000A,   make_block_tile($001D,0,0,0,0),$001A    ; $4E
    dc.w    make_block_tile($004A,0,0,0,0),$0007,   make_block_tile($001D,0,0,0,0),$0018    ; $50
    dc.w    make_block_tile($000B,0,0,0,0),$0004,   make_block_tile($001D,0,0,0,0),$0012    ; $52
    dc.w    make_block_tile($001D,0,0,0,0),$0010,   make_block_tile($0001,0,0,0,0),$000F    ; $54
    dc.w    make_block_tile($000B,0,0,0,0),$0005,   make_block_tile($0001,0,0,0,0),$000D    ; $56
    dc.w    make_block_tile($0001,0,0,0,0),$0013,   make_block_tile($004A,0,0,0,0),$0009    ; $58
    dc.w    make_block_tile($004A,0,0,0,0),$000B,   make_block_tile($004A,0,0,0,0),$000C    ; $5A
    dc.w    make_block_tile($002C,0,0,0,0),$0005,   make_block_tile($001D,0,0,0,0),$0014    ; $5C
    dc.w    make_block_tile($000B,0,0,0,0),$0007,   make_block_tile($001D,0,0,0,0),$0016    ; $5E
    dc.w    make_block_tile($0001,0,0,0,0),$000C,   make_block_tile($0001,0,0,0,0),$000E    ; $60
    dc.w    make_block_tile($004A,0,0,0,0),$0008,   make_block_tile($001D,0,0,0,0),$005F    ; $62
    dc.w    make_block_tile($0001,0,0,0,0),$000A,   make_block_tile($000B,0,0,0,0),$0006    ; $64
    dc.w    make_block_tile($000B,0,0,0,0),$0008,   make_block_tile($000B,0,0,0,0),$000A    ; $66
    dc.w    make_block_tile($0039,0,0,0,0),$0008,   make_block_tile($000B,0,0,0,0),$0009    ; $68
    dc.w    make_block_tile($002C,0,0,0,0),$0006,   make_block_tile($0001,0,0,0,0),$0010    ; $6A
    dc.w    make_block_tile($000B,0,0,0,0),$000C,   make_block_tile($0001,0,0,0,0),$000B    ; $6C
    dc.w    make_block_tile($0001,0,0,0,0),$0012,   make_block_tile($0007,0,0,0,0),$0007    ; $6E
    dc.w    make_block_tile($001D,0,0,0,0),$001F,   make_block_tile($0028,0,0,0,0),$0012    ; $70
    dc.w    make_block_tile($000B,0,0,0,0),$000B,   make_block_tile($002C,0,0,0,0),$0007    ; $72
    dc.w    make_block_tile($002C,0,0,0,0),$000B,   make_block_tile($001D,0,0,0,0),$0023    ; $74
    dc.w    make_block_tile($0001,0,0,0,0),$0015,   make_block_tile($002C,0,0,0,0),$0008    ; $76
    dc.w    make_block_tile($001D,0,0,0,0),$002E,   make_block_tile($001D,0,0,0,0),$003F    ; $78
    dc.w    make_block_tile($0001,0,0,0,0),$0014,   make_block_tile($000B,0,0,0,0),$000D    ; $7A
    dc.w    make_block_tile($002C,0,0,0,0),$0009,   make_block_tile($002C,0,0,0,0),$000A    ; $7C
    dc.w    make_block_tile($001D,0,0,0,0),$0025,   make_block_tile($001D,0,0,0,0),$0055    ; $7E
    dc.w    make_block_tile($001D,0,0,0,0),$0071,   make_block_tile($001D,0,0,0,0),$007C    ; $80
    dc.w    make_block_tile($004A,0,0,0,0),$000D,   make_block_tile($002C,0,0,0,0),$000C    ; $82
    dc.w    make_block_tile($002C,0,0,0,0),$000F,   make_block_tile($002C,0,0,0,0),$0010    ; $84
 
;unknown
;byte_6BFE:
    dc.b $FF,$FB,$FF,$FB,$FF,$FA,$FF,$FA; 528
    dc.b $FF,$FA,$FF,$FA    ; 544
; ===========================================================================
; (!)
;loc_6C0A
SSTrackSetOrientation:
    move.b  (SS_Alternate_HorizScroll_Buf).w,(SS_Last_Alternate_HorizScroll_Buf).w
    moveq   #0,d1
    movea.l (SSTrack_mappings_bitflags).w,a0                ; Get frame mappings pointer
    cmpa.l  #MapSpec_Straight2,a0                           ; Is the track rising or one of the first straight frame?
    blt.s   +                                               ; Branch if yes
    cmpa.l  #MapSpec_Straight3,a0                           ; Is it straight path frame 3 or higher?
    bge.s   +                                               ; Branch if yes
    ; We only get here for straight frame 2
    movea.l (SS_CurrentLevelLayout).w,a5                    ; Get current level layout
    move.b  (SpecialStage_CurrentSegment).w,d1              ; Get current segment
    move.b  (a5,d1.w),d1                                    ; Get segment geometry
    bpl.s   +++                                             ; Branch if not flipped
-
    st.b    (SSTrack_Orientation).w                         ; Mark as being flipped
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    cmp.b   (SS_player_anim_frame_timer).w,d0               ; Is it lower than the player's frame?
    blt.w   return_6C9A                                     ; Return if yes
    st.b    (SS_Alternate_HorizScroll_Buf).w                ; Use the alternate horizontal scroll buffer
    rts
; ===========================================================================
+
    cmpa.l  #MapSpec_Rise14,a0                              ; Is the track one of the first 13 rising frames?
    blt.s   +                                               ; Branch if yes
    cmpa.l  #MapSpec_Rise15,a0                              ; Is it rising frame 15 or higher?
    bge.s   +                                               ; Branch if yes
    ; We only get here for straight frame 14
    movea.l (SS_CurrentLevelLayout).w,a5                    ; Get current level layout
    move.b  (SpecialStage_CurrentSegment).w,d1              ; Get current segment
    move.b  (a5,d1.w),d1                                    ; Get segment geometry
    bpl.s   ++                                              ; Branch if not flipped
    bra.s   -
; ===========================================================================
+
    cmpa.l  #MapSpec_Drop6,a0                               ; Is the track before drop frame 6?
    blt.s   return_6C9A                                     ; Return is yes
    cmpa.l  #MapSpec_Drop7,a0                               ; Is it drop frame 7 or higher?
    bge.s   return_6C9A                                     ; Return if yes
    ; We only get here for straight frame 6
    movea.l (SS_CurrentLevelLayout).w,a5                    ; Get current level layout
    move.b  (SpecialStage_CurrentSegment).w,d1              ; Get current segment
    move.b  (a5,d1.w),d1                                    ; Get segment geometry
    bmi.s   -                                               ; Branch if flipped
+
    sf.b    (SSTrack_Orientation).w                         ; Mark as being unflipped
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    cmp.b   (SS_player_anim_frame_timer).w,d0               ; Is it lower than the player's frame?
    blt.s   return_6C9A                                     ; Return if yes
    sf.b    (SS_Alternate_HorizScroll_Buf).w                ; Don't use the alternate horizontal scroll buffer
 
return_6C9A:
    rts
; End of function SSTrack_Draw
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Initialize the PNT and H scroll table buffers.
 
ssInitTableBuffers:
    lea (SS_Horiz_Scroll_Buf_1).w,a1
    lea (SS_Horiz_Scroll_Buf_2).w,a2
    moveq   #0,d0                                           ; Scroll of 0 for PNTA and PNTB on lines 0 and 1 (normal) or lines 6 and 7 (flipped)
    moveq   #0,d1                                           ; Scroll of 0 for PNTB on lines 2 and 3 (normal) or lines 4 and 5 (flipped)
    moveq   #0,d2                                           ; Scroll of 0 for PNTB on lines 4 and 5 (normal) or lines 2 and 3 (flipped)
    moveq   #0,d3                                           ; Scroll of 0 for PNTB on lines 6 and 7 (normal) or lines 0 and 1 (flipped)
    move.w  #-$100,d1                                       ; Scroll of 3 screens for PNTA on lines 2 and 3 (normal) or lines 4 and 5 (flipped)
    move.w  #-$200,d2                                       ; Scroll of 2 screens for PNTA on lines 4 and 5 (normal) or lines 2 and 3 (flipped)
    move.w  #-$300,d3                                       ; Scroll of 1 screen for PNTA on lines 6 and 7 (normal) or lines 0 and 1 (flipped)
    swap    d1
    swap    d2
    swap    d3
    moveq   #$1F,d4
 
-   move.l  d0,(a1)+
    move.l  d0,(a1)+
    move.l  d1,(a1)+
    move.l  d1,(a1)+
    move.l  d2,(a1)+
    move.l  d2,(a1)+
    move.l  d3,(a1)+
    move.l  d3,(a1)+
    move.l  d3,(a2)+
    move.l  d3,(a2)+
    move.l  d2,(a2)+
    move.l  d2,(a2)+
    move.l  d1,(a2)+
    move.l  d1,(a2)+
    move.l  d0,(a2)+
    move.l  d0,(a2)+
    dbf d4,-
 
    rts
; End of function ssInitTableBuffers
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; Load compressed special stage data into RAM, or VRAM for the art.
 
ssLdComprsdData:
    lea (ArtKos_Special).l,a0
    lea (Chunk_Table).l,a1
    bsr.w   KosDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_VRAM_Start),VRAM,WRITE),(VDP_control_port).l
    lea (VDP_data_port).l,a1
    movea.l #Chunk_Table,a0
    move.w  (a0)+,d0
    subq.w  #1,d0
 
-   rept 7
    move.l  (a0),(a1)
    endm
    move.l  (a0)+,(a1)
    dbf d0,-
 
    lea (MiscKoz_SpecialPerspective).l,a0
    lea (SSRAM_MiscKoz_SpecialPerspective).l,a1
    bsr.w   KosDec
    lea (MiscKoz_SpecialLevelLayout).l,a0
    lea (SSRAM_MiscNem_SpecialLevelLayout).w,a4
    bsr.w   NemDecToRAM
    lea (MiscKoz_SpecialObjectLocations).l,a0
    lea (SSRAM_MiscKoz_SpecialObjectLocations).w,a1
    bsr.w   KosDec
    rts
; End of function ssLdComprsdData
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_6D52
SSPlaneB_Background:
    move    #$2700,sr
    movea.l #Chunk_Table,a1
    lea (MapEng_SpecialBackBottom).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialBack,0,0),d0
    bsr.w   EniDec
    movea.l #Chunk_Table+$400,a1
    lea (MapEng_SpecialBack).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialBack,0,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_SS_Plane_B_Name_Table + $0000,VRAM,WRITE),d0
    moveq   #$1F,d1
    moveq   #$1F,d2
    jsrto   (PlaneMapToVRAM_H80_SpecialStage).l, PlaneMapToVRAM_H80_SpecialStage
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_SS_Plane_B_Name_Table + $0040,VRAM,WRITE),d0
    moveq   #$1F,d1
    moveq   #$1F,d2
    jsrto   (PlaneMapToVRAM_H80_SpecialStage).l, PlaneMapToVRAM_H80_SpecialStage
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_SS_Plane_B_Name_Table + $0080,VRAM,WRITE),d0
    moveq   #$1F,d1
    moveq   #$1F,d2
    jsrto   (PlaneMapToVRAM_H80_SpecialStage).l, PlaneMapToVRAM_H80_SpecialStage
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_SS_Plane_B_Name_Table + $00C0,VRAM,WRITE),d0
    moveq   #$1F,d1
    moveq   #$1F,d2
    jsrto   (PlaneMapToVRAM_H80_SpecialStage).l, PlaneMapToVRAM_H80_SpecialStage
    move    #$2300,sr
    rts
; End of function SSPlaneB_Background
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_6DD4
SSDecompressPlayerArt:
    lea (ArtNem_SpecialSonicAndTails).l,a0
    lea (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF).l,a4
    bra.w   NemDecToRAM
; End of function SSDecompressPlayerArt
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_6DE4
SS_ScrollBG:
    bsr.w   SSPlaneB_SetHorizOffset
    bsr.w   SSTrack_SetVscroll
    rts
; End of function SS_ScrollBG
 
; ===========================================================================
; special stage background vertical and horizontal scroll offsets
off_6DEE:   offsetTable
        offsetTableEntry.w byte_6E04    ;  0
        offsetTableEntry.w byte_6E09    ;  1
        offsetTableEntry.w byte_6E0E    ;  2
        offsetTableEntry.w byte_6E13    ;  3
        offsetTableEntry.w byte_6E18    ;  4
        offsetTableEntry.w byte_6E1D    ;  5
        offsetTableEntry.w byte_6E22    ;  6
        offsetTableEntry.w byte_6E27    ;  7
        offsetTableEntry.w byte_6E2C    ;  8
        offsetTableEntry.w byte_6E31    ;  9
        offsetTableEntry.w byte_6E36    ; $A
byte_6E04:  dc.b   2,  2,  2,  2,  2
byte_6E09:  dc.b   4,  4,  5,  4,  5
byte_6E0E:  dc.b  $B, $B, $B, $B, $C
byte_6E13:  dc.b   0,  0,  1,  0,  0
byte_6E18:  dc.b   1,  1,  1,  1,  1
byte_6E1D:  dc.b   9,  9,  8,  9,  9
byte_6E22:  dc.b   9,  9,  9,  9, $A
byte_6E27:  dc.b   7,  7,  6,  7,  7
byte_6E2C:  dc.b   0,  1,  1,  1,  0
byte_6E31:  dc.b   4,  3,  3,  3,  4
byte_6E36:  dc.b   0,  0,$FF,  0,  0
    even
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_6E3C
SSPlaneB_SetHorizOffset:
    moveq   #0,d7
    moveq   #0,d6
    moveq   #0,d0
    move.b  (SSTrack_last_anim_frame).w,d2                  ; Get last track animation frame
    move.b  (SSTrack_anim).w,d0                             ; Get current track animation
    add.w   d0,d0                                           ; Convert it to an index
    move.w  off_6E54(pc,d0.w),d0
    jmp off_6E54(pc,d0.w)
; ===========================================================================
off_6E54:   offsetTable
        offsetTableEntry.w +    ; 0         ; Turn, then rise
        offsetTableEntry.w +    ; 1         ; Turn, then drop
        offsetTableEntry.w +    ; 2         ; Turn, then straight
        offsetTableEntry.w ++   ; 3 ; rts   ; Straight
        offsetTableEntry.w ++   ; 4 ; rts   ; Straight, then turn
; ===========================================================================
+
    moveq   #0,d1
    cmpi.b  #1,d2                                           ; Was the last frame the first in this segment?
    blt.s   ++                                              ; Branch if yes
    moveq   #2,d1
    cmpi.b  #2,d2                                           ; Was the last frame frame 1?
    blt.s   ++                                              ; Branch if yes
    moveq   #4,d1
    cmpi.b  #$A,d2                                          ; Was the last frame less than $A?
    blt.s   ++                                              ; Branch if yes
    moveq   #2,d1
    cmpi.b  #$B,d2                                          ; Was the last frame $A?
    blt.s   ++                                              ; Branch if yes
    moveq   #0,d1
    cmpi.b  #$C,d2                                          ; Was the last frame $B?
    blt.s   ++                                              ; Branch if yes
+
    rts
; ===========================================================================
+
    moveq   #0,d0
    moveq   #0,d2
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    lea_    off_6DEE,a0                                     ; a0 = pointer to background scroll data
    adda.w  (a0,d1.w),a0                                    ; a0 = pointer to background scroll data for current animation frame
    move.b  (a0,d0.w),d2                                    ; Get background offset for current frame duration
    tst.b   (SS_Last_Alternate_HorizScroll_Buf).w           ; Was the alternate horizontal scroll buffer used last time?
    bne.s   +                                               ; Branch if yes
    tst.b   (SS_Alternate_HorizScroll_Buf).w                ; Is the alternate horizontal scroll buffer being used now?
    beq.s   +++                                             ; Branch if not
    bra.s   ++
; ===========================================================================
+
    tst.b   (SS_Alternate_HorizScroll_Buf).w                ; Is the alternate horizontal scroll buffer still being used?
    bne.s   ++                                              ; Branch if yes
    lea (SS_Horiz_Scroll_Buf_1 + 2).w,a1                    ; Load horizontal scroll buffer for PNT B
    bra.s   +++
; ===========================================================================
+
    lea (SS_Horiz_Scroll_Buf_2 + 2).w,a1                    ; Load alternate horizontal scroll buffer for PNT B
    neg.w   d2                                              ; Change the sign of the background offset
    bra.s   ++
; ===========================================================================
+
    lea (SS_Horiz_Scroll_Buf_1 + 2).w,a1                    ; Load horizontal scroll buffer for PNT B
    tst.b   (SS_Alternate_HorizScroll_Buf).w                ; Is the alternate horizontal scroll buffer being used now?
    beq.s   +                                               ; Branch if not
    lea (SS_Horiz_Scroll_Buf_2 + 2).w,a1                    ; Load alternate horizontal scroll buffer for PNT B
    neg.w   d2                                              ; Change the sign of the background offset
+
    move.w  #$FF,d0                                         ; 256 lines
-   sub.w   d2,(a1)+                                        ; Change current line's offset
    adda_.l #2,a1                                           ; Skip PNTA entry
    dbf d0,-
 
    rts
; End of function SSPlaneB_SetHorizOffset
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_6EE0
SSTrack_SetVscroll:
    move.w  (Vscroll_Factor_BG).w,(SSTrack_LastVScroll).w   ; Save last vertical scroll value
    moveq   #0,d7                                           ; Set flag to decrease vertical scroll
    moveq   #0,d0
    moveq   #0,d2
    move.b  (SSTrack_last_anim_frame).w,d2                  ; Get last track animation frame
    move.b  (SSTrack_anim).w,d0                             ; Get current track animation
    add.w   d0,d0                                           ; Convert it to index
    move.w  off_6EFE(pc,d0.w),d0
    jmp off_6EFE(pc,d0.w)
; ===========================================================================
off_6EFE:   offsetTable
        offsetTableEntry.w loc_6F0A ; 0         ; Turn, then rise
        offsetTableEntry.w loc_6F2A ; 1         ; Turn, then drop
        offsetTableEntry.w +        ; 2 ; rts   ; Turn, then straight
        offsetTableEntry.w loc_6F4C ; 3         ; Straight
        offsetTableEntry.w +        ; 4 ; rts   ; Straight, then turn
; ===========================================================================
+
    rts
; ===========================================================================
 
loc_6F0A:
    move.b  +(pc,d2.w),d1                                   ; Get current frame's vertical scroll offset
    bpl.s   SSTrack_ApplyVscroll                            ; Branch if positive
    rts
; ===========================================================================
; Special stage vertical scroll index for 'turn, then rise' animation
+
    dc.b  -1
    dc.b  -1    ; 1
    dc.b  -1    ; 2
    dc.b  -1    ; 3
    dc.b  -1    ; 4
    dc.b  -1    ; 5
    dc.b  -1    ; 6
    dc.b  -1    ; 7
    dc.b  -1    ; 8
    dc.b  -1    ; 9
    dc.b   8    ; 10
    dc.b   8    ; 11
    dc.b   2    ; 12
    dc.b   4    ; 13
    dc.b   4    ; 14
    dc.b   4    ; 15
    dc.b   4    ; 16
    dc.b   4    ; 17
    dc.b   4    ; 18
    dc.b  $A    ; 19
    dc.b  $C    ; 20
    dc.b  $E    ; 21
    dc.b $12    ; 22
    dc.b $10    ; 23
; ===========================================================================
 
loc_6F2A:
    st  d7                                                  ; Set flag to increase vertical scroll
    move.b  +(pc,d2.w),d1                                   ; Get current frame's vertical scroll offset
    bpl.s   SSTrack_ApplyVscroll                            ; Branch if positive
    rts
; ===========================================================================
; Special stage vertical scroll index for 'turn, then drop' animation
+
    dc.b  -1
    dc.b  -1    ; 1
    dc.b  -1    ; 2
    dc.b  -1    ; 3
    dc.b  -1    ; 4
    dc.b  -1    ; 5
    dc.b  -1    ; 6
    dc.b  -1    ; 7
    dc.b  -1    ; 8
    dc.b  -1    ; 9
    dc.b  -1    ; 10
    dc.b $10    ; 11
    dc.b $12    ; 12
    dc.b  $E    ; 13
    dc.b  $C    ; 14
    dc.b  $A    ; 15
    dc.b   4    ; 16
    dc.b   4    ; 17
    dc.b   4    ; 18
    dc.b   4    ; 19
    dc.b   4    ; 20
    dc.b   4    ; 21
    dc.b   2    ; 22
    dc.b   0    ; 23
; ===========================================================================
 
loc_6F4C:
    tst.b   (SS_Pause_Only_flag).w                          ; Is the game paused?
    bne.s   +   ; rts                                       ; Return if yes
    move.b  ++(pc,d2.w),d1                                  ; Get current frame's vertical scroll offset
    bpl.s   SSTrack_ApplyVscroll                            ; Branch if positive                                    
+
    rts
; ===========================================================================
; Special stage vertical scroll index for 'straight' animation -- bobbing up and down
+
   rept 4
    dc.b   6
    dc.b   6
    dc.b $14
    dc.b $14
    endm
; ===========================================================================
;loc_6F6A
SSTrack_ApplyVscroll:
    moveq   #0,d0
    moveq   #0,d2
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    lea_    off_6DEE,a0                                     ; a0 = pointer to background scroll data
    adda.w  (a0,d1.w),a0                                    ; a0 = pointer to background scroll data for current animation frame
    move.b  (a0,d0.w),d2                                    ; Get background offset for current frame duration
    tst.b   d7                                              ; Are we supposed to increase the vertical scroll?
    bpl.s   +                                               ; Branch if not
    add.w   d2,(Vscroll_Factor_BG).w                        ; Increase vertical scroll
    rts
; ===========================================================================
+
    sub.w   d2,(Vscroll_Factor_BG).w                        ; Decrease vertical scroll
    rts
; End of function SSTrack_SetVscroll
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; sub_6F8E:
SSSingleObjLoad:
    lea (SS_Dynamic_Object_RAM).w,a1
    move.w  #(SS_Dynamic_Object_RAM_End-SS_Dynamic_Object_RAM)/object_size-1,d5
 
-   tst.b   id(a1)
    beq.s   +   ; rts
    lea next_object(a1),a1 ; a1=object
    dbf d5,-
+
    rts
; End of function sub_6F8E
 
; ===========================================================================
 
;loc_6FA4:
SSSingleObjLoad2:
    movea.l a0,a1
    move.w  #SS_Dynamic_Object_RAM_End,d5
    sub.w   a0,d5
    if object_size=$40
    lsr.w   #6,d5
    else
    divu.w  #object_size,d5
    endif
    subq.w  #1,d5
    bcs.s   +   ; rts
 
-   tst.b   id(a1)
    beq.s   +   ; rts
    lea next_object(a1),a1
    dbf d5,-
 
+   rts
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5E - HUD from Special Stage
; ----------------------------------------------------------------------------
; Sprite_6FC0:
Obj5E:
    move.b  routine(a0),d0
    bne.w   JmpTo_DisplaySprite
    move.l  #Obj5E_MapUnc_7070,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,0,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #0,priority(a0)
    move.b  #1,routine(a0)
    bset    #6,render_flags(a0)
    moveq   #0,d1
    tst.b   (SS_2p_Flag).w
    beq.s   +
    addq.w  #6,d1
    tst.b   (Graphics_Flags).w
    bpl.s   ++
    addq.w  #1,d1
    bra.s   ++
; ---------------------------------------------------------------------------
+   move.w  (Player_mode).w,d1
    andi.w  #3,d1
    tst.b   (Graphics_Flags).w
    bpl.s   +
    addq.w  #3,d1 ; set special stage tails name to "TAILS" instead of MILES
+
    add.w   d1,d1
    moveq   #0,d2
    moveq   #0,d3
    lea (SSHUDLayout).l,a1
    lea sub2_x_pos(a0),a2
    adda.w  (a1,d1.w),a1
    move.b  (a1)+,d3
    move.b  d3,mainspr_childsprites(a0)
    subq.w  #1,d3
    moveq   #0,d0
    move.b  (a1)+,d0
 
-   move.w  d0,(a2,d2.w)
    move.b  (a1)+,sub2_mapframe-sub2_x_pos(a2,d2.w) ; sub2_mapframe
    addq.w  #next_subspr,d2
    dbf d3,-
 
    rts
; ===========================================================================
; off_7042:
SSHUDLayout:    offsetTable
        offsetTableEntry.w SSHUD_SonicMilesTotal    ; 0
        offsetTableEntry.w SSHUD_Sonic          ; 1
        offsetTableEntry.w SSHUD_Miles          ; 2
        offsetTableEntry.w SSHUD_SonicTailsTotal    ; 3
        offsetTableEntry.w SSHUD_Sonic_2        ; 4
        offsetTableEntry.w SSHUD_Tails          ; 5
        offsetTableEntry.w SSHUD_SonicMiles     ; 6
        offsetTableEntry.w SSHUD_SonicTails     ; 7
 
; byte_7052:
SSHUD_SonicMilesTotal:
    dc.b   3        ; Sprite count
    dc.b   $80      ; X-pos
    dc.b   0,  1,  3    ; Sprite 1 frame, Sprite 2 frame, etc
; byte_7057:
SSHUD_Sonic:
    dc.b   1
    dc.b   $D4
    dc.b   0
; byte_705A:
SSHUD_Miles:
    dc.b   1
    dc.b   $38
    dc.b   1
 
; byte_705D:
SSHUD_SonicTailsTotal:
    dc.b   3
    dc.b   $80
    dc.b   0,  2,  3
; byte_7062:
SSHUD_Sonic_2:
    dc.b   1
    dc.b   $D4
    dc.b   0
; byte_7065:
SSHUD_Tails:
    dc.b   1
    dc.b   $38
    dc.b   2
 
; 2 player
; byte_7068:
SSHUD_SonicMiles:
    dc.b   2
    dc.b   $80
    dc.b   0,  1
; byte_706C:
SSHUD_SonicTails:
    dc.b   2
    dc.b   $80
    dc.b   0,  2
; -----------------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------------
Obj5E_MapUnc_7070:  BINCLUDE "mappings/sprite/obj5E.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5F - Start banner/"Ending controller" from Special Stage
; ----------------------------------------------------------------------------
; Sprite_70F0:
Obj5F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj5F_Index(pc,d0.w),d1
    jmp Obj5F_Index(pc,d1.w)
; ===========================================================================
; off_70FE:
Obj5F_Index:    offsetTable
        offsetTableEntry.w Obj5F_Init   ;  0
        offsetTableEntry.w Obj5F_Main   ;  2
        offsetTableEntry.w loc_71B4 ;  4
        offsetTableEntry.w loc_710A ;  6
        offsetTableEntry.w return_723E  ;  8
        offsetTableEntry.w loc_7218 ; $A
; ===========================================================================
 
loc_710A:
    moveq   #0,d0
    move.b  angle(a0),d0
    bsr.w   CalcSine
    muls.w  objoff_14(a0),d0
    muls.w  objoff_14(a0),d1
    asr.w   #8,d0
    asr.w   #8,d1
    add.w   d1,x_pos(a0)
    add.w   d0,y_pos(a0)
    cmpi.w  #0,x_pos(a0)
    blt.w   JmpTo_DeleteObject
    cmpi.w  #$100,x_pos(a0)
    bgt.w   JmpTo_DeleteObject
    cmpi.w  #0,y_pos(a0)
    blt.w   JmpTo_DeleteObject
 
    if removeJmpTos
JmpTo_DisplaySprite 
    endif
 
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
 
; loc_714A:
Obj5F_Init:
    tst.b   (SS_2p_Flag).w
    beq.s   +
    move.w  #8,d0
    jsrto   (Obj5A_PrintPhrase).l, JmpTo_Obj5A_PrintPhrase
+   move.w  #$80,x_pos(a0)
    move.w  #-$40,y_pos(a0)
    move.w  #$100,y_vel(a0)
    move.l  #Obj5F_MapUnc_7240,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialStart,0,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #2,routine(a0)
 
; loc_718A:
Obj5F_Main:
    jsrto   (ObjectMove).l, JmpTo_ObjectMove
    cmpi.w  #$48,y_pos(a0)
    blt.w   JmpTo_DisplaySprite
    move.w  #0,y_vel(a0)
    move.w  #$48,y_pos(a0)
    move.b  #4,routine(a0)
    move.b  #$F,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
 
loc_71B4:
    subi_.b #1,objoff_2A(a0)
    if ~~removeJmpTos
    bne.w   JmpTo_DisplaySprite
    else
    bne.s   JmpTo_DisplaySprite
    endif
    moveq   #6,d6
 
; WARNING: the build script needs editing if you rename this label
word_728C_user: lea (Obj5F_MapUnc_7240+$4C).l,a2 ; word_728C
 
    moveq   #2,d3
    move.w  #8,objoff_14(a0)
    move.b  #6,routine(a0)
 
-   bsr.w   SSSingleObjLoad
    bne.s   +
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
 
-   move.l  (a0,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,-
    if object_size&3
    move.w  (a0,d0.w),(a1,d0.w)
    endif
 
    move.b  d3,mapping_frame(a1)
    addq.w  #1,d3
    move.w  #-$28,d2
    move.w  8(a2),d1
    bsr.w   CalcAngle
    move.b  d0,angle(a1)
    lea $A(a2),a2
+   dbf d6,--
 
    move.b  #$A,routine(a0)
    move.w  #$1E,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_7218:
    subi_.w #1,objoff_2A(a0)
    bpl.s   +++ ; rts
    tst.b   (SS_2p_Flag).w
    beq.s   +
    move.w  #$A,d0
    jsrto   (Obj5A_PrintPhrase).l, JmpTo_Obj5A_PrintPhrase
    bra.s   ++
; ===========================================================================
+   jsrto   (Obj5A_CreateRingReqMessage).l, JmpTo_Obj5A_CreateRingReqMessage
 
+   st.b    (SpecialStage_Started).w
    jmpto   (DeleteObject).l, JmpTo_DeleteObject
; ===========================================================================
 
+   rts
; ===========================================================================
 
    if removeJmpTos
JmpTo_DeleteObject 
    jmp (DeleteObject).l
    endif
 
; ===========================================================================
 
return_723E:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
; WARNING: the build script needs editing if you rename this label
;      or if you change the meaning of frame 2 in these mappings
Obj5F_MapUnc_7240:  BINCLUDE "mappings/sprite/obj5F_a.bin"
; -----------------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------------
Obj5F_MapUnc_72D2:  BINCLUDE "mappings/sprite/obj5F_b.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 87 - Number of rings in Special Stage
; ----------------------------------------------------------------------------
; Sprite_7356:
Obj87:
    moveq   #0,d0
    move.b  objoff_A(a0),d0
    move.w  Obj87_Index(pc,d0.w),d1
    jmp Obj87_Index(pc,d1.w)
; ===========================================================================
; off_7364:
Obj87_Index:    offsetTable
        offsetTableEntry.w Obj87_Init   ; 0
        offsetTableEntry.w loc_7480 ; 2
        offsetTableEntry.w loc_753E ; 4
        offsetTableEntry.w loc_75DE ; 6
; ===========================================================================
 
; loc_736C:
Obj87_Init:
    move.b  #2,objoff_A(a0)     ; => loc_7480
    move.l  #Obj5F_MapUnc_72D2,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,2,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    bset    #6,render_flags(a0)
    move.b  #2,mainspr_childsprites(a0)
    move.w  #$20,d0
    moveq   #0,d1
    lea sub2_x_pos(a0),a1
    move.w  #$48,(a1)           ; sub2_x_pos
    move.w  d0,sub2_y_pos-sub2_x_pos(a1)    ; sub2_y_pos
    move.w  d1,mainspr_height-sub2_x_pos(a1) ; mainspr_height and sub2_mapframe
    move.w  #$E0,sub3_x_pos-sub2_x_pos(a1)  ; sub3_x_pos
    move.w  d0,sub3_y_pos-sub2_x_pos(a1)    ; sub3_y_pos
    move.w  d1,mapping_frame-sub2_x_pos(a1) ; mapping_frame and sub3_mapframe
    move.w  d0,sub4_y_pos-sub2_x_pos(a1)    ; sub4_y_pos
    move.w  d0,sub5_y_pos-sub2_x_pos(a1)    ; sub5_y_pos
    move.w  d0,sub6_y_pos-sub2_x_pos(a1)    ; sub6_y_pos
    move.w  d0,sub7_y_pos-sub2_x_pos(a1)    ; sub7_y_pos
    tst.b   (SS_2p_Flag).w
    bne.s   +++
    cmpi.w  #0,(Player_mode).w
    beq.s   +
    subi_.b #1,mainspr_childsprites(a0)
    move.w  #$94,(a1)           ; sub2_x_pos
    rts
; ===========================================================================
+
    bsr.w   SSSingleObjLoad
    bne.s   +   ; rts
    move.b  #ObjID_SSNumberOfRings,id(a1) ; load obj87
    move.b  #4,objoff_A(a1)     ; => loc_753E
    move.l  #Obj5F_MapUnc_72D2,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,2,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #1,mainspr_childsprites(a1)
    lea sub2_x_pos(a1),a2
    move.w  #$80,(a2)           ; sub2_x_pos
    move.w  d0,sub2_y_pos-sub2_x_pos(a2)    ; sub2_y_pos
    move.w  d1,mainspr_height-sub2_x_pos(a2) ; mainspr_height and sub2_mapframe
    move.w  d0,sub3_y_pos-sub2_x_pos(a2)    ; sub3_y_pos
    move.w  d0,sub4_y_pos-sub2_x_pos(a2)    ; sub4_y_pos
/   rts
; ===========================================================================
+
    bsr.w   SSSingleObjLoad
    bne.s   -   ; rts
    move.b  #ObjID_SSNumberOfRings,id(a1) ; load obj87
    move.b  #6,objoff_A(a1)     ; => loc_75DE
    move.l  #Obj5F_MapUnc_72D2,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,2,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #0,mainspr_childsprites(a1)
    lea sub2_x_pos(a1),a2
    move.w  #$2C,d0
    move.w  #$A,d1
    move.w  d0,sub2_y_pos-sub2_x_pos(a2)    ; sub2_y_pos
    move.w  d1,mainspr_height-sub2_x_pos(a2) ; mainspr_height and sub2_mapframe
    move.w  d0,sub3_y_pos-sub2_x_pos(a2)    ; sub3_y_pos
    move.w  d1,mapping_frame-sub2_x_pos(a2) ; mapping_frame and sub3_mapframe
    move.w  d0,sub4_y_pos-sub2_x_pos(a2)    ; sub4_y_pos
    move.w  d1,sub4_mapframe-1-sub2_x_pos(a2) ; something and sub4_mapframe
    rts
; ===========================================================================
 
loc_7480:
    moveq   #0,d0
    moveq   #0,d3
    moveq   #0,d5
    lea sub2_x_pos(a0),a1
    movea.l a1,a2
    addq.w  #5,a2   ; a2 = sub2_mapframe(a0)
    cmpi.w  #2,(Player_mode).w
    beq.s   loc_74EA
    move.b  (MainCharacter+ss_rings_hundreds).w,d0
    beq.s   +
    addq.w  #1,d3
    move.b  d0,(a2)
    lea next_subspr(a2),a2
+   move.b  (MainCharacter+ss_rings_tens).w,d0
    tst.b   d3
    bne.s   +
    tst.b   d0
    beq.s   ++
+   addq.w  #1,d3
    move.b  d0,(a2)
    lea next_subspr(a2),a2
+   addq.w  #1,d3
    move.b  (MainCharacter+ss_rings_units).w,(a2)
    lea next_subspr(a2),a2
    move.w  d3,d4
    subq.w  #1,d4
    move.w  #$48,d1
    tst.w   (Player_mode).w
    beq.s   +
    addi.w  #$54,d1
/   move.w  d1,(a1,d5.w)
    addi_.w #8,d1
    addq.w  #next_subspr,d5
    dbf d4,-
    cmpi.w  #1,(Player_mode).w
    beq.s   loc_7536
 
loc_74EA:
    moveq   #0,d0
    moveq   #0,d4
    move.b  (Sidekick+ss_rings_hundreds).w,d0
    beq.s   +
    addq.w  #1,d4
    move.b  d0,(a2)
    lea next_subspr(a2),a2
+   move.b  (Sidekick+ss_rings_tens).w,d0
    tst.b   d4
    bne.s   +
    tst.b   d0
    beq.s   ++
+
    addq.w  #1,d4
    move.b  d0,(a2)
    lea next_subspr(a2),a2
+   move.b  (Sidekick+ss_rings_units).w,(a2)
    addq.w  #1,d4
    add.w   d4,d3
    subq.w  #1,d4
    move.w  #$E0,d1
    tst.w   (Player_mode).w
    beq.s   +
    subi.w  #$44,d1
/   move.w  d1,(a1,d5.w)
    addi_.w #8,d1
    addq.w  #6,d5
    dbf d4,-
 
loc_7536:
    move.b  d3,mainspr_childsprites(a0)
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
 
loc_753E:
    moveq   #0,d0
    moveq   #0,d1
    moveq   #0,d2
    moveq   #1,d3
    move.b  (MainCharacter+ss_rings_units).w,d0
    add.b   (Sidekick+ss_rings_units).w,d0
    move.b  (MainCharacter+ss_rings_tens).w,d1
    add.b   (Sidekick+ss_rings_tens).w,d1
    move.b  (MainCharacter+ss_rings_hundreds).w,d2
    add.b   (Sidekick+ss_rings_hundreds).w,d2
    cmpi.b  #10,d0
    blo.s   +
    addq.w  #1,d1
    subi.b  #10,d0
+
    tst.b   d1
    beq.s   ++
    cmpi.b  #10,d1
    blo.s   +
    addi_.b #1,d2
    subi.b  #10,d1
+
    addq.w  #1,d3
    tst.b   d2
    beq.s   ++
    addq.w  #1,d3
    bra.s   ++
; ===========================================================================
+
    tst.b   d2
    beq.s   +
    addq.w  #2,d3
+
    lea sub2_x_pos(a0),a1
    move.b  d3,mainspr_childsprites(a0)
    cmpi.b  #2,d3
    blt.s   +
    beq.s   ++
    move.w  #$78,(a1)           ; sub2_x_pos
    move.b  d2,sub2_mapframe-sub2_x_pos(a1) ; sub2_mapframe
    move.w  #$80,sub3_x_pos-sub2_x_pos(a1)  ; sub3_x_pos
    move.b  d1,sub3_mapframe-sub2_x_pos(a1) ; sub3_mapframe
    move.w  #$88,sub4_x_pos-sub2_x_pos(a1)  ; sub4_x_pos
    move.b  d0,sub4_mapframe-sub2_x_pos(a1) ; sub4_mapframe
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
+
    move.w  #$80,(a1)           ; sub2_x_pos
    move.b  d0,sub2_mapframe-sub2_x_pos(a1) ; sub2_mapframe
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
+
    move.w  #$7C,(a1)           ; sub2_x_pos
    move.b  d1,sub2_mapframe-sub2_x_pos(a1) ; sub2_mapframe
    move.w  #$84,sub3_x_pos-sub2_x_pos(a1)  ; sub3_x_pos
    move.b  d0,sub3_mapframe-sub2_x_pos(a1) ; sub3_mapframe
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
; ===========================================================================
 
loc_75DE:
    move.b  (SS_2P_BCD_Score).w,d0
    bne.s   +
    rts
; ===========================================================================
+
    lea sub2_x_pos(a0),a1
    moveq   #0,d2
    move.b  d0,d1
    andi.b  #$F0,d0
    beq.s   +
    addq.w  #1,d2
    move.w  #$20,(a1)   ; sub2_x_pos
    lea next_subspr(a1),a1
    subi.b  #$10,d0
    beq.s   +
    addq.w  #1,d2
    move.w  #$30,(a1)   ; sub3_x_pos
    lea next_subspr(a1),a1
    subi.b  #$10,d0
    beq.s   +
    addq.w  #1,d2
    move.w  #$40,(a1)   ; sub4_x_pos
    bra.s   ++
; ===========================================================================
+
    andi.b  #$F,d1
    beq.s   +
    addq.w  #1,d2
    move.w  #$B8,(a1)   ; sub?_x_pos
    lea next_subspr(a1),a1
    subi_.b #1,d1
    beq.s   +
    addq.w  #1,d2
    move.w  #$C8,(a1)   ; sub?_x_pos
    lea next_subspr(a1),a1
    subi_.b #1,d1
    beq.s   +
    addq.w  #1,d2
    move.w  #$D8,(a1)   ; sub?_x_pos
+
    move.b  d2,mainspr_childsprites(a0)
    jmpto   (DisplaySprite).l, JmpTo_DisplaySprite
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_7650
SSSetGeometryOffsets:
    move.b  (SSTrack_drawing_index).w,d0                    ; Get drawing position
    cmp.b   (SS_player_anim_frame_timer).w,d0               ; Compare to player frame duration
    beq.s   +                                               ; If both are equal, branch
    rts
; ===========================================================================
+
    moveq   #0,d0
    move.b  (SSTrack_mapping_frame).w,d0                    ; Get current track mapping frame
    add.w   d0,d0                                           ; Convert to index
    lea SSCurveOffsets(pc,d0.w),a2                          ; Load current curve offsets into a2
    move.b  (a2)+,d0                                        ; Get x offset
    tst.b   (SSTrack_Orientation).w                         ; Is track flipped?
    beq.s   +                                               ; Branch if not
    neg.b   d0                                              ; Change sign of offset
+
    ext.w   d0                                              ; Extend to word
    addi.w  #$80,d0                                         ; Add 128 (why?)
    move.w  d0,(SS_Offset_X).w                              ; Set X geometry offset
    move.b  (a2),d0                                         ; Get y offset
    ext.w   d0                                              ; Extend to word
    addi.w  #$36,d0                                         ; Add $36 (why?)
    move.w  d0,(SS_Offset_Y).w                              ; Set Y geometry offset
    rts
; End of function SSSetGeometryOffsets
 
; ===========================================================================
; Position offsets to sort-of rotate the plane sonic/tails are in
; when the special stage track is curving, so they follow it better.
; Each word seems to be (x_offset, y_offset)
; See also Ani_SpecialStageTrack.
SSCurveOffsets: ; word_768A:
    dc.b $13,   0,   $13,   0,   $13,   0,   $13,   0   ; $00
    dc.b   9, -$A,     0,-$1C,     0,-$1C,     0,-$20   ; $04
    dc.b   0,-$24,     0,-$2A,     0,-$10,     0,   6   ; $08
    dc.b   0,  $E,     0, $10,     0, $12,     0, $12   ; $0C
    dc.b   9, $12                                       ; $10; upward curve
    dc.b   0,   0,     0,   0,     0,   0,     0,   0   ; $11; straight
    dc.b $13,   0,   $13,   0,   $13,   0,   $13,   0   ; $15
    dc.b  $B,  $C,     0,  $C,     0, $12,     0,  $A   ; $19
    dc.b   0,   8,     0,   2,     0, $10,     0,-$20   ; $1D
    dc.b   0,-$1F,     0,-$1E,     0,-$1B,     0,-$18   ; $21
    dc.b   0, -$E                                       ; $25; downward curve
    dc.b $13,   0,   $13,   0,   $13,   0,   $13,   0   ; $26
    dc.b $13,   0,   $13,   0                           ; $2B; turning
    dc.b $13,   0,   $13,   0,   $13,   0,   $13,   0   ; $2C
    dc.b  $B,   0                                       ; $30; exit turn
    dc.b   0,   0,     0,   0,     0,   0,     0,   0   ; $31
    dc.b   0,   0,     0,   0,     3,   0               ; $35; straight
; ===========================================================================
; Subroutine to advance to the next act and get an encoded version
; of the ring requirements.
; Output:
;   d0, d1: Binary coded decimal version of ring requirements (maximum of 299 rings)
;   d2: Number of digits in the ring requirements - 1 (minimum 2 digits)
;loc_76FA
SSStartNewAct:
    moveq   #0,d1
    moveq   #1,d2
    move.w  (Current_Special_StageAndAct).w,d0
    move.b  d0,d1
    lsr.w   #8,d0
    add.w   d0,d0
    add.w   d0,d0
    add.w   d1,d0
    tst.w   (Player_mode).w
    bne.s   +
    move.b  SpecialStage_RingReq_Team(pc,d0.w),d1
    bra.s   ++
; ===========================================================================
+
    move.b  SpecialStage_RingReq_Alone(pc,d0.w),d1
+
    move.w  d1,(SS_Ring_Requirement).w
    moveq   #0,d0
    cmpi.w  #100,d1
    blt.s   +
    addq.w  #1,d2
  ; The following code does a more complete binary coded decimal conversion:
    if 1==0
-   addi.w  #$100,d0
    subi.w  #100,d1
    cmpi.w  #100,d1
    bgt.s   -
    else
    ; This code (the original) is limited to 299 rings:
    subi.w  #100,d1
    move.w  #$100,d0
    cmpi.w  #100,d1
    blt.s   +
    subi.w  #100,d1
    addi.w  #$100,d0
    endif
+
    divu.w  #10,d1
    lsl.w   #4,d1
    or.b    d1,d0
    swap    d1
    or.b    d1,d0
    move.w  d0,d1
    addi_.w #1,(Current_Special_StageAndAct).w
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Ring requirement values for Sonic and Tails games
;
; This array stores the number of rings you need to get to complete each round
; of each special stage, while playing with both sonic and tails. 4 bytes per
; stage, corresponding to the four possible parts of the level. Last part is unused.
; ----------------------------------------------------------------------------
; Misc_7756:
SpecialStage_RingReq_Team:
    dc.b  40, 80,140,120    ; 4
    dc.b  50,100,140,150    ; 8
    dc.b  60,110,160,170    ; 12
    dc.b  40,100,150,160    ; 16
    dc.b  55,110,200,200    ; 20
    dc.b  80,140,220,220    ; 24
    dc.b 100,190,210,210    ; 28
; ----------------------------------------------------------------------------
; Ring requirement values for Sonic or Tails alone games
;
; This array stores the number of rings you need to get to complete each round
; of each special stage, while playing with either sonic or tails. 4 bytes per
; stage, corresponding to the four possible parts of the level. Last part is unused.
; ----------------------------------------------------------------------------
; Misc_7772:
SpecialStage_RingReq_Alone:
    dc.b  30, 70,130,110    ; 4
    dc.b  50,100,140,140    ; 8
    dc.b  50,110,160,160    ; 12
    dc.b  40,110,150,150    ; 16
    dc.b  50, 90,160,160    ; 20
    dc.b  80,140,210,210    ; 24
    dc.b 100,150,190,190    ; 28
 
; special stage palette table
; word_778E:
SpecialStage_Palettes:
    dc.w   PalID_SS1
    dc.w   PalID_SS2
    dc.w   PalID_SS3
    dc.w   PalID_SS4
    dc.w   PalID_SS5
    dc.w   PalID_SS6
    dc.w   PalID_SS7
    dc.w   PalID_SS1_2p
    dc.w   PalID_SS2_2p
    dc.w   PalID_SS3_2p
              
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_77A2
SSInitPalAndData:
    clr.b   (Current_Special_Act).w
    move.b  #-1,(SpecialStage_LastSegment2).w
    move.w  #0,(Ring_count).w
    move.w  #0,(Ring_count_2P).w
    move.b  #0,(Perfect_rings_flag).w
    move.b  #0,(Got_Emerald).w
    move.b  #4,(SS_Star_color_2).w
    lea (SS2p_RingBuffer).w,a2
    moveq   #0,d0
    move.w  d0,(a2)+
    move.w  d0,(a2)+
    move.w  d0,(a2)+
    move.w  d0,(a2)+
    move.w  d0,(a2)+
    move.w  d0,(a2)+
    moveq   #PalID_SS,d0
    bsr.w   PalLoad_ForFade
    lea_    SpecialStage_Palettes,a1
    moveq   #0,d0
    move.b  (Current_Special_Stage).w,d0
    add.w   d0,d0
    move.w  d0,d1
    tst.b   (SS_2p_Flag).w
    beq.s   +
    cmpi.b  #4,d0
    blo.s   +
    addi_.w #6,d0
+
    move.w  (a1,d0.w),d0
    bsr.w   PalLoad_ForFade
    lea (SSRAM_MiscKoz_SpecialObjectLocations).w,a0
    adda.w  (a0,d1.w),a0
    move.l  a0,(SS_CurrentLevelObjectLocations).w
    lea (SSRAM_MiscNem_SpecialLevelLayout).w,a0
    adda.w  (a0,d1.w),a0
    move.l  a0,(SS_CurrentLevelLayout).w
    rts
; End of function SSInitPalAndData
 
; ===========================================================================
 
 ; temporarily remap characters to title card letter format
 ; Characters are encoded as Aa, Bb, Cc, etc. through a macro
 charset 'A',0  ; can't have an embedded 0 in a string
 charset 'B',"\4\8\xC\4\x10\x14\x18\x1C\x1E\x22\x26\x2A\4\4\x30\x34\x38\x3C\x40\x44\x48\x4C\x52\x56\4"
 charset 'a',"\4\4\4\4\4\4\4\4\2\4\4\4\6\4\4\4\4\4\4\4\4\4\6\4\4"
 charset '.',"\x5A"
 
; letter lookup string
llookup := "ABCDEFGHIJKLMNOPQRSTUVWXYZ ."
 
; macro for defining title card letters in conjunction with the remapped character set
titleLetters macro letters
     ;  ". ZYXWVUTSRQPONMLKJIHGFEDCBA"
used := %0110000000000110000000010000   ; set to initial state
c := 0
    rept strlen(letters)
t := substr(letters,c,1)
    if ~~(used&1<<strstr(llookup,t))    ; has the letter been used already?
used := used|1<<strstr(llookup,t)   ; if not, mark it as used
    dc.b t          ; output letter code
    if t=="."
    dc.b 2          ; output character size
    else
    dc.b lowstring(t)   ; output letter size
    endif
    endif
c := c+1
    endm
    dc.w $FFFF  ; output string terminator
    endm
 
;word_7822:
SpecialStage_ResultsLetters:
    titleLetters    "ACDGHILMPRSTUW."
 
 charset ; revert character set
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo_LoadTitleCardSS 
    jmp (LoadTitleCardSS).l
JmpTo_DeleteObject 
    jmp (DeleteObject).l
JmpTo_Obj5A_CreateRingReqMessage 
    jmp (Obj5A_CreateRingReqMessage).l
JmpTo_Obj5A_PrintPhrase 
    jmp (Obj5A_PrintPhrase).l
; sub_7862:
JmpTo_ObjectMove 
    jmp (ObjectMove).l
JmpTo_Hud_Base 
    jmp (Hud_Base).l
 
    align 4
    endif
 
 
 
 
; ----------------------------------------------------------------------------
; Continue Screen
; ----------------------------------------------------------------------------
; loc_7870:
ContinueScreen:
    bsr.w   Pal_FadeToBlack
    move    #$2700,sr
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    bsr.w   ClearScreen
 
    clearRAM ContScr_Object_RAM,ContScr_Object_RAM_End
 
    bsr.w   ContinueScreen_LoadLetters
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_ContinueTails),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_ContinueTails).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_MiniContinue),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_MiniSonic).l,a0
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    lea (ArtNem_MiniTails).l,a0
+
    bsr.w   NemDec
    moveq   #$A,d1
    jsr (ContScrCounter).l
    moveq   #PalID_SS1,d0
    bsr.w   PalLoad_ForFade
    move.w  #0,(Target_palette).w
    move.b  #MusID_Continue,d0
    bsr.w   PlayMusic
    move.w  #$293,(Demo_Time_left).w    ; 11 seconds minus 1 frame
    clr.b   (Level_started_flag).w
    clr.l   (Camera_X_pos_copy).w
    move.l  #$1000000,(Camera_Y_pos_copy).w
    move.b  #ObjID_ContinueChars,(MainCharacter+id).w ; load ObjDB (sonic on continue screen)
    move.b  #ObjID_ContinueChars,(Sidekick+id).w ; load ObjDB (tails on continue screen)
    move.b  #6,(Sidekick+routine).w ; => ObjDB_Tails_Init
    move.b  #ObjID_ContinueText,(ContinueText+id).w ; load ObjDA (continue screen text)
    move.b  #ObjID_ContinueIcons,(ContinueIcons+id).w ; load ObjDA (continue icons)
    move.b  #4,(ContinueIcons+routine).w ; => loc_7AD0
    jsr (RunObjects).l
    jsr (BuildSprites).l
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromBlack
-
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    cmpi.b  #4,(MainCharacter+routine).w
    bhs.s   +
    move    #$2700,sr
    move.w  (Demo_Time_left).w,d1
    divu.w  #60,d1
    andi.l  #$F,d1
    jsr (ContScrCounter).l
    move    #$2300,sr
+
    jsr (RunObjects).l
    jsr (BuildSprites).l
    cmpi.w  #$180,(Sidekick+x_pos).w
    bhs.s   +
    cmpi.b  #4,(MainCharacter+routine).w
    bhs.s   -
    tst.w   (Demo_Time_left).w
    bne.w   -
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
; ---------------------------------------------------------------------------
+
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
    moveq   #0,d0
    move.w  d0,(Ring_count).w
    move.l  d0,(Timer).w
    move.l  d0,(Score).w
    move.b  d0,(Last_star_pole_hit).w
    move.w  d0,(Ring_count_2P).w
    move.l  d0,(Timer_2P).w
    move.l  d0,(Score_2P).w
    move.b  d0,(Last_star_pole_hit_2P).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    subq.b  #1,(Continue_count).w
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_7A04:
ContinueScreen_LoadLetters:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_TitleCard),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_TitleCard).l,a0
    bsr.w   NemDec
    lea (Level_Layout).w,a4
    lea (ArtNem_TitleCard2).l,a0
    bsr.w   NemDecToRAM
    lea (ContinueScreen_AdditionalLetters).l,a0
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ContinueScreen_Additional),VRAM,WRITE),(VDP_control_port).l
    lea (Level_Layout).w,a1
    lea (VDP_data_port).l,a6
-
    moveq   #0,d0
    move.b  (a0)+,d0
    bmi.s   +   ; rts
    lsl.w   #5,d0
    lea (a1,d0.w),a2
    moveq   #0,d1
    move.b  (a0)+,d1
    lsl.w   #3,d1
    subq.w  #1,d1
 
-   move.l  (a2)+,(a6)
    dbf d1,-
 
    bra.s   --
; ---------------------------------------------------------------------------
+   rts
; End of function ContinueScreen_LoadLetters
 
; ===========================================================================
 
 ; temporarily remap characters to title card letter format
 ; Characters are encoded as Aa, Bb, Cc, etc. through a macro
 charset 'A',0  ; can't have an embedded 0 in a string
 charset 'B',"\4\8\xC\4\x10\x14\x18\x1C\x1E\x22\x26\x2A\4\4\x30\x34\x38\x3C\x40\x44\x48\x4C\x52\x56\4"
 charset 'a',"\4\4\4\4\4\4\4\4\2\4\4\4\6\4\4\4\4\4\4\4\4\4\6\4\4"
 charset '.',"\x5A"
 
; Defines which letters load for the continue screen
; Each letter occurs only once, and  the letters ENOZ (i.e. ZONE) aren't loaded here
; However, this is hidden by the titleLetters macro, and normal titles can be used
; (the macro is defined near SpecialStage_ResultsLetters, which uses it before here)
 
; word_7A5E:
ContinueScreen_AdditionalLetters:
    titleLetters "CONTINUE"
 
 charset ; revert character set
; ===========================================================================
; ----------------------------------------------------------------------------
; Object DA - Continue text
; ----------------------------------------------------------------------------
; loc_7A68:
ObjDA: ; (screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjDA_Index(pc,d0.w),d1
    jmp ObjDA_Index(pc,d1.w)
; ===========================================================================
; Obj_DA_subtbl:
ObjDA_Index:    offsetTable
        offsetTableEntry.w ObjDA_Init       ; 0
        offsetTableEntry.w JmpTo2_DisplaySprite ; 2
        offsetTableEntry.w loc_7AD0     ; 4
        offsetTableEntry.w loc_7B46     ; 6
; ===========================================================================
; loc_7A7E:
ObjDA_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjDA_MapUnc_7CB6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_ContinueText,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo_Adjust2PArtPointer
    move.b  #0,render_flags(a0)
    move.b  #$3C,width_pixels(a0)
    move.w  #$120,x_pixel(a0)
    move.w  #$C0,y_pixel(a0)
 
JmpTo2_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
; word_7AB2:
ObjDA_XPositions:
    dc.w  $116, $12A, $102, $13E,  $EE, $152,  $DA, $166
    dc.w   $C6, $17A,  $B2, $18E,  $9E, $1A2,  $8A; 8
; ===========================================================================
 
loc_7AD0:
    movea.l a0,a1
    lea_    ObjDA_XPositions,a2
    moveq   #0,d1
    move.b  (Continue_count).w,d1
    subq.b  #2,d1
    bcc.s   +
    jmp (DeleteObject).l
; ===========================================================================
+
    moveq   #1,d3
    cmpi.b  #$E,d1
    blo.s   +
    moveq   #0,d3
    moveq   #$E,d1
+
    move.b  d1,d2
    andi.b  #1,d2
 
-   _move.b #ObjID_ContinueIcons,id(a1) ; load objDA
    move.w  (a2)+,x_pixel(a1)
    tst.b   d2
    beq.s   +
    subi.w  #$A,x_pixel(a1)
+
    move.w  #$D0,y_pixel(a1)
    move.b  #4,mapping_frame(a1)
    move.b  #6,routine(a1)
    move.l  #ObjDA_MapUnc_7CB6,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_ContinueText_2,0,1),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo_Adjust2PArtPointer2
    move.b  #0,render_flags(a1)
    lea next_object(a1),a1 ; load obj addr
    dbf d1,-
 
    lea -next_object(a1),a1 ; load obj addr
    move.b  d3,subtype(a1)
 
loc_7B46:
    tst.b   subtype(a0)
    beq.s   +
    cmpi.b  #4,(MainCharacter+routine).w
    blo.s   +
    move.b  (Vint_runcount+3).w,d0
    andi.b  #1,d0
    bne.s   +
    tst.w   (MainCharacter+x_vel).w
    bne.s   JmpTo2_DeleteObject
    rts
; ===========================================================================
+
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$F,d0
    bne.s   JmpTo3_DisplaySprite
    bchg    #0,mapping_frame(a0)
 
JmpTo3_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo2_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; ----------------------------------------------------------------------------
; Object DB - Sonic lying down or Tails nagging (on the continue screen)
; ----------------------------------------------------------------------------
; Sprite_7B82:
ObjDB:
    ; a0=character
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjDB_Index(pc,d0.w),d1
    jsr ObjDB_Index(pc,d1.w)
    jmp (DisplaySprite).l
; ===========================================================================
; off_7B96: ObjDB_States:
ObjDB_Index:    offsetTable
        offsetTableEntry.w ObjDB_Sonic_Init ;  0
        offsetTableEntry.w ObjDB_Sonic_Wait ;  2
        offsetTableEntry.w ObjDB_Sonic_Run  ;  4
        offsetTableEntry.w ObjDB_Tails_Init ;  6
        offsetTableEntry.w ObjDB_Tails_Wait ;  8
        offsetTableEntry.w ObjDB_Tails_Run  ; $A
; ===========================================================================
; loc_7BA2:
ObjDB_Sonic_Init:
    addq.b  #2,routine(a0) ; => ObjDB_Sonic_Wait
    move.w  #$9C,x_pos(a0)
    move.w  #$19C,y_pos(a0)
    move.l  #Mapunc_Sonic,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtUnc_Sonic,0,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #2,priority(a0)
    move.b  #$20,anim(a0)
 
; loc_7BD2:
ObjDB_Sonic_Wait:
    tst.b   (Ctrl_1_Press).w    ; is start pressed?
    bmi.s   ObjDB_Sonic_StartRunning ; if yes, branch
    jsr (Sonic_Animate).l
    jmp (LoadSonicDynPLC).l
; ---------------------------------------------------------------------------
; loc_7BE4:
ObjDB_Sonic_StartRunning:
    addq.b  #2,routine(a0) ; => ObjDB_Sonic_Run
    move.b  #$21,anim(a0)
    clr.w   inertia(a0)
    move.b  #SndID_SpindashRev,d0 ; super peel-out sound
    bsr.w   PlaySound
 
; loc_7BFA:
ObjDB_Sonic_Run:
    cmpi.w  #$800,inertia(a0)
    bne.s   +
    move.w  #$1000,x_vel(a0)
    bra.s   ++
; ---------------------------------------------------------------------------
+
    addi.w  #$20,inertia(a0)
+
    jsr (ObjectMove).l
    jsr (Sonic_Animate).l
    jmp (LoadSonicDynPLC).l
; ===========================================================================
; loc_7C22:
ObjDB_Tails_Init:
    addq.b  #2,routine(a0) ; => ObjDB_Tails_Wait
    move.w  #$B8,x_pos(a0)
    move.w  #$1A0,y_pos(a0)
    move.l  #ObjDA_MapUnc_7CB6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_ContinueTails,0,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #2,priority(a0)
    move.b  #0,anim(a0)
 
; loc_7C52:
ObjDB_Tails_Wait:
    tst.b   (Ctrl_1_Press).w    ; is start pressed?
    bmi.s   ObjDB_Tails_StartRunning ; if yes, branch
    lea (Ani_objDB).l,a1
    jmp (AnimateSprite).l
; ---------------------------------------------------------------------------
; loc_7C64:
ObjDB_Tails_StartRunning:
    addq.b  #2,routine(a0) ; => ObjDB_Tails_Run
    move.l  #MapUnc_Tails,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtUnc_Tails,0,0),art_tile(a0)
    move.b  #0,anim(a0)
    clr.w   inertia(a0)
    move.b  #SndID_SpindashRev,d0 ; super peel-out sound
    bsr.w   PlaySound
 
; loc_7C88:
ObjDB_Tails_Run:
    cmpi.w  #$720,inertia(a0)
    bne.s   +
    move.w  #$1000,x_vel(a0)
    bra.s   ++
; ---------------------------------------------------------------------------
+
    addi.w  #$18,inertia(a0)
+
    jsr (ObjectMove).l
    jsr (Tails_Animate).l
    jmp (LoadTailsDynPLC).l
; ===========================================================================
; animation script for continue screen Tails nagging
; off_7CB0
Ani_objDB:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   9,  2,  3,$FF
    even
; -------------------------------------------------------------------------------
; Sprite mappings for text, countdown, stars, and Tails on the continue screen
; Art starts at $A000 in VRAM
; -------------------------------------------------------------------------------
ObjDA_MapUnc_7CB6:  BINCLUDE    "mappings/sprite/objDA.bin"
 
    if ~~removeJmpTos
JmpTo_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; loc_7D50:
TwoPlayerResults:
    bsr.w   Pal_FadeToBlack
    move    #$2700,sr
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   ClearScreen
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8200|(VRAM_Menu_Plane_A_Name_Table/$400),(a6) ; PNT A base: $C000
    move.w  #$8400|(VRAM_Menu_Plane_B_Name_Table/$2000),(a6)    ; PNT B base: $E000
    move.w  #$8200|(VRAM_Menu_Plane_A_Name_Table/$400),(a6) ; PNT A base: $C000
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
 
    clearRAM Sprite_Table_Input,Sprite_Table_Input_End
    clearRAM VSRslts_Object_RAM,VSRslts_Object_RAM_End
 
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_FontStuff),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_FontStuff).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_1P2PWins),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_1P2PWins).l,a0
    bsr.w   NemDec
    lea (Chunk_Table).l,a1
    lea (MapEng_MenuBack).l,a0
    move.w  #make_art_tile(ArtTile_VRAM_Start,3,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_Plane_B_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
    move.w  (Results_Screen_2P).w,d0
    add.w   d0,d0
    add.w   d0,d0
    add.w   d0,d0
    lea TwoPlayerResultsPointers(pc),a2
    movea.l (a2,d0.w),a0
    movea.l 4(a2,d0.w),a2
    lea (Chunk_Table).l,a1
    move.w  #make_art_tile(ArtTile_VRAM_Start,0,0),d0
    bsr.w   EniDec
    jsr (a2)    ; dynamic call! to Setup2PResults_Act, Setup2PResults_Zone, Setup2PResults_Game, Setup2PResults_SpecialAct, or Setup2PResults_SpecialZone, assuming the pointers in TwoPlayerResultsPointers have not been changed
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(tiles_to_bytes(ArtTile_TwoPlayerResults),VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, PlaneMapToVRAM_H40
    clr.w   (VDP_Command_Buffer).w
    move.l  #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w
    clr.b   (Level_started_flag).w
    clr.w   (Anim_Counters).w
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo_Dynamic_Normal
    moveq   #PLCID_Std1,d0
    bsr.w   LoadPLC2
    moveq   #PalID_Menu,d0
    bsr.w   PalLoad_ForFade
    moveq   #0,d0
    move.b  #MusID_2PResult,d0
    cmp.w   (Level_Music).w,d0
    beq.s   +
    move.w  d0,(Level_Music).w
    bsr.w   PlayMusic
+
    move.w  #$707,(Demo_Time_left).w
    clr.w   (Two_player_mode).w
    clr.l   (Camera_X_pos).w
    clr.l   (Camera_Y_pos).w
    clr.l   (Vscroll_Factor).w
    clr.l   (Vscroll_Factor_P2).w
    clr.l   (Vscroll_Factor_P2_HInt).w
    move.b  #ObjID_HUD,(VSResults_HUD+id).w
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromBlack
 
-   move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo_Dynamic_Normal
    jsr (RunObjects).l
    jsr (BuildSprites).l
    bsr.w   RunPLC_RAM
    tst.l   (Plc_Buffer).w
    bne.s   -
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0
    beq.s   -           ; stay on that screen until either player presses start
 
    move.w  (Results_Screen_2P).w,d0 ; were we at the act results screen? (VsRSID_Act)
    bne.w   TwoPlayerResultsDone_Zone ; if not, branch
    tst.b   (Current_Act).w     ; did we just finish act 1?
    bne.s   +           ; if not, branch
    addq.b  #1,(Current_Act).w  ; go to the next act
    move.b  #1,(Current_Act_2P).w
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    move.b  #0,(Last_star_pole_hit).w
    move.b  #0,(Last_star_pole_hit_2P).w
    moveq   #1,d0
    move.w  d0,(Two_player_mode).w
    move.w  d0,(Two_player_mode_copy).w
    moveq   #0,d0
    move.l  d0,(Score).w
    move.l  d0,(Score_2P).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    rts
; ===========================================================================
+   ; Displays results for the zone
    move.b  #2,(Current_Act_2P).w
    bsr.w   sub_84A4
    lea (SS_Total_Won).w,a4
    clr.w   (a4)
    bsr.s   sub_7F9A
    bsr.s   sub_7F9A
    move.b  (a4),d1
    sub.b   1(a4),d1
    beq.s   +       ; if there's a tie, branch
    move.w  #VsRSID_Zone,(Results_Screen_2P).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    rts
; ===========================================================================
+   ; There's a tie, play a special stage
    move.b  (Current_Zone_2P).w,d0
    addq.b  #1,d0
    move.b  d0,(Current_Special_Stage).w
    move.w  #VsRSID_SS,(Results_Screen_2P).w
    move.b  #1,(SpecialStage_flag_2P).w
    move.b  #GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
    moveq   #1,d0
    move.w  d0,(Two_player_mode).w
    move.w  d0,(Two_player_mode_copy).w
    move.b  #0,(Last_star_pole_hit).w
    move.b  #0,(Last_star_pole_hit_2P).w
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_7F9A:
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    beq.s   ++
    bcs.s   +
    addq.b  #1,(a4)
    bra.s   ++
; ===========================================================================
+
    addq.b  #1,1(a4)
+
    addq.w  #2,a5
    rts
; End of function sub_7F9A
 
; ===========================================================================
 
; loc_7FB2:
TwoPlayerResultsDone_Zone:
    subq.w  #1,d0           ; were we at the zone results screen? (VsRSID_Zone)
    bne.s   TwoPlayerResultsDone_Game ; if not, branch
 
; loc_7FB6:
TwoPlayerResultsDone_ZoneOrSpecialStages:
    lea (Results_Data_2P).w,a4
    moveq   #0,d0
    moveq   #0,d1
    rept 3
    move.w  (a4)+,d0
    add.l   d0,d1
    move.w  (a4)+,d0
    add.l   d0,d1
    addq.w  #2,a4
    endm
    move.w  (a4)+,d0
    add.l   d0,d1
    move.w  (a4)+,d0
    add.l   d0,d1
    swap    d1
    tst.w   d1  ; have all levels been completed?
    bne.s   +   ; if not, branch
    move.w  #VsRSID_Game,(Results_Screen_2P).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    rts
; ===========================================================================
+
    tst.w   (Game_Over_2P).w
    beq.s   +       ; if there's a Game Over, clear the results
    lea (Results_Data_2P).w,a1
 
    moveq   #bytesToWcnt(Results_Data_2P_End-Results_Data_2P),d0
-   move.w  #-1,(a1)+
    dbf d0,-
 
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
+
    move.b  #GameModeID_2PLevelSelect,(Game_Mode).w ; => LevelSelectMenu2P
    rts
; ===========================================================================
; loc_8020:
TwoPlayerResultsDone_Game:
    subq.w  #1,d0   ; were we at the game results screen? (VsRSID_Game)
    bne.s   TwoPlayerResultsDone_SpecialStage ; if not, branch
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
; ===========================================================================
; loc_802C:
TwoPlayerResultsDone_SpecialStage:
    subq.w  #1,d0           ; were we at the special stage results screen? (VsRSID_SS)
    bne.w   TwoPlayerResultsDone_SpecialStages ; if not, branch
    cmpi.b  #3,(Current_Zone_2P).w  ; do we come from the special stage "zone"?
    beq.s   +           ; if yes, branch
    move.w  #VsRSID_Zone,(Results_Screen_2P).w ; show zone results after tiebreaker special stage
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    rts
; ===========================================================================
+
    tst.b   (Current_Act_2P).w
    beq.s   +
    cmpi.b  #2,(Current_Act_2P).w
    beq.s   loc_80AC
    bsr.w   sub_84A4
    lea (SS_Total_Won).w,a4
    clr.w   (a4)
    bsr.s   sub_8094
    bsr.s   sub_8094
    move.b  (a4),d1
    sub.b   1(a4),d1
    bne.s   loc_80AC
+
    addq.b  #1,(Current_Act_2P).w
    addq.b  #1,(Current_Special_Stage).w
    move.w  #VsRSID_SS,(Results_Screen_2P).w
    move.b  #1,(SpecialStage_flag_2P).w
    move.b  #GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
    move.w  #1,(Two_player_mode).w
    move.w  #0,(Level_Music).w
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_8094:
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    beq.s   ++
    bcs.s   +
    addq.b  #1,(a4)
    bra.s   ++
; ===========================================================================
+
    addq.b  #1,1(a4)
+
    addq.w  #2,a5
    rts
; End of function sub_8094
 
; ===========================================================================
 
loc_80AC:
    move.w  #VsRSID_SSZone,(Results_Screen_2P).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    rts
; ===========================================================================
; loc_80BA: BranchTo_loc_7FB6:
TwoPlayerResultsDone_SpecialStages:
    ; we were at the special stages results screen (VsRSID_SSZone)
    bra.w   TwoPlayerResultsDone_ZoneOrSpecialStages
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 21 - Score/Rings/Time display (in 2P results)
; ----------------------------------------------------------------------------
; Sprite_80BE:
Obj21: ; (screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj21_Index(pc,d0.w),d1
    jmp Obj21_Index(pc,d1.w)
; ===========================================================================
; JmpTbl_80CC: Obj21_States:
Obj21_Index:    offsetTable
        offsetTableEntry.w Obj21_Init   ; 0
        offsetTableEntry.w Obj21_Main   ; 2
; ---------------------------------------------------------------------------
; word_80D0:
Obj21_PositionTable:
    ;      x,    y
    dc.w $F0, $148
    dc.w $F0, $130
    dc.w $E0, $148
    dc.w $F0, $148
    dc.w $F0, $148
; ===========================================================================
; loc_80E4:
Obj21_Init:
    addq.b  #2,routine(a0) ; => Obj21_Main
    move.w  (Results_Screen_2P).w,d0
    add.w   d0,d0
    add.w   d0,d0
    move.l  Obj21_PositionTable(pc,d0.w),x_pixel(a0) ; and y_pixel(a0)
    move.l  #Obj21_MapUnc_8146,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_1P2PWins,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo2_Adjust2PArtPointer
    move.b  #0,render_flags(a0)
    move.b  #0,priority(a0)
    moveq   #2,d1
    move.b  (SS_Total_Won).w,d0 ; d0 = SS_Total_Won_1P
    sub.b   (SS_Total_Won+1).w,d0   ;    - SS_Total_Won_2P
    beq.s   ++
    bcs.s   +
    moveq   #0,d1
    bra.s   ++
; ---------------------------------------------------------------------------
+
    moveq   #1,d1
+
    move.b  d1,mapping_frame(a0)
 
; loc_812C:
Obj21_Main:
    andi.w  #tile_mask,art_tile(a0)
    btst    #3,(Vint_runcount+3).w
    beq.s   JmpTo4_DisplaySprite
    ori.w   #palette_line_1,art_tile(a0)
 
JmpTo4_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
; --------------------------------------------------------------------------
; sprite mappings
; --------------------------------------------------------------------------
Obj21_MapUnc_8146:  BINCLUDE "mappings/sprite/obj21.bin"
; ===========================================================================
 
; loc_819A:
Setup2PResults_Act:
    move.w  #$1F2,d2
    moveq   #0,d0
    bsr.w   sub_8672
    move.w  #$216,d2
    moveq   #0,d1
    move.b  (Current_Act_2P).w,d1
    addq.b  #1,d1
    bsr.w   sub_86B0
    move.w  #$33E,d2
    move.l  (Score).w,d1
    bsr.w   sub_86F6
    move.w  #$352,d2
    move.l  (Score_2P).w,d1
    bsr.w   sub_86F6
    move.w  #$3DA,d2
    moveq   #0,d0
    move.w  (Timer_minute_word).w,d1
    bsr.w   sub_86B0
    move.w  #$3E0,d2
    moveq   #0,d1
    move.b  (Timer_second).w,d1
    bsr.w   sub_86B0
    move.w  #$3E6,d2
    moveq   #0,d1
    move.b  (Timer_frame).w,d1
    mulu.w  #$1B0,d1
    lsr.l   #8,d1
    bsr.w   sub_86B0
    move.w  #$3EE,d2
    moveq   #0,d0
    move.w  (Timer_minute_word_2P).w,d1
    bsr.w   sub_86B0
    move.w  #$3F4,d2
    moveq   #0,d1
    move.b  (Timer_second_2P).w,d1
    bsr.w   sub_86B0
    move.w  #$3FA,d2
    moveq   #0,d1
    move.b  (Timer_centisecond_2P).w,d1
    mulu.w  #$1B0,d1
    lsr.l   #8,d1
    bsr.w   sub_86B0
    move.w  #$486,d2
    moveq   #0,d0
    move.w  (Ring_count).w,d1
    bsr.w   sub_86B0
    move.w  #$49A,d2
    move.w  (Ring_count_2P).w,d1
    bsr.w   sub_86B0
    move.w  #$526,d2
    moveq   #0,d0
    move.w  (Rings_Collected).w,d1
    bsr.w   sub_86B0
    move.w  #$53A,d2
    move.w  (Rings_Collected_2P).w,d1
    bsr.w   sub_86B0
    move.w  #$5C6,d2
    moveq   #0,d0
    move.w  (Monitors_Broken).w,d1
    bsr.w   sub_86B0
    move.w  #$5DA,d2
    move.w  (Monitors_Broken_2P).w,d1
    bsr.w   sub_86B0
    bsr.w   sub_8476
    move.w  #$364,d2
    move.w  #$6000,d0
    move.l  (Score).w,d1
    sub.l   (Score_2P).w,d1
    bsr.w   sub_8652
    move.w  #$404,d2
    move.l  (Timer_2P).w,d1
    sub.l   (Timer).w,d1
    bsr.w   sub_8652
    move.w  #$4A4,d2
    moveq   #0,d1
    move.w  (Ring_count).w,d1
    sub.w   (Ring_count_2P).w,d1
    bsr.w   sub_8652
    move.w  #$544,d2
    moveq   #0,d1
    move.w  (Rings_Collected).w,d1
    sub.w   (Rings_Collected_2P).w,d1
    bsr.w   sub_8652
    move.w  #$5E4,d2
    moveq   #0,d1
    move.w  (Monitors_Broken).w,d1
    sub.w   (Monitors_Broken_2P).w,d1
    bsr.w   sub_8652
    move.w  #$706,d2
    moveq   #0,d0
    moveq   #0,d1
    move.b  (a4),d1
    bsr.w   sub_86B0
    move.w  #$70E,d2
    moveq   #0,d1
    move.b  1(a4),d1
    bsr.w   sub_86B0
    move.w  (a4),(SS_Total_Won).w
    rts
; ===========================================================================
; loc_82FA:
Setup2PResults_Zone:
    move.w  #$242,d2
    moveq   #0,d0
    bsr.w   sub_8672
    bsr.w   sub_84A4
    lea (SS_Total_Won).w,a4
    clr.w   (a4)
    move.w  #$398,d6
    bsr.w   sub_854A
    move.w  #$488,d6
    bsr.w   sub_854A
    move.w  #$618,d6
    bsr.w   sub_854A
    rts
; ===========================================================================
; loc_8328:
Setup2PResults_Game:
    lea (Results_Data_2P).w,a5
    lea (SS_Total_Won).w,a4
    clr.w   (a4)
    move.w  #$208,d6
    bsr.w   sub_84C4
    move.w  #$258,d6
    bsr.w   sub_84C4
    move.w  #$2A8,d6
    bsr.w   sub_84C4
    move.w  #$348,d6
    bsr.w   sub_84C4
    move.w  #$398,d6
    bsr.w   sub_84C4
    move.w  #$3E8,d6
    bsr.w   sub_84C4
    move.w  #$488,d6
    bsr.w   sub_84C4
    move.w  #$4D8,d6
    bsr.w   sub_84C4
    move.w  #$528,d6
    bsr.w   sub_84C4
    move.w  #$5C8,d6
    bsr.w   sub_84C4
    move.w  #$618,d6
    bsr.w   sub_84C4
    move.w  #$668,d6
    bsr.w   sub_84C4
    move.w  #$70A,d2
    moveq   #0,d0
    moveq   #0,d1
    move.b  (a4),d1
    bsr.w   sub_86B0
    move.w  #$710,d2
    moveq   #0,d1
    move.b  1(a4),d1
    bsr.w   sub_86B0
    rts
; ===========================================================================
; loc_83B0:
Setup2PResults_SpecialAct:
    move.w  #$266,d2
    moveq   #0,d1
    move.b  (Current_Act_2P).w,d1
    addq.b  #1,d1
    bsr.w   sub_86B0
    move.w  #$4D6,d2
    moveq   #0,d0
    move.w  (SS2p_RingBuffer).w,d1      ; P1 SS act 1 rings
    bsr.w   sub_86B0
    move.w  #$4E6,d2
    move.w  (SS2p_RingBuffer+2).w,d1    ; P2 SS act 1 rings
    bsr.w   sub_86B0
    move.w  #$576,d2
    moveq   #0,d0
    move.w  (SS2p_RingBuffer+4).w,d1    ; P1 SS act 2 rings
    bsr.w   sub_86B0
    move.w  #$586,d2
    move.w  (SS2p_RingBuffer+6).w,d1    ; P2 SS act 2 rings
    bsr.w   sub_86B0
    move.w  #$616,d2
    moveq   #0,d0
    move.w  (SS2p_RingBuffer+8).w,d1    ; P1 SS act 3 rings
    bsr.w   sub_86B0
    move.w  #$626,d2
    move.w  (SS2p_RingBuffer+$A).w,d1   ; P2 SS act 3 rings
    bsr.w   sub_86B0
    bsr.w   sub_8476
    move.w  #$6000,d0
    move.w  #$4F0,d2
    moveq   #0,d1
    move.w  (SS2p_RingBuffer).w,d1      ; P1 SS act 1 rings
    sub.w   (SS2p_RingBuffer+2).w,d1    ; P2 SS act 1 rings
    bsr.w   sub_8652
    move.w  #$590,d2
    moveq   #0,d1
    move.w  (SS2p_RingBuffer+4).w,d1    ; P1 SS act 2 rings
    sub.w   (SS2p_RingBuffer+6).w,d1    ; P2 SS act 2 rings
    bsr.w   sub_8652
    move.w  #$630,d2
    moveq   #0,d1
    move.w  (SS2p_RingBuffer+8).w,d1    ; P1 SS act 3 rings
    sub.w   (SS2p_RingBuffer+$A).w,d1   ; P2 SS act 3 rings
    bsr.w   sub_8652
    move.w  (a4),(SS_Total_Won).w
    rts
; ===========================================================================
; loc_8452:
Setup2PResults_SpecialZone:
    bsr.w   sub_84A4
    lea (SS_Total_Won).w,a4
    clr.w   (a4)
    move.w  #$4D4,d6
    bsr.w   sub_85CE
    move.w  #$574,d6
    bsr.w   sub_85CE
    move.w  #$614,d6
    bsr.w   sub_85CE
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_8476:
    lea (EHZ_Results_2P).w,a4
    move.b  (Current_Zone_2P).w,d0
    beq.s   +
    lea (MCZ_Results_2P).w,a4
    subq.b  #1,d0
    beq.s   +
    lea (CNZ_Results_2P).w,a4
    subq.b  #1,d0
    beq.s   +
    lea (SS_Results_2P).w,a4
+
    moveq   #0,d0
    move.b  (Current_Act_2P).w,d0
    add.w   d0,d0
    lea (a4,d0.w),a4
    clr.w   (a4)
    rts
; End of function sub_8476
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_84A4:
    lea (EHZ_Results_2P).w,a5
    move.b  (Current_Zone_2P).w,d0
    beq.s   +   ; rts
    lea (MCZ_Results_2P).w,a5
    subq.b  #1,d0
    beq.s   +   ; rts
    lea (CNZ_Results_2P).w,a5
    subq.b  #1,d0
    beq.s   +   ; rts
    lea (SS_Results_2P).w,a5
+
    rts
; End of function sub_84A4
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_84C4:
    move.w  (a5),d0
    bmi.s   +
    move.w  d6,d2
    moveq   #0,d0
    moveq   #0,d1
    move.b  (a5),d1
    bsr.w   sub_86B0
    addq.w  #8,d6
    move.w  d6,d2
    moveq   #0,d1
    move.b  1(a5),d1
    bsr.w   sub_86B0
    addi.w  #$12,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; ===========================================================================
+
    addq.w  #4,d6
    not.w   d0
    bne.s   +
    lea (Text2P_NoGame).l,a1
    move.w  d6,d2
    bsr.w   loc_8698
    addi.w  #$16,d6
    move.w  d6,d2
    lea (Text2P_Blank).l,a1
    bsr.w   loc_8698
    addq.w  #2,a5
    rts
; ===========================================================================
+
    moveq   #0,d0
    lea (Text2P_GameOver).l,a1
    move.w  d6,d2
    bsr.w   loc_8698
    addi.w  #$16,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; End of function sub_84C4
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_854A:
    move.w  (a5),d0
    bmi.s   loc_8582
    move.w  d6,d2
    moveq   #0,d0
    moveq   #0,d1
    move.b  (a5),d1
    bsr.w   sub_86B0
    addq.w  #8,d6
    move.w  d6,d2
    moveq   #0,d1
    move.b  1(a5),d1
    bsr.w   sub_86B0
    addi.w  #$C,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; ===========================================================================
 
loc_8582:
    not.w   d0
    bne.s   loc_85A6
    lea (Text2P_NoGame).l,a1
    move.w  d6,d2
    bsr.w   loc_8698
    addi.w  #$14,d6
    move.w  d6,d2
    lea (Text2P_Blank).l,a1
    bsr.w   loc_8698
    addq.w  #2,a5
    rts
; ===========================================================================
 
loc_85A6:
    moveq   #0,d0
    lea (Text2P_GameOver).l,a1
    move.w  d6,d2
    bsr.w   loc_8698
    addi.w  #$14,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; End of function sub_854A
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_85CE:
    move.w  (a5),d0
    bmi.s   +
    move.w  d6,d2
    moveq   #0,d0
    moveq   #0,d1
    move.b  (a5),d1
    bsr.w   sub_86B0
    addi.w  #$C,d6
    move.w  d6,d2
    moveq   #0,d1
    move.b  1(a5),d1
    bsr.w   sub_86B0
    addi.w  #$10,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; ===========================================================================
+
    not.w   d0
    bne.s   loc_862C
    lea (Text2P_NoGame).l,a1
    move.w  d6,d2
    addq.w  #4,d2
    bsr.w   loc_8698
    addi.w  #$14,d6
    move.w  d6,d2
    lea (Text2P_Blank).l,a1
    bsr.s   loc_8698
    addq.w  #2,a5
    rts
; ===========================================================================
 
loc_862C:
    moveq   #0,d0
    lea (Text2P_GameOver).l,a1
    move.w  d6,d2
    bsr.s   loc_8698
    addi.w  #$14,d6
    move.w  d6,d2
    move.w  #$6000,d0
    moveq   #0,d1
    move.b  (a5),d1
    sub.b   1(a5),d1
    bsr.w   sub_8652
    addq.w  #2,a5
    rts
; End of function sub_85CE
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_8652:
    lea (Text2P_Tied).l,a1
    beq.s   ++
    bcs.s   +
    lea (Text2P_1P).l,a1
    addq.b  #1,(a4)
    bra.s   ++
; ===========================================================================
+
    lea (Text2P_2P).l,a1
    addq.b  #1,1(a4)
+
    bra.s   loc_8698
; End of function sub_8652
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_8672:
    lea (Text2P_EmeraldHill).l,a1
    move.b  (Current_Zone_2P).w,d1
    beq.s   loc_8698
    lea (Text2P_MysticCave).l,a1
    subq.b  #1,d1
    beq.s   loc_8698
    lea (Text2P_CasinoNight).l,a1
    subq.b  #1,d1
    beq.s   loc_8698
    lea (Text2P_SpecialStage).l,a1
 
loc_8698:
    lea (Chunk_Table).l,a2
    lea (a2,d2.w),a2
    moveq   #0,d1
 
    move.b  (a1)+,d1
-   move.b  (a1)+,d0
    move.w  d0,(a2)+
    dbf d1,-
 
    rts
; End of function sub_8672
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_86B0:
    lea (Chunk_Table).l,a2
    lea (a2,d2.w),a2
    lea (word_86F0).l,a3
    moveq   #0,d2
 
    moveq   #2,d5
-   moveq   #0,d3
    move.w  (a3)+,d4
 
-   sub.w   d4,d1
    bcs.s   +
    addq.w  #1,d3
    bra.s   -
; ---------------------------------------------------------------------------
+
    add.w   d4,d1
    tst.w   d5
    beq.s   ++
    tst.w   d3
    beq.s   +
    moveq   #1,d2
+
    tst.w   d2
    beq.s   ++
+
    addi.b  #$10,d3
    move.b  d3,d0
    move.w  d0,(a2)
+
    addq.w  #2,a2
    dbf d5,--
 
    rts
; End of function sub_86B0
 
; ===========================================================================
word_86F0:
    dc.w   100
    dc.w    10  ; 1
    dc.w     1  ; 2
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_86F6:
    lea (Chunk_Table).l,a2
    lea (a2,d2.w),a2
    lea (dword_8732).l,a3
    moveq   #0,d2
 
    moveq   #5,d5
-   moveq   #0,d3
    move.l  (a3)+,d4
 
-   sub.l   d4,d1
    bcs.s   +
    addq.w  #1,d3
    bra.s   -
; ===========================================================================
+
    add.l   d4,d1
    tst.w   d3
    beq.s   +
    moveq   #1,d2
+
    tst.w   d2
    beq.s   +
    addi.b  #$10,d3
    move.b  d3,d0
    move.w  d0,(a2)
+
    addq.w  #2,a2
    dbf d5,--
 
    rts
; End of function sub_86F6
 
; ===========================================================================
dword_8732:
    dc.l 100000
    dc.l  10000
    dc.l   1000
    dc.l    100
    dc.l     10
    dc.l      1
 
    ; set the character set for menu text
    charset '@',"\27\30\31\32\33\34\35\36\37\38\39\40\41\42\43\44\45\46\47\48\49\50\51\52\53\54\55"
    charset '0',"\16\17\18\19\20\21\22\23\24\25"
    charset '*',$1A
    charset ':',$1C
    charset '.',$1D
    charset ' ',0
 
    ; Menu text
menutxt macro   text
    dc.b    strlen(text)-1
    dc.b    text
    endm
Text2P_EmeraldHill: menutxt "EMERALD HILL"  ; byte_874A:
    rev02even
Text2P_MysticCave:  menutxt " MYSTIC CAVE"  ; byte_8757:
    rev02even
Text2P_CasinoNight: menutxt "CASINO NIGHT"  ; byte_8764:
    rev02even
Text2P_SpecialStage:    menutxt "SPECIAL STAGE" ; byte_8771:
    rev02even
Text2P_Special:     menutxt "   SPECIAL  "  ; byte_877F:
    rev02even
Text2P_Zone:        menutxt "ZONE "     ; byte_878C:
    rev02even
Text2P_Stage:       menutxt "STAGE"     ; byte_8792:
    rev02even
Text2P_GameOver:    menutxt "GAME OVER" ; byte_8798:
    rev02even
Text2P_TimeOver:    menutxt "TIME OVER"
    rev02even
Text2P_NoGame:      menutxt "NO GAME"   ; byte_87AC:
    rev02even
Text2P_Tied:        menutxt "TIED"      ; byte_87B4:
    rev02even
Text2P_1P:      menutxt " 1P"       ; byte_87B9:
    rev02even
Text2P_2P:      menutxt " 2P"       ; byte_87BD:
    rev02even
Text2P_Blank:       menutxt "    "      ; byte_87C1:
    rev02even
 
    charset ; reset character set
 
; ------------------------------------------------------------------------
; MENU ANIMATION SCRIPT
; ------------------------------------------------------------------------
;word_87C6:
Anim_SonicMilesBG:  zoneanimstart
    ; Sonic/Miles animated background
    zoneanimdecl  -1, ArtUnc_MenuBack,    1,  6, $A
    dc.b   0,$C7
    dc.b  $A,  5
    dc.b $14,  5
    dc.b $1E,$C7
    dc.b $14,  5
    dc.b  $A,  5
    even
 
    zoneanimend
 
; off_87DC:
TwoPlayerResultsPointers:
VsResultsScreen_Act:    dc.l Map_2PActResults, Setup2PResults_Act
VsResultsScreen_Zone:   dc.l Map_2PZoneResults, Setup2PResults_Zone
VsResultsScreen_Game:   dc.l Map_2PGameResults, Setup2PResults_Game
VsResultsScreen_SS: dc.l Map_2PSpecialStageActResults, Setup2PResults_SpecialAct
VsResultsScreen_SSZone: dc.l Map_2PSpecialStageZoneResults, Setup2PResults_SpecialZone
 
; 2P single act results screen (enigma compressed)
; byte_8804:
Map_2PActResults:   BINCLUDE "mappings/misc/2P Act Results.bin"
 
; 2P zone results screen (enigma compressed)
; byte_88CE:
Map_2PZoneResults:  BINCLUDE "mappings/misc/2P Zone Results.bin"
 
; 2P game results screen (after all 4 zones) (enigma compressed)
; byte_8960:
Map_2PGameResults:  BINCLUDE "mappings/misc/2P Game Results.bin"
 
; 2P special stage act results screen (enigma compressed)
; byte_8AA4:
Map_2PSpecialStageActResults:   BINCLUDE "mappings/misc/2P Special Stage Act Results.bin"
 
; 2P special stage zone results screen (enigma compressed)
; byte_8B30:
Map_2PSpecialStageZoneResults:  BINCLUDE "mappings/misc/2P Special Stage Zone Results.bin"
 
    even
 
    if ~~removeJmpTos
JmpTo2_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_Dynamic_Normal 
    jmp (Dynamic_Normal).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; loc_8BD4:
MenuScreen:
    bsr.w   Pal_FadeToBlack
    move    #$2700,sr
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   ClearScreen
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8200|(VRAM_Menu_Plane_A_Name_Table/$400),(a6)     ; PNT A base: $C000
    move.w  #$8400|(VRAM_Menu_Plane_B_Name_Table/$2000),(a6)    ; PNT B base: $E000
    move.w  #$8200|(VRAM_Menu_Plane_A_Name_Table/$400),(a6)     ; PNT A base: $C000
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
 
    clearRAM Sprite_Table_Input,Sprite_Table_Input_End
    clearRAM Menus_Object_RAM,Menus_Object_RAM_End
 
    ; load background + graphics of font/LevSelPics
    clr.w   (VDP_Command_Buffer).w
    move.l  #VDP_Command_Buffer,(VDP_Command_Buffer_Slot).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_FontStuff),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_FontStuff).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_MenuBox),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_MenuBox).l,a0
    bsr.w   NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_LevelSelectPics),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_LevelSelectPics).l,a0
    bsr.w   NemDec
    lea (Chunk_Table).l,a1
    lea (MapEng_MenuBack).l,a0
    move.w  #make_art_tile(ArtTile_VRAM_Start,3,0),d0
    bsr.w   EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_Plane_B_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40    ; fullscreen background
 
    cmpi.b  #GameModeID_OptionsMenu,(Game_Mode).w   ; options menu?
    beq.w   MenuScreen_Options  ; if yes, branch
 
    cmpi.b  #GameModeID_LevelSelect,(Game_Mode).w   ; level select menu?
    beq.w   MenuScreen_LevelSelect  ; if yes, branch
 
;MenuScreen_LevSel2P:
    lea (Chunk_Table).l,a1
    lea (MapEng_LevSel2P).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_MenuBox,0,0),d0
    bsr.w   EniDec
    lea (Chunk_Table+$198).l,a1
    lea (MapEng_LevSel2P).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_MenuBox,1,0),d0
    bsr.w   EniDec
    lea (Chunk_Table+$330).l,a1
    lea (MapEng_LevSelIcon).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_LevelSelectPics,0,0),d0
    bsr.w   EniDec
    lea (Chunk_Table+$498).l,a2
 
    moveq   #$F,d1
-   move.w  #$207B,(a2)+
    dbf d1,-
 
    bsr.w   Update2PLevSelSelection
    addq.b  #1,(Current_Zone_2P).w
    andi.b  #3,(Current_Zone_2P).w
    bsr.w   ClearOld2PLevSelSelection
    addq.b  #1,(Current_Zone_2P).w
    andi.b  #3,(Current_Zone_2P).w
    bsr.w   ClearOld2PLevSelSelection
    addq.b  #1,(Current_Zone_2P).w
    andi.b  #3,(Current_Zone_2P).w
    bsr.w   ClearOld2PLevSelSelection
    addq.b  #1,(Current_Zone_2P).w
    andi.b  #3,(Current_Zone_2P).w
    clr.w   (Player_mode).w
    clr.b   (Current_Act_2P).w
    clr.w   (Results_Screen_2P).w   ; VsRSID_Act
    clr.b   (Level_started_flag).w
    clr.w   (Anim_Counters).w
    clr.w   (Game_Over_2P).w
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal
    moveq   #PalID_Menu,d0
    bsr.w   PalLoad_ForFade
    lea (Normal_palette_line3).w,a1
    lea (Target_palette_line3).w,a2
 
    moveq   #bytesToLcnt($20),d1
-   move.l  (a1),(a2)+
    clr.l   (a1)+
    dbf d1,-
 
    move.b  #MusID_Options,d0
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
    move.w  #$707,(Demo_Time_left).w
    clr.w   (Two_player_mode).w
    clr.l   (Camera_X_pos).w
    clr.l   (Camera_Y_pos).w
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromBlack
 
;loc_8DA8:
LevelSelect2P_Main:
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move    #$2700,sr
    bsr.w   ClearOld2PLevSelSelection
    bsr.w   LevelSelect2P_Controls
    bsr.w   Update2PLevSelSelection
    move    #$2300,sr
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0
    bne.s   LevelSelect2P_PressStart
    bra.w   LevelSelect2P_Main
; ===========================================================================
;loc_8DE2:
LevelSelect2P_PressStart:
    bsr.w   Chk2PZoneCompletion
    bmi.s   loc_8DF4
    move.w  #SndID_Error,d0
    jsrto   (PlaySound).l, JmpTo_PlaySound
    bra.w   LevelSelect2P_Main
; ===========================================================================
 
loc_8DF4:
    moveq   #0,d0
    move.b  (Current_Zone_2P).w,d0
    add.w   d0,d0
    move.w  LevelSelect2P_LevelOrder(pc,d0.w),d0
    bmi.s   loc_8E3A
    move.w  d0,(Current_ZoneAndAct).w
    move.w  #1,(Two_player_mode).w
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    move.b  #0,(Last_star_pole_hit).w
    move.b  #0,(Last_star_pole_hit_2P).w
    moveq   #0,d0
    move.l  d0,(Score).w
    move.l  d0,(Score_2P).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    rts
; ===========================================================================
 
loc_8E3A:
    move.b  #4,(Current_Special_Stage).w
    move.b  #GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
    moveq   #1,d0
    move.w  d0,(Two_player_mode).w
    move.w  d0,(Two_player_mode_copy).w
    rts
; ===========================================================================
; word_8E52:
LevelSelect2P_LevelOrder:
    dc.w    emerald_hill_zone_act_1
    dc.w    mystic_cave_zone_act_1
    dc.w    casino_night_zone_act_1
    dc.w    $FFFF
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_8E5A:
LevelSelect2P_Controls:
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    move.b  d0,d1
    andi.b  #button_up_mask|button_down_mask,d0
    beq.s   +
    bchg    #1,(Current_Zone_2P).w
 
+
    andi.b  #button_left_mask|button_right_mask,d1
    beq.s   +   ; rts
    bchg    #0,(Current_Zone_2P).w
+
    rts
; End of function LevelSelect2P_Controls
 
; ---------------------------------------------------------------------------
; Subroutine to update the 2P level select selection graphically
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_8E7E:
Update2PLevSelSelection:
    moveq   #0,d0
    move.b  (Current_Zone_2P).w,d0
    lsl.w   #4,d0   ; 16 bytes per entry
    lea (LevSel2PIconData).l,a3
    lea (a3,d0.w),a3
    move.w  #$6000,d0   ; highlight text
    lea (Chunk_Table+$48).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$94).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$D8).l,a2
    movea.l 4(a3),a1
    bsr.w   Chk2PZoneCompletion ; has the zone been completed?
    bmi.s   +   ; if not, branch
    lea (Chunk_Table+$468).l,a1 ; display large X instead of icon
+
    moveq   #2,d1
-   move.l  (a1)+,(a2)+
    move.l  (a1)+,(a2)+
    lea $1A(a2),a2
    dbf d1,-
 
    lea (Chunk_Table).l,a1
    move.l  (a3)+,d0
    moveq   #$10,d1
    moveq   #$B,d2
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40
    lea (Pal_LevelIcons).l,a1
    moveq   #0,d0
    move.b  (a3),d0
    lsl.w   #5,d0
    lea (a1,d0.w),a1
    lea (Normal_palette_line3).w,a2
 
    moveq   #bytesToLcnt(palette_line_size),d1
-   move.l  (a1)+,(a2)+
    dbf d1,-
 
    rts
; End of function Update2PLevSelSelection
 
; ---------------------------------------------------------------------------
; Subroutine to check if a 2P zone has been completed
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_8EFE:
Chk2PZoneCompletion:
    moveq   #0,d0
    move.b  (Current_Zone_2P).w,d0
    ; multiply d0 by 6
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    add.w   d0,d0
    lea (Results_Data_2P).w,a5
    lea (a5,d0.w),a5
    move.w  (a5),d0
    add.w   2(a5),d0
    rts
; End of function Chk2PZoneCompletion
 
; ---------------------------------------------------------------------------
; Subroutine to clear the old 2P level select selection
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_8F1C:
ClearOld2PLevSelSelection:
    moveq   #0,d0
    move.b  (Current_Zone_2P).w,d0
    lsl.w   #4,d0
    lea (LevSel2PIconData).l,a3
    lea (a3,d0.w),a3
    moveq   #0,d0
    lea (Chunk_Table+$1E0).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$22C).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$270).l,a2
    lea (Chunk_Table+$498).l,a1
    bsr.w   Chk2PZoneCompletion
    bmi.s   +
    lea (Chunk_Table+$468).l,a1
+
    moveq   #2,d1
-   move.l  (a1)+,(a2)+
    move.l  (a1)+,(a2)+
    lea $1A(a2),a2
    dbf d1,-
 
    lea (Chunk_Table+$198).l,a1
    move.l  (a3)+,d0
    moveq   #$10,d1
    moveq   #$B,d2
    jmpto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40
; End of function ClearOld2PLevSelSelection
 
; ===========================================================================
; off_8F7E:
LevSel2PIconData:
 
; macro to declare icon data for a 2P level select icon
iconData macro txtlabel,txtlabel2,vramAddr,iconPal,iconAddr
    dc.l txtlabel, txtlabel2    ; text locations
    dc.l vdpComm(vramAddr,VRAM,WRITE)   ; VRAM location to place data
    dc.l iconPal<<24|iconAddr   ; icon palette and plane data location
    endm
 
    iconData    Text2P_EmeraldHill,Text2P_Zone,VRAM_Plane_A_Name_Table+planeLocH40(2,2),0,$FF0330
    iconData    Text2P_MysticCave,Text2P_Zone,VRAM_Plane_A_Name_Table+planeLocH40(22,2),5,$FF03A8
    iconData    Text2P_CasinoNight,Text2P_Zone,VRAM_Plane_A_Name_Table+planeLocH40(2,15),6,$FF03C0
    iconData    Text2P_Special,Text2P_Stage,VRAM_Plane_A_Name_Table+planeLocH40(22,15),$C,$FF0450
 
; ---------------------------------------------------------------------------
; Common menu screen subroutine for transferring text to RAM
 
; ARGUMENTS:
; d0 = starting art tile
; a1 = data source
; a2 = destination
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_8FBE:
MenuScreenTextToRAM:
    moveq   #0,d1
    move.b  (a1)+,d1
-   move.b  (a1)+,d0
    move.w  d0,(a2)+
    dbf d1,-
    rts
; End of function MenuScreenTextToRAM
 
; ===========================================================================
; loc_8FCC:
MenuScreen_Options:
    lea (Chunk_Table).l,a1
    lea (MapEng_Options).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_MenuBox,0,0),d0
    bsr.w   EniDec
    lea (Chunk_Table+$160).l,a1
    lea (MapEng_Options).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_MenuBox,1,0),d0
    bsr.w   EniDec
    clr.b   (Options_menu_box).w
    bsr.w   OptionScreen_DrawSelected
    addq.b  #1,(Options_menu_box).w
    bsr.w   OptionScreen_DrawUnselected
    addq.b  #1,(Options_menu_box).w
    bsr.w   OptionScreen_DrawUnselected
    clr.b   (Options_menu_box).w
    clr.b   (Level_started_flag).w
    clr.w   (Anim_Counters).w
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal
    moveq   #PalID_Menu,d0
    bsr.w   PalLoad_ForFade
    move.b  #MusID_Options,d0
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
    clr.w   (Two_player_mode).w
    clr.l   (Camera_X_pos).w
    clr.l   (Camera_Y_pos).w
    clr.w   (Correct_cheat_entries).w
    clr.w   (Correct_cheat_entries_2).w
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
    bsr.w   Pal_FadeFromBlack
; loc_9060:
OptionScreen_Main:
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
    move    #$2700,sr
    bsr.w   OptionScreen_DrawUnselected
    bsr.w   OptionScreen_Controls
    bsr.w   OptionScreen_DrawSelected
    move    #$2300,sr
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0
    bne.s   OptionScreen_Select
    bra.w   OptionScreen_Main
; ===========================================================================
; loc_909A:
OptionScreen_Select:
    move.b  (Options_menu_box).w,d0
    bne.s   OptionScreen_Select_Not1P
    ; Start a single player game
    moveq   #0,d0
    move.w  d0,(Two_player_mode).w
    move.w  d0,(Two_player_mode_copy).w
    move.w  d0,(Current_ZoneAndAct).w   ; emerald_hill_zone_act_1
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    rts
; ===========================================================================
; loc_90B6:
OptionScreen_Select_Not1P:
    subq.b  #1,d0
    bne.s   OptionScreen_Select_Other
    ; Start a 2P VS game
    moveq   #1,d0
    move.w  d0,(Two_player_mode).w
    move.w  d0,(Two_player_mode_copy).w
    move.b  #GameModeID_2PLevelSelect,(Game_Mode).w ; => LevelSelectMenu2P
    move.b  #0,(Current_Zone_2P).w
    move.w  #0,(Player_mode).w
    rts
; ===========================================================================
; loc_90D8:
OptionScreen_Select_Other:
    ; When pressing START on the sound test option, return to the SEGA screen
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_90E0:
OptionScreen_Controls:
    moveq   #0,d2
    move.b  (Options_menu_box).w,d2
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    btst    #button_up,d0
    beq.s   +
    subq.b  #1,d2
    bcc.s   +
    move.b  #2,d2
 
+
    btst    #button_down,d0
    beq.s   +
    addq.b  #1,d2
    cmpi.b  #3,d2
    blo.s   +
    moveq   #0,d2
 
+
    move.b  d2,(Options_menu_box).w
    lsl.w   #2,d2
    move.b  OptionScreen_Choices(pc,d2.w),d3 ; number of choices for the option
    movea.l OptionScreen_Choices(pc,d2.w),a1 ; location where the choice is stored (in RAM)
    move.w  (a1),d2
    btst    #button_left,d0
    beq.s   +
    subq.b  #1,d2
    bcc.s   +
    move.b  d3,d2
 
+
    btst    #button_right,d0
    beq.s   +
    addq.b  #1,d2
    cmp.b   d3,d2
    bls.s   +
    moveq   #0,d2
 
+
    btst    #button_A,d0
    beq.s   +
    addi.b  #$10,d2
    cmp.b   d3,d2
    bls.s   +
    moveq   #0,d2
 
+
    move.w  d2,(a1)
    cmpi.b  #2,(Options_menu_box).w
    bne.s   +   ; rts
    andi.w  #button_B_mask|button_C_mask,d0
    beq.s   +   ; rts
    move.w  (Sound_test_sound).w,d0
    addi.w  #$80,d0
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
    lea (level_select_cheat).l,a0
    lea (continues_cheat).l,a2
    lea (Level_select_flag).w,a1
    moveq   #0,d2   ; flag to tell the routine to enable the continues cheat
    bsr.w   CheckCheats
 
+
    rts
; End of function OptionScreen_Controls
 
; ===========================================================================
; word_917A:
OptionScreen_Choices:
    dc.l (3-1)<<24|(Player_option&$FFFFFF)
    dc.l (2-1)<<24|(Two_player_items&$FFFFFF)
    dc.l ($80-1)<<24|(Sound_test_sound&$FFFFFF)
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_9186
OptionScreen_DrawSelected:
    bsr.w   OptionScreen_SelectTextPtr
    moveq   #0,d1
    move.b  (Options_menu_box).w,d1
    lsl.w   #3,d1
    lea (OptScrBoxData).l,a3
    lea (a3,d1.w),a3
    move.w  #palette_line_3,d0
    lea (Chunk_Table+$30).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$B6).l,a2
    moveq   #0,d1
    cmpi.b  #2,(Options_menu_box).w
    beq.s   +
    move.b  (Options_menu_box).w,d1
    lsl.w   #2,d1
    lea OptionScreen_Choices(pc),a1
    movea.l (a1,d1.w),a1
    move.w  (a1),d1
    lsl.w   #2,d1
+
    movea.l (a4,d1.w),a1
    bsr.w   MenuScreenTextToRAM
    cmpi.b  #2,(Options_menu_box).w
    bne.s   +
    lea (Chunk_Table+$C2).l,a2
    bsr.w   OptionScreen_HexDumpSoundTest
+
    lea (Chunk_Table).l,a1
    move.l  (a3)+,d0
    moveq   #$15,d1
    moveq   #7,d2
    jmpto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40
; ===========================================================================
 
;loc_91F8
OptionScreen_DrawUnselected:
    bsr.w   OptionScreen_SelectTextPtr
    moveq   #0,d1
    move.b  (Options_menu_box).w,d1
    lsl.w   #3,d1
    lea (OptScrBoxData).l,a3
    lea (a3,d1.w),a3
    moveq   #palette_line_0,d0
    lea (Chunk_Table+$190).l,a2
    movea.l (a3)+,a1
    bsr.w   MenuScreenTextToRAM
    lea (Chunk_Table+$216).l,a2
    moveq   #0,d1
    cmpi.b  #2,(Options_menu_box).w
    beq.s   +
    move.b  (Options_menu_box).w,d1
    lsl.w   #2,d1
    lea OptionScreen_Choices(pc),a1
    movea.l (a1,d1.w),a1
    move.w  (a1),d1
    lsl.w   #2,d1
 
+
    movea.l (a4,d1.w),a1
    bsr.w   MenuScreenTextToRAM
    cmpi.b  #2,(Options_menu_box).w
    bne.s   +
    lea (Chunk_Table+$222).l,a2
    bsr.w   OptionScreen_HexDumpSoundTest
 
+
    lea (Chunk_Table+$160).l,a1
    move.l  (a3)+,d0
    moveq   #$15,d1
    moveq   #7,d2
    jmpto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40
; ===========================================================================
 
;loc_9268
OptionScreen_SelectTextPtr:
    lea (off_92D2).l,a4
    tst.b   (Graphics_Flags).w
    bpl.s   +
    lea (off_92DE).l,a4
 
+
    tst.b   (Options_menu_box).w
    beq.s   +
    lea (off_92EA).l,a4
 
+
    cmpi.b  #2,(Options_menu_box).w
    bne.s   +   ; rts
    lea (off_92F2).l,a4
 
+
    rts
; ===========================================================================
 
;loc_9296
OptionScreen_HexDumpSoundTest:
    move.w  (Sound_test_sound).w,d1
    move.b  d1,d2
    lsr.b   #4,d1
    bsr.s   +
    move.b  d2,d1
 
+
    andi.w  #$F,d1
    cmpi.b  #$A,d1
    blo.s   +
    addi.b  #4,d1
 
+
    addi.b  #$10,d1
    move.b  d1,d0
    move.w  d0,(a2)+
    rts
; ===========================================================================
; off_92BA:
OptScrBoxData:
 
; macro to declare the data for an options screen box
boxData macro txtlabel,vramAddr
    dc.l txtlabel, vdpComm(vramAddr,VRAM,WRITE)
    endm
 
    boxData TextOptScr_PlayerSelect,VRAM_Plane_A_Name_Table+planeLocH40(9,3)
    boxData TextOptScr_VsModeItems,VRAM_Plane_A_Name_Table+planeLocH40(9,11)
    boxData TextOptScr_SoundTest,VRAM_Plane_A_Name_Table+planeLocH40(9,19)
 
off_92D2:
    dc.l TextOptScr_SonicAndMiles
    dc.l TextOptScr_SonicAlone
    dc.l TextOptScr_MilesAlone
off_92DE:
    dc.l TextOptScr_SonicAndTails
    dc.l TextOptScr_SonicAlone
    dc.l TextOptScr_TailsAlone
off_92EA:
    dc.l TextOptScr_AllKindsItems
    dc.l TextOptScr_TeleportOnly
off_92F2:
    dc.l TextOptScr_0
; ===========================================================================
; loc_92F6:
MenuScreen_LevelSelect:
    ; Load foreground (sans zone icon)
    lea (Chunk_Table).l,a1
    lea (MapEng_LevSel).l,a0    ; 2 bytes per 8x8 tile, compressed
    move.w  #make_art_tile(ArtTile_VRAM_Start,0,0),d0
    bsr.w   EniDec
 
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE),d0
    moveq   #$27,d1
    moveq   #$1B,d2 ; 40x28 = whole screen
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40    ; display patterns
 
    ; Draw sound test number
    moveq   #palette_line_0,d3
    bsr.w   LevelSelect_DrawSoundNumber
 
    ; Load zone icon
    lea (Chunk_Table+$8C0).l,a1
    lea (MapEng_LevSelIcon).l,a0
    move.w  #make_art_tile(ArtTile_ArtNem_LevelSelectPics,0,0),d0
    bsr.w   EniDec
 
    bsr.w   LevelSelect_DrawIcon
 
    clr.w   (Player_mode).w
    clr.w   (Results_Screen_2P).w   ; VsRSID_Act
    clr.b   (Level_started_flag).w
    clr.w   (Anim_Counters).w
 
    ; Animate background (loaded back in MenuScreen)
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal   ; background
 
    moveq   #PalID_Menu,d0
    bsr.w   PalLoad_ForFade
 
    lea (Normal_palette_line3).w,a1
    lea (Target_palette_line3).w,a2
 
    moveq   #bytesToLcnt(palette_line_size),d1
-   move.l  (a1),(a2)+
    clr.l   (a1)+
    dbf d1,-
 
    move.b  #MusID_Options,d0
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
 
    move.w  #$707,(Demo_Time_left).w
    clr.w   (Two_player_mode).w
    clr.l   (Camera_X_pos).w
    clr.l   (Camera_Y_pos).w
    clr.w   (Correct_cheat_entries).w
    clr.w   (Correct_cheat_entries_2).w
 
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
 
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
 
    bsr.w   Pal_FadeFromBlack
 
;loc_93AC:
LevelSelect_Main:   ; routine running during level select
    move.b  #VintID_Menu,(Vint_routine).w
    bsr.w   WaitForVint
 
    move    #$2700,sr
 
    moveq   #palette_line_0-palette_line_0,d3   ; palette line << 13
    bsr.w   LevelSelect_MarkFields  ; unmark fields
    bsr.w   LevSelControls  ; possible change selected fields
    move.w  #palette_line_3-palette_line_0,d3   ; palette line << 13
    bsr.w   LevelSelect_MarkFields  ; mark fields
 
    bsr.w   LevelSelect_DrawIcon
 
    move    #$2300,sr
 
    lea (Anim_SonicMilesBG).l,a2
    jsrto   (Dynamic_Normal).l, JmpTo2_Dynamic_Normal
 
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_start_mask,d0   ; start pressed?
    bne.s   LevelSelect_PressStart  ; yes
    bra.w   LevelSelect_Main    ; no
; ===========================================================================
 
;loc_93F0:
LevelSelect_PressStart:
    move.w  (Level_select_zone).w,d0
    add.w   d0,d0
    move.w  LevelSelect_Order(pc,d0.w),d0
    bmi.w   LevelSelect_Return  ; sound test
    cmpi.w  #$4000,d0
    bne.s   LevelSelect_StartZone
 
;LevelSelect_SpecialStage:
    move.b  #GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
    clr.w   (Current_ZoneAndAct).w
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
    moveq   #0,d0
    move.w  d0,(Ring_count).w
    move.l  d0,(Timer).w
    move.l  d0,(Score).w
    move.w  d0,(Ring_count_2P).w
    move.l  d0,(Timer_2P).w
    move.l  d0,(Score_2P).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    move.w  (Player_option).w,(Player_mode).w
    rts
; ===========================================================================
 
;loc_944C:
LevelSelect_Return:
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
; ===========================================================================
; -----------------------------------------------------------------------------
; Level Select Level Order
 
; One entry per item in the level select menu. Just set the value for the item
; you want to link to the level/act number of the level you want to load when
; the player selects that item.
; -----------------------------------------------------------------------------
;Misc_9454:
LevelSelect_Order:
    dc.w    emerald_hill_zone_act_1
    dc.w    emerald_hill_zone_act_2 ; 1
    dc.w    chemical_plant_zone_act_1   ; 2
    dc.w    chemical_plant_zone_act_2   ; 3
    dc.w    aquatic_ruin_zone_act_1 ; 4
    dc.w    aquatic_ruin_zone_act_2 ; 5
    dc.w    casino_night_zone_act_1 ; 6
    dc.w    casino_night_zone_act_2 ; 7
    dc.w    hill_top_zone_act_1 ; 8
    dc.w    hill_top_zone_act_2 ; 9
    dc.w    mystic_cave_zone_act_1  ; 10
    dc.w    mystic_cave_zone_act_2  ; 11
    dc.w    oil_ocean_zone_act_1    ; 12
    dc.w    oil_ocean_zone_act_2    ; 13
    dc.w    metropolis_zone_act_1   ; 14
    dc.w    metropolis_zone_act_2   ; 15
    dc.w    metropolis_zone_act_3   ; 16
    dc.w    sky_chase_zone_act_1    ; 17
    dc.w    wing_fortress_zone_act_1    ; 18
    dc.w    death_egg_zone_act_1    ; 19
    dc.w    $4000   ; 20 - special stage
    dc.w    $FFFF   ; 21 - sound test
; ===========================================================================
 
;loc_9480:
LevelSelect_StartZone:
    andi.w  #$3FFF,d0
    move.w  d0,(Current_ZoneAndAct).w
    move.b  #GameModeID_Level,(Game_Mode).w ; => Level (Zone play mode)
    move.b  #3,(Life_count).w
    move.b  #3,(Life_count_2P).w
    moveq   #0,d0
    move.w  d0,(Ring_count).w
    move.l  d0,(Timer).w
    move.l  d0,(Score).w
    move.w  d0,(Ring_count_2P).w
    move.l  d0,(Timer_2P).w
    move.l  d0,(Score_2P).w
    move.b  d0,(Continue_count).w
    move.l  #5000,(Next_Extra_life_score).w
    move.l  #5000,(Next_Extra_life_score_2P).w
    move.b  #MusID_FadeOut,d0
    jsrto   (PlaySound).l, JmpTo_PlaySound
    moveq   #0,d0
    move.w  d0,(Two_player_mode_copy).w
    move.w  d0,(Two_player_mode).w
    rts
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Change what you're selecting in the level select
; ---------------------------------------------------------------------------
; loc_94DC:
LevSelControls:
    move.b  (Ctrl_1_Press).w,d1
    andi.b  #button_up_mask|button_down_mask,d1
    bne.s   +   ; up/down pressed
    subq.w  #1,(LevSel_HoldTimer).w
    bpl.s   LevSelControls_CheckLR
 
+
    move.w  #$B,(LevSel_HoldTimer).w
    move.b  (Ctrl_1_Held).w,d1
    andi.b  #button_up_mask|button_down_mask,d1
    beq.s   LevSelControls_CheckLR  ; up/down not pressed, check for left & right
    move.w  (Level_select_zone).w,d0
    btst    #button_up,d1
    beq.s   +
    subq.w  #1,d0   ; decrease by 1
    bcc.s   +   ; >= 0?
    moveq   #$15,d0 ; set to $15
 
+
    btst    #button_down,d1
    beq.s   +
    addq.w  #1,d0   ; yes, add 1
    cmpi.w  #$16,d0
    blo.s   +   ; smaller than $16?
    moveq   #0,d0   ; if not, set to 0
 
+
    move.w  d0,(Level_select_zone).w
    rts
; ===========================================================================
; loc_9522:
LevSelControls_CheckLR:
    cmpi.w  #$15,(Level_select_zone).w  ; are we in the sound test?
    bne.s   LevSelControls_SwitchSide   ; no
    move.w  (Sound_test_sound).w,d0
    move.b  (Ctrl_1_Press).w,d1
    btst    #button_left,d1
    beq.s   +
    subq.b  #1,d0
    bcc.s   +
    moveq   #$7F,d0
 
+
    btst    #button_right,d1
    beq.s   +
    addq.b  #1,d0
    cmpi.w  #$80,d0
    blo.s   +
    moveq   #0,d0
 
+
    btst    #button_A,d1
    beq.s   +
    addi.b  #$10,d0
    andi.b  #$7F,d0
 
+
    move.w  d0,(Sound_test_sound).w
    andi.w  #button_B_mask|button_C_mask,d1
    beq.s   +   ; rts
    move.w  (Sound_test_sound).w,d0
    addi.w  #$80,d0
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
    lea (debug_cheat).l,a0
    lea (super_sonic_cheat).l,a2
    lea (Debug_options_flag).w,a1
    moveq   #1,d2   ; flag to tell the routine to enable the Super Sonic cheat
    bsr.w   CheckCheats
 
+
    rts
; ===========================================================================
; loc_958A:
LevSelControls_SwitchSide:  ; not in soundtest, not up/down pressed
    move.b  (Ctrl_1_Press).w,d1
    andi.b  #button_left_mask|button_right_mask,d1
    beq.s   +               ; no direction key pressed
    move.w  (Level_select_zone).w,d0    ; left or right pressed
    move.b  LevelSelect_SwitchTable(pc,d0.w),d0 ; set selected zone according to table
    move.w  d0,(Level_select_zone).w
+
    rts
; ===========================================================================
;byte_95A2:
LevelSelect_SwitchTable:
    dc.b $E
    dc.b $F     ; 1
    dc.b $11    ; 2
    dc.b $11    ; 3
    dc.b $12    ; 4
    dc.b $12    ; 5
    dc.b $13    ; 6
    dc.b $13    ; 7
    dc.b $14    ; 8
    dc.b $14    ; 9
    dc.b $15    ; 10
    dc.b $15    ; 11
    dc.b $C     ; 12
    dc.b $D     ; 13
    dc.b 0      ; 14
    dc.b 1      ; 15
    dc.b 1      ; 16
    dc.b 2      ; 17
    dc.b 4      ; 18
    dc.b 6      ; 19
    dc.b 8      ; 20
    dc.b $A     ; 21
    even
; ===========================================================================
 
;loc_95B8:
LevelSelect_MarkFields:
    lea (Chunk_Table).l,a4
    lea (LevSel_MarkTable).l,a5
    lea (VDP_data_port).l,a6
    moveq   #0,d0
    move.w  (Level_select_zone).w,d0
    lsl.w   #2,d0
    lea (a5,d0.w),a3
    moveq   #0,d0
    move.b  (a3),d0
    mulu.w  #$50,d0
    moveq   #0,d1
    move.b  1(a3),d1
    add.w   d1,d0
    lea (a4,d0.w),a1
    moveq   #0,d1
    move.b  (a3),d1
    lsl.w   #7,d1
    add.b   1(a3),d1
    addi.w  #VRAM_Plane_A_Name_Table,d1
    lsl.l   #2,d1
    lsr.w   #2,d1
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d1
    swap    d1
    move.l  d1,4(a6)
 
    moveq   #$D,d2
-   move.w  (a1)+,d0
    add.w   d3,d0
    move.w  d0,(a6)
    dbf d2,-
 
    addq.w  #2,a3
    moveq   #0,d0
    move.b  (a3),d0
    beq.s   +
    mulu.w  #$50,d0
    moveq   #0,d1
    move.b  1(a3),d1
    add.w   d1,d0
    lea (a4,d0.w),a1
    moveq   #0,d1
    move.b  (a3),d1
    lsl.w   #7,d1
    add.b   1(a3),d1
    addi.w  #VRAM_Plane_A_Name_Table,d1
    lsl.l   #2,d1
    lsr.w   #2,d1
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d1
    swap    d1
    move.l  d1,4(a6)
    move.w  (a1)+,d0
    add.w   d3,d0
    move.w  d0,(a6)
 
+
    cmpi.w  #$15,(Level_select_zone).w
    bne.s   +   ; rts
    bsr.w   LevelSelect_DrawSoundNumber
+
    rts
; ===========================================================================
;loc_965A:
LevelSelect_DrawSoundNumber:
    move.l  #vdpComm(VRAM_Plane_A_Name_Table+planeLocH40(34,18),VRAM,WRITE),(VDP_control_port).l
    move.w  (Sound_test_sound).w,d0
    move.b  d0,d2
    lsr.b   #4,d0
    bsr.s   +
    move.b  d2,d0
 
+
    andi.w  #$F,d0
    cmpi.b  #$A,d0
    blo.s   +
    addi.b  #4,d0
 
+
    addi.b  #$10,d0
    add.w   d3,d0
    move.w  d0,(a6)
    rts
; ===========================================================================
 
;loc_9688:
LevelSelect_DrawIcon:
    move.w  (Level_select_zone).w,d0
    lea (LevSel_IconTable).l,a3
    lea (a3,d0.w),a3
    lea (Chunk_Table+$8C0).l,a1
    moveq   #0,d0
    move.b  (a3),d0
    lsl.w   #3,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    lea (a1,d0.w),a1
    move.l  #vdpComm(VRAM_Plane_A_Name_Table+planeLocH40(27,22),VRAM,WRITE),d0
    moveq   #3,d1
    moveq   #2,d2
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo_PlaneMapToVRAM_H40
    lea (Pal_LevelIcons).l,a1
    moveq   #0,d0
    move.b  (a3),d0
    lsl.w   #5,d0
    lea (a1,d0.w),a1
    lea (Normal_palette_line3).w,a2
 
    moveq   #bytesToLcnt(palette_line_size),d1
-   move.l  (a1)+,(a2)+
    dbf d1,-
 
    rts
; ===========================================================================
;byte_96D8
LevSel_IconTable:
    dc.b   0,0  ;0  EHZ
    dc.b   7,7  ;2  CPZ
    dc.b   8,8  ;4  ARZ
    dc.b   6,6  ;6  CNZ
    dc.b   2,2  ;8  HTZ
    dc.b   5,5  ;$A MCZ
    dc.b   4,4  ;$C OOZ
    dc.b   1,1,1    ;$E MTZ
    dc.b   9    ;$11    SCZ
    dc.b  $A    ;$12    WFZ
    dc.b  $B    ;$13    DEZ
    dc.b  $C    ;$14    Special Stage
    dc.b  $E    ;$15    Sound Test
    even
;byte_96EE:
LevSel_MarkTable:   ; 4 bytes per level select entry
; line primary, 2*column ($E fields), line secondary, 2*column secondary (1 field)
    dc.b   3,  6,  3,$24    ;0
    dc.b   3,  6,  4,$24
    dc.b   6,  6,  6,$24
    dc.b   6,  6,  7,$24
    dc.b   9,  6,  9,$24    ;4
    dc.b   9,  6, $A,$24
    dc.b  $C,  6, $C,$24
    dc.b  $C,  6, $D,$24
    dc.b  $F,  6, $F,$24    ;8
    dc.b  $F,  6,$10,$24
    dc.b $12,  6,$12,$24
    dc.b $12,  6,$13,$24
    dc.b $15,  6,$15,$24    ;$C
    dc.b $15,  6,$16,$24
; --- second column ---
    dc.b   3,$2C,  3,$48
    dc.b   3,$2C,  4,$48
    dc.b   3,$2C,  5,$48    ;$10
    dc.b   6,$2C,  0,  0
    dc.b   9,$2C,  0,  0
    dc.b  $C,$2C,  0,  0
    dc.b  $F,$2C,  0,  0    ;$14
    dc.b $12,$2C,$12,$48
; ===========================================================================
; loc_9746:
CheckCheats:    ; This is called from 2 places: the options screen and the level select screen
    move.w  (Correct_cheat_entries).w,d0    ; Get the number of correct sound IDs entered so far
    adda.w  d0,a0               ; Skip to the next entry
    move.w  (Sound_test_sound).w,d0     ; Get the current sound test sound
    cmp.b   (a0),d0             ; Compare it to the cheat
    bne.s   +               ; If they're different, branch
    addq.w  #1,(Correct_cheat_entries).w    ; Add 1 to the number of correct entries
    tst.b   1(a0)               ; Is the next entry 0?
    bne.s   ++              ; If not, branch
    move.w  #$101,(a1)          ; Enable the cheat
    move.b  #SndID_Ring,d0          ; Play the ring sound
    jsrto   (PlaySound).l, JmpTo_PlaySound
+
    move.w  #0,(Correct_cheat_entries).w    ; Clear the number of correct entries
+
    move.w  (Correct_cheat_entries_2).w,d0  ; Do the same procedure with the other cheat
    adda.w  d0,a2
    move.w  (Sound_test_sound).w,d0
    cmp.b   (a2),d0
    bne.s   ++
    addq.w  #1,(Correct_cheat_entries_2).w
    tst.b   1(a2)
    bne.s   +++ ; rts
    tst.w   d2              ; Test this to determine which cheat to enable
    bne.s   +               ; If not 0, branch
    move.b  #$F,(Continue_count).w      ; Give 15 continues
    ; The next line causes the bug where the OOZ music plays until reset.
    ; Remove "&$7F" to fix the bug.
    move.b  #SndID_ContinueJingle&$7F,d0    ; Play the continue jingle
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
    bra.s   ++
; ===========================================================================
+
    move.w  #7,(Got_Emerald).w      ; Give 7 emeralds to the player
    move.b  #MusID_Emerald,d0       ; Play the emerald jingle
    jsrto   (PlayMusic).l, JmpTo_PlayMusic
+
    move.w  #0,(Correct_cheat_entries_2).w  ; Clear the number of correct entries
+
    rts
; ===========================================================================
level_select_cheat: dc.b $19, $65,   9, $17,   0    ; 17th September 1965, Yuji Naka's birthdate
    rev02even
; byte_97B7
continues_cheat:    dc.b   1,   1,   2,   4,   0    ; 24th November, Sonic 2's release date in the EU and US: "Sonic 2sday"
    rev02even
debug_cheat:        dc.b   1,   9,   9,   2,   1,   1,   2,   4,   0    ; 24th November 1992, Sonic 2's release date in the EU and US: "Sonic 2sday"
    rev02even
; byte_97C5
super_sonic_cheat:  dc.b   4,   1,   2,   6,   0    ; Book of Genesis, 41:26
    rev02even
 
    ; set the character set for menu text
    charset '@',"\27\30\31\32\33\34\35\36\37\38\39\40\41\42\43\44\45\46\47\48\49\50\51\52\53\54\55"
    charset '0',"\16\17\18\19\20\21\22\23\24\25"
    charset '*',$1A
    charset ':',$1C
    charset '.',$1D
    charset ' ',0
 
    ; options screen menu text
 
TextOptScr_PlayerSelect:    menutxt "* PLAYER SELECT *" ; byte_97CA:
TextOptScr_SonicAndMiles:   menutxt "SONIC AND MILES"   ; byte_97DC:
TextOptScr_SonicAndTails:   menutxt "SONIC AND TAILS"   ; byte_97EC:
TextOptScr_SonicAlone:      menutxt "SONIC ALONE    "   ; byte_97FC:
TextOptScr_MilesAlone:      menutxt "MILES ALONE    "   ; byte_980C:
TextOptScr_TailsAlone:      menutxt "TAILS ALONE    "   ; byte_981C:
TextOptScr_VsModeItems:     menutxt "* VS MODE ITEMS *" ; byte_982C:
TextOptScr_AllKindsItems:   menutxt "ALL KINDS ITEMS"   ; byte_983E:
TextOptScr_TeleportOnly:    menutxt "TELEPORT ONLY  "   ; byte_984E:
TextOptScr_SoundTest:       menutxt "*  SOUND TEST   *" ; byte_985E:
TextOptScr_0:           menutxt "      00       "   ; byte_9870:
 
    charset ; reset character set
 
; level select picture palettes
; byte_9880:
Pal_LevelIcons: BINCLUDE "art/palettes/Level Select Icons.bin"
 
; 2-player level select screen mappings (Enigma compressed)
; byte_9A60:
MapEng_LevSel2P:    BINCLUDE "mappings/misc/Level Select 2P.bin"
 
; options screen mappings (Enigma compressed)
; byte_9AB2:
MapEng_Options: BINCLUDE "mappings/misc/Options Screen.bin"
 
; level select screen mappings (Enigma compressed)
; byte_9ADE:
MapEng_LevSel:  BINCLUDE "mappings/misc/Level Select.bin"
 
; 1P and 2P level select icon mappings (Enigma compressed)
; byte_9C32:
MapEng_LevSelIcon:  BINCLUDE "mappings/misc/Level Select Icons.bin"
 
    if ~~removeJmpTos
JmpTo_PlaySound 
    jmp (PlaySound).l
JmpTo_PlayMusic 
    jmp (PlayMusic).l
; loc_9C70: JmpTo_PlaneMapToVRAM 
JmpTo_PlaneMapToVRAM_H40 
    jmp (PlaneMapToVRAM_H40).l
JmpTo2_Dynamic_Normal 
    jmp (Dynamic_Normal).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; loc_9C7C:
EndingSequence:
    clearRAM EndSeq_Object_RAM,EndSeq_Object_RAM_End
    clearRAM Misc_Variables,Misc_Variables_End
    clearRAM Camera_RAM,Camera_RAM_End
 
    move    #$2700,sr
    move.w  (VDP_Reg1_val).w,d0
    andi.b  #$BF,d0
    move.w  d0,(VDP_control_port).l
 
    stopZ80
    dmaFillVRAM 0,VRAM_Plane_A_Name_Table,VRAM_Plane_Table_Size ; clear Plane A pattern name table
    clr.l   (Vscroll_Factor).w
    clr.l   (unk_F61A).w
    startZ80
 
    lea (VDP_control_port).l,a6
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8200|(VRAM_EndSeq_Plane_A_Name_Table/$400),(a6)   ; PNT A base: $C000
    move.w  #$8400|(VRAM_EndSeq_Plane_B_Name_Table1/$2000),(a6) ; PNT B base: $E000
    move.w  #$8500|(VRAM_Sprite_Attribute_Table/$200),(a6)      ; Sprite attribute table base: $F800
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8720,(a6)     ; Background palette/color: 2/0
    move.w  #$8ADF,(Hint_counter_reserve).w ; H-INT every 224th scanline
    move.w  (Hint_counter_reserve).w,(a6)
    clr.b   (Super_Sonic_flag).w
    cmpi.b  #7,(Emerald_count).w
    bne.s   +
    cmpi.w  #2,(Player_mode).w
    beq.s   +
    st  (Super_Sonic_flag).w
    move.b  #-1,(Super_Sonic_palette).w
    move.b  #$F,(Palette_timer).w
    move.w  #$30,(Palette_frame).w
+
    moveq   #0,d0
    cmpi.w  #2,(Player_mode).w
    beq.s   +
    tst.b   (Super_Sonic_flag).w
    bne.s   ++
    bra.w   +++
 
; ===========================================================================
+
    addq.w  #2,d0
+
    addq.w  #2,d0
+
    move.w  d0,(Ending_Routine).w
    bsr.w   EndingSequence_LoadCharacterArt
    bsr.w   EndingSequence_LoadFlickyArt
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_EndingFinalTornado),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingFinalTornado).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_EndingPics),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingPics).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_EndingMiniTornado),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingMiniTornado).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Tornado),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Tornado).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Clouds),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Clouds).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    move.w  #death_egg_zone_act_1,(Current_ZoneAndAct).w
    move    #$2300,sr
    moveq   #MusID_Ending,d0
    jsrto   (PlayMusic).l, JmpTo2_PlayMusic
    move.l  #$EEE0EEE,d1
    lea (Normal_palette).w,a1
 
    moveq   #bytesToLcnt(palette_line_size*4),d0
-   move.l  d1,(a1)+
    dbf d0,-
 
    lea (Pal_AC7E).l,a1
    lea (Target_palette).w,a2
 
    moveq   #bytesToLcnt(palette_line_size*4),d0
-   move.l  (a1)+,(a2)+
    dbf d0,-
 
    clr.b   (Screen_Shaking_Flag).w
    moveq   #0,d0
    move.w  d0,(Debug_placement_mode).w
    move.w  d0,(Level_Inactive_flag).w
    move.w  d0,(Timer_frames).w
    move.w  d0,(Camera_X_pos).w
    move.w  d0,(Camera_Y_pos).w
    move.w  d0,(Camera_X_pos_copy).w
    move.w  d0,(Camera_Y_pos_copy).w
    move.w  d0,(Camera_BG_X_pos).w
    move.w  #$C8,(Camera_BG_Y_pos).w
    move.l  d0,(Vscroll_Factor).w
    move.b  d0,(Horiz_block_crossed_flag_BG).w
    move.b  d0,(Verti_block_crossed_flag_BG).w
    move.w  d0,(Ending_VInt_Subrout).w
    move.w  d0,(Credits_Trigger).w
 
    ; Bug: The '+4' shouldn't be here; clearRAM accidentally clears an additional 4 bytes
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End+4
 
    move.w  #$7FFF,(PalCycle_Timer).w
    lea (CutScene).w,a1
    move.b  #ObjID_CutScene,id(a1) ; load objCA (end of game cutscene) at $FFFFB100
    move.b  #6,routine(a1)
    move.w  #$60,objoff_3C(a1)
    move.w  #1,objoff_30(a1)
    cmpi.w  #4,(Ending_Routine).w
    bne.s   +
    move.w  #$10,objoff_2E(a1)
    move.w  #$100,objoff_3C(a1)
+
    move.b  #VintID_Ending,(Vint_routine).w
    bsr.w   WaitForVint
    move.w  (VDP_Reg1_val).w,d0
    ori.b   #$40,d0
    move.w  d0,(VDP_control_port).l
-
    move.b  #VintID_Ending,(Vint_routine).w
    bsr.w   WaitForVint
    addq.w  #1,(Timer_frames).w
    jsr (RandomNumber).l
    jsr (RunObjects).l
    jsr (BuildSprites).l
    tst.b   (Ending_PalCycle_flag).w
    beq.s   +
    jsrto   (PalCycle_Load).l, JmpTo_PalCycle_Load
+
    bsr.w   EndgameCredits
    tst.w   (Level_Inactive_flag).w
    beq.w   -
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; sub_9EF4
EndgameCredits:
    tst.b   (Credits_Trigger).w
    beq.w   +++ ; rts
    bsr.w   Pal_FadeToBlack
    lea (VDP_control_port).l,a6
    move.w  #$8004,(a6)     ; H-INT disabled
    move.w  #$8200|(VRAM_EndSeq_Plane_A_Name_Table/$400),(a6)   ; PNT A base: $C000
    move.w  #$8400|(VRAM_EndSeq_Plane_B_Name_Table1/$2000),(a6) ; PNT B base: $E000
    move.w  #$9001,(a6)     ; Scroll table size: 64x32
    move.w  #$9200,(a6)     ; Disable window
    move.w  #$8B03,(a6)     ; EXT-INT disabled, V scroll by screen, H scroll by line
    move.w  #$8700,(a6)     ; Background palette/color: 0/0
    clr.b   (Water_fullscreen_flag).w
    move.w  #$8C81,(a6)     ; H res 40 cells, no interlace, S/H disabled
    jsrto   (ClearScreen).l, JmpTo_ClearScreen
 
    clearRAM Sprite_Table_Input,Sprite_Table_Input_End
    clearRAM EndSeq_Object_RAM,EndSeq_Object_RAM_End
    clearRAM Misc_Variables,Misc_Variables_End
    clearRAM Camera_RAM,Camera_RAM_End
 
    clr.b   (Screen_Shaking_Flag).w
    moveq   #0,d0
    move.w  d0,(Level_Inactive_flag).w
    move.w  d0,(Timer_frames).w
    move.w  d0,(Camera_X_pos).w
    move.w  d0,(Camera_Y_pos).w
    move.w  d0,(Camera_X_pos_copy).w
    move.w  d0,(Camera_Y_pos_copy).w
    move.w  d0,(Camera_BG_X_pos).w
    move.w  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Vscroll_Factor).w
    move.b  d0,(Horiz_block_crossed_flag_BG).w
    move.b  d0,(Verti_block_crossed_flag_BG).w
    move.w  d0,(Ending_VInt_Subrout).w
    move.w  d0,(Credits_Trigger).w
 
    ; Bug: The '+4' shouldn't be here; clearRAM accidentally clears an additional 4 bytes
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End+4
 
    moveq   #MusID_Credits,d0
    jsrto   (PlaySound).l, JmpTo2_PlaySound
    clr.w   (Target_palette).w
    move.w  #$EEE,(Target_palette+$C).w
    move.w  #$EE,(Target_palette_line2+$C).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_CreditText_CredScr),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_CreditText).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    clr.w   (CreditsScreenIndex).w
-
    jsrto   (ClearScreen).l, JmpTo_ClearScreen
    bsr.w   ShowCreditsScreen
    bsr.w   Pal_FadeFromBlack
 
    ; Here's how to calculate new duration values for the below instructions.
    ; Each slide of the credits is displayed for $18E frames at 60 FPS, or $144 frames at 50 FPS.
    ; We also need to take into account how many frames the fade-in/fade-out take: which is $16 each.
    ; Also, there are 21 slides to display.
    ; That said, by doing '($18E+$16+$16)*21', we get the total number of frames it takes until
    ; the credits reach the Sonic 2 splash (which is technically not an actual slide in the credits).
    ; Dividing this by 60 will give us how many seconds it takes. The result being 154.7.
    ; Doing the same for 50 FPS, by dividing the result of '($144+$16+$16)*21' by 50, will give us 154.56.
    ; Now that we have the time it should take for the credits to end, we can adjust the calculation to account
    ; for any slides we may have added. For example, if you added a slide, bringing the total to 22,
    ; performing '((154.7*60)/22)-($16+$16)' will give you the new value to put in the 'move.w' instruction below.
    move.w  #$18E,d0
    btst    #6,(Graphics_Flags).w
    beq.s   +
    move.w  #$144,d0
 
/   move.b  #VintID_Ending,(Vint_routine).w
    bsr.w   WaitForVint
    dbf d0,-
 
    bsr.w   Pal_FadeToBlack
    lea (off_B2CA).l,a1
    addq.w  #1,(CreditsScreenIndex).w
    move.w  (CreditsScreenIndex).w,d0
    lsl.w   #2,d0
    move.l  (a1,d0.w),d0
    bpl.s   --
    bsr.w   Pal_FadeToBlack
    jsrto   (ClearScreen).l, JmpTo_ClearScreen
    move.l  #vdpComm($0000,VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingTitle).l,a0
    jsrto   (NemDec).l, JmpTo_NemDec
    lea (MapEng_EndGameLogo).l,a0
    lea (Chunk_Table).l,a1
    move.w  #0,d0
    jsrto   (EniDec).l, JmpTo_EniDec
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_Plane_A_Name_Table+planeLocH40(12,11),VRAM,WRITE),d0
    moveq   #$F,d1
    moveq   #5,d2
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo2_PlaneMapToVRAM_H40
    clr.w   (CreditsScreenIndex).w
    bsr.w   EndgameLogoFlash
 
    move.w  #$3B,d0
-   move.b  #VintID_Ending,(Vint_routine).w
    bsr.w   WaitForVint
    dbf d0,-
 
    move.w  #$257,d6
-   move.b  #VintID_Ending,(Vint_routine).w
    bsr.w   WaitForVint
    addq.w  #1,(CreditsScreenIndex).w
    bsr.w   EndgameLogoFlash
    cmpi.w  #$5E,(CreditsScreenIndex).w
    blo.s   -
    move.b  (Ctrl_1_Press).w,d1
    andi.b  #button_B_mask|button_C_mask|button_A_mask|button_start_mask,d1
    bne.s   +
    dbf d6,-
+
    st  (Level_Inactive_flag).w
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
/
    rts
; End of function sub_9EF4
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_A0C0
EndgameLogoFlash:
    lea (Normal_palette+2).w,a2
    move.w  (CreditsScreenIndex).w,d0
    cmpi.w  #$24,d0
    bhs.s   -
    btst    #0,d0
    bne.s   -
    lsr.w   #1,d0
    move.b  byte_A0EC(pc,d0.w),d0
    mulu.w  #$18,d0
    lea pal_A0FE(pc,d0.w),a1
 
    moveq   #5,d0
-   move.l  (a1)+,(a2)+
    dbf d0,-
 
    rts
; End of function EndgameLogoFlash
 
; ===========================================================================
byte_A0EC:
    dc.b   0
    dc.b   1    ; 1
    dc.b   2    ; 2
    dc.b   3    ; 3
    dc.b   4    ; 4
    dc.b   3    ; 5
    dc.b   2    ; 6
    dc.b   1    ; 7
    dc.b   0    ; 8
    dc.b   5    ; 9
    dc.b   6    ; 10
    dc.b   7    ; 11
    dc.b   8    ; 12
    dc.b   7    ; 13
    dc.b   6    ; 14
    dc.b   5    ; 15
    dc.b   0    ; 16
    dc.b   0    ; 17
 
; palette cycle for the end-of-game logo
pal_A0FE:   BINCLUDE    "art/palettes/Ending Cycle.bin"
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CA - Cut scene at end of game
; ----------------------------------------------------------------------------
; Sprite_A1D6:
ObjCA:
    addq.w  #1,objoff_32(a0)
    cmpi.w  #4,(Ending_Routine).w
    beq.s   +
    cmpi.w  #2,(Ending_Routine).w
    bne.s   +
    st  (Super_Sonic_flag).w
    move.w  #$100,(Ring_count).w
    move.b  #-1,(Super_Sonic_palette).w
+
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCA_Index(pc,d0.w),d1
    jmp ObjCA_Index(pc,d1.w)
; ===========================================================================
; off_A208:
ObjCA_Index:    offsetTable
        offsetTableEntry.w ObjCA_Init   ;  0
        offsetTableEntry.w loc_A240 ;  2
        offsetTableEntry.w loc_A24E ;  4
        offsetTableEntry.w loc_A240 ;  6
        offsetTableEntry.w loc_A256 ;  8
        offsetTableEntry.w loc_A30A ; $A
        offsetTableEntry.w loc_A34C ; $C
        offsetTableEntry.w loc_A38E ; $E
; ===========================================================================
; loc_A218:
ObjCA_Init:
    moveq   #4,d0
    move.w  #$180,d1
    btst    #6,(Graphics_Flags).w
    beq.s   sub_A22A
    move.w  #$100,d1
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_A22A:
 
    lea (EndSeqPaletteChanger).w,a1
    move.b  #ObjID_TtlScrPalChanger,id(a1) ; load objC9 (palette change handler) at $FFFFB0C0
    move.b  d0,subtype(a1)
    addq.b  #2,routine(a0)
    move.w  d1,objoff_3C(a0)
    rts
; End of function sub_A22A
 
; ===========================================================================
 
loc_A240:
    subq.w  #1,objoff_3C(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine(a0)
    rts
; ===========================================================================
 
loc_A24E:
    moveq   #6,d0
    move.w  #$80,d1
    bra.s   sub_A22A
; ===========================================================================
 
loc_A256:
    move.w  objoff_2E(a0),d0
    cmpi.w  #$10,d0
    bhs.s   +
    addq.w  #4,objoff_2E(a0)
    clr.b   routine(a0)
    move.l  a0,-(sp)
    movea.l off_A29C(pc,d0.w),a0
    lea (Chunk_Table).l,a1
    move.w  #make_art_tile(ArtTile_ArtNem_EndingPics,0,0),d0
    jsrto   (EniDec).l, JmpTo_EniDec
    move    #$2700,sr
    lea (Chunk_Table).l,a1
    move.l  #vdpComm(VRAM_Plane_A_Name_Table + planeLocH40(14,8),VRAM,WRITE),d0
    moveq   #$B,d1
    moveq   #8,d2
    jsrto   (PlaneMapToVRAM_H40).l, JmpTo2_PlaneMapToVRAM_H40
    move    #$2300,sr
    movea.l (sp)+,a0 ; load 0bj address
    rts
; ===========================================================================
off_A29C:
    dc.l MapEng_Ending1
    dc.l MapEng_Ending2
    dc.l MapEng_Ending3
    dc.l MapEng_Ending4
; ===========================================================================
+
    move.w  #2,(Ending_VInt_Subrout).w
    st  (Control_Locked).w
    st  (Ending_PalCycle_flag).w
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ending_Routine).w,d0
    move.w  ObjCA_State5_States(pc,d0.w),d0
    jsr ObjCA_State5_States(pc,d0.w)
    move.w  #$80,d1
    bsr.w   sub_A22A
    move.w  #$40,objoff_3C(a0)
    rts
; ===========================================================================
ObjCA_State5_States:    offsetTable
    offsetTableEntry.w loc_A2E0 ; 0
    offsetTableEntry.w loc_A2EE ; 2
    offsetTableEntry.w loc_A2F2 ; 4
; ===========================================================================
 
loc_A2E0:
    moveq   #8,d0
-
    move.b  #ObjID_Sonic,id(a1) ; load Sonic object
    move.b  #$81,obj_control(a1)
    rts
; ===========================================================================
 
loc_A2EE:
    moveq   #$C,d0
    bra.s   -
; ===========================================================================
 
loc_A2F2:
    moveq   #$E,d0
    move.b  #ObjID_Tails,id(a1) ; load Tails object
    move.b  #$81,obj_control(a1)
    move.b  #ObjID_TailsTails,(Tails_Tails_Cutscene+id).w ; load Obj05 (Tails' tails) at $FFFFB080
    move.w  a1,(Tails_Tails_Cutscene+parent).w
    rts
; ===========================================================================
 
loc_A30A:
    subq.w  #1,objoff_3C(a0)
    bpl.s   +
    moveq   #$A,d0
    move.w  #$80,d1
    bsr.w   sub_A22A
    move.w  #$C0,objoff_3C(a0)
+
    lea (MainCharacter).w,a1 ; a1=character
    move.b  #AniIDSonAni_Float2,anim(a1)
    move.w  #$A0,x_pos(a1)
    move.w  #$50,y_pos(a1)
    cmpi.w  #2,(Ending_Routine).w
    bne.s   +   ; rts
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.w  #$1000,inertia(a1)
+
    rts
; ===========================================================================
 
loc_A34C:
    subq.w  #1,objoff_3C(a0)
    bmi.s   +
    moveq   #0,d4
    moveq   #0,d5
    move.w  #0,(Camera_X_pos_diff).w
    move.w  #$100,(Camera_Y_pos_diff).w
    bra.w   SwScrl_DEZ
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  #$100,objoff_3C(a0)
    cmpi.w  #4,(Ending_Routine).w
    bne.s   return_A38C
    move.w  #$880,objoff_3C(a0)
    btst    #6,(Graphics_Flags).w
    beq.s   return_A38C
    move.w  #$660,objoff_3C(a0)
 
return_A38C:
    rts
; ===========================================================================
 
loc_A38E:
    btst    #6,(Graphics_Flags).w
    beq.s   +
    cmpi.w  #$E40,objoff_32(a0)
    beq.s   loc_A3BE
    bra.w   ++
; ===========================================================================
+
    cmpi.w  #$1140,objoff_32(a0)
    beq.s   loc_A3BE
+
    subq.w  #1,objoff_3C(a0)
    bne.s   +
    lea (word_AD62).l,a2
    jsrto   (LoadChildObject).l, JmpTo_LoadChildObject
+
    bra.w   loc_AB9C
; ===========================================================================
 
loc_A3BE:
    addq.b  #2,routine(a0)
    st  (Credits_Trigger).w
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CC - Trigger for rescue plane and birds from ending sequence
; ----------------------------------------------------------------------------
; Sprite_A3C8:
ObjCC:
    jsrto   (ObjB2_Animate_Pilot).l, JmpTo_ObjB2_Animate_Pilot
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCC_Index(pc,d0.w),d1
    jmp ObjCC_Index(pc,d1.w)
; ===========================================================================
; loc_A3DA:
ObjCC_Index:    offsetTable
        offsetTableEntry.w ObjCC_Init   ; 0
        offsetTableEntry.w ObjCC_Main   ; 2
; ===========================================================================
; loc_A3DE:
ObjCC_Init:
    lea (ObjB2_SubObjData).l,a1
    jsrto   (LoadSubObject_Part3).l, JmpTo_LoadSubObject_Part3
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    move.b  #4,mapping_frame(a0)
    move.b  #1,anim(a0)
+
    move.w  #-$10,x_pos(a0)
    move.w  #$C0,y_pos(a0)
    move.w  #$100,x_vel(a0)
    move.w  #-$80,y_vel(a0)
    move.b  #$14,objoff_35(a0)
    move.b  #3,priority(a0)
    move.w  #4,(Ending_VInt_Subrout).w
    move.l  a0,-(sp)
    lea (MapEng_EndingTailsPlane).l,a0
    cmpi.w  #4,(Ending_Routine).w
    bne.s   +
    lea (MapEng_EndingSonicPlane).l,a0
+
    lea (Chunk_Table).l,a1
    move.w  #make_art_tile(ArtTile_ArtNem_EndingFinalTornado,0,1),d0
    jsrto   (EniDec).l, JmpTo_EniDec
    movea.l (sp)+,a0 ; load 0bj address
    move.w  #$C00,(Normal_palette_line3).w
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
; loc_A456:
ObjCC_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjCC_State2_States(pc,d0.w),d1
    jsr ObjCC_State2_States(pc,d1.w)
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
ObjCC_State2_States: offsetTable
    offsetTableEntry.w loc_A474 ;  0
    offsetTableEntry.w loc_A4B6 ;  2
    offsetTableEntry.w loc_A5A6 ;  4
    offsetTableEntry.w loc_A6C6 ;  6
    offsetTableEntry.w loc_A7DE ;  8
    offsetTableEntry.w loc_A83E ; $A
; ===========================================================================
 
loc_A474:
    cmpi.w  #$A0,x_pos(a0)
    beq.s   +
    jsrto   (ObjectMove).l, JmpTo2_ObjectMove
-
    lea (Ani_objB2_a).l,a1
    jmpto   (AnimateSprite).l, JmpTo_AnimateSprite
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$480,objoff_3C(a0)
    btst    #6,(Graphics_Flags).w
    beq.s   +
    move.w  #$3D0,objoff_3C(a0)
+
    move.w  #$40,objoff_32(a0)
    st  (CutScene+objoff_34).w
    clr.w   x_vel(a0)
    clr.w   y_vel(a0)
    bra.s   -
; ===========================================================================
 
loc_A4B6:
    bsr.w   sub_ABBA
    bsr.w   sub_A524
    subq.w  #1,objoff_3C(a0)
    bmi.s   +
    bra.s   -
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #2,objoff_3C(a0)
    clr.w   objoff_32(a0)
    clr.b   mapping_frame(a0)
    cmpi.w  #2,(Ending_Routine).w
    beq.s   +
    move.b  #7,mapping_frame(a0)
    cmpi.w  #4,(Ending_Routine).w
    bne.s   +
    move.b  #$18,mapping_frame(a0)
+
    clr.b   anim(a0)
    clr.b   anim_frame(a0)
    clr.b   anim_frame_duration(a0)
    move.l  #ObjCF_MapUnc_ADA2,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    jsr (Adjust2PArtPointer).l
    subi.w  #$14,x_pos(a0)
    addi.w  #$14,y_pos(a0)
    bra.w   sub_A58C
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_A524:
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ending_Routine).w,d0
    move.w  off_A534(pc,d0.w),d0
    jmp off_A534(pc,d0.w)
; End of function sub_A524
 
; ===========================================================================
off_A534:   offsetTable
        offsetTableEntry.w loc_A53A ; 0
        offsetTableEntry.w loc_A55C ; 2
        offsetTableEntry.w loc_A582 ; 4
; ===========================================================================
 
loc_A53A:
    move.w  y_pos(a0),d0
    subi.w  #$1C,d0
-
    move.w  d0,y_pos(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.l  #$1000505,mapping_frame(a1)
    move.w  #$100,anim_frame_duration(a1)
    rts
; ===========================================================================
 
loc_A55C:
    tst.w   objoff_32(a0)
    beq.s   +
    subq.w  #1,objoff_32(a0)
    addi.l  #$8000,x_pos(a1)
    addq.w  #1,y_pos(a1)
    rts
; ===========================================================================
+
    move.w  #$C0,x_pos(a1)
    move.w  #$90,y_pos(a1)
    rts
; ===========================================================================
 
loc_A582:
    move.w  y_pos(a0),d0
    subi.w  #$18,d0
    bra.s   -
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_A58C:
    tst.b   (Super_Sonic_flag).w
    bne.w   return_A38C
 
loc_A594:
    lea (MainCharacter).w,a1 ; a1=character
    move.w  #$200,x_pos(a1)
    move.w  #0,y_pos(a1)
    rts
; End of function sub_A58C
 
; ===========================================================================
 
loc_A5A6:
    bsr.s   sub_A58C
    subq.w  #1,objoff_3C(a0)
    bpl.s   +   ; rts
    move.w  #2,objoff_3C(a0)
    move.w  objoff_32(a0),d0
    cmpi.w  #$1C,d0
    bhs.s   ++
    addq.w  #1,objoff_32(a0)
    move.w  (Ending_Routine).w,d1
    move.w  off_A5FC(pc,d1.w),d1
    lea off_A5FC(pc,d1.w),a1
    move.b  (a1,d0.w),mapping_frame(a0)
    add.w   d0,d0
    add.w   d0,d0
    move.l  word_A656(pc,d0.w),d1
    move.w  d1,y_pos(a0)
    swap    d1
    move.w  d1,x_pos(a0)
+
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$60,objoff_3C(a0)
    clr.b   objoff_31(a0)
    clr.w   objoff_32(a0)
    rts
; ===========================================================================
off_A5FC:   offsetTable
        offsetTableEntry.w byte_A602    ; 0
        offsetTableEntry.w byte_A61E    ; 2
        offsetTableEntry.w byte_A63A    ; 4
byte_A602:
    dc.b   7,  7,  7,  7,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9, $A, $A
    dc.b  $A, $B, $B, $B, $B, $B, $B, $B, $B, $B, $B, $B; 16
byte_A61E:
    dc.b   0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  3,  3
    dc.b   3,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4; 16
byte_A63A:
    dc.b $18,$18,$18,$18,$19,$19,$19,$19,$19,$19,$19,  9,  9,  9, $A, $A
    dc.b  $A, $B, $B, $B, $B, $B, $B, $B, $B, $B, $B, $B; 16
word_A656:
    dc.w   $A0,  $70,  $B0,  $70,  $B6,  $71,  $BC,  $72
    dc.w   $C4,  $74,  $C8,  $75,  $CA,  $76,  $CC,  $77; 8
    dc.w   $CE,  $78,  $D0,  $79,  $D2,  $7A,  $D4,  $7B; 16
    dc.w   $D6,  $7C,  $D9,  $7E,  $DC,  $81,  $DE,  $84; 24
    dc.w   $E1,  $87,  $E4,  $8B,  $E7,  $8F,  $EC,  $94; 32
    dc.w   $F0,  $99,  $F5,  $9D,  $F9,  $A4, $100,  $AC; 40
    dc.w  $108,  $B8, $112,  $C4, $11F,  $D3, $12C,  $FA; 48
; ===========================================================================
 
loc_A6C6:
    subq.w  #1,objoff_3C(a0)
    bmi.s   loc_A720
    tst.b   (Super_Sonic_flag).w
    beq.s   +   ; rts
    subq.b  #1,objoff_31(a0)
    bpl.s   +   ; rts
    addq.b  #3,objoff_31(a0)
    move.w  objoff_32(a0),d0
    addq.w  #4,objoff_32(a0)
    cmpi.w  #$78,d0
    bhs.s   +   ; rts
    cmpi.w  #$C,d0
    blo.s   ++
    bsr.w   loc_A594
    move.l  word_A766(pc,d0.w),d1
    move.w  d1,y_pos(a0)
    swap    d1
    move.w  d1,x_pos(a0)
    lsr.w   #2,d0
    move.b  byte_A748(pc,d0.w),mapping_frame(a0)
+
    rts
; ===========================================================================
+
    move.l  word_A766(pc,d0.w),d0
    lea (MainCharacter).w,a1 ; a1=character
    move.w  d0,y_pos(a1)
    swap    d0
    move.w  d0,x_pos(a1)
    rts
; ===========================================================================
 
loc_A720:
    addq.b  #2,routine_secondary(a0)
    clr.w   objoff_3C(a0)
    clr.w   objoff_32(a0)
    lea (word_AD6E).l,a2
    jsrto   (LoadChildObject).l, JmpTo_LoadChildObject
    tst.b   (Super_Sonic_flag).w
    bne.w   return_A38C
    lea (word_AD6A).l,a2
    jmpto   (LoadChildObject).l, JmpTo_LoadChildObject
; ===========================================================================
byte_A748:
    dc.b $12,$12,$12,$12,$12,$12,$12,$13,$13,$13,$13,$13,$13,$14,$14,$14
    dc.b $14,$15,$15,$15,$16,$16,$16,$16,$16,$16,$16,$16,$16,  0; 16
word_A766:
    dc.w   $C0, $90 ; 1
    dc.w   $B0, $91 ; 3
    dc.w   $A8, $92 ; 5
    dc.w   $9B, $96 ; 7
    dc.w   $99, $98 ; 9
    dc.w   $98, $99 ; 11
    dc.w   $99, $9A ; 13
    dc.w   $9B, $9C ; 15
    dc.w   $9F, $9E ; 17
    dc.w   $A4, $A0 ; 19
    dc.w   $AC, $A2 ; 21
    dc.w   $B7, $A5 ; 23
    dc.w   $C4, $A8 ; 25
    dc.w   $D3, $AB ; 27
    dc.w   $DE, $AE ; 29
    dc.w   $E8, $B0 ; 31
    dc.w   $EF, $B2 ; 33
    dc.w   $F4, $B5 ; 35
    dc.w   $F9, $B8 ; 37
    dc.w   $FC, $BB ; 39
    dc.w   $FE, $BE ; 41
    dc.w   $FF, $C0 ; 43
    dc.w  $100, $C2 ; 45
    dc.w  $101, $C5 ; 47
    dc.w  $102, $C8 ; 49
    dc.w  $102, $CC ; 51
    dc.w  $101, $D1 ; 53
    dc.w   $FD, $D7 ; 55
    dc.w   $F9, $DE ; 57
    dc.w   $F9,$118 ; 59
; ===========================================================================
 
loc_A7DE:
    bsr.w   loc_A594
    subq.w  #1,objoff_3C(a0)
    bpl.s   +   ; rts
    move.w  #2,objoff_3C(a0)
    move.w  objoff_32(a0),d0
    cmpi.w  #$1C,d0
    bhs.s   ++
    addq.w  #4,objoff_32(a0)
    lea word_A822(pc,d0.w),a1
    move.w  (a1)+,d0
    add.w   d0,(Horiz_Scroll_Buf).w
    move.w  (a1)+,d0
    add.w   d0,(Vscroll_Factor_FG).w
+
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    bset    #3,status(a0)
    clr.b   objoff_31(a0)
    clr.w   objoff_32(a0)
    rts
; ===========================================================================
word_A822:
    dc.w  -$3A
    dc.w   $88  ; 1
    dc.w   -$C  ; 2
    dc.w   $22  ; 3
    dc.w    -8  ; 4
    dc.w   $10  ; 5
    dc.w    -4  ; 6
    dc.w     8  ; 7
    dc.w    -2  ; 8
    dc.w     4  ; 9
    dc.w    -1  ; 10
    dc.w     2  ; 11
    dc.w    -1  ; 12
    dc.w     2  ; 13
; ===========================================================================
 
loc_A83E:
    tst.b   (Super_Sonic_flag).w
    beq.w   return_A38C
    move.b  #$17,mapping_frame(a0)
    subq.b  #1,objoff_31(a0)
    bpl.s   +   ; rts
    addq.b  #3,objoff_31(a0)
    move.w  objoff_32(a0),d0
    cmpi.w  #$20,d0
    bhs.s   +   ; rts
    addq.w  #4,objoff_32(a0)
    move.l  word_A874(pc,d0.w),d1
    move.w  d1,y_pos(a0)
    swap    d1
    move.w  d1,x_pos(a0)
+
    rts
; ===========================================================================
word_A874:
    dc.w   $60,$88  ; 1
    dc.w   $50,$68  ; 3
    dc.w   $44,$46  ; 5
    dc.w   $3C,$36  ; 7
    dc.w   $36,$2A  ; 9
    dc.w   $33,$24  ; 11
    dc.w   $31,$20  ; 13
    dc.w   $30,$1E  ; 15
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CE - Sonic and Tails jumping off the plane from ending sequence
; ----------------------------------------------------------------------------
; Sprite_A894:
ObjCE:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCE_Index(pc,d0.w),d1
    jmp ObjCE_Index(pc,d1.w)
; ===========================================================================
; off_A8A2:
ObjCE_Index:    offsetTable
        offsetTableEntry.w ObjCE_Init               ; 0
        offsetTableEntry.w loc_A902             ; 2
        offsetTableEntry.w loc_A936             ; 4
        offsetTableEntry.w BranchTo_JmpTo5_DisplaySprite    ; 6
; ===========================================================================
; loc_A8AA:
ObjCE_Init:
    lea (ObjB3_SubObjData).l,a1
    jsrto   (LoadSubObject_Part3).l, JmpTo_LoadSubObject_Part3
    move.l  #ObjCF_MapUnc_ADA2,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,1),art_tile(a0)
    move.b  #1,priority(a0)
    jsr (Adjust2PArtPointer).l
    move.b  #$C,mapping_frame(a0)
    cmpi.w  #4,(Ending_Routine).w
    bne.s   +
    move.b  #$F,mapping_frame(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,1,1),art_tile(a0)
+
    move.w  #$E8,d0
    move.w  d0,x_pos(a0)
    move.w  d0,objoff_30(a0)
    move.w  #$118,d0
    move.w  d0,y_pos(a0)
    move.w  d0,objoff_32(a0)
    rts
; ===========================================================================
 
loc_A902:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #3,status(a1)
    bne.s   +
 
loc_A90E:
    move.w  objoff_30(a0),d0
    add.w   (Horiz_Scroll_Buf).w,d0
    move.w  d0,x_pos(a0)
    move.w  objoff_32(a0),d0
    sub.w   (Vscroll_Factor_FG).w,d0
    move.w  d0,y_pos(a0)
 
BranchTo_JmpTo5_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
+
    addq.b  #2,routine(a0)
    clr.w   objoff_3C(a0)
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
 
loc_A936:
    subq.w  #1,objoff_3C(a0)
    bpl.s   BranchTo2_JmpTo5_DisplaySprite
    move.w  #4,objoff_3C(a0)
    move.w  objoff_34(a0),d0
    cmpi.w  #4,d0
    bhs.s   ++
    addq.w  #2,objoff_34(a0)
    lea byte_A980(pc,d0.w),a1
    cmpi.w  #2,(Ending_Routine).w
    bne.s   +
    lea byte_A984(pc,d0.w),a1
+
    move.b  (a1)+,d0
    ext.w   d0
    add.w   d0,x_pos(a0)
    move.b  (a1)+,d0
    ext.w   d0
    add.w   d0,y_pos(a0)
    addq.b  #1,mapping_frame(a0)
 
BranchTo2_JmpTo5_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
+
    addq.b  #2,routine(a0)
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
byte_A980:
    dc.b   -8,   0
    dc.b -$44,-$38  ; 2
byte_A984:
    dc.b   -8,   0
    dc.b -$50,-$40  ; 2
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CF - "Plane's helixes" from ending sequence
; ----------------------------------------------------------------------------
; Sprite_A988:
ObjCF:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCF_Index(pc,d0.w),d1
    jmp ObjCF_Index(pc,d1.w)
; ===========================================================================
; off_A996:
ObjCF_Index:    offsetTable
        offsetTableEntry.w ObjCF_Init       ; 0
        offsetTableEntry.w ObjCF_Animate    ; 2
; ===========================================================================
; loc_A99A:
ObjCF_Init:
    lea (ObjB3_SubObjData).l,a1
    jsrto   (LoadSubObject_Part3).l, JmpTo_LoadSubObject_Part3
    move.l  #ObjCF_MapUnc_ADA2,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,1),art_tile(a0)
    move.b  #3,priority(a0)
    jsr (Adjust2PArtPointer).l
    move.b  #5,mapping_frame(a0)
    move.b  #2,anim(a0)
    move.w  #$10F,d0
    move.w  d0,x_pos(a0)
    move.w  d0,objoff_30(a0)
    move.w  #$15E,d0
    move.w  d0,y_pos(a0)
    move.w  d0,objoff_32(a0)
    rts
; ===========================================================================
; loc_A9E4:
ObjCF_Animate:
    lea (Ani_objCF).l,a1
    jsrto   (AnimateSprite).l, JmpTo_AnimateSprite
    bra.w   loc_A90E
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CB - Background clouds from ending sequence
; ----------------------------------------------------------------------------
; Sprite_A9F2:
ObjCB:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCB_Index(pc,d0.w),d1
    jmp ObjCB_Index(pc,d1.w)
; ===========================================================================
; off_AA00:
ObjCB_Index:    offsetTable
        offsetTableEntry.w ObjCB_Init   ; 0
        offsetTableEntry.w loc_AA76 ; 2
        offsetTableEntry.w loc_AA8A ; 4
; ===========================================================================
; loc_AA06:
ObjCB_Init:
    lea (ObjB3_SubObjData).l,a1
    jsrto   (LoadSubObject_Part3).l, JmpTo_LoadSubObject_Part3
    move.w  art_tile(a0),d0
    andi.w  #$1FFF,d0
    ori.w   #palette_mask,d0
    move.w  d0,art_tile(a0)
    move.b  #$30,width_pixels(a0)
    move.l  (RNG_seed).w,d0
    ror.l   #1,d0
    move.l  d0,(RNG_seed).w
    move.w  d0,d1
    andi.w  #3,d0
    move.b  ObjCB_Frames(pc,d0.w),mapping_frame(a0)
    add.w   d0,d0
    move.w  ObjCB_YSpeeds(pc,d0.w),y_vel(a0)
    tst.b   (CutScene+$34).w
    beq.s   +
    andi.w  #$FF,d1
    move.w  d1,y_pos(a0)
    move.w  #$150,x_pos(a0)
    rts
; ===========================================================================
+
    andi.w  #$1FF,d1
    move.w  d1,x_pos(a0)
    move.w  #$100,y_pos(a0)
    rts
; ===========================================================================
; byte_AA6A:
ObjCB_Frames:
    dc.b   0
    dc.b   1    ; 1
    dc.b   2    ; 2
    dc.b   0    ; 3
; word_AA6E:
ObjCB_YSpeeds:
    dc.w -$300
    dc.w -$200  ; 1
    dc.w -$100  ; 2
    dc.w -$300  ; 3
; ===========================================================================
 
loc_AA76:
    tst.b   (CutScene+objoff_34).w
    beq.s   loc_AA8A
    addq.b  #2,routine(a0)
    move.w  y_vel(a0),x_vel(a0)
    clr.w   y_vel(a0)
 
loc_AA8A:
    jsrto   (ObjectMove).l, JmpTo2_ObjectMove
    tst.b   (CutScene+objoff_34).w
    beq.s   +
    cmpi.w  #-$20,x_pos(a0)
    blt.w   JmpTo3_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
+
    tst.w   y_pos(a0)
    bmi.w   JmpTo3_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object CD - Birds from ending sequence
; ----------------------------------------------------------------------------
endingbird_delay    = objoff_3C ; delay before doing the next action
; Sprite_AAAE:
ObjCD:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjCD_Index(pc,d0.w),d1
    jmp ObjCD_Index(pc,d1.w)
; ===========================================================================
; off_AABC:
ObjCD_Index:    offsetTable
        offsetTableEntry.w ObjCD_Init   ; 0
        offsetTableEntry.w ObjCD_Main   ; 2
; ===========================================================================
; loc_AAC0:
ObjCD_Init:
    lea (Obj28_SubObjData).l,a1
    jsrto   (LoadSubObject_Part3).l, JmpTo_LoadSubObject_Part3
    move.l  (RNG_seed).w,d0
    ror.l   #3,d0
    move.l  d0,(RNG_seed).w
    move.l  d0,d1
    andi.w  #$7F,d0
    move.w  #-$A0,d2
    add.w   d0,d2
    move.w  d2,x_pos(a0)
    ror.l   #3,d1
    andi.w  #$FF,d1
    moveq   #8,d2
    add.w   d1,d2
    move.w  d2,y_pos(a0)
    move.w  #$100,x_vel(a0)
    moveq   #$20,d0
    cmpi.w  #$20,d1
    blo.s   +
    neg.w   d0
+
    move.w  d0,y_vel(a0)
    move.w  #$C0,endingbird_delay(a0)
    rts
; ===========================================================================
; loc_AB0E:
ObjCD_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjCD_Main_States(pc,d0.w),d1
    jsr ObjCD_Main_States(pc,d1.w)
    jsrto   (ObjectMove).l, JmpTo2_ObjectMove
    lea (Ani_objCD).l,a1
    jsrto   (AnimateSprite).l, JmpTo_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo5_DisplaySprite
; ===========================================================================
ObjCD_Main_States:  offsetTable
    offsetTableEntry.w loc_AB34 ; 0
    offsetTableEntry.w loc_AB5C ; 2
    offsetTableEntry.w loc_AB8E ; 4
; ===========================================================================
 
loc_AB34:
    subq.w  #1,endingbird_delay(a0)
    bpl.s   +   ; rts
    addq.b  #2,routine_secondary(a0)
    move.w  y_vel(a0),objoff_2E(a0)
    clr.w   x_vel(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.w  #$80,y_vel(a0)
    move.w  #$180,endingbird_delay(a0)
+
    rts
; ===========================================================================
 
loc_AB5C:
    subq.w  #1,endingbird_delay(a0)
    bmi.s   ++
    move.w  y_pos(a0),d0
    moveq   #-4,d1
    cmp.w   objoff_32(a0),d0
    bhs.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #-$100,x_vel(a0)
    move.w  objoff_2E(a0),y_vel(a0)
    move.w  #$C0,endingbird_delay(a0)
    rts
; ===========================================================================
 
loc_AB8E:
    subq.w  #1,endingbird_delay(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.w  #4,sp
 
    if removeJmpTos
JmpTo3_DeleteObject 
    endif
 
    jmpto   (DeleteObject).l, JmpTo3_DeleteObject
; ===========================================================================
 
loc_AB9C:
    subq.w  #1,objoff_30(a0)
    bpl.s   +   ; rts
    move.l  (RNG_seed).w,d0
    andi.w  #$1F,d0
    move.w  d0,objoff_30(a0)
    lea (word_AD5E).l,a2
    jsrto   (LoadChildObject).l, JmpTo_LoadChildObject
+
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_ABBA:
    subq.w  #1,objoff_30(a0)
    bpl.s   +   ; rts
    tst.b   objoff_35(a0)
    beq.s   +   ; rts
    subq.b  #1,objoff_35(a0)
    move.l  (RNG_seed).w,d0
    andi.w  #$F,d0
    move.w  d0,objoff_30(a0)
    lea (word_AD66).l,a2
    jsrto   (LoadChildObject).l, JmpTo_LoadChildObject
+   rts
; End of function sub_ABBA
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; sub_ABE2:
EndingSequence_LoadCharacterArt:
    move.w  (Ending_Routine).w,d0
    move.w  EndingSequence_LoadCharacterArt_Characters(pc,d0.w),d0
    jmp EndingSequence_LoadCharacterArt_Characters(pc,d0.w)
; End of function EndingSequence_LoadCharacterArt
 
; ===========================================================================
EndingSequence_LoadCharacterArt_Characters: offsetTable
    offsetTableEntry.w EndingSequence_LoadCharacterArt_Sonic    ; 0
    offsetTableEntry.w EndingSequence_LoadCharacterArt_SuperSonic   ; 2
    offsetTableEntry.w EndingSequence_LoadCharacterArt_Tails    ; 4
; ===========================================================================
; loc_ABF4:
EndingSequence_LoadCharacterArt_Sonic:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_EndingCharacter),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingSonic).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
; ===========================================================================
; loc_AC08:
EndingSequence_LoadCharacterArt_SuperSonic:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_EndingCharacter),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingSuperSonic).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
; ===========================================================================
; loc_AC1C:
EndingSequence_LoadCharacterArt_Tails:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_EndingCharacter),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_EndingTails).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; sub_AC30:
EndingSequence_LoadFlickyArt:
    move.w  (Ending_Routine).w,d0
    move.w  EndingSequence_LoadFlickyArt_Flickies(pc,d0.w),d0
    jmp EndingSequence_LoadFlickyArt_Flickies(pc,d0.w)
; End of function EndingSequence_LoadFlickyArt
 
; ===========================================================================
EndingSequence_LoadFlickyArt_Flickies: offsetTable
    offsetTableEntry.w EndingSequence_LoadFlickyArt_Bird    ; 0
    offsetTableEntry.w EndingSequence_LoadFlickyArt_Eagle   ; 2
    offsetTableEntry.w EndingSequence_LoadFlickyArt_Chicken ; 4
; ===========================================================================
; loc_AC42:
EndingSequence_LoadFlickyArt_Bird:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Animal_2),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Bird).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
; ===========================================================================
; loc_AC56:
EndingSequence_LoadFlickyArt_Eagle:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Animal_2),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Eagle).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
; ===========================================================================
; loc_AC6A:
EndingSequence_LoadFlickyArt_Chicken:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_Animal_2),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_Chicken).l,a0
    jmpto   (NemDec).l, JmpTo_NemDec
; ===========================================================================
Pal_AC7E:   BINCLUDE    "art/palettes/Ending Sonic.bin"
Pal_AC9E:   BINCLUDE    "art/palettes/Ending Sonic Far.bin"
Pal_ACDE:   BINCLUDE    "art/palettes/Ending Background.bin"
Pal_AD1E:   BINCLUDE    "art/palettes/Ending Photos.bin"
Pal_AD3E:   BINCLUDE    "art/palettes/Ending Super Sonic.bin"
 
word_AD5E:
    dc.w objoff_3E
    dc.b ObjID_EndingSeqClouds
    dc.b $00
word_AD62:
    dc.w objoff_3E
    dc.b ObjID_EndingSeqTrigger
    dc.b $00
word_AD66:
    dc.w objoff_3E
    dc.b ObjID_EndingSeqBird
    dc.b $00
word_AD6A:
    dc.w objoff_3E
    dc.b ObjID_EndingSeqSonic
    dc.b $00
word_AD6E:
    dc.w objoff_3E
    dc.b ObjID_TornadoHelixes
    dc.b $00
 
; off_AD72:
Obj28_SubObjData:
    subObjData Obj28_MapUnc_11E1C,make_art_tile(ArtTile_ArtNem_Animal_2,0,0),4,2,8,0
 
; animation script
; byte_AD7C
Ani_objCD:  offsetTable
        offsetTableEntry.w byte_AD7E    ; 0
byte_AD7E:  dc.b   5,  0,  1,$FF
 
; animation script
; off_AD82
Ani_objCF:  offsetTable
        offsetTableEntry.w byte_AD88    ; 0
        offsetTableEntry.w byte_AD8E    ; 1
        offsetTableEntry.w byte_AD9E    ; 2
byte_AD88:  dc.b   3,  0,  0,  1,$FA,  0
byte_AD8E:  dc.b   3,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  3,  3,  4,$FA,  0
byte_AD9E:  dc.b   1,  5,  6,$FF
    even
; -----------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------
ObjCF_MapUnc_ADA2:  BINCLUDE "mappings/sprite/objCF.bin"
; --------------------------------------------------------------------------------------
; Enigma compressed art mappings
; "Sonic the Hedgehog 2" mappings       ; MapEng_B23A:
MapEng_EndGameLogo: BINCLUDE    "mappings/misc/Sonic 2 end of game logo.bin"
    even
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_B262
ShowCreditsScreen:
    lea off_B2CA(pc),a1
    move.w  (CreditsScreenIndex).w,d0
    lsl.w   #2,d0
    move.l  (a1,d0.w),d0
    movea.l d0,a1
 
loc_B272:
    move    #$2700,sr
    lea (VDP_data_port).l,a6
-
    move.l  (a1)+,d0
    bmi.s   ++
    movea.l d0,a2
    move.w  (a1)+,d0
    bsr.s   sub_B29E
    move.l  d0,4(a6)
    move.b  (a2)+,d0
    lsl.w   #8,d0
-
    move.b  (a2)+,d0
    bmi.s   +
    move.w  d0,(a6)
    bra.s   -
; ===========================================================================
+   bra.s   --
; ===========================================================================
+
    move    #$2300,sr
    rts
; End of function ShowCreditsScreen
 
 
; ---------------------------------------------------------------------------
; Subroutine to convert a VRAM address into a 32-bit VRAM write command word
; Input:
;   d0  VRAM address (word)
; Output:
;   d0  32-bit VDP command word for a VRAM write to specified address.
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_B29E:
    andi.l  #$FFFF,d0
    lsl.l   #2,d0
    lsr.w   #2,d0
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d0
    swap    d0
    rts
; End of function sub_B29E
 
; ===========================================================================
 
; macro for declaring pointer/position structures for intro/credit text
vram_pnt := VRAM_Plane_A_Name_Table
creditsPtrs macro addr,pos
    if "addr"<>""
        dc.l addr
        dc.w vram_pnt + pos
        shift
        shift
        creditsPtrs ALLARGS
    else
        dc.w -1
    endif
    endm
 
textLoc function col,line,(($80 * line) + (2 * col))
 
; intro text pointers (one intro screen)
vram_pnt := VRAM_TtlScr_Plane_A_Name_Table
off_B2B0: creditsPtrs   byte_BD1A,textLoc($0F,$09), byte_BCEE,textLoc($11,$0C), \
            byte_BCF6,textLoc($03,$0F), byte_BCE9,textLoc($12,$12)
 
; credits screen pointer table
off_B2CA:
    dc.l off_B322, off_B336, off_B34A, off_B358 ; 3
    dc.l off_B366, off_B374, off_B388, off_B3A8 ; 7
    dc.l off_B3C2, off_B3DC, off_B3F0, off_B41C ; 11
    dc.l off_B436, off_B450, off_B45E, off_B490 ; 15
    dc.l off_B4B0, off_B4C4, off_B4F0, off_B51C ; 19
    dc.l off_B548, -1               ; 21
 
; credits text pointers for each screen of credits
vram_pnt := VRAM_Plane_A_Name_Table
off_B322: creditsPtrs   byte_BC46,textLoc($0E,$0B), byte_BC51,textLoc($18,$0B), byte_BC55,textLoc($02,$0F)
off_B336: creditsPtrs   byte_B55C,textLoc($03,$0B), byte_B56F,textLoc($16,$0B), byte_B581,textLoc($06,$0F)
off_B34A: creditsPtrs   byte_B56F,textLoc($0C,$0B), byte_B59F,textLoc($07,$0F)
off_B358: creditsPtrs   byte_B5BC,textLoc($0C,$0B), byte_B5CD,textLoc($06,$0F)
off_B366: creditsPtrs   byte_B5EB,textLoc($05,$0B), byte_B60C,textLoc($07,$0F)
off_B374: creditsPtrs   byte_B628,textLoc($08,$0A), byte_B642,textLoc($04,$0E), byte_B665,textLoc($0A,$10)
off_B388: creditsPtrs   byte_B67B,textLoc($04,$08), byte_B69C,textLoc($11,$0A), byte_B6A4,textLoc($09,$0C), byte_B6BC,textLoc($04,$10), byte_B6DE,textLoc($08,$12)
off_B3A8: creditsPtrs   byte_B6F8,textLoc($0B,$09), byte_B70B,textLoc($09,$0B), byte_B723,textLoc($0A,$0F), byte_B738,textLoc($03,$11)
off_B3C2: creditsPtrs   byte_B75C,textLoc($04,$09), byte_B642,textLoc($04,$0D), byte_B77E,textLoc($07,$0F), byte_B799,textLoc($07,$11)
off_B3DC: creditsPtrs   byte_B7B5,textLoc($08,$0A), byte_B75C,textLoc($04,$0C), byte_B799,textLoc($07,$10)
off_B3F0: creditsPtrs   byte_B7F2,textLoc($09,$06), byte_B6BC,textLoc($04,$0A), byte_B80B,textLoc($0A,$0C), byte_B821,textLoc($09,$0E), byte_B839,textLoc($07,$10), byte_B855,textLoc($0B,$12), byte_B869,textLoc($0B,$14)
off_B41C: creditsPtrs   byte_B7B5,textLoc($09,$09), byte_B87D,textLoc($0A,$0B), byte_B893,textLoc($0B,$0F), byte_B8A8,textLoc($07,$11)
off_B436: creditsPtrs   byte_B8C5,textLoc($06,$09), byte_B8E2,textLoc($05,$0D), byte_B902,textLoc($03,$0F), byte_B90F,textLoc($04,$11)
off_B450: creditsPtrs   byte_B932,textLoc($04,$0B), byte_B954,textLoc($05,$0F)
off_B45E: creditsPtrs   byte_B974,textLoc($04,$05), byte_B995,textLoc($0F,$09), byte_B9A1,textLoc($0F,$0B), byte_B9AD,textLoc($0F,$0D), byte_B9B8,textLoc($10,$0F), byte_B9C1,textLoc($11,$11), byte_B9C8,textLoc($11,$13), byte_B9D0,textLoc($0F,$15)
off_B490: creditsPtrs   byte_B9DB,textLoc($03,$08), byte_BA00,textLoc($08,$0C), byte_BA1B,textLoc($06,$0E), byte_BA3A,textLoc($09,$10), byte_BA52,textLoc($0A,$12)
off_B4B0: creditsPtrs   byte_BA69,textLoc($09,$0A), byte_BA81,textLoc($05,$0E), byte_B7CE,textLoc($03,$10)
off_B4C4: creditsPtrs   byte_B55C,textLoc($0B,$06), byte_BAA2,textLoc($0A,$08), byte_BAB8,textLoc($03,$0C), byte_BADC,textLoc($07,$0E), byte_BAF7,textLoc($05,$10), byte_BB16,textLoc($07,$12), byte_BB32,textLoc($02,$14)
off_B4F0: creditsPtrs   byte_BB58,textLoc($06,$06), byte_BB75,textLoc($12,$08), byte_BB7B,textLoc($06,$0C), byte_BC9F,textLoc($05,$0E), byte_BBD8,textLoc($08,$10), byte_BBF2,textLoc($08,$12), byte_BC0C,textLoc($09,$14)
off_B51C: creditsPtrs   byte_BB58,textLoc($06,$06), byte_BB75,textLoc($12,$08), byte_BB98,textLoc($03,$0C), byte_BBBC,textLoc($07,$0E), byte_BCBE,textLoc($07,$10), byte_BCD9,textLoc($0D,$12), byte_BC25,textLoc($04,$14)
off_B548: creditsPtrs   byte_BC7B,textLoc($0B,$09), byte_BC8F,textLoc($12,$0D), byte_BC95,textLoc($10,$11)
 
 ; temporarily remap characters to credit text format
 ; let's encode 2-wide characters like Aa, Bb, Cc, etc. and hide it with a macro
 charset '@',"\x3B\2\4\6\8\xA\xC\xE\x10\x12\x13\x15\x17\x19\x1B\x1D\x1F\x21\x23\x25\x27\x29\x2B\x2D\x2F\x31\x33"
 charset 'a',"\3\5\7\9\xB\xD\xF\x11\x12\x14\x16\x18\x1A\x1C\x1E\x20\x22\x24\x26\x28\x2A\x2C\x2E\x30\x32\x34"
 charset '!',"\x3D\x39\x3F\x36"
 charset '\H',"\x39\x37\x38"
 charset '9',"\x3E\x40\x41"
 charset '1',"\x3C\x35"
 charset '.',"\x3A"
 charset ' ',0
 
 ; macro for defining credit text in conjunction with the remapped character set
vram_src := ArtTile_ArtNem_CreditText_CredScr
creditText macro pal,ss
    if ((vram_src & $FF) <> $0) && ((vram_src & $FF) <> $1)
        fatal "The low byte of vram_src was $\{vram_src & $FF}, but it must be $00 or $01."
    endif
c := 0
    dc.b (make_art_tile(vram_src,pal,0) & $FF00) >> 8
    rept strlen(ss)
t := substr(ss,c,1)
    dc.b t
l := lowstring(t)
    if t="I"
    elseif l<>t
        dc.b l
    elseif t="1"
        dc.b "!"
    elseif t="2"
        dc.b "$"
    elseif t="9"
        dc.b "#"
    endif
c := c+1
    endm
    dc.b -1
    rev02even
    endm
 
; credits text data (palette index followed by a string)
vram_src := ArtTile_ArtNem_CreditText_CredScr
byte_B55C:  creditText 1,"EXECUTIVE"
byte_B56F:  creditText 1,"PRODUCER"
byte_B581:  creditText 0,"HAYAO  NAKAYAMA"
byte_B59F:  creditText 0,"SHINOBU  TOYODA"
byte_B5BC:  creditText 1,"DIRECTOR"
byte_B5CD:  creditText 0,"MASAHARU  YOSHII"
byte_B5EB:  creditText 1,"CHIEF  PROGRAMMER"
byte_B60C:  creditText 0,"YUJI  NAKA (YU2)"
byte_B628:  creditText 1,"GAME  PLANNER"
byte_B642:  creditText 0,"HIROKAZU  YASUHARA"
byte_B665:  creditText 0,"(CAROL  YAS)"
byte_B67B:  creditText 1,"CHARACTER  DESIGN"
byte_B69C:  creditText 1,"AND"
byte_B6A4:  creditText 1,"CHIEF  ARTIST"
byte_B6BC:  creditText 0,"YASUSHI  YAMAGUCHI"
byte_B6DE:  creditText 0,"(JUDY  TOTOYA)"
byte_B6F8:  creditText 1,"ASSISTANT"
byte_B70B:  creditText 1,"PROGRAMMERS"
byte_B723:  creditText 0,"BILL  WILLIS"
byte_B738:  creditText 0,"MASANOBU  YAMAMOTO"
byte_B75C:  creditText 1,"OBJECT  PLACEMENT"
byte_B77E:  creditText 0,"TAKAHIRO  ANTO"
byte_B799:  creditText 0,"YUTAKA  SUGANO"
byte_B7B5:  creditText 1,"SPECIALSTAGE"
byte_B7CE:  creditText 0,"CAROL  ANN  HANSHAW"
byte_B7F2:  creditText 1,"ZONE  ARTISTS"
byte_B80B:  creditText 0,"CRAIG  STITT"
byte_B821:  creditText 0,"BRENDA  ROSS"
byte_B839:  creditText 0,"JINA  ISHIWATARI"
byte_B855:  creditText 0,"TOM  PAYNE"
byte_B869:  creditText 0,"PHENIX  RIE"
byte_B87D:  creditText 1,"ART  AND  CG"
byte_B893:  creditText 0,"TIM  SKELLY"
byte_B8A8:  creditText 0,"PETER  MORAWIEC"
byte_B8C5:  creditText 1,"MUSIC  COMPOSER"
byte_B8E2:  creditText 0,"MASATO  NAKAMURA"
byte_B902:  creditText 0,"( @1992"
byte_B90F:  creditText 0,"DREAMS  COME  TRUE)"
byte_B932:  creditText 1,"SOUND  PROGRAMMER"
byte_B954:  creditText 0,"TOMOYUKI  SHIMADA"
byte_B974:  creditText 1,"SOUND  ASSISTANTS"
byte_B995:  creditText 0,"MACKY"
byte_B9A1:  creditText 0,"JIMITA"
byte_B9AD:  creditText 0,"MILPO"
byte_B9B8:  creditText 0,"IPPO"
byte_B9C1:  creditText 0,"S.O"
byte_B9C8:  creditText 0,"OYZ"
byte_B9D0:  creditText 0,"N.GEE"
byte_B9DB:  creditText 1,"PROJECT  ASSISTANTS"
byte_BA00:  creditText 0,"SYUICHI  KATAGI"
byte_BA1B:  creditText 0,"TAKAHIRO  HAMANO"
byte_BA3A:  creditText 0,"YOSHIKI  OOKA"
byte_BA52:  creditText 0,"STEVE  WOITA"
byte_BA69:  creditText 1,"GAME  MANUAL"
byte_BA81:  creditText 0,"YOUICHI  TAKAHASHI"
byte_BAA2:  creditText 1,"SUPPORTERS"
byte_BAB8:  creditText 0,"DAIZABUROU  SAKURAI"
byte_BADC:  creditText 0,"HISASHI  SUZUKI"
    if gameRevision=0
byte_BAF7:  creditText 0,"TOHMAS  KALINSKE" ; typo
    else
byte_BAF7:  creditText 0,"THOMAS  KALINSKE"
    endif
byte_BB16:  creditText 0,"FUJIO  MINEGISHI"
byte_BB32:  creditText 0,"TAKAHARU UTSUNOMIYA"
byte_BB58:  creditText 1,"SPECIAL  THANKS"
byte_BB75:  creditText 1,"TO"
byte_BB7B:  creditText 0,"CINDY  CLAVERAN"
byte_BB98:  creditText 0,"DEBORAH  MCCRACKEN"
byte_BBBC:  creditText 0,"TATSUO  YAMADA"
byte_BBD8:  creditText 0,"DAISUKE  SAITO"
byte_BBF2:  creditText 0,"KUNITAKE  AOKI"
byte_BC0C:  creditText 0,"TSUNEKO  AOKI"
byte_BC25:  creditText 0,"MASAAKI  KAWAMURA"
byte_BC46:  creditText 0,"SONIC"
byte_BC51:  creditText 1,"2"
byte_BC55:  creditText 0,"CAST  OF  CHARACTERS"
byte_BC7B:  creditText 0,"PRESENTED"
byte_BC8F:  creditText 0,"BY"
byte_BC95:  creditText 0,"SEGA"
byte_BC9F:  creditText 0,"FRANCE  TANTIADO"
byte_BCBE:  creditText 0,"RICK  MACARAEG"
byte_BCD9:  creditText 0,"LOCKY  P"
 
 charset ; have to revert character set before changing again
 
 ; temporarily remap characters to intro text format
 charset '@',"\x3A\1\3\5\7\9\xB\xD\xF\x11\x12\x14\x16\x18\x1A\x1C\x1E\x20\x22\x24\x26\x28\x2A\x2C\x2E\x30\x32"
 charset 'a',"\2\4\6\8\xA\xC\xE\x10\x11\x13\x15\x17\x19\x1B\x1D\x1F\x21\x23\x25\x27\x29\x2B\x2D\x2F\x31\x33"
 charset '!',"\x3C\x38\x3E\x35"
 charset '\H',"\x38\x36\x37"
 charset '9',"\x3D\x3F\x40"
 charset '1',"\x3B\x34"
 charset '.',"\x39"
 charset ' ',0
 
; intro text
vram_src := ArtTile_ArtNem_CreditText
byte_BCE9:  creditText   0,"IN"
byte_BCEE:  creditText   0,"AND"
byte_BCF6:  creditText   0,"MILES 'TAILS' PROWER"
byte_BD1A:  creditText   0,"SONIC"
 
 charset ; revert character set
 
    even
 
; -------------------------------------------------------------------------------
; Nemesis compressed art
; 64 blocks
; Standard font used in credits
; -------------------------------------------------------------------------------
; ArtNem_BD26:
ArtNem_CreditText:  BINCLUDE    "art/nemesis/Credit Text.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo5_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo3_DeleteObject 
    jmp (DeleteObject).l
JmpTo2_PlaySound 
    jmp (PlaySound).l
JmpTo_ObjB2_Animate_Pilot 
    jmp (ObjB2_Animate_Pilot).l
JmpTo_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo_NemDec 
    jmp (NemDec).l
JmpTo_EniDec 
    jmp (EniDec).l
JmpTo_ClearScreen 
    jmp (ClearScreen).l
JmpTo2_PlayMusic 
    jmp (PlayMusic).l
JmpTo_LoadChildObject 
    jmp (LoadChildObject).l
; JmpTo2_PlaneMapToVRAM_H40 
JmpTo2_PlaneMapToVRAM_H40 
    jmp (PlaneMapToVRAM_H40).l
JmpTo2_ObjectMove 
    jmp (ObjectMove).l
JmpTo_PalCycle_Load 
    jmp (PalCycle_Load).l
JmpTo_LoadSubObject_Part3 
    jmp (LoadSubObject_Part3).l
 
    align 4
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to load level boundaries and start locations
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_BFBC:
LevelSizeLoad:
    clr.w   (Scroll_flags).w
    clr.w   (Scroll_flags_BG).w
    clr.w   (Scroll_flags_BG2).w
    clr.w   (Scroll_flags_BG3).w
    clr.w   (Scroll_flags_P2).w
    clr.w   (Scroll_flags_BG_P2).w
    clr.w   (Scroll_flags_BG2_P2).w
    clr.w   (Scroll_flags_BG3_P2).w
    clr.w   (Scroll_flags_copy).w
    clr.w   (Scroll_flags_BG_copy).w
    clr.w   (Scroll_flags_BG2_copy).w
    clr.w   (Scroll_flags_BG3_copy).w
    clr.w   (Scroll_flags_copy_P2).w
    clr.w   (Scroll_flags_BG_copy_P2).w
    clr.w   (Scroll_flags_BG2_copy_P2).w
    clr.w   (Scroll_flags_BG3_copy_P2).w
    clr.b   (Deform_lock).w
    clr.b   (Screen_Shaking_Flag_HTZ).w
    clr.b   (Screen_Shaking_Flag).w
    clr.b   (Scroll_lock).w
    clr.b   (Scroll_lock_P2).w
    moveq   #0,d0
    move.b  d0,(Dynamic_Resize_Routine).w ; load level boundaries
    if gameRevision=2
    move.w  d0,(WFZ_LevEvent_Subrout).w
    move.w  d0,(WFZ_BG_Y_Speed).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  d0,(Camera_BG_Y_offset).w
    endif
    move.w  (Current_ZoneAndAct).w,d0
    ror.b   #1,d0
    lsr.w   #4,d0
    lea LevelSize(pc,d0.w),a0
    move.l  (a0)+,d0
    move.l  d0,(Camera_Min_X_pos).w
    move.l  d0,(unk_EEC0).w ; unused besides this one write...
    move.l  d0,(Tails_Min_X_pos).w
    move.l  (a0)+,d0
    move.l  d0,(Camera_Min_Y_pos).w
    ; Warning: unk_EEC4 is only a word long, this line also writes to Camera_Max_Y_pos
    ; If you remove this instruction, the camera will scroll up until it kills Sonic
    move.l  d0,(unk_EEC4).w ; unused besides this one write... 
    move.l  d0,(Tails_Min_Y_pos).w
    move.w  #$1010,(Horiz_block_crossed_flag).w
    move.w  #(224/2)-16,(Camera_Y_pos_bias).w
    move.w  #(224/2)-16,(Camera_Y_pos_bias_P2).w
    bra.w   +
; ===========================================================================
; ----------------------------------------------------------------------------
; LEVEL SIZE ARRAY
 
; This array defines the screen boundaries for each act in the game.
; ----------------------------------------------------------------------------
;               xstart  xend    ystart  yend    ; ZID ; Zone
LevelSize: zoneOrderedTable 2,8 ; WrdArr_LvlSize
    zoneTableEntry.w    $0, $29A0,  $0, $320    ; EHZ act 1
    zoneTableEntry.w    $0, $2940,  $0, $420    ; EHZ act 2
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; $01
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; $02
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; $03
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $2280,  -$100,  $800    ; MTZ act 1
    zoneTableEntry.w    $0, $1E80,  -$100,  $800    ; MTZ act 2
    zoneTableEntry.w    $0, $2A80,  -$100,  $800    ; MTZ act 3
    zoneTableEntry.w    $0, $3FFF,  -$100,  $800
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; WFZ
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $2800,  $0, $720    ; HTZ act 1
    zoneTableEntry.w    $0, $3280,  $0, $720    ; HTZ act 2
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; $08
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $3FFF,  $0, $720    ; $09
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEntry.w    $0, $2F80,  $0, $680    ; OOZ act 1
    zoneTableEntry.w    $0, $2D00,  $0, $680    ; OOZ act 2
    zoneTableEntry.w    $0, $2380,  $3C0,   $720    ; MCZ act 1
    zoneTableEntry.w    $0, $3FFF,  $60,    $720    ; MCZ act 2
    zoneTableEntry.w    $0, $27A0,  $0, $720    ; CNZ act 1
    zoneTableEntry.w    $0, $2A80,  $0, $720    ; CNZ act 2
    zoneTableEntry.w    $0, $2780,  $0, $720    ; CPZ act 1
    zoneTableEntry.w    $0, $2A80,  $0, $720    ; CPZ act 2
    zoneTableEntry.w    $0, $1000,  $C8,     $C8    ; DEZ
    zoneTableEntry.w    $0, $1000,  $C8,     $C8
    zoneTableEntry.w    $0, $28C0,  $200,   $600    ; ARZ act 1
    zoneTableEntry.w    $0, $3FFF,  $180,   $710    ; ARZ act 2
    zoneTableEntry.w    $0, $3FFF,  $0, $000    ; SCZ
    zoneTableEntry.w    $0, $3FFF,  $0, $720
    zoneTableEnd
 
; ===========================================================================
+
    tst.b   (Last_star_pole_hit).w      ; was a star pole hit yet?
    beq.s   +               ; if not, branch
    jsr (Obj79_LoadData).l      ; load the previously saved data
    move.w  (MainCharacter+x_pos).w,d1
    move.w  (MainCharacter+y_pos).w,d0
    bra.s   ++
; ===========================================================================
+   ; Put the character at the start location for the level
    move.w  (Current_ZoneAndAct).w,d0
    ror.b   #1,d0
    lsr.w   #5,d0
    lea StartLocations(pc,d0.w),a1
    moveq   #0,d1
    move.w  (a1)+,d1
    move.w  d1,(MainCharacter+x_pos).w
    moveq   #0,d0
    move.w  (a1),d0
    move.w  d0,(MainCharacter+y_pos).w
+
    subi.w  #$A0,d1
    bcc.s   +
    moveq   #0,d1
+
    move.w  (Camera_Max_X_pos).w,d2
    cmp.w   d2,d1
    blo.s   +
    move.w  d2,d1
+
    move.w  d1,(Camera_X_pos).w
    move.w  d1,(Camera_X_pos_P2).w
    subi.w  #$60,d0
    bcc.s   +
    moveq   #0,d0
+
    cmp.w   (Camera_Max_Y_pos_now).w,d0
    blt.s   +
    move.w  (Camera_Max_Y_pos_now).w,d0
+
    move.w  d0,(Camera_Y_pos).w
    move.w  d0,(Camera_Y_pos_P2).w
    bsr.w   InitCameraValues
    rts
; End of function LevelSizeLoad
 
; ===========================================================================
; --------------------------------------------------------------------------------------
; CHARACTER START LOCATION ARRAY
 
; 2 entries per act, corresponding to the X and Y locations that you want the player to
; appear at when the level starts.
; --------------------------------------------------------------------------------------
StartLocations: zoneOrderedTable 2,4    ; WrdArr_StartLoc
    zoneTableBinEntry   2, "startpos/EHZ_1.bin" ; $00
    zoneTableBinEntry   2, "startpos/EHZ_2.bin"
    zoneTableEntry.w    $60,    $28F        ; $01
    zoneTableEntry.w    $60,    $2AF
    zoneTableEntry.w    $60,    $1AC        ; $02
    zoneTableEntry.w    $60,    $1AC
    zoneTableEntry.w    $60,    $28F        ; $03
    zoneTableEntry.w    $60,    $2AF
    zoneTableBinEntry   2, "startpos/MTZ_1.bin" ; $04
    zoneTableBinEntry   2, "startpos/MTZ_2.bin"
    zoneTableBinEntry   2, "startpos/MTZ_3.bin" ; $05
    zoneTableEntry.w    $60,    $2AF
    zoneTableBinEntry   2, "startpos/WFZ.bin"   ; $06
    zoneTableEntry.w    $1E0,   $4CC
    zoneTableBinEntry   2, "startpos/HTZ_1.bin" ; $07
    zoneTableBinEntry   2, "startpos/HTZ_2.bin"
    zoneTableEntry.w    $230,   $1AC        ; $08
    zoneTableEntry.w    $230,   $1AC
    zoneTableEntry.w    $60,    $28F        ; $09
    zoneTableEntry.w    $60,    $2AF
    zoneTableBinEntry   2, "startpos/OOZ_1.bin" ; $0A
    zoneTableBinEntry   2, "startpos/OOZ_2.bin"
    zoneTableBinEntry   2, "startpos/MCZ_1.bin" ; $0B
    zoneTableBinEntry   2, "startpos/MCZ_2.bin"
    zoneTableBinEntry   2, "startpos/CNZ_1.bin" ; $0C
    zoneTableBinEntry   2, "startpos/CNZ_2.bin"
    zoneTableBinEntry   2, "startpos/CPZ_1.bin" ; $0D
    zoneTableBinEntry   2, "startpos/CPZ_2.bin"
    zoneTableBinEntry   2, "startpos/DEZ.bin"   ; $0E
    zoneTableEntry.w    $60,    $12D
    zoneTableBinEntry   2, "startpos/ARZ_1.bin" ; $0F
    zoneTableBinEntry   2, "startpos/ARZ_2.bin"
    zoneTableBinEntry   2, "startpos/SCZ.bin"   ; $10
    zoneTableEntry.w    $140,   $70
    zoneTableEnd
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_C258:
InitCameraValues:
    tst.b   (Last_star_pole_hit).w  ; was a star pole hit yet?
    bne.s   +           ; if yes, branch
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  d0,(Camera_BG2_Y_pos).w
    move.w  d1,(Camera_BG_X_pos).w
    move.w  d1,(Camera_BG2_X_pos).w
    move.w  d1,(Camera_BG3_X_pos).w
    move.w  d0,(Camera_BG_Y_pos_P2).w
    move.w  d0,(Camera_BG2_Y_pos_P2).w
    move.w  d1,(Camera_BG_X_pos_P2).w
    move.w  d1,(Camera_BG2_X_pos_P2).w
    move.w  d1,(Camera_BG3_X_pos_P2).w
+
    moveq   #0,d2
    move.b  (Current_Zone).w,d2
    add.w   d2,d2
    move.w  InitCam_Index(pc,d2.w),d2
    jmp InitCam_Index(pc,d2.w)
; End of function InitCameraValues
 
; ===========================================================================
; off_C296:
InitCam_Index: zoneOrderedOffsetTable 2,1
    zoneOffsetTableEntry.w InitCam_EHZ
    zoneOffsetTableEntry.w InitCam_Null0    ; 1
    zoneOffsetTableEntry.w InitCam_WZ   ; 2
    zoneOffsetTableEntry.w InitCam_Null0    ; 3
    zoneOffsetTableEntry.w InitCam_Std  ; 4 MTZ
    zoneOffsetTableEntry.w InitCam_Std  ; 5 MTZ3
    zoneOffsetTableEntry.w InitCam_Null1    ; 6
    zoneOffsetTableEntry.w InitCam_HTZ  ; 7
    zoneOffsetTableEntry.w InitCam_HPZ  ; 8
    zoneOffsetTableEntry.w InitCam_Null2    ; 9
    zoneOffsetTableEntry.w InitCam_OOZ  ; 10
    zoneOffsetTableEntry.w InitCam_MCZ  ; 11
    zoneOffsetTableEntry.w InitCam_CNZ  ; 12
    zoneOffsetTableEntry.w InitCam_CPZ  ; 13
    zoneOffsetTableEntry.w InitCam_Null3    ; 14
    zoneOffsetTableEntry.w InitCam_ARZ  ; 15
    zoneOffsetTableEntry.w InitCam_SCZ  ; 16
    zoneTableEnd
; ===========================================================================
;loc_C2B8:
InitCam_EHZ:
    clr.l   (Camera_BG_X_pos).w
    clr.l   (Camera_BG_Y_pos).w
    clr.l   (Camera_BG2_Y_pos).w
    clr.l   (Camera_BG3_Y_pos).w
    lea (TempArray_LayerDef).w,a2
    clr.l   (a2)+
    clr.l   (a2)+
    clr.l   (a2)+
    clr.l   (Camera_BG_X_pos_P2).w
    clr.l   (Camera_BG_Y_pos_P2).w
    clr.l   (Camera_BG2_Y_pos_P2).w
    clr.l   (Camera_BG3_Y_pos_P2).w
    rts
; ===========================================================================
; wtf:
InitCam_Null0:
    if gameRevision=0
    rts
    endif
; ===========================================================================
; Wood_Zone_BG:
InitCam_WZ:
    if gameRevision=0
    asr.w   #2,d0
    addi.w  #$400,d0
    move.w  d0,(Camera_BG_Y_pos).w
    asr.w   #3,d1
    move.w  d1,(Camera_BG_X_pos).w
    rts
    endif
; ===========================================================================
;loc_C2E4:
InitCam_Std:
    asr.w   #2,d0
    move.w  d0,(Camera_BG_Y_pos).w
    asr.w   #3,d1
    move.w  d1,(Camera_BG_X_pos).w
    rts
; ===========================================================================
;return_C2F2:
InitCam_Null1:
    rts
; ===========================================================================
;loc_C2F4:
InitCam_HTZ:
    clr.l   (Camera_BG_X_pos).w
    clr.l   (Camera_BG_Y_pos).w
    clr.l   (Camera_BG2_Y_pos).w
    clr.l   (Camera_BG3_Y_pos).w
    lea (TempArray_LayerDef).w,a2
    clr.l   (a2)+
    clr.l   (a2)+
    clr.l   (a2)+
    clr.l   (Camera_BG_X_pos_P2).w
    clr.l   (Camera_BG_Y_pos_P2).w
    clr.l   (Camera_BG2_Y_pos_P2).w
    clr.l   (Camera_BG3_Y_pos_P2).w
    rts
; ===========================================================================
; Hidden_Palace_Zone_BG:
InitCam_HPZ:
    if gameRevision=0
    asr.w   #1,d0
    move.w  d0,(Camera_BG_Y_pos).w
    clr.l   (Camera_BG_X_pos).w
    rts    
    endif
; ===========================================================================   
; Unknown_Zone_BG:
InitCam_CCZ:
    if gameRevision=0
    asl.l   #4,d0
    move.l  d0,d2
    asl.l   #1,d0
    add.l   d2,d0
    asr.l   #8,d0
    addq.w  #1,d0
    move.w  d0,(Camera_BG_Y_pos).w
    clr.l   (Camera_BG_X_pos).w
    rts
    endif
; ===========================================================================
;return_C320:
InitCam_Null2:
    rts
; ===========================================================================
;loc_C322:
InitCam_OOZ:
    lsr.w   #3,d0
    addi.w  #$50,d0
    move.w  d0,(Camera_BG_Y_pos).w
    clr.l   (Camera_BG_X_pos).w
    rts
; ===========================================================================
;loc_C332:
InitCam_MCZ:
    clr.l   (Camera_BG_X_pos).w
    clr.l   (Camera_BG_X_pos_P2).w
    tst.b   (Current_Act).w
    bne.s   +
    divu.w  #3,d0
    subi.w  #$140,d0
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  d0,(Camera_BG_Y_pos_P2).w
    rts
; ===========================================================================
+
    divu.w  #6,d0
    subi.w  #$10,d0
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  d0,(Camera_BG_Y_pos_P2).w
    rts
; ===========================================================================
;loc_C364:
InitCam_CNZ:
    clr.l   (Camera_BG_X_pos).w
    clr.l   (Camera_BG_Y_pos).w
    clr.l   (Camera_BG_Y_pos_P2).w
    rts
; ===========================================================================
;loc_C372:
InitCam_CPZ:
    lsr.w   #2,d0
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  d0,(Camera_BG_Y_pos_P2).w
    lsr.w   #1,d1
    move.w  d1,(Camera_BG2_X_pos).w
    lsr.w   #2,d1
    move.w  d1,(Camera_BG_X_pos).w
    rts
; ===========================================================================
;return_C38A:
InitCam_Null3:
    rts
; ===========================================================================
;loc_C38C:
InitCam_ARZ:
    tst.b   (Current_Act).w
    beq.s   +
    subi.w  #$E0,d0
    lsr.w   #1,d0
    move.w  d0,(Camera_BG_Y_pos).w
    bra.s   loc_C3A6
; ===========================================================================
+
    subi.w  #$180,d0
    move.w  d0,(Camera_BG_Y_pos).w
 
loc_C3A6:
    muls.w  #$119,d1
    asr.l   #8,d1
    move.w  d1,(Camera_BG_X_pos).w
    move.w  d1,(Camera_ARZ_BG_X_pos).w
    clr.w   (Camera_BG_X_pos+2).w
    clr.w   (Camera_ARZ_BG_X_pos+2).w
    clr.l   (Camera_BG2_Y_pos).w
    clr.l   (Camera_BG3_Y_pos).w
    rts
; ===========================================================================
;loc_C3C6:
InitCam_SCZ:
    clr.l   (Camera_BG_X_pos).w
    clr.l   (Camera_BG_Y_pos).w
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; sub_C3D0:
DeformBgLayer:
    tst.b   (Deform_lock).w
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    clr.w   (Scroll_flags).w
    clr.w   (Scroll_flags_BG).w
    clr.w   (Scroll_flags_BG2).w
    clr.w   (Scroll_flags_BG3).w
    clr.w   (Scroll_flags_P2).w
    clr.w   (Scroll_flags_BG_P2).w
    clr.w   (Scroll_flags_BG2_P2).w
    clr.w   (Scroll_flags_BG3_P2).w
    clr.w   (Camera_X_pos_diff).w
    clr.w   (Camera_Y_pos_diff).w
    clr.w   (Camera_X_pos_diff_P2).w
    clr.w   (Camera_Y_pos_diff_P2).w
    cmpi.b  #sky_chase_zone,(Current_Zone).w
    bne.w   +
    tst.w   (Debug_placement_mode).w
    beq.w   loc_C4D0    ; skip normal scrolling for SCZ
+
    tst.b   (Scroll_lock).w
    bne.s   DeformBgLayerAfterScrollVert
    lea (MainCharacter).w,a0 ; a0=character
    lea (Camera_X_pos).w,a1
    lea (Camera_Min_X_pos).w,a2
    lea (Scroll_flags).w,a3
    lea (Camera_X_pos_diff).w,a4
    lea (Horiz_scroll_delay_val).w,a5
    lea (Sonic_Pos_Record_Buf).w,a6
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    lea (Horiz_scroll_delay_val_P2).w,a5
    lea (Tails_Pos_Record_Buf).w,a6
+
    bsr.w   ScrollHoriz
    lea (Horiz_block_crossed_flag).w,a2
    bsr.w   SetHorizScrollFlags
    lea (Camera_Y_pos).w,a1
    lea (Camera_Min_X_pos).w,a2
    lea (Camera_Y_pos_diff).w,a4
    move.w  (Camera_Y_pos_bias).w,d3
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    move.w  (Camera_Y_pos_bias_P2).w,d3
+
    bsr.w   ScrollVerti
    lea (Verti_block_crossed_flag).w,a2
    bsr.w   SetVertiScrollFlags
 
DeformBgLayerAfterScrollVert:
    tst.w   (Two_player_mode).w
    beq.s   loc_C4D0
    tst.b   (Scroll_lock_P2).w
    bne.s   loc_C4D0
    lea (Sidekick).w,a0 ; a0=character
    lea (Camera_X_pos_P2).w,a1
    lea (Tails_Min_X_pos).w,a2
    lea (Scroll_flags_P2).w,a3
    lea (Camera_X_pos_diff_P2).w,a4
    lea (Horiz_scroll_delay_val_P2).w,a5
    lea (Tails_Pos_Record_Buf).w,a6
    bsr.w   ScrollHoriz
    lea (Horiz_block_crossed_flag_P2).w,a2
    bsr.w   SetHorizScrollFlags
    lea (Camera_Y_pos_P2).w,a1
    lea (Tails_Min_X_pos).w,a2
    lea (Camera_Y_pos_diff_P2).w,a4
    move.w  (Camera_Y_pos_bias_P2).w,d3
    bsr.w   ScrollVerti
    lea (Verti_block_crossed_flag_P2).w,a2
    bsr.w   SetVertiScrollFlags
 
loc_C4D0:
    bsr.w   RunDynamicLevelEvents
    move.w  (Camera_Y_pos).w,(Vscroll_Factor_FG).w
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    move.l  (Camera_X_pos).w,(Camera_X_pos_copy).w
    move.l  (Camera_Y_pos).w,(Camera_Y_pos_copy).w
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    move.w  SwScrl_Index(pc,d0.w),d0
    jmp SwScrl_Index(pc,d0.w)
; End of function DeformBgLayer
 
; ===========================================================================
; ---------------------------------------------------------------------------
; JUMP TABLE FOR SOFTWARE SCROLL MANAGERS
;
; "Software scrolling" is my term for what Nemesis (and by extension, the rest
; of the world) calls "rasterized layer deformation".* Software scroll managers
; are needed to achieve certain special camera effects - namely, locking the
; screen for a boss fight and defining the limits of said screen lock, or in
; the case of Sky Chase Zone ($10), moving the camera at a fixed rate through
; a predefined course.
; They are also used for things like controlling the parallax scrolling and
; water ripple effects in EHZ, and moving the clouds in HTZ and the stars in DEZ.
; ---------------------------------------------------------------------------
SwScrl_Index: zoneOrderedOffsetTable 2,1    ; JmpTbl_SwScrlMgr
    zoneOffsetTableEntry.w SwScrl_EHZ   ; $00
    zoneOffsetTableEntry.w SwScrl_Minimal   ; $01
    zoneOffsetTableEntry.w SwScrl_Lev2  ; $02
    zoneOffsetTableEntry.w SwScrl_Minimal   ; $03
    zoneOffsetTableEntry.w SwScrl_MTZ   ; $04
    zoneOffsetTableEntry.w SwScrl_MTZ   ; $05
    zoneOffsetTableEntry.w SwScrl_WFZ   ; $06
    zoneOffsetTableEntry.w SwScrl_HTZ   ; $07
    zoneOffsetTableEntry.w SwScrl_HPZ   ; $08
    zoneOffsetTableEntry.w SwScrl_Minimal   ; $09
    zoneOffsetTableEntry.w SwScrl_OOZ   ; $0A
    zoneOffsetTableEntry.w SwScrl_MCZ   ; $0B
    zoneOffsetTableEntry.w SwScrl_CNZ   ; $0C
    zoneOffsetTableEntry.w SwScrl_CPZ   ; $0D
    zoneOffsetTableEntry.w SwScrl_DEZ   ; $0E
    zoneOffsetTableEntry.w SwScrl_ARZ   ; $0F
    zoneOffsetTableEntry.w SwScrl_SCZ   ; $10
    zoneTableEnd
; ===========================================================================
; loc_C51E:
SwScrl_Title:
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    addq.w  #1,(Camera_X_pos).w
    move.w  (Camera_X_pos).w,d2
    neg.w   d2
    asr.w   #2,d2
    lea (Horiz_Scroll_Buf).w,a1
    moveq   #0,d0
 
    move.w  #bytesToLcnt($280),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
 
    move.w  #bytesToLcnt($80),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d0,d3
    move.b  (Vint_runcount+3).w,d1
    andi.w  #7,d1
    bne.s   +
    subq.w  #1,(TempArray_LayerDef).w
+
    move.w  (TempArray_LayerDef).w,d1
    andi.w  #$1F,d1
    lea SwScrl_RippleData(pc),a2
    lea (a2,d1.w),a2
 
    move.w  #bytesToLcnt($40),d1
-   move.b  (a2)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; loc_C57E:
SwScrl_EHZ:
    tst.w   (Two_player_mode).w
    bne.w   SwScrl_EHZ_2P
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    move.w  d0,d2
    swap    d0
    move.w  #0,d0
 
    move.w  #bytesToLcnt($58),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #6,d0
 
    move.w  #bytesToLcnt($E8),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d0,d3
    move.b  (Vint_runcount+3).w,d1
    andi.w  #7,d1
    bne.s   +
    subq.w  #1,(TempArray_LayerDef).w
+
    move.w  (TempArray_LayerDef).w,d1
    andi.w  #$1F,d1
    lea (SwScrl_RippleData).l,a2
    lea (a2,d1.w),a2
 
    move.w  #bytesToLcnt($54),d1
-   move.b  (a2)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d1,-
 
    move.w  #0,d0
 
    move.w  #bytesToLcnt($2C),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #4,d0
 
    move.w  #bytesToLcnt($40),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #4,d0
    move.w  d0,d1
    asr.w   #1,d1
    add.w   d1,d0
 
    move.w  #bytesToLcnt($40),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.l  d0,d4
    swap    d4
    move.w  d2,d0
    asr.w   #1,d0
    move.w  d2,d1
    asr.w   #3,d1
    sub.w   d1,d0
    ext.l   d0
    asl.l   #8,d0
    divs.w  #$30,d0
    ext.l   d0
    asl.l   #8,d0
    moveq   #0,d3
    move.w  d2,d3
    asr.w   #3,d3
 
    move.w  #bytesToLcnt($3C),d1 ; $3C bytes
-   move.w  d4,(a1)+
    move.w  d3,(a1)+
    swap    d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    move.w  #($48)/8-1,d1 ; $48 bytes
-   move.w  d4,(a1)+
    move.w  d3,(a1)+
    move.w  d4,(a1)+
    move.w  d3,(a1)+
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    move.w  #($B4)/12-1,d1 ; $B4 bytes
-   move.w  d4,(a1)+
    move.w  d3,(a1)+
    move.w  d4,(a1)+
    move.w  d3,(a1)+
    move.w  d4,(a1)+
    move.w  d3,(a1)+
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    ; note there is a bug here. the bottom 8 pixels haven't had their hscroll values set. only the EHZ scrolling code has this bug.
 
    rts
; ===========================================================================
; horizontal offsets for the water rippling effect
; byte_C682:
SwScrl_RippleData:
    dc.b   1,  2,  1,  3,  1,  2,  2,  1,  2,  3,  1,  2,  1,  2,  0,  0; 16
    dc.b   2,  0,  3,  2,  2,  3,  2,  2,  1,  3,  0,  0,  1,  0,  1,  3; 32
    dc.b   1,  2,  1,  3,  1,  2,  2,  1,  2,  3,  1,  2,  1,  2,  0,  0; 48
    dc.b   2,  0,  3,  2,  2,  3,  2,  2,  1,  3,  0,  0,  1,  0,  1,  3; 64
    dc.b   1,  2    ; 66
; ===========================================================================
; loc_C6C4:
SwScrl_EHZ_2P:
    move.b  (Vint_runcount+3).w,d1
    andi.w  #7,d1
    bne.s   +
    subq.w  #1,(TempArray_LayerDef).w
+
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_X_pos).w,d0
    move.w  #bytesToLcnt($2C),d1
    bsr.s   sub_C71A
    moveq   #0,d0
    move.w  d0,(Vscroll_Factor_P2_BG).w
    subi.w  #$E0,(Vscroll_Factor_P2_BG).w
    move.w  (Camera_Y_pos_P2).w,(Vscroll_Factor_P2_FG).w
    subi.w  #$E0,(Vscroll_Factor_P2_FG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor_P2).w
    lea (Horiz_Scroll_Buf+$1B0).w,a1
    move.w  (Camera_X_pos_P2).w,d0
    move.w  #bytesToLcnt($3C),d1
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_C71A:
    neg.w   d0
    move.w  d0,d2
    swap    d0
    move.w  #0,d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #6,d0
 
    move.w  #bytesToLcnt($74),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d0,d3
    move.w  (TempArray_LayerDef).w,d1
    andi.w  #$1F,d1
    lea_    SwScrl_RippleData,a2
    lea (a2,d1.w),a2
 
    move.w  #bytesToLcnt($2C),d1
-   move.b  (a2)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d1,-
 
    move.w  #0,d0
 
    move.w  #bytesToLcnt($14),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #4,d0
 
    move.w  #bytesToLcnt($20),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #4,d0
    move.w  d0,d1
    asr.w   #1,d1
    add.w   d1,d0
 
    move.w  #bytesToLcnt($20),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #1,d0
    move.w  d2,d1
    asr.w   #3,d1
    sub.w   d1,d0
    ext.l   d0
    asl.l   #8,d0
    divs.w  #$30,d0
    ext.l   d0
    asl.l   #8,d0
    moveq   #0,d3
    move.w  d2,d3
    asr.w   #3,d3
 
    move.w  #bytesToLcnt($A0),d1
-   move.w  d2,(a1)+
    move.w  d3,(a1)+
    swap    d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    rts
; End of function sub_C71A
 
; ===========================================================================
; unused...
; loc_C7BA:
SwScrl_Lev2:
    if gameRevision<2
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #5,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #6,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($380),d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
    endif
 
    rts
; ===========================================================================
; loc_C7F2:
SwScrl_MTZ:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #5,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #6,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($380),d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; loc_C82A:
SwScrl_WFZ:
    move.w  (Camera_BG_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #8,d4
    moveq   #2,d6
    bsr.w   SetHorizScrollFlagsBG
    move.w  (Camera_BG_Y_pos_diff).w,d5
    ext.l   d5
    lsl.l   #8,d5
    moveq   #6,d6
    bsr.w   SetVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    move.l  (Camera_BG_X_pos).w,d0
    ; This can be removed if the getaway ship's entry uses d0 instead.
    move.l  d0,d1
    lea (TempArray_LayerDef).w,a2
    move.l  d0,(a2)+                ; Static parts of BG (generally no clouds in them)
    move.l  d1,(a2)+                ; Eggman's getaway ship
    ; Note: this is bugged: this tallies only the cloud speeds. It works fine
    ; if you are standing still, but makes the clouds move faster when going
    ; right and slower when going left. This is exactly the opposite of what
    ; should happen.
    addi.l  #$8000,(a2)+            ; Larger clouds
    addi.l  #$4000,(a2)+            ; Medium clouds
    addi.l  #$2000,(a2)+            ; Small clouds
    lea (SwScrl_WFZ_Transition_Array).l,a3
    cmpi.w  #$2700,(Camera_X_pos).w
    bhs.s   .got_array
    lea (SwScrl_WFZ_Normal_Array).l,a3
 
.got_array:
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    andi.w  #$7FF,d1
    moveq   #0,d0
    moveq   #0,d3
 
    ; Find the first visible scrolling section
.seg_loop:
    move.b  (a3)+,d0                ; Number of lines in this segment
    addq.w  #1,a3                   ; Skip index
    sub.w   d0,d1                   ; Does this segment have any visible lines?
    bcc.s   .seg_loop               ; Branch if not
 
    neg.w   d1                      ; d1 = number of lines to draw in this segment
    move.w  #bytesToLcnt($380),d2   ; Number of rows in hscroll buffer
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.b  -1(a3),d3               ; Fetch TempArray_LayerDef index
    move.w  (a2,d3.w),d0            ; Fetch scroll value for this row...
    neg.w   d0                      ; ... and flip sign for VDP
 
.row_loop:
    move.l  d0,(a1)+
    subq.w  #1,d1                   ; Has the current segment finished?
    bne.s   .next_row               ; Branch if not
    move.b  (a3)+,d1                ; Fetch a new line count
    move.b  (a3)+,d3                ; Fetch TempArray_LayerDef index
    move.w  (a2,d3.w),d0            ; Fetch scroll value for this row...
    neg.w   d0                      ; ... and flip sign for VDP
 
.next_row:
    dbf d2,.row_loop
 
    rts
; ===========================================================================
; WFZ BG scrolling data
; Each pair of bytes corresponds to one scrolling segment of the BG, and
; the bytes have the following meaning:
;   number of lines, index into TempArray_LayerDef
; byte_C8CA
SwScrl_WFZ_Transition_Array:
    dc.b $C0,  0,$C0,  0,$80,  0,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C
    dc.b $30,$10,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10,$20,  8; 16
    dc.b $30, $C,$30,$10,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10; 32
    dc.b $80,  4,$80,  4,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10; 48
    dc.b $20,  8,$30, $C,$30,$10,$C0,  0,$C0,  0,$80,  0; 64
;byte_C916
SwScrl_WFZ_Normal_Array:
    dc.b $C0,  0,$C0,  0,$80,  0,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C
    dc.b $30,$10,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10,$20,  8; 16
    dc.b $30, $C,$30,$10,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10; 32
    dc.b $20,  8,$30, $C,$30,$10,$20,  8,$30, $C,$30,$10,$20,  8,$30, $C; 48
    dc.b $30,$10,$20,  8,$30, $C,$30,$10,$C0,  0,$C0,  0,$80,  0; 64
; Note: this array is missing $80 lines compared to the transition array.
; This causes the lower clouds to read data from the start of SwScrl_HTZ.
; These are the missing entries:
    if 1==0
    dc.b $20,  8,$30, $C,$30,$10
    endif
; ===========================================================================
; loc_C964:
SwScrl_HTZ:
    tst.w   (Two_player_mode).w
    bne.w   SwScrl_HTZ_2P   ; never used in normal gameplay
    tst.b   (Screen_Shaking_Flag_HTZ).w
    bne.w   HTZ_Screen_Shake
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    move.w  d0,d2
    swap    d0
    move.w  d2,d0
    asr.w   #3,d0
 
    move.w  #bytesToLcnt($200),d1
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.l  d0,d4
    move.w  (TempArray_LayerDef+$22).w,d0
    addq.w  #4,(TempArray_LayerDef+$22).w
    sub.w   d0,d2
    move.w  d2,d0
    move.w  d0,d1
    asr.w   #1,d0
    asr.w   #4,d1
    sub.w   d1,d0
    ext.l   d0
    asl.l   #8,d0
    divs.w  #$70,d0
    ext.l   d0
    asl.l   #8,d0
    lea (TempArray_LayerDef).w,a2
    moveq   #0,d3
    move.w  d1,d3
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a2)+
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a2)+
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a2)+
    move.w  d3,(a2)+
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
 
    moveq   #3,d1
-   move.w  d3,(a2)+
    move.w  d3,(a2)+
    move.w  d3,(a2)+
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    add.l   d0,d0
    add.l   d0,d0
    move.w  d3,d4
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,d4
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    move.l  d4,(a1)+
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,d4
 
    move.w  #6,d1
-   move.l  d4,(a1)+
    dbf d1,-
 
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    move.w  d3,d4
 
    move.w  #7,d1
-   move.l  d4,(a1)+
    dbf d1,-
 
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    move.w  d3,d4
 
    move.w  #9,d1
-   move.l  d4,(a1)+
    dbf d1,-
 
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    move.w  d3,d4
 
    move.w  #$E,d1
-   move.l  d4,(a1)+
    dbf d1,-
 
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
 
    move.w  #2,d2
-   move.w  d3,d4
 
    move.w  #$F,d1
-   move.l  d4,(a1)+
    dbf d1,-
 
    swap    d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    add.l   d0,d3
    swap    d3
    dbf d2,--
 
    rts
; ===========================================================================
 
;loc_CA92:
HTZ_Screen_Shake:
    move.w  (Camera_BG_X_pos_diff).w,d4
    ext.l   d4
    lsl.l   #8,d4
    moveq   #2,d6
    bsr.w   SetHorizScrollFlagsBG
    move.w  (Camera_BG_Y_pos_diff).w,d5
    ext.l   d5
    lsl.l   #8,d5
    moveq   #0,d6
    bsr.w   SetVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    move.w  (Camera_Y_pos).w,(Vscroll_Factor_FG).w
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    moveq   #0,d2
    tst.b   (Screen_Shaking_Flag).w
    beq.s   +
 
    move.w  (Timer_frames).w,d0
    andi.w  #$3F,d0
    lea_    SwScrl_RippleData,a1
    lea (a1,d0.w),a1
    moveq   #0,d0
    move.b  (a1)+,d0
    add.w   d0,(Vscroll_Factor_FG).w
    add.w   d0,(Vscroll_Factor_BG).w
    add.w   d0,(Camera_Y_pos_copy).w
    move.b  (a1)+,d2
    add.w   d2,(Camera_X_pos_copy).w
+
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($380),d1
    move.w  (Camera_X_pos).w,d0
    add.w   d2,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    add.w   d2,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; loc_CB10:
SwScrl_HTZ_2P:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #6,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #2,d5
    moveq   #0,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.b  #0,(Scroll_flags_BG).w
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($1C0),d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    move.w  (Camera_X_pos_diff_P2).w,d4
    ext.l   d4
    asl.l   #6,d4
    add.l   d4,(Camera_BG_X_pos_P2).w
    moveq   #0,d0
    move.w  d0,(Vscroll_Factor_P2_BG).w
    subi.w  #$E0,(Vscroll_Factor_P2_BG).w
    move.w  (Camera_Y_pos_P2).w,(Vscroll_Factor_P2_FG).w
    subi.w  #$E0,(Vscroll_Factor_P2_FG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor_P2).w
    lea (Horiz_Scroll_Buf+$1B0).w,a1
    move.w  #bytesToLcnt($1D0),d1
    move.w  (Camera_X_pos_P2).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos_P2).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; unused...
; loc_CBA0:
SwScrl_HPZ:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #6,d4
    moveq   #2,d6
    bsr.w   SetHorizScrollFlagsBG
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #7,d5
    moveq   #6,d6
    bsr.w   SetVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (TempArray_LayerDef).w,a1
    move.w  (Camera_X_pos).w,d2
    neg.w   d2
    move.w  d2,d0
    asr.w   #1,d0
 
    move.w  #7,d1
-   move.w  d0,(a1)+
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #3,d0
    sub.w   d2,d0
    ext.l   d0
    asl.l   #3,d0
    divs.w  #8,d0
    ext.l   d0
    asl.l   #4,d0
    asl.l   #8,d0
    moveq   #0,d3
    move.w  d2,d3
    asr.w   #1,d3
    lea (TempArray_LayerDef+$60).w,a2
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a1)+
    move.w  d3,(a1)+
    move.w  d3,(a1)+
    move.w  d3,-(a2)
    move.w  d3,-(a2)
    move.w  d3,-(a2)
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a1)+
    move.w  d3,(a1)+
    move.w  d3,-(a2)
    move.w  d3,-(a2)
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a1)+
    move.w  d3,-(a2)
    swap    d3
    add.l   d0,d3
    swap    d3
    move.w  d3,(a1)+
    move.w  d3,-(a2)
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
    move.w  #$19,d1
-   move.w  d0,(a1)+
    dbf d1,-
 
    adda.w  #$E,a1
    move.w  d2,d0
    asr.w   #1,d0
 
    move.w  #$17,d1
-   move.w  d0,(a1)+
    dbf d1,-
 
    lea (TempArray_LayerDef).w,a2
    move.w  (Camera_BG_Y_pos).w,d0
    move.w  d0,d2
    andi.w  #$3F0,d0
    lsr.w   #3,d0
    lea (a2,d0.w),a2
    bra.w   SwScrl_HPZ_Continued
; ===========================================================================
; loc_CC66:
SwScrl_OOZ:
    move.w  (Camera_X_pos_diff).w,d0
    ext.l   d0
    asl.l   #5,d0
    add.l   d0,(Camera_BG_X_pos).w
    move.w  (Camera_Y_pos_diff).w,d0
    ext.l   d0
    asl.l   #5,d0
    move.l  (Camera_BG_Y_pos).w,d3
    add.l   d3,d0
    moveq   #4,d6
    bsr.w   SetVertiScrollFlagsBG2
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf+$380).w,a1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d7
    neg.w   d7
    move.w  (Camera_BG_Y_pos).w,d1
    subi.w  #$50,d1
    bcc.s   +
    moveq   #0,d1
+
    subi.w  #$B0,d1
    bcs.s   +
    moveq   #0,d1
+
    move.w  #$DF,d6
    add.w   d6,d1
    move.w  d7,d0
    bsr.s   OOZ_BGScroll_Lines
    bsr.s   OOZ_BGScroll_MediumClouds
    bsr.s   OOZ_BGScroll_SlowClouds
    bsr.s   OOZ_BGScroll_FastClouds
    move.w  d7,d0
    asr.w   #4,d0
    moveq   #6,d1
    bsr.s   OOZ_BGScroll_Lines
    move.b  (Vint_runcount+3).w,d1
    andi.w  #7,d1
    bne.s   +
    subq.w  #1,(TempArray_LayerDef).w
+
    move.w  (TempArray_LayerDef).w,d1
    andi.w  #$1F,d1
    lea SwScrl_RippleData(pc),a2
    lea (a2,d1.w),a2
 
    moveq   #$20,d1
-   move.b  (a2)+,d0
    ext.w   d0
    move.l  d0,-(a1)
    subq.w  #1,d6
    bmi.s   +   ; rts
    dbf d1,-
 
    bsr.s   OOZ_BGScroll_MediumClouds
    bsr.s   OOZ_BGScroll_SlowClouds
    bsr.s   OOZ_BGScroll_FastClouds
    bsr.s   OOZ_BGScroll_SlowClouds
    bsr.s   OOZ_BGScroll_MediumClouds
    move.w  d7,d0
    moveq   #$47,d1
    bsr.s   OOZ_BGScroll_Lines
+   rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_CD0A
OOZ_BGScroll_FastClouds:
    move.w  d7,d0
    asr.w   #2,d0
    bra.s   +
; End of function OOZ_BGScroll_FastClouds
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_CD10
OOZ_BGScroll_MediumClouds:
    move.w  d7,d0
    asr.w   #3,d0
    bra.s   +
; End of function OOZ_BGScroll_MediumClouds
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_CD16
OOZ_BGScroll_SlowClouds:
    move.w  d7,d0
    asr.w   #4,d0
 
+
    moveq   #7,d1
; End of function OOZ_BGScroll_SlowClouds
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Scrolls min(d6,d1+1) lines by an (constant) amount specified in d0
 
;sub_CD1C
OOZ_BGScroll_Lines:
    move.l  d0,-(a1)
    subq.w  #1,d6
    bmi.s   +
    dbf d1,OOZ_BGScroll_Lines
 
    rts
; ===========================================================================
+
    addq.l  #4,sp
    rts
; End of function OOZ_BGScroll_Lines
 
; ===========================================================================
; loc_CD2C:
SwScrl_MCZ:
    tst.w   (Two_player_mode).w
    bne.w   SwScrl_MCZ_2P
    move.w  (Camera_Y_pos).w,d0
    move.l  (Camera_BG_Y_pos).w,d3
    tst.b   (Current_Act).w
    bne.s   +
    divu.w  #3,d0
    subi.w  #$140,d0
    bra.s   ++
; ===========================================================================
+
    divu.w  #6,d0
    subi.w  #$10,d0
+
    swap    d0
    moveq   #6,d6
    bsr.w   SetVertiScrollFlagsBG2
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    moveq   #0,d2
    tst.b   (Screen_Shaking_Flag).w
    beq.s   +
 
    move.w  (Timer_frames).w,d0
    andi.w  #$3F,d0
    lea_    SwScrl_RippleData,a1
    lea (a1,d0.w),a1
    moveq   #0,d0
    move.b  (a1)+,d0
    add.w   d0,(Vscroll_Factor_FG).w
    add.w   d0,(Vscroll_Factor_BG).w
    add.w   d0,(Camera_Y_pos_copy).w
    move.b  (a1)+,d2
    add.w   d2,(Camera_X_pos_copy).w
+
    lea (TempArray_LayerDef).w,a2
    lea $1E(a2),a3
    move.w  (Camera_X_pos).w,d0
    ext.l   d0
    asl.l   #4,d0
    divs.w  #$A,d0
    ext.l   d0
    asl.l   #4,d0
    asl.l   #8,d0
    move.l  d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$E(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,8(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,6(a2)
    move.w  d1,$10(a2)
    move.w  d1,$1C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,4(a2)
    move.w  d1,$12(a2)
    move.w  d1,$1A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,2(a2)
    move.w  d1,$14(a2)
    move.w  d1,$18(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,(a2)
    move.w  d1,$16(a2)
    lea (SwScrl_MCZ_RowHeights).l,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    moveq   #0,d0
 
-   move.b  (a3)+,d0
    addq.w  #2,a2
    sub.w   d0,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    move.w  #bytesToLcnt($380),d2
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
    move.b  (a3)+,d1
    move.w  (a2)+,d0
    neg.w   d0
+   dbf d2,-
 
    rts
; ===========================================================================
; byte_CE6C:
SwScrl_MCZ_RowHeights:
    dc.b $25
    dc.b $17    ; 1
    dc.b $12    ; 2
    dc.b   7    ; 3
    dc.b   7    ; 4
    dc.b   2    ; 5
    dc.b   2    ; 6
    dc.b $30    ; 7
    dc.b  $D    ; 8
    dc.b $13    ; 9
    dc.b $20    ; 10
    dc.b $40    ; 11
    dc.b $20    ; 12
    dc.b $13    ; 13
    dc.b  $D    ; 14
    dc.b $30    ; 15
    dc.b   2    ; 16
    dc.b   2    ; 17
    dc.b   7    ; 18
    dc.b   7    ; 19
    dc.b $20    ; 20
    dc.b $12    ; 21
    dc.b $17    ; 22
    dc.b $25    ; 23
    even
; ===========================================================================
; loc_CE84:
SwScrl_MCZ_2P:
    moveq   #0,d0
    move.w  (Camera_Y_pos).w,d0
    tst.b   (Current_Act).w
    bne.s   +
    divu.w  #3,d0
    subi.w  #$140,d0
    bra.s   ++
; ===========================================================================
+
    divu.w  #6,d0
    subi.w  #$10,d0
+
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  d0,(Vscroll_Factor_BG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor).w
    lea (TempArray_LayerDef).w,a2
    lea $1E(a2),a3
    move.w  (Camera_X_pos).w,d0
    ext.l   d0
    asl.l   #4,d0
    divs.w  #$A,d0
    ext.l   d0
    asl.l   #4,d0
    asl.l   #8,d0
    move.l  d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$E(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,8(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,6(a2)
    move.w  d1,$10(a2)
    move.w  d1,$1C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,4(a2)
    move.w  d1,$12(a2)
    move.w  d1,$1A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,2(a2)
    move.w  d1,$14(a2)
    move.w  d1,$18(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,(a2)
    move.w  d1,$16(a2)
    lea (SwScrl_MCZ2P_RowHeights).l,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    lsr.w   #1,d1
    moveq   #0,d0
 
-   move.b  (a3)+,d0
    addq.w  #2,a2
    sub.w   d0,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    move.w  #bytesToLcnt($1C0),d2
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
    move.b  (a3)+,d1
    move.w  (a2)+,d0
    neg.w   d0
+   dbf d2,-
 
    bra.s   +
; ===========================================================================
; byte_CF90:
SwScrl_MCZ2P_RowHeights:
    dc.b $13
    dc.b  $B
    dc.b   9    ; 1
    dc.b   4    ; 2
    dc.b   3    ; 3
    dc.b   1    ; 4
    dc.b   1    ; 5
    dc.b $18    ; 6
    dc.b   6    ; 7
    dc.b  $A    ; 8
    dc.b $10    ; 9
    dc.b $20    ; 10
    dc.b $10    ; 11
    dc.b  $A    ; 12
    dc.b   6    ; 13
    dc.b $18    ; 14
    dc.b   1    ; 15
    dc.b   1    ; 16
    dc.b   3    ; 17
    dc.b   4    ; 18
    dc.b $10    ; 19
    dc.b   9    ; 20
    dc.b  $B    ; 21
    dc.b $13    ; 22
    even
; ===========================================================================
+
    moveq   #0,d0
    move.w  (Camera_Y_pos_P2).w,d0
    tst.b   (Current_Act).w
    bne.s   +
    divu.w  #3,d0
    subi.w  #$140,d0
    bra.s   ++
; ===========================================================================
+
    divu.w  #6,d0
    subi.w  #$10,d0
+
    move.w  d0,(Camera_BG_Y_pos_P2).w
    move.w  d0,(Vscroll_Factor_P2_BG).w
    subi.w  #$E0,(Vscroll_Factor_P2_BG).w
    move.w  (Camera_Y_pos_P2).w,(Vscroll_Factor_P2_FG).w
    subi.w  #$E0,(Vscroll_Factor_P2_FG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor_P2).w
    lea (TempArray_LayerDef).w,a2
    lea $1E(a2),a3
    move.w  (Camera_X_pos_P2).w,d0
    ext.l   d0
    asl.l   #4,d0
    divs.w  #$A,d0
    ext.l   d0
    asl.l   #4,d0
    asl.l   #8,d0
    move.l  d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$E(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,$A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,8(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,6(a2)
    move.w  d1,$10(a2)
    move.w  d1,$1C(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,4(a2)
    move.w  d1,$12(a2)
    move.w  d1,$1A(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,2(a2)
    move.w  d1,$14(a2)
    move.w  d1,$18(a2)
    swap    d1
    add.l   d0,d1
    swap    d1
    move.w  d1,(a3)+
    move.w  d1,(a2)
    move.w  d1,$16(a2)
    lea_    SwScrl_MCZ2P_RowHeights+1,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf+$1B0).w,a1
    move.w  (Camera_BG_Y_pos_P2).w,d1
    lsr.w   #1,d1
    moveq   #$17,d0
    bra.s   +
; ===========================================================================
-
    move.b  (a3)+,d0
+
    addq.w  #2,a2
    sub.w   d0,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    move.w  #bytesToLcnt($1D0),d2
    move.w  (Camera_X_pos_P2).w,d0
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
    move.b  (a3)+,d1
    move.w  (a2)+,d0
    neg.w   d0
+   dbf d2,-
 
    rts
; ===========================================================================
; loc_D0C6:
SwScrl_CNZ:
    tst.w   (Two_player_mode).w
    bne.w   SwScrl_CNZ_2P
    move.w  (Camera_Y_pos).w,d0
    lsr.w   #6,d0
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    move.w  (Camera_X_pos).w,d2
    bsr.w   sub_D160
    lea (SwScrl_CNZ_RowHeights).l,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    moveq   #0,d0
 
-   move.b  (a3)+,d0
    addq.w  #2,a2
    sub.w   d0,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    move.w  #bytesToLcnt($380),d2
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
 
-   move.w  (a2)+,d0
    neg.w   d0
    move.b  (a3)+,d1
    beq.s   ++
+   dbf d2,--
 
    rts
; ===========================================================================
+
    move.w  #bytesToLcnt($40),d1
    move.w  d0,d3
    move.b  (Vint_runcount+3).w,d0
    lsr.w   #3,d0
    neg.w   d0
    andi.w  #$1F,d0
    lea_    SwScrl_RippleData,a4
    lea (a4,d0.w),a4
 
-   move.b  (a4)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d1,-
 
    subi.w  #$10,d2
    bra.s   --
; ===========================================================================
; byte_D156:
SwScrl_CNZ_RowHeights:
    dc.b  $10
    dc.b  $10   ; 1
    dc.b  $10   ; 2
    dc.b  $10   ; 3
    dc.b  $10   ; 4
    dc.b  $10   ; 5
    dc.b  $10   ; 6
    dc.b  $10   ; 7
    dc.b    0   ; 8
    dc.b -$10   ; 9
    even
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_D160:
    lea (TempArray_LayerDef).w,a1
    move.w  d2,d0
    asr.w   #3,d0
    sub.w   d2,d0
    ext.l   d0
    asl.l   #5,d0
    asl.l   #8,d0
    moveq   #0,d3
    move.w  d2,d3
 
    move.w  #6,d1
-   move.w  d3,(a1)+
    swap    d3
    add.l   d0,d3
    swap    d3
    dbf d1,-
 
    move.w  d2,d0
    asr.w   #3,d0
    move.w  d0,4(a1)
    asr.w   #1,d0
    move.w  d0,(a1)+
    move.w  d0,(a1)+
    rts
; End of function sub_D160
 
; ===========================================================================
; loc_D194:
SwScrl_CNZ_2P:
    move.w  (Camera_Y_pos).w,d0
    lsr.w   #6,d0
    move.w  d0,(Camera_BG_Y_pos).w
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor).w
    move.w  (Camera_X_pos).w,d2
    bsr.w   sub_D160
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    moveq   #0,d0
    move.w  (Camera_X_pos).w,d0
    move.w  #$6F,d2
    lea (SwScrl_CNZ2P_RowHeights+2).l,a3
    bsr.s   sub_D216
    move.w  (Camera_Y_pos_P2).w,d0
    lsr.w   #6,d0
    move.w  d0,(Camera_BG_Y_pos_P2).w
    move.w  d0,(Vscroll_Factor_P2_BG).w
    subi.w  #$E0,(Vscroll_Factor_P2_BG).w
    move.w  (Camera_Y_pos_P2).w,(Vscroll_Factor_P2_FG).w
    subi.w  #$E0,(Vscroll_Factor_P2_FG).w
    andi.l  #$FFFEFFFE,(Vscroll_Factor_P2).w
    move.w  (Camera_X_pos_P2).w,d2
    bsr.w   sub_D160
    lea (Horiz_Scroll_Buf+$1B0).w,a1
    move.w  (Camera_BG_Y_pos_P2).w,d1
    moveq   #0,d0
    move.w  (Camera_X_pos_P2).w,d0
    move.w  #bytesToLcnt($1D0),d2
    lea (SwScrl_CNZ2P_RowHeights+1).l,a3
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_D216:
    lsr.w   #1,d1
    lea (TempArray_LayerDef).w,a2
    moveq   #0,d3
 
-   move.b  (a3)+,d3
    addq.w  #2,a2
    sub.w   d3,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
 
-   move.w  (a2)+,d0
    neg.w   d0
    move.b  (a3)+,d1
    beq.s   ++
+
    dbf d2,--
 
    rts
; ===========================================================================
+
    move.w  #bytesToLcnt($20),d1
    move.w  d0,d3
    move.b  (Vint_runcount+3).w,d0
    lsr.w   #3,d0
    neg.w   d0
    andi.w  #$1F,d0
    lea_    SwScrl_RippleData,a4
    lea (a4,d0.w),a4
 
-   move.b  (a4)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d1,-
 
    subq.w  #8,d2
    bra.s   --
; End of function sub_D216
 
; ===========================================================================
; byte_D270:
SwScrl_CNZ2P_RowHeights:
    dc.b   4
    dc.b   4    ; 1
    dc.b   8    ; 2
    dc.b   8    ; 3
    dc.b   8    ; 4
    dc.b   8    ; 5
    dc.b   8    ; 6
    dc.b   8    ; 7
    dc.b   8    ; 8
    dc.b   8    ; 9
    dc.b   0    ; 10
    dc.b $78    ; 11
    even
; ===========================================================================
; loc_D27C:
SwScrl_CPZ:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #5,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #6,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #7,d4
    moveq   #4,d6
    bsr.w   SetHorizScrollFlagsBG2
    move.w  (Camera_BG_Y_pos).w,d0
    move.w  d0,(Camera_BG2_Y_pos).w
    move.w  d0,(Vscroll_Factor_BG).w
    move.b  (Scroll_flags_BG).w,d0
    or.b    (Scroll_flags_BG2).w,d0
    move.b  d0,(Scroll_flags_BG3).w
    clr.b   (Scroll_flags_BG).w
    clr.b   (Scroll_flags_BG2).w
    move.b  (Vint_runcount+3).w,d1
    andi.w  #7,d1
    bne.s   +
    subq.w  #1,(TempArray_LayerDef).w
+
    lea (CPZ_CameraSections+1).l,a0
    move.w  (Camera_BG_Y_pos).w,d0
    move.w  d0,d2
    andi.w  #$3F0,d0
    lsr.w   #4,d0
    lea (a0,d0.w),a0
    move.w  d0,d4
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #$E,d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    andi.w  #$F,d2
    move.w  (Camera_BG_X_pos).w,d0
    cmpi.b  #$12,d4
    beq.s   loc_D34A
    blo.s   +
    move.w  (Camera_BG2_X_pos).w,d0
+
    neg.w   d0
    add.w   d2,d2
    jmp ++(pc,d2.w)
; ===========================================================================
 
-   move.w  (Camera_BG_X_pos).w,d0
    cmpi.b  #$12,d4
    beq.s   +++
    blo.s   +
    move.w  (Camera_BG2_X_pos).w,d0
+
    neg.w   d0
 
+   rept 16
    move.l  d0,(a1)+
    endm
    addq.b  #1,d4
    dbf d1,-
    rts
; ===========================================================================
 
loc_D34A:
    move.w  #bytesToLcnt($40),d0
    sub.w   d2,d0
    move.w  d0,d2
    bra.s   ++
; ===========================================================================
+
    move.w  #$F,d2
+
    move.w  (Camera_BG_X_pos).w,d3
    neg.w   d3
    move.w  (TempArray_LayerDef).w,d0
    andi.w  #$1F,d0
    lea_    SwScrl_RippleData,a2
    lea (a2,d0.w),a2
 
-   move.b  (a2)+,d0
    ext.w   d0
    add.w   d3,d0
    move.l  d0,(a1)+
    dbf d2,-
 
    addq.b  #1,d4
    dbf d1,--
    rts
; ===========================================================================
; loc_D382:
SwScrl_DEZ:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #8,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #8,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    move.w  (Camera_X_pos).w,d4
    lea (TempArray_LayerDef).w,a2
    move.w  d4,(a2)+
 
    addq.w  #3,(a2)+ ; these random-seeming numbers control how fast each row of stars scrolls by
    addq.w  #2,(a2)+
    addq.w  #4,(a2)+
    addq.w  #1,(a2)+
    addq.w  #2,(a2)+
    addq.w  #4,(a2)+
    addq.w  #3,(a2)+
    addq.w  #4,(a2)+
    addq.w  #2,(a2)+
    addq.w  #6,(a2)+
    addq.w  #3,(a2)+
    addq.w  #4,(a2)+
    addq.w  #1,(a2)+
    addq.w  #2,(a2)+
    addq.w  #4,(a2)+
    addq.w  #3,(a2)+
    addq.w  #2,(a2)+
    addq.w  #3,(a2)+
    addq.w  #4,(a2)+
    addq.w  #1,(a2)+
    addq.w  #3,(a2)+
    addq.w  #4,(a2)+
    addq.w  #2,(a2)+
    addq.w  #1,(a2)
 
    move.w  (a2)+,d0 ; this is to make one row go at half speed (1 pixel every other frame)
    moveq   #0,d1
    move.w  d0,d1
    lsr.w   #1,d0
    move.w  d0,(a2)+
 
    addq.w  #3,(a2)+ ; more star speeds...
    addq.w  #2,(a2)+
    addq.w  #4,(a2)+
 
    swap    d1
    move.l  d1,d0
    lsr.l   #3,d1
    sub.l   d1,d0
    swap    d0
    move.w  d0,4(a2)
    swap    d0
    sub.l   d1,d0
    swap    d0
    move.w  d0,2(a2)
    swap    d0
    sub.l   d1,d0
    swap    d0
    move.w  d0,(a2)+
    addq.w  #4,a2
    addq.w  #1,(a2)+
    move.w  d4,(a2)+
    move.w  d4,(a2)+
    move.w  d4,(a2)+
    lea (SwScrl_DEZ_RowHeights).l,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    moveq   #0,d0
 
-   move.b  (a3)+,d0
    addq.w  #2,a2
    sub.w   d0,d1
    bcc.s   -
 
    neg.w   d1
    subq.w  #2,a2
    move.w  #bytesToLcnt($380),d2
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (a2)+,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    subq.w  #1,d1
    bne.s   +
    move.b  (a3)+,d1
    move.w  (a2)+,d0
    neg.w   d0
+   dbf d2,-
 
    moveq   #0,d2
    tst.b   (Screen_Shaking_Flag).w
    beq.s   ++  ; rts
    subq.w  #1,(DEZ_Shake_Timer).w
    bpl.s   +
    clr.b   (Screen_Shaking_Flag).w
+
    move.w  (Timer_frames).w,d0
    andi.w  #$3F,d0
    lea_    SwScrl_RippleData,a1
    lea (a1,d0.w),a1
    moveq   #0,d0
    move.b  (a1)+,d0
    add.w   d0,(Vscroll_Factor_FG).w
    add.w   d0,(Vscroll_Factor_BG).w
    add.w   d0,(Camera_Y_pos_copy).w
    move.b  (a1)+,d2
    add.w   d2,(Camera_X_pos_copy).w
+
    rts
; ===========================================================================
; byte_D48A:
SwScrl_DEZ_RowHeights:
    dc.b $80
    dc.b   8    ; 1
    dc.b   8    ; 2
    dc.b   8    ; 3
    dc.b   8    ; 4
    dc.b   8    ; 5
    dc.b   8    ; 6
    dc.b   8    ; 7
    dc.b   8    ; 8
    dc.b   8    ; 9
    dc.b   8    ; 10
    dc.b   8    ; 11
    dc.b   8    ; 12
    dc.b   8    ; 13
    dc.b   8    ; 14
    dc.b   8    ; 15
    dc.b   8    ; 16
    dc.b   8    ; 17
    dc.b   8    ; 18
    dc.b   8    ; 19
    dc.b   8    ; 20
    dc.b   8    ; 21
    dc.b   8    ; 22
    dc.b   8    ; 23
    dc.b   8    ; 24
    dc.b   8    ; 25
    dc.b   8    ; 26
    dc.b   8    ; 27
    dc.b   8    ; 28
    dc.b   3    ; 29
    dc.b   5    ; 30
    dc.b   8    ; 31
    dc.b $10    ; 32
    dc.b $80    ; 33
    dc.b $80    ; 34
    dc.b $80    ; 35
    even
; ===========================================================================
; loc_D4AE:
SwScrl_ARZ:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    muls.w  #$119,d4
    moveq   #2,d6
    bsr.w   SetHorizScrollFlagsBG_ARZ
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #7,d5
    tst.b   (Current_Act).w
    bne.s   +
    asl.l   #1,d5
+
    moveq   #6,d6
    bsr.w   SetVertiScrollFlagsBG
 
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
 
    moveq   #0,d2
    tst.b   (Screen_Shaking_Flag).w
    beq.s   .screenNotShaking
 
    move.w  (Timer_frames).w,d0
    andi.w  #$3F,d0
    lea_    SwScrl_RippleData,a1
    lea (a1,d0.w),a1
    moveq   #0,d0
    ; Shake camera Y-pos (note that BG scrolling is not affected by this, causing it to distort)
    move.b  (a1)+,d0
    add.w   d0,(Vscroll_Factor_FG).w
    add.w   d0,(Vscroll_Factor_BG).w
    add.w   d0,(Camera_Y_pos_copy).w
    ; Shake camera X-pos
    move.b  (a1)+,d2
    add.w   d2,(Camera_X_pos_copy).w
 
.screenNotShaking:
    lea (TempArray_LayerDef).w,a2   ; Starts at BG scroll row 1
    lea 6(a2),a3            ; Starts at BG scroll row 4
 
    ; Set up the speed of each row (there are 16 rows in total)
    move.w  (Camera_X_pos).w,d0
    ext.l   d0
    asl.l   #4,d0
    divs.w  #$A,d0
    ext.l   d0
    asl.l   #4,d0
    asl.l   #8,d0
    move.l  d0,d1
 
    ; Set row 4's speed
    swap    d1
    move.w  d1,(a3)+    ; Top row of background moves 10 ($A) times slower than foreground
    swap    d1
    add.l   d1,d1
    add.l   d0,d1
    ; Set rows 5-10's speed
    rept 6
    swap    d1
    move.w  d1,(a3)+    ; Next row moves 3 times faster than top row, then next row is 4 times faster, then 5, etc.
    swap    d1
    add.l   d0,d1
    endm
    ; Set row 11's speed
    swap    d1
    move.w  d1,(a3)+
 
    ; These instructions reveal that ARZ had slightly different scrolling,
    ; at one point:
    ; Above the background's mountains is a row of leaves, which is actually
    ; composed of three separately-scrolling rows. According to this code,
    ; the first and third rows were meant to scroll at a different speed to the
    ; second. Possibly due to how bad it looks, the speed values are overwritten
    ; a few instructions later, so all three move at the same speed.
    ; This code seems to pre-date the Simon Wai build, which uses the final's
    ; scrolling.
    move.w  d1,(a2)     ; Set row 1's speed
    move.w  d1,4(a2)    ; Set row 3's speed
 
    move.w  (Camera_BG_X_pos).w,d0
    move.w  d0,2(a2)    ; Set row 2's speed
    move.w  d0,$16(a2)  ; Set row 12's speed
    _move.w d0,0(a2)    ; Overwrite row 1's speed (now same as row 2's)
    move.w  d0,4(a2)    ; Overwrite row 3's speed (now same as row 2's)
    move.w  d0,$18(a2)  ; Set row 13's speed
    move.w  d0,$1A(a2)  ; Set row 14's speed
    move.w  d0,$1C(a2)  ; Set row 15's speed
    move.w  d0,$1E(a2)  ; Set row 16's speed
 
    lea (SwScrl_ARZ_RowHeights).l,a3
    lea (TempArray_LayerDef).w,a2
    lea (Horiz_Scroll_Buf).w,a1
    move.w  (Camera_BG_Y_pos).w,d1
    moveq   #0,d0
 
    ; Find which row of background is visible at the top of the screen
.findTopRowLoop:
    move.b  (a3)+,d0    ; Get row height
    addq.w  #2,a2       ; Next row speed (note: is off by 2. This is fixed below)
    sub.w   d0,d1
    bcc.s   .findTopRowLoop     ; If current row is above the screen, loop and do next row
 
    neg.w   d1  ; d1 now contains how many pixels of the row is currently on-screen
    subq.w  #2,a2   ; Get correct row speed
 
    move.w  #bytesToLcnt($380),d2   ; Actual size of Horiz_Scroll_Buf
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0      ; Store FG X-pos in upper 16-bits...
    move.w  (a2)+,d0    ; ...and BG X-pos in lower 16 bits, as Horiz_Scroll_Buf expects it
    neg.w   d0
 
-   move.l  d0,(a1)+    ; Write 1 FG Horizontal Scroll value, and 1 BG Horizontal Scroll value
    subq.w  #1,d1       ; Loop until row at top of screen is done
    bne.s   +
    move.b  (a3)+,d1    ; Once that row is done, go to next row...
    move.w  (a2)+,d0    ; ...and use next speed
    neg.w   d0
+   dbf d2,-        ; Loop until Horiz_Scroll_Buf is full
 
    rts
; ===========================================================================
; byte_D5CE:
SwScrl_ARZ_RowHeights:
    dc.b $B0
    dc.b $70    ; 1
    dc.b $30    ; 2
    dc.b $60    ; 3
    dc.b $15    ; 4
    dc.b  $C    ; 5
    dc.b  $E    ; 6
    dc.b   6    ; 7
    dc.b  $C    ; 8
    dc.b $1F    ; 9
    dc.b $30    ; 10
    dc.b $C0    ; 11
    dc.b $F0    ; 12
    dc.b $F0    ; 13
    dc.b $F0    ; 14
    dc.b $F0    ; 15
    even
; ===========================================================================
; loc_D5DE:
SwScrl_SCZ:
    tst.w   (Debug_placement_mode).w
    bne.w   SwScrl_Minimal
    lea (Camera_X_pos).w,a1
    lea (Scroll_flags).w,a3
    lea (Camera_X_pos_diff).w,a4
    move.w  (Tornado_Velocity_X).w,d0
    move.w  (a1),d4
    add.w   (a1),d0
    move.w  d0,d1
    sub.w   (a1),d1
    asl.w   #8,d1
    move.w  d0,(a1)
    move.w  d1,(a4)
    lea (Horiz_block_crossed_flag).w,a2
    bsr.w   SetHorizScrollFlags
    lea (Camera_Y_pos).w,a1
    lea (Camera_Y_pos_diff).w,a4
    move.w  (Tornado_Velocity_Y).w,d0
    move.w  (a1),d4
    add.w   (a1),d0
    move.w  d0,d1
    sub.w   (a1),d1
    asl.w   #8,d1
    move.w  d0,(a1)
    move.w  d1,(a4)
    lea (Verti_block_crossed_flag).w,a2
    bsr.w   SetVertiScrollFlags
    move.w  (Camera_X_pos_diff).w,d4
    beq.s   +
    move.w  #$100,d4
+
    ext.l   d4
    asl.l   #7,d4
    moveq   #0,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($380),d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; loc_D666:
SwScrl_Minimal:
    move.w  (Camera_X_pos_diff).w,d4
    ext.l   d4
    asl.l   #5,d4
    move.w  (Camera_Y_pos_diff).w,d5
    ext.l   d5
    asl.l   #6,d5
    bsr.w   SetHorizVertiScrollFlagsBG
    move.w  (Camera_BG_Y_pos).w,(Vscroll_Factor_BG).w
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #bytesToLcnt($380),d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    move.w  (Camera_BG_X_pos).w,d0
    neg.w   d0
 
-   move.l  d0,(a1)+
    dbf d1,-
 
    rts
; ===========================================================================
; unused...
; loc_D69E:
SwScrl_HPZ_Continued:
    lea (Horiz_Scroll_Buf).w,a1
    move.w  #$E,d1
    move.w  (Camera_X_pos).w,d0
    neg.w   d0
    swap    d0
    andi.w  #$F,d2
    add.w   d2,d2
    move.w  (a2)+,d0
    jmp +(pc,d2.w)
; ===========================================================================
 
-   move.w  (a2)+,d0
 
+   rept 16
    move.l  d0,(a1)+
    endm
    dbf d1,-
 
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to set horizontal scroll flags
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D6E2:
SetHorizScrollFlags:
    move.w  (a1),d0     ; get camera X pos
    andi.w  #$10,d0 
    move.b  (a2),d1 
    eor.b   d1,d0       ; has the camera crossed a 16-pixel boundary?
    bne.s   ++      ; if not, branch
    eori.b  #$10,(a2)
    move.w  (a1),d0     ; get camera X pos
    sub.w   d4,d0       ; subtract previous camera X pos
    bpl.s   +       ; branch if the camera has moved forward
    bset    #2,(a3)     ; set moving back in level bit
    rts
; ===========================================================================
+
    bset    #3,(a3)     ; set moving forward in level bit
+
    rts
; End of function SetHorizScrollFlags
 
; ---------------------------------------------------------------------------
; Subroutine to scroll the camera horizontally
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D704:
ScrollHoriz:
    move.w  (a1),d4     ; get camera X pos
    tst.b   (Teleport_flag).w
    bne.s   .return     ; if a teleport is in progress, return
    move.w  (a5),d1     ; should scrolling be delayed?
    beq.s   .scrollNotDelayed   ; if not, branch
    subi.w  #$100,d1    ; reduce delay value
    move.w  d1,(a5)
    moveq   #0,d1
    move.b  (a5),d1     ; get delay value
    lsl.b   #2,d1       ; multiply by 4, the size of a position buffer entry
    addq.b  #4,d1
    move.w  2(a5),d0    ; get current position buffer index
    sub.b   d1,d0
    move.w  (a6,d0.w),d0    ; get Sonic's position a certain number of frames ago
    andi.w  #$3FFF,d0
    bra.s   .checkIfShouldScroll    ; use that value for scrolling
; ===========================================================================
; loc_D72E:
.scrollNotDelayed:
    move.w  x_pos(a0),d0
; loc_D732:
.checkIfShouldScroll:
    sub.w   (a1),d0
    subi.w  #(320/2)-16,d0      ; is the player less than 144 pixels from the screen edge?
    blt.s   .scrollLeft ; if he is, scroll left
    subi.w  #16,d0      ; is the player more than 159 pixels from the screen edge?
    bge.s   .scrollRight    ; if he is, scroll right
    clr.w   (a4)        ; otherwise, don't scroll
; return_D742:
.return:
    rts
; ===========================================================================
; loc_D744:
.scrollLeft:
    cmpi.w  #-16,d0
    bgt.s   .maxNotReached
    move.w  #-16,d0     ; limit scrolling to 16 pixels per frame
; loc_D74E:
.maxNotReached:
    add.w   (a1),d0     ; get new camera position
    cmp.w   (a2),d0     ; is it greater than the minimum position?
    bgt.s   .doScroll       ; if it is, branch
    move.w  (a2),d0     ; prevent camera from going any further back
    bra.s   .doScroll
; ===========================================================================
; loc_D758:
.scrollRight:
    cmpi.w  #16,d0
    blo.s   .maxNotReached2
    move.w  #16,d0
; loc_D762:
.maxNotReached2:
    add.w   (a1),d0     ; get new camera position
    cmp.w   Camera_Max_X_pos-Camera_Min_X_pos(a2),d0    ; is it less than the max position?
    blt.s   .doScroll   ; if it is, branch
    move.w  Camera_Max_X_pos-Camera_Min_X_pos(a2),d0    ; prevent camera from going any further forward
; loc_D76E:
.doScroll:
    move.w  d0,d1
    sub.w   (a1),d1     ; subtract old camera position
    asl.w   #8,d1       ; shift up by a byte
    move.w  d0,(a1)     ; set new camera position
    move.w  d1,(a4)     ; set difference between old and new positions
    rts
; End of function ScrollHoriz
 
; ---------------------------------------------------------------------------
; Subroutine to scroll the camera vertically
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; The upper 16 bits of Camera_Y_pos is the actual Y-pos, the lower ones seem
; unused, yet this code goes to a strange extent to manage them.
;sub_D77A:
ScrollVerti:
    moveq   #0,d1
    move.w  y_pos(a0),d0
    sub.w   (a1),d0     ; subtract camera Y pos
    cmpi.w  #-$100,(Camera_Min_Y_pos).w ; does the level wrap vertically?
    bne.s   .noWrap     ; if not, branch
    andi.w  #$7FF,d0
; loc_D78E:
.noWrap:
    btst    #2,status(a0)   ; is the player rolling?
    beq.s   .notRolling ; if not, branch
    subq.w  #5,d0       ; subtract difference between standing and rolling heights
; loc_D798:
.notRolling:
    btst    #1,status(a0)           ; is the player in the air?
    beq.s   .checkBoundaryCrossed_onGround  ; if not, branch
;.checkBoundaryCrossed_inAir:
    ; If Sonic's in the air, he has $20 pixels above and below him to move without disturbing the camera.
    ; The camera movement is also only capped at $10 pixels.
    addi.w  #$20,d0
    sub.w   d3,d0
    bcs.s   .doScroll_fast  ; If Sonic is above the boundary, scroll to catch up to him
    subi.w  #$40,d0
    bcc.s   .doScroll_fast  ; If Sonic is below the boundary, scroll to catch up to him
    tst.b   (Camera_Max_Y_Pos_Changing).w   ; is the max Y pos changing?
    bne.s   .scrollUpOrDown_maxYPosChanging ; if it is, branch
    bra.s   .doNotScroll
; ===========================================================================
; loc_D7B6:
.checkBoundaryCrossed_onGround:
    ; On the ground, the camera follows Sonic very strictly.
    sub.w   d3,d0               ; subtract camera bias
    bne.s   .decideScrollType       ; If Sonic has moved, scroll to catch up to him
    tst.b   (Camera_Max_Y_Pos_Changing).w   ; is the max Y pos changing?
    bne.s   .scrollUpOrDown_maxYPosChanging ; if it is, branch
; loc_D7C0:
.doNotScroll:
    clr.w   (a4)        ; clear Y position difference (Camera_Y_pos_bias)
    rts
; ===========================================================================
; loc_D7C4:
.decideScrollType:
    cmpi.w  #(224/2)-16,d3      ; is the camera bias normal?
    bne.s   .doScroll_slow  ; if not, branch
    mvabs.w inertia(a0),d1  ; get player ground velocity, force it to be positive
    cmpi.w  #$800,d1    ; is the player travelling very fast?
    bhs.s   .doScroll_fast  ; if he is, branch
;.doScroll_medium:
    move.w  #6<<8,d1    ; If player is going too fast, cap camera movement to 6 pixels per frame
    cmpi.w  #6,d0       ; is player going down too fast?
    bgt.s   .scrollDown_max ; if so, move camera at capped speed
    cmpi.w  #-6,d0      ; is player going up too fast?
    blt.s   .scrollUp_max   ; if so, move camera at capped speed
    bra.s   .scrollUpOrDown ; otherwise, move camera at player's speed
; ===========================================================================
; loc_D7EA:
.doScroll_slow:
    move.w  #2<<8,d1    ; If player is going too fast, cap camera movement to 2 pixels per frame
    cmpi.w  #2,d0       ; is player going down too fast?
    bgt.s   .scrollDown_max ; if so, move camera at capped speed
    cmpi.w  #-2,d0      ; is player going up too fast?
    blt.s   .scrollUp_max   ; if so, move camera at capped speed
    bra.s   .scrollUpOrDown ; otherwise, move camera at player's speed
; ===========================================================================
; loc_D7FC:
.doScroll_fast:
    ; related code appears in ScrollBG
    ; S3K uses 24 instead of 16
    move.w  #16<<8,d1   ; If player is going too fast, cap camera movement to $10 pixels per frame
    cmpi.w  #16,d0      ; is player going down too fast?
    bgt.s   .scrollDown_max ; if so, move camera at capped speed
    cmpi.w  #-16,d0     ; is player going up too fast?
    blt.s   .scrollUp_max   ; if so, move camera at capped speed
    bra.s   .scrollUpOrDown ; otherwise, move camera at player's speed
; ===========================================================================
; loc_D80E:
.scrollUpOrDown_maxYPosChanging:
    moveq   #0,d0       ; Distance for camera to move = 0
    move.b  d0,(Camera_Max_Y_Pos_Changing).w    ; clear camera max Y pos changing flag
; loc_D814:
.scrollUpOrDown:
    moveq   #0,d1
    move.w  d0,d1       ; get position difference
    add.w   (a1),d1     ; add old camera Y position
    tst.w   d0      ; is the camera to scroll down?
    bpl.w   .scrollDown ; if it is, branch
    bra.w   .scrollUp
; ===========================================================================
; loc_D824:
.scrollUp_max:
    neg.w   d1  ; make the value negative (since we're going backwards)
    ext.l   d1
    asl.l   #8,d1   ; move this into the upper word, so it lines up with the actual y_pos value in Camera_Y_pos
    add.l   (a1),d1 ; add the two, getting the new Camera_Y_pos value
    swap    d1  ; actual Y-coordinate is now the low word
; loc_D82E:
.scrollUp:
    cmp.w   Camera_Min_Y_pos-Camera_Min_X_pos(a2),d1    ; is the new position less than the minimum Y pos?
    bgt.s   .doScroll   ; if not, branch
    cmpi.w  #-$100,d1
    bgt.s   .minYPosReached
    andi.w  #$7FF,d1
    andi.w  #$7FF,(a1)
    bra.s   .doScroll
; ===========================================================================
; loc_D844:
.minYPosReached:
    move.w  Camera_Min_Y_pos-Camera_Min_X_pos(a2),d1    ; prevent camera from going any further up
    bra.s   .doScroll
; ===========================================================================
; loc_D84A:
.scrollDown_max:
    ext.l   d1
    asl.l   #8,d1       ; move this into the upper word, so it lines up with the actual y_pos value in Camera_Y_pos
    add.l   (a1),d1     ; add the two, getting the new Camera_Y_pos value
    swap    d1      ; actual Y-coordinate is now the low word
; loc_D852:
.scrollDown:
    cmp.w   Camera_Max_Y_pos_now-Camera_Min_X_pos(a2),d1    ; is the new position greater than the maximum Y pos?
    blt.s   .doScroll   ; if not, branch
    subi.w  #$800,d1
    bcs.s   .maxYPosReached
    subi.w  #$800,(a1)
    bra.s   .doScroll
; ===========================================================================
; loc_D864:
.maxYPosReached:
    move.w  Camera_Max_Y_pos_now-Camera_Min_X_pos(a2),d1    ; prevent camera from going any further down
; loc_D868:
.doScroll:
    move.w  (a1),d4     ; get old pos (used by SetVertiScrollFlags)
    swap    d1      ; actual Y-coordinate is now the high word, as Camera_Y_pos expects it
    move.l  d1,d3
    sub.l   (a1),d3
    ror.l   #8,d3
    move.w  d3,(a4)     ; set difference between old and new positions
    move.l  d1,(a1)     ; set new camera Y pos
    rts
; End of function ScrollVerti
 
; ---------------------------------------------------------------------------
; Subroutine to set vertical scroll flags
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
SetVertiScrollFlags:
    move.w  (a1),d0     ; get camera Y pos
    andi.w  #$10,d0
    move.b  (a2),d1
    eor.b   d1,d0       ; has the camera crossed a 16-pixel boundary?
    bne.s   ++      ; if not, branch
    eori.b  #$10,(a2)
    move.w  (a1),d0     ; get camera Y pos
    sub.w   d4,d0       ; subtract old camera Y pos
    bpl.s   +       ; branch if the camera has scrolled down
    bset    #0,(a3)     ; set moving up in level bit
    rts
; ===========================================================================
+
    bset    #1,(a3)     ; set moving down in level bit
+
    rts
; End of function SetVertiScrollFlags
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; d4 is horizontal, d5 vertical, derived from $FFFFEEB0 & $FFFFEEB2 respectively
 
;sub_D89A: ;Hztl_Vrtc_Bg_Deformation:
SetHorizVertiScrollFlagsBG: ; used by lev2, MTZ, HTZ, CPZ, DEZ, SCZ, Minimal
    move.l  (Camera_BG_X_pos).w,d2
    move.l  d2,d0
    add.l   d4,d0   ; add x-shift for this frame
    move.l  d0,(Camera_BG_X_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Horiz_block_crossed_flag_BG).w,d3
    eor.b   d3,d1
    bne.s   ++
    eori.b  #$10,(Horiz_block_crossed_flag_BG).w
    sub.l   d2,d0
    bpl.s   +
    bset    #2,(Scroll_flags_BG).w
    bra.s   ++
; ===========================================================================
+
    bset    #3,(Scroll_flags_BG).w
+
    move.l  (Camera_BG_Y_pos).w,d3
    move.l  d3,d0
    add.l   d5,d0   ; add y-shift for this frame
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Verti_block_crossed_flag_BG).w,d2
    eor.b   d2,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Verti_block_crossed_flag_BG).w
    sub.l   d3,d0
    bpl.s   +
    bset    #0,(Scroll_flags_BG).w
    rts
; ===========================================================================
+
    bset    #1,(Scroll_flags_BG).w
+
    rts
; End of function SetHorizVertiScrollFlagsBG
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D904: ;Horizontal_Bg_Deformation:
SetHorizScrollFlagsBG:  ; used by WFZ, HTZ, HPZ
    move.l  (Camera_BG_X_pos).w,d2
    move.l  d2,d0
    add.l   d4,d0   ; add x-shift for this frame
    move.l  d0,(Camera_BG_X_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Horiz_block_crossed_flag_BG).w,d3
    eor.b   d3,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Horiz_block_crossed_flag_BG).w
    sub.l   d2,d0
    bpl.s   +
    bset    d6,(Scroll_flags_BG).w
    bra.s   ++  ; rts
; ===========================================================================
+
    addq.b  #1,d6
    bset    d6,(Scroll_flags_BG).w
+
    rts
; End of function SetHorizScrollFlagsBG
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D938: ;Vertical_Bg_Deformation1:
SetVertiScrollFlagsBG:      ;   used by WFZ, HTZ, HPZ, ARZ
    move.l  (Camera_BG_Y_pos).w,d3
    move.l  d3,d0
    add.l   d5,d0   ; add y-shift for this frame
 
;loc_D940: ;Vertical_Bg_Deformation2:
SetVertiScrollFlagsBG2:
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Verti_block_crossed_flag_BG).w,d2
    eor.b   d2,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Verti_block_crossed_flag_BG).w
    sub.l   d3,d0
    bpl.s   +
    bset    d6,(Scroll_flags_BG).w  ; everytime Verti_block_crossed_flag_BG changes from $10 to $00
    rts
; ===========================================================================
+
    addq.b  #1,d6
    bset    d6,(Scroll_flags_BG).w  ; everytime Verti_block_crossed_flag_BG changes from $00 to $10
+
    rts
; End of function SetVertiScrollFlagsBG
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D96C: ;ARZ_Bg_Deformation:
SetHorizScrollFlagsBG_ARZ:  ; only used by ARZ
    move.l  (Camera_ARZ_BG_X_pos).w,d0
    add.l   d4,d0
    move.l  d0,(Camera_ARZ_BG_X_pos).w
    lea (Camera_BG_X_pos).w,a1
    move.w  (a1),d2
    move.w  (Camera_ARZ_BG_X_pos).w,d0
    sub.w   d2,d0
    bcs.s   +
    bhi.s   ++
    rts
; ===========================================================================
+
    cmpi.w  #-$10,d0
    bgt.s   ++
    move.w  #-$10,d0
    bra.s   ++
; ===========================================================================
+
    cmpi.w  #$10,d0
    blo.s   +
    move.w  #$10,d0
+
    add.w   (a1),d0
    move.w  d0,(a1)
    move.w  d0,d1
    andi.w  #$10,d1
    move.b  (Horiz_block_crossed_flag_BG).w,d3
    eor.b   d3,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Horiz_block_crossed_flag_BG).w
    sub.w   d2,d0
    bpl.s   +
    bset    d6,(Scroll_flags_BG).w
    bra.s   ++  ; rts
; ===========================================================================
+
    addq.b  #1,d6
    bset    d6,(Scroll_flags_BG).w
+
    rts
; End of function SetHorizScrollFlagsBG_ARZ
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_D9C8: ;CPZ_Bg_Deformation:
SetHorizScrollFlagsBG2: ; only used by CPZ
    move.l  (Camera_BG2_X_pos).w,d2
    move.l  d2,d0
    add.l   d4,d0
    move.l  d0,(Camera_BG2_X_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Horiz_block_crossed_flag_BG2).w,d3
    eor.b   d3,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Horiz_block_crossed_flag_BG2).w
    sub.l   d2,d0
    bpl.s   +
    bset    d6,(Scroll_flags_BG2).w
    bra.s   ++  ; rts
; ===========================================================================
+
    addq.b  #1,d6
    bset    d6,(Scroll_flags_BG2).w
+
    rts
; End of function SetHorizScrollFlagsBG2
 
; ===========================================================================
; some apparently unused code
;SetHorizScrollFlagsBG3:
    move.l  (Camera_BG3_X_pos).w,d2
    move.l  d2,d0
    add.l   d4,d0
    move.l  d0,(Camera_BG3_X_pos).w
    move.l  d0,d1
    swap    d1
    andi.w  #$10,d1
    move.b  (Horiz_block_crossed_flag_BG3).w,d3
    eor.b   d3,d1
    bne.s   ++  ; rts
    eori.b  #$10,(Horiz_block_crossed_flag_BG3).w
    sub.l   d2,d0
    bpl.s   +
    bset    d6,(Scroll_flags_BG3).w
    bra.s   ++  ; rts
; ===========================================================================
+
    addq.b  #1,d6
    bset    d6,(Scroll_flags_BG3).w
+
    rts
; ===========================================================================
; Unused - dead code leftover from S1:
    lea (VDP_control_port).l,a5
    lea (VDP_data_port).l,a6
    lea (Scroll_flags_BG).w,a2
    lea (Camera_BG_X_pos).w,a3
    lea (Level_Layout+$80).w,a4
    move.w  #vdpComm(VRAM_Plane_B_Name_Table,VRAM,WRITE)>>16,d2
    bsr.w   Draw_BG1
    lea (Scroll_flags_BG2).w,a2
    lea (Camera_BG2_X_pos).w,a3
    bra.w   Draw_BG2
 
; ===========================================================================
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to display correct tiles as you move
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; loc_DA5C:
LoadTilesAsYouMove:
    lea (VDP_control_port).l,a5
    lea (VDP_data_port).l,a6
    lea (Scroll_flags_BG_copy).w,a2
    lea (Camera_BG_copy).w,a3
    lea (Level_Layout+$80).w,a4 ; first background line
    move.w  #vdpComm(VRAM_Plane_B_Name_Table,VRAM,WRITE)>>16,d2
    bsr.w   Draw_BG1
    lea (Scroll_flags_BG2_copy).w,a2    ; referred to in CPZ deformation routine, but cleared right after
    lea (Camera_BG2_copy).w,a3
    bsr.w   Draw_BG2    ; Essentially unused, though
    lea (Scroll_flags_BG3_copy).w,a2
    lea (Camera_BG3_copy).w,a3
    bsr.w   Draw_BG3    ; used in CPZ deformation routine
    tst.w   (Two_player_mode).w
    beq.s   +
    lea (Scroll_flags_copy_P2).w,a2
    lea (Camera_P2_copy).w,a3   ; second player camera
    lea (Level_Layout).w,a4
    move.w  #vdpComm(VRAM_Plane_A_Name_Table_2P,VRAM,WRITE)>>16,d2
    bsr.w   Draw_FG_P2
 
+
    lea (Scroll_flags_copy).w,a2
    lea (Camera_RAM_copy).w,a3
    lea (Level_Layout).w,a4
    move.w  #vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE)>>16,d2
    tst.b   (Screen_redraw_flag).w
 
    ; comment out this line to disable blast processing
    beq.s   Draw_FG
 
    move.b  #0,(Screen_redraw_flag).w
    moveq   #-$10,d4
    moveq   #$F,d6
; loc_DACE:
Draw_All:
    movem.l d4-d6,-(sp) ; This whole routine basically redraws the whole
    moveq   #-$10,d5    ; area instead of merely a line of tiles
    move.w  d4,d1
    bsr.w   CalcBlockVRAMPos
    move.w  d1,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1   ; draw the current row
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4     ; move onto the next row
    dbf d6,Draw_All ; repeat for all rows
    move.b  #0,(Scroll_flags_copy).w
    rts
; ===========================================================================
; loc_DAF6:
Draw_FG:
    tst.b   (a2)        ; is any scroll flag set?
    beq.s   return_DB5A ; if not, branch
    bclr    #0,(a2)     ; has the level scrolled up?
    beq.s   +       ; if not, branch
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1   ; redraw upper row
+
    bclr    #1,(a2)     ; has the level scrolled down?
    beq.s   +       ; if not, branch
    move.w  #224,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #224,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1   ; redraw bottom row
+
    bclr    #2,(a2)     ; has the level scrolled to the left?
    beq.s   +   ; if not, branch
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockCol1   ; redraw left-most column
+
    bclr    #3,(a2)     ; has the level scrolled to the right?
    beq.s   return_DB5A ; if not, return
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   DrawBlockCol1   ; redraw right-most column
 
return_DB5A:
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_DB5C:
Draw_FG_P2:
    tst.b   (a2)
    beq.s   return_DBC0
    bclr    #0,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPosB
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1
+
    bclr    #1,(a2)
    beq.s   +
    move.w  #$E0,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPosB
    move.w  #$E0,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1
+
    bclr    #2,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPosB
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockCol1
+
    bclr    #3,(a2)
    beq.s   return_DBC0
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   CalcBlockVRAMPosB
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   DrawBlockCol1
 
return_DBC0:
    rts
; End of function Draw_FG_P2
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_DBC2:
Draw_BG1:
    tst.b   (a2)
    beq.w   return_DC90
    bclr    #0,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1
+
    bclr    #1,(a2)
    beq.s   +
    move.w  #$E0,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$E0,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockRow1
+
    bclr    #2,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   DrawBlockCol1
+
    bclr    #3,(a2)
    beq.s   +
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    move.w  #320,d5
    bsr.w   DrawBlockCol1
+
    bclr    #4,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #0,d5
    bsr.w   CalcBlockVRAMPos2
    moveq   #-$10,d4
    moveq   #0,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow2
+
    bclr    #5,(a2)
    beq.s   +
    move.w  #$E0,d4
    moveq   #0,d5
    bsr.w   CalcBlockVRAMPos2
    move.w  #$E0,d4
    moveq   #0,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow2
+
    bclr    #6,(a2)
    beq.s   +
    moveq   #-$10,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    moveq   #-$10,d4
    moveq   #-$10,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow
+
    bclr    #7,(a2)
    beq.s   return_DC90
    move.w  #$E0,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$E0,d4
    moveq   #-$10,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow
 
return_DC90:
    rts
; End of function Draw_BG1
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_DC92:
Draw_BG2:
    tst.b   (a2)
    beq.w   ++  ; rts
    bclr    #0,(a2)
    beq.s   +
    move.w  #$70,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$70,d4
    moveq   #-$10,d5
    moveq   #2,d6
    bsr.w   DrawBlockCol2
+
    bclr    #1,(a2)
    beq.s   +   ; rts
    move.w  #$70,d4
    move.w  #320,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$70,d4
    move.w  #320,d5
    moveq   #2,d6
    bsr.w   DrawBlockCol2
+
    rts
; End of function Draw_BG2
 
; ===========================================================================
; Scrap Brain Zone 1 block positioning array -- S1 left-over
; Each entry is an index into BGCameraLookup; used to decide the camera to use
; for given block for reloading BG. A entry of 0 means assume X = 0 for section,
; but otherwise loads camera Y for selected camera.
;byte_DCD6
SBZ_CameraSections:
    dc.b   0
    dc.b   0    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   0    ; 4
    dc.b   6    ; 5
    dc.b   6    ; 6
    dc.b   6    ; 7
    dc.b   6    ; 8
    dc.b   6    ; 9
    dc.b   6    ; 10
    dc.b   6    ; 11
    dc.b   6    ; 12
    dc.b   6    ; 13
    dc.b   6    ; 14
    dc.b   4    ; 15
    dc.b   4    ; 16
    dc.b   4    ; 17
    dc.b   4    ; 18
    dc.b   4    ; 19
    dc.b   4    ; 20
    dc.b   4    ; 21
    dc.b   2    ; 22
    dc.b   2    ; 23
    dc.b   2    ; 24
    dc.b   2    ; 25
    dc.b   2    ; 26
    dc.b   2    ; 27
    dc.b   2    ; 28
    dc.b   2    ; 29
    dc.b   2    ; 30
    dc.b   2    ; 31
    dc.b   2    ; 32
    even
; ===========================================================================
; Scrap Brain Zone 1 drawing code -- S1 left-over
; Compare with CPZ drawing code
; begin unused routine
    moveq   #-$10,d4
    bclr    #0,(a2)
    bne.s   +
    bclr    #1,(a2)
    beq.s   +++
    move.w  #$E0,d4
+
    lea_    SBZ_CameraSections+1,a0
    move.w  (Camera_BG_Y_pos).w,d0
    add.w   d4,d0
    andi.w  #$1F0,d0
    lsr.w   #4,d0
    move.b  (a0,d0.w),d0
    lea (BGCameraLookup).l,a3
    movea.w (a3,d0.w),a3    ; Camera, either BG, BG2 or BG3 depending on Y
    beq.s   +
    moveq   #-$10,d5
    movem.l d4-d5,-(sp)
    bsr.w   CalcBlockVRAMPos
    movem.l (sp)+,d4-d5
    bsr.w   DrawBlockRow1
    bra.s   ++
; ===========================================================================
+
    moveq   #0,d5
    movem.l d4-d5,-(sp)
    bsr.w   CalcBlockVRAMPos2
    movem.l (sp)+,d4-d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow2
+
    tst.b   (a2)
    bne.s   +
    rts
; ===========================================================================
+
    moveq   #-$10,d4
    moveq   #-$10,d5
    move.b  (a2),d0
    andi.b  #-$58,d0
    beq.s   +
    lsr.b   #1,d0
    move.b  d0,(a2)
    move.w  #320,d5
+
    lea_    SBZ_CameraSections,a0
    move.w  (Camera_BG_Y_pos).w,d0
    andi.w  #$1F0,d0
    lsr.w   #4,d0
    lea (a0,d0.w),a0
    bra.w   loc_DE86
; end unused routine
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_DD82:
Draw_BG3:
    tst.b   (a2)
    beq.w   ++  ; rts
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.w   Draw_BG3_CPZ
    ; S1 left-over: GHZ used this
    bclr    #0,(a2)
    beq.s   +
    move.w  #$40,d4
    moveq   #-$10,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$40,d4
    moveq   #-$10,d5
    moveq   #2,d6
    bsr.w   DrawBlockCol2
+
    bclr    #1,(a2)
    beq.s   +   ; rts
    move.w  #$40,d4
    move.w  #320,d5
    bsr.w   CalcBlockVRAMPos
    move.w  #$40,d4
    move.w  #320,d5
    moveq   #2,d6
    bsr.w   DrawBlockCol2
+
    rts
; ===========================================================================
; Chemical Plant Zone 1 block positioning array
; Each entry is an index into BGCameraLookup; used to decide the camera to use
; for given block for reloading BG. A entry of 0 means assume X = 0 for section,
; but otherwise loads camera Y for selected camera.
;byte_DDD0
CPZ_CameraSections:
    dc.b   2
    dc.b   2    ; 1
    dc.b   2    ; 2
    dc.b   2    ; 3
    dc.b   2    ; 4
    dc.b   2    ; 5
    dc.b   2    ; 6
    dc.b   2    ; 7
    dc.b   2    ; 8
    dc.b   2    ; 9
    dc.b   2    ; 10
    dc.b   2    ; 11
    dc.b   2    ; 12
    dc.b   2    ; 13
    dc.b   2    ; 14
    dc.b   2    ; 15
    dc.b   2    ; 16
    dc.b   2    ; 17
    dc.b   2    ; 18
    dc.b   2    ; 19
    dc.b   4    ; 20
    dc.b   4    ; 21
    dc.b   4    ; 22
    dc.b   4    ; 23
    dc.b   4    ; 24
    dc.b   4    ; 25
    dc.b   4    ; 26
    dc.b   4    ; 27
    dc.b   4    ; 28
    dc.b   4    ; 29
    dc.b   4    ; 30
    dc.b   4    ; 31
    dc.b   4    ; 32
    dc.b   4    ; 33
    dc.b   4    ; 34
    dc.b   4    ; 35
    dc.b   4    ; 36
    dc.b   4    ; 37
    dc.b   4    ; 38
    dc.b   4    ; 39
    dc.b   4    ; 40
    dc.b   4    ; 41
    dc.b   4    ; 42
    dc.b   4    ; 43
    dc.b   4    ; 44
    dc.b   4    ; 45
    dc.b   4    ; 46
    dc.b   4    ; 47
    dc.b   4    ; 48
    dc.b   4    ; 49
    dc.b   4    ; 50
    dc.b   4    ; 51
    dc.b   4    ; 52
    dc.b   4    ; 53
    dc.b   4    ; 54
    dc.b   4    ; 55
    dc.b   4    ; 56
    dc.b   4    ; 57
    dc.b   4    ; 58
    dc.b   4    ; 59
    dc.b   4    ; 60
    dc.b   4    ; 61
    dc.b   4    ; 62
    dc.b   4    ; 63
    dc.b   4    ; 64
    even
; ===========================================================================
; loc_DE12:
Draw_BG3_CPZ:
    moveq   #-$10,d4    ; bit0 = top row
    bclr    #0,(a2)
    bne.s   +
    bclr    #1,(a2)
    beq.s   ++
    move.w  #$E0,d4     ; bit1 = bottom row
+
    lea_    CPZ_CameraSections+1,a0
    move.w  (Camera_BG_Y_pos).w,d0
    add.w   d4,d0
    andi.w  #$3F0,d0
    lsr.w   #4,d0
    move.b  (a0,d0.w),d0
    movea.w BGCameraLookup(pc,d0.w),a3  ; Camera, either BG, BG2 or BG3 depending on Y
    moveq   #-$10,d5
    movem.l d4-d5,-(sp)
    bsr.w   CalcBlockVRAMPos
    movem.l (sp)+,d4-d5
    bsr.w   DrawBlockRow1
+
    tst.b   (a2)
    bne.s   +
    rts
; ===========================================================================
+
    moveq   #-$10,d4
    moveq   #-$10,d5
    move.b  (a2),d0
    andi.b  #-$58,d0
    beq.s   +
    lsr.b   #1,d0
    move.b  d0,(a2)
    move.w  #320,d5
+
    lea_    CPZ_CameraSections,a0
    move.w  (Camera_BG_Y_pos).w,d0
    andi.w  #$7F0,d0
    lsr.w   #4,d0
    lea (a0,d0.w),a0
    bra.w   loc_DE86
; ===========================================================================
;word_DE7E
BGCameraLookup:
    dc.w Camera_BG_copy ; BG Camera
    dc.w Camera_BG_copy ; BG Camera
    dc.w Camera_BG2_copy    ; BG2 Camera
    dc.w Camera_BG3_copy    ; BG3 Camera
; ===========================================================================
 
loc_DE86:
    tst.w   (Two_player_mode).w
    bne.s   ++
    moveq   #$F,d6
    move.l  #vdpCommDelta($0080),d7
 
-   moveq   #0,d0
    move.b  (a0)+,d0
    btst    d0,(a2)
    beq.s   +
    movea.w BGCameraLookup(pc,d0.w),a3  ; Camera, either BG, BG2 or BG3 depending on Y
    movem.l d4-d5/a0,-(sp)
    movem.l d4-d5,-(sp)
    bsr.w   GetBlockPtr
    movem.l (sp)+,d4-d5
    bsr.w   CalcBlockVRAMPos
    bsr.w   ProcessAndWriteBlock2
    movem.l (sp)+,d4-d5/a0
+
    addi.w  #$10,d4
    dbf d6,-
 
    clr.b   (a2)
    rts
; ===========================================================================
+
    moveq   #$F,d6
    move.l  #vdpCommDelta($0080),d7
 
-   moveq   #0,d0
    move.b  (a0)+,d0
    btst    d0,(a2)
    beq.s   +
    movea.w BGCameraLookup(pc,d0.w),a3  ; Camera, either BG, BG2 or BG3 depending on Y
    movem.l d4-d5/a0,-(sp)
    movem.l d4-d5,-(sp)
    bsr.w   GetBlockPtr
    movem.l (sp)+,d4-d5
    bsr.w   CalcBlockVRAMPos
    bsr.w   ProcessAndWriteBlock2_2P
    movem.l (sp)+,d4-d5/a0
+
    addi.w  #$10,d4
    dbf d6,-
 
    clr.b   (a2)
    rts
; End of function Draw_BG3
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_DF04:
DrawBlockCol1:
    moveq   #$F,d6
 
DrawBlockCol2:
    add.w   (a3),d5     ; add camera X pos
    add.w   4(a3),d4    ; add camera Y pos
    move.l  #vdpCommDelta($0080),d7 ; store VDP command for line increment
    move.l  d0,d1       ; copy byte-swapped VDP command for later access
    bsr.w   GetBlockAddr
    tst.w   (Two_player_mode).w
    bne.s   ++
 
-   move.w  (a0),d3     ; get ID of the 16x16 block
    andi.w  #$3FF,d3
    lsl.w   #3,d3       ; multiply by 8, the size in bytes of a 16x16
    lea (Block_Table).w,a1
    adda.w  d3,a1       ; a1 = address of the current 16x16 in the block table
    move.l  d1,d0
    bsr.w   ProcessAndWriteBlock2
    adda.w  #$10,a0     ; move onto the 16x16 vertically below this one
    addi.w  #$100,d1    ; draw on alternate 8x8 lines
    andi.w  #$FFF,d1
    addi.w  #$10,d4     ; add 16 to Y offset
    move.w  d4,d0
    andi.w  #$70,d0     ; have we reached a new 128x128?
    bne.s   +   ; if not, branch
    bsr.w   GetBlockAddr    ; otherwise, renew the block address
+   dbf d6,-        ; repeat 16 times
 
    rts
; ===========================================================================
 
/   move.w  (a0),d3
    andi.w  #$3FF,d3
    lsl.w   #3,d3
    lea (Block_Table).w,a1
    adda.w  d3,a1
    move.l  d1,d0
    bsr.w   ProcessAndWriteBlock2_2P
    adda.w  #$10,a0
    addi.w  #$80,d1
    andi.w  #$FFF,d1
    addi.w  #$10,d4
    move.w  d4,d0
    andi.w  #$70,d0
    bne.s   +
    bsr.w   GetBlockAddr
+   dbf d6,-
 
    rts
; End of function DrawBlockCol1
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_DF8A: DrawTiles_Vertical:
DrawBlockRow:
    add.w   (a3),d5
    add.w   4(a3),d4
    bra.s   DrawBlockRow3
; End of function DrawBlockRow
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_DF92: DrawTiles_Vertical1:
DrawBlockRow1:
    moveq   #$15,d6
    add.w   (a3),d5     ; add X pos
; loc_DF96: DrawTiles_Vertical2:
DrawBlockRow2:
    add.w   4(a3),d4    ; add Y pos
; loc_DF9A: DrawTiles_Vertical3:
DrawBlockRow3:
    tst.w   (Two_player_mode).w
    bne.s   DrawBlockRow_2P
    move.l  a2,-(sp)
    move.w  d6,-(sp)
    lea (Block_cache).w,a2
    move.l  d0,d1
    or.w    d2,d1
    swap    d1      ; make VRAM write command
    move.l  d1,-(sp)
    move.l  d1,(a5)     ; set up a VRAM write at that address
    swap    d1
    bsr.w   GetBlockAddr
 
-   move.w  (a0),d3     ; get ID of the 16x16 block
    andi.w  #$3FF,d3
    lsl.w   #3,d3       ; multiply by 8, the size in bytes of a 16x16
    lea (Block_Table).w,a1
    adda.w  d3,a1       ; a1 = address of current 16x16 in the block table
    bsr.w   ProcessAndWriteBlock
    addq.w  #2,a0       ; move onto next 16x16
    addq.b  #4,d1       ; increment VRAM write address
    bpl.s   +
    andi.b  #$7F,d1     ; restrict to a single 8x8 line
    swap    d1
    move.l  d1,(a5)     ; set up a VRAM write at a new address
    swap    d1
+
    addi.w  #$10,d5     ; add 16 to X offset
    move.w  d5,d0
    andi.w  #$70,d0     ; have we reached a new 128x128?
    bne.s   +       ; if not, branch
    bsr.w   GetBlockAddr    ; otherwise, renew the block address
+
    dbf d6,-        ; repeat 22 times
 
    move.l  (sp)+,d1
    addi.l  #vdpCommDelta($0080),d1 ; move onto next line
    lea (Block_cache).w,a2
    move.l  d1,(a5)     ; write to this VRAM address
    swap    d1
    move.w  (sp)+,d6
 
-   move.l  (a2)+,(a6)  ; write stored 8x8s
    addq.b  #4,d1       ; increment VRAM write address
    bmi.s   +
    ori.b   #$80,d1     ; force to bottom 8x8 line
    swap    d1
    move.l  d1,(a5)     ; set up a VRAM write at a new address
    swap    d1
+
    dbf d6,-        ; repeat 22 times
 
    movea.l (sp)+,a2
    rts
; ===========================================================================
; loc_E018:
DrawBlockRow_2P:
    move.l  d0,d1
    or.w    d2,d1
    swap    d1
    move.l  d1,(a5)
    swap    d1
    tst.b   d1
    bmi.s   +++
    bsr.w   GetBlockAddr
 
-   move.w  (a0),d3
    andi.w  #$3FF,d3
    lsl.w   #3,d3
    lea (Block_Table).w,a1
    adda.w  d3,a1
    bsr.w   ProcessAndWriteBlock_2P
    addq.w  #2,a0
    addq.b  #4,d1
    bpl.s   +
    andi.b  #$7F,d1
    swap    d1
    move.l  d1,(a5)
    swap    d1
+
    addi.w  #$10,d5
    move.w  d5,d0
    andi.w  #$70,d0
    bne.s   +
    bsr.w   GetBlockAddr
+   dbf d6,-
 
    rts
; ===========================================================================
+
    bsr.w   GetBlockAddr
 
-   move.w  (a0),d3
    andi.w  #$3FF,d3
    lsl.w   #3,d3
    lea (Block_Table).w,a1
    adda.w  d3,a1
    bsr.w   ProcessAndWriteBlock_2P
    addq.w  #2,a0
    addq.b  #4,d1
    bmi.s   +
    ori.b   #$80,d1
    swap    d1
    move.l  d1,(a5)
    swap    d1
+
    addi.w  #$10,d5
    move.w  d5,d0
    andi.w  #$70,d0
    bne.s   +
    bsr.w   GetBlockAddr
+   dbf d6,-
 
    rts
; End of function DrawBlockRow1
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_E09E:
GetBlockAddr:
    movem.l d4-d5,-(sp)
    move.w  d4,d3       ; d3 = camera Y pos + offset
    add.w   d3,d3
    andi.w  #$F00,d3    ; limit to units of $100 ($100 = $80 * 2, $80 = height of a 128x128)
    lsr.w   #3,d5       ; divide by 8
    move.w  d5,d0
    lsr.w   #4,d0       ; divide by 16 (overall division of 128)
    andi.w  #$7F,d0
    add.w   d3,d0       ; get offset of current 128x128 in the level layout table
    moveq   #-1,d3
    clr.w   d3      ; d3 = $FFFF0000
    move.b  (a4,d0.w),d3    ; get tile ID of the current 128x128 tile
    lsl.w   #7,d3       ; multiply by 128, the size in bytes of a 128x128 in RAM
    andi.w  #$70,d4     ; round down to nearest 16-pixel boundary
    andi.w  #$E,d5      ; force this to be a multiple of 16
    add.w   d4,d3       ; add vertical offset of current 16x16
    add.w   d5,d3       ; add horizontal offset of current 16x16
    movea.l d3,a0       ; store address, in the metablock table, of the current 16x16
    movem.l (sp)+,d4-d5
    rts
; End of function GetBlockAddr
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_E0D4:
ProcessAndWriteBlock:
    btst    #3,(a0)     ; is this 16x16 to be Y-flipped?
    bne.s   ProcessAndWriteBlock_FlipY  ; if it is, branch
    btst    #2,(a0)     ; is this 16x16 to be X-flipped?
    bne.s   ProcessAndWriteBlock_FlipX  ; if it is, branch
    move.l  (a1)+,(a6)  ; write top two 8x8s to VRAM
    move.l  (a1)+,(a2)+ ; store bottom two 8x8s for later writing
    rts
; ===========================================================================
 
ProcessAndWriteBlock_FlipX:
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3 ; toggle X-flip flag of the 8x8s
    swap    d3      ; swap the position of the 8x8s
    move.l  d3,(a6)     ; write top two 8x8s to VRAM
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3
    swap    d3
    move.l  d3,(a2)+    ; store bottom two 8x8s for later writing
    rts
; ===========================================================================
 
ProcessAndWriteBlock_FlipY:
    btst    #2,(a0)     ; is this 16x16 to be X-flipped as well?
    bne.s   ProcessAndWriteBlock_FlipXY ; if it is, branch
    move.l  (a1)+,d0
    move.l  (a1)+,d3
    eori.l  #(flip_y<<16)|flip_y,d3 ; toggle Y-flip flag of the 8x8s
    move.l  d3,(a6)     ; write bottom two 8x8s to VRAM
    eori.l  #(flip_y<<16)|flip_y,d0
    move.l  d0,(a2)+    ; store top two 8x8s for later writing
    rts
; ===========================================================================
 
ProcessAndWriteBlock_FlipXY:
    move.l  (a1)+,d0
    move.l  (a1)+,d3
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d3 ; toggle X and Y-flip flags of the 8x8s
    swap    d3
    move.l  d3,(a6)     ; write bottom two 8x8s to VRAM
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d0
    swap    d0
    move.l  d0,(a2)+    ; store top two 8x8s for later writing
    rts
; End of function ProcessAndWriteBlock
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_E136:
ProcessAndWriteBlock_2P:
    btst    #3,(a0)
    bne.s   loc_E154
    btst    #2,(a0)
    bne.s   loc_E146
    move.l  (a1)+,(a6)
    rts
; ===========================================================================
 
loc_E146:
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3
    swap    d3
    move.l  d3,(a6)
    rts
; ===========================================================================
 
loc_E154:
    btst    #2,(a0)
    bne.s   loc_E166
    move.l  (a1)+,d3
    eori.l  #(flip_y<<16)|flip_y,d3
    move.l  d3,(a6)
    rts
; ===========================================================================
 
loc_E166:
    move.l  (a1)+,d3
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d3
    swap    d3
    move.l  d3,(a6)
    rts
; End of function ProcessAndWriteBlock_2P
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_E174:
ProcessAndWriteBlock2:
    or.w    d2,d0
    swap    d0      ; make VRAM write command
    btst    #3,(a0)     ; is the 16x16 to be Y-flipped?
    bne.s   ProcessAndWriteBlock2_FlipY ; if it is, branch
    btst    #2,(a0)     ; is the 16x16 to be X-flipped?
    bne.s   ProcessAndWriteBlock2_FlipX ; if it is, branch
    move.l  d0,(a5)     ; write to this VRAM address
    move.l  (a1)+,(a6)  ; write top two 8x8s
    add.l   d7,d0       ; move onto next line
    move.l  d0,(a5)
    move.l  (a1)+,(a6)  ; write bottom two 8x8s
    rts
; ===========================================================================
 
ProcessAndWriteBlock2_FlipX:
    move.l  d0,(a5)
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3 ; toggle X-flip flag of the 8x8s
    swap    d3      ; swap the position of the 8x8s
    move.l  d3,(a6)     ; write top two 8x8s
    add.l   d7,d0       ; move onto next line
    move.l  d0,(a5)
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3
    swap    d3
    move.l  d3,(a6)     ; write bottom two 8x8s
    rts
; ===========================================================================
 
ProcessAndWriteBlock2_FlipY:
    btst    #2,(a0)     ; is the 16x16 to be X-flipped as well?
    bne.s   ProcessAndWriteBlock2_FlipXY    ; if it is, branch
    move.l  d5,-(sp)
    move.l  d0,(a5)
    move.l  (a1)+,d5
    move.l  (a1)+,d3
    eori.l  #(flip_y<<16)|flip_y,d3 ; toggle Y-flip flag of 8x8s
    move.l  d3,(a6)     ; write bottom two 8x8s
    add.l   d7,d0       ; move onto next line
    move.l  d0,(a5)
    eori.l  #(flip_y<<16)|flip_y,d5
    move.l  d5,(a6)     ; write top two 8x8s
    move.l  (sp)+,d5
    rts
; ===========================================================================
 
ProcessAndWriteBlock2_FlipXY:
    move.l  d5,-(sp)
    move.l  d0,(a5)
    move.l  (a1)+,d5
    move.l  (a1)+,d3
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d3 ; toggle X and Y-flip flags of 8x8s
    swap    d3      ; swap the position of the 8x8s
    move.l  d3,(a6)     ; write bottom two 8x8s
    add.l   d7,d0
    move.l  d0,(a5)
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d5
    swap    d5
    move.l  d5,(a6)     ; write top two 8x8s
    move.l  (sp)+,d5
    rts
; End of function ProcessAndWriteBlock2
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_E1FA:
ProcessAndWriteBlock2_2P:
    or.w    d2,d0
    swap    d0
    btst    #3,(a0)
    bne.s   loc_E220
    btst    #2,(a0)
    bne.s   loc_E210
    move.l  d0,(a5)
    move.l  (a1)+,(a6)
    rts
; ===========================================================================
 
loc_E210:
    move.l  d0,(a5)
    move.l  (a1)+,d3
    eori.l  #(flip_x<<16)|flip_x,d3
    swap    d3
    move.l  d3,(a6)
    rts
; ===========================================================================
 
loc_E220:
    btst    #2,(a0)
    bne.s   loc_E234
    move.l  d0,(a5)
    move.l  (a1)+,d3
    eori.l  #(flip_y<<16)|flip_y,d3
    move.l  d3,(a6)
    rts
; ===========================================================================
 
loc_E234:
    move.l  d0,(a5)
    move.l  (a1)+,d3
    eori.l  #((flip_x|flip_y)<<16)|flip_x|flip_y,d3
    swap    d3
    move.l  d3,(a6)
    rts
; End of function ProcessAndWriteBlock2_2P
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_E244
GetBlockPtr:
    add.w   (a3),d5
    add.w   4(a3),d4
    lea (Block_Table).w,a1
    move.w  d4,d3       ; d3 = camera Y pos + offset
    add.w   d3,d3
    andi.w  #$F00,d3    ; limit to units of $100 ($100 = $80 * 2, $80 = height of a 128x128)
    lsr.w   #3,d5       ; divide by 8
    move.w  d5,d0
    lsr.w   #4,d0       ; divide by 16 (overall division of 128)
    andi.w  #$7F,d0
    add.w   d3,d0       ; get offset of current 128x128 in the level layout table
    moveq   #-1,d3
    clr.w   d3      ; d3 = $FFFF0000
    move.b  (a4,d0.w),d3    ; get tile ID of the current 128x128 tile
    lsl.w   #7,d3       ; multiply by 128, the size in bytes of a 128x128 in RAM
    andi.w  #$70,d4     ; round down to nearest 16-pixel boundary
    andi.w  #$E,d5      ; force this to be a multiple of 16
    add.w   d4,d3       ; add vertical offset of current 16x16
    add.w   d5,d3       ; add horizontal offset of current 16x16
    movea.l d3,a0       ; store address, in the metablock table, of the current 16x16
    move.w  (a0),d3
    andi.w  #$3FF,d3
    lsl.w   #3,d3
    adda.w  d3,a1
    rts
; End of function GetBlockPtr
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_E286: Calc_VRAM_Pos:
CalcBlockVRAMPos:
    add.w   (a3),d5     ; add X pos
 
CalcBlockVRAMPos2:
    tst.w   (Two_player_mode).w
    bne.s   CalcBlockVRAMPos_2P
    add.w   4(a3),d4    ; add Y pos
    andi.w  #$F0,d4     ; round down to the nearest 16-pixel boundary
    andi.w  #$1F0,d5    ; round down to the nearest 16-pixel boundary
    lsl.w   #4,d4       ; make it into units of $100 - the height in plane A of a 16x16
    lsr.w   #2,d5       ; make it into units of 4 - the width in plane A of a 16x16
    add.w   d5,d4       ; combine the two to get final address
    ; access a VDP address in plane name table A ($C000) or B ($E000) if d2 has bit 13 unset or set
    moveq   #vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE)&$FFFF,d0
    swap    d0
    move.w  d4,d0       ; make word-swapped VDP command
    rts
; ===========================================================================
; loc_E2A8:
CalcBlockVRAMPos_2P:
    add.w   4(a3),d4
 
loc_E2AC:
    andi.w  #$1F0,d4
    andi.w  #$1F0,d5
    lsl.w   #3,d4
    lsr.w   #2,d5
    add.w   d5,d4
    ; access a VDP address in plane name table A ($C000) or B ($E000) if d2 has bit 13 unset or set
    moveq   #vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE)&$FFFF,d0
    swap    d0
    move.w  d4,d0
    rts
; End of function CalcBlockVRAMPos
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;loc_E2C2:
CalcBlockVRAMPosB:
    tst.w   (Two_player_mode).w
    bne.s   +
    add.w   4(a3),d4
    add.w   (a3),d5
    andi.w  #$F0,d4
    andi.w  #$1F0,d5
    lsl.w   #4,d4
    lsr.w   #2,d5
    add.w   d5,d4
    ; access a VDP address in 2p plane name table A ($A000) or B ($8000) if d2 has bit 13 unset or set
    moveq   #vdpComm(VRAM_Plane_A_Name_Table_2P,VRAM,WRITE)&$FFFF,d0
    swap    d0
    move.w  d4,d0
    rts
; ===========================================================================
; interestingly, this subroutine was in the Sonic 1 ROM, unused
+
    add.w   4(a3),d4
    add.w   (a3),d5
    andi.w  #$1F0,d4
    andi.w  #$1F0,d5
    lsl.w   #3,d4
    lsr.w   #2,d5
    add.w   d5,d4
    ; access a VDP address in 2p plane name table A ($A000) or B ($8000) if d2 has bit 13 unset or set
    moveq   #vdpComm(VRAM_Plane_A_Name_Table_2P,VRAM,WRITE)&$FFFF,d0
    swap    d0
    move.w  d4,d0
    rts
; End of function CalcBlockVRAMPosB
 
; ===========================================================================
; Loads the background in its initial state into VRAM (plane B).
; Especially important for levels that never re-load the background dynamically
;loc_E300:
DrawInitialBG:
    lea (VDP_control_port).l,a5
    lea (VDP_data_port).l,a6
    lea (Camera_BG_X_pos).w,a3
    lea (Level_Layout+$80).w,a4 ; background
    move.w  #vdpComm(VRAM_Plane_B_Name_Table,VRAM,WRITE)>>16,d2
    moveq   #0,d4
    cmpi.b  #casino_night_zone,(Current_Zone).w
    beq.w   ++
    tst.w   (Two_player_mode).w
    beq.w   +
    cmpi.b  #mystic_cave_zone,(Current_Zone).w
    beq.w   loc_E396
+
    moveq   #-$10,d4
+
    moveq   #$F,d6
-   movem.l d4-d6,-(sp)
    moveq   #0,d5
    move.w  d4,d1
    bsr.w   CalcBlockVRAMPos
    move.w  d1,d4
    moveq   #0,d5
    moveq   #$1F,d6
    move    #$2700,sr
    bsr.w   DrawBlockRow
    move    #$2300,sr
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4
    dbf d6,-
 
    rts
; ===========================================================================
; dead code
    moveq   #-$10,d4
 
    moveq   #$F,d6
-   movem.l d4-d6,-(sp)
    moveq   #0,d5
    move.w  d4,d1
    bsr.w   CalcBlockVRAMPosB
    move.w  d1,d4
    moveq   #0,d5
    moveq   #$1F,d6
    move    #$2700,sr
    bsr.w   DrawBlockRow
    move    #$2300,sr
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4
    dbf d6,-
 
    rts
; ===========================================================================
 
loc_E396:
    moveq   #0,d4
 
    moveq   #$1F,d6
-   movem.l d4-d6,-(sp)
    moveq   #0,d5
    move.w  d4,d1
    bsr.w   loc_E2AC
    move.w  d1,d4
    moveq   #0,d5
    moveq   #$1F,d6
    move    #$2700,sr
    bsr.w   DrawBlockRow3
    move    #$2300,sr
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4
    dbf d6,-
 
    rts
; ===========================================================================
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; loadZoneBlockMaps
 
; Loads block and bigblock mappings for the current Zone.
 
loadZoneBlockMaps:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    lea (LevelArtPointers).l,a2
    lea (a2,d0.w),a2
    move.l  a2,-(sp)
    addq.w  #4,a2
    move.l  (a2)+,d0
    andi.l  #$FFFFFF,d0 ; pointer to block mappings
    movea.l d0,a0
    lea (Block_Table).w,a1
    jsrto   (KosDec).l, JmpTo_KosDec    ; load block maps
    cmpi.b  #hill_top_zone,(Current_Zone).w
    bne.s   +
    lea (Block_Table+$980).w,a1
    lea (BM16_HTZ).l,a0
    jsrto   (KosDec).l, JmpTo_KosDec    ; patch for Hill Top Zone block map
+
    tst.w   (Two_player_mode).w
    beq.s   +
    ; In 2P mode, adjust the block table to halve the pattern index on each block
    lea (Block_Table).w,a1
 
    move.w  #bytesToWcnt(Block_Table_End-Block_Table),d2
-   move.w  (a1),d0     ; read an entry
    move.w  d0,d1
    andi.w  #$F800,d0   ; filter for upper five bits
    andi.w  #$7FF,d1    ; filter for lower eleven bits (patternIndex)
    lsr.w   #1,d1       ; halve the pattern index
    or.w    d1,d0       ; put the parts back together
    move.w  d0,(a1)+    ; change the entry with the adjusted value
    dbf d2,-
+
    move.l  (a2)+,d0
    andi.l  #$FFFFFF,d0 ; pointer to chunk mappings
    movea.l d0,a0
    lea (Chunk_Table).l,a1
    jsrto   (KosDec).l, JmpTo_KosDec
    bsr.w   loadLevelLayout
    movea.l (sp)+,a2    ; zone specific pointer in LevelArtPointers
    addq.w  #4,a2
    moveq   #0,d0
    move.b  (a2),d0 ; PLC2 ID
    beq.s   +
    jsrto   (LoadPLC).l, JmpTo_LoadPLC
+
    addq.w  #4,a2
    moveq   #0,d0
    move.b  (a2),d0 ; palette ID
    jsrto   (PalLoad_Now).l, JmpTo_PalLoad_Now
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
loadLevelLayout:
    moveq   #0,d0
    move.w  (Current_ZoneAndAct).w,d0
    ror.b   #1,d0
    lsr.w   #6,d0
    lea (Off_Level).l,a0
    move.w  (a0,d0.w),d0
    lea (a0,d0.l),a0
    lea (Level_Layout).w,a1
    jmpto   (KosDec).l, JmpTo_KosDec
; End of function loadLevelLayout
 
; ===========================================================================
    lea (Level_Layout).w,a3
    move.w  #bytesToLcnt(Level_Layout_End-Level_Layout),d1
    moveq   #0,d0
 
-   move.l  d0,(a3)+
    dbf d1,-
 
    lea (Level_Layout).w,a3
    moveq   #0,d1
    bsr.w   sub_E4A2
    lea (Level_Layout+$80).w,a3
    moveq   #2,d1
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_E4A2:
    moveq   #0,d0
    move.w  (Current_ZoneAndAct).w,d0
    ror.b   #1,d0
    lsr.w   #5,d0
    add.w   d1,d0
    lea (Off_Level).l,a1
    move.w  (a1,d0.w),d0
    lea (a1,d0.l),a1
    moveq   #0,d1
    move.w  d1,d2
    move.b  (a1)+,d1
    move.b  (a1)+,d2
    move.l  d1,d5
    addq.l  #1,d5
    moveq   #0,d3
    move.w  #$80,d3
    divu.w  d5,d3
    subq.w  #1,d3
 
-   movea.l a3,a0
 
    move.w  d3,d4
-   move.l  a1,-(sp)
 
    move.w  d1,d0
-   move.b  (a1)+,(a0)+
    dbf d0,-
 
    movea.l (sp)+,a1
    dbf d4,--
 
    lea (a1,d5.w),a1
    lea $100(a3),a3
    dbf d2,---
 
    rts
; End of function sub_E4A2
 
; ===========================================================================
    lea ($FE0000).l,a1
    lea ($FE0080).l,a2
    lea (Chunk_Table).l,a3
 
    move.w  #$3F,d1
-   bsr.w   sub_E59C
    bsr.w   sub_E59C
    dbf d1,-
 
    lea ($FE0000).l,a1
    lea ($FF0000).l,a2
 
    move.w  #$3F,d1
-   move.w  #0,(a2)+
    dbf d1,-
 
    move.w  #$3FBF,d1
-   move.w  (a1)+,(a2)+
    dbf d1,-
 
    rts
; ===========================================================================
    lea ($FE0000).l,a1
    lea (Chunk_Table).l,a3
 
    moveq   #$1F,d0
-   move.l  (a1)+,(a3)+
    dbf d0,-
 
    moveq   #0,d7
    lea ($FE0000).l,a1
    move.w  #$FF,d5
 
loc_E55A:
    lea (Chunk_Table).l,a3
    move.w  d7,d6
 
-   movem.l a1-a3,-(sp)
    move.w  #$3F,d0
 
-   cmpm.w  (a1)+,(a3)+
    bne.s   +
    dbf d0,-
    movem.l (sp)+,a1-a3
    adda.w  #$80,a1
    dbf d5,loc_E55A
 
    bra.s   ++
; ===========================================================================
+   movem.l (sp)+,a1-a3
    adda.w  #$80,a3
    dbf d6,--
 
    moveq   #$1F,d0
-   move.l  (a1)+,(a3)+
    dbf d0,-
 
    addq.l  #1,d7
    dbf d5,loc_E55A
/
    bra.s   -   ; infinite loop
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_E59C:
    moveq   #7,d0
-   move.l  (a3)+,(a1)+
    move.l  (a3)+,(a1)+
    move.l  (a3)+,(a1)+
    move.l  (a3)+,(a1)+
    move.l  (a3)+,(a2)+
    move.l  (a3)+,(a2)+
    move.l  (a3)+,(a2)+
    move.l  (a3)+,(a2)+
    dbf d0,-
 
    adda.w  #$80,a1
    adda.w  #$80,a2
    rts
; End of function sub_E59C
 
 ; ===========================================================================
 
    if gameRevision=0
    nop
    endif
 
    if ~~removeJmpTos
; JmpTo_PalLoad2 
JmpTo_PalLoad_Now 
    jmp (PalLoad_Now).l
JmpTo_LoadPLC 
    jmp (LoadPLC).l
JmpTo_KosDec 
    jmp (KosDec).l
 
    align 4
    endif
 
 
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; screen resizing, earthquakage, etc
 
; sub_E5D0:
RunDynamicLevelEvents:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    move.w  DynamicLevelEventIndex(pc,d0.w),d0
    jsr DynamicLevelEventIndex(pc,d0.w)
    moveq   #2,d1
    move.w  (Camera_Max_Y_pos).w,d0
    sub.w   (Camera_Max_Y_pos_now).w,d0
    beq.s   ++  ; rts
    bcc.s   +++
    neg.w   d1
    move.w  (Camera_Y_pos).w,d0
    cmp.w   (Camera_Max_Y_pos).w,d0
    bls.s   +
    move.w  d0,(Camera_Max_Y_pos_now).w
    andi.w  #$FFFE,(Camera_Max_Y_pos_now).w
+
    add.w   d1,(Camera_Max_Y_pos_now).w
    move.b  #1,(Camera_Max_Y_Pos_Changing).w
+
    rts
; ===========================================================================
+
    move.w  (Camera_Y_pos).w,d0
    addi_.w #8,d0
    cmp.w   (Camera_Max_Y_pos_now).w,d0
    blo.s   +
    btst    #1,(MainCharacter+status).w
    beq.s   +
    add.w   d1,d1
    add.w   d1,d1
+
    add.w   d1,(Camera_Max_Y_pos_now).w
    move.b  #1,(Camera_Max_Y_Pos_Changing).w
    rts
; End of function RunDynamicLevelEvents
 
; ===========================================================================
; off_E636:
DynamicLevelEventIndex: zoneOrderedOffsetTable 2,1
    zoneOffsetTableEntry.w LevEvents_EHZ    ;   0 ; EHZ 
    zoneOffsetTableEntry.w LevEvents_001    ;   1 ; LEV1
    zoneOffsetTableEntry.w LevEvents_002    ;   2 ; LEV2
    zoneOffsetTableEntry.w LevEvents_003    ;   3 ; LEV3
    zoneOffsetTableEntry.w LevEvents_MTZ    ;   4 ; MTZ 
    zoneOffsetTableEntry.w LevEvents_MTZ3   ;   5 ; MTZ3
    zoneOffsetTableEntry.w LevEvents_WFZ    ;   6 ; WFZ 
    zoneOffsetTableEntry.w LevEvents_HTZ    ;   7 ; HTZ 
    zoneOffsetTableEntry.w LevEvents_HPZ    ;   8 ; HPZ 
    zoneOffsetTableEntry.w LevEvents_009    ;   9 ; LEV9
    zoneOffsetTableEntry.w LevEvents_OOZ    ;  $A ; OOZ 
    zoneOffsetTableEntry.w LevEvents_MCZ    ;  $B ; MCZ 
    zoneOffsetTableEntry.w LevEvents_CNZ    ;  $C ; CNZ 
    zoneOffsetTableEntry.w LevEvents_CPZ    ;  $D ; CPZ 
    zoneOffsetTableEntry.w LevEvents_DEZ    ;  $E ; DEZ 
    zoneOffsetTableEntry.w LevEvents_ARZ    ;  $F ; ARZ 
    zoneOffsetTableEntry.w LevEvents_SCZ    ; $10 ; SCZ 
    zoneTableEnd
; ===========================================================================
; loc_E658:
LevEvents_EHZ:
    tst.b   (Current_Act).w
    bne.s   LevEvents_EHZ2
    rts
; ---------------------------------------------------------------------------
LevEvents_EHZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_EHZ2_Index(pc,d0.w),d0
    jmp LevEvents_EHZ2_Index(pc,d0.w)
; ===========================================================================
; off_E66E:
LevEvents_EHZ2_Index:   offsetTable
    offsetTableEntry.w LevEvents_EHZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_EHZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_EHZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_EHZ2_Routine4  ; 6
; ===========================================================================
; loc_E676:
LevEvents_EHZ2_Routine1:
    tst.w   (Two_player_mode).w
    bne.s   ++
    cmpi.w  #$2780,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$390,(Camera_Max_Y_pos).w
    move.w  #$390,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_EHZ2_Routine2
+
    rts
; ---------------------------------------------------------------------------
+
    move.w  #$2920,(Camera_Max_X_pos).w
    move.w  #$2920,(Tails_Max_X_pos).w
    rts
; ===========================================================================
; loc_E6B0:
LevEvents_EHZ2_Routine2:
    cmpi.w  #$28F0,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$28F0,(Camera_Min_X_pos).w
    move.w  #$2940,(Camera_Max_X_pos).w
    move.w  #$28F0,(Tails_Min_X_pos).w
    move.w  #$2940,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_EHZ2_Routine3
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #2,(Current_Boss_ID).w
    moveq   #PLCID_EhzBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
+
    rts
; ===========================================================================
; loc_E6EE:
LevEvents_EHZ2_Routine3:
    cmpi.w  #$388,(Camera_Y_pos).w
    blo.s   +
    move.w  #$388,(Camera_Min_Y_pos).w
    move.w  #$388,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
 
    move.b  #ObjID_EHZBoss,id(a1) ; load obj56 (EHZ boss)
    move.b  #$81,subtype(a1)
    move.w  #$29D0,x_pos(a1)
    move.w  #$426,y_pos(a1)
+
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_EHZ2_Routine4
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_E738:
LevEvents_EHZ2_Routine4:
    tst.b   (Boss_defeated_flag).w
    beq.s   +
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
+
    rts
 
; ===========================================================================
; return_E752:
LevEvents_001:
    rts
; ===========================================================================
; return_E754:
LevEvents_002:
    rts
; ===========================================================================
; return_E756:
LevEvents_003:
    rts
; ===========================================================================
; return_E758:
LevEvents_MTZ:
    rts
 
; ===========================================================================
; loc_E75A:
LevEvents_MTZ3:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_MTZ3_Index(pc,d0.w),d0
    jmp LevEvents_MTZ3_Index(pc,d0.w)
; ===========================================================================
; off_E768:
LevEvents_MTZ3_Index: offsetTable
    offsetTableEntry.w LevEvents_MTZ3_Routine1  ; 0
    offsetTableEntry.w LevEvents_MTZ3_Routine2  ; 2
    offsetTableEntry.w LevEvents_MTZ3_Routine3  ; 4
    offsetTableEntry.w LevEvents_MTZ3_Routine4  ; 6
    offsetTableEntry.w LevEvents_MTZ3_Routine5  ; 8
; ===========================================================================
; loc_E772:
LevEvents_MTZ3_Routine1:
    cmpi.w  #$2530,(Camera_X_pos).w
    blo.s   +
    move.w  #$500,(Camera_Max_Y_pos_now).w
    move.w  #$450,(Camera_Max_Y_pos).w
    move.w  #$450,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_MTZ3_Routine2
+
    rts
; ===========================================================================
; loc_E792:
LevEvents_MTZ3_Routine2:
    cmpi.w  #$2980,(Camera_X_pos).w
    blo.s   +
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$400,(Camera_Max_Y_pos).w
    move.w  #$400,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_MTZ3_Routine3
+
    rts
; ===========================================================================
; loc_E7B8:
LevEvents_MTZ3_Routine3:
    cmpi.w  #$2A80,(Camera_X_pos).w
    blo.s   +
    move.w  #$2AB0,(Camera_Min_X_pos).w
    move.w  #$2AB0,(Camera_Max_X_pos).w
    move.w  #$2AB0,(Tails_Min_X_pos).w
    move.w  #$2AB0,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_MTZ3_Routine4
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #7,(Current_Boss_ID).w
    moveq   #PLCID_MtzBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
+
    rts
; ===========================================================================
; loc_E7F6:
LevEvents_MTZ3_Routine4:
    cmpi.w  #$400,(Camera_Y_pos).w
    blo.s   +
    move.w  #$400,(Camera_Min_Y_pos).w
    move.w  #$400,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_MTZBoss,id(a1) ; load obj54 (MTZ boss)
+
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_MTZ3_Routine5
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_E82E:
LevEvents_MTZ3_Routine5:
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    rts
 
; ===========================================================================
; loc_E842:
LevEvents_WFZ:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_WFZ_Index(pc,d0.w),d0
    jsr LevEvents_WFZ_Index(pc,d0.w)
    move.w  (WFZ_LevEvent_Subrout).w,d0
    move.w  LevEvents_WFZ_Index2(pc,d0.w),d0
    jmp LevEvents_WFZ_Index2(pc,d0.w)
; ===========================================================================
; off_E85C:
LevEvents_WFZ_Index2: offsetTable
    offsetTableEntry.w LevEvents_WFZ_Routine5   ; 0
    offsetTableEntry.w LevEvents_WFZ_Routine6   ; 2
    offsetTableEntry.w LevEvents_WFZ_RoutineNull    ; 4
; ===========================================================================
; off_E862:
LevEvents_WFZ_Index: offsetTable
    offsetTableEntry.w LevEvents_WFZ_Routine1   ; 0
    offsetTableEntry.w LevEvents_WFZ_Routine2   ; 2
    offsetTableEntry.w LevEvents_WFZ_Routine3   ; 4
    offsetTableEntry.w LevEvents_WFZ_Routine4   ; 6
; ===========================================================================
; loc_E86A:
LevEvents_WFZ_Routine1:
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  d0,(Camera_BG_Y_offset).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_WFZ_Routine2
    rts
; ===========================================================================
; loc_E88E:
LevEvents_WFZ_Routine2:
    cmpi.w  #$2BC0,(Camera_X_pos).w
    blo.s   +
    cmpi.w  #$580,(Camera_Y_pos).w
    blo.s   +
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_WFZ_Routine3
    move.w  #0,(WFZ_BG_Y_Speed).w
+
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ===========================================================================
; loc_E8C0:
LevEvents_WFZ_Routine3:
    cmpi.w  #$800,(Camera_BG_X_offset).w
    beq.s   +
    addq.w  #2,(Camera_BG_X_offset).w
+
    cmpi.w  #$600,(Camera_BG_X_offset).w
    blt.s   LevEvents_WFZ_Routine3_Part2
    move.w  (WFZ_BG_Y_Speed).w,d0
    moveq   #4,d1
    cmpi.w  #$840,d0
    bhs.s   +
    add.w   d1,d0
    move.w  d0,(WFZ_BG_Y_Speed).w
+
    lsr.w   #8,d0
    add.w   d0,(Camera_BG_Y_offset).w
; loc_E8EC:
LevEvents_WFZ_Routine3_Part2:
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ===========================================================================
; loc_E904:
LevEvents_WFZ_Routine4:
    cmpi.w  #-$2C0,(Camera_BG_X_offset).w
    beq.s   ++
    subi_.w #2,(Camera_BG_X_offset).w
    cmpi.w  #$1B81,(Camera_BG_Y_offset).w
    beq.s   ++
    move.w  (WFZ_BG_Y_Speed).w,d0
    beq.s   +
    moveq   #4,d1
    neg.w   d1
    add.w   d1,d0
    move.w  d0,(WFZ_BG_Y_Speed).w
    lsr.w   #8,d0
+
    addq.w  #1,d0
    add.w   d0,(Camera_BG_Y_offset).w
+
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ===========================================================================
; loc_E94A:
LevEvents_WFZ_Routine5:
    cmpi.w  #$2880,(Camera_X_pos).w
    blo.s   +   ; rts
    cmpi.w  #$400,(Camera_Y_pos).w
    blo.s   +   ; rts
    addq.w  #2,(WFZ_LevEvent_Subrout).w ; => LevEvents_WFZ_Routine6
    moveq   #PLCID_WfzBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    move.w  #$2880,(Camera_Min_X_pos).w
+
    rts
; ===========================================================================
; loc_E96C:
LevEvents_WFZ_Routine6:
    cmpi.w  #$500,(Camera_Y_pos).w
    blo.s   +   ; rts
    addq.w  #2,(WFZ_LevEvent_Subrout).w ; => LevEvents_WFZ_RoutineNull
    st  (Control_Locked).w
    moveq   #PLCID_Tornado,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
+
    rts
; ===========================================================================
; return_E984:
LevEvents_WFZ_RoutineNull:
    rts
 
; ===========================================================================
; loc_E986:
LevEvents_HTZ:
    tst.b   (Current_Act).w
    bne.w   LevEvents_HTZ2
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_HTZ_Index(pc,d0.w),d0
    jmp LevEvents_HTZ_Index(pc,d0.w)
; ===========================================================================
; off_E99C:
LevEvents_HTZ_Index: offsetTable
    offsetTableEntry.w LevEvents_HTZ_Routine1   ; 0 left of earthquake
    offsetTableEntry.w LevEvents_HTZ_Routine2   ; 2 earthquake
    offsetTableEntry.w LevEvents_HTZ_Routine3   ; 4 right of earthquake
; ===========================================================================
; loc_E9A2:
LevEvents_HTZ_Routine1:
    cmpi.w  #$400,(Camera_Y_pos).w
    blo.s   LevEvents_HTZ_Routine1_Part2
    cmpi.w  #$1800,(Camera_X_pos).w
    blo.s   LevEvents_HTZ_Routine1_Part2
    move.b  #1,(Screen_Shaking_Flag_HTZ).w
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  #320,(Camera_BG_Y_offset).w
    subi.w  #$100,(Camera_BG_Y_pos).w
    move.w  #0,(HTZ_Terrain_Delay).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ_Routine2
-
    rts
; ===========================================================================
 
LevEvents_HTZ_Routine1_Part2:
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.s   -   ; rts
    move.w  #$200,d0
    moveq   #0,d1
    move.w  d1,(Camera_BG_X_pos_diff).w
    move.w  d1,(Camera_BG_Y_pos_diff).w
    bsr.w   ScrollBG
    or.w    d0,d1
    bne.s   -   ; rts
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
    rts
; ===========================================================================
; loc_EA0E:
LevEvents_HTZ_Routine2:
    cmpi.w  #$1978,(Camera_X_pos).w
    blo.w   LevEvents_HTZ_Routine2_Continue
    cmpi.w  #$1E00,(Camera_X_pos).w
    blo.s   .keep_shaking
    move.b  #0,(Screen_Shaking_Flag).w
    bra.s   LevEvents_HTZ_Routine2_Continue
; ---------------------------------------------------------------------------
.keep_shaking:
    tst.b   (HTZ_Terrain_Direction).w
    bne.s   .sinking
    cmpi.w  #320,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ_Routine2_Continue
    addq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ_Routine2_Continue
    move.w  #SndID_Rumbling2,d0 ; rumbling sound
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ_Routine2_Continue
; ---------------------------------------------------------------------------
.sinking:
    cmpi.w  #224,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ_Routine2_Continue
    subq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ_Routine2_Continue
    move.w  #SndID_Rumbling2,d0
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ_Routine2_Continue
; ---------------------------------------------------------------------------
.flip_delay:
    move.b  #0,(Screen_Shaking_Flag).w
    subq.w  #1,(HTZ_Terrain_Delay).w
    bpl.s   LevEvents_HTZ_Routine2_Continue
    move.w  #$78,(HTZ_Terrain_Delay).w
    eori.b  #1,(HTZ_Terrain_Direction).w
    move.b  #1,(Screen_Shaking_Flag).w
 
; loc_EAA0:
LevEvents_HTZ_Routine2_Continue:
    cmpi.w  #$1800,(Camera_X_pos).w
    blo.s   .exit_left
    cmpi.w  #$1F00,(Camera_X_pos).w
    bhs.s   .exit_right
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ---------------------------------------------------------------------------
.exit_left:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    subq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ_Routine1
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
; ---------------------------------------------------------------------------
.exit_right:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ_Routine3
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
 
; ===========================================================================
; loc_EB14:
LevEvents_HTZ_Routine3:
    cmpi.w  #$1F00,(Camera_X_pos).w
    bhs.s   LevEvents_HTZ_Routine3_Part2
    move.b  #1,(Screen_Shaking_Flag_HTZ).w
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  #320,(Camera_BG_Y_offset).w
    subi.w  #$100,(Camera_BG_Y_pos).w
    move.w  #0,(HTZ_Terrain_Delay).w
    subq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ_Routine2
-
    rts
; ---------------------------------------------------------------------------
; loc_EB54:
LevEvents_HTZ_Routine3_Part2:
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.s   -   ; rts
    move.w  #$200,d0
    moveq   #0,d1
    move.w  d1,(Camera_BG_X_pos_diff).w
    move.w  d1,(Camera_BG_Y_pos_diff).w
    bsr.w   ScrollBG
    or.w    d0,d1
    bne.s   -   ; rts
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Computes how much the background layer has been scrolled in X and Y and
; stores result to Camera_BG_X_pos_diff and Camera_BG_Y_pos_diff.
; Caps maximum scroll speed to 16 pixels per frame in either direction.
; This is used to decide how much of the BG needs to be reloaded.
;
; Used for rising lava/terrain in HTZ, and for WFZ->DEZ transition in WFZ.
;
; Input:
;   d0  Target X position of background
;   d1  Target Y position of background
;sub_EB78
ScrollBG:
    sub.w   (Camera_BG_X_pos).w,d0
    sub.w   (Camera_BG_X_offset).w,d0
    bpl.s   .going_right
    cmpi.w  #-16,d0
    bgt.s   .skip_x_cap
    move.w  #-16,d0
 
.skip_x_cap:
    bra.s   .move_x
; ===========================================================================
.going_right:
    cmpi.w  #16,d0
    blo.s   .move_x
    move.w  #16,d0
 
.move_x:
    move.b  d0,(Camera_BG_X_pos_diff).w
    sub.w   (Camera_BG_Y_pos).w,d1
    sub.w   (Camera_BG_Y_offset).w,d1
    bpl.s   .going_down
    cmpi.w  #-16,d1
    bgt.s   .skip_y_cap
    move.w  #-16,d1
 
.skip_y_cap:
    bra.s   .move_y
; ===========================================================================
.going_down:
    cmpi.w  #16,d1
    blo.s   .move_y
    move.w  #16,d1
 
.move_y:
    move.b  d1,(Camera_BG_Y_pos_diff).w
    rts
; End of function ScrollBG
 
; ===========================================================================
    ; unused/dead code
    ; This code is probably meant for testing the background scrolling code
    ; used by HTZ and WFZ. It would allows the BG position to be shifted up
    ; and down by the second controller.
    btst    #button_up,(Ctrl_2_Held).w
    beq.s   +
    tst.w   (Camera_BG_Y_offset).w
    beq.s   +
    subq.w  #1,(Camera_BG_Y_offset).w
+
    btst    #button_down,(Ctrl_2_Held).w
    beq.s   +
    cmpi.w  #$700,(Camera_BG_Y_offset).w
    beq.s   +
    addq.w  #1,(Camera_BG_Y_offset).w
+
    rts
; ===========================================================================
 
; sub_EBEA:
LevEvents_HTZ2:
    bsr.w   LevEvents_HTZ2_Prepare
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_HTZ2_Index(pc,d0.w),d0
    jmp LevEvents_HTZ2_Index(pc,d0.w)
; ===========================================================================
; off_EBFC:
LevEvents_HTZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_HTZ2_Routine1  ;   0 earthquake left
    offsetTableEntry.w LevEvents_HTZ2_Routine2  ;   2 earthquake (top)
    offsetTableEntry.w LevEvents_HTZ2_Routine3  ;   4 earthquake right (top)
    offsetTableEntry.w LevEvents_HTZ2_Routine4  ;   6 earthquake (bottom)
    offsetTableEntry.w LevEvents_HTZ2_Routine5  ;   8 earthquake right (bottom)
    offsetTableEntry.w LevEvents_HTZ2_Routine6  ;  $A boss area cutoff
    offsetTableEntry.w LevEvents_HTZ2_Routine7  ;  $C boss area camera shift
    offsetTableEntry.w LevEvents_HTZ2_Routine8  ;  $E boss begin
    offsetTableEntry.w LevEvents_HTZ2_Routine9  ; $10 boss end / extend camera
; ===========================================================================
; loc_EC0E:
LevEvents_HTZ2_Routine1:
    cmpi.w  #$14C0,(Camera_X_pos).w
    blo.s   LevEvents_HTZ2_Routine1_Part2
    move.b  #1,(Screen_Shaking_Flag_HTZ).w
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  #$2C0,(Camera_BG_Y_offset).w
    subi.w  #$100,(Camera_BG_Y_pos).w
    move.w  #0,(HTZ_Terrain_Delay).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine2
    cmpi.w  #$380,(Camera_Y_pos).w
    blo.s   +   ; rts
    move.w  #-$680,(Camera_BG_X_offset).w
    addi.w  #$480,(Camera_BG_X_pos).w
    move.w  #$300,(Camera_BG_Y_offset).w
    addq.b  #6,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine5
/
    rts
; ---------------------------------------------------------------------------
 
LevEvents_HTZ2_Routine1_Part2:
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.s   -   ; rts
    move.w  #$200,d0
    moveq   #0,d1
    move.w  d1,(Camera_BG_X_pos_diff).w
    move.w  d1,(Camera_BG_Y_pos_diff).w
    bsr.w   ScrollBG
    or.w    d0,d1
    bne.s   -   ; rts
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
    rts
 
; ===========================================================================
; loc_EC90:
LevEvents_HTZ2_Routine2:
    cmpi.w  #$1678,(Camera_X_pos).w
    blo.w   LevEvents_HTZ2_Routine2_Continue
    cmpi.w  #$1A00,(Camera_X_pos).w
    blo.s   .keep_shaking
    move.b  #0,(Screen_Shaking_Flag).w
    bra.s   LevEvents_HTZ2_Routine2_Continue
; ---------------------------------------------------------------------------
.keep_shaking:
    tst.b   (HTZ_Terrain_Direction).w
    bne.s   .sinking
    cmpi.w  #$2C0,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ2_Routine2_Continue
    addq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ2_Routine2_Continue
    move.w  #SndID_Rumbling2,d0
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ2_Routine2_Continue
; ---------------------------------------------------------------------------
.sinking:
    cmpi.w  #0,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ2_Routine2_Continue
    subq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ2_Routine2_Continue
    move.w  #SndID_Rumbling2,d0
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ2_Routine2_Continue
; ---------------------------------------------------------------------------
.flip_delay:
    move.b  #0,(Screen_Shaking_Flag).w
    subq.w  #1,(HTZ_Terrain_Delay).w
    bpl.s   LevEvents_HTZ2_Routine2_Continue
    move.w  #$78,(HTZ_Terrain_Delay).w
    eori.b  #1,(HTZ_Terrain_Direction).w
    move.b  #1,(Screen_Shaking_Flag).w
 
; loc_ED22:
LevEvents_HTZ2_Routine2_Continue:
    cmpi.w  #$14C0,(Camera_X_pos).w
    blo.s   .exit_left
    cmpi.w  #$1B00,(Camera_X_pos).w
    bhs.s   .exit_right
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ---------------------------------------------------------------------------
.exit_left:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    subq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine1
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
; ---------------------------------------------------------------------------
.exit_right:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine3
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
; ===========================================================================
; loc_ED96:
LevEvents_HTZ2_Routine3:
    cmpi.w  #$1B00,(Camera_X_pos).w
    bhs.s   LevEvents_HTZ2_Routine3_Part2
    move.b  #1,(Screen_Shaking_Flag_HTZ).w
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  d0,(Camera_BG_X_offset).w
    move.w  #$2C0,(Camera_BG_Y_offset).w
    subi.w  #$100,(Camera_BG_Y_pos).w
    move.w  #0,(HTZ_Terrain_Delay).w
    subq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine2
-
    rts
; ===========================================================================
 
LevEvents_HTZ2_Routine3_Part2:
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.s   -   ; rts
    move.w  #$200,d0
    moveq   #0,d1
    move.w  d1,(Camera_BG_X_pos_diff).w
    move.w  d1,(Camera_BG_Y_pos_diff).w
    bsr.w   ScrollBG
    or.w    d0,d1
    bne.s   -   ; rts
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
    rts
; ===========================================================================
; loc_EDFA:
LevEvents_HTZ2_Routine4:
    cmpi.w  #$15F0,(Camera_X_pos).w
    blo.w   LevEvents_HTZ2_Routine4_Continue
    cmpi.w  #$1AC0,(Camera_X_pos).w
    bhs.s   LevEvents_HTZ2_Routine4_Continue
    tst.b   (HTZ_Terrain_Direction).w
    bne.s   .sinking
    cmpi.w  #$300,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ2_Routine4_Continue
    addq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ2_Routine4_Continue
    move.w  #SndID_Rumbling2,d0
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ2_Routine4_Continue
; ===========================================================================
.sinking:
    cmpi.w  #0,(Camera_BG_Y_offset).w
    beq.s   .flip_delay
    move.w  (Timer_frames).w,d0
    move.w  d0,d1
    andi.w  #3,d0
    bne.s   LevEvents_HTZ2_Routine4_Continue
    subq.w  #1,(Camera_BG_Y_offset).w
    andi.w  #$3F,d1
    bne.s   LevEvents_HTZ2_Routine4_Continue
    move.w  #SndID_Rumbling2,d0
    jsr (PlaySound).l
    bra.s   LevEvents_HTZ2_Routine4_Continue
; ===========================================================================
.flip_delay:
    move.b  #0,(Screen_Shaking_Flag).w
    subq.w  #1,(HTZ_Terrain_Delay).w
    bpl.s   LevEvents_HTZ2_Routine4_Continue
    move.w  #$78,(HTZ_Terrain_Delay).w
    eori.b  #1,(HTZ_Terrain_Direction).w
    move.b  #1,(Screen_Shaking_Flag).w
 
LevEvents_HTZ2_Routine4_Continue:
    cmpi.w  #$14C0,(Camera_X_pos).w
    blo.s   .exit_left
    cmpi.w  #$1B00,(Camera_X_pos).w
    bhs.s   .exit_right
    move.w  (Camera_X_pos_diff).w,(Camera_BG_X_pos_diff).w
    move.w  (Camera_Y_pos_diff).w,(Camera_BG_Y_pos_diff).w
    move.w  (Camera_X_pos).w,d0
    move.w  (Camera_Y_pos).w,d1
    bra.w   ScrollBG
; ===========================================================================
.exit_left:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    subq.b  #6,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine1
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
; ===========================================================================
.exit_right:
    move.l  #$4000000,(Camera_BG_X_pos).w
    moveq   #0,d0
    move.l  d0,(Camera_BG_Y_pos).w
    move.l  d0,(Camera_BG_X_offset).w
    move.b  d0,(HTZ_Terrain_Direction).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine5
    move.w  #MusID_StopSFX,d0
    jsr (PlaySound).l
    rts
; ===========================================================================
; loc_EEF8:
LevEvents_HTZ2_Routine5:
    cmpi.w  #$1B00,(Camera_X_pos).w
    bhs.s   LevEvents_HTZ2_Routine5_Part2
    move.b  #1,(Screen_Shaking_Flag_HTZ).w
    move.l  (Camera_X_pos).w,(Camera_BG_X_pos).w
    move.l  (Camera_Y_pos).w,(Camera_BG_Y_pos).w
    moveq   #0,d0
    move.w  d0,(Camera_BG_X_pos_diff).w
    move.w  d0,(Camera_BG_Y_pos_diff).w
    move.w  #-$680,(Camera_BG_X_offset).w
    addi.w  #$480,(Camera_BG_X_pos).w
    move.w  #$300,(Camera_BG_Y_offset).w
    subi.w  #$100,(Camera_BG_Y_pos).w
    move.w  #0,(HTZ_Terrain_Delay).w
    subq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine4
-
    rts
; ===========================================================================
 
LevEvents_HTZ2_Routine5_Part2:
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.s   -   ; rts
    move.w  #$200,d0
    moveq   #0,d1
    move.w  d1,(Camera_BG_X_pos_diff).w
    move.w  d1,(Camera_BG_Y_pos_diff).w
    bsr.w   ScrollBG
    or.w    d0,d1
    bne.s   -   ; rts
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
    rts
; ===========================================================================
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_EF66:
LevEvents_HTZ2_Prepare:
    cmpi.w  #$2B00,(Camera_X_pos).w
    blo.s   +   ; rts
    cmpi.b  #$A,(Dynamic_Resize_Routine).w
    bge.s   +   ; rts
    move.b  #$A,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine6
    move.b  #0,(Screen_Shaking_Flag_HTZ).w
+
    rts
; End of function LevEvents_HTZ2_Prepare
 
; ===========================================================================
; loc_EF84:
LevEvents_HTZ2_Routine6:
    cmpi.w  #$2C50,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$480,(Camera_Max_Y_pos).w
    move.w  #$480,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine7
+
    rts
; ===========================================================================
; loc_EFAA:
LevEvents_HTZ2_Routine7:
    cmpi.w  #$2EDF,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$2EE0,(Camera_Min_X_pos).w
    move.w  #$2F5E,(Camera_Max_X_pos).w
    move.w  #$2EE0,(Tails_Min_X_pos).w
    move.w  #$2F5E,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine8
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #3,(Current_Boss_ID).w
    moveq   #PLCID_HtzBoss,d0
    jmpto   (LoadPLC).l, JmpTo2_LoadPLC
; ===========================================================================
+
    rts
; ===========================================================================
; loc_EFE8:
LevEvents_HTZ2_Routine8:
    cmpi.w  #$478,(Camera_Y_pos).w
    blo.s   +
    move.w  #$478,(Camera_Min_Y_pos).w
    move.w  #$478,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++  ; rts
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_HTZBoss,id(a1) ; load obj52 (HTZ boss)
+
    addq.b  #2,(Dynamic_Resize_Routine).w ; => LevEvents_HTZ2_Routine9
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F020:
LevEvents_HTZ2_Routine9:
    tst.b   (Boss_defeated_flag).w
    beq.s   ++  ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    cmpi.w  #$30E0,(Camera_X_pos).w
    blo.s   ++  ; rts
    cmpi.w  #$428,(Camera_Min_Y_pos).w
    blo.s   +
    subq.w  #2,(Camera_Min_Y_pos).w
+
    cmpi.w  #$430,(Camera_Max_Y_pos).w
    blo.s   +
    subq.w  #2,(Camera_Max_Y_pos).w
+
    rts
 
; ===========================================================================
; return_F05A:
LevEvents_HPZ:
    rts
 
; ===========================================================================
; return_F05C:
LevEvents_009:
    rts
 
; ===========================================================================
; loc_F05E:
LevEvents_OOZ:
    tst.b   (Current_Act).w
    bne.s   LevEvents_OOZ2
    rts
; ---------------------------------------------------------------------------
; loc_F066:
LevEvents_OOZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_OOZ2_Index(pc,d0.w),d0
    jmp LevEvents_OOZ2_Index(pc,d0.w)
; ===========================================================================
; off_F074:
LevEvents_OOZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_OOZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_OOZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_OOZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_OOZ2_Routine4  ; 6
; ===========================================================================
; loc_F07C:
LevEvents_OOZ2_Routine1:
    cmpi.w  #$2668,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$2D8,(Oil+y_pos).w
    move.w  #$1E0,(Camera_Max_Y_pos).w
    move.w  #$1E0,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ===========================================================================
; loc_F0A8:
LevEvents_OOZ2_Routine2:
    cmpi.w  #$2880,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$2880,(Camera_Min_X_pos).w
    move.w  #$28C0,(Camera_Max_X_pos).w
    move.w  #$2880,(Tails_Min_X_pos).w
    move.w  #$28C0,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #8,(Current_Boss_ID).w
    moveq   #PLCID_OozBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    moveq   #PalID_OOZ_B,d0
    jsrto   (PalLoad_Now).l, JmpTo2_PalLoad_Now
+
    rts
; ===========================================================================
; loc_F0EC:
LevEvents_OOZ2_Routine3:
    cmpi.w  #$1D8,(Camera_Y_pos).w
    blo.s   +
    move.w  #$1D8,(Camera_Min_Y_pos).w
    move.w  #$1D8,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++  ; rts
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_OOZBoss,id(a1) ; load obj55 (OOZ boss)
+
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F124:
LevEvents_OOZ2_Routine4:
    tst.b   (Boss_defeated_flag).w
    beq.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
+
    rts
; ===========================================================================
; loc_F13E:
LevEvents_MCZ:
    tst.b   (Current_Act).w
    bne.s   LevEvents_MCZ2
    rts
; ---------------------------------------------------------------------------
; loc_F146:
LevEvents_MCZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_MCZ2_Index(pc,d0.w),d0
    jmp LevEvents_MCZ2_Index(pc,d0.w)
; ===========================================================================
; off_F154:
LevEvents_MCZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_MCZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_MCZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_MCZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_MCZ2_Routine4  ; 6
; ===========================================================================
; loc_F15C:
LevEvents_MCZ2_Routine1:
    tst.w   (Two_player_mode).w
    bne.s   ++
    cmpi.w  #$2080,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$5D0,(Camera_Max_Y_pos).w
    move.w  #$5D0,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ---------------------------------------------------------------------------
+
    move.w  #$2100,(Camera_Max_X_pos).w
    move.w  #$2100,(Tails_Max_X_pos).w
    rts
; ===========================================================================
; loc_F196:
LevEvents_MCZ2_Routine2:
    cmpi.w  #$20F0,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$20F0,(Camera_Max_X_pos).w
    move.w  #$20F0,(Camera_Min_X_pos).w
    move.w  #$20F0,(Tails_Max_X_pos).w
    move.w  #$20F0,(Tails_Min_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtUnc_FallingRocks),VRAM,WRITE),(VDP_control_port).l
    lea (VDP_data_port).l,a6
    lea (ArtUnc_FallingRocks).l,a2
 
    moveq   #7,d0
-   rept 8
    move.l  (a2)+,(a6)
    endm
    dbf d0,-
 
    move.b  #5,(Current_Boss_ID).w
    moveq   #PLCID_MczBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    moveq   #PalID_MCZ_B,d0
    jsrto   (PalLoad_Now).l, JmpTo2_PalLoad_Now
+
    rts
; ===========================================================================
; loc_F206:
LevEvents_MCZ2_Routine3:
    cmpi.w  #$5C8,(Camera_Y_pos).w
    blo.s   +
    move.w  #$5C8,(Camera_Min_Y_pos).w
    move.w  #$5C8,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++  ; rts
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_MCZBoss,id(a1) ; load obj57 (MCZ boss)
+
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F23E:
LevEvents_MCZ2_Routine4:
    tst.b   (Screen_Shaking_Flag).w
    beq.s   +
    move.w  (Timer_frames).w,d0
    andi.w  #$1F,d0
    bne.s   +
    move.w  #SndID_Rumbling2,d0
    jsrto   (PlaySound).l, JmpTo3_PlaySound
+
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    rts
 
; ===========================================================================
; loc_F26A:
LevEvents_CNZ:
    jsr (SlotMachine).l
    tst.b   (Current_Act).w
    bne.s   LevEvents_CNZ2
    rts         ; no events for act 1
; ===========================================================================
; loc_F278:
LevEvents_CNZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_CNZ2_Index(pc,d0.w),d0
    jmp LevEvents_CNZ2_Index(pc,d0.w)
; ===========================================================================
; off_F286:
LevEvents_CNZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_CNZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_CNZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_CNZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_CNZ2_Routine4  ; 6
; ===========================================================================
; loc_F28E:
LevEvents_CNZ2_Routine1:
    tst.w   (Two_player_mode).w
    bne.s   ++
    cmpi.w  #$27C0,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$62E,(Camera_Max_Y_pos).w
    move.w  #$62E,(Tails_Max_Y_pos).w
    move.b  #$F9,(Level_Layout+$C54).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ===========================================================================
+
    move.w  #$26A0,(Camera_Max_X_pos).w
    move.w  #$26A0,(Tails_Max_X_pos).w
    rts
; ===========================================================================
; loc_F2CE:
LevEvents_CNZ2_Routine2:
    cmpi.w  #$2890,(Camera_X_pos).w
    blo.s   +   ; rts
    move.b  #$F9,(Level_Layout+$C50).w
    move.w  #$2860,(Camera_Min_X_pos).w
    move.w  #$28E0,(Camera_Max_X_pos).w
    move.w  #$2860,(Tails_Min_X_pos).w
    move.w  #$28E0,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #6,(Current_Boss_ID).w
    moveq   #PLCID_CnzBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    moveq   #PalID_CNZ_B,d0
    jsrto   (PalLoad_Now).l, JmpTo2_PalLoad_Now
+
    rts
; ===========================================================================
; loc_F318:
LevEvents_CNZ2_Routine3:
    cmpi.w  #$4E0,(Camera_Y_pos).w
    blo.s   +
    move.w  #$4E0,(Camera_Min_Y_pos).w
    move.w  #$4E0,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++  ; rts
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_CNZBoss,id(a1) ; load obj51
+
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F350:
LevEvents_CNZ2_Routine4:
    cmpi.w  #$2A00,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$5D0,(Camera_Max_Y_pos).w
    move.w  #$5D0,(Tails_Max_Y_pos).w
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
+
    rts
; ===========================================================================
; loc_F378:
LevEvents_CPZ:
    tst.b   (Current_Act).w
    bne.s   LevEvents_CPZ2
    rts
; ===========================================================================
; loc_F380:
LevEvents_CPZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_CPZ2_Index(pc,d0.w),d0
    jmp LevEvents_CPZ2_Index(pc,d0.w)
; ===========================================================================
; off_F38E:
LevEvents_CPZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_CPZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_CPZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_CPZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_CPZ2_Routine4  ; 6
; ===========================================================================
; loc_F396:
LevEvents_CPZ2_Routine1:
    cmpi.w  #$2680,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$450,(Camera_Max_Y_pos).w
    move.w  #$450,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ===========================================================================
; loc_F3BC:
LevEvents_CPZ2_Routine2:
    cmpi.w  #$2A20,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$2A20,(Camera_Min_X_pos).w
    move.w  #$2A20,(Camera_Max_X_pos).w
    move.w  #$2A20,(Tails_Min_X_pos).w
    move.w  #$2A20,(Tails_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    move.b  #1,(Current_Boss_ID).w
    moveq   #PLCID_CpzBoss,d0
    jmpto   (LoadPLC).l, JmpTo2_LoadPLC
; ===========================================================================
+
    rts
; ===========================================================================
; loc_F3FA:
LevEvents_CPZ2_Routine3:
    cmpi.w  #$448,(Camera_Y_pos).w
    blo.s   +
    move.w  #$448,(Camera_Min_Y_pos).w
    move.w  #$448,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   ++
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +
    move.b  #ObjID_CPZBoss,id(a1) ; load obj5D
+
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F432:
LevEvents_CPZ2_Routine4:
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    rts
; ===========================================================================
; loc_F446:
LevEvents_DEZ:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_DEZ_Index(pc,d0.w),d0
    jmp LevEvents_DEZ_Index(pc,d0.w)
; ===========================================================================
; off_F454:
LevEvents_DEZ_Index: offsetTable
    offsetTableEntry.w LevEvents_DEZ_Routine1   ; 0
    offsetTableEntry.w LevEvents_DEZ_Routine2   ; 2
    offsetTableEntry.w LevEvents_DEZ_Routine3   ; 4
    offsetTableEntry.w LevEvents_DEZ_Routine4   ; 6
    offsetTableEntry.w LevEvents_DEZ_Routine5   ; 8
; ===========================================================================
; loc_F45E:
LevEvents_DEZ_Routine1:
    move.w  #320,d0
    cmp.w   (Camera_X_pos).w,d0
    bhi.s   +   ; rts
    addq.b  #2,(Dynamic_Resize_Routine).w
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +   ; rts
    move.b  #ObjID_MechaSonic,id(a1) ; load objAF (silver sonic)
    move.b  #$48,subtype(a1)
    move.w  #$348,x_pos(a1)
    move.w  #$A0,y_pos(a1)
    moveq   #PLCID_FieryExplosion,d0
    jmpto   (LoadPLC).l, JmpTo2_LoadPLC
; ===========================================================================
+
    rts
; ===========================================================================
; return_F490:
LevEvents_DEZ_Routine2:
    rts
; ===========================================================================
; loc_F492:
LevEvents_DEZ_Routine3:
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    cmpi.w  #$300,(Camera_X_pos).w
    blo.s   +   ; rts
    addq.b  #2,(Dynamic_Resize_Routine).w
    moveq   #PLCID_DezBoss,d0
    jmpto   (LoadPLC).l, JmpTo2_LoadPLC
; ===========================================================================
+
    rts
; ===========================================================================
; loc_F4AC:
LevEvents_DEZ_Routine4:
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  #$680,d0
    cmp.w   (Camera_X_pos).w,d0
    bhi.s   +   ; rts
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  d0,(Camera_Min_X_pos).w
    addi.w  #$C0,d0
    move.w  d0,(Camera_Max_X_pos).w
+
    rts
; ===========================================================================
; return_F4CE:
LevEvents_DEZ_Routine5:
    rts
; ===========================================================================
; loc_F4D0:
LevEvents_ARZ:
    tst.b   (Current_Act).w
    bne.s   LevEvents_ARZ2
    rts
; ===========================================================================
; loc_F4D8:
LevEvents_ARZ2:
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_ARZ2_Index(pc,d0.w),d0
    jmp LevEvents_ARZ2_Index(pc,d0.w)
; ===========================================================================
; off_F4E6:
LevEvents_ARZ2_Index: offsetTable
    offsetTableEntry.w LevEvents_ARZ2_Routine1  ; 0
    offsetTableEntry.w LevEvents_ARZ2_Routine2  ; 2
    offsetTableEntry.w LevEvents_ARZ2_Routine3  ; 4
    offsetTableEntry.w LevEvents_ARZ2_Routine4  ; 6
; ===========================================================================
; loc_F4EE:
LevEvents_ARZ2_Routine1:
    cmpi.w  #$2810,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    move.w  #$400,(Camera_Max_Y_pos).w
    move.w  #$400,(Tails_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.b  #4,(Current_Boss_ID).w
    moveq   #PLCID_ArzBoss,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
+
    rts
; ===========================================================================
; loc_F520:
LevEvents_ARZ2_Routine2:
    cmpi.w  #$2A40,(Camera_X_pos).w
    blo.s   +   ; rts
    move.w  #$2A40,(Camera_Max_X_pos).w
    move.w  #$2A40,(Camera_Min_X_pos).w
    move.w  #$2A40,(Tails_Max_X_pos).w
    move.w  #$2A40,(Tails_Min_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_FadeOut,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
    clr.b   (ScreenShift).w
    jsrto   (SingleObjLoad).l, JmpTo_SingleObjLoad
    bne.s   +   ; rts
    move.b  #ObjID_ARZBoss,id(a1) ; load obj89
+
    rts
; ===========================================================================
; loc_F55C:
LevEvents_ARZ2_Routine3:
    cmpi.w  #$3F8,(Camera_Y_pos).w
    blo.s   +
    move.w  #$3F8,(Camera_Min_Y_pos).w
    move.w  #$3F8,(Tails_Min_Y_pos).w
+
    addq.b  #1,(ScreenShift).w
    cmpi.b  #$5A,(ScreenShift).w
    blo.s   +   ; rts
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.w  #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo3_PlayMusic
+
    rts
; ===========================================================================
; loc_F58A:
LevEvents_ARZ2_Routine4:
    move.w  (Camera_X_pos).w,(Camera_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_X_pos).w,(Tails_Min_X_pos).w
    rts
; ===========================================================================
; loc_F59E:
LevEvents_SCZ:
    tst.b   (Current_Act).w
    bne.w   LevEvents_SCZ2
    moveq   #0,d0
    move.b  (Dynamic_Resize_Routine).w,d0
    move.w  LevEvents_SCZ_Index(pc,d0.w),d0
    jmp LevEvents_SCZ_Index(pc,d0.w)
; ===========================================================================
; off_F5B4:
LevEvents_SCZ_Index: offsetTable
    offsetTableEntry.w LevEvents_SCZ_Routine1   ; 0
    offsetTableEntry.w LevEvents_SCZ_Routine2   ; 2
    offsetTableEntry.w LevEvents_SCZ_Routine3   ; 4
    offsetTableEntry.w LevEvents_SCZ_Routine4   ; 6
    offsetTableEntry.w LevEvents_SCZ_RoutineNull    ; 8
; ===========================================================================
; loc_F5BE:
LevEvents_SCZ_Routine1:
    move.w  #1,(Tornado_Velocity_X).w
    move.w  #0,(Tornado_Velocity_Y).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    rts
; ===========================================================================
; loc_F5D0:
LevEvents_SCZ_Routine2:
    cmpi.w  #$1180,(Camera_X_pos).w
    blo.s   +
    move.w  #-1,(Tornado_Velocity_X).w
    move.w  #1,(Tornado_Velocity_Y).w
    move.w  #$500,(Camera_Max_Y_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ===========================================================================
; loc_F5F0:
LevEvents_SCZ_Routine3:
    cmpi.w  #$500,(Camera_Y_pos).w
    blo.s   +
    move.w  #1,(Tornado_Velocity_X).w
    move.w  #0,(Tornado_Velocity_Y).w
    addq.b  #2,(Dynamic_Resize_Routine).w
+
    rts
; ===========================================================================
; loc_F60A:
LevEvents_SCZ_Routine4:
    cmpi.w  #$1400,(Camera_X_pos).w
    blo.s   LevEvents_SCZ_RoutineNull
    move.w  #0,(Tornado_Velocity_X).w
    move.w  #0,(Tornado_Velocity_Y).w
    addq.b  #2,(Dynamic_Resize_Routine).w
 
; return_F622:
LevEvents_SCZ_RoutineNull:
    rts
; ===========================================================================
; return_F624:
LevEvents_SCZ2:
    rts
; ===========================================================================
 
; loc_F626:
PlayLevelMusic:
    move.w  (Level_Music).w,d0
    jmpto   (PlayMusic).l, JmpTo3_PlayMusic
; ===========================================================================
 
; loc_F62E:
LoadPLC_AnimalExplosion:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    lea (Animal_PLCTable).l,a2
    move.b  (a2,d0.w),d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    moveq   #PLCID_Explosion,d0
    jsrto   (LoadPLC).l, JmpTo2_LoadPLC
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo3_PlaySound 
    jmp (PlaySound).l
; JmpTo2_PalLoad2 
JmpTo2_PalLoad_Now 
    jmp (PalLoad_Now).l
JmpTo2_LoadPLC 
    jmp (LoadPLC).l
JmpTo3_PlayMusic 
    jmp (PlayMusic).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 11 - Bridge in Emerald Hill Zone and Hidden Palace Zone
; ----------------------------------------------------------------------------
; OST Variables:
Obj11_child1        = objoff_30 ; pointer to first set of bridge segments
Obj11_child2        = objoff_34 ; pointer to second set of bridge segments, if applicable
 
; Sprite_F66C:
Obj11:
    btst    #6,render_flags(a0) ; is this a child sprite object?
    bne.w   +           ; if yes, branch
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj11_Index(pc,d0.w),d1
    jmp Obj11_Index(pc,d1.w)
; ===========================================================================
+   ; child sprite objects only need to be drawn
    move.w  #$180,d0
    bra.w   DisplaySprite3
; ===========================================================================
; off_F68C:
Obj11_Index:    offsetTable
        offsetTableEntry.w Obj11_Init       ; 0
        offsetTableEntry.w Obj11_EHZ        ; 2
        offsetTableEntry.w Obj11_Display    ; 4
        offsetTableEntry.w Obj11_HPZ        ; 6
; ===========================================================================
; loc_F694: Obj11_Main:
Obj11_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj11_MapUnc_FC70,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZ_Bridge,2,0),art_tile(a0)
    move.b  #3,priority(a0)
    cmpi.b  #hidden_palace_zone,(Current_Zone).w    ; is this an HPZ bridge?
    bne.s   +           ; if not, branch
    addq.b  #4,routine(a0)
    move.l  #Obj11_MapUnc_FC28,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HPZ_Bridge,3,0),art_tile(a0)
+
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$80,width_pixels(a0)
    move.w  y_pos(a0),d2
    move.w  d2,objoff_3C(a0)
    move.w  x_pos(a0),d3
    lea subtype(a0),a2  ; copy bridge subtype to a2
    moveq   #0,d1
    move.b  (a2),d1     ; d1 = subtype
    move.w  d1,d0
    lsr.w   #1,d0
    lsl.w   #4,d0   ; (d0 div 2) * 16
    sub.w   d0,d3   ; x position of left half
    swap    d1  ; store subtype in high word for later
    move.w  #8,d1
    bsr.s   Obj11_MakeBdgSegment
    move.w  sub6_x_pos(a1),d0
    subq.w  #8,d0
    move.w  d0,x_pos(a1)        ; center of first subsprite object
    move.l  a1,Obj11_child1(a0) ; pointer to first subsprite object
    swap    d1  ; retrieve subtype
    subq.w  #8,d1
    bls.s   +   ; branch, if subtype <= 8 (bridge has no more than 8 logs)
    ; else, create a second subsprite object for the rest of the bridge
    move.w  d1,d4
    bsr.s   Obj11_MakeBdgSegment
    move.l  a1,Obj11_child2(a0) ; pointer to second subsprite object
    move.w  d4,d0
    add.w   d0,d0
    add.w   d4,d0   ; d0*3
    move.w  sub2_x_pos(a1,d0.w),d0
    subq.w  #8,d0
    move.w  d0,x_pos(a1)        ; center of second subsprite object 
+
    bra.s   Obj11_EHZ
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; sub_F728:
Obj11_MakeBdgSegment:
    jsrto   (SingleObjLoad2).l, JmpTo_SingleObjLoad2
    bne.s   +   ; rts
    _move.b id(a0),id(a1) ; load obj11
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  render_flags(a0),render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #$40,mainspr_width(a1)
    move.b  d1,mainspr_childsprites(a1)
    subq.b  #1,d1
    lea sub2_x_pos(a1),a2 ; starting address for subsprite data
 
-   move.w  d3,(a2)+    ; sub?_x_pos
    move.w  d2,(a2)+    ; sub?_y_pos
    move.w  #0,(a2)+    ; sub?_mapframe
    addi.w  #$10,d3     ; width of a log, x_pos for next log
    dbf d1,-    ; repeat for d1 logs
+
    rts
; End of function Obj11_MakeBdgSegment
 
; ===========================================================================
; loc_F77A: Obj11_Action:
Obj11_EHZ:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    tst.b   objoff_3E(a0)
    beq.s   loc_F7BC
    subq.b  #4,objoff_3E(a0)
    bra.s   loc_F7B8
+
    andi.b  #p2_standing,d0
    beq.s   ++
    move.b  objoff_3F(a0),d0
    sub.b   objoff_3B(a0),d0
    beq.s   ++
    bcc.s   +
    addq.b  #1,objoff_3F(a0)
    bra.s   ++
; ---------------------------------------------------------------------------
+
    subq.b  #1,objoff_3F(a0)
+
    cmpi.b  #$40,objoff_3E(a0)
    beq.s   loc_F7B8
    addq.b  #4,objoff_3E(a0)
 
loc_F7B8:
    bsr.w   Obj11_Depress
 
loc_F7BC:
    moveq   #0,d1
    move.b  subtype(a0),d1
    lsl.w   #3,d1
    move.w  d1,d2
    addq.w  #8,d1
    add.w   d2,d2
    moveq   #8,d3
    move.w  x_pos(a0),d4
    bsr.w   sub_F872
 
; loc_F7D4:
Obj11_Unload:
    ; this is essentially MarkObjGone, except we need to delete our subsprite objects as well
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.s   +           ; if not, branch
    rts
; ---------------------------------------------------------------------------
+
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   +
    rts
; ---------------------------------------------------------------------------
+   ; delete first subsprite object
    movea.l Obj11_child1(a0),a1 ; a1=object
    bsr.w   DeleteObject2
    cmpi.b  #8,subtype(a0)
    bls.s   +   ; if bridge has more than 8 logs, delete second subsprite object
    movea.l Obj11_child2(a0),a1 ; a1=object
    bsr.w   DeleteObject2
+
    bra.w   DeleteObject
; ===========================================================================
; loc_F80C: BranchTo_DisplaySprite:
Obj11_Display:
    bra.w   DisplaySprite
; ===========================================================================
; loc_F810: Obj11_Action_HPZ:
Obj11_HPZ:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    tst.b   objoff_3E(a0)
    beq.s   loc_F852
    subq.b  #4,objoff_3E(a0)
    bra.s   loc_F84E
; ===========================================================================
+
    andi.b  #p2_standing,d0
    beq.s   ++
    move.b  objoff_3F(a0),d0
    sub.b   objoff_3B(a0),d0
    beq.s   ++
    bcc.s   +
    addq.b  #1,objoff_3F(a0)
    bra.s   ++
; ===========================================================================
+
    subq.b  #1,objoff_3F(a0)
+
    cmpi.b  #$40,objoff_3E(a0)
    beq.s   loc_F84E
    addq.b  #4,objoff_3E(a0)
 
loc_F84E:
    bsr.w   Obj11_Depress
 
loc_F852:
    moveq   #0,d1
    move.b  subtype(a0),d1
    lsl.w   #3,d1
    move.w  d1,d2
    addq.w  #8,d1
    add.w   d2,d2
    moveq   #8,d3
    move.w  x_pos(a0),d4
    bsr.w   sub_F872
    bsr.w   sub_F912
    bra.w   Obj11_Unload
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_F872:
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    moveq   #$3B,d5
    movem.l d1-d4,-(sp)
    bsr.s   +
    movem.l (sp)+,d1-d4
    lea (MainCharacter).w,a1 ; a1=character
    subq.b  #1,d6
    moveq   #$3F,d5
+
    btst    d6,status(a0)
    beq.s   loc_F8F0
    btst    #1,status(a1)
    bne.s   +
    moveq   #0,d0
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   +
    cmp.w   d2,d0
    blo.s   ++
+
    bclr    #3,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ===========================================================================
+
    lsr.w   #4,d0
    move.b  d0,(a0,d5.w)
    movea.l Obj11_child1(a0),a2
    cmpi.w  #8,d0
    blo.s   +
    movea.l Obj11_child2(a0),a2 ; a2=object
    subi_.w #8,d0
+
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    move.w  sub2_y_pos(a2,d0.w),d0
    subq.w  #8,d0
    moveq   #0,d1
    move.b  y_radius(a1),d1
    sub.w   d1,d0
    move.w  d0,y_pos(a1)
    moveq   #0,d4
    rts
; ===========================================================================
 
loc_F8F0:
    move.w  d1,-(sp)
    jsrto   (PlatformObject11_cont).l, JmpTo_PlatformObject11_cont
    move.w  (sp)+,d1
    btst    d6,status(a0)
    beq.s   +   ; rts
    moveq   #0,d0
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    lsr.w   #4,d0
    move.b  d0,(a0,d5.w)
+
    rts
; End of function sub_F872
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_F912:
    moveq   #0,d0
    tst.w   (MainCharacter+x_vel).w
    bne.s   +
    move.b  (Vint_runcount+3).w,d0
    andi.w  #$1C,d0
    lsr.w   #1,d0
+
    moveq   #0,d2
    move.b  byte_F950+1(pc,d0.w),d2
    swap    d2
    move.b  byte_F950(pc,d0.w),d2
    moveq   #0,d0
    tst.w   (Sidekick+x_vel).w
    bne.s   +
    move.b  (Vint_runcount+3).w,d0
    andi.w  #$1C,d0
    lsr.w   #1,d0
+
    moveq   #0,d6
    move.b  byte_F950+1(pc,d0.w),d6
    swap    d6
    move.b  byte_F950(pc,d0.w),d6
    bra.s   +
; ===========================================================================
byte_F950:
    dc.b   1,  2
    dc.b   1,  2    ; 2
    dc.b   1,  2    ; 4
    dc.b   1,  2    ; 6
    dc.b   0,  1    ; 8
    dc.b   0,  0    ; 10
    dc.b   0,  0    ; 12
    dc.b   0,  1    ; 14
; ===========================================================================
+
    moveq   #-2,d3
    moveq   #-2,d4
    move.b  status(a0),d0
    andi.b  #p1_standing,d0
    beq.s   +
    move.b  objoff_3F(a0),d3
+
    move.b  status(a0),d0
    andi.b  #p2_standing,d0
    beq.s   +
    move.b  objoff_3B(a0),d4
+
    movea.l Obj11_child1(a0),a1
    lea sub9_mapframe+next_subspr(a1),a2
    lea sub2_mapframe(a1),a1
    moveq   #0,d1
    move.b  subtype(a0),d1
    subq.b  #1,d1
    moveq   #0,d5
 
-   moveq   #0,d0
    subq.w  #1,d3
    cmp.b   d3,d5
    bne.s   +
    move.w  d2,d0
+
    addq.w  #2,d3
    cmp.b   d3,d5
    bne.s   +
    move.w  d2,d0
+
    subq.w  #1,d3
    subq.w  #1,d4
    cmp.b   d4,d5
    bne.s   +
    move.w  d6,d0
+
    addq.w  #2,d4
    cmp.b   d4,d5
    bne.s   +
    move.w  d6,d0
+
    subq.w  #1,d4
    cmp.b   d3,d5
    bne.s   +
    swap    d2
    move.w  d2,d0
    swap    d2
+
    cmp.b   d4,d5
    bne.s   +
    swap    d6
    move.w  d6,d0
    swap    d6
+
    move.b  d0,(a1)
    addq.w  #1,d5
    addq.w  #6,a1
    cmpa.w  a2,a1
    bne.s   +
    movea.l Obj11_child2(a0),a1 ; a1=object
    lea sub2_mapframe(a1),a1
+   dbf d1,-
 
    rts
; End of function sub_F912
 
; ===========================================================================
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; subroutine to make the bridge push down where Sonic or Tails walks over
; loc_F9E8:
Obj11_Depress:
    move.b  objoff_3E(a0),d0
    jsrto   (CalcSine).l, JmpTo_CalcSine
    move.w  d0,d4
    lea (byte_FB28).l,a4
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #4,d0
    moveq   #0,d3
    move.b  objoff_3F(a0),d3
    move.w  d3,d2
    add.w   d0,d3
    moveq   #0,d5
    lea (Obj11_DepressionOffsets-$80).l,a5
    move.b  (a5,d3.w),d5
    andi.w  #$F,d3
    lsl.w   #4,d3
    lea (a4,d3.w),a3
    movea.l Obj11_child1(a0),a1
    lea sub9_y_pos+next_subspr(a1),a2
    lea sub2_y_pos(a1),a1
 
-   moveq   #0,d0
    move.b  (a3)+,d0
    addq.w  #1,d0
    mulu.w  d5,d0
    mulu.w  d4,d0
    swap    d0
    add.w   objoff_3C(a0),d0
    move.w  d0,(a1)
    addq.w  #6,a1
    cmpa.w  a2,a1
    bne.s   +
    movea.l Obj11_child2(a0),a1 ; a1=object
    lea sub2_y_pos(a1),a1
+   dbf d2,-
 
    moveq   #0,d0
    move.b  subtype(a0),d0
    moveq   #0,d3
    move.b  objoff_3F(a0),d3
    addq.b  #1,d3
    sub.b   d0,d3
    neg.b   d3
    bmi.s   ++  ; rts
    move.w  d3,d2
    lsl.w   #4,d3
    lea (a4,d3.w),a3
    adda.w  d2,a3
    subq.w  #1,d2
    bcs.s   ++  ; rts
 
-   moveq   #0,d0
    move.b  -(a3),d0
    addq.w  #1,d0
    mulu.w  d5,d0
    mulu.w  d4,d0
    swap    d0
    add.w   objoff_3C(a0),d0
    move.w  d0,(a1)
    addq.w  #6,a1
    cmpa.w  a2,a1
    bne.s   +
    movea.l Obj11_child2(a0),a1 ; a1=object
    lea sub2_y_pos(a1),a1
+   dbf d2,-
+
    rts
; ===========================================================================
; seems to be bridge piece vertical position offset data
Obj11_DepressionOffsets: ; byte_FA98:
    dc.b   2,  4,  6,  8,  8,  6,  4,  2,  0,  0,  0,  0,  0,  0,  0,  0; 16
    dc.b   2,  4,  6,  8, $A,  8,  6,  4,  2,  0,  0,  0,  0,  0,  0,  0; 32
    dc.b   2,  4,  6,  8, $A, $A,  8,  6,  4,  2,  0,  0,  0,  0,  0,  0; 48
    dc.b   2,  4,  6,  8, $A, $C, $A,  8,  6,  4,  2,  0,  0,  0,  0,  0; 64
    dc.b   2,  4,  6,  8, $A, $C, $C, $A,  8,  6,  4,  2,  0,  0,  0,  0; 80
    dc.b   2,  4,  6,  8, $A, $C, $E, $C, $A,  8,  6,  4,  2,  0,  0,  0; 96
    dc.b   2,  4,  6,  8, $A, $C, $E, $E, $C, $A,  8,  6,  4,  2,  0,  0; 112
    dc.b   2,  4,  6,  8, $A, $C, $E,$10, $E, $C, $A,  8,  6,  4,  2,  0; 128
    dc.b   2,  4,  6,  8, $A, $C, $E,$10,$10, $E, $C, $A,  8,  6,  4,  2; 144
 
; something else important for bridge depression to work (phase? bridge size adjustment?)
byte_FB28:
    dc.b $FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 16
    dc.b $B5,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 32
    dc.b $7E,$DB,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 48
    dc.b $61,$B5,$EC,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 64
    dc.b $4A,$93,$CD,$F3,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 80
    dc.b $3E,$7E,$B0,$DB,$F6,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0; 96
    dc.b $38,$6D,$9D,$C5,$E4,$F8,$FF,  0,  0,  0,  0,  0,  0,  0,  0,  0; 112
    dc.b $31,$61,$8E,$B5,$D4,$EC,$FB,$FF,  0,  0,  0,  0,  0,  0,  0,  0; 128
    dc.b $2B,$56,$7E,$A2,$C1,$DB,$EE,$FB,$FF,  0,  0,  0,  0,  0,  0,  0; 144
    dc.b $25,$4A,$73,$93,$B0,$CD,$E1,$F3,$FC,$FF,  0,  0,  0,  0,  0,  0; 160
    dc.b $1F,$44,$67,$88,$A7,$BD,$D4,$E7,$F4,$FD,$FF,  0,  0,  0,  0,  0; 176
    dc.b $1F,$3E,$5C,$7E,$98,$B0,$C9,$DB,$EA,$F6,$FD,$FF,  0,  0,  0,  0; 192
    dc.b $19,$38,$56,$73,$8E,$A7,$BD,$D1,$E1,$EE,$F8,$FE,$FF,  0,  0,  0; 208
    dc.b $19,$38,$50,$6D,$83,$9D,$B0,$C5,$D8,$E4,$F1,$F8,$FE,$FF,  0,  0; 224
    dc.b $19,$31,$4A,$67,$7E,$93,$A7,$BD,$CD,$DB,$E7,$F3,$F9,$FE,$FF,  0; 240
    dc.b $19,$31,$4A,$61,$78,$8E,$A2,$B5,$C5,$D4,$E1,$EC,$F4,$FB,$FE,$FF; 256
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj11_MapUnc_FC28:  BINCLUDE "mappings/sprite/obj11_a.bin"
 
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj11_MapUnc_FC70:  BINCLUDE "mappings/sprite/obj11_b.bin"
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
    if ~~removeJmpTos
; sub_FC88:
JmpTo_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo_PlatformObject11_cont 
    jmp (PlatformObject11_cont).l
; sub_FC94:
JmpTo_CalcSine 
    jmp (CalcSine).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 15 - Swinging platform from Aquatic Ruin Zone
; ----------------------------------------------------------------------------
; Sprite_FC9C:
Obj15:
    btst    #6,render_flags(a0)
    bne.w   +
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj15_Index(pc,d0.w),d1
    jmp Obj15_Index(pc,d1.w)
; ---------------------------------------------------------------------------
+
    move.w  #$200,d0
    bra.w   DisplaySprite3
; ===========================================================================
; off_FCBC: Obj15_States:
Obj15_Index:    offsetTable
        offsetTableEntry.w Obj15_Init       ;  0
        offsetTableEntry.w Obj15_State2     ;  2
        offsetTableEntry.w Obj15_Display    ;  4
        offsetTableEntry.w Obj15_State4     ;  6
        offsetTableEntry.w Obj15_State5     ;  8
        offsetTableEntry.w Obj15_State6     ; $A
        offsetTableEntry.w Obj15_State7     ; $C
; ===========================================================================
; loc_FCCA:
Obj15_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj15_MapUnc_101E8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZSwingPlat,2,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #$10,y_radius(a0)
    move.w  y_pos(a0),objoff_38(a0)
    move.w  x_pos(a0),objoff_3A(a0)
    cmpi.b  #mystic_cave_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj15_Obj7A_MapUnc_10256,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #8,y_radius(a0)
+
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj15_Obj83_MapUnc_1021E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #8,y_radius(a0)
+
    bsr.w   Adjust2PArtPointer
    moveq   #0,d1
    move.b  subtype(a0),d1
    bpl.s   +
    addq.b  #4,routine(a0)
+
    move.b  d1,d4
    andi.b  #$70,d4
    andi.w  #$F,d1
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    jsrto   (SingleObjLoad2).l, JmpTo2_SingleObjLoad2
    bne.w   +++
    _move.b id(a0),id(a1) ; load obj15
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    cmpi.b  #$20,d4
    bne.s   +
    move.b  #4,routine(a1)
    move.b  #4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #$50,y_radius(a1)
    bset    #4,render_flags(a1)
    move.b  #3,mapping_frame(a1)
    move.w  d2,x_pos(a1)
    addi.w  #$40,d3
    move.w  d3,y_pos(a1)
    addi.w  #$48,d3
    move.w  d3,y_pos(a0)
    bra.s   ++
; ===========================================================================
+
    bset    #6,render_flags(a1)
    move.b  #$48,mainspr_width(a1)
    move.b  d1,mainspr_childsprites(a1)
    subq.b  #1,d1
    lea sub2_x_pos(a1),a2
 
-   move.w  d2,(a2)+    ; sub?_x_pos
    move.w  d3,(a2)+    ; sub?_y_pos
    move.w  #1,(a2)+    ; sub2_mapframe
    addi.w  #$10,d3
    dbf d1,-
 
    move.b  #2,sub2_mapframe(a1)
    move.w  sub6_x_pos(a1),x_pos(a1)
    move.w  sub6_y_pos(a1),y_pos(a1)
    move.w  d2,sub6_x_pos(a1)
    move.w  d3,sub6_y_pos(a1)
    move.b  #1,mainspr_mapframe(a1)
    addi_.w #8,d3
    move.w  d3,y_pos(a0)
    move.b  #$50,mainspr_height(a1)
    bset    #4,render_flags(a1)
+
    move.l  a1,objoff_30(a0)
+
    move.w  #$8000,angle(a0)
    move.w  #0,objoff_3E(a0)
    move.b  subtype(a0),d1
    andi.w  #$70,d1
    move.b  d1,subtype(a0)
    cmpi.b  #$40,d1
    bne.s   Obj15_State2
    move.l  #Obj15_MapUnc_102DE,mappings(a0)
    move.b  #$A7,collision_flags(a0)
 
; loc_FE50:
Obj15_State2:
    move.w  x_pos(a0),-(sp)
    bsr.w   sub_FE70
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #0,d3
    move.b  y_radius(a0),d3
    addq.b  #1,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject2).l, JmpTo_PlatformObject2
    bra.w   loc_1000C
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_FE70:
 
    moveq   #0,d0
    moveq   #0,d1
    move.b  (Oscillating_Data+$18).w,d0
    move.b  subtype(a0),d1
    beq.s   loc_FEC2
    cmpi.b  #$10,d1
    bne.s   ++
    cmpi.b  #$3F,d0
    beq.s   +
    bhs.s   loc_FEC2
    moveq   #$40,d0
    bra.s   loc_FEC2
; ===========================================================================
/
    move.w  #SndID_PlatformKnock,d0
    jsr (PlaySoundLocal).l
    moveq   #$40,d0
    bra.s   loc_FEC2
; ===========================================================================
+
    cmpi.b  #$20,d1
    beq.w   +++ ; rts
    cmpi.b  #$30,d1
    bne.s   +
    cmpi.b  #$41,d0
    beq.s   -
    blo.s   loc_FEC2
    moveq   #$40,d0
    bra.s   loc_FEC2
; ===========================================================================
+
    cmpi.b  #$40,d1
    bne.s   loc_FEC2
    bsr.w   loc_FF6E
 
loc_FEC2:
    move.b  objoff_2E(a0),d1
    cmp.b   d0,d1
    beq.w   ++  ; rts
    move.b  d0,objoff_2E(a0)
    move.w  #$80,d1
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    add.w   d1,d0
+
    jsrto   (CalcSine).l, JmpTo2_CalcSine
    move.w  objoff_38(a0),d2
    move.w  objoff_3A(a0),d3
    moveq   #0,d6
    movea.l objoff_30(a0),a1
    move.b  mainspr_childsprites(a1),d6
    subq.w  #1,d6
    bcs.s   +   ; rts
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    moveq   #0,d4
    moveq   #0,d5
    lea sub2_x_pos(a1),a2
 
-   movem.l d4-d5,-(sp)
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,(a2)+    ; sub?_x_pos
    move.w  d4,(a2)+    ; sub?_y_pos
    movem.l (sp)+,d4-d5
    add.l   d0,d4
    add.l   d1,d5
    addq.w  #next_subspr-4,a2
    dbf d6,-
 
    movem.l d4-d5,-(sp)
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  sub6_x_pos(a1),d2
    move.w  sub6_y_pos(a1),d3
    move.w  d5,sub6_x_pos(a1)
    move.w  d4,sub6_y_pos(a1)
    move.w  d2,x_pos(a1)
    move.w  d3,y_pos(a1)
    movem.l (sp)+,d4-d5
    asr.l   #1,d0
    asr.l   #1,d1
    add.l   d0,d4
    add.l   d1,d5
    swap    d4
    swap    d5
    add.w   objoff_38(a0),d4
    add.w   objoff_3A(a0),d5
    move.w  d4,y_pos(a0)
    move.w  d5,x_pos(a0)
+
    rts
; End of function sub_FE70
 
; ===========================================================================
 
loc_FF6E:
    tst.w   objoff_36(a0)
    beq.s   +
    subq.w  #1,objoff_36(a0)
    bra.w   loc_10006
; ===========================================================================
+
    tst.b   objoff_34(a0)
    bne.s   +
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   objoff_3A(a0),d0
    addi.w  #$20,d0
    cmpi.w  #$40,d0
    bhs.s   loc_10006
    tst.w   (Debug_placement_mode).w
    bne.w   loc_10006
    move.b  #1,objoff_34(a0)
+
    tst.b   objoff_3D(a0)
    beq.s   +
    move.w  objoff_3E(a0),d0
    addi_.w #8,d0
    move.w  d0,objoff_3E(a0)
    add.w   d0,angle(a0)
    cmpi.w  #$200,d0
    bne.s   loc_10006
    move.w  #0,objoff_3E(a0)
    move.w  #$8000,angle(a0)
    move.b  #0,objoff_3D(a0)
    move.w  #$3C,objoff_36(a0)
    bra.s   loc_10006
; ===========================================================================
+
    move.w  objoff_3E(a0),d0
    subi_.w #8,d0
    move.w  d0,objoff_3E(a0)
    add.w   d0,angle(a0)
    cmpi.w  #$FE00,d0
    bne.s   loc_10006
    move.w  #0,objoff_3E(a0)
    move.w  #$4000,angle(a0)
    move.b  #1,objoff_3D(a0)
; loc_10000:
    move.w  #$3C,objoff_36(a0)
 
loc_10006:
    move.b  angle(a0),d0
    rts
; ===========================================================================
 
loc_1000C:
    tst.w   (Two_player_mode).w
    beq.s   +
    bra.w   DisplaySprite
; ===========================================================================
+
    move.w  objoff_3A(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   +
    bra.w   DisplaySprite
; ===========================================================================
+
    movea.l objoff_30(a0),a1
    bsr.w   DeleteObject2
    bra.w   DeleteObject
; ===========================================================================
 
Obj15_Display: ;;
    bra.w   DisplaySprite
; ===========================================================================
 
; loc_1003E:
Obj15_State4:
    move.w  x_pos(a0),-(sp)
    bsr.w   sub_FE70
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #0,d3
    move.b  y_radius(a0),d3
    addq.b  #1,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject2).l, JmpTo_PlatformObject2
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.w   BranchTo_loc_1000C
    tst.b   (Oscillating_Data+$18).w
    bne.w   BranchTo_loc_1000C
    jsrto   (SingleObjLoad2).l, JmpTo2_SingleObjLoad2
    bne.s   loc_100E4
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
-   move.l  (a0,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,-
    if object_size&3
    move.w  (a0,d0.w),(a1,d0.w)
    endif
 
    move.b  #$A,routine(a1)
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   +
    addq.b  #2,routine(a1)
+
    move.w  #$200,x_vel(a1)
    btst    #0,status(a0)
    beq.s   +
    neg.w   x_vel(a1)
+
    bset    #1,status(a1)
    move.w  a0,d0
    subi.w  #Object_RAM,d0
    if object_size=$40
    lsr.w   #6,d0
    else
    divu.w  #object_size,d0
    endif
    andi.w  #$7F,d0
    move.w  a1,d1
    subi.w  #Object_RAM,d1
    if object_size=$40
    lsr.w   #6,d1
    else
    divu.w  #object_size,d1
    endif
    andi.w  #$7F,d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.b   interact(a1),d0
    bne.s   +
    move.b  d1,interact(a1)
+
    lea (Sidekick).w,a1 ; a1=character
    cmp.b   interact(a1),d0
    bne.s   loc_100E4
    move.b  d1,interact(a1)
 
loc_100E4:
    move.b  #3,mapping_frame(a0)
    addq.b  #2,routine(a0)
    andi.b  #$E7,status(a0)
 
BranchTo_loc_1000C 
    bra.w   loc_1000C
; ===========================================================================
; loc_100F8:
Obj15_State5:
    bsr.w   sub_FE70
    bra.w   loc_1000C
 
; ===========================================================================
; loc_10100:
Obj15_State6:
    move.w  x_pos(a0),-(sp)
    btst    #1,status(a0)
    beq.s   +
    bsr.w   ObjectMove
    addi.w  #$18,y_vel(a0)
    cmpi.w  #$720,y_pos(a0)
    blo.s   ++
    move.w  #$720,y_pos(a0)
    bclr    #1,status(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    move.w  y_pos(a0),objoff_38(a0)
    bra.s   ++
; ===========================================================================
+
    moveq   #0,d0
    move.b  (Oscillating_Data+$14).w,d0
    lsr.w   #1,d0
    add.w   objoff_38(a0),d0
    move.w  d0,y_pos(a0)
+
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #0,d3
    move.b  y_radius(a0),d3
    addq.b  #1,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject2).l, JmpTo_PlatformObject2
    bra.w   MarkObjGone
 
; ===========================================================================
; loc_10166:
Obj15_State7:
    move.w  x_pos(a0),-(sp)
    bsr.w   ObjectMove
    btst    #1,status(a0)
    beq.s   +
    addi.w  #$18,y_vel(a0)
    move.w  (Water_Level_2).w,d0
    cmp.w   y_pos(a0),d0
    bhi.s   ++
    move.w  d0,y_pos(a0)
    move.w  d0,objoff_38(a0)
    bclr    #1,status(a0)
    move.w  #$100,x_vel(a0)
    move.w  #0,y_vel(a0)
    bra.s   ++
; ===========================================================================
+
    moveq   #0,d0
    move.b  (Oscillating_Data+$14).w,d0
    lsr.w   #1,d0
    add.w   objoff_38(a0),d0
    move.w  d0,y_pos(a0)
    tst.w   x_vel(a0)
    beq.s   +
    moveq   #0,d3
    move.b  width_pixels(a0),d3
    jsrto   (ObjCheckRightWallDist).l, JmpTo_ObjCheckRightWallDist
    tst.w   d1
    bpl.s   +
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)
+
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #0,d3
    move.b  y_radius(a0),d3
    addq.b  #1,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject2).l, JmpTo_PlatformObject2
    bra.w   MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj15_MapUnc_101E8: BINCLUDE "mappings/sprite/obj15_a.bin"
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj15_Obj83_MapUnc_1021E:   BINCLUDE "mappings/sprite/obj83.bin"
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj15_Obj7A_MapUnc_10256:   offsetTable
    offsetTableEntry.w word_1025E
    offsetTableEntry.w word_10270
    offsetTableEntry.w word_1027A
    offsetTableEntry.w word_1028C
word_1025E: dc.w 2
    dc.w $F809, $6060, $6030, $FFE8
    dc.w $F809, $6860, $6830, 0
word_10270: dc.w 1
        dc.w $F805, $6066, $6033, $FFF8
word_1027A: dc.w 2
        dc.w $E805, $406A, $4035, $FFF4
        dc.w $F80B, $406E, $4037, $FFF4
word_1028C: dc.w $A
        dc.w $A805, $406A, $4035, $FFF4
        dc.w $B80B, $406E, $4037, $FFF4
        dc.w $C805, $6066, $6033, $FFF8
        dc.w $D805, $6066, $6033, $FFF8
        dc.w $E805, $6066, $6033, $FFF8
        dc.w $F805, $6066, $6033, $FFF8
        dc.w $805, $6066, $6033, $FFF8
        dc.w $1805, $6066, $6033, $FFF8
        dc.w $2805, $6066, $6033, $FFF8
        dc.w $3805, $6066, $6033, $FFF8
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj15_MapUnc_102DE: offsetTable
    offsetTableEntry.w  word_102E4
    offsetTableEntry.w word_10270
    offsetTableEntry.w word_1027A
word_102E4: dc.w 2
    dc.w $F80D, $6058, $602C, $FFE0
    dc.w $F80D, $6858, $682C, 0
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_PlatformObject2 
    jmp (PlatformObject2).l
JmpTo2_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo2_CalcSine 
    jmp (CalcSine).l
JmpTo_ObjCheckRightWallDist 
    jmp (ObjCheckRightWallDist).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 17 - GHZ rotating log helix spikes (from Sonic 1, unused)
; the programming of this was modified somewhat between Sonic 1 and Sonic 2
; ----------------------------------------------------------------------------
; Sprite_10310:
Obj17:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj17_Index(pc,d0.w),d1
    jmp Obj17_Index(pc,d1.w)
; ===========================================================================
; off_1031E:
Obj17_Index:    offsetTable
        offsetTableEntry.w Obj17_Init       ; 0
        offsetTableEntry.w Obj17_Main       ; 2
        offsetTableEntry.w Obj17_Display    ; 4
; ===========================================================================
; loc_10324: Obj17_Main:
Obj17_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj17_MapUnc_10452,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_GHZ_Spiked_Log,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #8,width_pixels(a0)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    _move.b id(a0),d4
    lea subtype(a0),a2  ; move helix length to a2
    moveq   #0,d1
    move.b  (a2),d1 ; move a2 to d1
    move.b  #0,(a2)+
    move.w  d1,d0
    lsr.w   #1,d0
    lsl.w   #4,d0
    sub.w   d0,d3
    subq.b  #2,d1
    bcs.s   Obj17_Main
    moveq   #0,d6
; loc_10372:
Obj17_MakeHelix:
    bsr.w   SingleObjLoad2
    bne.s   Obj17_Main
    addq.b  #1,subtype(a0)
    move.w  a1,d5
    subi.w  #Object_RAM,d5
    if object_size=$40
    lsr.w   #6,d5
    else
    divu.w  #object_size,d5
    endif
    andi.w  #$7F,d5
    move.b  d5,(a2)+
    move.b  #4,routine(a1)
    _move.b d4,id(a1) ; load obj17
    move.w  d2,y_pos(a1)
    move.w  d3,x_pos(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_GHZ_Spiked_Log,2,0),art_tile(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #8,width_pixels(a1)
    move.b  d6,objoff_3E(a1)
    addq.b  #1,d6
    andi.b  #7,d6
    addi.w  #$10,d3
    cmp.w   x_pos(a0),d3
    bne.s   +
    move.b  d6,objoff_3E(a0)
    addq.b  #1,d6
    andi.b  #7,d6
    addi.w  #$10,d3
    addq.b  #1,subtype(a0)
+   dbf d1,Obj17_MakeHelix ; repeat d1 times (helix length)
 
; loc_103E8: Obj17_Action:
Obj17_Main:
    bsr.w   Obj17_RotateSpike
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   Obj17_DelAll
    bra.w   DisplaySprite
; ===========================================================================
; loc_10404:
Obj17_DelAll:
    moveq   #0,d2
    lea subtype(a0),a2  ; move helix length to a2
    move.b  (a2)+,d2    ; move a2 to d2
    subq.b  #2,d2
    bcs.s   BranchTo2_DeleteObject
; loc_10410:
Obj17_DelLoop:
    moveq   #0,d0
    move.b  (a2)+,d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a1 ; a1=object
    bsr.w   DeleteObject2   ; delete object
    dbf d2,Obj17_DelLoop    ; repeat d2 times (helix length)
; loc_10426:
BranchTo2_DeleteObject 
    bra.w   DeleteObject
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1042A:
Obj17_RotateSpike:
    move.b  (Logspike_anim_frame).w,d0
    move.b  #0,collision_flags(a0)  ; make object harmless
    add.b   objoff_3E(a0),d0
    andi.b  #7,d0
    move.b  d0,mapping_frame(a0)    ; change current frame
    bne.s   +   ; rts
    move.b  #%10000100,collision_flags(a0)  ; make object harmful
+
    rts
; End of function Obj17_RotateSpike
 
; ===========================================================================
; loc_1044A:
Obj17_Display:
    bsr.w   Obj17_RotateSpike
    bra.w   DisplaySprite
; ===========================================================================
; -----------------------------------------------------------------------------
; sprite mappings - helix of spikes on a pole (GHZ) (unused)
; -----------------------------------------------------------------------------
Obj17_MapUnc_10452: BINCLUDE "mappings/sprite/obj17.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ----------------------------------------------------------------------------
; Object 18 - Stationary floating platform from ARZ, EHZ and HTZ
; ----------------------------------------------------------------------------
; Sprite_104AC:
Obj18:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj18_Index(pc,d0.w),d1
    jmp Obj18_Index(pc,d1.w)
; ===========================================================================
; off_104BA:
Obj18_Index:    offsetTable
        offsetTableEntry.w Obj18_Init           ; 0
        offsetTableEntry.w loc_1056A            ; 2
        offsetTableEntry.w BranchTo3_DeleteObject   ; 4
        offsetTableEntry.w loc_105A8            ; 6
        offsetTableEntry.w loc_105D4            ; 8
; ===========================================================================
;word_104C4:
Obj18_InitData:
    ;    width_pixels
    ;    frame
    dc.b $20, 0
    dc.b $20, 1
    dc.b $20, 2
    dc.b $40, 3
    dc.b $30, 4
; ===========================================================================
; loc_104CE:
Obj18_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$E,d0
    lea Obj18_InitData(pc,d0.w),a2
    move.b  (a2)+,width_pixels(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.l  #Obj18_MapUnc_107F6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,0),art_tile(a0)
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj18_MapUnc_1084E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,0),art_tile(a0)
+
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),objoff_2C(a0)
    move.w  y_pos(a0),objoff_34(a0)
    move.w  x_pos(a0),objoff_32(a0)
    move.w  #$80,angle(a0)
    tst.b   subtype(a0)
    bpl.s   ++
    addq.b  #6,routine(a0)
    andi.b  #$F,subtype(a0)
    move.b  #$30,y_radius(a0)
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   +
    move.b  #$28,y_radius(a0)
+
    bset    #4,render_flags(a0)
    bra.w   loc_105D4
; ===========================================================================
+
    andi.b  #$F,subtype(a0)
 
loc_1056A:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    tst.b   objoff_38(a0)
    beq.s   ++
    subq.b  #4,objoff_38(a0)
    bra.s   ++
; ===========================================================================
+
    cmpi.b  #$40,objoff_38(a0)
    beq.s   +
    addq.b  #4,objoff_38(a0)
+
    move.w  x_pos(a0),-(sp)
    bsr.w   sub_10638
    bsr.w   sub_1061E
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #8,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject).l, JmpTo_PlatformObject
    bra.s   loc_105B0
; ===========================================================================
 
loc_105A8:
    bsr.w   sub_10638
    bsr.w   sub_1061E
 
loc_105B0:
    tst.w   (Two_player_mode).w
    beq.s   +
    bra.w   DisplaySprite
; ===========================================================================
+
    move.w  objoff_32(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   BranchTo3_DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
 
BranchTo3_DeleteObject 
    bra.w   DeleteObject
; ===========================================================================
 
loc_105D4:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    tst.b   objoff_38(a0)
    beq.s   ++
    subq.b  #4,objoff_38(a0)
    bra.s   ++
; ===========================================================================
+
    cmpi.b  #$40,objoff_38(a0)
    beq.s   +
    addq.b  #4,objoff_38(a0)
+
    move.w  x_pos(a0),-(sp)
    bsr.w   sub_10638
    bsr.w   sub_1061E
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo_SolidObject
    bra.s   loc_105B0
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_1061E:
    move.b  objoff_38(a0),d0
    jsrto   (CalcSine).l, JmpTo3_CalcSine
    move.w  #$400,d1
    muls.w  d1,d0
    swap    d0
    add.w   objoff_2C(a0),d0
    move.w  d0,y_pos(a0)
    rts
; End of function sub_1061E
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_10638:
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    add.w   d0,d0
    move.w  Obj18_Behaviours(pc,d0.w),d1
    jmp Obj18_Behaviours(pc,d1.w)
; End of function sub_10638
 
; ===========================================================================
; off_1064C:
Obj18_Behaviours: offsetTable
    offsetTableEntry.w return_10668 ;  0
    offsetTableEntry.w loc_1067A    ;  1
    offsetTableEntry.w loc_106C0    ;  2
    offsetTableEntry.w loc_106D8    ;  3
    offsetTableEntry.w loc_10702    ;  4
    offsetTableEntry.w loc_1066A    ;  5
    offsetTableEntry.w loc_106B0    ;  6
    offsetTableEntry.w loc_10778    ;  7
    offsetTableEntry.w loc_107A4    ;  8
    offsetTableEntry.w return_10668 ;  9
    offsetTableEntry.w loc_107BC    ; $A
    offsetTableEntry.w loc_107D6    ; $B
    offsetTableEntry.w loc_106A2    ; $C
    offsetTableEntry.w loc_10692    ; $D
; ===========================================================================
 
return_10668:
    rts
; ===========================================================================
 
loc_1066A:
    move.w  objoff_32(a0),d0
    move.b  angle(a0),d1
    neg.b   d1
    addi.b  #$40,d1
    bra.s   loc_10686
; ===========================================================================
 
loc_1067A:
    move.w  objoff_32(a0),d0
    move.b  angle(a0),d1
    subi.b  #$40,d1
 
loc_10686:
    ext.w   d1
    add.w   d1,d0
    move.w  d0,x_pos(a0)
    bra.w   loc_107EE
; ===========================================================================
 
loc_10692:
    move.w  objoff_34(a0),d0
    move.b  (Oscillating_Data+$C).w,d1
    neg.b   d1
    addi.b  #$30,d1
    bra.s   loc_106CC
; ===========================================================================
 
loc_106A2:
    move.w  objoff_34(a0),d0
    move.b  (Oscillating_Data+$C).w,d1
    subi.b  #$30,d1
    bra.s   loc_106CC
; ===========================================================================
 
loc_106B0:
    move.w  objoff_34(a0),d0
    move.b  angle(a0),d1
    neg.b   d1
    addi.b  #$40,d1
    bra.s   loc_106CC
; ===========================================================================
 
loc_106C0:
    move.w  objoff_34(a0),d0
    move.b  angle(a0),d1
    subi.b  #$40,d1
 
loc_106CC:
    ext.w   d1
    add.w   d1,d0
    move.w  d0,objoff_2C(a0)
    bra.w   loc_107EE
; ===========================================================================
 
loc_106D8:
    tst.w   objoff_3A(a0)
    bne.s   loc_106F0
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   +   ; rts
    move.w  #$1E,objoff_3A(a0)
/
    rts
; ===========================================================================
 
loc_106F0:
    subq.w  #1,objoff_3A(a0)
    bne.s   -   ; rts
    move.w  #$20,objoff_3A(a0)
    addq.b  #1,subtype(a0)
    rts
; ===========================================================================
 
loc_10702:
    tst.w   objoff_3A(a0)
    beq.s   loc_10730
    subq.w  #1,objoff_3A(a0)
    bne.s   loc_10730
    bclr    #p1_standing_bit,status(a0)
    beq.s   +
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   sub_1075E
+
    bclr    #p2_standing_bit,status(a0)
    beq.s   +
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   sub_1075E
+
    move.b  #6,routine(a0)
 
loc_10730:
    move.l  objoff_2C(a0),d3
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d3,objoff_2C(a0)
    addi.w  #$38,y_vel(a0)
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$120,d0
    cmp.w   objoff_2C(a0),d0
    bhs.s   +   ; rts
    move.b  #4,routine(a0)
+
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_1075E:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.w  y_vel(a0),y_vel(a1)
    rts
; End of function sub_1075E
 
; ===========================================================================
 
loc_10778:
    tst.w   objoff_3A(a0)
    bne.s   loc_10798
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #4,d0
    tst.b   (a2,d0.w)
    beq.s   +   ; rts
    move.w  #$3C,objoff_3A(a0)
/
    rts
; ===========================================================================
 
loc_10798:
    subq.w  #1,objoff_3A(a0)
    bne.s   -   ; rts
    addq.b  #1,subtype(a0)
    rts
; ===========================================================================
 
loc_107A4:
    subq.w  #2,objoff_2C(a0)
    move.w  objoff_34(a0),d0
    subi.w  #$200,d0
    cmp.w   objoff_2C(a0),d0
    bne.s   +   ; rts
    clr.b   subtype(a0)
+
    rts
; ===========================================================================
 
loc_107BC:
    move.w  objoff_34(a0),d0
    move.b  angle(a0),d1
    subi.b  #$40,d1
    ext.w   d1
    asr.w   #1,d1
    add.w   d1,d0
    move.w  d0,objoff_2C(a0)
    bra.w   loc_107EE
; ===========================================================================
 
loc_107D6:
    move.w  objoff_34(a0),d0
    move.b  angle(a0),d1
    neg.b   d1
    addi.b  #$40,d1
    ext.w   d1
    asr.w   #1,d1
    add.w   d1,d0
    move.w  d0,objoff_2C(a0)
 
loc_107EE:
    move.b  (Oscillating_Data+$18).w,angle(a0)
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj18_MapUnc_107F6: BINCLUDE "mappings/sprite/obj18_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj18_MapUnc_1084E: BINCLUDE "mappings/sprite/obj18_b.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo3_CalcSine 
    jmp (CalcSine).l
JmpTo_PlatformObject 
    jmp (PlatformObject).l
JmpTo_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1A - Collapsing platform from HPZ (and GHZ)
; also supports OOZ, but never made use of
;
; Unlike Object 1F, this supports sloped platforms and subtype-dependant
; mappings. Both are used by GHZ, the latter to allow different shading
; on right-facing ledges.
; ----------------------------------------------------------------------------
; Sprite_108BC:
Obj1A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1A_Index(pc,d0.w),d1
    jmp Obj1A_Index(pc,d1.w)
; ===========================================================================
; off_108CA:
Obj1A_Index:    offsetTable
        offsetTableEntry.w Obj1A_Init       ; 0
        offsetTableEntry.w Obj1A_Main       ; 2
        offsetTableEntry.w Obj1A_Fragment   ; 4
; ===========================================================================
 
collapsing_platform_delay_pointer = objoff_34
collapsing_platform_delay_counter = objoff_38
collapsing_platform_stood_on_flag = objoff_3A
collapsing_platform_slope_pointer = objoff_3C
 
; loc_108D0:
Obj1A_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj1A_MapUnc_10C6C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #7,collapsing_platform_delay_counter(a0)
    move.b  subtype(a0),mapping_frame(a0)
    move.l  #Obj1A_DelayData,collapsing_platform_delay_pointer(a0)
    cmpi.b  #hidden_palace_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj1A_MapUnc_1101C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HPZPlatform,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$30,width_pixels(a0)
    move.l  #Obj1A_HPZ_SlopeData,collapsing_platform_slope_pointer(a0)
    move.l  #Obj1A_HPZ_DelayData,collapsing_platform_delay_pointer(a0)
    bra.s   Obj1A_Main
; ===========================================================================
+
    cmpi.b  #oil_ocean_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj1F_MapUnc_110C6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZPlatform,3,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$40,width_pixels(a0)
    move.l  #Obj1A_OOZ_SlopeData,collapsing_platform_slope_pointer(a0)
    bra.s   Obj1A_Main
; ===========================================================================
+
    move.l  #Obj1A_GHZ_SlopeData,collapsing_platform_slope_pointer(a0)
    move.b  #$34,width_pixels(a0)
    move.b  #$38,y_radius(a0)
    bset    #4,render_flags(a0)
; loc_1097C:
Obj1A_Main:
    tst.b   collapsing_platform_stood_on_flag(a0)
    beq.s   +
    tst.b   collapsing_platform_delay_counter(a0)
    beq.w   Obj1A_CreateFragments   ; time up; collapse
    subq.b  #1,collapsing_platform_delay_counter(a0)
+
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   sub_1099E
    move.b  #1,collapsing_platform_stood_on_flag(a0)
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_1099E:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    movea.l collapsing_platform_slope_pointer(a0),a2 ; a2=object
    move.w  x_pos(a0),d4
    jsrto   (SlopedPlatform).l, JmpTo_SlopedPlatform
    bra.w   MarkObjGone
; End of function sub_1099E
 
; ===========================================================================
; loc_109B4:
Obj1A_Fragment:
    tst.b   collapsing_platform_delay_counter(a0)
    beq.s   Obj1A_FragmentFall  ; time up; collapse
    tst.b   collapsing_platform_stood_on_flag(a0)
    bne.s   +
    subq.b  #1,collapsing_platform_delay_counter(a0)
    bra.w   DisplaySprite
; ===========================================================================
+
    bsr.w   sub_1099E
    subq.b  #1,collapsing_platform_delay_counter(a0)
    bne.s   +
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   sub_109DC
    lea (Sidekick).w,a1 ; a1=character
 
sub_109DC:
    btst    #3,status(a1)
    beq.s   +
    bclr    #3,status(a1)
    bclr    #5,status(a1)
    move.b  #AniIDSonAni_Run,next_anim(a1)
+
    rts
; End of function sub_109DC
 
; ===========================================================================
; loc_109F8:
Obj1A_FragmentFall:
    bsr.w   ObjectMoveAndFall
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1F - Collapsing platform from ARZ, MCZ and OOZ (and MZ, SLZ and SBZ)
; ----------------------------------------------------------------------------
; Sprite_10A08:
Obj1F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1F_Index(pc,d0.w),d1
    jmp Obj1F_Index(pc,d1.w)
; ===========================================================================
; off_10A16:
Obj1F_Index:    offsetTable
        offsetTableEntry.w Obj1F_Init       ; 0
        offsetTableEntry.w Obj1F_Main       ; 2
        offsetTableEntry.w Obj1F_Fragment   ; 4
; ===========================================================================
; loc_10A1C:
Obj1F_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj1F_MapUnc_10F0C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MZ_Platform,2,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #7,collapsing_platform_delay_counter(a0)
    move.b  #$44,width_pixels(a0)
    lea (Obj1F_DelayData_EvenSubtype).l,a4
    btst    #0,subtype(a0)
    beq.s   +
    lea (Obj1F_DelayData_OddSubtype).l,a4
+
    move.l  a4,collapsing_platform_delay_pointer(a0)
    cmpi.b  #oil_ocean_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj1F_MapUnc_110C6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZPlatform,3,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$40,width_pixels(a0)
    move.l  #Obj1F_OOZ_DelayData,collapsing_platform_delay_pointer(a0)
+
    cmpi.b  #mystic_cave_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj1F_MapUnc_11106,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MCZCollapsePlat,3,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$20,width_pixels(a0)
    move.l  #Obj1F_MCZ_DelayData,collapsing_platform_delay_pointer(a0)
+
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   Obj1F_Main
    move.l  #Obj1F_MapUnc_1115E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$20,width_pixels(a0)
    move.l  #Obj1F_ARZ_DelayData,collapsing_platform_delay_pointer(a0)
; loc_10AD6:
Obj1F_Main:
    tst.b   collapsing_platform_stood_on_flag(a0)
    beq.s   +
    tst.b   collapsing_platform_delay_counter(a0)
    beq.w   Obj1F_CreateFragments   ; time up; collapse
    subq.b  #1,collapsing_platform_delay_counter(a0)
+
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   sub_10AF8
    move.b  #1,collapsing_platform_stood_on_flag(a0)
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_10AF8:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    jsrto   (PlatformObject).l, JmpTo2_PlatformObject
    bra.w   MarkObjGone
; End of function sub_10AF8
 
; ===========================================================================
; loc_10B0E:
Obj1F_Fragment:
    tst.b   collapsing_platform_delay_counter(a0)
    beq.s   Obj1F_FragmentFall  ; time up; collapse
    tst.b   collapsing_platform_stood_on_flag(a0)
    bne.s   +
    subq.b  #1,collapsing_platform_delay_counter(a0)
    bra.w   DisplaySprite
; ===========================================================================
+
    bsr.w   sub_10AF8
    subq.b  #1,collapsing_platform_delay_counter(a0)
    bne.s   +   ; rts
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   sub_10B36
    lea (Sidekick).w,a1 ; a1=character
 
sub_10B36:
    btst    #3,status(a1)
    beq.s   +   ; rts
    bclr    #3,status(a1)
    bclr    #5,status(a1)
    move.b  #AniIDSonAni_Run,next_anim(a1)
+
    rts
; End of function sub_10B36
 
; ===========================================================================
; loc_10B52:
Obj1F_FragmentFall:
    bsr.w   ObjectMoveAndFall
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
; loc_10B62:
Obj1F_CreateFragments:
    addq.b  #1,mapping_frame(a0)
    bra.s   +
; ===========================================================================
; loc_10B68:
Obj1A_CreateFragments:
    addq.b  #2,mapping_frame(a0)
+
    movea.l collapsing_platform_delay_pointer(a0),a4
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    add.w   d0,d0
    movea.l mappings(a0),a3
    adda.w  (a3,d0.w),a3
    move.w  (a3)+,d1
    subq.w  #1,d1
    bset    #5,render_flags(a0)
    _move.b id(a0),d4
    move.b  render_flags(a0),d5
    movea.l a0,a1
    bra.s   +
; ===========================================================================
-   bsr.w   SingleObjLoad
    bne.s   +++
    addq.w  #8,a3
+
    move.b  #4,routine(a1)
    _move.b d4,id(a1) ; load obj1F
    move.l  a3,mappings(a1)
    move.b  d5,render_flags(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  priority(a0),priority(a1)
    move.b  width_pixels(a0),width_pixels(a1)
    move.b  y_radius(a0),y_radius(a1)
    move.b  (a4)+,collapsing_platform_delay_counter(a1)
    cmpa.l  a0,a1
    bhs.s   +
    bsr.w   DisplaySprite2
+   dbf d1,-
+
    bsr.w   DisplaySprite
    move.w  #SndID_Smash,d0
    jmp (PlaySound).l
; ===========================================================================
; Delay data for obj1A in all but HPZ:
;byte_10BF2:
Obj1A_DelayData:
    dc.b $1C,$18,$14,$10,$1A,$16,$12, $E, $A,  6,$18,$14,$10, $C,  8,  4
    dc.b $16,$12, $E, $A,  6,  2,$14,$10, $C; 16
    rev02even
; Delay data for obj1A in HPZ:
;byte_10C0B:
Obj1A_HPZ_DelayData:
    dc.b $18,$1C,$20,$1E,$1A,$16,  6, $E,$14,$12, $A,  2
    rev02even
; Delay data for obj1F even subtypes in all levels without more specific data:
;byte_10C17:
Obj1F_DelayData_EvenSubtype:
    dc.b $1E,$16, $E,  6,$1A,$12, $A,  2
    rev02even
; Delay data for obj1F odd subtypes in all levels without more specific data:
;byte_10C1F:
Obj1F_DelayData_OddSubtype:
    dc.b $16,$1E,$1A,$12,  6, $E, $A,  2
    rev02even
; Delay data for obj1F in OOZ:
;byte_10C27:
Obj1F_OOZ_DelayData:
    dc.b $1A,$12, $A,  2,$16, $E,  6
    rev02even
; Delay data for obj1F in MCZ:
;byte_10C2E:
Obj1F_MCZ_DelayData:
    dc.b $1A,$16,$12, $E, $A,  2
    rev02even
; Delay data for obj1F in ARZ:
;byte_10C34:
Obj1F_ARZ_DelayData:
    dc.b $16,$1A,$18,$12,  6, $E, $A,  2
    rev02even
; S1 remnant: Height data for GHZ collapsing platform (unused):
;byte_10C3C:
Obj1A_GHZ_SlopeData:
    dc.b $20,$20,$20,$20,$20,$20,$20,$20,$21,$21,$22,$22,$23,$23,$24,$24
    dc.b $25,$25,$26,$26,$27,$27,$28,$28,$29,$29,$2A,$2A,$2B,$2B,$2C,$2C; 16
    dc.b $2D,$2D,$2E,$2E,$2F,$2F,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30; 32
    even
; -------------------------------------------------------------------------------
; unused sprite mappings (GHZ)
; -------------------------------------------------------------------------------
Obj1A_MapUnc_10C6C: BINCLUDE "mappings/sprite/obj1A_a.bin"
; ----------------------------------------------------------------------------
; unused sprite mappings (MZ, SLZ, SBZ)
; ----------------------------------------------------------------------------
Obj1F_MapUnc_10F0C: BINCLUDE "mappings/sprite/obj1F_a.bin"
 
; Slope data for platforms.
;byte_10FDC:
Obj1A_OOZ_SlopeData:
    dc.b $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10
;byte_10FEC:
Obj1A_HPZ_SlopeData
    dc.b $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10
    dc.b $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10
    dc.b $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10
; ----------------------------------------------------------------------------
; sprite mappings (HPZ)
; ----------------------------------------------------------------------------
Obj1A_MapUnc_1101C: BINCLUDE "mappings/sprite/obj1A_b.bin"
; ----------------------------------------------------------------------------
; sprite mappings (OOZ)
; ----------------------------------------------------------------------------
Obj1F_MapUnc_110C6: BINCLUDE "mappings/sprite/obj1F_b.bin"
; -------------------------------------------------------------------------------
; sprite mappings (MCZ)
; -------------------------------------------------------------------------------
Obj1F_MapUnc_11106: BINCLUDE "mappings/sprite/obj1F_c.bin"
; -------------------------------------------------------------------------------
; sprite mappings (ARZ)
; -------------------------------------------------------------------------------
Obj1F_MapUnc_1115E: BINCLUDE "mappings/sprite/obj1F_d.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_SlopedPlatform 
    jmp (SlopedPlatform).l
JmpTo2_PlatformObject 
    jmp (PlatformObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1C - Bridge stake in Emerald Hill Zone and Hill Top Zone, falling oil in Oil Ocean Zone
; ----------------------------------------------------------------------------
; Sprite_111D4:
Obj1C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1C_Index(pc,d0.w),d1
    jmp Obj1C_Index(pc,d1.w)
; ===========================================================================
; off_111E2:
Obj1C_Index:    offsetTable
        offsetTableEntry.w Obj1C_Init       ; 0
        offsetTableEntry.w BranchTo_MarkObjGone ; 2
; ===========================================================================
 
objsubdecl macro frame, mapaddr,artaddr,width,priority
    dc.l frame<<24|mapaddr
    dc.w artaddr
    dc.b width, priority
    endm
 
; dword_111E6:
Obj1C_InitData:
    objsubdecl 0, Obj1C_MapUnc_11552, make_art_tile(ArtTile_ArtNem_BoltEnd_Rope,2,0), 4, 6
    objsubdecl 1, Obj1C_MapUnc_11552, make_art_tile(ArtTile_ArtNem_BoltEnd_Rope,2,0), 4, 6
    objsubdecl 1, Obj11_MapUnc_FC70,  make_art_tile(ArtTile_ArtNem_EHZ_Bridge,2,0), 4, 1
    objsubdecl 2, Obj1C_MapUnc_11552, make_art_tile(ArtTile_ArtNem_BoltEnd_Rope,1,0), $10, 6
    objsubdecl 3, Obj16_MapUnc_21F14, make_art_tile(ArtTile_ArtNem_HtzZipline,2,0), 8, 4
    objsubdecl 4, Obj16_MapUnc_21F14, make_art_tile(ArtTile_ArtNem_HtzZipline,2,0), 8, 4
    objsubdecl 1, Obj16_MapUnc_21F14, make_art_tile(ArtTile_ArtNem_HtzZipline,2,0), $20, 1
    objsubdecl 0, Obj1C_MapUnc_113D6, make_art_tile(ArtTile_ArtKos_LevelArt,2,0), 8, 1
    objsubdecl 1, Obj1C_MapUnc_113D6, make_art_tile(ArtTile_ArtKos_LevelArt,2,0), 8, 1
    objsubdecl 0, Obj1C_MapUnc_113EE, make_art_tile(ArtTile_ArtUnc_Waterfall3,2,0), 4, 4
    objsubdecl 0, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 1, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 2, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 3, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 4, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 5, Obj1C_MapUnc_11406, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 4, 4
    objsubdecl 0, Obj1C_MapUnc_114AE, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), $18, 4
    objsubdecl 1, Obj1C_MapUnc_114AE, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), $18, 4
    objsubdecl 2, Obj1C_MapUnc_114AE, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 8, 4
    objsubdecl 3, Obj1C_MapUnc_114AE, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 8, 4
    objsubdecl 4, Obj1C_MapUnc_114AE, make_art_tile(ArtTile_ArtNem_Oilfall2,2,0), 8, 4
; byte_1128E:
Obj1C_Radii:
    dc.b   0
    dc.b   0    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   0    ; 4
    dc.b   0    ; 5
    dc.b   0    ; 6
    dc.b   0    ; 7
    dc.b   0    ; 8
    dc.b   0    ; 9
    dc.b   0    ; 10
    dc.b   0    ; 11
    dc.b   0    ; 12
    dc.b $30    ; 13
    dc.b $40    ; 14
    dc.b $60    ; 15
    dc.b   0    ; 16
    dc.b   0    ; 17
    dc.b $30    ; 18
    dc.b $40    ; 19
    dc.b $50    ; 20
    dc.b   0    ; 21
; ===========================================================================
; loc_112A4:
Obj1C_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.w  d0,d1
    lsl.w   #3,d0
    lea Obj1C_InitData(pc),a1
    lea (a1,d0.w),a1
    move.b  (a1),mapping_frame(a0)
    move.l  (a1)+,mappings(a0)
    move.w  (a1)+,art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  (a1)+,width_pixels(a0)
    move.b  (a1)+,priority(a0)
    lea Obj1C_Radii(pc),a1
    move.b  (a1,d1.w),d1
    beq.s   BranchTo_MarkObjGone    ; if the radius is zero, branch
    move.b  d1,y_radius(a0)
    bset    #4,render_flags(a0)
 
BranchTo_MarkObjGone 
    bra.w   MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 71 - Bridge stake and pulsing orb from Hidden Palace Zone
; ----------------------------------------------------------------------------
; Sprite_112F0:
Obj71:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj71_Index(pc,d0.w),d1
    jmp Obj71_Index(pc,d1.w)
; ===========================================================================
; off_112FE:
Obj71_Index:    offsetTable
        offsetTableEntry.w Obj71_Init   ; 0
        offsetTableEntry.w Obj71_Main   ; 2
; ---------------------------------------------------------------------------
; dword_11302:
Obj71_InitData:
    objsubdecl 3, Obj11_MapUnc_FC28,  make_art_tile(ArtTile_ArtNem_HPZ_Bridge,3,0), 4, 1        ; Hidden Palace bridge
    objsubdecl 0, Obj71_MapUnc_11396, make_art_tile(ArtTile_ArtNem_HPZOrb,3,1), $10, 1      ; Hidden Palace pulsing orb
    objsubdecl 0, Obj71_MapUnc_11576, make_art_tile(ArtTile_ArtNem_MtzLavaBubble,2,0), $10, 1   ; MTZ lava bubble
; ===========================================================================
; loc_1131A:
Obj71_Init:
    addq.b  #2,routine(a0)
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lsl.w   #3,d0
    lea Obj71_InitData(pc),a1
    lea (a1,d0.w),a1
    move.b  (a1),mapping_frame(a0)
    move.l  (a1)+,mappings(a0)
    move.w  (a1)+,art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  (a1)+,width_pixels(a0)
    move.b  (a1)+,priority(a0)
    move.b  subtype(a0),d0
    andi.w  #$F0,d0
    lsr.b   #4,d0
    move.b  d0,anim(a0)
; loc_1135C:
Obj71_Main:
    lea (Ani_obj71).l,a1
    bsr.w   AnimateSprite
    bra.w   MarkObjGone
; ===========================================================================
; off_1136A:
Ani_obj71:  offsetTable
        offsetTableEntry.w byte_11372   ; 0
        offsetTableEntry.w byte_1137A   ; 1
        offsetTableEntry.w byte_11389   ; 2
        offsetTableEntry.w byte_11392   ; 3
byte_11372: dc.b   8,  3,  3,  4,  5,  5,  4,$FF
    rev02even
byte_1137A: dc.b   5,  0,  0,  0,  1,  2,  3,  3,  2,  1,  2,  3,  3,  1,$FF
    rev02even
byte_11389: dc.b  $B,  0,  1,  2,  3,  4,  5,$FD,  3
    rev02even
byte_11392: dc.b $7F,  6,$FD,  2
    even
 
; --------------------------------------------------------------------------------
; sprite mappings
; --------------------------------------------------------------------------------
Obj71_MapUnc_11396: BINCLUDE "mappings/sprite/obj71_a.bin"
; ----------------------------------------------------------------------------------------
; Unknown sprite mappings
; ----------------------------------------------------------------------------------------
Obj1C_MapUnc_113D6: BINCLUDE "mappings/sprite/obj1C_a.bin"
; --------------------------------------------------------------------------------
; Unknown sprite mappings
; --------------------------------------------------------------------------------
Obj1C_MapUnc_113EE: BINCLUDE "mappings/sprite/obj1C_b.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj1C_MapUnc_11406: BINCLUDE "mappings/sprite/obj1C_c.bin"
; --------------------------------------------------------------------------------
; sprite mappings
; --------------------------------------------------------------------------------
Obj1C_MapUnc_114AE: BINCLUDE "mappings/sprite/obj1C_d.bin"
; --------------------------------------------------------------------------------
; sprite mappings
; --------------------------------------------------------------------------------
Obj1C_MapUnc_11552: BINCLUDE "mappings/sprite/obj1C_e.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj71_MapUnc_11576: BINCLUDE "mappings/sprite/obj71_b.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ----------------------------------------------------------------------------
; Object 2A - Stomper from MCZ
; ----------------------------------------------------------------------------
; Sprite_115C4:
Obj2A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2A_Index(pc,d0.w),d1
    jmp Obj2A_Index(pc,d1.w)
; ===========================================================================
; off_115D2:
Obj2A_Index:    offsetTable
        offsetTableEntry.w Obj2A_Init   ; 0
        offsetTableEntry.w Obj2A_Main   ; 2
; ===========================================================================
; loc_115D6:
Obj2A_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj2A_MapUnc_11666,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  #$50,y_radius(a0)
    bset    #4,render_flags(a0)
; loc_11610:
Obj2A_Main:
    tst.b   routine_secondary(a0)
    bne.s   +
    addq.w  #1,objoff_30(a0)
    cmpi.w  #$60,objoff_30(a0)
    bne.s   ++
    move.b  #2,routine_secondary(a0)
    bra.s   ++
; ===========================================================================
+
    subq.w  #8,objoff_30(a0)
    bhi.s   +
    move.w  #0,objoff_30(a0)
    move.b  #0,routine_secondary(a0)
+
    move.w  objoff_32(a0),d0
    sub.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$40,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo2_SolidObject
    bra.w   MarkObjGone
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj2A_MapUnc_11666: BINCLUDE "mappings/sprite/obj2A.bin"
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 2D - One way barrier from CPZ and DEZ
; ----------------------------------------------------------------------------
; Sprite_1169A:
Obj2D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2D_Index(pc,d0.w),d1
    jmp Obj2D_Index(pc,d1.w)
; ===========================================================================
; off_116A8:
Obj2D_Index:    offsetTable
        offsetTableEntry.w Obj2D_Init   ; 0
        offsetTableEntry.w Obj2D_Main   ; 2
; ===========================================================================
; loc_116AC:
Obj2D_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj2D_MapUnc_11822,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HtzValveBarrier,1,0),art_tile(a0)
    move.b  #8,width_pixels(a0)
    cmpi.b  #metropolis_zone,(Current_Zone).w
    beq.s   +
    cmpi.b  #metropolis_zone_2,(Current_Zone).w
    bne.s   ++
+
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    move.b  #$C,width_pixels(a0)
+
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    bne.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_ConstructionStripes_2,1,0),art_tile(a0)
    move.b  #8,width_pixels(a0)
+
    cmpi.b  #death_egg_zone,(Current_Zone).w
    bne.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_ConstructionStripes_1,1,0),art_tile(a0)
    move.b  #8,width_pixels(a0)
+
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_ARZBarrierThing,1,0),art_tile(a0)
    move.b  #8,width_pixels(a0)
+
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  subtype(a0),mapping_frame(a0)
    move.w  x_pos(a0),d2
    move.w  d2,d3
    subi.w  #$200,d2
    addi.w  #$18,d3
    btst    #0,status(a0)
    beq.s   +
    subi.w  #-$1E8,d2
    addi.w  #$1E8,d3
+
    move.w  d2,objoff_38(a0)
    move.w  d3,objoff_3A(a0)
; loc_1175E:
Obj2D_Main:
    btst    #0,status(a0)
    bne.s   +
    move.w  objoff_38(a0),d2
    move.w  x_pos(a0),d3
    tst.b   routine_secondary(a0)                ; check if barrier is moving up
    beq.s   ++
    move.w  objoff_3A(a0),d3
    bra.s   ++
; ===========================================================================
+
    move.w  x_pos(a0),d2
    move.w  objoff_3A(a0),d3
    tst.b   routine_secondary(a0)                ; check if barrier is moving up
    beq.s   +
    move.w  objoff_38(a0),d2
+
    move.w  objoff_32(a0),d4
    move.w  d4,d5
    subi.w  #$20,d4
    addi.w  #$20,d5
    move.b  #0,routine_secondary(a0)             ; set barrier to move down, check if characters are in area
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj2D_CheckCharacter
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   Obj2D_CheckCharacter
    tst.b   routine_secondary(a0)                ; check if barrier is moving up
    beq.s   +
    cmpi.w  #$40,objoff_30(a0)                   ; check if barrier is high enough
    beq.s   +++
    addq.w  #8,objoff_30(a0)                     ; move barrier up
    bra.s   ++
; ===========================================================================
+
    tst.w   objoff_30(a0)                        ; check if barrier is not in original position
    beq.s   ++
    subq.w  #8,objoff_30(a0)                     ; move barrier down
+
    move.w  objoff_32(a0),d0                     ; set the barrier y position
    sub.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
+
    moveq   #0,d1                                ; perform solid object collision
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$20,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo2_SolidObject
    bra.w   MarkObjGone                          ; delete object if off screen
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_117F4
Obj2D_CheckCharacter:
    ; rect ltrb (d2, d4, d3, d5)
 
    move.w  x_pos(a1),d0
    cmp.w   d2,d0
    blt.w   return_11820
    cmp.w   d3,d0
    bhs.w   return_11820
    move.w  y_pos(a1),d0
    cmp.w   d4,d0
    blo.w   return_11820
    cmp.w   d5,d0
    bhs.w   return_11820
    tst.b   obj_control(a1)
    bmi.s   return_11820
    move.b  #2,routine_secondary(a0)             ; set barrier to move up
 
return_11820:
    rts
; End of function Obj2D_CheckCharacter
 
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj2D_MapUnc_11822: BINCLUDE "mappings/sprite/obj2D.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 28 - Animal and the 100 points from a badnik
; ----------------------------------------------------------------------------
animal_ground_routine_base = objoff_30
animal_ground_x_vel = objoff_32
animal_ground_y_vel = objoff_34
; Sprite_1188C:
Obj28:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj28_Index(pc,d0.w),d1
    jmp Obj28_Index(pc,d1.w)
; ===========================================================================
; off_1189A:
Obj28_Index:    offsetTable
        offsetTableEntry.w Obj28_Init   ;   0
        offsetTableEntry.w Obj28_Main   ;   2
        offsetTableEntry.w Obj28_Walk   ;   4
        offsetTableEntry.w Obj28_Fly    ;   6
        offsetTableEntry.w Obj28_Walk   ;   8
        offsetTableEntry.w Obj28_Walk   ;  $A
        offsetTableEntry.w Obj28_Walk   ;  $C
        offsetTableEntry.w Obj28_Fly    ;  $E
        offsetTableEntry.w Obj28_Walk   ; $10
        offsetTableEntry.w Obj28_Fly    ; $12
        offsetTableEntry.w Obj28_Walk   ; $14
        offsetTableEntry.w Obj28_Walk   ; $16
        offsetTableEntry.w Obj28_Walk   ; $18
        offsetTableEntry.w Obj28_Walk   ; $1A
        offsetTableEntry.w Obj28_Prison ; $1C
        ; These are the S1 ending actions:
        offsetTableEntry.w Obj28_FlickyWait ; $1E
        offsetTableEntry.w Obj28_FlickyWait ; $20
        offsetTableEntry.w Obj28_FlickyJump ; $22
        offsetTableEntry.w Obj28_RabbitWait ; $24
        offsetTableEntry.w Obj28_LandJump   ; $26
        offsetTableEntry.w Obj28_SingleBounce   ; $28
        offsetTableEntry.w Obj28_LandJump   ; $2A
        offsetTableEntry.w Obj28_SingleBounce   ; $2C
        offsetTableEntry.w Obj28_LandJump   ; $2E
        offsetTableEntry.w Obj28_FlyBounce  ; $30
        offsetTableEntry.w Obj28_DoubleBounce   ; $32
 
; byte_118CE:
Obj28_ZoneAnimals:  zoneOrderedTable 1,2
 
zoneAnimals macro first,second
    zoneTableEntry.b (Obj28_Properties_first - Obj28_Properties) / 8
    zoneTableEntry.b (Obj28_Properties_second - Obj28_Properties) / 8
    endm
    ; This table declares what animals will appear in the zone.
    ; When an enemy is destroyed, a random animal is chosen from the 2 selected animals.
    ; Note: you must also load the corresponding art in the PLCs.
    zoneAnimals.b Squirrel, Bird    ; EHZ
    zoneAnimals.b Squirrel, Bird    ; Zone 1
    zoneAnimals.b Squirrel, Bird    ; WZ
    zoneAnimals.b Squirrel, Bird    ; Zone 3
    zoneAnimals.b Beaver,   Eagle   ; MTZ
    zoneAnimals.b Beaver,   Eagle   ; MTZ
    zoneAnimals.b Beaver,   Eagle   ; WFZ
    zoneAnimals.b Beaver,   Eagle   ; HTZ
    zoneAnimals.b Mouse,    Seal    ; HPZ
    zoneAnimals.b Mouse,    Seal    ; Zone 9
    zoneAnimals.b Penguin,  Seal    ; OOZ
    zoneAnimals.b Mouse,    Chicken ; MCZ
    zoneAnimals.b Bear, Bird    ; CNZ
    zoneAnimals.b Rabbit,   Eagle   ; CPZ
    zoneAnimals.b Pig,  Chicken ; DEZ
    zoneAnimals.b Penguin,  Bird    ; ARZ
    zoneAnimals.b Turtle,   Chicken ; SCZ
    zoneTableEnd
 
; word_118F0:
Obj28_Properties:
 
obj28decl macro xvel,yvel,mappings,{INTLABEL}
Obj28_Properties___LABEL__: label *
    dc.w xvel
    dc.w yvel
    dc.l mappings
    endm
        ; This table declares the speed and mappings of each animal.
Rabbit:     obj28decl -$200,-$400,Obj28_MapUnc_11EAC
Chicken:    obj28decl -$200,-$300,Obj28_MapUnc_11E1C
Penguin:    obj28decl -$180,-$300,Obj28_MapUnc_11EAC
Seal:       obj28decl -$140,-$180,Obj28_MapUnc_11E88
Pig:        obj28decl -$1C0,-$300,Obj28_MapUnc_11E64
Bird:       obj28decl -$300,-$400,Obj28_MapUnc_11E1C
Squirrel:   obj28decl -$280,-$380,Obj28_MapUnc_11E40
Eagle:      obj28decl -$280,-$300,Obj28_MapUnc_11E1C
Mouse:      obj28decl -$200,-$380,Obj28_MapUnc_11E40
Beaver:     obj28decl -$2C0,-$300,Obj28_MapUnc_11E40
Turtle:     obj28decl -$140,-$200,Obj28_MapUnc_11E40
Bear:       obj28decl -$200,-$300,Obj28_MapUnc_11E40
 
    ; The following tables tell the properties of animals based on their subtype.
 
; word_11950:
Obj28_Speeds:
    dc.w -$440, -$400
    dc.w -$440, -$400   ; 2
    dc.w -$440, -$400   ; 4
    dc.w -$300, -$400   ; 6
    dc.w -$300, -$400   ; 8
    dc.w -$180, -$300   ; 10
    dc.w -$180, -$300   ; 12
    dc.w -$140, -$180   ; 14
    dc.w -$1C0, -$300   ; 16
    dc.w -$200, -$300   ; 18
    dc.w -$280, -$380   ; 20
; off_1197C:
Obj28_Mappings:
    dc.l Obj28_MapUnc_11E1C
    dc.l Obj28_MapUnc_11E1C ; 1
    dc.l Obj28_MapUnc_11E1C ; 2
    dc.l Obj28_MapUnc_11EAC ; 3
    dc.l Obj28_MapUnc_11EAC ; 4
    dc.l Obj28_MapUnc_11EAC ; 5
    dc.l Obj28_MapUnc_11EAC ; 6
    dc.l Obj28_MapUnc_11E88 ; 7
    dc.l Obj28_MapUnc_11E64 ; 8
    dc.l Obj28_MapUnc_11E1C ; 9
    dc.l Obj28_MapUnc_11E40 ; 10
; word_119A8:
Obj28_ArtLocations:
    dc.w  ArtTile_ArtNem_S1EndFlicky    ;  0    Flicky
    dc.w  ArtTile_ArtNem_S1EndFlicky    ;  1    Flicky
    dc.w  ArtTile_ArtNem_S1EndFlicky    ;  2    Flicky
    dc.w  ArtTile_ArtNem_S1EndRabbit    ;  3    Rabbit
    dc.w  ArtTile_ArtNem_S1EndRabbit    ;  4    Rabbit
    dc.w  ArtTile_ArtNem_S1EndPenguin   ;  5    Penguin
    dc.w  ArtTile_ArtNem_S1EndPenguin   ;  6    Penguin
    dc.w  ArtTile_ArtNem_S1EndSeal      ;  7    Seal
    dc.w  ArtTile_ArtNem_S1EndPig       ;  8    Pig
    dc.w  ArtTile_ArtNem_S1EndChicken   ;  9    Chicken
    dc.w  ArtTile_ArtNem_S1EndSquirrel  ; 10    Squirrel
 
; ===========================================================================
; loc_119BE:
Obj28_Init:
    tst.b   subtype(a0)
    beq.w   Obj28_InitRandom
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.b  d0,routine(a0)
    subi.w  #$14,d0
    move.w  Obj28_ArtLocations(pc,d0.w),art_tile(a0)
    add.w   d0,d0
    move.l  Obj28_Mappings(pc,d0.w),mappings(a0)
    lea Obj28_Speeds(pc),a1
    move.w  (a1,d0.w),animal_ground_x_vel(a0)
    move.w  (a1,d0.w),x_vel(a0)
    move.w  2(a1,d0.w),animal_ground_y_vel(a0)
    move.w  2(a1,d0.w),y_vel(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$C,y_radius(a0)
    move.b  #4,render_flags(a0)
    bset    #0,render_flags(a0)
    move.b  #6,priority(a0)
    move.b  #8,width_pixels(a0)
    move.b  #7,anim_frame_duration(a0)
    bra.w   DisplaySprite
; ===========================================================================
; loc_11A2C:
Obj28_InitRandom:
    addq.b  #2,routine(a0)
    jsrto   (RandomNumber).l, JmpTo_RandomNumber
    move.w  #make_art_tile(ArtTile_ArtNem_Animal_1,0,0),art_tile(a0)
    andi.w  #1,d0
    beq.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_Animal_2,0,0),art_tile(a0)
+
    moveq   #0,d1
    move.b  (Current_Zone).w,d1
    add.w   d1,d1
    add.w   d0,d1
    lea Obj28_ZoneAnimals(pc),a1
    move.b  (a1,d1.w),d0
    move.b  d0,animal_ground_routine_base(a0)
    lsl.w   #3,d0
    lea Obj28_Properties(pc),a1
    adda.w  d0,a1
    move.w  (a1)+,animal_ground_x_vel(a0)
    move.w  (a1)+,animal_ground_y_vel(a0)
    move.l  (a1)+,mappings(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$C,y_radius(a0)
    move.b  #4,render_flags(a0)
    bset    #0,render_flags(a0)
    move.b  #6,priority(a0)
    move.b  #8,width_pixels(a0)
    move.b  #7,anim_frame_duration(a0)
    move.b  #2,mapping_frame(a0)
    move.w  #-$400,y_vel(a0)
    tst.b   objoff_38(a0)
    bne.s   ++
    bsr.w   SingleObjLoad
    bne.s   +
    _move.b #ObjID_Points,id(a1) ; load obj29
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  objoff_3E(a0),d0
    lsr.w   #1,d0
    move.b  d0,mapping_frame(a1)
+   bra.w   DisplaySprite
; ===========================================================================
+
    move.b  #$1C,routine(a0)
    clr.w   x_vel(a0)
    bra.w   DisplaySprite
; ===========================================================================
;loc_11ADE
Obj28_Main:
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bsr.w   ObjectMoveAndFall
    tst.w   y_vel(a0)
    bmi.s   +
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    add.w   d1,y_pos(a0)
    move.w  animal_ground_x_vel(a0),x_vel(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
    move.b  #1,mapping_frame(a0)
    move.b  animal_ground_routine_base(a0),d0
    add.b   d0,d0
    addq.b  #4,d0
    move.b  d0,routine(a0)
    tst.b   objoff_38(a0)
    beq.s   +
    btst    #4,(Vint_runcount+3).w
    beq.s   +
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
+   bra.w   DisplaySprite
; ===========================================================================
;loc_11B38
Obj28_Walk:
 
    bsr.w   ObjectMoveAndFall
    move.b  #1,mapping_frame(a0)
    tst.w   y_vel(a0)
    bmi.s   +
    move.b  #0,mapping_frame(a0)
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
+
    tst.b   subtype(a0)
    bne.s   Obj28_ChkDel
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
;loc_11B74
Obj28_Fly:
    bsr.w   ObjectMove
    addi.w  #$18,y_vel(a0)
    tst.w   y_vel(a0)
    bmi.s   +
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
    tst.b   subtype(a0)
    beq.s   +
    cmpi.b  #$A,subtype(a0)
    beq.s   +
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
+
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #1,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #1,mapping_frame(a0)
+
    tst.b   subtype(a0)
    bne.s   Obj28_ChkDel
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
;loc_11BD8
Obj28_ChkDel:
    move.w  x_pos(a0),d0
    sub.w   (MainCharacter+x_pos).w,d0
    bcs.s   +
    subi.w  #$180,d0
    bpl.s   +
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
+
    bra.w   DisplaySprite
; ===========================================================================
;loc_11BF4
Obj28_Prison:
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    subq.w  #1,objoff_36(a0)
    bne.w   +
    move.b  #2,routine(a0)
    move.b  #1,priority(a0)
+
    bra.w   DisplaySprite
; ===========================================================================
;loc_11C14
Obj28_FlickyWait:
    bsr.w   ChkAnimalInRange
    bcc.s   +
    move.w  animal_ground_x_vel(a0),x_vel(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
    move.b  #$E,routine(a0)
    bra.w   Obj28_Fly
; ===========================================================================
+
    bra.w   Obj28_ChkDel
; ===========================================================================
;loc_11C34
Obj28_FlickyJump:
    bsr.w   ChkAnimalInRange
    bpl.s   +
    clr.w   x_vel(a0)
    clr.w   animal_ground_x_vel(a0)
    bsr.w   ObjectMove
    addi.w  #$18,y_vel(a0)
    bsr.w   AnimalJump
    bsr.w   AnimalFaceSonic
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #1,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #1,mapping_frame(a0)
+
    bra.w   Obj28_ChkDel
; ===========================================================================
;loc_11C6E
Obj28_RabbitWait:
    bsr.w   ChkAnimalInRange
    bpl.s   ++
    move.w  animal_ground_x_vel(a0),x_vel(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
    move.b  #4,routine(a0)
    bra.w   Obj28_Walk
; ===========================================================================
;loc_11C8A
Obj28_DoubleBounce:
    bsr.w   ObjectMoveAndFall
    move.b  #1,mapping_frame(a0)
    tst.w   y_vel(a0)
    bmi.s   ++
    move.b  #0,mapping_frame(a0)
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   ++
    not.b   objoff_29(a0)
    bne.s   +
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
+
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
+
    bra.w   Obj28_ChkDel
; ===========================================================================
;loc_11CC8
Obj28_LandJump:
    bsr.w   ChkAnimalInRange
    bpl.s   +
    clr.w   x_vel(a0)
    clr.w   animal_ground_x_vel(a0)
    bsr.w   ObjectMoveAndFall
    bsr.w   AnimalJump
    bsr.w   AnimalFaceSonic
+
    bra.w   Obj28_ChkDel
; ===========================================================================
;loc_11CE6
Obj28_SingleBounce:
    bsr.w   ChkAnimalInRange
    bpl.s   +
    bsr.w   ObjectMoveAndFall
    move.b  #1,mapping_frame(a0)
    tst.w   y_vel(a0)
    bmi.s   +
    move.b  #0,mapping_frame(a0)
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
+
    bra.w   Obj28_ChkDel
; ===========================================================================
;loc_11D24
Obj28_FlyBounce:
    bsr.w   ChkAnimalInRange
    bpl.s   +++
    bsr.w   ObjectMove
    addi.w  #$18,y_vel(a0)
    tst.w   y_vel(a0)
    bmi.s   ++
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   ++
    not.b   objoff_29(a0)
    bne.s   +
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
+
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
+
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #1,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #1,mapping_frame(a0)
+
    bra.w   Obj28_ChkDel
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_11D78
AnimalJump:
    move.b  #1,mapping_frame(a0)
    tst.w   y_vel(a0)
    bmi.s   +   ; rts
    move.b  #0,mapping_frame(a0)
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +   ; rts
    add.w   d1,y_pos(a0)
    move.w  animal_ground_y_vel(a0),y_vel(a0)
+
    rts
; End of function AnimalJump
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_11DA0
AnimalFaceSonic:
    bset    #0,render_flags(a0)
    move.w  x_pos(a0),d0
    sub.w   (MainCharacter+x_pos).w,d0
    bcc.s   +   ; rts
    bclr    #0,render_flags(a0)
+
    rts
; End of function AnimalFaceSonic
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;sub_11DB8
ChkAnimalInRange:
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    subi.w  #$B8,d0
    rts
; End of function ChkAnimalInRange
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 29 - "100 points" text
; ----------------------------------------------------------------------------
; Sprite_11DC6:
Obj29:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj29_Index(pc,d0.w),d1
    jmp Obj29_Index(pc,d1.w)
; ===========================================================================
; off_11DD4:
Obj29_Index:    offsetTable
        offsetTableEntry.w Obj29_Init   ; 0
        offsetTableEntry.w Obj29_Main   ; 2
; ===========================================================================
 
Obj29_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj29_MapUnc_11ED0,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Numbers,0,1),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #8,width_pixels(a0)
    move.w  #-$300,y_vel(a0)    ; set initial speed (upwards)
 
Obj29_Main:
    tst.w   y_vel(a0)       ; test speed
    bpl.w   DeleteObject        ; if it's positive (>= 0), delete the object
    bsr.w   ObjectMove      ; move the points
    addi.w  #$18,y_vel(a0)      ; slow down
    bra.w   DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj28_MapUnc_11E1C: BINCLUDE "mappings/sprite/obj28_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj28_MapUnc_11E40: BINCLUDE "mappings/sprite/obj28_b.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj28_MapUnc_11E64: BINCLUDE "mappings/sprite/obj28_c.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj28_MapUnc_11E88: BINCLUDE "mappings/sprite/obj28_d.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj28_MapUnc_11EAC: BINCLUDE "mappings/sprite/obj28_e.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj29_MapUnc_11ED0: BINCLUDE "mappings/sprite/obj29.bin"
 
    if ~~removeJmpTos
JmpTo_RandomNumber 
    jmp (RandomNumber).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 25 - A ring (usually only placed through placement mode)
; ----------------------------------------------------------------------------
; Obj_Ring:
Obj25:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj25_Index(pc,d0.w),d1
    jmp Obj25_Index(pc,d1.w)
; ===========================================================================
; Obj_25_subtbl:
Obj25_Index:    offsetTable
        offsetTableEntry.w Obj25_Init       ; 0
        offsetTableEntry.w Obj25_Animate    ; 2
        offsetTableEntry.w Obj25_Collect    ; 4
        offsetTableEntry.w Obj25_Sparkle    ; 6
        offsetTableEntry.w Obj25_Delete     ; 8
; ===========================================================================
; Obj_25_sub_0:
Obj25_Init:
    addq.b  #2,routine(a0)
    move.w  x_pos(a0),objoff_32(a0)
    move.l  #Obj25_MapUnc_12382,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #2,priority(a0)
    move.b  #$47,collision_flags(a0)
    move.b  #8,width_pixels(a0)
; Obj_25_sub_2:
Obj25_Animate:
    move.b  (Rings_anim_frame).w,mapping_frame(a0)
    move.w  objoff_32(a0),d0
    bra.w   MarkObjGone2
; ===========================================================================
; Obj_25_sub_4:
Obj25_Collect:
    addq.b  #2,routine(a0)
    move.b  #0,collision_flags(a0)
    move.b  #1,priority(a0)
    bsr.s   CollectRing
; Obj_25_sub_6:
Obj25_Sparkle:
    lea (Ani_Ring).l,a1
    bsr.w   AnimateSprite
    bra.w   DisplaySprite
; ===========================================================================
; BranchTo4_DeleteObject 
Obj25_Delete:
    bra.w   DeleteObject
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_11FC2:
CollectRing:
    tst.b   parent+1(a0)        ; did Tails collect the ring?
    bne.s   CollectRing_Tails   ; if yes, branch
 
CollectRing_Sonic:
    cmpi.w  #999,(Rings_Collected).w ; did Sonic collect 999 or more rings?
    bhs.s   CollectRing_1P      ; if yes, branch
    addq.w  #1,(Rings_Collected).w  ; add 1 to the number of collected rings
 
CollectRing_1P:
 
    if gameRevision=0
    cmpi.w  #999,(Ring_count).w ; does the player 1 have 999 or more rings?
    bhs.s   +           ; if yes, skip the increment
    addq.w  #1,(Ring_count).w   ; add 1 to the ring count
+
    ori.b   #1,(Update_HUD_rings).w ; set flag to update the ring counter in the HUD
    move.w  #SndID_Ring,d0      ; prepare to play the ring sound
    else
    move.w  #SndID_Ring,d0      ; prepare to play the ring sound
    cmpi.w  #999,(Ring_count).w ; does the player 1 have 999 or more rings?
    bhs.s   JmpTo_PlaySoundStereo   ; if yes, play the ring sound
    addq.w  #1,(Ring_count).w   ; add 1 to the ring count
    ori.b   #1,(Update_HUD_rings).w ; set flag to update the ring counter in the HUD
    endif
 
    cmpi.w  #100,(Ring_count).w ; does the player 1 have less than 100 rings?
    blo.s   JmpTo_PlaySoundStereo   ; if yes, play the ring sound
    bset    #1,(Extra_life_flags).w ; test and set the flag for the first extra life
    beq.s   +           ; if it was clear before, branch
    cmpi.w  #200,(Ring_count).w ; does the player 1 have less than 200 rings?
    blo.s   JmpTo_PlaySoundStereo   ; if yes, play the ring sound
    bset    #2,(Extra_life_flags).w ; test and set the flag for the second extra life
    bne.s   JmpTo_PlaySoundStereo   ; if it was set before, play the ring sound
+
    addq.b  #1,(Life_count).w   ; add 1 to the life count
    addq.b  #1,(Update_HUD_lives).w ; add 1 to the displayed life count
    move.w  #MusID_ExtraLife,d0 ; prepare to play the extra life jingle
 
JmpTo_PlaySoundStereo 
    jmp (PlaySoundStereo).l
; ===========================================================================
    rts
; ===========================================================================
 
CollectRing_Tails:
    cmpi.w  #999,(Rings_Collected_2P).w ; did Tails collect 999 or more rings?
    bhs.s   +               ; if yes, branch
    addq.w  #1,(Rings_Collected_2P).w   ; add 1 to the number of collected rings
+                                          
    cmpi.w  #999,(Ring_count_2P).w      ; does Tails have 999 or more rings?
    bhs.s   +               ; if yes, branch
    addq.w  #1,(Ring_count_2P).w        ; add 1 to the ring count
+
    tst.w   (Two_player_mode).w     ; are we in a 2P game?
    beq.s   CollectRing_1P          ; if not, branch
 
; CollectRing_2P:
    ori.b   #1,(Update_HUD_rings_2P).w  ; set flag to update the ring counter in the second player's HUD
    move.w  #SndID_Ring,d0          ; prepare to play the ring sound
    cmpi.w  #100,(Ring_count_2P).w      ; does the player 2 have less than 100 rings?
    blo.s   JmpTo2_PlaySoundStereo      ; if yes, play the ring sound
    bset    #1,(Extra_life_flags_2P).w  ; test and set the flag for the first extra life
    beq.s   +               ; if it was clear before, branch
    cmpi.w  #200,(Ring_count_2P).w      ; does the player 2 have less than 200 rings?
    blo.s   JmpTo2_PlaySoundStereo      ; if yes, play the ring sound
    bset    #2,(Extra_life_flags_2P).w  ; test and set the flag for the second extra life
    bne.s   JmpTo2_PlaySoundStereo      ; if it was set before, play the ring sound
+
    addq.b  #1,(Life_count_2P).w        ; add 1 to the life count
    addq.b  #1,(Update_HUD_lives_2P).w  ; add 1 to the displayed life count
    move.w  #MusID_ExtraLife,d0     ; prepare to play the extra life jingle
 
JmpTo2_PlaySoundStereo 
    jmp (PlaySoundStereo).l
; End of function CollectRing
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 37 - Scattering rings (generated when Sonic is hurt and has rings)
; ----------------------------------------------------------------------------
; Sprite_12078:
Obj37:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj37_Index(pc,d0.w),d1
    jmp Obj37_Index(pc,d1.w)
; ===========================================================================
; Obj_37_subtbl:
Obj37_Index:    offsetTable
        offsetTableEntry.w Obj37_Init       ; 0
        offsetTableEntry.w Obj37_Main       ; 2
        offsetTableEntry.w Obj37_Collect    ; 4
        offsetTableEntry.w Obj37_Sparkle    ; 6
        offsetTableEntry.w Obj37_Delete     ; 8
; ===========================================================================
; Obj_37_sub_0:
Obj37_Init:
    movea.l a0,a1
    moveq   #0,d5
    move.w  (Ring_count).w,d5
    tst.b   parent+1(a0)
    beq.s   +
    move.w  (Ring_count_2P).w,d5
+
    moveq   #$20,d0
    cmp.w   d0,d5
    blo.s   +
    move.w  d0,d5
+
    subq.w  #1,d5
    move.w  #$288,d4
    bra.s   +
; ===========================================================================
 
-   bsr.w   SingleObjLoad
    bne.w   +++
+
    _move.b #ObjID_LostRings,id(a1) ; load obj37
    addq.b  #2,routine(a1)
    move.b  #8,y_radius(a1)
    move.b  #8,x_radius(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  #Obj25_MapUnc_12382,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #$84,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #$47,collision_flags(a1)
    move.b  #8,width_pixels(a1)
    move.b  #-1,(Ring_spill_anim_counter).w
    tst.w   d4
    bmi.s   +
    move.w  d4,d0
    jsrto   (CalcSine).l, JmpTo4_CalcSine
    move.w  d4,d2
    lsr.w   #8,d2
    asl.w   d2,d0
    asl.w   d2,d1
    move.w  d0,d2
    move.w  d1,d3
    addi.b  #$10,d4
    bcc.s   +
    subi.w  #$80,d4
    bcc.s   +
    move.w  #$288,d4
+
    move.w  d2,x_vel(a1)
    move.w  d3,y_vel(a1)
    neg.w   d2
    neg.w   d4
    dbf d5,-
+
    move.w  #SndID_RingSpill,d0
    jsr (PlaySoundStereo).l
    tst.b   parent+1(a0)
    bne.s   +
    move.w  #0,(Ring_count).w
    move.b  #$80,(Update_HUD_rings).w
    move.b  #0,(Extra_life_flags).w
    bra.s   Obj37_Main
; ===========================================================================
+
    move.w  #0,(Ring_count_2P).w
    move.b  #$80,(Update_HUD_rings_2P).w
    move.b  #0,(Extra_life_flags_2P).w
; Obj_37_sub_2:
Obj37_Main:
    move.b  (Ring_spill_anim_frame).w,mapping_frame(a0)
    bsr.w   ObjectMove
    addi.w  #$18,y_vel(a0)
    bmi.s   loc_121B8
    move.b  (Vint_runcount+3).w,d0
    add.b   d7,d0
    andi.b  #7,d0
    bne.s   loc_121B8
    tst.b   render_flags(a0)
    bpl.s   loc_121D0
    jsr (RingCheckFloorDist).l
    tst.w   d1
    bpl.s   loc_121B8
    add.w   d1,y_pos(a0)
    move.w  y_vel(a0),d0
    asr.w   #2,d0
    sub.w   d0,y_vel(a0)
    neg.w   y_vel(a0)
 
loc_121B8:
 
    tst.b   (Ring_spill_anim_counter).w
    beq.s   Obj37_Delete
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    blo.s   Obj37_Delete
    bra.w   DisplaySprite
; ===========================================================================
 
loc_121D0:
    tst.w   (Two_player_mode).w
    bne.w   Obj37_Delete
    bra.s   loc_121B8
; ===========================================================================
; Obj_37_sub_4:
Obj37_Collect:
    addq.b  #2,routine(a0)
    move.b  #0,collision_flags(a0)
    move.b  #1,priority(a0)
    bsr.w   CollectRing
; Obj_37_sub_6:
Obj37_Sparkle:
    lea (Ani_Ring).l,a1
    bsr.w   AnimateSprite
    bra.w   DisplaySprite
; ===========================================================================
; BranchTo5_DeleteObject 
Obj37_Delete:
    bra.w   DeleteObject
 
; Unused - dead code/data S1 big ring:
; ===========================================================================
; BigRing:
    ; a0=object
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  BigRing_States(pc,d0.w),d1
    jmp BigRing_States(pc,d1.w)
; ===========================================================================
BigRing_States: offsetTable
        offsetTableEntry.w BigRing_Init     ; 0
        offsetTableEntry.w BigRing_Main     ; 2
        offsetTableEntry.w BigRing_Enter    ; 4
        offsetTableEntry.w BigRing_Delete   ; 6
; ===========================================================================
; loc_12216:
BigRing_Init:
    move.l  #Obj37_MapUnc_123E6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BigRing,1,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$40,width_pixels(a0)
    tst.b   render_flags(a0)
    bpl.s   BigRing_Main
    cmpi.b  #6,(Got_Emerald).w
    beq.w   BigRing_Delete
    cmpi.w  #50,(Ring_count).w
    bhs.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.b  #2,priority(a0)
    move.b  #$52,collision_flags(a0)
    move.w  #$C40,(BigRingGraphics).w
; loc_12264:
BigRing_Main:
    move.b  (Rings_anim_frame).w,mapping_frame(a0)
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
; loc_12282:
BigRing_Enter:
    subq.b  #2,routine(a0)
    move.b  #0,collision_flags(a0)
    bsr.w   SingleObjLoad
    bne.w   +
    ; Note: the object ID is not set
    ; If you want to restore the big ring object, you'll also have to
    ; restore the ring flash object (right after this) and assign its ID to
    ; the created object here (a1).
    ;move.b #ObjID_BigRingFlash,id(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  a0,objoff_3C(a1)
    move.w  (MainCharacter+x_pos).w,d0
    cmp.w   x_pos(a0),d0
    blo.s   +
    bset    #0,render_flags(a1)
+
    move.w  #SndID_EnterGiantRing,d0
    jsr (PlaySoundStereo).l
    bra.s   BigRing_Main
; ===========================================================================
; BranchTo6_DeleteObject 
BigRing_Delete:
    bra.w   DeleteObject
 
; Unused - dead code/data S1 ring flash:
; ===========================================================================
; BigRingFlash:
    ; a0=object
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  BigRingFlash_States(pc,d0.w),d1
    jmp BigRingFlash_States(pc,d1.w)
; ===========================================================================
BigRingFlash_States: offsetTable
    offsetTableEntry.w BigRingFlash_Init    ; 0
    offsetTableEntry.w BigRingFlash_Main    ; 2
    offsetTableEntry.w BigRingFlash_Delete  ; 4
; ===========================================================================
; loc_122D8:
BigRingFlash_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj37_MapUnc_124E6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BigRing_Flash,1,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #0,priority(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #-1,mapping_frame(a0)
; loc_12306:
BigRingFlash_Main:
    bsr.s   BigRingFlash_Animate
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   DeleteObject
    bra.w   DisplaySprite
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_12320:
BigRingFlash_Animate:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.s   +   ; rts
    move.b  #1,anim_frame_duration(a0)  ; reset frame duration (2 frames)
    addq.b  #1,mapping_frame(a0)        ; use next animation frame
    cmpi.b  #8,mapping_frame(a0)        ; have we reached the end of the animation frames?
    bhs.s   ++              ; if yes, branch
    cmpi.b  #3,mapping_frame(a0)        ; have we reached the 4th animation frame?
    bne.s   +   ; rts           ; if not, return
    movea.l objoff_3C(a0),a1 ; a1=object    ; get the parent big ring object
    move.b  #6,routine(a1)          ; set its routine to "delete"
    move.b  #AniIDSonAni_Blank,(MainCharacter+anim).w   ; change the character's animation
    move.b  #1,(SpecialStage_flag_2P).w
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #status_sec_isInvincible,status_secondary(a1)
    bclr    #status_sec_hasShield,status_secondary(a1)
+   rts
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  #0,(MainCharacter).w        ; delete the player object
    addq.l  #4,sp
    rts
; End of function BigRingFlash_Animate
 
; ===========================================================================
; BranchTo7_DeleteObject 
BigRingFlash_Delete:
    bra.w   DeleteObject
 
; end of dead code/data
 
; ===========================================================================
 
; animation script
; byte_1237A:
Ani_Ring:   offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   5,  4,  5,  6,  7,$FC
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj25_MapUnc_12382: BINCLUDE "mappings/sprite/obj37_a.bin"
 
; -------------------------------------------------------------------------------
; Unused sprite mappings
; -------------------------------------------------------------------------------
Obj37_MapUnc_123E6: BINCLUDE "mappings/sprite/obj37_b.bin"
; -------------------------------------------------------------------------------
; Unused sprite mappings
; -------------------------------------------------------------------------------
Obj37_MapUnc_124E6: BINCLUDE "mappings/sprite/obj37_c.bin"
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object DC - Ring prize from Casino Night Zone
; ----------------------------------------------------------------------------
casino_prize_x_pos =        objoff_30   ; X position of the ring with greater precision
casino_prize_y_pos =        objoff_34   ; Y position of the ring with greater precision
casino_prize_machine_x_pos =    objoff_38   ; X position of the slot machine that generated the ring
casino_prize_machine_y_pos =    objoff_3A   ; Y position of the slot machine that generated the ring
casino_prize_display_delay =    objoff_3C   ; number of frames before which the ring is displayed
; Sprite_125E6:
ObjDC:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjDC_Index(pc,d0.w),d1
    jmp ObjDC_Index(pc,d1.w)
; ===========================================================================
; off_125F4:
ObjDC_Index:    offsetTable
        offsetTableEntry.w ObjDC_Main       ; 0
        offsetTableEntry.w ObjDC_Animate    ; 2
        offsetTableEntry.w ObjDC_Delete     ; 4
; ===========================================================================
; loc_125FA:
ObjDC_Main:
    moveq   #0,d1
    move.w  casino_prize_machine_x_pos(a0),d1
    swap    d1
    move.l  casino_prize_x_pos(a0),d0
    sub.l   d1,d0
    asr.l   #4,d0
    sub.l   d0,casino_prize_x_pos(a0)
    move.w  casino_prize_x_pos(a0),x_pos(a0)
    moveq   #0,d1
    move.w  casino_prize_machine_y_pos(a0),d1
    swap    d1
    move.l  casino_prize_y_pos(a0),d0
    sub.l   d1,d0
    asr.l   #4,d0
    sub.l   d0,casino_prize_y_pos(a0)
    move.w  casino_prize_y_pos(a0),y_pos(a0)
    lea Ani_objDC(pc),a1
    bsr.w   AnimateSprite
    subq.w  #1,casino_prize_display_delay(a0)
    bne.w   DisplaySprite
    movea.l objoff_2A(a0),a1
    subq.w  #1,(a1)
    bsr.w   CollectRing
    addi_.b #2,routine(a0)
; loc_1264E:
ObjDC_Animate:
    lea Ani_Ring(pc),a1
    bsr.w   AnimateSprite
    bra.w   DisplaySprite
; ===========================================================================
; BranchTo8_DeleteObject 
ObjDC_Delete:
    bra.w   DeleteObject
; ===========================================================================
; animation script
; byte_1265E
Ani_objDC:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,  2,  3,$FF
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo4_CalcSine 
    jmp (CalcSine).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 26 - Monitor
;
; The power-ups themselves are handled by the next object. This just does the
; monitor collision and graphics.
; ----------------------------------------------------------------------------
; Obj_Monitor:
Obj26:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj26_Index(pc,d0.w),d1
    jmp Obj26_Index(pc,d1.w)
; ===========================================================================
; obj_26_subtbl:
Obj26_Index:    offsetTable
        offsetTableEntry.w Obj26_Init           ; 0
        offsetTableEntry.w Obj26_Main           ; 2
        offsetTableEntry.w Obj26_Break          ; 4
        offsetTableEntry.w Obj26_Animate        ; 6
        offsetTableEntry.w BranchTo2_MarkObjGone    ; 8
; ===========================================================================
; obj_26_sub_0: Obj_26_Init:
Obj26_Init:
    addq.b  #2,routine(a0)
    move.b  #$E,y_radius(a0)
    move.b  #$E,x_radius(a0)
    move.l  #Obj26_MapUnc_12D36,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #$F,width_pixels(a0)
 
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    bclr    #7,2(a2,d0.w)
    btst    #0,2(a2,d0.w)   ; if this bit is set it means the monitor is already broken
    beq.s   +
    move.b  #8,routine(a0)  ; set monitor to 'broken' state
    move.b  #$B,mapping_frame(a0)
    rts
; ---------------------------------------------------------------------------
+
    move.b  #$46,collision_flags(a0)
    move.b  subtype(a0),anim(a0)    ; subtype = icon to display
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.s   Obj26_Main      ; if not, branch
    move.b  #9,anim(a0)     ; use '?' icon
;obj_26_sub_2:
Obj26_Main:
    move.b  routine_secondary(a0),d0
    beq.s   SolidObject_Monitor
    ; only when secondary routine isn't 0
    ; make monitor fall
    bsr.w   ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1          ; is monitor in the ground?
    bpl.w   SolidObject_Monitor ; if not, branch
    add.w   d1,y_pos(a0)        ; move monitor out of the ground
    clr.w   y_vel(a0)
    clr.b   routine_secondary(a0)   ; stop monitor from falling
; loc_1271C:
SolidObject_Monitor:
    move.w  #$1A,d1 ; monitor's width
    move.w  #$F,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SolidObject_Monitor_Sonic
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SolidObject_Monitor_Tails
 
Obj26_Animate:
    lea (Ani_obj26).l,a1
    bsr.w   AnimateSprite
 
BranchTo2_MarkObjGone 
    bra.w   MarkObjGone
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; sub_12756:
SolidObject_Monitor_Sonic:
    btst    d6,status(a0)       ; is Sonic standing on the monitor?
    bne.s   Obj26_ChkOverEdge   ; if yes, branch
    cmpi.b  #AniIDSonAni_Roll,anim(a1)      ; is Sonic spinning?
    bne.w   SolidObject_cont    ; if not, branch
    rts
; End of function SolidObject_Monitor_Sonic
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; sub_12768:
SolidObject_Monitor_Tails:
    btst    d6,status(a0)       ; is Tails standing on the monitor?
    bne.s   Obj26_ChkOverEdge   ; if yes, branch
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.w   SolidObject_cont    ; if not, branch
    ; in one player mode monitors always behave as solid for Tails
    cmpi.b  #2,anim(a1)     ; is Tails spinning?
    bne.w   SolidObject_cont    ; if not, branch
    rts
; End of function SolidObject_Monitor_Tails
 
; ---------------------------------------------------------------------------
; Checks if the player has walked over the edge of the monitor.
; ---------------------------------------------------------------------------
;loc_12782:
Obj26_ChkOverEdge:
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)   ; is the character in the air?
    bne.s   +       ; if yes, branch
    ; check, if character is standing on 
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   +   ; branch, if character is behind the left edge of the monitor
    cmp.w   d2,d0
    blo.s   Obj26_CharStandOn   ; branch, if character is not beyond the right edge of the monitor
+
    ; if the character isn't standing on the monitor
    bclr    #3,status(a1)   ; clear 'on object' bit
    bset    #1,status(a1)   ; set 'in air' bit
    bclr    d6,status(a0)   ; clear 'standing on' bit for the current character
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
;loc_127B2:
Obj26_CharStandOn:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
    rts
; ===========================================================================
;obj_26_sub_4:
Obj26_Break:
    move.b  status(a0),d0
    andi.b  #standing_mask|pushing_mask,d0  ; is someone touching the monitor?
    beq.s   Obj26_SpawnIcon ; if not, branch
    move.b  d0,d1
    andi.b  #p1_standing|p1_pushing,d1  ; is it the main character?
    beq.s   +       ; if not, branch
    andi.b  #$D7,(MainCharacter+status).w
    ori.b   #2,(MainCharacter+status).w ; prevent Sonic from walking in the air
+
    andi.b  #p2_standing|p2_pushing,d0  ; is it the sidekick?
    beq.s   Obj26_SpawnIcon ; if not, branch
    andi.b  #$D7,(Sidekick+status).w
    ori.b   #2,(Sidekick+status).w  ; prevent Tails from walking in the air
;loc_127EC:
Obj26_SpawnIcon:
    clr.b   status(a0)
    addq.b  #2,routine(a0)
    move.b  #0,collision_flags(a0)
    bsr.w   SingleObjLoad
    bne.s   Obj26_SpawnSmoke
    _move.b #ObjID_MonitorContents,id(a1) ; load obj2E
    move.w  x_pos(a0),x_pos(a1) ; set icon's position
    move.w  y_pos(a0),y_pos(a1)
    move.b  anim(a0),anim(a1)
    move.w  parent(a0),parent(a1)   ; parent gets the item
;loc_1281E:
Obj26_SpawnSmoke:
    bsr.w   SingleObjLoad
    bne.s   +
    _move.b #ObjID_Explosion,id(a1) ; load obj27
    addq.b  #2,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    bset    #0,2(a2,d0.w)   ; mark monitor as destroyed
    move.b  #$A,anim(a0)
    bra.w   DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 2E - Monitor contents (code for power-up behavior and rising image)
; ----------------------------------------------------------------------------
 
Obj2E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2E_Index(pc,d0.w),d1
    jmp Obj2E_Index(pc,d1.w)
; ===========================================================================
; off_12862:
Obj2E_Index:    offsetTable
        offsetTableEntry.w Obj2E_Init   ; 0
        offsetTableEntry.w Obj2E_Raise  ; 2
        offsetTableEntry.w Obj2E_Wait   ; 4
; ===========================================================================
; Object initialization. Called if routine counter == 0.
; loc_12868:
Obj2E_Init:
    addq.b  #2,routine(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$24,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #8,width_pixels(a0)
    move.w  #-$300,y_vel(a0)
    moveq   #0,d0
    move.b  anim(a0),d0
 
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.s   loc_128C6       ; if not, branch
    ; give 'random' item in two player mode
    move.w  (Timer_frames).w,d0 ; use the timer to determine which item
    andi.w  #7,d0   ; and 7 means there are 8 different items
    addq.w  #1,d0   ; add 1 to prevent getting the static monitor
    tst.w   (Two_player_items).w    ; are monitors set to 'teleport only'?
    beq.s   +           ; if not, branch
    moveq   #8,d0           ; force contents to be teleport
+   ; keep teleport monitor from causing unwanted effects
    cmpi.w  #8,d0   ; teleport?
    bne.s   +   ; if not, branch
    move.b  (Update_HUD_timer).w,d1
    add.b   (Update_HUD_timer_2P).w,d1
    cmpi.b  #2,d1   ; is either player done with the act?
    beq.s   +   ; if not, branch
    moveq   #7,d0   ; give invincibility, instead
+
    move.b  d0,anim(a0)
;loc_128C6:
loc_128C6:          ; Determine correct mappings offset.
    addq.b  #1,d0
    move.b  d0,mapping_frame(a0)
    movea.l #Obj26_MapUnc_12D36,a1
    add.b   d0,d0
    adda.w  (a1,d0.w),a1
    addq.w  #2,a1
    move.l  a1,mappings(a0)
; loc_128DE:
Obj2E_Raise:
    bsr.s   +
    bra.w   DisplaySprite
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
+
    tst.w   y_vel(a0)   ; is icon still floating up?
    bpl.w   +       ; if not, branch
    bsr.w   ObjectMove  ; update position
    addi.w  #$18,y_vel(a0)  ; reduce upward speed
    rts
; ---------------------------------------------------------------------------
 
+
    addq.b  #2,routine(a0)
    move.w  #$1D,anim_frame_duration(a0)
    movea.w parent(a0),a1 ; a1=character
    lea (Monitors_Broken).w,a2
    cmpa.w  #MainCharacter,a1   ; did Sonic break the monitor?
    beq.s   +           ; if yes, branch
    lea (Monitors_Broken_2P).w,a2
 
+
    moveq   #0,d0
    move.b  anim(a0),d0
    add.w   d0,d0
    move.w  Obj2E_Types(pc,d0.w),d0
    jmp Obj2E_Types(pc,d0.w)
; End of function
 
; ===========================================================================
Obj2E_Types:    offsetTable
        offsetTableEntry.w robotnik_monitor ; 0 - Static
        offsetTableEntry.w sonic_1up        ; 1 - Sonic 1-up
        offsetTableEntry.w tails_1up        ; 2 - Tails 1-up
        offsetTableEntry.w robotnik_monitor ; 3 - Robotnik
        offsetTableEntry.w super_ring       ; 4 - Super Ring
        offsetTableEntry.w super_shoes      ; 5 - Speed Shoes
        offsetTableEntry.w shield_monitor   ; 6 - Shield
        offsetTableEntry.w invincible_monitor   ; 7 - Invincibility
        offsetTableEntry.w teleport_monitor ; 8 - Teleport
        offsetTableEntry.w qmark_monitor    ; 9 - Question mark
; ===========================================================================
; ---------------------------------------------------------------------------
; Robotnik Monitor
; hurts the player
; ---------------------------------------------------------------------------
; badnik_monitor:
robotnik_monitor:
    addq.w  #1,(a2)
    bra.w   Touch_ChkHurt2
; ===========================================================================
; ---------------------------------------------------------------------------
; Sonic 1up Monitor
; gives Sonic an extra life, or Tails in a 'Tails alone' game
; ---------------------------------------------------------------------------
sonic_1up:
    addq.w  #1,(Monitors_Broken).w
    addq.b  #1,(Life_count).w
    addq.b  #1,(Update_HUD_lives).w
    move.w  #MusID_ExtraLife,d0
    jmp (PlayMusic).l   ; Play extra life music
; ===========================================================================
; ---------------------------------------------------------------------------
; Tails 1up Monitor
; gives Tails an extra life in two player mode
; ---------------------------------------------------------------------------
tails_1up:
    addq.w  #1,(Monitors_Broken_2P).w
    addq.b  #1,(Life_count_2P).w
    addq.b  #1,(Update_HUD_lives_2P).w
    move.w  #MusID_ExtraLife,d0
    jmp (PlayMusic).l   ; Play extra life music
; ===========================================================================
; ---------------------------------------------------------------------------
; Super Ring Monitor
; gives the player 10 rings
; ---------------------------------------------------------------------------
super_ring:
    addq.w  #1,(a2)
 
    if gameRevision=0
    lea (Ring_count).w,a2
    lea (Update_HUD_rings).w,a3
    lea (Extra_life_flags).w,a4
    cmpa.w  #MainCharacter,a1
    beq.s   +
    lea (Ring_count_2P).w,a2
    lea (Update_HUD_rings_2P).w,a3
    lea (Extra_life_flags_2P).w,a4
+   ; give player 10 rings
    addi.w  #10,(a2)
    else
    lea (Ring_count).w,a2
    lea (Update_HUD_rings).w,a3
    lea (Extra_life_flags).w,a4
    lea (Rings_Collected).w,a5
    cmpa.w  #MainCharacter,a1
    beq.s   +
    lea (Ring_count_2P).w,a2
    lea (Update_HUD_rings_2P).w,a3
    lea (Extra_life_flags_2P).w,a4
    lea (Rings_Collected_2P).w,a5
+
    addi.w  #10,(a5)
    cmpi.w  #999,(a5)
    blo.s   +
    move.w  #999,(a5)
 
+   ; give player 10 rings and max out at 999
    addi.w  #10,(a2)
    cmpi.w  #999,(a2)
    blo.s   +
    move.w  #999,(a2)
    endif
 
+
    ori.b   #1,(a3)
    cmpi.w  #100,(a2)
    blo.s   +       ; branch, if player has less than 100 rings
    bset    #1,(a4)     ; set flag for first 1up
    beq.s   ChkPlayer_1up   ; branch, if not yet set
    cmpi.w  #200,(a2)
    blo.s   +       ; branch, if player has less than 200 rings
    bset    #2,(a4)     ; set flag for second 1up
    beq.s   ChkPlayer_1up   ; branch, if not yet set
+
    move.w  #SndID_Ring,d0
    jmp (PlayMusic).l
; ---------------------------------------------------------------------------
;loc_129D4:
ChkPlayer_1up:
    ; give 1up to correct player
    cmpa.w  #MainCharacter,a1
    beq.w   sonic_1up
    bra.w   tails_1up
; ===========================================================================
; ---------------------------------------------------------------------------
; Super Sneakers Monitor
; speeds the player up temporarily
; ---------------------------------------------------------------------------
super_shoes:
    addq.w  #1,(a2)
    bset    #status_sec_hasSpeedShoes,status_secondary(a1)  ; give super sneakers status
    move.w  #$4B0,speedshoes_time(a1)
    cmpa.w  #MainCharacter,a1   ; did the main character break the monitor?
    bne.s   super_shoes_Tails   ; if not, branch
    cmpi.w  #2,(Player_mode).w  ; is player using Tails?
    beq.s   super_shoes_Tails   ; if yes, branch
    move.w  #$C00,(Sonic_top_speed).w   ; set stats
    move.w  #$18,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
    bra.s   +
; ---------------------------------------------------------------------------
;loc_12A10:
super_shoes_Tails:
    move.w  #$C00,(Tails_top_speed).w
    move.w  #$18,(Tails_acceleration).w
    move.w  #$80,(Tails_deceleration).w
+
    move.w  #MusID_SpeedUp,d0
    jmp (PlayMusic).l   ; Speed up tempo
; ===========================================================================
; ---------------------------------------------------------------------------
; Shield Monitor
; gives the player a shield that absorbs one hit
; ---------------------------------------------------------------------------
shield_monitor:
    addq.w  #1,(a2)
    bset    #status_sec_hasShield,status_secondary(a1)  ; give shield status
    move.w  #SndID_Shield,d0
    jsr (PlayMusic).l
    tst.b   parent+1(a0)
    bne.s   +
    move.b  #ObjID_Shield,(Sonic_Shield+id).w ; load Obj38 (shield) at $FFFFD180
    move.w  a1,(Sonic_Shield+parent).w
    rts
; ---------------------------------------------------------------------------
+   ; give shield to sidekick
    move.b  #ObjID_Shield,(Tails_Shield+id).w ; load Obj38 (shield) at $FFFFD1C0
    move.w  a1,(Tails_Shield+parent).w
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Invincibility Monitor
; makes the player temporarily invincible
; ---------------------------------------------------------------------------
invincible_monitor:
    addq.w  #1,(a2)
    tst.b   (Super_Sonic_flag).w    ; is Sonic super?
    bne.s   +++ ; rts       ; if yes, branch
    bset    #status_sec_isInvincible,status_secondary(a1)   ; give invincibility status
    move.w  #20*60,invincibility_time(a1) ; 20 seconds
    tst.b   (Current_Boss_ID).w ; don't change music during boss battles
    bne.s   +
    cmpi.b  #$C,air_left(a1)    ; or when drowning
    bls.s   +
    move.w  #MusID_Invincible,d0
    jsr (PlayMusic).l
+
    tst.b   parent+1(a0)
    bne.s   +
    move.b  #ObjID_InvStars,(Sonic_InvincibilityStars+id).w ; load Obj35 (invincibility stars) at $FFFFD200
    move.w  a1,(Sonic_InvincibilityStars+parent).w
    rts
; ---------------------------------------------------------------------------
+   ; give invincibility to sidekick
    move.b  #ObjID_InvStars,(Tails_InvincibilityStars+id).w ; load Obj35 (invincibility stars) at $FFFFD300
    move.w  a1,(Tails_InvincibilityStars+parent).w
+
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Teleport Monitor
; swaps both players around
; ---------------------------------------------------------------------------
;loc_12AA6:
teleport_monitor:
    addq.w  #1,(a2)
    cmpi.b  #6,(MainCharacter+routine).w    ; is player 1 dead or respawning?
    bhs.s   +               ; if yes, branch
    cmpi.b  #6,(Sidekick+routine).w     ; is player 2 dead or respawning?
    blo.s   swap_players            ; if not, branch
+   ; can't teleport if either player is dead
    rts
 
; ---------------------------------------------------------------------------
; Routine to make both players swap positions
; and handle anything else that needs to be done
; ---------------------------------------------------------------------------
swap_players:
    lea (teleport_swap_table).l,a3
    moveq   #(teleport_swap_table_end-teleport_swap_table)/6-1,d2   ; amount of entries in table - 1
 
process_swap_table:
    movea.w (a3)+,a1    ; address for main character
    movea.w (a3)+,a2    ; address for sidekick
    move.w  (a3)+,d1    ; amount of word length data to be swapped
 
-   ; swap data between the main character and the sidekick d1 times
    move.w  (a1),d0
    move.w  (a2),(a1)+
    move.w  d0,(a2)+
    dbf d1,-
 
    dbf d2,process_swap_table   ; process remaining entries in the list
 
    move.b  #1,(MainCharacter+next_anim).w
    move.b  #1,(Sidekick+next_anim).w
    if gameRevision>0
    move.b  #0,(MainCharacter+mapping_frame).w
    move.b  #0,(Sidekick+mapping_frame).w
    endif
    move.b  #-1,(Sonic_LastLoadedDPLC).w
    move.b  #-1,(Tails_LastLoadedDPLC).w
    move.b  #-1,(TailsTails_LastLoadedDPLC).w
    lea (unk_F786).w,a1
    lea (unk_F789).w,a2
 
    moveq   #2,d1
-   move.b  (a1),d0
    move.b  (a2),(a1)+
    move.b  d0,(a2)+
    dbf d1,-
 
    subi.w  #$180,(Camera_Y_pos).w
    subi.w  #$180,(Camera_Y_pos_P2).w
    move.w  (MainCharacter+art_tile).w,d0
    andi.w  #drawing_mask,(MainCharacter+art_tile).w
    tst.w   (Sidekick+art_tile).w
    bpl.s   +
    ori.w   #high_priority,(MainCharacter+art_tile).w
+
    andi.w  #drawing_mask,(Sidekick+art_tile).w
    tst.w   d0
    bpl.s   +
    ori.w   #high_priority,(Sidekick+art_tile).w
+
    move.b  #1,(Camera_Max_Y_Pos_Changing).w
    lea (Dynamic_Object_RAM).w,a1
    moveq   #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d1
 
; process objects:
swap_loop_objects:
    cmpi.b  #ObjID_PinballMode,id(a1) ; is it obj84 (pinball mode switcher)?
    beq.s   + ; if yes, branch
    cmpi.b  #ObjID_PlaneSwitcher,id(a1) ; is it obj03 (collision plane switcher)?
    bne.s   ++ ; if not, branch further
 
+
    move.b  objoff_34(a1),d0
    move.b  objoff_35(a1),objoff_34(a1)
    move.b  d0,objoff_35(a1)
 
+
    cmpi.b  #ObjID_PointPokey,id(a1) ; is it objD6 (CNZ point giver)?
    bne.s   + ; if not, branch
    move.l  objoff_30(a1),d0
    move.l  objoff_34(a1),objoff_30(a1)
    move.l  d0,objoff_34(a1)
 
+
    cmpi.b  #ObjID_LauncherSpring,id(a1) ; is it obj85 (CNZ pressure spring)?
    bne.s   + ; if not, branch
    move.b  objoff_36(a1),d0
    move.b  objoff_37(a1),objoff_36(a1)
    move.b  d0,objoff_37(a1)
 
+
    lea next_object(a1),a1 ; look at next object ; a1=object
    dbf d1,swap_loop_objects ; loop
 
 
    lea (MainCharacter).w,a1 ; a1=character
    move.b  #ObjID_Shield,(Sonic_Shield+id).w ; load Obj38 (shield) at $FFFFD180
    move.w  a1,(Sonic_Shield+parent).w
    move.b  #ObjID_InvStars,(Sonic_InvincibilityStars+id).w ; load Obj35 (invincibility stars) at $FFFFD200
    move.w  a1,(Sonic_InvincibilityStars+parent).w
    btst    #2,status(a1)   ; is Sonic spinning?
    bne.s   +       ; if yes, branch
    move.b  #$13,y_radius(a1)   ; set to standing height
    move.b  #9,x_radius(a1)
+
    btst    #3,status(a1)   ; is Sonic on an object?
    beq.s   +       ; if not, branch
    moveq   #0,d0
    move.b  interact(a1),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a2   ; a2=object
    bclr    #4,status(a2)
    bset    #3,status(a2)
 
+
    lea (Sidekick).w,a1 ; a1=character
    move.b  #ObjID_Shield,(Tails_Shield+id).w ; load Obj38 (shield) at $FFFFD1C0
    move.w  a1,(Tails_Shield+parent).w
    move.b  #ObjID_InvStars,(Tails_InvincibilityStars+id).w ; load Obj35 (invincibility) at $FFFFD300
    move.w  a1,(Tails_InvincibilityStars+parent).w
    btst    #2,status(a1)   ; is Tails spinning?
    bne.s   +       ; if yes, branch
    move.b  #$F,y_radius(a1)    ; set to standing height
    move.b  #9,x_radius(a1)
 
+
    btst    #3,status(a1)   ; is Tails on an object?
    beq.s   +       ; if not, branch
    moveq   #0,d0
    move.b  interact(a1),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a2   ; a2=object
    bclr    #3,status(a2)
    bset    #4,status(a2)
 
+
    move.b  #$40,(Teleport_timer).w
    move.b  #1,(Teleport_flag).w
    move.w  #SndID_Teleport,d0
    jmp (PlayMusic).l
; ===========================================================================
; Table listing all the addresses for players 1 and 2 that need to be swapped
; when a teleport monitor is destroyed
;byte_12C52:
teleport_swap_table:
    dc.w MainCharacter+x_pos,   Sidekick+x_pos,         $1B
    dc.w Camera_X_pos_last,     Camera_X_pos_last_P2,         0
    dc.w Obj_respawn_index,     Obj_respawn_index_P2,         0
    dc.w Obj_load_addr_right,   Obj_load_addr_2,          3
    dc.w Sonic_top_speed,       Tails_top_speed,          2
    dc.w Ring_start_addr,       Ring_start_addr_P2,       1
    dc.w CNZ_Visible_bumpers_start, CNZ_Visible_bumpers_start_P2,  3
    dc.w Camera_X_pos,      Camera_X_pos_P2,         $F
    dc.w Camera_X_pos_coarse,   Camera_X_pos_coarse_P2,       0
    dc.w Camera_Min_X_pos,      Tails_Min_X_pos,          3
    dc.w Horiz_scroll_delay_val,    Horiz_scroll_delay_val_P2,    1
    dc.w Camera_Y_pos_bias,     Camera_Y_pos_bias_P2,         0
    dc.w Horiz_block_crossed_flag,  Horiz_block_crossed_flag_P2,      3
    dc.w Scroll_flags,      Scroll_flags_P2,          3
    dc.w Camera_RAM_copy,       Camera_P2_copy,          $F
    dc.w Scroll_flags_copy,     Scroll_flags_copy_P2,         3
    dc.w Camera_X_pos_diff,     Camera_X_pos_diff_P2,         1
    dc.w Sonic_Pos_Record_Buf,  Tails_Pos_Record_Buf,       $7F
teleport_swap_table_end:
; ===========================================================================
; ---------------------------------------------------------------------------
; '?' Monitor
; doesn't actually do anything other than increase the player's monitor score
; ---------------------------------------------------------------------------
qmark_monitor:
    addq.w  #1,(a2)
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Holds icon in place for a while, then destroys it
; ---------------------------------------------------------------------------
;loc_12CC2:
Obj2E_Wait:
    subq.w  #1,anim_frame_duration(a0)
    bmi.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
; animation script
; off_12CCE:
Ani_obj26:  offsetTable
        offsetTableEntry.w Ani_obj26_Static     ;  0
        offsetTableEntry.w Ani_obj26_Sonic      ;  1
        offsetTableEntry.w Ani_obj26_Tails      ;  2
        offsetTableEntry.w Ani_obj26_Eggman     ;  3
        offsetTableEntry.w Ani_obj26_Ring       ;  4
        offsetTableEntry.w Ani_obj26_Shoes      ;  5
        offsetTableEntry.w Ani_obj26_Shield     ;  6
        offsetTableEntry.w Ani_obj26_Invincibility  ;  7
        offsetTableEntry.w Ani_obj26_Teleport       ;  8
        offsetTableEntry.w Ani_obj26_QuestionMark   ;  9
        offsetTableEntry.w Ani_obj26_Broken     ; $A
; byte_12CE4:
Ani_obj26_Static:
    dc.b    $01 ; duration
    dc.b    $00 ; frame number (which sprite table to use)
    dc.b    $01 ; frame number
    dc.b    $FF ; terminator
; byte_12CE8:
Ani_obj26_Sonic:
    dc.b   1,  0,  2,  2,  1,  2,  2,$FF
; byte_12CF0:
Ani_obj26_Tails:
    dc.b   1,  0,  3,  3,  1,  3,  3,$FF
; byte_12CF8:
Ani_obj26_Eggman:
    dc.b   1,  0,  4,  4,  1,  4,  4,$FF
; byte_12D00:
Ani_obj26_Ring:
    dc.b   1,  0,  5,  5,  1,  5,  5,$FF
; byte_12D08:
Ani_obj26_Shoes:
    dc.b   1,  0,  6,  6,  1,  6,  6,$FF
; byte_12D10:
Ani_obj26_Shield:
    dc.b   1,  0,  7,  7,  1,  7,  7,$FF
; byte_12D18:
Ani_obj26_Invincibility:
    dc.b   1,  0,  8,  8,  1,  8,  8,$FF
; byte_12D20:
Ani_obj26_Teleport:
    dc.b   1,  0,  9,  9,  1,  9,  9,$FF
; byte_12D28:
Ani_obj26_QuestionMark:
    dc.b   1,  0, $A, $A,  1, $A, $A,$FF
; byte_12D30:
Ani_obj26_Broken:
    dc.b   2,  0,  1, $B,$FE,  1
    even
; ---------------------------------------------------------------------------------
; Sprite Mappings - Sprite table for monitor and monitor contents (26, ??)
; ---------------------------------------------------------------------------------
; MapUnc_12D36: MapUnc_obj26:
Obj26_MapUnc_12D36: BINCLUDE "mappings/sprite/obj26.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ----------------------------------------------------------------------------
; Object 0E - Flashing stars from intro
; ----------------------------------------------------------------------------
; Sprite_12E18:
Obj0E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0E_Index(pc,d0.w),d1
    jmp Obj0E_Index(pc,d1.w)
; ===========================================================================
; off_12E26: Obj0E_States:
Obj0E_Index:    offsetTable
        offsetTableEntry.w Obj0E_Init   ;   0
        offsetTableEntry.w Obj0E_Sonic  ;   2
        offsetTableEntry.w Obj0E_Tails  ;   4
        offsetTableEntry.w Obj0E_LogoTop    ;   6
        offsetTableEntry.w Obj0E_LargeStar  ;   8
        offsetTableEntry.w Obj0E_SonicHand  ;  $A
        offsetTableEntry.w Obj0E_SmallStar  ;  $C
        offsetTableEntry.w Obj0E_SkyPiece   ;  $E
        offsetTableEntry.w Obj0E_TailsHand  ; $10
; ===========================================================================
; loc_12E38:
Obj0E_Init:
    addq.b  #2,routine(a0)  ; useless, because it's overwritten with the subtype below
    move.l  #Obj0E_MapUnc_136A8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_TitleSprites,0,0),art_tile(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),routine(a0)
    bra.s   Obj0E
; ===========================================================================
 
Obj0E_Sonic:
    addq.w  #1,objoff_34(a0)
    cmpi.w  #$120,objoff_34(a0)
    bhs.s   +
    bsr.w   TitleScreen_SetFinalState
+
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_12E76(pc,d0.w),d1
    jmp off_12E76(pc,d1.w)
; ===========================================================================
off_12E76:  offsetTable
        offsetTableEntry.w Obj0E_Sonic_Init ;   0
        offsetTableEntry.w loc_12EC2    ;   2
        offsetTableEntry.w loc_12EE8    ;   4
        offsetTableEntry.w loc_12F18    ;   6
        offsetTableEntry.w loc_12F52    ;   8
        offsetTableEntry.w Obj0E_Sonic_LastFrame    ;  $A
        offsetTableEntry.w loc_12F7C    ;  $C
        offsetTableEntry.w loc_12F9A    ;  $E
        offsetTableEntry.w loc_12FD6    ; $10
        offsetTableEntry.w loc_13014    ; $12
; ===========================================================================
; spawn more stars
Obj0E_Sonic_Init:
    addq.b  #2,routine_secondary(a0)
    move.b  #5,mapping_frame(a0)
    move.w  #$110,x_pixel(a0)
    move.w  #$E0,y_pixel(a0)
    lea (IntroLargeStar).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro stars) at $FFFFB0C0
    move.b  #8,subtype(a1)              ; large star
    lea (IntroEmblemTop).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro stars) at $FFFFD140
    move.b  #6,subtype(a1)              ; logo top
    moveq   #SndID_Sparkle,d0
    jmpto   (PlaySound).l, JmpTo4_PlaySound
; ===========================================================================
 
loc_12EC2:
    cmpi.w  #$38,objoff_34(a0)
    bhs.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    lea (TitleScreenPaletteChanger3).w,a1
    move.b  #ObjID_TtlScrPalChanger,id(a1) ; load objC9 (palette change)
    move.b  #0,subtype(a1)
    st.b    objoff_30(a0)
    moveq   #MusID_Title,d0 ; title music
    jmpto   (PlayMusic).l, JmpTo4_PlayMusic
; ===========================================================================
 
loc_12EE8:
    cmpi.w  #$80,objoff_34(a0)
    bhs.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    lea (Pal_133EC).l,a1
    lea (Normal_palette).w,a2
 
    moveq   #$F,d6
-   move.w  (a1)+,(a2)+
    dbf d6,-
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_12F08:
    lea (IntroSmallStar1).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB180
    move.b  #$E,subtype(a1)             ; piece of sky
    rts
; End of function sub_12F08
 
; ===========================================================================
 
loc_12F18:
    moveq   #word_13046_end-word_13046+4,d2
    lea (word_13046).l,a1
 
loc_12F20:
    move.w  objoff_2A(a0),d0
    addq.w  #1,d0
    move.w  d0,objoff_2A(a0)
    andi.w  #3,d0
    bne.s   +
    move.w  objoff_2C(a0),d1
    addq.w  #4,d1
    cmp.w   d2,d1
    bhs.w   loc_1310A
    move.w  d1,objoff_2C(a0)
    move.l  -4(a1,d1.w),d0
    move.w  d0,y_pixel(a0)
    swap    d0
    move.w  d0,x_pixel(a0)
+
    bra.w   DisplaySprite
; ===========================================================================
 
loc_12F52:
    lea (Ani_obj0E).l,a1
    bsr.w   AnimateSprite
    bra.w   DisplaySprite
; ===========================================================================
 
Obj0E_Sonic_LastFrame:
    addq.b  #2,routine_secondary(a0)
    move.b  #$12,mapping_frame(a0)
    lea (IntroSonicHand).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB1C0
    move.b  #$A,subtype(a1)             ; Sonic's hand
    bra.w   DisplaySprite
; ===========================================================================
 
loc_12F7C:
    cmpi.w  #$C0,objoff_34(a0)
    blo.s   +
    addq.b  #2,routine_secondary(a0)
    lea (IntroTails).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB080
    move.b  #4,subtype(a1)              ; Tails
+
    bra.w   DisplaySprite
; ===========================================================================
 
loc_12F9A:
    cmpi.w  #$120,objoff_34(a0)
    blo.s   +
    addq.b  #2,routine_secondary(a0)
    clr.w   objoff_2C(a0)
    st  objoff_2F(a0)
    lea (Normal_palette_line3).w,a1
    move.w  #$EEE,d0
 
    moveq   #$F,d6
-   move.w  d0,(a1)+
    dbf d6,-
 
    lea (TitleScreenPaletteChanger2).w,a1
    move.b  #ObjID_TtlScrPalChanger,id(a1) ; load objC9 (palette change handler) at $FFFFB240
    move.b  #2,subtype(a1)
    move.b  #ObjID_TitleMenu,(TitleScreenMenu+id).w ; load Obj0F (title screen menu) at $FFFFB400
+
    bra.w   DisplaySprite
; ===========================================================================
 
loc_12FD6:
    btst    #6,(Graphics_Flags).w
    beq.s   +
    cmpi.w  #$190,objoff_34(a0)
    beq.s   ++
    bra.w   DisplaySprite
; ===========================================================================
+
    cmpi.w  #$1D0,objoff_34(a0)
    beq.s   +
    bra.w   DisplaySprite
; ===========================================================================
+
    lea (IntroSmallStar2).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB440
    move.b  #$C,subtype(a1)             ; small star
    addq.b  #2,routine_secondary(a0)
    lea (IntroSmallStar1).w,a1
    bsr.w   DeleteObject2 ; delete object at $FFFFB180
    bra.w   DisplaySprite
; ===========================================================================
 
loc_13014:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    bne.s   ++
    move.w  objoff_2C(a0),d0
    addq.w  #2,d0
    cmpi.w  #CyclingPal_TitleStar_End-CyclingPal_TitleStar,d0
    blo.s   +
    moveq   #0,d0
+
    move.w  d0,objoff_2C(a0)
    move.w  CyclingPal_TitleStar(pc,d0.w),(Normal_palette_line3+$A).w
+
    bra.w   DisplaySprite
; ===========================================================================
; word_1303A:
CyclingPal_TitleStar:
    binclude "art/palettes/Title Star Cycle.bin"
CyclingPal_TitleStar_End
 
word_13046:
    dc.w  $108, $D0
    dc.w  $100, $C0 ; 2
    dc.w   $F8, $B0 ; 4
    dc.w   $F6, $A6 ; 6
    dc.w   $FA, $9E ; 8
    dc.w  $100, $9A ; $A
    dc.w  $104, $99 ; $C
    dc.w  $108, $98 ; $E
word_13046_end
; ===========================================================================
 
Obj0E_Tails:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_13074(pc,d0.w),d1
    jmp off_13074(pc,d1.w)
; ===========================================================================
off_13074:  offsetTable
        offsetTableEntry.w Obj0E_Tails_Init         ; 0
        offsetTableEntry.w loc_13096            ; 2
        offsetTableEntry.w loc_12F52            ; 4
        offsetTableEntry.w loc_130A2            ; 6
        offsetTableEntry.w BranchTo10_DisplaySprite ; 8
; ===========================================================================
 
Obj0E_Tails_Init:
    addq.b  #2,routine_secondary(a0)
    move.w  #$D8,x_pixel(a0)
    move.w  #$D8,y_pixel(a0)
    move.b  #1,anim(a0)
    rts
; ===========================================================================
 
loc_13096:
    moveq   #word_130B8_end-word_130B8+4,d2
    lea (word_130B8).l,a1
    bra.w   loc_12F20
; ===========================================================================
 
loc_130A2:
    addq.b  #2,routine_secondary(a0)
    lea (IntroTailsHand).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB200
    move.b  #$10,subtype(a1)            ; Tails' hand
 
BranchTo10_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
word_130B8:
    dc.w   $D7,$C8
    dc.w   $D3,$B8  ; 2
    dc.w   $CE,$AC  ; 4
    dc.w   $CC,$A6  ; 6
    dc.w   $CA,$A2  ; 8
    dc.w   $C9,$A1  ; $A
    dc.w   $C8,$A0  ; $C
word_130B8_end
; ===========================================================================
 
Obj0E_LogoTop:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_130E2(pc,d0.w),d1
    jmp off_130E2(pc,d1.w)
; ===========================================================================
off_130E2:  offsetTable
        offsetTableEntry.w Obj0E_LogoTop_Init           ; 0
        offsetTableEntry.w BranchTo11_DisplaySprite ; 2
; ===========================================================================
 
Obj0E_LogoTop_Init:
    move.b  #$B,mapping_frame(a0)
    tst.b   (Graphics_Flags).w
    bmi.s   +
    move.b  #$A,mapping_frame(a0)
+
    move.b  #2,priority(a0)
    move.w  #$120,x_pixel(a0)
    move.w  #$E8,y_pixel(a0)
 
loc_1310A:
    addq.b  #2,routine_secondary(a0)
 
BranchTo11_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
 
Obj0E_SkyPiece:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_13120(pc,d0.w),d1
    jmp off_13120(pc,d1.w)
; ===========================================================================
off_13120:  offsetTable
        offsetTableEntry.w Obj0E_SkyPiece_Init          ; 0
        offsetTableEntry.w BranchTo12_DisplaySprite ; 2
; ===========================================================================
 
Obj0E_SkyPiece_Init:
    addq.b  #2,routine_secondary(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    move.b  #$11,mapping_frame(a0)
    move.b  #2,priority(a0)
    move.w  #$100,x_pixel(a0)
    move.w  #$F0,y_pixel(a0)
 
BranchTo12_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
 
Obj0E_LargeStar:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_13158(pc,d0.w),d1
    jmp off_13158(pc,d1.w)
; ===========================================================================
off_13158:  offsetTable
        offsetTableEntry.w Obj0E_LargeStar_Init ; 0
        offsetTableEntry.w loc_12F52    ; 2
        offsetTableEntry.w loc_13190    ; 4
        offsetTableEntry.w loc_1319E    ; 6
; ===========================================================================
 
Obj0E_LargeStar_Init:
    addq.b  #2,routine_secondary(a0)
    move.b  #$C,mapping_frame(a0)
    ori.w   #high_priority,art_tile(a0)
    move.b  #2,anim(a0)
    move.b  #1,priority(a0)
    move.w  #$100,x_pixel(a0)
    move.w  #$A8,y_pixel(a0)
    move.w  #4,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_13190:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    rts
; ===========================================================================
 
loc_1319E:
    move.b  #2,routine_secondary(a0)
    move.b  #0,anim_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    move.w  #6,objoff_2A(a0)
    move.w  objoff_2C(a0),d0
    addq.w  #4,d0
    cmpi.w  #word_131DC_end-word_131DC+4,d0
    bhs.w   DeleteObject
    move.w  d0,objoff_2C(a0)
    move.l  word_131DC-4(pc,d0.w),d0
    move.w  d0,y_pixel(a0)
    swap    d0
    move.w  d0,x_pixel(a0)
    moveq   #SndID_Sparkle,d0 ; play intro sparkle sound
    jmpto   (PlaySound).l, JmpTo4_PlaySound
; ===========================================================================
; unknown
word_131DC:
    dc.w   $DA, $F2
    dc.w  $170, $F8 ; 2
    dc.w  $132,$131 ; 4
    dc.w  $19E, $A2 ; 6
    dc.w   $C0, $E3 ; 8
    dc.w  $180, $E0 ; $A
    dc.w  $10D,$13B ; $C
    dc.w   $C0, $AB ; $E
    dc.w  $165, $107    ; $10
word_131DC_end
; ===========================================================================
 
Obj0E_SonicHand:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_1320E(pc,d0.w),d1
    jmp off_1320E(pc,d1.w)
; ===========================================================================
off_1320E:  offsetTable
        offsetTableEntry.w Obj0E_SonicHand_Init         ; 0
        offsetTableEntry.w loc_13234            ; 2
        offsetTableEntry.w BranchTo13_DisplaySprite ; 4
; ===========================================================================
 
Obj0E_SonicHand_Init:
    addq.b  #2,routine_secondary(a0)
    move.b  #9,mapping_frame(a0)
    move.b  #3,priority(a0)
    move.w  #$145,x_pixel(a0)
    move.w  #$BF,y_pixel(a0)
 
BranchTo13_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
 
loc_13234:
    moveq   #word_13240_end-word_13240+4,d2
    lea (word_13240).l,a1
    bra.w   loc_12F20
; ===========================================================================
word_13240:
    dc.w  $143, $C1
    dc.w  $140, $C2 ; 2
    dc.w  $141, $C1 ; 4
word_13240_end
; ===========================================================================
 
Obj0E_TailsHand:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_1325A(pc,d0.w),d1
    jmp off_1325A(pc,d1.w)
; ===========================================================================
off_1325A:  offsetTable
        offsetTableEntry.w Obj0E_TailsHand_Init         ; 0
        offsetTableEntry.w loc_13280            ; 2
        offsetTableEntry.w BranchTo14_DisplaySprite ; 4
; ===========================================================================
 
Obj0E_TailsHand_Init:
    addq.b  #2,routine_secondary(a0)
    move.b  #$13,mapping_frame(a0)
    move.b  #3,priority(a0)
    move.w  #$10F,x_pixel(a0)
    move.w  #$D5,y_pixel(a0)
 
BranchTo14_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
 
loc_13280:
    moveq   #word_1328C_end-word_1328C+4,d2
    lea (word_1328C).l,a1
    bra.w   loc_12F20
; ===========================================================================
word_1328C:
    dc.w  $10C, $D0
    dc.w  $10D, $D1 ; 2
word_1328C_end
; ===========================================================================
 
Obj0E_SmallStar:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_132A2(pc,d0.w),d1
    jmp off_132A2(pc,d1.w)
; ===========================================================================
off_132A2:  offsetTable
        offsetTableEntry.w Obj0E_SmallStar_Init ; 0
        offsetTableEntry.w loc_132D2    ; 2
; ===========================================================================
 
Obj0E_SmallStar_Init:
    addq.b  #2,routine_secondary(a0)
    move.b  #$C,mapping_frame(a0)
    move.b  #5,priority(a0)
    move.w  #$170,x_pixel(a0)
    move.w  #$80,y_pixel(a0)
    move.b  #3,anim(a0)
    move.w  #$8C,objoff_2A(a0)
    bra.w   DisplaySprite
; ===========================================================================
 
loc_132D2:
    subq.w  #1,objoff_2A(a0)
    bmi.w   DeleteObject
    subq.w  #2,x_pixel(a0)
    addq.w  #1,y_pixel(a0)
    lea (Ani_obj0E).l,a1
    bsr.w   AnimateSprite
    bra.w   DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C9 - "Palette changing handler" from title screen
; ----------------------------------------------------------------------------
ttlscrpalchanger_fadein_time_left = objoff_30
ttlscrpalchanger_fadein_time = objoff_31
ttlscrpalchanger_fadein_amount = objoff_32
ttlscrpalchanger_start_offset = objoff_34
ttlscrpalchanger_length = objoff_36
ttlscrpalchanger_codeptr = objoff_3A
 
; Sprite_132F0:
ObjC9:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC9_Index(pc,d0.w),d1
    jmp ObjC9_Index(pc,d1.w)
; ===========================================================================
ObjC9_Index:    offsetTable
        offsetTableEntry.w ObjC9_Init   ; 0
        offsetTableEntry.w ObjC9_Main   ; 2
; ===========================================================================
 
ObjC9_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lea (PaletteChangerDataIndex).l,a1
    adda.w  (a1,d0.w),a1
    move.l  (a1)+,ttlscrpalchanger_codeptr(a0)
    movea.l (a1)+,a2
    move.b  (a1)+,d0
    move.w  d0,ttlscrpalchanger_start_offset(a0)
    lea (Target_palette).w,a3
    adda.w  d0,a3
    move.b  (a1)+,d0
    move.w  d0,ttlscrpalchanger_length(a0)
 
-   move.w  (a2)+,(a3)+
    dbf d0,-
 
    move.b  (a1)+,d0
    move.b  d0,ttlscrpalchanger_fadein_time_left(a0)
    move.b  d0,ttlscrpalchanger_fadein_time(a0)
    move.b  (a1)+,ttlscrpalchanger_fadein_amount(a0)
    rts
; ===========================================================================
 
ObjC9_Main:
    subq.b  #1,ttlscrpalchanger_fadein_time_left(a0)
    bpl.s   +
    move.b  ttlscrpalchanger_fadein_time(a0),ttlscrpalchanger_fadein_time_left(a0)
    subq.b  #1,ttlscrpalchanger_fadein_amount(a0)
    bmi.w   DeleteObject
    movea.l ttlscrpalchanger_codeptr(a0),a2
    movea.l a0,a3
    move.w  ttlscrpalchanger_length(a0),d0
    move.w  ttlscrpalchanger_start_offset(a0),d1
    lea (Normal_palette).w,a0
    adda.w  d1,a0
    lea (Target_palette).w,a1
    adda.w  d1,a1
 
-   jsr (a2)    ; dynamic call! to Pal_FadeFromBlack.UpdateColour, loc_1344C, or loc_1348A, assuming the PaletteChangerData pointers haven't been changed
    dbf d0,-
 
    movea.l a3,a0
+
    rts
; ===========================================================================
; off_1337C:
PaletteChangerDataIndex: offsetTable
    offsetTableEntry.w off_1338C    ;  0
    offsetTableEntry.w off_13398    ;  2
    offsetTableEntry.w off_133A4    ;  4
    offsetTableEntry.w off_133B0    ;  6
    offsetTableEntry.w off_133BC    ;  8
    offsetTableEntry.w off_133C8    ; $A
    offsetTableEntry.w off_133D4    ; $C
    offsetTableEntry.w off_133E0    ; $E
 
C9PalInfo macro codeptr,dataptr,loadtoOffset,length,fadeinTime,fadeinAmount
    dc.l codeptr, dataptr
    dc.b loadtoOffset, length, fadeinTime, fadeinAmount
    endm
 
off_1338C:  C9PalInfo Pal_FadeFromBlack.UpdateColour, Pal_1342C, $60, $F,2,$15
off_13398:  C9PalInfo                      loc_1344C, Pal_1340C, $40, $F,4,7
off_133A4:  C9PalInfo                      loc_1344C,  Pal_AD1E,   0, $F,8,7
off_133B0:  C9PalInfo                      loc_1348A,  Pal_AD1E,   0, $F,8,7
off_133BC:  C9PalInfo                      loc_1344C,  Pal_AC7E,   0,$1F,4,7
off_133C8:  C9PalInfo                      loc_1344C,  Pal_ACDE, $40,$1F,4,7
off_133D4:  C9PalInfo                      loc_1344C,  Pal_AD3E,   0, $F,4,7
off_133E0:  C9PalInfo                      loc_1344C,  Pal_AC9E,   0,$1F,4,7
 
Pal_133EC:  BINCLUDE "art/palettes/Title Sonic.bin"
Pal_1340C:  BINCLUDE "art/palettes/Title Background.bin"
Pal_1342C:  BINCLUDE "art/palettes/Title Emblem.bin"
 
; ===========================================================================
 
loc_1344C:
 
    move.b  (a1)+,d2
    andi.b  #$E,d2
    move.b  (a0),d3
    cmp.b   d2,d3
    bls.s   loc_1345C
    subq.b  #2,d3
    move.b  d3,(a0)
 
loc_1345C:
    addq.w  #1,a0
    move.b  (a1)+,d2
    move.b  d2,d3
    andi.b  #$E0,d2
    andi.b  #$E,d3
    move.b  (a0),d4
    move.b  d4,d5
    andi.b  #$E0,d4
    andi.b  #$E,d5
    cmp.b   d2,d4
    bls.s   loc_1347E
    subi.b  #$20,d4
 
loc_1347E:
    cmp.b   d3,d5
    bls.s   loc_13484
    subq.b  #2,d5
 
loc_13484:
    or.b    d4,d5
    move.b  d5,(a0)+
    rts
; ===========================================================================
 
loc_1348A:
    moveq   #$E,d2
    move.b  (a0),d3
    and.b   d2,d3
    cmp.b   d2,d3
    bhs.s   loc_13498
    addq.b  #2,d3
    move.b  d3,(a0)
 
loc_13498:
    addq.w  #1,a0
    move.b  (a0),d3
    move.b  d3,d4
    andi.b  #$E0,d3
    andi.b  #$E,d4
    cmpi.b  #-$20,d3
    bhs.s   loc_134B0
    addi.b  #$20,d3
 
loc_134B0:
    cmp.b   d2,d4
    bhs.s   loc_134B6
    addq.b  #2,d4
 
loc_134B6:
    or.b    d3,d4
    move.b  d4,(a0)+
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
TitleScreen_SetFinalState:
    tst.b   objoff_2F(a0)
    bne.w   +   ; rts
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask|button_B_mask|button_C_mask|button_A_mask,(Ctrl_1_Press).w
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask|button_B_mask|button_C_mask|button_A_mask,(Ctrl_2_Press).w
    andi.b  #button_start_mask,d0
    beq.w   +   ; rts
    st.b    objoff_2F(a0)
    move.b  #$10,routine_secondary(a0)
    move.b  #$12,mapping_frame(a0)
    move.w  #$108,x_pixel(a0)
    move.w  #$98,y_pixel(a0)
    lea (IntroSonicHand).w,a1
    bsr.w   TitleScreen_InitSprite
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E (flashing intro star) at $FFFFB1C0
    move.b  #$A,routine(a1)             ; Sonic's hand
    move.b  #2,priority(a1)
    move.b  #9,mapping_frame(a1)
    move.b  #4,routine_secondary(a1)
    move.w  #$141,x_pixel(a1)
    move.w  #$C1,y_pixel(a1)
    lea (IntroTails).w,a1
    bsr.w   TitleScreen_InitSprite
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E
    move.b  #4,routine(a1)              ; Tails
    move.b  #4,mapping_frame(a1)
    move.b  #6,routine_secondary(a1)
    move.b  #3,priority(a1)
    move.w  #$C8,x_pixel(a1)
    move.w  #$A0,y_pixel(a1)
    lea (IntroTailsHand).w,a1
    bsr.w   TitleScreen_InitSprite
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E
    move.b  #$10,routine(a1)            ; Tails' hand
    move.b  #2,priority(a1)
    move.b  #$13,mapping_frame(a1)
    move.b  #4,routine_secondary(a1)
    move.w  #$10D,x_pixel(a1)
    move.w  #$D1,y_pixel(a1)
    lea (IntroEmblemTop).w,a1
    move.b  #ObjID_IntroStars,id(a1) ; load obj0E
    move.b  #6,subtype(a1)              ; logo top
    bsr.w   sub_12F08
    move.b  #ObjID_TitleMenu,(TitleScreenMenu+id).w ; load Obj0F (title screen menu) at $FFFFB400
    lea (TitleScreenPaletteChanger).w,a1
    bsr.w   DeleteObject2
    lea_    Pal_1342C,a1
    lea (Normal_palette_line4).w,a2
 
    moveq   #7,d6
-   move.l  (a1)+,(a2)+
    dbf d6,-
 
    lea_    Pal_1340C,a1
    lea (Normal_palette_line3).w,a2
 
    moveq   #7,d6
-   move.l  (a1)+,(a2)+
    dbf d6,-
 
    lea_    Pal_133EC,a1
    lea (Normal_palette).w,a2
 
    moveq   #7,d6
-   move.l  (a1)+,(a2)+
    dbf d6,-
 
    tst.b   objoff_30(a0)
    bne.s   +   ; rts
    moveq   #MusID_Title,d0 ; title music
    jsrto   (PlayMusic).l, JmpTo4_PlayMusic
+
    rts
; End of function sub_134BC
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
;sub_135EA:
TitleScreen_InitSprite:
 
    move.l  #Obj0E_MapUnc_136A8,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_TitleSprites,0,0),art_tile(a1)
    move.b  #4,priority(a1)
    rts
; End of function TitleScreen_InitSprite
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 0F - Title screen menu
; ----------------------------------------------------------------------------
; Sprite_13600:
Obj0F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0F_Index(pc,d0.w),d1
    jsr Obj0F_Index(pc,d1.w)
    bra.w   DisplaySprite
; ===========================================================================
; off_13612: Obj0F_States:
Obj0F_Index:    offsetTable
        offsetTableEntry.w Obj0F_Init   ; 0
        offsetTableEntry.w Obj0F_Main   ; 2
; ===========================================================================
; loc_13616:
Obj0F_Init:
    addq.b  #2,routine(a0) ; => Obj0F_Main
    move.w  #$128,x_pixel(a0)
    move.w  #$14C,y_pixel(a0)
    move.l  #Obj0F_MapUnc_13B70,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    andi.b  #1,(Title_screen_option).w
    move.b  (Title_screen_option).w,mapping_frame(a0)
 
; loc_13644:
Obj0F_Main:
    moveq   #0,d2
    move.b  (Title_screen_option).w,d2
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    btst    #button_up,d0
    beq.s   +
    subq.b  #1,d2
    bcc.s   +
    move.b  #2,d2
+
    btst    #button_down,d0
    beq.s   +
    addq.b  #1,d2
    cmpi.b  #3,d2
    blo.s   +
    moveq   #0,d2
+
    move.b  d2,mapping_frame(a0)
    move.b  d2,(Title_screen_option).w
    andi.b  #button_up_mask|button_down_mask,d0
    beq.s   +   ; rts
    moveq   #SndID_Blip,d0 ; selection blip sound
    jsrto   (PlaySound).l, JmpTo4_PlaySound
+
    rts
; ===========================================================================
; animation script
; off_13686:
Ani_obj0E:  offsetTable
        offsetTableEntry.w byte_1368E   ; 0
        offsetTableEntry.w byte_13694   ; 1
        offsetTableEntry.w byte_1369C   ; 2
        offsetTableEntry.w byte_136A4   ; 3
byte_1368E:
    dc.b   1
    dc.b   5    ; 1
    dc.b   6    ; 2
    dc.b   7    ; 3
    dc.b   8    ; 4
    dc.b $FA    ; 5
    even
byte_13694:
    dc.b   1
    dc.b   0    ; 1
    dc.b   1    ; 2
    dc.b   2    ; 3
    dc.b   3    ; 4
    dc.b   4    ; 5
    dc.b $FA    ; 6
    even
byte_1369C:
    dc.b   1
    dc.b  $C    ; 1
    dc.b  $D    ; 2
    dc.b  $E    ; 3
    dc.b  $D    ; 4
    dc.b  $C    ; 5
    dc.b $FA    ; 6
    even
byte_136A4:
    dc.b   3
    dc.b  $C    ; 1
    dc.b  $F    ; 2
    dc.b $FF    ; 3
    even
; -----------------------------------------------------------------------------
; Sprite Mappings - Flashing stars from intro (Obj0E)
; -----------------------------------------------------------------------------
Obj0E_MapUnc_136A8: BINCLUDE "mappings/sprite/obj0E.bin"
; -----------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------
Obj0F_MapUnc_13B70: BINCLUDE "mappings/sprite/obj0F.bin"
 
    if ~~removeJmpTos
JmpTo4_PlaySound 
    jmp (PlaySound).l
JmpTo4_PlayMusic 
    jmp (PlayMusic).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 34 - level title card (screen with red, yellow, and blue)
; ----------------------------------------------------------------------------
titlecard_x_target     = objoff_30  ; the X position the object will reach
titlecard_x_source     = objoff_32  ; the X position the object starts from and will end at
titlecard_location     = objoff_34  ; point up to which titlecard is drawn
titlecard_vram_dest    = objoff_36  ; target of VRAM write
titlecard_vram_dest_2P = objoff_38  ; target of VRAM write
titlecard_split_point  = objoff_3A  ; point to split drawing for yellow and red portions
titlecard_leaveflag    = objoff_3E  ; whether or not titlecard is leaving screen
; Sprite_13C48:
Obj34: ; (note: screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj34_Index(pc,d0.w),d1
    jmp Obj34_Index(pc,d1.w)
; ===========================================================================
Obj34_Index:    offsetTable
        offsetTableEntry.w Obj34_Init           ;   0 - create all the title card objects
        offsetTableEntry.w Obj34_BackgroundIn       ;   2 - the background, coming in
        offsetTableEntry.w Obj34_BottomPartIn       ;   4 - the yellow part at the bottom, coming in
        offsetTableEntry.w Obj34_LeftPartIn     ;   6 - the red part on the left, coming in
        offsetTableEntry.w Obj34_ZoneName       ;   8 - the name of the zone, coming in
        offsetTableEntry.w Obj34_Zone           ;  $A - the word "ZONE", coming in
        offsetTableEntry.w Obj34_ActNumber      ;  $C - the act number, coming in
        offsetTableEntry.w Obj34_LeftPartOut        ;  $E - red part on the left, going out
        offsetTableEntry.w Obj34_BottomPartOut      ; $10 - yellow part at the bottom, going out
        offsetTableEntry.w Obj34_BackgroundOutInit  ; $12 - the background, going out (first frame)
        offsetTableEntry.w Obj34_BackgroundOut      ; $14 - the background, going out
        offsetTableEntry.w Obj34_WaitAndGoAway      ; $16 - wait and go away, used by the zone name, "ZONE" and the act number
; ===========================================================================
; loc_13C6E:
Obj34_Init:
    lea (a0),a1
    lea Obj34_TitleCardData(pc),a2
 
    moveq   #(Obj34_TitleCardData_End-Obj34_TitleCardData)/$A-1,d1
-   _move.b #ObjID_TitleCard,id(a1) ; load obj34
    move.b  (a2)+,routine(a1)
    move.l  #Obj34_MapUnc_147BA,mappings(a1)
    move.b  (a2)+,mapping_frame(a1)
    move.b  (a2)+,width_pixels(a1)
    move.b  (a2)+,anim_frame_duration(a1)
    move.w  (a2),x_pixel(a1)
    move.w  (a2)+,titlecard_x_source(a1)
    move.w  (a2)+,titlecard_x_target(a1)
    move.w  (a2)+,y_pixel(a1)
    move.b  #0,render_flags(a1)
    lea next_object(a1),a1 ; a1=object
    dbf d1,-
 
    move.w  #$26,(TitleCard_Bottom+titlecard_location).w
    clr.w   (Vscroll_Factor_FG).w
    move.w  #-$E0,(Vscroll_Factor_P2_FG).w
 
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End
 
    rts
; ===========================================================================
; This macro declares data for an object. The data includes:
; - the initial routine counter (byte)
; - the initial mapping frame (byte)
; - the width of the object (byte)
; - the number of frames before it appears on screen (byte)
; - the X position where it starts and where it will go back (word)
; - the X position to reach (word)
; - the Y position (word)
titlecardobjdata macro routine,frame,width,duration,xstart,xstop,y
    dc.b routine,frame,width,duration
    dc.w xstart,xstop,y
    endm
; word_13CD4:
Obj34_TitleCardData:
    titlecardobjdata  8,   0, $80, $1B, $240, $120, $B8 ; zone name
    titlecardobjdata $A, $11, $40, $1C,  $28, $148, $D0 ; "ZONE"
    titlecardobjdata $C, $12, $18, $1C,  $68, $188, $D0 ; act number
    titlecardobjdata  2,   0,   0,   0,    0,    0,   0 ; blue background
    titlecardobjdata  4, $15, $48,   8, $2A8, $168,$120 ; bottom yellow part
    titlecardobjdata  6, $16,   8, $15,  $80,  $F0, $F0 ; left red part
Obj34_TitleCardData_End:
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_13D10:
Obj34_Wait:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1
    bne.s   +               ; if it's not 0, branch
    move.b  #1,anim_frame_duration(a0)  ; reset to 1
    rts
; ---------------------------------------------------------------------------
+   addq.w  #4,sp   ; don't run the code after the call to this routine
    rts
; End of function Obj34_Wait
 
; ===========================================================================
; loc_13D22:
Obj34_BackgroundIn: ; the blue background (green when playing as Knuckles), coming in
    moveq   #$10,d0
    moveq   #8,d1
    tst.w   (Two_player_mode).w ; if two-player mode is on (1)
    sne d6          ; then set d6 to $FF, else set d6 to $00
    beq.s   +
    moveq   #$20,d0
    moveq   #7,d1
+
    move.w  titlecard_location(a0),d2
    cmp.w   d0,d2
    beq.s   ++  ; rts
    lsl.w   d1,d2
    move.w  #VRAM_Plane_A_Name_Table,d0
    add.w   d2,d0
    move.w  d0,titlecard_vram_dest(a0)
    tst.b   d6
    beq.s   +
    addi.w  #VRAM_Plane_A_Name_Table_2P,d2
    move.w  d2,titlecard_vram_dest_2P(a0)
+
    addq.w  #1,titlecard_location(a0)
+
    rts
; ===========================================================================
; loc_13D58:
Obj34_BottomPartIn: ; the yellow part at the bottom, coming in
    jsr Obj34_Wait(pc)
    move.w  titlecard_location(a0),d0
    bmi.w   Obj34_MoveTowardsTargetPosition
    add.w   d0,d0
    move.w  #$80*$14/2,d1       ; $14 half-cells down (for 2P mode)
    tst.w   (Two_player_mode).w
    sne d6
    bne.s   +
    add.w   d1,d1               ; double distance down for 1P mode
+
    move.w  #VRAM_Plane_A_Name_Table,d2
    add.w   d0,d2
    add.w   d1,d2
    move.w  d2,titlecard_vram_dest(a0)
    tst.b   d6
    beq.s   +
    addi.w  #VRAM_Plane_A_Name_Table_2P,d1
    add.w   d0,d1
    move.w  d1,titlecard_vram_dest_2P(a0)
+
    subq.w  #2,titlecard_location(a0)
    move.w  titlecard_location(a0),titlecard_split_point(a0)
    cmpi.w  #6,titlecard_location(a0) ; if titlecard_location(a0) is 6,
    seq titlecard_location(a0) ; then set it to $FF, else set it to $00
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
; loc_13DA6:
Obj34_LeftPartIn:   ; the red part on the left, coming in
    jsr Obj34_Wait(pc)
    tst.w   titlecard_location(a0)
    bmi.w   Obj34_MoveTowardsTargetPosition
    move.w  #VRAM_Plane_A_Name_Table,titlecard_vram_dest(a0)
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  #VRAM_Plane_A_Name_Table_2P,titlecard_vram_dest_2P(a0)
+
    addq.w  #2,titlecard_location(a0)
    move.w  titlecard_location(a0),titlecard_split_point(a0)
    cmpi.w  #$E,titlecard_location(a0)
    seq titlecard_location(a0)
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
; loc_13DDC:
Obj34_ZoneName:     ; the name of the zone, coming in
    jsr Obj34_Wait(pc)
    move.b  (Current_Zone).w,mapping_frame(a0)
    bra.s   Obj34_MoveTowardsTargetPosition
; ===========================================================================
; loc_13DE8:
Obj34_Zone:     ; the word "ZONE", coming in
    jsr Obj34_Wait(pc)
    bra.s   Obj34_MoveTowardsTargetPosition
; ===========================================================================
; loc_13DEE:
Obj34_ActNumber:    ; the act number, coming in
    jsr Obj34_Wait(pc)
    move.b  (Current_Zone).w,d0 ; get the current zone
    cmpi.b  #sky_chase_zone,d0  ; is it Sky Chase?
    beq.s   BranchTo9_DeleteObject  ; if yes, branch
    cmpi.b  #wing_fortress_zone,d0  ; is it Wing Fortress?
    beq.s   BranchTo9_DeleteObject  ; if yes, branch
    cmpi.b  #death_egg_zone,d0  ; is it Death Egg Zone?
    beq.s   BranchTo9_DeleteObject  ; if yes, branch
    move.b  (Current_Act).w,d1  ; get the current act
    addi.b  #$12,d1         ; add $12 to it (this is the index of the "1" frame in the mappings)
    cmpi.b  #metropolis_zone_2,d0   ; are we in Metropolis Zone Act 3?
    bne.s   +           ; if not, branch
    moveq   #$14,d1         ; use the "3" frame instead
+
    move.b  d1,mapping_frame(a0)    ; set the mapping frame
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_13E1C:
Obj34_MoveTowardsTargetPosition:
    moveq   #$10,d0         ; set speed
    move.w  x_pixel(a0),d1      ; get the X position
    cmp.w   titlecard_x_target(a0),d1 ; compare with target position
    beq.s   ++          ; if it reached its target position, branch
    bhi.s   +           ; if it's beyond the target position, branch
    neg.w   d0          ; negate the speed
+
    sub.w   d0,x_pixel(a0)      ; move the object
    cmpi.w  #$200,x_pixel(a0)   ; is it beyond $200?
    bhi.s   ++          ; if yes, return
+
    bra.w   DisplaySprite
; ---------------------------------------------------------------------------
+   rts
; End of function Obj34_MoveTowardsTargetPosition
 
; ===========================================================================
 
BranchTo9_DeleteObject 
    bra.w   DeleteObject
; ===========================================================================
; loc_13E42:
Obj34_LeftPartOut:  ; red part on the left, going out
    move.w  titlecard_location(a0),d0
    bpl.s   +
    move.b  #$10,TitleCard_Bottom-TitleCard_Left+routine(a0)
    clr.w   TitleCard_Bottom-TitleCard_Left+titlecard_location(a0)
    bra.s   BranchTo9_DeleteObject
; ===========================================================================
+
    add.w   d0,d0
    move.w  #VRAM_Plane_A_Name_Table,titlecard_vram_dest(a0)
    add.w   d0,titlecard_vram_dest(a0)
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  #VRAM_Plane_A_Name_Table_2P,titlecard_vram_dest_2P(a0)
    add.w   d0,titlecard_vram_dest_2P(a0)
+
    subq.w  #4,titlecard_location(a0)
    cmpi.w  #-2,titlecard_location(a0)
    bne.s   +
    clr.w   titlecard_location(a0)
+
    bra.w   loc_13EC4
; ===========================================================================
; loc_13E84:
Obj34_BottomPartOut:    ; yellow part at the bottom, going out
    move.w  titlecard_location(a0),d0
    cmpi.w  #$28,d0
    bne.s   +
    move.b  #$12,TitleCard_Background-TitleCard_Bottom+routine(a0)
    bra.s   BranchTo9_DeleteObject
; ---------------------------------------------------------------------------
+
    add.w   d0,d0
    move.w  #$80*$14/2,d1       ; $14 half-cells down (for 2P mode)
    tst.w   (Two_player_mode).w
    sne d6
    bne.s   +
    add.w   d1,d1               ; double distance down for 1P mode
+
    move.w  #VRAM_Plane_A_Name_Table,d2
    add.w   d0,d2
    add.w   d1,d2
    move.w  d2,titlecard_vram_dest(a0)
    tst.b   d6
    beq.s   +
    addi.w  #VRAM_Plane_A_Name_Table_2P,d1
    add.w   d0,d1
    move.w  d1,titlecard_vram_dest_2P(a0)
+
    addq.w  #4,titlecard_location(a0)
 
loc_13EC4:
    moveq   #$20,d0
    move.w  x_pixel(a0),d1
    cmp.w   titlecard_x_source(a0),d1
    beq.s   ++  ; rts
    bhi.s   +
    neg.w   d0
+
    sub.w   d0,x_pixel(a0)
    cmpi.w  #$200,x_pixel(a0)
    bhi.s   +   ; rts
    bra.w   DisplaySprite
; ---------------------------------------------------------------------------
+   rts
; ===========================================================================
; loc_13EE6:
Obj34_BackgroundOutInit:    ; the background, going out
    move.l  a0,-(sp)
    move.l  d7,-(sp)
    bsr.w   DeformBgLayer
    move.l  (sp)+,d7
    movea.l (sp)+,a0 ; load 0bj address
    addi_.b #2,routine(a0)
    move.w  #$F0,titlecard_location(a0)
; loc_13EFE:
Obj34_BackgroundOut:
    move.w  titlecard_location(a0),d0
    subi.w  #$20,d0
    cmpi.w  #-$30,d0
    beq.w   BranchTo9_DeleteObject
    move.w  d0,titlecard_location(a0)
    move.w  d0,titlecard_vram_dest(a0)
    rts
; ===========================================================================
; loc_13F18:
Obj34_WaitAndGoAway:
    tst.w   anim_frame_duration(a0)
    beq.s   +
    subq.w  #1,anim_frame_duration(a0)
    bra.s   +++ ; DisplaySprite
; ---------------------------------------------------------------------------
+
    moveq   #$20,d0
    move.w  x_pixel(a0),d1
    cmp.w   titlecard_x_source(a0),d1
    beq.s   Obj34_LoadStandardWaterAndAnimalArt
    bhi.s   +
    neg.w   d0
+
    sub.w   d0,x_pixel(a0)
    cmpi.w  #$200,x_pixel(a0)
    bhi.s   Obj34_LoadStandardWaterAndAnimalArt
+
    bra.w   DisplaySprite
; ===========================================================================
; loc_13F44:
Obj34_LoadStandardWaterAndAnimalArt:
    cmpa.w  #TitleCard_ZoneName,a0  ; is this the zone name object?
    bne.s   +           ; if not, just delete the title card
    moveq   #PLCID_StdWtr,d0    ; load the standard water graphics
    jsrto   (LoadPLC).l, JmpTo3_LoadPLC
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    move.b  Animal_PLCTable(pc,d0.w),d0 ; load the animal graphics for the current zone
    jsrto   (LoadPLC).l, JmpTo3_LoadPLC
+
    bra.w   DeleteObject        ; delete the title card object
; ===========================================================================
;byte_13F62:
Animal_PLCTable: zoneOrderedTable 1,1
    zoneTableEntry.b PLCID_EhzAnimals   ; $0
    zoneTableEntry.b PLCID_EhzAnimals   ; $1
    zoneTableEntry.b PLCID_EhzAnimals   ; $2
    zoneTableEntry.b PLCID_EhzAnimals   ; $3
    zoneTableEntry.b PLCID_MtzAnimals   ; $4
    zoneTableEntry.b PLCID_MtzAnimals   ; $5
    zoneTableEntry.b PLCID_WfzAnimals   ; $6
    zoneTableEntry.b PLCID_HtzAnimals   ; $7
    zoneTableEntry.b PLCID_HpzAnimals   ; $8
    zoneTableEntry.b PLCID_HpzAnimals   ; $9
    zoneTableEntry.b PLCID_OozAnimals   ; $A
    zoneTableEntry.b PLCID_MczAnimals   ; $B
    zoneTableEntry.b PLCID_CnzAnimals   ; $C
    zoneTableEntry.b PLCID_CpzAnimals   ; $D
    zoneTableEntry.b PLCID_DezAnimals   ; $E
    zoneTableEntry.b PLCID_ArzAnimals   ; $F
    zoneTableEntry.b PLCID_SczAnimals   ; $10
    zoneTableEnd
 
    dc.b PLCID_SczAnimals   ; level slot $11 (non-existent), not part of main table
    even
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 39 - Game/Time Over text
; ----------------------------------------------------------------------------
; Sprite_13F74:
Obj39: ; (screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj39_Index(pc,d0.w),d1
    jmp Obj39_Index(pc,d1.w)
; ===========================================================================
Obj39_Index:    offsetTable
        offsetTableEntry.w Obj39_Init       ; 0
        offsetTableEntry.w Obj39_SlideIn    ; 2
        offsetTableEntry.w Obj39_Wait       ; 4
; ===========================================================================
; loc_13F88:
Obj39_Init:
    tst.l   (Plc_Buffer).w
    beq.s   +
    rts     ; wait until the art is loaded
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine(a0)
    move.w  #$50,x_pixel(a0)
    btst    #0,mapping_frame(a0)
    beq.s   +
    move.w  #$1F0,x_pixel(a0)
+
    move.w  #$F0,y_pixel(a0)
    move.l  #Obj39_MapUnc_14C6C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Game_Over,0,1),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #0,render_flags(a0)
    move.b  #0,priority(a0)
; loc_13FCC:
Obj39_SlideIn:
    moveq   #$10,d1
    cmpi.w  #$120,x_pixel(a0)
    beq.s   Obj39_SetTimer
    blo.s   +
    neg.w   d1
+
    add.w   d1,x_pixel(a0)
    bra.w   DisplaySprite
; ===========================================================================
; loc_13FE2:
Obj39_SetTimer:
    move.w  #$2D0,anim_frame_duration(a0)
    addq.b  #2,routine(a0)
    rts
; ===========================================================================
; loc_13FEE:
Obj39_Wait:
    btst    #0,mapping_frame(a0)
    bne.w   Obj39_Display
    move.b  (Ctrl_1_Press).w,d0
    or.b    (Ctrl_2_Press).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    bne.s   Obj39_Dismiss
    tst.w   anim_frame_duration(a0)
    beq.s   Obj39_Dismiss
    subq.w  #1,anim_frame_duration(a0)
    bra.w   DisplaySprite
; ===========================================================================
; loc_14014:
Obj39_Dismiss:
    tst.b   (Time_Over_flag).w
    bne.s   Obj39_TimeOver
    tst.b   (Time_Over_flag_2P).w
    bne.s   Obj39_TimeOver
    move.b  #GameModeID_ContinueScreen,(Game_Mode).w ; => ContinueScreen
    tst.b   (Continue_count).w
    bne.s   Obj39_Check2PMode
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    bra.s   Obj39_Check2PMode
; ===========================================================================
; loc_14034:
Obj39_TimeOver:
    clr.l   (Saved_Timer).w
    move.w  #1,(Level_Inactive_flag).w
; loc_1403E:
Obj39_Check2PMode:
    tst.w   (Two_player_mode).w
    beq.s   Obj39_Display
 
    move.w  #0,(Level_Inactive_flag).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    move.w  #VsRSID_Act,(Results_Screen_2P).w
    tst.b   (Time_Over_flag).w
    bne.s   Obj39_Display
    tst.b   (Time_Over_flag_2P).w
    bne.s   Obj39_Display
    move.w  #1,(Game_Over_2P).w
    move.w  #VsRSID_Zone,(Results_Screen_2P).w
    jsrto   (sub_8476).l, JmpTo_sub_8476
    move.w  #-1,(a4)
    tst.b   parent+1(a0)
    beq.s   +
    addq.w  #1,a4
+
    move.b  #-2,(a4)
; BranchTo17_DisplaySprite 
Obj39_Display:
    bra.w   DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3A - End of level results screen
; ----------------------------------------------------------------------------
; Sprite_14086:
Obj3A: ; (screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3A_Index(pc,d0.w),d1
    jmp Obj3A_Index(pc,d1.w)
; ===========================================================================
; off_14094:
Obj3A_Index:    offsetTable
        offsetTableEntry.w loc_140AC                    ;   0
        offsetTableEntry.w loc_14102                    ;   2
        offsetTableEntry.w BranchTo_Obj34_MoveTowardsTargetPosition ;   4
        offsetTableEntry.w loc_14146                    ;   6
        offsetTableEntry.w loc_14168                    ;   8
        offsetTableEntry.w loc_1419C                    ;  $A
        offsetTableEntry.w loc_141AA                    ;  $C
        offsetTableEntry.w loc_1419C                    ;  $E
        offsetTableEntry.w loc_14270                    ; $10
        offsetTableEntry.w loc_142B0                    ; $12
        offsetTableEntry.w loc_142CC                    ; $14
        offsetTableEntry.w loc_1413A                    ; $16
; ===========================================================================
 
loc_140AC:
    tst.l   (Plc_Buffer).w
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    movea.l a0,a1
    lea byte_14380(pc),a2
    moveq   #7,d1
 
loc_140BC:
    _move.b id(a1),d0
    beq.s   loc_140CE
    cmpi.b  #ObjID_Results,d0
    beq.s   loc_140CE
    lea next_object(a1),a1 ; a1=object
    bra.s   loc_140BC
; ===========================================================================
 
loc_140CE:
 
    _move.b #ObjID_Results,id(a1) ; load obj3A
    move.w  (a2)+,x_pixel(a1)
    move.w  (a2)+,objoff_30(a1)
    move.w  (a2)+,y_pixel(a1)
    move.b  (a2)+,routine(a1)
    move.b  (a2)+,mapping_frame(a1)
    move.l  #Obj3A_MapUnc_14CBC,mappings(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #0,render_flags(a1)
    lea next_object(a1),a1 ; a1=object
    dbf d1,loc_140BC
 
loc_14102:
    moveq   #0,d0
    cmpi.w  #2,(Player_mode).w
    bne.s   loc_14118
    addq.w  #1,d0
    btst    #7,(Graphics_Flags).w
    beq.s   loc_14118
    addq.w  #1,d0
 
loc_14118:
 
    move.b  d0,mapping_frame(a0)
    bsr.w   Obj34_MoveTowardsTargetPosition
    move.w  x_pixel(a0),d0
    cmp.w   objoff_30(a0),d0
    bne.w   return_14138
    move.b  #$A,routine(a0)
    move.w  #$B4,anim_frame_duration(a0)
 
return_14138:
    rts
; ===========================================================================
 
loc_1413A:
    tst.w   (Perfect_rings_left).w
    bne.w   DeleteObject
 
BranchTo_Obj34_MoveTowardsTargetPosition 
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
 
loc_14146:
    move.b  (Current_Zone).w,d0
    cmpi.b  #sky_chase_zone,d0
    beq.s   loc_1415E
    cmpi.b  #wing_fortress_zone,d0
    beq.s   loc_1415E
    cmpi.b  #death_egg_zone,d0
    bne.w   Obj34_MoveTowardsTargetPosition
 
loc_1415E:
 
    move.b  #5,mapping_frame(a0)
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
 
loc_14168:
    move.b  (Current_Zone).w,d0
    cmpi.b  #sky_chase_zone,d0
    beq.w   BranchTo9_DeleteObject
    cmpi.b  #wing_fortress_zone,d0
    beq.w   BranchTo9_DeleteObject
    cmpi.b  #death_egg_zone,d0
    beq.w   BranchTo9_DeleteObject
    cmpi.b  #metropolis_zone_2,d0
    bne.s   loc_1418E
    moveq   #8,d0
    bra.s   loc_14194
; ===========================================================================
 
loc_1418E:
    move.b  (Current_Act).w,d0
    addq.b  #6,d0
 
loc_14194:
    move.b  d0,mapping_frame(a0)
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
 
loc_1419C:
    subq.w  #1,anim_frame_duration(a0)
    bne.s   BranchTo18_DisplaySprite
    addq.b  #2,routine(a0)
 
BranchTo18_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
 
loc_141AA:
    bsr.w   DisplaySprite
    move.b  #1,(Update_Bonus_score).w
    moveq   #0,d0
    tst.w   (Bonus_Countdown_1).w
    beq.s   loc_141C6
    addi.w  #10,d0
    subi.w  #10,(Bonus_Countdown_1).w
 
loc_141C6:
    tst.w   (Bonus_Countdown_2).w
    beq.s   loc_141D6
    addi.w  #10,d0
    subi.w  #10,(Bonus_Countdown_2).w
 
loc_141D6:
    tst.w   (Bonus_Countdown_3).w
    beq.s   loc_141E6
    addi.w  #10,d0
    subi.w  #10,(Bonus_Countdown_3).w
 
loc_141E6:
    add.w   d0,(Total_Bonus_Countdown).w
    tst.w   d0
    bne.s   loc_14256
    move.w  #SndID_TallyEnd,d0
    jsr (PlaySound).l
    addq.b  #2,routine(a0)
    move.w  #$B4,anim_frame_duration(a0)
    cmpi.w  #1000,(Total_Bonus_Countdown).w
    blo.s   return_14254
    move.w  #$12C,anim_frame_duration(a0)
    lea next_object(a0),a1 ; a1=object
 
loc_14214:
    _tst.b  id(a1)
    beq.s   loc_14220
    lea next_object(a1),a1 ; a1=object
    bra.s   loc_14214
; ===========================================================================
 
loc_14220:
    _move.b #ObjID_Results,id(a1) ; load obj3A (uses screen-space)
    move.b  #$12,routine(a1)
    move.w  #$188,x_pixel(a1)
    move.w  #$118,y_pixel(a1)
    move.l  #Obj3A_MapUnc_14CBC,mappings(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #0,render_flags(a1)
    move.w  #$3C,anim_frame_duration(a1)
    addq.b  #1,(Continue_count).w
 
return_14254:
 
    rts
; ===========================================================================
 
loc_14256:
    jsr (AddPoints).l
    move.b  (Vint_runcount+3).w,d0
    andi.b  #3,d0
    bne.s   return_14254
    move.w  #SndID_Blip,d0
    jmp (PlaySound).l
; ===========================================================================
 
loc_14270:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    add.b   (Current_Act).w,d0
    add.w   d0,d0
    lea LevelOrder(pc),a1
    tst.w   (Two_player_mode).w
    beq.s   loc_1428C
    lea LevelOrder_2P(pc),a1
 
loc_1428C:
    move.w  (a1,d0.w),d0
    tst.w   d0
    bpl.s   loc_1429C
    move.b  #GameModeID_SegaScreen,(Game_Mode).w ; => SegaScreen
    rts
; ===========================================================================
 
loc_1429C:
    move.w  d0,(Current_ZoneAndAct).w
    clr.b   (Last_star_pole_hit).w
    clr.b   (Last_star_pole_hit_2P).w
    move.w  #1,(Level_Inactive_flag).w
    rts
; ===========================================================================
 
loc_142B0:
    tst.w   anim_frame_duration(a0)
    beq.s   loc_142BC
    subq.w  #1,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_142BC:
    addi_.b #2,routine(a0)
    move.w  #SndID_ContinueJingle,d0
    jsr (PlaySound).l
 
loc_142CC:
    subq.w  #1,anim_frame_duration(a0)
    bpl.s   loc_142E2
    move.w  #$13,anim_frame_duration(a0)
    addq.b  #1,anim_frame(a0)
    andi.b  #1,anim_frame(a0)
 
loc_142E2:
    moveq   #$C,d0
    add.b   anim_frame(a0),d0
    move.b  d0,mapping_frame(a0)
    btst    #4,(Timer_frames+1).w
    bne.w   DisplaySprite
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; Main game level order
 
; One value per act. That value is the level/act number of the level to load when
; that act finishes.
; -------------------------------------------------------------------------------
;word_142F8:
LevelOrder: zoneOrderedTable 2,2    ; WrdArr_LevelOrder
    zoneTableEntry.w  emerald_hill_zone_act_2
    zoneTableEntry.w  chemical_plant_zone_act_1 ; 1
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 2
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 3
    zoneTableEntry.w  wood_zone_act_2       ; 4
    zoneTableEntry.w  metropolis_zone_act_1     ; 5
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 6
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 7
    zoneTableEntry.w  metropolis_zone_act_2     ; 8
    zoneTableEntry.w  metropolis_zone_act_3     ; 9
    zoneTableEntry.w  sky_chase_zone_act_1      ; 10
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 11
    zoneTableEntry.w  death_egg_zone_act_1      ; 12
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 13
    zoneTableEntry.w  hill_top_zone_act_2       ; 14
    zoneTableEntry.w  mystic_cave_zone_act_1    ; 15
    zoneTableEntry.w  hidden_palace_zone_act_2  ; 16
    zoneTableEntry.w  oil_ocean_zone_act_1      ; 17
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 18
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 19
    zoneTableEntry.w  oil_ocean_zone_act_2      ; 20
    zoneTableEntry.w  metropolis_zone_act_1     ; 21
    zoneTableEntry.w  mystic_cave_zone_act_2    ; 22
    zoneTableEntry.w  oil_ocean_zone_act_1      ; 23
    zoneTableEntry.w  casino_night_zone_act_2   ; 24
    zoneTableEntry.w  hill_top_zone_act_1       ; 25
    zoneTableEntry.w  chemical_plant_zone_act_2 ; 26
    zoneTableEntry.w  aquatic_ruin_zone_act_1   ; 27
    zoneTableEntry.w  $FFFF             ; 28
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 29
    zoneTableEntry.w  aquatic_ruin_zone_act_2   ; 30
    zoneTableEntry.w  casino_night_zone_act_1   ; 31
    zoneTableEntry.w  wing_fortress_zone_act_1  ; 32
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 33
    zoneTableEnd
 
;word_1433C:
LevelOrder_2P: zoneOrderedTable 2,2 ; WrdArr_LevelOrder_2P
    zoneTableEntry.w  emerald_hill_zone_act_2
    zoneTableEntry.w  casino_night_zone_act_1   ; 1
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 2
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 3
    zoneTableEntry.w  wood_zone_act_2       ; 4
    zoneTableEntry.w  metropolis_zone_act_1     ; 5
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 6
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 7
    zoneTableEntry.w  metropolis_zone_act_2     ; 8
    zoneTableEntry.w  metropolis_zone_act_3     ; 9
    zoneTableEntry.w  sky_chase_zone_act_1      ; 10
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 11
    zoneTableEntry.w  death_egg_zone_act_1      ; 12
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 13
    zoneTableEntry.w  hill_top_zone_act_2       ; 14
    zoneTableEntry.w  mystic_cave_zone_act_1    ; 15
    zoneTableEntry.w  hidden_palace_zone_act_2  ; 16
    zoneTableEntry.w  oil_ocean_zone_act_1      ; 17
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 18
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 19
    zoneTableEntry.w  oil_ocean_zone_act_2      ; 20
    zoneTableEntry.w  metropolis_zone_act_1     ; 21
    zoneTableEntry.w  mystic_cave_zone_act_2    ; 22
    zoneTableEntry.w  $FFFF             ; 23
    zoneTableEntry.w  casino_night_zone_act_2   ; 24
    zoneTableEntry.w  mystic_cave_zone_act_1    ; 25
    zoneTableEntry.w  chemical_plant_zone_act_2     ; 26
    zoneTableEntry.w  aquatic_ruin_zone_act_1   ; 27
    zoneTableEntry.w  $FFFF             ; 28
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 29
    zoneTableEntry.w  aquatic_ruin_zone_act_2   ; 30
    zoneTableEntry.w  casino_night_zone_act_1   ; 31
    zoneTableEntry.w  wing_fortress_zone_act_1  ; 32
    zoneTableEntry.w  emerald_hill_zone_act_1   ; 33
    zoneTableEnd
 
byte_14380:
results_screen_object macro startx, targetx, y, routine, frame
    dc.w    startx, targetx, y
    dc.b    routine, frame
    endm
    results_screen_object   $20, $120,  $B8,   2,  0
    results_screen_object  $200, $100,  $CA,   4,  3
    results_screen_object  $240, $140,  $CA,   6,  4
    results_screen_object  $278, $178,  $BE,   8,  6
    results_screen_object  $350, $120, $120,   4,  9
    results_screen_object  $320, $120,  $F0,   4, $A
    results_screen_object  $330, $120, $100,   4, $B
    results_screen_object  $340, $120, $110, $16, $E
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6F - End of special stage results screen
; ----------------------------------------------------------------------------
; Sprite_143C0:
Obj6F: ; (note: screen-space obj)
    moveq   #0,d0
    moveq   #0,d6
    move.b  routine(a0),d0
    move.w  Obj6F_Index(pc,d0.w),d1
    jmp Obj6F_Index(pc,d1.w)
; ===========================================================================
; off_143D0:
Obj6F_Index:    offsetTable
        offsetTableEntry.w Obj6F_Init   ;   0
        offsetTableEntry.w Obj6F_InitEmeraldText    ;   2
        offsetTableEntry.w Obj6F_InitResultTitle    ;   4
        offsetTableEntry.w Obj6F_Emerald0   ;   6
        offsetTableEntry.w Obj6F_Emerald1   ;   8
        offsetTableEntry.w Obj6F_Emerald2   ;  $A
        offsetTableEntry.w Obj6F_Emerald3   ;  $C
        offsetTableEntry.w Obj6F_Emerald4   ;  $E
        offsetTableEntry.w Obj6F_Emerald5   ; $10
        offsetTableEntry.w Obj6F_Emerald6   ; $12
        offsetTableEntry.w BranchTo3_Obj34_MoveTowardsTargetPosition    ; $14
        offsetTableEntry.w Obj6F_P1Rings    ; $16
        offsetTableEntry.w Obj6F_P2Rings    ; $18
        offsetTableEntry.w Obj6F_DeleteIfNotEmerald ; $1A
        offsetTableEntry.w Obj6F_TimedDisplay   ; $1C
        offsetTableEntry.w Obj6F_TallyScore ; $1E
        offsetTableEntry.w Obj6F_TimedDisplay   ; $20
        offsetTableEntry.w Obj6F_DisplayOnly    ; $22
        offsetTableEntry.w Obj6F_TimedDisplay   ; $24
        offsetTableEntry.w Obj6F_TimedDisplay   ; $26
        offsetTableEntry.w Obj6F_TallyPerfect   ; $28
        offsetTableEntry.w Obj6F_PerfectBonus   ; $2A
        offsetTableEntry.w Obj6F_TimedDisplay   ; $2C
        offsetTableEntry.w Obj6F_DisplayOnly    ; $2E
        offsetTableEntry.w Obj6F_InitAndMoveSuperMsg    ; $30
        offsetTableEntry.w Obj6F_MoveToTargetPos    ; $32
        offsetTableEntry.w Obj6F_MoveAndDisplay ; $34
; ===========================================================================
;loc_14406
Obj6F_Init:
    tst.l   (Plc_Buffer).w
    beq.s   +
    rts
; ===========================================================================
+
    movea.l a0,a1
    lea byte_14752(pc),a2
    moveq   #$C,d1
 
-   _move.b id(a0),id(a1) ; load obj6F
    move.w  (a2),x_pixel(a1)
    move.w  (a2)+,objoff_32(a1)
    move.w  (a2)+,objoff_30(a1)
    move.w  (a2)+,y_pixel(a1)
    move.b  (a2)+,routine(a1)
    move.b  (a2)+,mapping_frame(a1)
    move.l  #Obj6F_MapUnc_14ED0,mappings(a1)
    move.b  #$78,width_pixels(a1)
    move.b  #0,render_flags(a1)
    lea next_object(a1),a1 ; go to next object ; a1=object
    dbf d1,- ; loop
 
;loc_14450
Obj6F_InitEmeraldText:
    tst.b   (Got_Emerald).w
    beq.s   +
    move.b  #4,mapping_frame(a0)        ; "Chaos Emerald"
+
    cmpi.b  #7,(Emerald_count).w
    bne.s   +
    move.b  #$19,mapping_frame(a0)      ; "Chaos Emeralds"
+
    move.w  objoff_30(a0),d0
    cmp.w   x_pixel(a0),d0
    bne.s   BranchTo2_Obj34_MoveTowardsTargetPosition
    move.b  #$1C,routine(a0)    ; => Obj6F_TimedDisplay
    move.w  #$B4,anim_frame_duration(a0)
 
BranchTo2_Obj34_MoveTowardsTargetPosition 
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
;loc_14484
Obj6F_InitResultTitle:
    cmpi.b  #7,(Emerald_count).w
    bne.s   +
    moveq   #$16,d0     ; "Sonic has all the"
    bra.s   ++
; ===========================================================================
+
    tst.b   (Got_Emerald).w
    beq.w   DeleteObject
    moveq   #1,d0       ; "Sonic got a"
+
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    addq.w  #1,d0       ; "Miles got a" or "Miles has all the"
    btst    #7,(Graphics_Flags).w
    beq.s   +
    addq.w  #1,d0       ; "Tails got a" or "Tails has all the"
+
    move.b  d0,mapping_frame(a0)
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
;loc_144B6
Obj6F_Emerald6:
    addq.w  #1,d6
;loc_144B8
Obj6F_Emerald5:
    addq.w  #1,d6
;loc_144BA
Obj6F_Emerald4:
    addq.w  #1,d6
;loc_144BC
Obj6F_Emerald3:
    addq.w  #1,d6
;loc_144BE
Obj6F_Emerald2:
    addq.w  #1,d6
;loc_144C0
Obj6F_Emerald1:
    addq.w  #1,d6
;loc_144C2
Obj6F_Emerald0:
    lea (Got_Emeralds_array).w,a1
    tst.b   (a1,d6.w)
    beq.w   DeleteObject
    btst    #0,(Vint_runcount+3).w
    beq.s   +
    bsr.w   DisplaySprite
+
    rts
; ===========================================================================
;loc_144DC
Obj6F_P2Rings:
    tst.w   (Player_mode).w
    bne.w   DeleteObject
    cmpi.b  #$26,(SpecialStageResults+routine).w    ; Do we need space for perfect countdown?
    beq.w   DeleteObject                            ; Branch if yes
    moveq   #$E,d0      ; "Miles rings"
    btst    #7,(Graphics_Flags).w
    beq.s   +
    addq.w  #1,d0       ; "Tails rings"
+
    lea (Bonus_Countdown_2).w,a1
    bra.s   loc_1455A
; ===========================================================================
;loc_14500
Obj6F_P1Rings:
    cmpi.b  #$26,(SpecialStageResults+routine).w    ; Do we need space for perfect countdown?
    bne.s   +                                       ; Branch if not
    move.w  #5000,(Bonus_Countdown_1).w             ; Perfect bonus
    move.b  #$2A,routine(a0)    ; => Obj6F_PerfectBonus
    move.w  #$120,y_pixel(a0)
    st.b    (Update_Bonus_score).w  ; set to -1 (update)
    move.w  #SndID_Signpost,d0
    jsr (PlaySound).l
    move.w  #$5A,(SpecialStageResults+anim_frame_duration).w
    bra.w   Obj6F_PerfectBonus
; ===========================================================================
+
    move.w  (Player_mode).w,d0
    beq.s   ++
    move.w  #$120,y_pixel(a0)
    subq.w  #1,d0
    beq.s   ++
    moveq   #$E,d0      ; "Miles rings"
    btst    #7,(Graphics_Flags).w
    beq.s   +
    addq.w  #1,d0       ; "Tails rings"
+
    lea (Bonus_Countdown_2).w,a1
    bra.s   loc_1455A
; ===========================================================================
+
    moveq   #$D,d0      ; "Sonic rings"
    lea (Bonus_Countdown_1).w,a1
 
loc_1455A:
    tst.w   (a1)
    bne.s   +
    addq.w  #5,d0       ; Rings text with zero points
+
    move.b  d0,mapping_frame(a0)
 
BranchTo3_Obj34_MoveTowardsTargetPosition 
    bra.w   Obj34_MoveTowardsTargetPosition
; ===========================================================================
;loc_14568
Obj6F_DeleteIfNotEmerald:
    tst.b   (Got_Emerald).w
    beq.w   DeleteObject
    bra.s   BranchTo3_Obj34_MoveTowardsTargetPosition
; ===========================================================================
;loc_14572
Obj6F_TimedDisplay:
    subq.w  #1,anim_frame_duration(a0)
    bne.s   BranchTo19_DisplaySprite
    addq.b  #2,routine(a0)
 
BranchTo19_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
;loc_14580
Obj6F_TallyScore:
    bsr.w   DisplaySprite
    move.b  #1,(Update_Bonus_score).w
    moveq   #0,d0
    tst.w   (Bonus_Countdown_1).w
    beq.s   +
    addi.w  #10,d0
    subq.w  #1,(Bonus_Countdown_1).w
+
    tst.w   (Bonus_Countdown_2).w
    beq.s   +
    addi.w  #10,d0
    subq.w  #1,(Bonus_Countdown_2).w
+
    tst.w   (Total_Bonus_Countdown).w
    beq.s   +
    addi.w  #10,d0
    subi.w  #10,(Total_Bonus_Countdown).w
+
    tst.w   d0
    bne.s   +++
    move.w  #SndID_TallyEnd,d0
    jsr (PlaySound).l
    addq.b  #2,routine(a0)      ; => Obj6F_TimedDisplay
    move.w  #$78,anim_frame_duration(a0)
    tst.w   (Perfect_rings_flag).w
    bne.s   +
    cmpi.w  #2,(Player_mode).w
    beq.s   ++      ; rts
    tst.b   (Got_Emerald).w
    beq.s   ++      ; rts
    cmpi.b  #7,(Emerald_count).w
    bne.s   ++      ; rts
    move.b  #$30,routine(a0)    ; => Obj6F_InitAndMoveSuperMsg
    rts
; ===========================================================================
+
    move.b  #$24,routine(a0)    ; => Obj6F_TimedDisplay
    move.w  #$5A,anim_frame_duration(a0)
/
    rts
; ===========================================================================
+
    jsr (AddPoints).l
    move.b  (Vint_runcount+3).w,d0
    andi.b  #3,d0
    bne.s   -       ; rts
    move.w  #SndID_Blip,d0
    jmp (PlaySound).l
; ===========================================================================
;loc_1461C
Obj6F_DisplayOnly:
    move.w  #1,(Level_Inactive_flag).w
    bra.w   DisplaySprite
; ===========================================================================
;loc_14626
Obj6F_TallyPerfect:
    bsr.w   DisplaySprite
    move.b  #1,(Update_Bonus_score).w
    moveq   #0,d0
    tst.w   (Bonus_Countdown_1).w
    beq.s   +
    addi.w  #20,d0
    subi.w  #20,(Bonus_Countdown_1).w
+
    tst.w   d0
    beq.s   +
    jsr (AddPoints).l
    move.b  (Vint_runcount+3).w,d0
    andi.b  #3,d0
    bne.s   ++      ; rts
    move.w  #SndID_Blip,d0
    jmp (PlaySound).l
; ===========================================================================
+
    move.w  #SndID_TallyEnd,d0
    jsr (PlaySound).l
    addq.b  #4,routine(a0)
    move.w  #$78,anim_frame_duration(a0)
    cmpi.w  #2,(Player_mode).w
    beq.s   +       ; rts
    tst.b   (Got_Emerald).w
    beq.s   +       ; rts
    cmpi.b  #7,(Emerald_count).w
    bne.s   +       ; rts
    move.b  #$30,routine(a0)    ; => Obj6F_InitAndMoveSuperMsg
+
    rts
; ===========================================================================
;loc_14692
Obj6F_PerfectBonus:
    moveq   #$11,d0     ; "Perfect bonus"
    btst    #3,(Vint_runcount+3).w
    beq.s   +
    moveq   #$15,d0     ; null text
+
    move.b  d0,mapping_frame(a0)
    bra.w   DisplaySprite
; ===========================================================================
;loc_146A6
Obj6F_InitAndMoveSuperMsg:
    move.b  #$32,next_object+routine(a0)            ; => Obj6F_MoveToTargetPos
    move.w  x_pos(a0),d0
    cmp.w   objoff_32(a0),d0
    bne.s   Obj6F_MoveToTargetPos
    move.b  #$14,next_object+routine(a0)            ; => BranchTo3_Obj34_MoveTowardsTargetPosition
    subq.w  #8,next_object+y_pixel(a0)
    move.b  #$1A,next_object+mapping_frame(a0)      ; "Now Sonic can"
    move.b  #$34,routine(a0)                        ; => Obj6F_MoveAndDisplay
    subq.w  #8,y_pixel(a0)
    move.b  #$1B,mapping_frame(a0)                  ; "Change into"
    lea (SpecialStageResults2).w,a1
    _move.b id(a0),id(a1) ; load obj6F; (uses screen-space)
    clr.w   x_pixel(a1)
    move.w  #$120,objoff_30(a1)
    move.w  #$B4,y_pixel(a1)
    move.b  #$14,routine(a1)                        ; => BranchTo3_Obj34_MoveTowardsTargetPosition
    move.b  #$1C,mapping_frame(a1)                  ; "Super Sonic"
    move.l  #Obj6F_MapUnc_14ED0,mappings(a1)
    move.b  #$78,width_pixels(a1)
    move.b  #0,render_flags(a1)
    bra.w   DisplaySprite
; ===========================================================================
;loc_14714
Obj6F_MoveToTargetPos:
    moveq   #$20,d0
    move.w  x_pos(a0),d1
    cmp.w   objoff_32(a0),d1
    beq.s   BranchTo20_DisplaySprite
    bhi.s   +
    neg.w   d0
+
    sub.w   d0,x_pos(a0)
    cmpi.w  #$200,x_pos(a0)
    bhi.s   +
 
BranchTo20_DisplaySprite 
    bra.w   DisplaySprite
; ===========================================================================
+
    rts
; ===========================================================================
;loc_14736
Obj6F_MoveAndDisplay:
    move.w  x_pos(a0),d0
    cmp.w   objoff_30(a0),d0
    bne.w   Obj34_MoveTowardsTargetPosition
    move.w  #$B4,anim_frame_duration(a0)
    move.b  #$20,routine(a0)    ; => Obj6F_TimedDisplay
    bra.w   DisplaySprite
; ===========================================================================
byte_14752:
    ;      startx  targx   starty  routine   map frame
    results_screen_object  $240, $120,  $AA,   2,   0       ; "Special Stage"
    results_screen_object     0, $120,  $98,   4,   1       ; "Sonic got a"
    results_screen_object  $118,    0,  $C4,   6,   5       ; Emerald 0
    results_screen_object  $130,    0,  $D0,   8,   6       ; Emerald 1
    results_screen_object  $130,    0,  $E8,  $A,   7       ; Emerald 2
    results_screen_object  $118,    0,  $F4,  $C,   8       ; Emerald 3
    results_screen_object  $100,    0,  $E8,  $E,   9       ; Emerald 4
    results_screen_object  $100,    0,  $D0, $10,  $A       ; Emerald 5
    results_screen_object  $118,    0,  $DC, $12,  $B       ; Emerald 6
    results_screen_object  $330, $120, $108, $14,  $C       ; Score
    results_screen_object  $340, $120, $118, $16,  $D       ; Sonic Rings
    results_screen_object  $350, $120, $128, $18,  $E       ; Miles Rings
    results_screen_object  $360, $120, $138, $1A, $10       ; Gems Bonus
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj34_MapUnc_147BA: offsetTable
    offsetTableEntry.w word_147E8
    offsetTableEntry.w word_147E8
    offsetTableEntry.w word_147E8
    offsetTableEntry.w word_147E8
    offsetTableEntry.w word_14842
    offsetTableEntry.w word_14842
    offsetTableEntry.w word_14B24
    offsetTableEntry.w word_14894
    offsetTableEntry.w word_148CE
    offsetTableEntry.w word_147E8
    offsetTableEntry.w word_14930
    offsetTableEntry.w word_14972
    offsetTableEntry.w word_149C4
    offsetTableEntry.w word_14A1E
    offsetTableEntry.w word_14B86
    offsetTableEntry.w word_14A88
    offsetTableEntry.w word_14AE2
    offsetTableEntry.w word_14BC8
    offsetTableEntry.w word_14BEA
    offsetTableEntry.w word_14BF4
    offsetTableEntry.w word_14BFE
    offsetTableEntry.w word_14C08
    offsetTableEntry.w word_14C32
word_147E8: dc.w $B
    dc.w 5, $8580, $82C0, $FFC3
    dc.w 9, $85DE, $82EF, $FFD0
    dc.w 5, $8580, $82C0, $FFE8
    dc.w 5, $85E4, $82F2, $FFF8
    dc.w 5, $85E8, $82F4, 8
    dc.w 5, $85EC, $82F6, $18
    dc.w 5, $85F0, $82F8, $28
    dc.w 5, $85F4, $82FA, $48
    dc.w 1, $85F8, $82FC, $58
    dc.w 5, $85EC, $82F6, $60
    dc.w 5, $85EC, $82F6, $70
word_14842: dc.w $A
    dc.w 9, $85DE, $82EF, $FFE0
    dc.w 5, $8580, $82C0, $FFF8
    dc.w 5, $85E4, $82F2, 8
    dc.w 5, $85E8, $82F4, $18
    dc.w 5, $8588, $82C4, $28
    dc.w 5, $85EC, $82F6, $38
    dc.w 5, $8588, $82C4, $48
    dc.w 5, $85F0, $82F8, $58
    dc.w 1, $85F4, $82FA, $68
    dc.w 5, $85F6, $82FB, $70
word_14894: dc.w 7
    dc.w 5, $85DE, $82EF, 8
    dc.w 1, $85E2, $82F1, $18
    dc.w 5, $85E4, $82F2, $20
    dc.w 5, $85E4, $82F2, $30
    dc.w 5, $85E8, $82F4, $51
    dc.w 5, $8588, $82C4, $60
    dc.w 5, $85EC, $82F6, $70
word_148CE: dc.w $C
    dc.w 5, $85DE, $82EF, $FFB8
    dc.w 1, $85E2, $82F1, $FFC8
    dc.w 5, $85E4, $82F2, $FFD0
    dc.w 5, $85E4, $82F2, $FFE0
    dc.w 5, $8580, $82C0, $FFF0
    dc.w 5, $8584, $82C2, 0
    dc.w 5, $85E8, $82F4, $20
    dc.w 5, $85EC, $82F6, $30
    dc.w 5, $85F0, $82F8, $40
    dc.w 5, $85EC, $82F6, $50
    dc.w 5, $85F4, $82FA, $60
    dc.w 5, $8580, $82C0, $70
word_14930: dc.w 8
    dc.w 5, $8588, $82C4, $FFFB
    dc.w 1, $85DE, $82EF, $B
    dc.w 5, $85E0, $82F0, $13
    dc.w 5, $8588, $82C4, $33
    dc.w 5, $85E4, $82F2, $43
    dc.w 5, $8580, $82C0, $53
    dc.w 5, $85E8, $82F4, $60
    dc.w 5, $8584, $82C2, $70
word_14972: dc.w $A
    dc.w 9, $85DE, $82EF, $FFD0
    dc.w 5, $85E4, $82F2, $FFE8
    dc.w 5, $85E8, $82F4, $FFF8
    dc.w 5, $85EC, $82F6, 8
    dc.w 1, $85F0, $82F8, $18
    dc.w 5, $85F2, $82F9, $20
    dc.w 5, $85F2, $82F9, $41
    dc.w 5, $85F6, $82FB, $50
    dc.w 5, $85FA, $82FD, $60
    dc.w 5, $8580, $82C0, $70
word_149C4: dc.w $B
    dc.w 5, $85DE, $82EF, $FFD1
    dc.w 5, $85E2, $82F1, $FFE0
    dc.w 5, $85E6, $82F3, $FFF0
    dc.w 1, $85EA, $82F5, 0
    dc.w 5, $8584, $82C2, 8
    dc.w 5, $8588, $82C4, $18
    dc.w 5, $8584, $82C2, $38
    dc.w 1, $85EA, $82F5, $48
    dc.w 5, $85EC, $82F6, $50
    dc.w 5, $85F0, $82F8, $60
    dc.w 5, $85F4, $82FA, $70
word_14A1E: dc.w $D
    dc.w 5, $85DE, $82EF, $FFA4
    dc.w 5, $85E2, $82F1, $FFB4
    dc.w 5, $8580, $82C0, $FFC4
    dc.w 9, $85E6, $82F3, $FFD1
    dc.w 1, $85EC, $82F6, $FFE9
    dc.w 5, $85DE, $82EF, $FFF1
    dc.w 5, $85EE, $82F7, 0
    dc.w 5, $85F2, $82F9, $10
    dc.w 5, $85F6, $82FB, $31
    dc.w 5, $85F2, $82F9, $41
    dc.w 5, $85EE, $82F7, $50
    dc.w 5, $8584, $82C2, $60
    dc.w 5, $85FA, $82FD, $70
word_14A88: dc.w $B
    dc.w 5, $85DE, $82EF, $FFD2
    dc.w 5, $85E2, $82F1, $FFE2
    dc.w 5, $85E6, $82F3, $FFF2
    dc.w 5, $85DE, $82EF, 0
    dc.w 5, $85EA, $82F5, $10
    dc.w 1, $85EE, $82F7, $20
    dc.w 5, $85F0, $82F8, $28
    dc.w 5, $85F4, $82FA, $48
    dc.w 5, $85E6, $82F3, $58
    dc.w 1, $85EE, $82F7, $68
    dc.w 5, $8584, $82C2, $70
word_14AE2: dc.w 8
    dc.w 5, $85DE, $82EF, $FFF0
    dc.w 5, $85E2, $82F1, 0
    dc.w 5, $85E6, $82F3, $10
    dc.w 5, $85EA, $82F5, $30
    dc.w 5, $85EE, $82F7, $40
    dc.w 5, $85F2, $82F9, $50
    dc.w 5, $85DE, $82EF, $60
    dc.w 5, $8580, $82C0, $70
word_14B24: dc.w $C
    dc.w 9, $85DE, $82EF, $FFB1
    dc.w 1, $85E4, $82F2, $FFC8
    dc.w 5, $8584, $82C2, $FFD0
    dc.w 5, $85E6, $82F3, $FFE0
    dc.w 5, $85EA, $82F5, 1
    dc.w 5, $8588, $82C4, $10
    dc.w 5, $85EE, $82F7, $20
    dc.w 5, $85F2, $82F9, $30
    dc.w 5, $85EE, $82F7, $40
    dc.w 5, $8580, $82C0, $50
    dc.w 5, $85F6, $82FB, $5F
    dc.w 5, $85F6, $82FB, $6F
word_14B86: dc.w 8
    dc.w 5, $85DE, $82EF, $FFF2
    dc.w 5, $8580, $82C0, 2
    dc.w 5, $85E2, $82F1, $10
    dc.w 5, $85E6, $82F3, $20
    dc.w 5, $85EA, $82F5, $30
    dc.w 5, $8580, $82C0, $51
    dc.w 5, $85EE, $82F7, $60
    dc.w 5, $85EE, $82F7, $70
word_14BC8: dc.w 4
    dc.w 5, $858C, $82C6, 1
    dc.w 5, $8588, $82C4, $10
    dc.w 5, $8584, $82C2, $20
    dc.w 5, $8580, $82C0, $30
word_14BEA: dc.w 1
    dc.w 7, $A590, $A2C8, 0
word_14BF4: dc.w 1
    dc.w $B, $A598, $A2CC, 0
word_14BFE: dc.w 1
    dc.w $B, $A5A4, $A2D2, 0
word_14C08: dc.w 5
    dc.w $D, $85B0, $82D8, $FFB8
    dc.w $D, $85B8, $82DC, $FFD8
    dc.w $D, $85C0, $82E0, $FFF8
    dc.w $D, $85C8, $82E4, $18
    dc.w 5, $85D0, $82E8, $38
word_14C32: dc.w 7
    dc.w $9003, $85D4, $82EA, 0
    dc.w $B003, $85D4, $82EA, 0
    dc.w $D003, $85D4, $82EA, 0
    dc.w $F003, $85D4, $82EA, 0
    dc.w $1003, $85D4, $82EA, 0
    dc.w $3003, $85D4, $82EA, 0
    dc.w $5003, $85D4, $82EA, 0
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj39_MapUnc_14C6C: BINCLUDE "mappings/sprite/obj39.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj3A_MapUnc_14CBC: offsetTable
    offsetTableEntry.w word_14CDA
    offsetTableEntry.w word_14D1C
    offsetTableEntry.w word_14D5E
    offsetTableEntry.w word_14DA0
    offsetTableEntry.w word_14DDA
    offsetTableEntry.w word_14BC8
    offsetTableEntry.w word_14BEA
    offsetTableEntry.w word_14BF4
    offsetTableEntry.w word_14BFE
    offsetTableEntry.w word_14DF4
    offsetTableEntry.w word_14E1E
    offsetTableEntry.w word_14E50
    offsetTableEntry.w word_14E82
    offsetTableEntry.w word_14E8C
    offsetTableEntry.w word_14E96
word_14CDA: dc.w 8
    dc.w 5, $85D0, $82E8, $FFC0
    dc.w 5, $8588, $82C4, $FFD0
    dc.w 5, $8584, $82C2, $FFE0
    dc.w 1, $85C0, $82E0, $FFF0
    dc.w 5, $85B4, $82DA, $FFF8
    dc.w 5, $85B8, $82DC, $10
    dc.w 5, $8588, $82C4, $20
    dc.w 5, $85D4, $82EA, $2F
word_14D1C: dc.w 8
    dc.w 9, $85C6, $82E3, $FFBC
    dc.w 1, $85C0, $82E0, $FFD4
    dc.w 5, $85C2, $82E1, $FFDC
    dc.w 5, $8580, $82C0, $FFEC
    dc.w 5, $85D0, $82E8, $FFFC
    dc.w 5, $85B8, $82DC, $14
    dc.w 5, $8588, $82C4, $24
    dc.w 5, $85D4, $82EA, $33
word_14D5E: dc.w 8
    dc.w 5, $85D4, $82EA, $FFC3
    dc.w 5, $85B0, $82D8, $FFD0
    dc.w 1, $85C0, $82E0, $FFE0
    dc.w 5, $85C2, $82E1, $FFE8
    dc.w 5, $85D0, $82E8, $FFF8
    dc.w 5, $85B8, $82DC, $10
    dc.w 5, $8588, $82C4, $20
    dc.w 5, $85D4, $82EA, $2F
word_14DA0: dc.w 7
    dc.w 5, $85D4, $82EA, $FFC8
    dc.w 5, $85BC, $82DE, $FFD8
    dc.w 5, $85CC, $82E6, $FFE8
    dc.w 5, $8588, $82C4, $FFF8
    dc.w 5, $85D8, $82EC, 8
    dc.w 5, $85B8, $82DC, $18
    dc.w 5, $85BC, $82DE, $28
word_14DDA: dc.w 3
    dc.w 5, $85B0, $82D8, 0
    dc.w 5, $85B4, $82DA, $10
    dc.w 5, $85D4, $82EA, $1F
word_14DF4: dc.w 5
    dc.w 9, $A5E6, $A2F3, $FFB8
    dc.w 5, $A5EC, $A2F6, $FFD0
    dc.w 5, $85F0, $82F8, $FFD4
    dc.w $D, $8520, $8290, $38
    dc.w 1, $86F0, $8378, $58
word_14E1E: dc.w 6
    dc.w $D, $A6DA, $A36D, $FFA4
    dc.w $D, $A5DE, $A2EF, $FFCC
    dc.w 1, $A6CA, $A365, $FFEC
    dc.w 5, $85F0, $82F8, $FFE8
    dc.w $D, $8528, $8294, $38
    dc.w 1, $86F0, $8378, $58
word_14E50: dc.w 6
    dc.w $D, $A6D2, $A369, $FFA4
    dc.w $D, $A5DE, $A2EF, $FFCC
    dc.w 1, $A6CA, $A365, $FFEC
    dc.w 5, $85F0, $82F8, $FFE8
    dc.w $D, $8530, $8298, $38
    dc.w 1, $86F0, $8378, $58
word_14E82: dc.w 1
    dc.w 6, $85F4, $82FA, 0
word_14E8C: dc.w 1
    dc.w 6, $85FA, $82FD, 0
word_14E96: dc.w 7
    dc.w $D, $A540, $A2A0, $FF98
    dc.w 9, $A548, $A2A4, $FFB8
    dc.w $D, $A5DE, $A2EF, $FFD8
    dc.w 1, $A6CA, $A365, $FFF8
    dc.w 5, $85F0, $82F8, $FFF4
    dc.w $D, $8538, $829C, $38
    dc.w 1, $86F0, $8378, $58
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj6F_MapUnc_14ED0: BINCLUDE "mappings/sprite/obj6F.bin"
; ===========================================================================
 
;loc_15584: ; level title card drawing function called from Vint
DrawLevelTitleCard:
    lea (VDP_data_port).l,a6
    tst.w   (TitleCard_ZoneName+titlecard_leaveflag).w
    bne.w   loc_15670
    moveq   #$3F,d5
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d6
    tst.w   (Two_player_mode).w
    beq.s   loc_155A8
    moveq   #$1F,d5
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d6
 
loc_155A8:
    lea (TitleCard_Background+titlecard_vram_dest).w,a0
    moveq   #1,d7   ; Once for P1, once for P2 (if in 2p mode)
 
loc_155AE:
    move.w  (a0)+,d0
    beq.s   loc_155C6
    clr.w   -2(a0)
    jsr sub_15792(pc)
    move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.w  d5,d4
 
loc_155C0:
    move.l  d6,(a6)
    dbf d4,loc_155C0
 
loc_155C6:
    dbf d7,loc_155AE
    moveq   #$26,d1
    sub.w   (TitleCard_Bottom+titlecard_split_point).w,d1
    lsr.w   #1,d1
    subq.w  #1,d1
    moveq   #7,d5
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$5C,0,0,1,1),d6
    tst.w   (Two_player_mode).w
    beq.s   loc_155EA
    moveq   #3,d5
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$5C,0,0,1,1),d6
 
loc_155EA:
    lea (TitleCard_Bottom+titlecard_vram_dest).w,a0
    moveq   #1,d7   ; Once for P1, once for P2 (if in 2p mode)
 
loc_155F0:
    move.w  (a0)+,d0
    beq.s   loc_15614
    clr.w   -2(a0)
    jsr sub_15792(pc)
    move.w  d5,d4
 
loc_155FE:
    move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.w  d1,d3
 
loc_15604:
    move.l  d6,(a6)
    dbf d3,loc_15604
    addi.l  #vdpCommDelta($0080),d0
    dbf d4,loc_155FE
 
loc_15614:
    dbf d7,loc_155F0
    move.w  (TitleCard_Left+titlecard_split_point).w,d1 ; horizontal draw from left until this position
    subq.w  #1,d1
    moveq   #$D,d5
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$58,0,0,0,1),d6 ; VRAM location of graphic to fill on left side
    tst.w   (Two_player_mode).w
    beq.s   loc_15634
    moveq   #6,d5
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$58,0,0,0,1),d6 ; VRAM location of graphic to fill on left side (2p)
 
loc_15634:
    lea (TitleCard_Left+titlecard_vram_dest).w,a0 ; obj34 red title card left side part
    moveq   #1,d7   ; Once for P1, once for P2 (if in 2p mode)
    move.w  #$8F80,VDP_control_port-VDP_data_port(a6)   ; VRAM pointer increment: $0080
 
loc_15640:
    move.w  (a0)+,d0
    beq.s   loc_15664
    clr.w   -2(a0)
    jsr sub_15792(pc)
    move.w  d1,d4
 
loc_1564E:
    move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.w  d5,d3
 
loc_15654:
    move.l  d6,(a6)
    dbf d3,loc_15654
    addi.l  #vdpCommDelta($0002),d0
    dbf d4,loc_1564E
 
loc_15664:
    dbf d7,loc_15640
    move.w  #$8F02,VDP_control_port-VDP_data_port(a6)   ; VRAM pointer increment: $0002
    rts
; ===========================================================================
 
loc_15670:
    moveq   #9,d3
    moveq   #3,d4
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d5
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$5C,0,0,1,1),d6
    tst.w   (Two_player_mode).w
    beq.s   +
    moveq   #4,d3
    moveq   #1,d4
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d5
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$5C,0,0,1,1),d6
+
    lea (TitleCard_Left+titlecard_vram_dest).w,a0
    moveq   #1,d7   ; Once for P1, once for P2 (if in 2p mode)
    move.w  #$8F80,VDP_control_port-VDP_data_port(a6)   ; VRAM pointer increment: $0080
 
loc_156A2:
    move.w  (a0)+,d0
    beq.s   loc_156CE
    clr.w   -2(a0)
    jsr sub_15792(pc)
    moveq   #3,d2
 
loc_156B0:
    move.l  d0,VDP_control_port-VDP_data_port(a6)
 
    move.w  d3,d1
-   move.l  d5,(a6)
    dbf d1,-
 
    move.w  d4,d1
-   move.l  d6,(a6)
    dbf d1,-
 
    addi.l  #vdpCommDelta($0002),d0
    dbf d2,loc_156B0
 
loc_156CE:
    dbf d7,loc_156A2
    move.w  #$8F02,VDP_control_port-VDP_data_port(a6)   ; VRAM pointer increment: $0002
    moveq   #7,d5
    move.l  #make_block_tile_pair(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d6
    tst.w   (Two_player_mode).w
    beq.s   +
    moveq   #3,d5
    move.l  #make_block_tile_pair_2p(ArtTile_ArtNem_TitleCard+$5A,0,0,0,1),d6
+
    lea (TitleCard_Bottom+titlecard_vram_dest).w,a0
    moveq   #1,d7   ; Once for P1, once for P2 (if in 2p mode)
 
loc_156F4:
    move.w  (a0)+,d0
    beq.s   loc_15714
    clr.w   -2(a0)
    jsr sub_15792(pc)
 
    move.w  d5,d4
-   move.l  d0,VDP_control_port-VDP_data_port(a6)
    move.l  d6,(a6)
    move.l  d6,(a6)
    addi.l  #vdpCommDelta($0080),d0
    dbf d4,-
 
loc_15714:
    dbf d7,loc_156F4
    move.w  (TitleCard_Background+titlecard_vram_dest).w,d4
    beq.s   loc_1578C
    lea VDP_control_port-VDP_data_port(a6),a5
    tst.w   (Two_player_mode).w
    beq.s   loc_15758
    lea (Camera_X_pos_P2).w,a3
    lea (Level_Layout).w,a4
    move.w  #vdpComm(VRAM_Plane_A_Name_Table_2P,VRAM,WRITE)>>16,d2
 
    moveq   #1,d6
-   movem.l d4-d6,-(sp)
    moveq   #-$10,d5
    move.w  d4,d1
    bsr.w   CalcBlockVRAMPosB
    move.w  d1,d4
    moveq   #-$10,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4
    dbf d6,-
 
loc_15758:
    lea (Camera_X_pos).w,a3
    lea (Level_Layout).w,a4
    move.w  #vdpComm(VRAM_Plane_A_Name_Table,VRAM,WRITE)>>16,d2
    move.w  (TitleCard_Background+titlecard_vram_dest).w,d4
 
    moveq   #1,d6
-   movem.l d4-d6,-(sp)
    moveq   #-$10,d5
    move.w  d4,d1
    bsr.w   CalcBlockVRAMPos
    move.w  d1,d4
    moveq   #-$10,d5
    moveq   #$1F,d6
    bsr.w   DrawBlockRow
    movem.l (sp)+,d4-d6
    addi.w  #$10,d4
    dbf d6,-
 
loc_1578C:
    clr.w   (TitleCard_Background+titlecard_vram_dest).w
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to convert a VRAM address into a 32-bit VRAM write command word
; Input:
;   d0  VRAM address (word)
; Output:
;   d0  32-bit VDP command word for a VRAM write to specified address.
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_15792:
    andi.l  #$FFFF,d0
    lsl.l   #2,d0
    lsr.w   #2,d0
    ori.w   #vdpComm($0000,VRAM,WRITE)>>16,d0
    swap    d0
    rts
; End of function sub_15792
 
; ===========================================================================
 
;loc_157A4
LoadTitleCardSS:
    movem.l d0/a0,-(sp)
    bsr.s   LoadTitleCard0
    movem.l (sp)+,d0/a0
    bra.s   loc_157EC
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_157B0:
LoadTitleCard0:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_TitleCard),VRAM,WRITE),(VDP_control_port).l
    lea (ArtNem_TitleCard).l,a0
    jsrto   (NemDec).l, JmpTo2_NemDec
    lea (Level_Layout).w,a4
    lea (ArtNem_TitleCard2).l,a0
    jmpto   (NemDecToRAM).l, JmpTo_NemDecToRAM
; ===========================================================================
; loc_157D2:
LoadTitleCard:
    bsr.s   LoadTitleCard0
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    move.b  Off_TitleCardLetters(pc,d0.w),d0
    lea TitleCardLetters(pc),a0
    lea (a0,d0.w),a0
    move.l  #vdpComm(tiles_to_bytes(ArtTile_LevelName),VRAM,WRITE),d0
 
loc_157EC:
    move    #$2700,sr
    lea (Level_Layout).w,a1
    lea (VDP_data_port).l,a6
    move.l  d0,4(a6)
 
loc_157FE:
    moveq   #0,d0
    move.b  (a0)+,d0
    bmi.s   loc_1581A
    lsl.w   #5,d0
    lea (a1,d0.w),a2
    moveq   #0,d1
    move.b  (a0)+,d1
    lsl.w   #3,d1
    subq.w  #1,d1
 
loc_15812:
    move.l  (a2)+,(a6)
    dbf d1,loc_15812
    bra.s   loc_157FE
; ===========================================================================
 
loc_1581A:
    move    #$2300,sr
    rts
; ===========================================================================
; byte_15820:
Off_TitleCardLetters:
    dc.b TitleCardLetters_EHZ - TitleCardLetters    ; 0
    dc.b TitleCardLetters_EHZ - TitleCardLetters    ; 1
    dc.b TitleCardLetters_EHZ - TitleCardLetters    ; 2
    dc.b TitleCardLetters_EHZ - TitleCardLetters    ; 3
    dc.b TitleCardLetters_MTZ - TitleCardLetters    ; 4
    dc.b TitleCardLetters_MTZ - TitleCardLetters    ; 5
    dc.b TitleCardLetters_WFZ - TitleCardLetters    ; 6
    dc.b TitleCardLetters_HTZ - TitleCardLetters    ; 7
    dc.b TitleCardLetters_HPZ - TitleCardLetters    ; 8
    dc.b TitleCardLetters_EHZ - TitleCardLetters    ; 9
    dc.b TitleCardLetters_OOZ - TitleCardLetters    ; A
    dc.b TitleCardLetters_MCZ - TitleCardLetters    ; B
    dc.b TitleCardLetters_CNZ - TitleCardLetters    ; C
    dc.b TitleCardLetters_CPZ - TitleCardLetters    ; D
    dc.b TitleCardLetters_DEZ - TitleCardLetters    ; E
    dc.b TitleCardLetters_ARZ - TitleCardLetters    ; F
    dc.b TitleCardLetters_SCZ - TitleCardLetters    ; 10
    even
 
 ; temporarily remap characters to title card letter format
 ; Characters are encoded as Aa, Bb, Cc, etc. through a macro
 charset 'A',0  ; can't have an embedded 0 in a string
 charset 'B',"\4\8\xC\4\x10\x14\x18\x1C\x1E\x22\x26\x2A\4\4\x30\x34\x38\x3C\x40\x44\x48\x4C\x52\x56\4"
 charset 'a',"\4\4\4\4\4\4\4\4\2\4\4\4\6\4\4\4\4\4\4\4\4\4\6\4\4"
 charset '.',"\x5A"
 
; Defines which letters load for the continue screen
; Each letter occurs only once, and  the letters ENOZ (i.e. ZONE) aren't loaded here
; However, this is hidden by the titleLetters macro, and normal titles can be used
; (the macro is defined near SpecialStage_ResultsLetters, which uses it before here)
 
; word_15832:
TitleCardLetters:
 
TitleCardLetters_EHZ:
    titleLetters    "EMERALD HILL"
TitleCardLetters_MTZ:
    titleLetters    "METROPOLIS"
TitleCardLetters_HTZ:
    titleLetters    "HILL TOP"
TitleCardLetters_HPZ:
    titleLetters    "HIDDEN PALACE"
TitleCardLetters_OOZ:
    titleLetters    "OIL OCEAN"
TitleCardLetters_MCZ:
    titleLetters    "MYSTIC CAVE"
TitleCardLetters_CNZ:
    titleLetters    "CASINO NIGHT"
TitleCardLetters_CPZ:
    titleLetters    "CHEMICAL PLANT"
TitleCardLetters_ARZ:
    titleLetters    "AQUATIC RUIN"
TitleCardLetters_SCZ:
    titleLetters    "SKY CHASE"
TitleCardLetters_WFZ:
    titleLetters    "WING FORTRESS"
TitleCardLetters_DEZ:
    titleLetters    "DEATH EGG"
 
 charset ; revert character set
 
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_NemDec 
    jmp (NemDec).l
JmpTo_NemDecToRAM 
    jmp (NemDecToRAM).l
JmpTo3_LoadPLC 
    jmp (LoadPLC).l
JmpTo_sub_8476 
    jmp (sub_8476).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 36 - Spikes
; ----------------------------------------------------------------------------
; OST Variables:
spikes_base_x_pos   = objoff_30 ; original x-position
spikes_base_y_pos   = objoff_32 ; original y-position
spikes_retract_offset   = objoff_34 ; actual position relative to base position
spikes_retract_state    = objoff_36 ; 0 = positive offset, 1 = original position
spikes_retract_timer    = objoff_38 ; delay, before spikes move again
; Sprite_15900:
Obj36:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj36_Index(pc,d0.w),d1
    jmp Obj36_Index(pc,d1.w)
; ===========================================================================
; off_1590E:
Obj36_Index:    offsetTable
        offsetTableEntry.w Obj36_Init       ; 0
        offsetTableEntry.w Obj36_Upright    ; 2
        offsetTableEntry.w Obj36_Sideways   ; 4
        offsetTableEntry.w Obj36_Upsidedown ; 6
; ===========================================================================
; byte_15916:
Obj36_InitData:
    ;    width_pixels
    ;    y_radius
    dc.b $10,$10    ; 0 - Upright or ceiling spikes
    dc.b $20,$10    ; 2
    dc.b $30,$10    ; 4
    dc.b $40,$10    ; 6
    dc.b $10,$10    ; 8 - Sideways spikes
    dc.b $10,$20    ; 10
    dc.b $10,$30    ; 12
    dc.b $10,$40    ; 14
; ===========================================================================
; loc_15926:
Obj36_Init:
    addq.b  #2,routine(a0)  ; => Obj36_Upright
    move.l  #Obj36_MapUnc_15B68,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Spikes,1,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),d0
    andi.b  #$F,subtype(a0)     ; lower 4 bits determine behavior, upper bits need to be removed
    andi.w  #$F0,d0
    lea_    Obj36_InitData,a1   ; upper 4 bits determine size and orientation
    lsr.w   #3,d0           ; use upper 4 bits * 2 as offset
    adda.w  d0,a1
    move.b  (a1)+,width_pixels(a0)
    move.b  (a1)+,y_radius(a0)
    lsr.w   #1,d0           ; use upper 4 bits to determine mappings frame
    move.b  d0,mapping_frame(a0)
    cmpi.b  #4,d0           ; do spikes face sideways?
    blo.s   +           ; if not, branch
    addq.b  #2,routine(a0)  ; => Obj36_Sideways
    move.w  #make_art_tile(ArtTile_ArtNem_HorizSpike,1,0),art_tile(a0)
+
    btst    #1,status(a0)       ; are spikes upsiede-down?
    beq.s   +           ; if not, branch
    move.b  #6,routine(a0)  ; => Obj36_Upsidedown
+
    move.w  x_pos(a0),spikes_base_x_pos(a0)
    move.w  y_pos(a0),spikes_base_y_pos(a0)
    bra.w   Adjust2PArtPointer
; ===========================================================================
; loc_15996:
Obj36_Upright:
    bsr.w   MoveSpikes
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject
    move.b  status(a0),d6
    andi.b  #standing_mask,d6   ; are Sonic or Tails standing on the object?
    beq.s   Obj36_UprightEnd    ; if not, branch
    move.b  d6,d0
    andi.b  #p1_standing,d0     ; is Sonic standing on the object?
    beq.s   +           ; if not, branch
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
+
    andi.b  #p2_standing,d6     ; is Tails standing on the object?
    beq.s   Obj36_UprightEnd    ; if not, branch
    lea (Sidekick).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
 
; loc_159DE:
Obj36_UprightEnd:
    move.w  spikes_base_x_pos(a0),d0
    bra.w   MarkObjGone2
; ===========================================================================
; loc_159E6:
Obj36_Sideways:
    move.w  x_pos(a0),-(sp)
    bsr.w   MoveSpikes
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  (sp)+,d4
    bsr.w   SolidObject
    swap    d6
    andi.w  #touch_side_mask,d6 ; are Sonic or Tails pushing against the side?
    beq.s   Obj36_SidewaysEnd   ; if not, branch
    move.b  d6,d0
    andi.b  #p1_touch_side,d0   ; is Sonic pushing against the side?
    beq.s   +           ; if not, branch
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
    bclr    #p1_pushing_bit,status(a0)
+
    andi.b  #p2_touch_side,d6   ; is Tails pushing against the side?
    beq.s   Obj36_SidewaysEnd   ; if not, branch
    lea (Sidekick).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
    bclr    #p2_pushing_bit,status(a0)
 
; loc_15A3A:
Obj36_SidewaysEnd:
    move.w  spikes_base_x_pos(a0),d0
    bra.w   MarkObjGone2
; ===========================================================================
; loc_15A42:
Obj36_Upsidedown:
    bsr.w   MoveSpikes
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject
    swap    d6
    andi.w  #touch_bottom_mask,d6   ; are Sonic or Tails touching the bottom?
    beq.s   Obj36_UpsidedownEnd ; if not, branch
    move.b  d6,d0
    andi.b  #p1_touch_bottom,d0 ; is Sonic touching the bottom?
    beq.s   +           ; if not, branch
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
+
    andi.b  #p2_touch_bottom,d6 ; is Tails touching the bottom?
    beq.s   Obj36_UpsidedownEnd ; if not, branch
    lea (Sidekick).w,a1 ; a1=character
    bsr.w   Touch_ChkHurt2
 
; loc_15A88:
Obj36_UpsidedownEnd:
    move.w  spikes_base_x_pos(a0),d0
    bra.w   MarkObjGone2
 
; ---------------------------------------------------------------------------
; Subroutine for checking if Sonic/Tails should be hurt and hurting them if so
; unlike Touch_ChkHurt, the character is at a1 instead of a0
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
Touch_ChkHurt2:
    btst    #status_sec_isInvincible,status_secondary(a1)   ; is character invincible?
    bne.s   +   ; rts       ; if yes, branch
    tst.w   invulnerable_time(a1)   ; is character invulnerable?
    bne.s   +   ; rts       ; if yes, branch
    cmpi.b  #4,routine(a1)      ; is the character hurt, dieing, etc. ?
    bhs.s   +   ; rts       ; if yes, branch
    move.l  y_pos(a1),d3
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    sub.l   d0,d3
    move.l  d3,y_pos(a1)
    movea.l a0,a2
    movea.l a1,a0
    jsr (HurtCharacter).l
    movea.l a2,a0
+
    rts
; End of function Touch_ChkHurt2
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; handles direction, timing and movement of moving spikes
 
; sub_15AC6:
MoveSpikes:
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.w  MoveSpikes_Behaviors(pc,d0.w),d1
    jmp MoveSpikes_Behaviors(pc,d1.w)
; End of function MoveSpikes
 
; ===========================================================================
; off_15AD6:
MoveSpikes_Behaviors:   offsetTable
        offsetTableEntry.w MoveSpikes_Still     ; 0
        offsetTableEntry.w MoveSpikes_Vertical      ; 1
        offsetTableEntry.w MoveSpikes_Horizontal    ; 2
; ===========================================================================
; return_15ADC:
MoveSpikes_Still:
    rts
; ===========================================================================
; loc_15ADE:
MoveSpikes_Vertical:
    bsr.w   MoveSpikes_Delay
    moveq   #0,d0
    move.b  spikes_retract_offset(a0),d0
    add.w   spikes_base_y_pos(a0),d0    ; apply offset to y-position
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
; loc_15AF2:
MoveSpikes_Horizontal:
    bsr.w   MoveSpikes_Delay
    moveq   #0,d0
    move.b  spikes_retract_offset(a0),d0
    add.w   spikes_base_x_pos(a0),d0    ; apply offset to x-position
    move.w  d0,x_pos(a0)
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_15B06:
MoveSpikes_Delay:
    tst.w   spikes_retract_timer(a0)    ; is it time for spikes to move again?
    beq.s   MoveSpikes_ChkDir       ; if yes, branch
    subq.w  #1,spikes_retract_timer(a0) ; else, decrement timer
    bne.s   +   ; rts           ; branch, if timer didn't reach 0
    tst.b   render_flags(a0)        ; are spikes on screen?
    bpl.s   +   ; rts           ; if not, branch
    move.w  #SndID_SpikesMove,d0        ; play spike movement sount
    jsr (PlaySound).l
    bra.s   +   ; rts
; ===========================================================================
; loc_15B24:
MoveSpikes_ChkDir:
    tst.w   spikes_retract_state(a0)    ; do spikes need to move away from initial position?
    beq.s   MoveSpikes_Retract      ; if yes, branch
    subi.w  #$800,spikes_retract_offset(a0) ; subtract 8 pixels from offset
    bhs.s   +   ; rts           ; branch, if offset is not yet 0
    move.w  #0,spikes_retract_offset(a0)
    move.w  #0,spikes_retract_state(a0) ; switch state
    move.w  #$3C,spikes_retract_timer(a0)   ; reset timer
    bra.s   +   ; rts
; ===========================================================================
; loc_15B46:
MoveSpikes_Retract:
    addi.w  #$800,spikes_retract_offset(a0)     ; add 8 pixels to offset
    cmpi.w  #$2000,spikes_retract_offset(a0)    ; is offset the width of one spike block (32 pixels)?
    blo.s   +   ; rts               ; if not, branch
    move.w  #$2000,spikes_retract_offset(a0)
    move.w  #1,spikes_retract_state(a0) ; switch state
    move.w  #$3C,spikes_retract_timer(a0)   ; reset timer
+
    rts
; End of function MoveSpikes_Delay
 
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj36_MapUnc_15B68: BINCLUDE "mappings/sprite/obj36.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3B - Purple rock (leftover from S1)
; ----------------------------------------------------------------------------
; Sprite_15CC8:
Obj3B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3B_Index(pc,d0.w),d1
    jmp Obj3B_Index(pc,d1.w)
; ===========================================================================
; off_15CD6:
Obj3B_Index:    offsetTable
        offsetTableEntry.w Obj3B_Init   ; 0
        offsetTableEntry.w Obj3B_Main   ; 2
; ===========================================================================
; loc_15CDA:
Obj3B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj3B_MapUnc_15D2E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_GHZ_Purple_Rock,3,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$13,width_pixels(a0)
    move.b  #4,priority(a0)
; loc_15D02:
Obj3B_Main:
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   DeleteObject
    bra.w   DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; Unused sprite mappings
; -------------------------------------------------------------------------------
Obj3B_MapUnc_15D2E: BINCLUDE "mappings/sprite/obj3B.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3C - Breakable wall (leftover from S1) (mostly unused)
; ----------------------------------------------------------------------------
; Sprite_15D44:
Obj3C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3C_Index(pc,d0.w),d1
    jsr Obj3C_Index(pc,d1.w)
    bra.w   MarkObjGone
; ===========================================================================
; off_15D56:
Obj3C_Index:    offsetTable
        offsetTableEntry.w Obj3C_Init       ; 0
        offsetTableEntry.w Obj3C_Main       ; 2
        offsetTableEntry.w Obj3C_Fragment   ; 4
; ===========================================================================
; loc_15D5C:
Obj3C_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj3C_MapUnc_15ECC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BreakWall,2,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),mapping_frame(a0)
; loc_15D8A:
Obj3C_Main:
    move.w  (MainCharacter+x_vel).w,objoff_30(a0)
    move.w  #$1B,d1
    move.w  #$20,d2
    move.w  #$20,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject
    btst    #5,status(a0)
    bne.s   +
-   rts
; ===========================================================================
+
    lea (MainCharacter).w,a1 ; a1=character
    cmpi.b  #2,anim(a1)
    bne.s   -   ; rts
    mvabs.w objoff_30(a0),d0
    cmpi.w  #$480,d0
    blo.s   -   ; rts
    move.w  objoff_30(a0),x_vel(a1)
    addq.w  #4,x_pos(a1)
    lea (Obj3C_FragmentSpeeds_LeftToRight).l,a4
    move.w  x_pos(a0),d0
    cmp.w   x_pos(a1),d0
    blo.s   +
    subi_.w #8,x_pos(a1)
    lea (Obj3C_FragmentSpeeds_RightToLeft).l,a4
+
    move.w  x_vel(a1),inertia(a1)
    bclr    #5,status(a0)
    bclr    #5,status(a1)
    bsr.s   BreakObjectToPieces
; loc_15E02:
Obj3C_Fragment:
    bsr.w   ObjectMove
    addi.w  #$70,y_vel(a0)
    tst.b   render_flags(a0)
    bpl.w   DeleteObject
    bra.w   DisplaySprite
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_15E18:
BreakObjectToPieces:    ; splits up one object into its current mapping frame pieces
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    add.w   d0,d0
    movea.l mappings(a0),a3
    adda.w  (a3,d0.w),a3    ; put address of appropriate frame to a3
    move.w  (a3)+,d1    ; amount of pieces the frame consists of
    subq.w  #1,d1
    bset    #5,render_flags(a0)
    _move.b id(a0),d4
    move.b  render_flags(a0),d5
    movea.l a0,a1
    bra.s   BreakObjectToPieces_InitObject
; ===========================================================================
; loc_15E3E:
BreakObjectToPieces_Loop:
    bsr.w   SingleObjLoad2
    bne.s   loc_15E82
    addq.w  #8,a3   ; next mapping piece
; loc_15E46:
BreakObjectToPieces_InitObject:
    move.b  #4,routine(a1)
    _move.b d4,id(a1) ; load object with ID of parent object and routine 4
    move.l  a3,mappings(a1)
    move.b  d5,render_flags(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  priority(a0),priority(a1)
    move.b  width_pixels(a0),width_pixels(a1)
    move.w  (a4)+,x_vel(a1)
    move.w  (a4)+,y_vel(a1)
    dbf d1,BreakObjectToPieces_Loop
 
loc_15E82:
    move.w  #SndID_SlowSmash,d0
    jmp (PlaySound).l
; End of function BreakObjectToPieces
 
; ===========================================================================
; word_15E8C:
Obj3C_FragmentSpeeds_LeftToRight:
    ;    x_vel,y_vel
    dc.w  $400,-$500    ; 0
    dc.w  $600,-$100    ; 2
    dc.w  $600, $100    ; 4
    dc.w  $400, $500    ; 6
    dc.w  $600,-$600    ; 8
    dc.w  $800,-$200    ; 10
    dc.w  $800, $200    ; 12
    dc.w  $600, $600    ; 14
; word_15EAC:
Obj3C_FragmentSpeeds_RightToLeft:
    dc.w -$600,-$600    ; 0
    dc.w -$800,-$200    ; 2
    dc.w -$800, $200    ; 4
    dc.w -$600, $600    ; 6
    dc.w -$400,-$500    ; 8
    dc.w -$600,-$100    ; 10
    dc.w -$600, $100    ; 12
    dc.w -$400, $500    ; 14
; -------------------------------------------------------------------------------
; Unused sprite mappings
; -------------------------------------------------------------------------------
Obj3C_MapUnc_15ECC: BINCLUDE "mappings/sprite/obj3C.bin"
; ===========================================================================
    bra.w   ObjNull
 
 
 
 
; -------------------------------------------------------------------------------
; This runs the code of all the objects that are in Object_RAM
; -------------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_15F9C: ObjectsLoad:
RunObjects:
    tst.b   (Teleport_flag).w
    bne.s   RunObjects_End  ; rts
    lea (Object_RAM).w,a0 ; a0=object
 
    moveq   #(Dynamic_Object_RAM_End-Object_RAM)/object_size-1,d7 ; run the first $80 objects out of levels
    moveq   #0,d0
    cmpi.b  #GameModeID_Demo,(Game_Mode).w  ; demo mode?
    beq.s   +   ; if in a level in a demo, branch
    cmpi.b  #GameModeID_Level,(Game_Mode).w ; regular level mode?
    bne.s   RunObject ; if not in a level, branch to RunObject
+
    move.w  #(Object_RAM_End-Object_RAM)/object_size-1,d7   ; run the first $90 objects in levels
    tst.w   (Two_player_mode).w
    bne.s   RunObject ; if in 2 player competition mode, branch to RunObject
    
    cmpi.b  #6,(MainCharacter+routine).w
    bhs.s   RunObjectsWhenPlayerIsDead ; if dead, branch
    ; continue straight to RunObject
; ---------------------------------------------------------------------------
 
; -------------------------------------------------------------------------------
; This is THE place where each individual object's code gets called from
; -------------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_15FCC:
RunObject:
    move.b  id(a0),d0   ; get the object's ID
    beq.s   RunNextObject ; if it's obj00, skip it
 
    add.w   d0,d0
    add.w   d0,d0   ; d0 = object ID * 4
    movea.l Obj_Index-4(pc,d0.w),a1 ; load the address of the object's code
    jsr (a1)    ; dynamic call! to one of the the entries in Obj_Index
    moveq   #0,d0
 
; loc_15FDC:
RunNextObject:
    lea next_object(a0),a0 ; load 0bj address
    dbf d7,RunObject
; return_15FE4:
RunObjects_End:
    rts
 
; ---------------------------------------------------------------------------
; this skips certain objects to make enemies and things pause when Sonic dies
; loc_15FE6:
RunObjectsWhenPlayerIsDead:
    moveq   #(Reserved_Object_RAM_End-Reserved_Object_RAM)/object_size-1,d7
    bsr.s   RunObject   ; run the first $10 objects normally
    moveq   #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d7
    bsr.s   RunObjectDisplayOnly ; all objects in this range are paused
    moveq   #(LevelOnly_Object_RAM_End-LevelOnly_Object_RAM)/object_size-1,d7
    bra.s   RunObject   ; run the last $10 objects normally
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_15FF2:
RunObjectDisplayOnly:
    moveq   #0,d0
    move.b  id(a0),d0   ; get the object's ID
    beq.s   +   ; if it's obj00, skip it
    tst.b   render_flags(a0)    ; should we render it?
    bpl.s   +           ; if not, skip it
    bsr.w   DisplaySprite
+
    lea next_object(a0),a0 ; load 0bj address
    dbf d7,RunObjectDisplayOnly
    rts
; End of function RunObjectDisplayOnly
 
; ===========================================================================
; ---------------------------------------------------------------------------
; OBJECT POINTER ARRAY ; object pointers ; sprite pointers ; object list ; sprite list
;
; This array contains the pointers to all the objects used in the game.
; ---------------------------------------------------------------------------
Obj_Index: ; ObjPtrs: ; loc_1600C:
ObjPtr_Sonic:       dc.l Obj01  ; Sonic
ObjPtr_Tails:       dc.l Obj02  ; Tails
ObjPtr_PlaneSwitcher:   dc.l Obj03  ; Collision plane/layer switcher
ObjPtr_WaterSurface:    dc.l Obj04  ; Surface of the water
ObjPtr_TailsTails:  dc.l Obj05  ; Tails' tails
ObjPtr_Spiral:      dc.l Obj06  ; Rotating cylinder in MTZ, twisting spiral pathway in EHZ
ObjPtr_Oil:     dc.l Obj07  ; Oil in OOZ
ObjPtr_SpindashDust:
ObjPtr_Splash:      dc.l Obj08  ; Water splash in Aquatic Ruin Zone, Spindash dust
ObjPtr_SonicSS:     dc.l Obj09  ; Sonic in Special Stage
ObjPtr_SmallBubbles:    dc.l Obj0A  ; Small bubbles from Sonic's face while underwater
ObjPtr_TippingFloor:    dc.l Obj0B  ; Section of pipe that tips you off from CPZ
            dc.l Obj0C  ; Small floating platform (unused)
ObjPtr_Signpost:    dc.l Obj0D  ; End of level signpost
ObjPtr_IntroStars:  dc.l Obj0E  ; Flashing stars from intro
ObjPtr_TitleMenu:   dc.l Obj0F  ; Title screen menu
ObjPtr_TailsSS:     dc.l Obj10  ; Tails in Special Stage
ObjPtr_Bridge:      dc.l Obj11  ; Bridge in Emerald Hill Zone and Hidden Palace Zone
ObjPtr_HPZEmerald:  dc.l Obj12  ; Emerald from Hidden Palace Zone (unused)
ObjPtr_HPZWaterfall:    dc.l Obj13  ; Waterfall in Hidden Palace Zone (unused)
ObjPtr_Seesaw:      dc.l Obj14  ; Seesaw from Hill Top Zone
ObjPtr_SwingingPlatform:dc.l Obj15  ; Swinging platform from Aquatic Ruin Zone
ObjPtr_HTZLift:     dc.l Obj16  ; Diagonally moving lift from HTZ
            dc.l Obj17  ; GHZ rotating log helix spikes (from Sonic 1, unused)
ObjPtr_ARZPlatform:
ObjPtr_EHZPlatform: dc.l Obj18  ; Stationary floating platform from ARZ and EHZ
ObjPtr_CPZPlatform:
ObjPtr_OOZMovingPform:
ObjPtr_WFZPlatform: dc.l Obj19  ; Platform from CPZ, OOZ and WFZ
ObjPtr_HPZCollapsPform: dc.l Obj1A  ; Collapsing platform from HPZ (and GHZ)
ObjPtr_SpeedBooster:    dc.l Obj1B  ; Speed booster from from CPZ
ObjPtr_Scenery:
ObjPtr_BridgeStake:
ObjPtr_FallingOil:  dc.l Obj1C  ; Bridge stake in Emerald Hill Zone and Hill Top Zone, falling oil in Oil Ocean Zone
ObjPtr_BlueBalls:   dc.l Obj1D  ; Blue balls in CPZ (jumping droplets hazard)
ObjPtr_CPZSpinTube: dc.l Obj1E  ; Spin tube from CPZ
ObjPtr_CollapsPform:    dc.l Obj1F  ; Collapsing platform from ARZ, MCZ and OOZ (and MZ, SLZ and SBZ)
ObjPtr_LavaBubble:  dc.l Obj20  ; Lava bubble from Hill Top Zone (boss weapon)
ObjPtr_HUD:     dc.l Obj21  ; Score/Rings/Time display (HUD)
ObjPtr_ArrowShooter:    dc.l Obj22  ; Arrow shooter from ARZ
ObjPtr_FallingPillar:   dc.l Obj23  ; Pillar that drops its lower part from ARZ
ObjPtr_ARZBubbles:  dc.l Obj24  ; Bubbles in Aquatic Ruin Zone
ObjPtr_Ring:        dc.l Obj25  ; A ring
ObjPtr_Monitor:     dc.l Obj26  ; Monitor
ObjPtr_Explosion:   dc.l Obj27  ; An explosion, giving off an animal and 100 points
ObjPtr_Animal:      dc.l Obj28  ; Animal and the 100 points from a badnik
ObjPtr_Points:      dc.l Obj29  ; "100 points" text
ObjPtr_Stomper:     dc.l Obj2A  ; Stomper from MCZ
ObjPtr_RisingPillar:    dc.l Obj2B  ; Rising pillar from ARZ
ObjPtr_LeavesGenerator: dc.l Obj2C  ; Sprite that makes leaves fly off when you hit it from ARZ
ObjPtr_Barrier:     dc.l Obj2D  ; One way barrier from CPZ and DEZ
ObjPtr_MonitorContents: dc.l Obj2E  ; Monitor contents (code for power-up behavior and rising image)
ObjPtr_SmashableGround: dc.l Obj2F  ; Smashable ground in Hill Top Zone
ObjPtr_RisingLava:  dc.l Obj30  ; Large rising lava during earthquake in HTZ
ObjPtr_LavaMarker:  dc.l Obj31  ; Lava collision marker
ObjPtr_BreakableBlock:
ObjPtr_BreakableRock:   dc.l Obj32  ; Breakable block/rock from CPZ and HTZ
ObjPtr_OOZPoppingPform: dc.l Obj33  ; Green platform from OOZ
ObjPtr_TitleCard:   dc.l Obj34  ; level title card (screen with red, yellow, and blue)
ObjPtr_InvStars:    dc.l Obj35  ; Invincibility Stars
ObjPtr_Spikes:      dc.l Obj36  ; Vertical spikes
ObjPtr_LostRings:   dc.l Obj37  ; Scattering rings (generated when Sonic is hurt and has rings)
ObjPtr_Shield:      dc.l Obj38  ; Shield
ObjPtr_GameOver:
ObjPtr_TimeOver:    dc.l Obj39  ; Game/Time Over text
ObjPtr_Results:     dc.l Obj3A  ; End of level results screen
            dc.l Obj3B  ; Purple rock (from Sonic 1, unused)
            dc.l Obj3C  ; Breakable wall (leftover from S1) (mostly unused)
ObjPtr_OOZLauncher: dc.l Obj3D  ; Block thingy in OOZ that launches you into the round ball things
ObjPtr_EggPrison:   dc.l Obj3E  ; Egg prison
ObjPtr_Fan:     dc.l Obj3F  ; Fan from OOZ
ObjPtr_Springboard: dc.l Obj40  ; Pressure spring from CPZ, ARZ, and MCZ (the red "diving board" springboard)
ObjPtr_Spring:      dc.l Obj41  ; Spring
ObjPtr_SteamSpring: dc.l Obj42  ; Steam Spring from MTZ
ObjPtr_SlidingSpike:    dc.l Obj43  ; Sliding spike obstacle thing from OOZ
ObjPtr_RoundBumper: dc.l Obj44  ; Round bumper from Casino Night Zone
ObjPtr_OOZSpring:   dc.l Obj45  ; Pressure spring from OOZ
ObjPtr_OOZBall:     dc.l Obj46  ; Ball from OOZ (unused, beta leftover)
ObjPtr_Button:      dc.l Obj47  ; Button
ObjPtr_LauncherBall:    dc.l Obj48  ; Round ball thing from OOZ that fires you off in a different direction
ObjPtr_EHZWaterfall:    dc.l Obj49  ; Waterfall from EHZ
ObjPtr_Octus:       dc.l Obj4A  ; Octus (octopus badnik) from OOZ
ObjPtr_Buzzer:      dc.l Obj4B  ; Buzzer (Buzz bomber) from EHZ
            dc.l ObjNull    ; Obj4C
            dc.l ObjNull    ; Obj4D
            dc.l ObjNull    ; Obj4E
            dc.l ObjNull    ; Obj4F
ObjPtr_Aquis:       dc.l Obj50  ; Aquis (seahorse badnik) from OOZ
ObjPtr_CNZBoss:     dc.l Obj51  ; CNZ boss
ObjPtr_HTZBoss:     dc.l Obj52  ; HTZ boss
ObjPtr_MTZBossOrb:  dc.l Obj53  ; Shield orbs that surround MTZ boss
ObjPtr_MTZBoss:     dc.l Obj54  ; MTZ boss
ObjPtr_OOZBoss:     dc.l Obj55  ; OOZ boss
ObjPtr_EHZBoss:     dc.l Obj56  ; EHZ boss
ObjPtr_MCZBoss:     dc.l Obj57  ; MCZ boss
ObjPtr_BossExplosion:   dc.l Obj58  ; Boss explosion
ObjPtr_SSEmerald:   dc.l Obj59  ; Emerald from Special Stage
ObjPtr_SSMessage:   dc.l Obj5A  ; Messages/checkpoint from Special Stage
ObjPtr_SSRingSpill: dc.l Obj5B  ; Ring spray/spill in Special Stage
ObjPtr_Masher:      dc.l Obj5C  ; Masher (jumping piranha fish badnik) from EHZ
ObjPtr_CPZBoss:     dc.l Obj5D  ; CPZ boss
ObjPtr_SSHUD:       dc.l Obj5E  ; HUD from Special Stage
ObjPtr_StartBanner:
ObjPtr_EndingController:dc.l Obj5F  ; Start banner/"Ending controller" from Special Stage
ObjPtr_SSRing:      dc.l Obj60  ; Rings from Special Stage
ObjPtr_SSBomb:      dc.l Obj61  ; Bombs from Special Stage
            dc.l ObjNull    ; Obj62
ObjPtr_SSShadow:    dc.l Obj63  ; Character shadow from Special Stage
ObjPtr_MTZTwinStompers: dc.l Obj64  ; Twin stompers from MTZ
ObjPtr_MTZLongPlatform: dc.l Obj65  ; Long moving platform from MTZ
ObjPtr_MTZSpringWall:   dc.l Obj66  ; Yellow spring walls from MTZ
ObjPtr_MTZSpinTube: dc.l Obj67  ; Spin tube from MTZ
ObjPtr_SpikyBlock:  dc.l Obj68  ; Block with a spike that comes out of each side sequentially from MTZ
ObjPtr_Nut:     dc.l Obj69  ; Nut from MTZ
ObjPtr_MCZRotPforms:
ObjPtr_MTZMovingPforms: dc.l Obj6A  ; Platform that moves when you walk off of it, from MTZ
ObjPtr_MTZPlatform:
ObjPtr_CPZSquarePform:  dc.l Obj6B  ; Immobile platform from MTZ
ObjPtr_Conveyor:    dc.l Obj6C  ; Small platform on pulleys (like at the start of MTZ2)
ObjPtr_FloorSpike:  dc.l Obj6D  ; Floor spike from MTZ
ObjPtr_LargeRotPform:   dc.l Obj6E  ; Platform moving in a circle (like at the start of MTZ3)
ObjPtr_SSResults:   dc.l Obj6F  ; End of special stage results screen
ObjPtr_Cog:     dc.l Obj70  ; Giant rotating cog from MTZ
ObjPtr_MTZLavaBubble:
ObjPtr_HPZBridgeStake:
ObjPtr_PulsingOrb:  dc.l Obj71  ; Bridge stake and pulsing orb from Hidden Palace Zone
ObjPtr_CNZConveyorBelt: dc.l Obj72  ; Conveyor belt from CNZ
ObjPtr_RotatingRings:   dc.l Obj73  ; Solid rotating ring thing from Mystic Cave Zone (mostly unused)
ObjPtr_InvisibleBlock:  dc.l Obj74  ; Invisible solid block
ObjPtr_MCZBrick:    dc.l Obj75  ; Brick from MCZ
ObjPtr_SlidingSpikes:   dc.l Obj76  ; Spike block that slides out of the wall from MCZ
ObjPtr_MCZBridge:   dc.l Obj77  ; Bridge from MCZ
ObjPtr_CPZStaircase:    dc.l Obj78  ; Stairs from CPZ that move down to open the way
ObjPtr_Starpost:    dc.l Obj79  ; Star pole / starpost / checkpoint
ObjPtr_SidewaysPform:   dc.l Obj7A  ; Platform that moves back and fourth on top of water in CPZ
ObjPtr_PipeExitSpring:  dc.l Obj7B  ; Warp pipe exit spring from CPZ
ObjPtr_CPZPylon:    dc.l Obj7C  ; Big pylon in foreground of CPZ
            dc.l Obj7D  ; Points that can be gotten at the end of an act (unused leftover from S1)
ObjPtr_SuperSonicStars: dc.l Obj7E  ; Super Sonic's stars
ObjPtr_VineSwitch:  dc.l Obj7F  ; Vine switch that you hang off in MCZ
ObjPtr_MovingVine:  dc.l Obj80  ; Vine that you hang off and it moves down from MCZ
ObjPtr_MCZDrawbridge:   dc.l Obj81  ; Long invisible vertical barrier
ObjPtr_SwingingPform:   dc.l Obj82  ; Platform that is usually swinging, from ARZ
ObjPtr_ARZRotPforms:    dc.l Obj83  ; 3 adjoined platforms from ARZ that rotate in a circle
ObjPtr_ForcedSpin:
ObjPtr_PinballMode: dc.l Obj84  ; Pinball mode enable/disable (CNZ)
ObjPtr_LauncherSpring:  dc.l Obj85  ; Spring from CNZ that you hold jump on to pull back further
ObjPtr_Flipper:     dc.l Obj86  ; Flipper from CNZ
ObjPtr_SSNumberOfRings: dc.l Obj87  ; Number of rings in Special Stage
ObjPtr_SSTailsTails:    dc.l Obj88  ; Tails' tails in Special Stage
ObjPtr_ARZBoss:     dc.l Obj89  ; ARZ boss
            dc.l Obj8A  ; Sonic Team Presents/Credits (seemingly unused leftover from S1)
ObjPtr_WFZPalSwitcher:  dc.l Obj8B  ; Cycling palette switcher from Wing Fortress Zone
ObjPtr_Whisp:       dc.l Obj8C  ; Whisp (blowfly badnik) from ARZ
ObjPtr_GrounderInWall:  dc.l Obj8D  ; Grounder in wall, from ARZ
ObjPtr_GrounderInWall2: dc.l Obj8D  ; Obj8E = Obj8D
ObjPtr_GrounderWall:    dc.l Obj8F  ; Wall behind which Grounder hides, from ARZ
ObjPtr_GrounderRocks:   dc.l Obj90  ; Rocks thrown by Grounder behind wall, from ARZ
ObjPtr_ChopChop:    dc.l Obj91  ; Chop Chop (piranha/shark badnik) from ARZ
ObjPtr_Spiker:      dc.l Obj92  ; Spiker (drill badnik) from HTZ
ObjPtr_SpikerDrill: dc.l Obj93  ; Drill thrown by Spiker from HTZ
ObjPtr_Rexon:       dc.l Obj94  ; Rexon (lava snake badnik), from HTZ
ObjPtr_Sol:     dc.l Obj95  ; Sol (fireball-throwing orbit badnik) from HTZ
ObjPtr_Rexon2:      dc.l Obj94  ; Obj96 = Obj94
ObjPtr_RexonHead:   dc.l Obj97  ; Rexon's head, from HTZ
ObjPtr_Projectile:  dc.l Obj98  ; Projectile with optional gravity (EHZ coconut, CPZ spiny, etc.)
ObjPtr_Nebula:      dc.l Obj99  ; Nebula (bomber badnik) from SCZ
ObjPtr_Turtloid:    dc.l Obj9A  ; Turtloid (turtle badnik) from Sky Chase Zone
ObjPtr_TurtloidRider:   dc.l Obj9B  ; Turtloid rider from Sky Chase Zone
ObjPtr_BalkiryJet:  dc.l Obj9C  ; Balkiry's jet from Sky Chase Zone
ObjPtr_Coconuts:    dc.l Obj9D  ; Coconuts (monkey badnik) from EHZ
ObjPtr_Crawlton:    dc.l Obj9E  ; Crawlton (snake badnik) from MCZ
ObjPtr_Shellcracker:    dc.l Obj9F  ; Shellcraker (crab badnik) from MTZ
ObjPtr_ShellcrackerClaw:dc.l ObjA0  ; Shellcracker's claw from MTZ
ObjPtr_Slicer:      dc.l ObjA1  ; Slicer (praying mantis dude) from MTZ
ObjPtr_SlicerPincers:   dc.l ObjA2  ; Slicer's pincers from MTZ
ObjPtr_Flasher:     dc.l ObjA3  ; Flasher (firefly/glowbug badnik) from MCZ
ObjPtr_Asteron:     dc.l ObjA4  ; Asteron (exploding starfish badnik) from MTZ
ObjPtr_Spiny:       dc.l ObjA5  ; Spiny (crawling badnik) from CPZ
ObjPtr_SpinyOnWall: dc.l ObjA6  ; Spiny (on wall) from CPZ
ObjPtr_Grabber:     dc.l ObjA7  ; Grabber (spider badnik) from CPZ
ObjPtr_GrabberLegs: dc.l ObjA8  ; Grabber's legs from CPZ
ObjPtr_GrabberBox:  dc.l ObjA9  ; The little hanger box thing a Grabber's string comes out of
ObjPtr_GrabberString:   dc.l ObjAA  ; The thin white string a Grabber hangs from
            dc.l ObjAB  ; Unknown (maybe unused?)
ObjPtr_Balkiry:     dc.l ObjAC  ; Balkiry (jet badnik) from SCZ
ObjPtr_CluckerBase: dc.l ObjAD  ; Clucker's base from WFZ
ObjPtr_Clucker:     dc.l ObjAE  ; Clucker (chicken badnik) from WFZ
ObjPtr_MechaSonic:  dc.l ObjAF  ; Mecha Sonic / Silver Sonic from DEZ
ObjPtr_SonicOnSegaScr:  dc.l ObjB0  ; Sonic on the Sega screen
ObjPtr_SegaHideTM:  dc.l ObjB1  ; Object that hides TM symbol on JP region
ObjPtr_Tornado:     dc.l ObjB2  ; The Tornado (Tails' plane)
ObjPtr_Cloud:       dc.l ObjB3  ; Clouds (placeable object) from SCZ
ObjPtr_VPropeller:  dc.l ObjB4  ; Vertical propeller from WFZ
ObjPtr_HPropeller:  dc.l ObjB5  ; Horizontal propeller from WFZ
ObjPtr_TiltingPlatform: dc.l ObjB6  ; Tilting platform from WFZ
ObjPtr_VerticalLaser:   dc.l ObjB7  ; Unused huge vertical laser from WFZ
ObjPtr_WallTurret:  dc.l ObjB8  ; Wall turret from WFZ
ObjPtr_Laser:       dc.l ObjB9  ; Laser from WFZ that shoots down the Tornado
ObjPtr_WFZWheel:    dc.l ObjBA  ; Wheel from WFZ
            dc.l ObjBB  ; Unknown
ObjPtr_WFZShipFire: dc.l ObjBC  ; Fire coming out of Robotnik's ship in WFZ
ObjPtr_SmallMetalPform: dc.l ObjBD  ; Ascending/descending metal platforms from WFZ
ObjPtr_LateralCannon:   dc.l ObjBE  ; Lateral cannon (temporary platform that pops in/out) from WFZ
ObjPtr_WFZStick:    dc.l ObjBF  ; Rotaty-stick badnik from WFZ
ObjPtr_SpeedLauncher:   dc.l ObjC0  ; Speed launcher from WFZ
ObjPtr_BreakablePlating:dc.l ObjC1  ; Breakable plating from WFZ / what sonic hangs onto on the back of Robotnic's getaway ship
ObjPtr_Rivet:       dc.l ObjC2  ; Rivet thing you bust to get into ship at the end of WFZ
ObjPtr_TornadoSmoke:    dc.l ObjC3  ; Plane's smoke from WFZ
ObjPtr_TornadoSmoke2:   dc.l ObjC3  ; ObjC4 = ObjC3
ObjPtr_WFZBoss:     dc.l ObjC5  ; WFZ boss
ObjPtr_Eggman:      dc.l ObjC6  ; Eggman
ObjPtr_Eggrobo:     dc.l ObjC7  ; Eggrobo (final boss) from Death Egg
ObjPtr_Crawl:       dc.l ObjC8  ; Crawl (shield badnik) from CNZ
ObjPtr_TtlScrPalChanger:dc.l ObjC9  ; "Palette changing handler" from title screen
ObjPtr_CutScene:    dc.l ObjCA  ; Cut scene at end of game
ObjPtr_EndingSeqClouds: dc.l ObjCB  ; Background clouds from ending sequence
ObjPtr_EndingSeqTrigger:dc.l ObjCC  ; Trigger for rescue plane and birds from ending sequence
ObjPtr_EndingSeqBird:   dc.l ObjCD  ; Birds from ending sequence
ObjPtr_EndingSeqSonic:
ObjPtr_EndingSeqTails:  dc.l ObjCE  ; Sonic and Tails jumping off the plane from ending sequence
ObjPtr_TornadoHelixes:  dc.l ObjCF  ;"Plane's helixes" from ending sequence
            dc.l ObjNull    ; ObjD0
            dc.l ObjNull    ; ObjD1
ObjPtr_CNZRectBlocks:   dc.l ObjD2  ; Flashing blocks that appear and disappear in a rectangular shape that you can walk across, from CNZ
ObjPtr_BombPrize:   dc.l ObjD3  ; Bomb prize from CNZ
ObjPtr_CNZBigBlock: dc.l ObjD4  ; Big block from CNZ that moves back and fourth
ObjPtr_Elevator:    dc.l ObjD5  ; Elevator from CNZ
ObjPtr_PointPokey:  dc.l ObjD6  ; Pokey that gives out points from CNZ
ObjPtr_Bumper:      dc.l ObjD7  ; Bumper from Casino Night Zone
ObjPtr_BonusBlock:  dc.l ObjD8  ; Block thingy from CNZ that disappears after 3 hits
ObjPtr_Grab:        dc.l ObjD9  ; Invisible sprite that you can hang on to, like the blocks in WFZ
ObjPtr_ContinueText:
ObjPtr_ContinueIcons:   dc.l ObjDA  ; Continue text
ObjPtr_ContinueChars:   dc.l ObjDB  ; Sonic lying down or Tails nagging (continue screen)
ObjPtr_RingPrize:   dc.l ObjDC  ; Ring prize from Casino Night Zone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 4C, 4D, 4E, 4F, 62, D0, and D1
 
; Object removed from the game. All it does is deallocate its array.
; ----------------------------------------------------------------------------
 
ObjNull: ;;
    bra.w   DeleteObject
 
; ---------------------------------------------------------------------------
; Subroutine to make an object move and fall downward increasingly fast
; This moves the object horizontally and vertically
; and also applies gravity to its speed
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16380: ObjectFall:
ObjectMoveAndFall:
    move.l  x_pos(a0),d2    ; load x position
    move.l  y_pos(a0),d3    ; load y position
    move.w  x_vel(a0),d0    ; load x speed
    ext.l   d0
    asl.l   #8,d0   ; shift velocity to line up with the middle 16 bits of the 32-bit position
    add.l   d0,d2   ; add x speed to x position ; note this affects the subpixel position x_sub(a0) = 2+x_pos(a0)
    move.w  y_vel(a0),d0    ; load y speed
    addi.w  #$38,y_vel(a0)  ; increase vertical speed (apply gravity)
    ext.l   d0
    asl.l   #8,d0   ; shift velocity to line up with the middle 16 bits of the 32-bit position
    add.l   d0,d3   ; add old y speed to y position ; note this affects the subpixel position y_sub(a0) = 2+y_pos(a0)
    move.l  d2,x_pos(a0)    ; store new x position
    move.l  d3,y_pos(a0)    ; store new y position
    rts
; End of function ObjectMoveAndFall
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
; ---------------------------------------------------------------------------
; Subroutine translating object speed to update object position
; This moves the object horizontally and vertically
; but does not apply gravity to it
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_163AC: SpeedToPos:
ObjectMove:
    move.l  x_pos(a0),d2    ; load x position
    move.l  y_pos(a0),d3    ; load y position
    move.w  x_vel(a0),d0    ; load horizontal speed
    ext.l   d0
    asl.l   #8,d0   ; shift velocity to line up with the middle 16 bits of the 32-bit position
    add.l   d0,d2   ; add to x-axis position    ; note this affects the subpixel position x_sub(a0) = 2+x_pos(a0)
    move.w  y_vel(a0),d0    ; load vertical speed
    ext.l   d0
    asl.l   #8,d0   ; shift velocity to line up with the middle 16 bits of the 32-bit position
    add.l   d0,d3   ; add to y-axis position    ; note this affects the subpixel position y_sub(a0) = 2+y_pos(a0)
    move.l  d2,x_pos(a0)    ; update x-axis position
    move.l  d3,y_pos(a0)    ; update y-axis position
    rts
; End of function ObjectMove
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
; ---------------------------------------------------------------------------
; Routines to mark an enemy/monitor/ring/platform as destroyed
; ---------------------------------------------------------------------------
 
; ===========================================================================
; input: a0 = the object
; loc_163D2:
MarkObjGone:
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.s   +           ; if not, branch
    bra.w   DisplaySprite
+
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$80+320+$40+$80,d0 ; This gives an object $80 pixels of room offscreen before being unloaded (the $40 is there to round up 320 to a multiple of $80)
    bhi.w   +
    bra.w   DisplaySprite
 
+   lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    bra.w   DeleteObject
; ===========================================================================
; input: d0 = the object's x position
; loc_1640A:
MarkObjGone2:
    tst.w   (Two_player_mode).w
    beq.s   +
    bra.w   DisplaySprite
+
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$80+320+$40+$80,d0 ; This gives an object $80 pixels of room offscreen before being unloaded (the $40 is there to round up 320 to a multiple of $80)
    bhi.w   +
    bra.w   DisplaySprite
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    bra.w   DeleteObject
; ===========================================================================
; input: a0 = the object
; does nothing instead of calling DisplaySprite in the case of no deletion
; loc_1643E:
MarkObjGone3:
    tst.w   (Two_player_mode).w
    beq.s   +
    rts
+
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$80+320+$40+$80,d0 ; This gives an object $80 pixels of room offscreen before being unloaded (the $40 is there to round up 320 to a multiple of $80)
    bhi.w   +
    rts
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    bra.w   DeleteObject
; ===========================================================================
; input: a0 = the object
; loc_16472:
MarkObjGone_P1:
    tst.w   (Two_player_mode).w
    bne.s   MarkObjGone_P2
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$80+320+$40+$80,d0 ; This gives an object $80 pixels of room offscreen before being unloaded (the $40 is there to round up 320 to a multiple of $80)
    bhi.w   +
    bra.w   DisplaySprite
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    bra.w   DeleteObject
; ---------------------------------------------------------------------------
; input: a0 = the object
; loc_164A6:
MarkObjGone_P2:
    move.w  x_pos(a0),d0
    andi.w  #$FF00,d0
    move.w  d0,d1
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$300,d0
    bhi.w   +
    bra.w   DisplaySprite
+
    sub.w   (Camera_X_pos_coarse_P2).w,d1
    cmpi.w  #$300,d1
    bhi.w   +
    bra.w   DisplaySprite
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    bra.w   DeleteObject ; useless branch...
 
; ---------------------------------------------------------------------------
; Subroutine to delete an object
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; freeObject:
DeleteObject:
    movea.l a0,a1
 
; sub_164E8:
DeleteObject2:
    moveq   #0,d1
 
    moveq   #bytesToLcnt(next_object),d0 ; we want to clear up to the next object
    ; delete the object by setting all of its bytes to 0
-   move.l  d1,(a1)+
    dbf d0,-
    if object_size&3
    move.w  d1,(a1)+
    endif
 
    rts
; End of function DeleteObject2
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to display a sprite/object, when a0 is the object RAM
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_164F4:
DisplaySprite:
    lea (Sprite_Table_Input).w,a1
    move.w  priority(a0),d0
    lsr.w   #1,d0
    andi.w  #$380,d0
    adda.w  d0,a1
    cmpi.w  #$7E,(a1)
    bhs.s   return_16510
    addq.w  #2,(a1)
    adda.w  (a1),a1
    move.w  a0,(a1)
 
return_16510:
    rts
; End of function DisplaySprite
 
; ---------------------------------------------------------------------------
; Subroutine to display a sprite/object, when a1 is the object RAM
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16512:
DisplaySprite2:
    lea (Sprite_Table_Input).w,a2
    move.w  priority(a1),d0
    lsr.w   #1,d0
    andi.w  #$380,d0
    adda.w  d0,a2
    cmpi.w  #$7E,(a2)
    bhs.s   return_1652E
    addq.w  #2,(a2)
    adda.w  (a2),a2
    move.w  a1,(a2)
 
return_1652E:
    rts
; End of function DisplaySprite2
 
; ---------------------------------------------------------------------------
; Subroutine to display a sprite/object, when a0 is the object RAM
; and d0 is already (priority/2)&$380
; ---------------------------------------------------------------------------
 
; loc_16530:
DisplaySprite3:
    lea (Sprite_Table_Input).w,a1
    adda.w  d0,a1
    cmpi.w  #$7E,(a1)
    bhs.s   return_16542
    addq.w  #2,(a1)
    adda.w  (a1),a1
    move.w  a0,(a1)
 
return_16542:
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to animate a sprite using an animation script
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16544:
AnimateSprite:
    moveq   #0,d0
    move.b  anim(a0),d0     ; move animation number to d0
    cmp.b   next_anim(a0),d0    ; is animation set to change?
    beq.s   Anim_Run        ; if not, branch
    move.b  d0,next_anim(a0)    ; set next anim to current current
    move.b  #0,anim_frame(a0)   ; reset animation
    move.b  #0,anim_frame_duration(a0)  ; reset frame duration
; loc_16560:
Anim_Run:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.s   Anim_Wait   ; if time remains, branch
    add.w   d0,d0
    adda.w  (a1,d0.w),a1    ; calculate address of appropriate animation script
    move.b  (a1),anim_frame_duration(a0)    ; load frame duration
    moveq   #0,d1
    move.b  anim_frame(a0),d1   ; load current frame number
    move.b  1(a1,d1.w),d0       ; read sprite number from script
    bmi.s   Anim_End_FF     ; if animation is complete, branch
; loc_1657C:
Anim_Next:
    andi.b  #$7F,d0         ; clear sign bit
    move.b  d0,mapping_frame(a0)    ; load sprite number
    move.b  status(a0),d1       ;* match the orientaion dictated by the object
    andi.b  #3,d1           ;* with the orientation used by the object engine
    andi.b  #$FC,render_flags(a0)   ;*
    or.b    d1,render_flags(a0) ;*
    addq.b  #1,anim_frame(a0)   ; next frame number
; return_1659A:
Anim_Wait:
    rts
; ===========================================================================
; loc_1659C:
Anim_End_FF:
    addq.b  #1,d0       ; is the end flag = $FF ?
    bne.s   Anim_End_FE ; if not, branch
    move.b  #0,anim_frame(a0)   ; restart the animation
    move.b  1(a1),d0    ; read sprite number
    bra.s   Anim_Next
; ===========================================================================
; loc_165AC:
Anim_End_FE:
    addq.b  #1,d0   ; is the end flag = $FE ?
    bne.s   Anim_End_FD ; if not, branch
    move.b  2(a1,d1.w),d0   ; read the next byte in the script
    sub.b   d0,anim_frame(a0)   ; jump back d0 bytes in the script
    sub.b   d0,d1
    move.b  1(a1,d1.w),d0   ; read sprite number
    bra.s   Anim_Next
; ===========================================================================
; loc_165C0:
Anim_End_FD:
    addq.b  #1,d0       ; is the end flag = $FD ?
    bne.s   Anim_End_FC ; if not, branch
    move.b  2(a1,d1.w),anim(a0) ; read next byte, run that animation
    rts
; ===========================================================================
; loc_165CC:
Anim_End_FC:
    addq.b  #1,d0   ; is the end flag = $FC ?
    bne.s   Anim_End_FB ; if not, branch
    addq.b  #2,routine(a0)  ; jump to next routine
    move.b  #0,anim_frame_duration(a0)
    addq.b  #1,anim_frame(a0)
    rts
; ===========================================================================
; loc_165E0:
Anim_End_FB:
    addq.b  #1,d0   ; is the end flag = $FB ?
    bne.s   Anim_End_FA ; if not, branch
    move.b  #0,anim_frame(a0)   ; reset animation
    clr.b   routine_secondary(a0)   ; reset 2nd routine counter
    rts
; ===========================================================================
; loc_165F0:
Anim_End_FA:
    addq.b  #1,d0   ; is the end flag = $FA ?
    bne.s   Anim_End_F9 ; if not, branch
    addq.b  #2,routine_secondary(a0)    ; jump to next routine
    rts
; ===========================================================================
; loc_165FA:
Anim_End_F9:
    addq.b  #1,d0   ; is the end flag = $F9 ?
    bne.s   Anim_End    ; if not, branch
    addq.b  #2,objoff_2A(a0)
; return_16602:
Anim_End:
    rts
; End of function AnimateSprite
 
 
; ---------------------------------------------------------------------------
; Subroutine to convert mappings (etc) to proper Megadrive sprites
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16604:
BuildSprites:
    tst.w   (Two_player_mode).w
    bne.w   BuildSprites_2P
    lea (Sprite_Table).w,a2
    moveq   #0,d5
    moveq   #0,d4
    tst.b   (Level_started_flag).w
    beq.s   +
    jsrto   (BuildHUD).l, JmpTo_BuildHUD
    bsr.w   BuildRings
+
    lea (Sprite_Table_Input).w,a4
    moveq   #7,d7   ; 8 priority levels
; loc_16628:
BuildSprites_LevelLoop:
    tst.w   (a4)    ; does this level have any objects?
    beq.w   BuildSprites_NextLevel  ; if not, check the next one
    moveq   #2,d6
; loc_16630:
BuildSprites_ObjLoop:
    movea.w (a4,d6.w),a0 ; a0=object
 
    if gameRevision=0
    ; the additional check prevents a crash triggered by placing an object in debug mode while dead
    ; unfortunately, the code it branches *to* causes a crash of its own
    tst.b   id(a0)          ; is this object slot occupied?
    beq.w   BuildSprites_Unknown    ; if not, branch
    tst.l   mappings(a0)        ; does this object have any mappings?
    beq.w   BuildSprites_Unknown    ; if not, branch
    else
    ; REV01 uses a better branch, but removed the useful check
    tst.b   id(a0)          ; is this object slot occupied?
    beq.w   BuildSprites_NextObj    ; if not, check next one
    endif
 
    andi.b  #$7F,render_flags(a0)   ; clear on-screen flag
    move.b  render_flags(a0),d0
    move.b  d0,d4
    btst    #6,d0   ; is the multi-draw flag set?
    bne.w   BuildSprites_MultiDraw  ; if it is, branch
    andi.w  #$C,d0  ; is this to be positioned by screen coordinates?
    beq.s   BuildSprites_ScreenSpaceObj ; if it is, branch
    lea (Camera_X_pos_copy).w,a1
    moveq   #0,d0
    move.b  width_pixels(a0),d0
    move.w  x_pos(a0),d3
    sub.w   (a1),d3
    move.w  d3,d1
    add.w   d0,d1   ; is the object right edge to the left of the screen?
    bmi.w   BuildSprites_NextObj    ; if it is, branch
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1 ; is the object left edge to the right of the screen?
    bge.w   BuildSprites_NextObj    ; if it is, branch
    addi.w  #128,d3
    btst    #4,d4       ; is the accurate Y check flag set?
    beq.s   BuildSprites_ApproxYCheck   ; if not, branch
    moveq   #0,d0
    move.b  y_radius(a0),d0
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.s   BuildSprites_NextObj    ; if the object is above the screen
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.s   BuildSprites_NextObj    ; if the object is below the screen
    addi.w  #128,d2
    bra.s   BuildSprites_DrawSprite
; ===========================================================================
; loc_166A6:
BuildSprites_ScreenSpaceObj:
    move.w  y_pixel(a0),d2
    move.w  x_pixel(a0),d3
    bra.s   BuildSprites_DrawSprite
; ===========================================================================
; loc_166B0:
BuildSprites_ApproxYCheck:
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    addi.w  #128,d2
    andi.w  #$7FF,d2
    cmpi.w  #-32+128,d2 ; assume Y radius to be 32 pixels
    blo.s   BuildSprites_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_NextObj
; loc_166CC:
BuildSprites_DrawSprite:
    movea.l mappings(a0),a1
    moveq   #0,d1
    btst    #5,d4   ; is the static mappings flag set?
    bne.s   +   ; if it is, branch
    move.b  mapping_frame(a0),d1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1   ; get number of pieces
    bmi.s   ++  ; if there are 0 pieces, branch
+
    bsr.w   DrawSprite  ; draw the sprite
+
    ori.b   #$80,render_flags(a0)   ; set on-screen flag
; loc_166F2:
BuildSprites_NextObj:
    addq.w  #2,d6   ; load next object
    subq.w  #2,(a4) ; decrement object count
    bne.w   BuildSprites_ObjLoop    ; if there are objects left, repeat
; loc_166FA:
BuildSprites_NextLevel:
    lea $80(a4),a4  ; load next priority level
    dbf d7,BuildSprites_LevelLoop   ; loop
    move.b  d5,(Sprite_count).w
    cmpi.b  #80,d5  ; was the sprite limit reached?
    beq.s   +   ; if it was, branch
    move.l  #0,(a2) ; set link field to 0
    rts
+
    move.b  #0,-5(a2)   ; set link field to 0
    rts
; ===========================================================================
    if gameRevision=0
BuildSprites_Unknown:
    ; in the Simon Wai beta, this was a simple BranchTo, but later builds have this mystery line
    move.w  (1).w,d0    ; causes a crash on hardware because of the word operation at an odd address
    bra.s   BuildSprites_NextObj
    endif
; loc_1671C:
BuildSprites_MultiDraw:
    move.l  a4,-(sp)
    lea (Camera_X_pos).w,a4
    movea.w art_tile(a0),a3
    movea.l mappings(a0),a5
    moveq   #0,d0
    
    ; check if object is within X bounds
    move.b  mainspr_width(a0),d0    ; load pixel width
    move.w  x_pos(a0),d3
    sub.w   (a4),d3
    move.w  d3,d1
    add.w   d0,d1
    bmi.w   BuildSprites_MultiDraw_NextObj
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1
    bge.w   BuildSprites_MultiDraw_NextObj
    addi.w  #128,d3
    
    ; check if object is within Y bounds
    btst    #4,d4
    beq.s   +
    moveq   #0,d0
    move.b  mainspr_height(a0),d0   ; load pixel height
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.w   BuildSprites_MultiDraw_NextObj
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.w   BuildSprites_MultiDraw_NextObj
    addi.w  #128,d2
    bra.s   ++
+
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    addi.w  #128,d2
    andi.w  #$7FF,d2
    cmpi.w  #-32+128,d2
    blo.s   BuildSprites_MultiDraw_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_MultiDraw_NextObj
+
    moveq   #0,d1
    move.b  mainspr_mapframe(a0),d1 ; get current frame
    beq.s   +
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite   ; draw the sprite
    move.w  (sp)+,d4
+
    ori.b   #$80,render_flags(a0)   ; set onscreen flag
    lea sub2_x_pos(a0),a6
    moveq   #0,d0
    move.b  mainspr_childsprites(a0),d0 ; get child sprite count
    subq.w  #1,d0       ; if there are 0, go to next object
    bcs.s   BuildSprites_MultiDraw_NextObj
 
-   swap    d0
    move.w  (a6)+,d3    ; get X pos
    sub.w   (a4),d3
    addi.w  #128,d3
    move.w  (a6)+,d2    ; get Y pos
    sub.w   4(a4),d2
    addi.w  #128,d2
    andi.w  #$7FF,d2
    addq.w  #1,a6
    moveq   #0,d1
    move.b  (a6)+,d1    ; get mapping frame
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite
    move.w  (sp)+,d4
+
    swap    d0
    dbf d0,-    ; repeat for number of child sprites
; loc_16804:
BuildSprites_MultiDraw_NextObj:
    movea.l (sp)+,a4
    bra.w   BuildSprites_NextObj
; End of function BuildSprites
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1680A:
ChkDrawSprite:
    cmpi.b  #80,d5      ; has the sprite limit been reached?
    blo.s   DrawSprite_Cont ; if it hasn't, branch
    rts ; otherwise, return
; End of function ChkDrawSprite
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16812:
DrawSprite:
    movea.w art_tile(a0),a3
    cmpi.b  #80,d5
    bhs.s   DrawSprite_Done
; loc_1681C:
DrawSprite_Cont:
    btst    #0,d4   ; is the sprite to be X-flipped?
    bne.s   DrawSprite_FlipX    ; if it is, branch
    btst    #1,d4   ; is the sprite to be Y-flipped?
    bne.w   DrawSprite_FlipY    ; if it is, branch
; loc__1682A:
DrawSprite_Loop:
    move.b  (a1)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,(a2)+    ; set Y pos
    move.b  (a1)+,(a2)+ ; set sprite size
    addq.b  #1,d5
    move.b  d5,(a2)+    ; set link field
    move.w  (a1)+,d0
    add.w   a3,d0
    move.w  d0,(a2)+    ; set art tile and flags
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0   ; avoid activating sprite masking
+
    move.w  d0,(a2)+    ; set X pos
    dbf d1,DrawSprite_Loop  ; repeat for next sprite
; return_16852:
DrawSprite_Done:
    rts
; ===========================================================================
; loc_16854:
DrawSprite_FlipX:
    btst    #1,d4   ; is it to be Y-flipped as well?
    bne.w   DrawSprite_FlipXY   ; if it is, branch
 
-   move.b  (a1)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4    ; store size for later use
    move.b  d4,(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$800,d0    ; toggle X flip flag
    move.w  d0,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    neg.w   d0  ; negate X offset
    move.b  CellOffsets_XFlip(pc,d4.w),d4
    sub.w   d4,d0   ; subtract sprite size
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,-
 
    rts
; ===========================================================================
; offsets for horizontally mirrored sprite pieces
CellOffsets_XFlip:
    dc.b   8,  8,  8,  8    ; 4
    dc.b $10,$10,$10,$10    ; 8
    dc.b $18,$18,$18,$18    ; 12
    dc.b $20,$20,$20,$20    ; 16
; offsets for vertically mirrored sprite pieces
CellOffsets_YFlip:
    dc.b   8,$10,$18,$20    ; 4
    dc.b   8,$10,$18,$20    ; 8
    dc.b   8,$10,$18,$20    ; 12
    dc.b   8,$10,$18,$20    ; 16
; ===========================================================================
; loc_168B4:
DrawSprite_FlipY:
    move.b  (a1)+,d0
    move.b  (a1),d4
    ext.w   d0
    neg.w   d0
    move.b  CellOffsets_YFlip(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d2,d0
    move.w  d0,(a2)+    ; set Y pos
    move.b  (a1)+,(a2)+ ; set size
    addq.b  #1,d5
    move.b  d5,(a2)+    ; set link field
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$1000,d0   ; toggle Y flip flag
    move.w  d0,(a2)+    ; set art tile and flags
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+    ; set X pos
    dbf d1,DrawSprite_FlipY
    rts
; ===========================================================================
; offsets for vertically mirrored sprite pieces
CellOffsets_YFlip2:
    dc.b   8,$10,$18,$20    ; 4
    dc.b   8,$10,$18,$20    ; 8
    dc.b   8,$10,$18,$20    ; 12
    dc.b   8,$10,$18,$20    ; 16
; ===========================================================================
; loc_168FC:
DrawSprite_FlipXY:
    move.b  (a1)+,d0
    move.b  (a1),d4
    ext.w   d0
    neg.w   d0
    move.b  CellOffsets_YFlip2(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4
    move.b  d4,(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$1800,d0   ; toggle X and Y flip flags
    move.w  d0,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    neg.w   d0
    move.b  CellOffsets_XFlip2(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,DrawSprite_FlipXY
    rts
; End of function DrawSprite
 
; ===========================================================================
; offsets for horizontally mirrored sprite pieces
CellOffsets_XFlip2:
    dc.b   8,  8,  8,  8    ; 4
    dc.b $10,$10,$10,$10    ; 8
    dc.b $18,$18,$18,$18    ; 12
    dc.b $20,$20,$20,$20    ; 16
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to convert mappings (etc) to proper Megadrive sprites
; for 2-player (split screen) mode
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1694E:
BuildSprites_2P:
    lea (Sprite_Table).w,a2
    moveq   #2,d5
    moveq   #0,d4
    move.l  #$1D80F01,(a2)+ ; mask all sprites
    move.l  #1,(a2)+
    move.l  #$1D80F02,(a2)+ ; from 216px to 248px
    move.l  #0,(a2)+
    tst.b   (Level_started_flag).w
    beq.s   +
    jsrto   (BuildHUD_P1).l, JmpTo_BuildHUD_P1
    bsr.w   BuildRings_P1
+
    lea (Sprite_Table_Input).w,a4
    moveq   #7,d7
; loc_16982:
BuildSprites_P1_LevelLoop:
    move.w  (a4),d0 ; does this priority level have any objects?
    beq.w   BuildSprites_P1_NextLevel   ; if not, check next one
    move.w  d0,-(sp)
    moveq   #2,d6
; loc_1698C:
BuildSprites_P1_ObjLoop:
    movea.w (a4,d6.w),a0 ; a0=object
    tst.b   id(a0)
    beq.w   BuildSprites_P1_NextObj
    andi.b  #$7F,render_flags(a0)
    move.b  render_flags(a0),d0
    move.b  d0,d4
    btst    #6,d0
    bne.w   BuildSprites_P1_MultiDraw
    andi.w  #$C,d0
    beq.s   BuildSprites_P1_ScreenSpaceObj
    lea (Camera_X_pos).w,a1
    moveq   #0,d0
    move.b  width_pixels(a0),d0
    move.w  x_pos(a0),d3
    sub.w   (a1),d3
    move.w  d3,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P1_NextObj
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1
    bge.s   BuildSprites_P1_NextObj
    addi.w  #128,d3
    btst    #4,d4
    beq.s   BuildSprites_P1_ApproxYCheck
    moveq   #0,d0
    move.b  y_radius(a0),d0
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.s   BuildSprites_P1_NextObj
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.s   BuildSprites_P1_NextObj
    addi.w  #256,d2
    bra.s   BuildSprites_P1_DrawSprite
; ===========================================================================
; loc_16A00:
BuildSprites_P1_ScreenSpaceObj:
    move.w  y_pixel(a0),d2
    move.w  x_pixel(a0),d3
    addi.w  #128,d2
    bra.s   BuildSprites_P1_DrawSprite
; ===========================================================================
; loc_16A0E:
BuildSprites_P1_ApproxYCheck:
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    addi.w  #128,d2
    cmpi.w  #-32+128,d2
    blo.s   BuildSprites_P1_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_P1_NextObj
    addi.w  #128,d2
; loc_16A2A:
BuildSprites_P1_DrawSprite:
    movea.l mappings(a0),a1
    moveq   #0,d1
    btst    #5,d4
    bne.s   +
    move.b  mapping_frame(a0),d1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   ++
+
    bsr.w   DrawSprite_2P
+
    ori.b   #$80,render_flags(a0)
; loc_16A50:
BuildSprites_P1_NextObj:
    addq.w  #2,d6
    subq.w  #2,(sp)
    bne.w   BuildSprites_P1_ObjLoop
    addq.w  #2,sp
; loc_16A5A:
BuildSprites_P1_NextLevel:
    lea $80(a4),a4
    dbf d7,BuildSprites_P1_LevelLoop
    move.b  d5,(Sprite_count).w
    cmpi.b  #80,d5
    bhs.s   +
    move.l  #0,(a2)
    bra.s   BuildSprites_P2
+
    move.b  #0,-5(a2)
 
; build sprites for player 2
 
; loc_16A7A:
BuildSprites_P2:
    tst.w   (Hint_flag).w   ; has H-int occured yet?
    bne.s   BuildSprites_P2 ; if not, wait
    lea (Sprite_Table_2).w,a2
    moveq   #0,d5
    moveq   #0,d4
    tst.b   (Level_started_flag).w
    beq.s   +
    jsrto   (BuildHUD_P2).l, JmpTo_BuildHUD_P2
    bsr.w   BuildRings_P2
+
    lea (Sprite_Table_Input).w,a4
    moveq   #7,d7
; loc_16A9C:
BuildSprites_P2_LevelLoop:
    move.w  (a4),d0
    beq.w   BuildSprites_P2_NextLevel
    move.w  d0,-(sp)
    moveq   #2,d6
; loc_16AA6:
BuildSprites_P2_ObjLoop:
    movea.w (a4,d6.w),a0 ; a0=object
    tst.b   id(a0)
    beq.w   BuildSprites_P2_NextObj
    move.b  render_flags(a0),d0
    move.b  d0,d4
    btst    #6,d0
    bne.w   BuildSprites_P2_MultiDraw
    andi.w  #$C,d0
    beq.s   BuildSprites_P2_ScreenSpaceObj
    lea (Camera_X_pos_P2).w,a1
    moveq   #0,d0
    move.b  width_pixels(a0),d0
    move.w  x_pos(a0),d3
    sub.w   (a1),d3
    move.w  d3,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P2_NextObj
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1
    bge.s   BuildSprites_P2_NextObj
    addi.w  #128,d3
    btst    #4,d4
    beq.s   BuildSprites_P2_ApproxYCheck
    moveq   #0,d0
    move.b  y_radius(a0),d0
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.s   BuildSprites_P2_NextObj
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.s   BuildSprites_P2_NextObj
    addi.w  #256+224,d2
    bra.s   BuildSprites_P2_DrawSprite
; ===========================================================================
; loc_16B14:
BuildSprites_P2_ScreenSpaceObj:
    move.w  y_pixel(a0),d2
    move.w  x_pixel(a0),d3
    addi.w  #$160,d2
    bra.s   BuildSprites_P2_DrawSprite
; ===========================================================================
; loc_16B22:
BuildSprites_P2_ApproxYCheck:
    move.w  y_pos(a0),d2
    sub.w   4(a1),d2
    addi.w  #128,d2
    cmpi.w  #-32+128,d2
    blo.s   BuildSprites_P2_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_P2_NextObj
    addi.w  #128+224,d2
; loc_16B3E:
BuildSprites_P2_DrawSprite:
    movea.l mappings(a0),a1
    moveq   #0,d1
    btst    #5,d4
    bne.s   +
    move.b  mapping_frame(a0),d1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   ++
+
    bsr.w   DrawSprite_2P
+
    ori.b   #$80,render_flags(a0)
; loc_16B64:
BuildSprites_P2_NextObj:
    addq.w  #2,d6
    subq.w  #2,(sp)
    bne.w   BuildSprites_P2_ObjLoop
    addq.w  #2,sp
    tst.b   (Teleport_flag).w
    bne.s   BuildSprites_P2_NextLevel
    move.w  #0,(a4)
; loc_16B78:
BuildSprites_P2_NextLevel:
    lea $80(a4),a4
    dbf d7,BuildSprites_P2_LevelLoop
    move.b  d5,(Sprite_count).w
    cmpi.b  #80,d5
    beq.s   +
    move.l  #0,(a2)
    rts
+
    move.b  #0,-5(a2)
    rts
; ===========================================================================
; loc_16B9A:
BuildSprites_P1_MultiDraw:
    move.l  a4,-(sp)
    lea (Camera_X_pos).w,a4
    movea.w art_tile(a0),a3
    movea.l mappings(a0),a5
    moveq   #0,d0
    move.b  mainspr_width(a0),d0
    move.w  x_pos(a0),d3
    sub.w   (a4),d3
    move.w  d3,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P1_MultiDraw_NextObj
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1
    bge.w   BuildSprites_P1_MultiDraw_NextObj
    addi.w  #128,d3
    btst    #4,d4
    beq.s   +
    moveq   #0,d0
    move.b  mainspr_height(a0),d0
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P1_MultiDraw_NextObj
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.w   BuildSprites_P1_MultiDraw_NextObj
    addi.w  #256,d2
    bra.s   ++
+
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    addi.w  #128,d2
    cmpi.w  #-32+128,d2
    blo.s   BuildSprites_P1_MultiDraw_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_P1_MultiDraw_NextObj
    addi.w  #128,d2
+
    moveq   #0,d1
    move.b  mainspr_mapframe(a0),d1
    beq.s   +
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite_2P
    move.w  (sp)+,d4
+
    ori.b   #$80,render_flags(a0)
    lea sub2_x_pos(a0),a6
    moveq   #0,d0
    move.b  mainspr_childsprites(a0),d0
    subq.w  #1,d0
    bcs.s   BuildSprites_P1_MultiDraw_NextObj
 
-   swap    d0
    move.w  (a6)+,d3
    sub.w   (a4),d3
    addi.w  #128,d3
    move.w  (a6)+,d2
    sub.w   4(a4),d2
    addi.w  #256,d2
    addq.w  #1,a6
    moveq   #0,d1
    move.b  (a6)+,d1
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite_2P
    move.w  (sp)+,d4
+
    swap    d0
    dbf d0,-
; loc_16C7E:
BuildSprites_P1_MultiDraw_NextObj:
    movea.l (sp)+,a4
    bra.w   BuildSprites_P1_NextObj
; ===========================================================================
; loc_16C84:
BuildSprites_P2_MultiDraw:
    move.l  a4,-(sp)
    lea (Camera_X_pos_P2).w,a4
    movea.w art_tile(a0),a3
    movea.l mappings(a0),a5
    moveq   #0,d0
    move.b  mainspr_width(a0),d0
    move.w  x_pos(a0),d3
    sub.w   (a4),d3
    move.w  d3,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P2_MultiDraw_NextObj
    move.w  d3,d1
    sub.w   d0,d1
    cmpi.w  #320,d1
    bge.w   BuildSprites_P2_MultiDraw_NextObj
    addi.w  #128,d3
    btst    #4,d4
    beq.s   +
    moveq   #0,d0
    move.b  mainspr_height(a0),d0
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    move.w  d2,d1
    add.w   d0,d1
    bmi.w   BuildSprites_P2_MultiDraw_NextObj
    move.w  d2,d1
    sub.w   d0,d1
    cmpi.w  #224,d1
    bge.w   BuildSprites_P2_MultiDraw_NextObj
    addi.w  #256+224,d2
    bra.s   ++
+
    move.w  y_pos(a0),d2
    sub.w   4(a4),d2
    addi.w  #128,d2
    cmpi.w  #-32+128,d2
    blo.s   BuildSprites_P2_MultiDraw_NextObj
    cmpi.w  #32+128+224,d2
    bhs.s   BuildSprites_P2_MultiDraw_NextObj
    addi.w  #128+224,d2
+
    moveq   #0,d1
    move.b  mainspr_mapframe(a0),d1
    beq.s   +
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite_2P
    move.w  (sp)+,d4
+
    ori.b   #$80,render_flags(a0)
    lea sub2_x_pos(a0),a6
    moveq   #0,d0
    move.b  mainspr_childsprites(a0),d0
    subq.w  #1,d0
    bcs.s   BuildSprites_P2_MultiDraw_NextObj
 
-   swap    d0
    move.w  (a6)+,d3
    sub.w   (a4),d3
    addi.w  #128,d3
    move.w  (a6)+,d2
    sub.w   4(a4),d2
    addi.w  #256+224,d2
    addq.w  #1,a6
    moveq   #0,d1
    move.b  (a6)+,d1
    add.w   d1,d1
    movea.l a5,a1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    move.w  d4,-(sp)
    bsr.w   ChkDrawSprite_2P
    move.w  (sp)+,d4
+
    swap    d0
    dbf d0,-
; loc_16D68:
BuildSprites_P2_MultiDraw_NextObj:
    movea.l (sp)+,a4
    bra.w   BuildSprites_P2_NextObj
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; adjust art pointer of object at a0 for 2-player mode
; sub_16D6E:
Adjust2PArtPointer:
    tst.w   (Two_player_mode).w
    beq.s   + ; rts
    move.w  art_tile(a0),d0
    andi.w  #tile_mask,d0
    lsr.w   #1,d0
    andi.w  #nontile_mask,art_tile(a0)
    add.w   d0,art_tile(a0)
+
    rts
; End of function Adjust2PArtPointer
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; adjust art pointer of object at a1 for 2-player mode
; sub_16D8A:
Adjust2PArtPointer2:
    tst.w   (Two_player_mode).w
    beq.s   + ; rts
    move.w  art_tile(a1),d0
    andi.w  #tile_mask,d0
    lsr.w   #1,d0
    andi.w  #nontile_mask,art_tile(a1)
    add.w   d0,art_tile(a1)
+
    rts
; End of function Adjust2PArtPointer2
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_16DA6:
ChkDrawSprite_2P:
    cmpi.b  #80,d5
    blo.s   DrawSprite_2P_Loop
    rts
; End of function ChkDrawSprite_2P
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; copy sprite art to VRAM, in 2-player mode
 
; sub_16DAE:
DrawSprite_2P:
    movea.w art_tile(a0),a3
    cmpi.b  #80,d5
    bhs.s   DrawSprite_2P_Done
    btst    #0,d4
    bne.s   DrawSprite_2P_FlipX
    btst    #1,d4
    bne.w   DrawSprite_2P_FlipY
; loc_16DC6:
DrawSprite_2P_Loop:
    move.b  (a1)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4
    move.b  SpriteSizes_2P(pc,d4.w),(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   a3,d0
    move.w  d0,(a2)+
    move.w  (a1)+,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,DrawSprite_2P_Loop
; return_16DF2:
DrawSprite_2P_Done:
    rts
; ===========================================================================
; cells are double the height in 2P mode, so halve the number of rows
 
;byte_16DF4:
SpriteSizes_2P:
    dc.b   0,0
    dc.b   1,1
    dc.b   4,4
    dc.b   5,5
    dc.b   8,8
    dc.b   9,9
    dc.b  $C,$C
    dc.b  $D,$D
; ===========================================================================
; loc_16E04:
DrawSprite_2P_FlipX:
    btst    #1,d4
    bne.w   DrawSprite_2P_FlipXY
 
-   move.b  (a1)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4
    move.b  SpriteSizes_2P(pc,d4.w),(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$800,d0
    move.w  d0,(a2)+
    move.w  (a1)+,d0
    neg.w   d0
    move.b  byte_16E46(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,-
 
    rts
; ===========================================================================
; offsets for horizontally mirrored sprite pieces (2P)
byte_16E46:
    dc.b   8,  8,  8,  8    ; 4
    dc.b $10,$10,$10,$10    ; 8
    dc.b $18,$18,$18,$18    ; 12
    dc.b $20,$20,$20,$20    ; 16
; offsets for vertically mirrored sprite pieces (2P)
byte_16E56:
    dc.b   8,$10,$18,$20    ; 4
    dc.b   8,$10,$18,$20    ; 8
    dc.b   8,$10,$18,$20    ; 12
    dc.b   8,$10,$18,$20    ; 16
; ===========================================================================
; loc_16E66:
DrawSprite_2P_FlipY:
    move.b  (a1)+,d0
    move.b  (a1),d4
    ext.w   d0
    neg.w   d0
    move.b  byte_16E56(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4
    move.b  SpriteSizes_2P_2(pc,d4.w),(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$1000,d0
    move.w  d0,(a2)+
    move.w  (a1)+,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,DrawSprite_2P_FlipY
    rts
; ===========================================================================
; cells are double the height in 2P mode, so halve the number of rows
 
; byte_16EA2:
SpriteSizes_2P_2:
    dc.b   0,0
    dc.b   1,1  ; 2
    dc.b   4,4  ; 4
    dc.b   5,5  ; 6
    dc.b   8,8  ; 8
    dc.b   9,9  ; 10
    dc.b  $C,$C ; 12
    dc.b  $D,$D ; 14
; offsets for vertically mirrored sprite pieces (2P)
byte_16EB2:
    dc.b   8,$10,$18,$20    ; 4
    dc.b   8,$10,$18,$20    ; 8
    dc.b   8,$10,$18,$20    ; 12
    dc.b   8,$10,$18,$20    ; 16
; ===========================================================================
; loc_16EC2:
DrawSprite_2P_FlipXY:
    move.b  (a1)+,d0
    move.b  (a1),d4
    ext.w   d0
    neg.w   d0
    move.b  byte_16EB2(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d2,d0
    move.w  d0,(a2)+
    move.b  (a1)+,d4
    move.b  SpriteSizes_2P_2(pc,d4.w),(a2)+
    addq.b  #1,d5
    move.b  d5,(a2)+
    addq.w  #2,a1
    move.w  (a1)+,d0
    add.w   a3,d0
    eori.w  #$1800,d0
    move.w  d0,(a2)+
    move.w  (a1)+,d0
    neg.w   d0
    move.b  byte_16F06(pc,d4.w),d4
    sub.w   d4,d0
    add.w   d3,d0
    andi.w  #$1FF,d0
    bne.s   +
    addq.w  #1,d0
+
    move.w  d0,(a2)+
    dbf d1,DrawSprite_2P_FlipXY
    rts
; End of function DrawSprite_2P
 
; ===========================================================================
; offsets for horizontally mirrored sprite pieces (2P)
byte_16F06:
    dc.b   8,  8,  8,  8    ; 4
    dc.b $10,$10,$10,$10    ; 8
    dc.b $18,$18,$18,$18    ; 12
    dc.b $20,$20,$20,$20    ; 16
 
; ===========================================================================
; loc_16F16: ; unused/dead code? ; a0=object
    move.w  x_pos(a0),d0
    sub.w   (Camera_X_pos).w,d0
    bmi.s   +
    cmpi.w  #320,d0
    bge.s   +
    move.w  y_pos(a0),d1
    sub.w   (Camera_Y_pos).w,d1
    bmi.s   +
    cmpi.w  #$E0,d1
    bge.s   +
    moveq   #0,d0
    rts
+   moveq   #1,d0
    rts
; ===========================================================================
; loc_16F3E: ; unused/dead code? ; a0=object
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  x_pos(a0),d0
    sub.w   (Camera_X_pos).w,d0
    add.w   d1,d0
    bmi.s   +
    add.w   d1,d1
    sub.w   d1,d0
    cmpi.w  #320,d0
    bge.s   +
    move.w  y_pos(a0),d1
    sub.w   (Camera_Y_pos).w,d1
    bmi.s   +
    cmpi.w  #$E0,d1
    bge.s   +
    moveq   #0,d0
    rts
+   moveq   #1,d0
    rts
; ===========================================================================
 
    if gameRevision=1
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_BuildHUD 
    jmp (BuildHUD).l
JmpTo_BuildHUD_P1 
    jmp (BuildHUD_P1).l
JmpTo_BuildHUD_P2 
    jmp (BuildHUD_P2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Pseudo-object that manages where rings are placed onscreen
; as you move through the level, and otherwise updates them.
; ----------------------------------------------------------------------------
 
; loc_16F88:
RingsManager:
    moveq   #0,d0
    move.b  (Rings_manager_routine).w,d0
    move.w  RingsManager_States(pc,d0.w),d0
    jmp RingsManager_States(pc,d0.w)
; ===========================================================================
; off_16F96:
RingsManager_States:    offsetTable
    offsetTableEntry.w RingsManager_Init    ;   0
    offsetTableEntry.w RingsManager_Main    ;   2
; ===========================================================================
; loc_16F9A:
RingsManager_Init:
    addq.b  #2,(Rings_manager_routine).w ; => RingsManager_Main
    bsr.w   RingsManager_Setup  ; perform initial setup
    lea (Ring_Positions).w,a1
    move.w  (Camera_X_pos).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4   ; no negative values allowed
    bra.s   +
-
    lea 6(a1),a1    ; load next ring
+
    cmp.w   2(a1),d4    ; is the X pos of the ring < camera X pos?
    bhi.s   -       ; if it is, check next ring
    move.w  a1,(Ring_start_addr).w  ; set start addresses
    move.w  a1,(Ring_start_addr_P2).w
    addi.w  #320+16,d4  ; advance by a screen
    bra.s   +
-
    lea 6(a1),a1    ; load next ring
+
    cmp.w   2(a1),d4    ; is the X pos of the ring < camera X + 336?
    bhi.s   -       ; if it is, check next ring
    move.w  a1,(Ring_end_addr).w    ; set end addresses
    move.w  a1,(Ring_end_addr_P2).w
    rts
; ===========================================================================
; loc_16FDE:
RingsManager_Main:
    lea (Ring_consumption_table).w,a2
    move.w  (a2)+,d1
    subq.w  #1,d1   ; are any rings currently being consumed?
    bcs.s   ++  ; if not, branch
 
-   move.w  (a2)+,d0    ; is there a ring in this slot?
    beq.s   -   ; if not, branch
    movea.w d0,a1   ; load ring address
    subq.b  #1,(a1) ; decrement timer
    bne.s   +   ; if it's not 0 yet, branch
    move.b  #6,(a1) ; reset timer
    addq.b  #1,1(a1); increment frame
    cmpi.b  #8,1(a1); is it destruction time yet?
    bne.s   +   ; if not, branch
    move.w  #-1,(a1); destroy ring
    move.w  #0,-2(a2)   ; clear ring entry
    subq.w  #1,(Ring_consumption_table).w   ; subtract count
+   dbf d1,-    ; repeat for all rings in table
+
    ; update ring start and end addresses
    movea.w (Ring_start_addr).w,a1
    move.w  (Camera_X_pos).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4
    bra.s   +
-
    lea 6(a1),a1
+
    cmp.w   2(a1),d4
    bhi.s   -
    bra.s   +
-
    subq.w  #6,a1
+
    cmp.w   -4(a1),d4
    bls.s   -
    move.w  a1,(Ring_start_addr).w  ; update start address
    
    movea.w (Ring_end_addr).w,a2
    addi.w  #320+16,d4
    bra.s   +
-
    lea 6(a2),a2
+
    cmp.w   2(a2),d4
    bhi.s   -
    bra.s   +
-
    subq.w  #6,a2
+
    cmp.w   -4(a2),d4
    bls.s   -
    move.w  a2,(Ring_end_addr).w    ; update end address
    tst.w   (Two_player_mode).w ; are we in 2P mode?
    bne.s   +   ; if we are, update P2 addresses
    move.w  a1,(Ring_start_addr_P2).w   ; otherwise, copy over P1 addresses
    move.w  a2,(Ring_end_addr_P2).w
    rts
+
    ; update ring start and end addresses for P2
    movea.w (Ring_start_addr_P2).w,a1
    move.w  (Camera_X_pos_P2).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4
    bra.s   +
-
    lea 6(a1),a1
+
    cmp.w   2(a1),d4
    bhi.s   -
    bra.s   +
-
    subq.w  #6,a1
+
    cmp.w   -4(a1),d4
    bls.s   -
    move.w  a1,(Ring_start_addr_P2).w   ; update start address
    
    movea.w (Ring_end_addr_P2).w,a2
    addi.w  #320+16,d4
    bra.s   +
-
    lea 6(a2),a2
+
    cmp.w   2(a2),d4
    bhi.s   -
    bra.s   +
-
    subq.w  #6,a2
+
    cmp.w   -4(a2),d4
    bls.s   -
    move.w  a2,(Ring_end_addr_P2).w     ; update end address
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to handle ring collision
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_170BA:
Touch_Rings:
    movea.w (Ring_start_addr).w,a1
    movea.w (Ring_end_addr).w,a2
    cmpa.w  #MainCharacter,a0
    beq.s   +
    movea.w (Ring_start_addr_P2).w,a1
    movea.w (Ring_end_addr_P2).w,a2
+
    cmpa.l  a1,a2   ; are there no rings in this area?
    beq.w   Touch_Rings_Done    ; if so, return
    cmpi.w  #$5A,invulnerable_time(a0)
    bhs.w   Touch_Rings_Done
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    subi_.w #8,d2   ; assume X radius to be 8
    moveq   #0,d5
    move.b  y_radius(a0),d5
    subq.b  #3,d5
    sub.w   d5,d3   ; subtract (Y radius - 3) from Y pos
    cmpi.b  #$4D,mapping_frame(a0)
    bne.s   +   ; if you're not ducking, branch
    addi.w  #$C,d3
    moveq   #$A,d5
+
    move.w  #6,d1   ; set ring radius
    move.w  #12,d6  ; set ring diameter
    move.w  #16,d4  ; set Sonic's X diameter
    add.w   d5,d5   ; set Y diameter
; loc_17112:
Touch_Rings_Loop:
    tst.w   (a1)        ; has this ring already been collided with?
    bne.w   Touch_NextRing  ; if it has, branch
    move.w  2(a1),d0    ; get ring X pos
    sub.w   d1,d0       ; get ring left edge X pos
    sub.w   d2,d0       ; subtract Sonic's left edge X pos
    bcc.s   +       ; if Sonic's to the left of the ring, branch
    add.w   d6,d0       ; add ring diameter
    bcs.s   ++      ; if Sonic's colliding, branch
    bra.w   Touch_NextRing  ; otherwise, test next ring
+
    cmp.w   d4,d0       ; has Sonic crossed the ring?
    bhi.w   Touch_NextRing  ; if he has, branch
+
    move.w  4(a1),d0    ; get ring Y pos
    sub.w   d1,d0       ; get ring top edge pos
    sub.w   d3,d0       ; subtract Sonic's top edge pos
    bcc.s   +       ; if Sonic's above the ring, branch
    add.w   d6,d0       ; add ring diameter
    bcs.s   ++      ; if Sonic's colliding, branch
    bra.w   Touch_NextRing  ; otherwise, test next ring
+
    cmp.w   d5,d0       ; has Sonic crossed the ring?
    bhi.w   Touch_NextRing  ; if he has, branch
+
    move.w  #$604,(a1)  ; set frame and destruction timer
    bsr.s   Touch_ConsumeRing
    lea (Ring_consumption_table+2).w,a3
 
-   tst.w   (a3)+       ; is this slot free?
    bne.s   -       ; if not, repeat until you find one
    move.w  a1,-(a3)    ; set ring address
    addq.w  #1,(Ring_consumption_table).w   ; increase count
; loc_1715C:
Touch_NextRing:
    lea 6(a1),a1
    cmpa.l  a1,a2       ; are we at the last ring for this area?
    bne.w   Touch_Rings_Loop    ; if not, branch
; return_17166:
Touch_Rings_Done:
    rts
; ===========================================================================
; loc_17168:
Touch_ConsumeRing:
    subq.w  #1,(Perfect_rings_left).w
    cmpa.w  #MainCharacter,a0   ; who collected the ring?
    beq.w   CollectRing_Sonic   ; if it was Sonic, branch here
    bra.w   CollectRing_Tails   ; if it was Tails, branch here
 
; ---------------------------------------------------------------------------
; Subroutine to draw on-screen rings
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_17178:
BuildRings:
    movea.w (Ring_start_addr).w,a0
    movea.w (Ring_end_addr).w,a4
    cmpa.l  a0,a4   ; are there any rings on-screen?
    bne.s   +   ; if there are, branch
    rts     ; otherwise, return
+
    lea (Camera_X_pos).w,a3
; loc_1718A:
BuildRings_Loop:
    tst.w   (a0)        ; has this ring been consumed?
    bmi.w   BuildRings_NextRing ; if it has, branch
    move.w  2(a0),d3    ; get ring X pos
    sub.w   (a3),d3     ; subtract camera X pos
    addi.w  #128,d3     ; screen top is 128x128 not 0x0
    move.w  4(a0),d2    ; get ring Y pos
    sub.w   4(a3),d2    ; subtract camera Y pos
    andi.w  #$7FF,d2
    addi_.w #8,d2
    bmi.s   BuildRings_NextRing ; dunno how this check is supposed to work
    cmpi.w  #240,d2
    bge.s   BuildRings_NextRing ; if the ring is not on-screen, branch
    addi.w  #128-8,d2
    lea (MapUnc_Rings).l,a1
    moveq   #0,d1
    move.b  1(a0),d1    ; get ring frame
    bne.s   +       ; if this ring is using a specific frame, branch
    move.b  (Rings_anim_frame).w,d1 ; use global frame
+
    add.w   d1,d1
    adda.w  (a1,d1.w),a1    ; get frame data address
    move.b  (a1)+,d0    ; get Y offset
    ext.w   d0
    add.w   d2,d0       ; add Y offset to Y pos
    move.w  d0,(a2)+    ; set Y pos
    move.b  (a1)+,(a2)+ ; set size
    addq.b  #1,d5
    move.b  d5,(a2)+    ; set link field
    move.w  (a1)+,d0    ; get art tile
    addi.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),d0  ; add base art tile
    move.w  d0,(a2)+    ; set art tile and flags
    addq.w  #2,a1       ; skip 2P art tile
    move.w  (a1)+,d0    ; get X offset
    add.w   d3,d0       ; add base X pos
    move.w  d0,(a2)+    ; set X pos
; loc_171EC:
BuildRings_NextRing:
    lea 6(a0),a0
    cmpa.l  a0,a4
    bne.w   BuildRings_Loop
    rts
 
; ---------------------------------------------------------------------------
; Subroutine to draw on-screen rings for player 1 in a 2P versus game
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_171F8:
BuildRings_P1:
    lea (Camera_X_pos).w,a3
    move.w  #128-8,d6
    movea.w (Ring_start_addr).w,a0
    movea.w (Ring_end_addr).w,a4
    cmpa.l  a0,a4   ; are there rings on-screen?
    bne.s   BuildRings_2P_Loop  ; if there are, draw them
    rts ; otherwise, return
 
; ---------------------------------------------------------------------------
; Subroutine to draw on-screen rings for player 2 in a 2P versus game
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1720E:
BuildRings_P2:
    lea (Camera_X_pos_P2).w,a3
    move.w  #224+128-8,d6
    movea.w (Ring_start_addr_P2).w,a0
    movea.w (Ring_end_addr_P2).w,a4
    cmpa.l  a0,a4   ; are there rings on-screen?
    bne.s   BuildRings_2P_Loop  ; if there are, draw them
    rts ; otherwise, return
; ===========================================================================
; loc_17224:
BuildRings_2P_Loop:
    tst.w   (a0)        ; has this ring been consumed?
    bmi.w   BuildRings_2P_NextRing  ; if it has, branch
    move.w  2(a0),d3    ; get ring X pos
    sub.w   (a3),d3     ; subtract camera X pos
    addi.w  #128,d3
    move.w  4(a0),d2    ; get ring Y pos
    sub.w   4(a3),d2    ; subtract camera Y pos
    andi.w  #$7FF,d2
    addi.w  #128+8,d2
    bmi.s   BuildRings_2P_NextRing
    cmpi.w  #240+128,d2
    bge.s   BuildRings_2P_NextRing
    add.w   d6,d2       ; add base Y pos
    lea (MapUnc_Rings).l,a1
    moveq   #0,d1
    move.b  1(a0),d1    ; use ring-specific frame
    bne.s   +       ; if there is one
    move.b  (Rings_anim_frame).w,d1 ; otherwise use global frame
+
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.b  (a1)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,(a2)+    ; set Y pos
    move.b  (a1)+,d4
    move.b  SpriteSizes_2P_3(pc,d4.w),(a2)+ ; set size
    addq.b  #1,d5
    move.b  d5,(a2)+    ; set link field
    addq.w  #2,a1
    move.w  (a1)+,d0
    addi.w  #make_art_tile_2p(ArtTile_ArtNem_Ring,1,0),d0
    move.w  d0,(a2)+    ; set art tile and flags
    move.w  (a1)+,d0
    add.w   d3,d0
    move.w  d0,(a2)+    ; set X pos
 
BuildRings_2P_NextRing:
    lea 6(a0),a0    ; load next ring
    cmpa.l  a0,a4       ; are there any rings left?
    bne.w   BuildRings_2P_Loop  ; if there are, loop
    rts
; ===========================================================================
; cells are double the height in 2P mode, so halve the number of rows
 
; byte_17294:
SpriteSizes_2P_3:
    dc.b   0,0  ; 1
    dc.b   1,1  ; 3
    dc.b   4,4  ; 5
    dc.b   5,5  ; 7
    dc.b   8,8  ; 9
    dc.b   9,9  ; 11
    dc.b  $C,$C ; 13
    dc.b  $D,$D ; 15
 
; ---------------------------------------------------------------------------
; Subroutine to perform initial rings manager setup
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_172A4:
RingsManager_Setup:
    clearRAM Ring_Positions,Ring_Positions_End
    ; d0 = 0
    lea (Ring_consumption_table).w,a1
 
    move.w  #bytesToLcnt(Ring_consumption_table_End-Ring_consumption_table-$40),d1  ; coding error, that '-$40' shouldn't be there
-   move.l  d0,(a1)+    ; only half of Ring_consumption_table is cleared
    dbf d1,-
 
    moveq   #0,d5
    moveq   #0,d0
    move.w  (Current_ZoneAndAct).w,d0
    ror.b   #1,d0
    lsr.w   #6,d0
    lea (Off_Rings).l,a1
    move.w  (a1,d0.w),d0
    lea (a1,d0.w),a1
    lea (Ring_Positions+6).w,a2 ; first ring is left blank
; loc_172E0:
RingsMgr_NextRowOrCol:
    move.w  (a1)+,d2    ; is this the last ring?
    bmi.s   RingsMgr_SortRings  ; if it is, sort the rings
    move.w  (a1)+,d3    ; is this a column of rings?
    bmi.s   RingsMgr_RingCol    ; if it is, branch
    move.w  d3,d0
    rol.w   #4,d0
    andi.w  #7,d0       ; store number of rings
    andi.w  #$FFF,d3    ; store Y pos
; loc_172F4:
RingsMgr_NextRingInRow:
    move.w  #0,(a2)+    ; set initial status
    move.w  d2,(a2)+    ; set X pos
    move.w  d3,(a2)+    ; set Y pos
    addi.w  #$18,d2     ; increment X pos
    addq.w  #1,d5       ; increment perfect counter
    dbf d0,RingsMgr_NextRingInRow
    bra.s   RingsMgr_NextRowOrCol
; ===========================================================================
; loc_17308:
RingsMgr_RingCol:
    move.w  d3,d0
    rol.w   #4,d0
    andi.w  #7,d0       ; store number of rings
    andi.w  #$FFF,d3    ; store Y pos
; loc_17314:
RingsMgr_NextRingInCol:
    move.w  #0,(a2)+    ; set initial status
    move.w  d2,(a2)+    ; set X pos
    move.w  d3,(a2)+    ; set Y pos
    addi.w  #$18,d3     ; increment Y pos
    addq.w  #1,d5       ; increment perfect counter
    dbf d0,RingsMgr_NextRingInCol
    bra.s   RingsMgr_NextRowOrCol
; ===========================================================================
; loc_17328:
RingsMgr_SortRings:
    move.w  d5,(Perfect_rings_left).w
    move.w  #0,(Perfect_rings_flag).w   ; no idea what this is
    moveq   #-1,d0
    move.l  d0,(a2)+    ; set X pos of last ring to -1
    lea (Ring_Positions+2).w,a1 ; X pos of first ring
 
    move.w  #$FE,d3     ; sort 255 rings
-   move.w  d3,d4
    lea 6(a1),a2    ; load next ring for comparison
    move.w  (a1),d0     ; get X pos of current ring
 
-   tst.w   (a2)        ; is the next ring blank?
    beq.s   +       ; if it is, branch
    cmp.w   (a2),d0     ; is the X pos of current ring <= X pos of next ring?
    bls.s   +       ; if so, branch
    move.l  (a1),d1     ; otherwise, swap the rings
    move.l  (a2),d0
    move.l  d0,(a1)
    move.l  d1,(a2)
    swap    d0
+
    lea 6(a2),a2    ; load next comparison ring
    dbf d4,-        ; repeat
 
    lea 6(a1),a1    ; load next ring
    dbf d3,--       ; repeat
 
    rts
; ===========================================================================
 
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
 
; off_1736A:
MapUnc_Rings:   BINCLUDE "mappings/sprite/Rings.bin"
 
    if ~~removeJmpTos
    align 4
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Pseudo-object to do collision with (and initialize?) the special bumpers in CNZ.
; These are the bumpers that are part of the level layout but have object-like collision.
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_173BC:
SpecialCNZBumpers:
    moveq   #0,d0
    move.b  (CNZ_Bumper_routine).w,d0
    move.w  SpecialCNZBumpers_Index(pc,d0.w),d0
    jmp SpecialCNZBumpers_Index(pc,d0.w)
; ===========================================================================
; off_173CA:
SpecialCNZBumpers_Index: offsetTable
    offsetTableEntry.w SpecialCNZBumpers_Init   ; 0
    offsetTableEntry.w SpecialCNZBumpers_Main   ; 2
; ===========================================================================
; loc_173CE:
SpecialCNZBumpers_Init:
    addq.b  #2,(CNZ_Bumper_routine).w
    lea (SpecialCNZBumpers_Act1).l,a1
    tst.b   (Current_Act).w
    beq.s   +
    lea (SpecialCNZBumpers_Act2).l,a1
+
    move.w  (Camera_X_pos).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a1),a1
+
    cmp.w   bumper_x(a1),d4
    bhi.s   -
    move.l  a1,(CNZ_Visible_bumpers_start).w
    move.l  a1,(CNZ_Visible_bumpers_start_P2).w
    addi.w  #$150,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a1),a1
+
    cmp.w   bumper_x(a1),d4
    bhi.s   -
    move.l  a1,(CNZ_Visible_bumpers_end).w
    move.l  a1,(CNZ_Visible_bumpers_end_P2).w
    move.b  #1,(CNZ_Bumper_UnkFlag).w
    rts
; ===========================================================================
; loc_17422:
SpecialCNZBumpers_Main:
    movea.l (CNZ_Visible_bumpers_start).w,a1
    move.w  (Camera_X_pos).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a1),a1
+
    cmp.w   bumper_x(a1),d4
    bhi.s   -
    bra.s   +
; ===========================================================================
-
    subq.w  #next_bumper,a1
+
    cmp.w   prev_bumper_x(a1),d4
    bls.s   -
    move.l  a1,(CNZ_Visible_bumpers_start).w
    movea.l (CNZ_Visible_bumpers_end).w,a2
    addi.w  #$150,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a2),a2
+
    cmp.w   bumper_x(a2),d4
    bhi.s   -
    bra.s   +
; ===========================================================================
-
    subq.w  #next_bumper,a2
+
    cmp.w   prev_bumper_x(a2),d4
    bls.s   -
    move.l  a2,(CNZ_Visible_bumpers_end).w
    tst.w   (Two_player_mode).w
    bne.s   +
    move.l  a1,(CNZ_Visible_bumpers_start_P2).w
    move.l  a2,(CNZ_Visible_bumpers_end_P2).w
    rts
; ===========================================================================
+
    movea.l (CNZ_Visible_bumpers_start_P2).w,a1
    move.w  (Camera_X_pos_P2).w,d4
    subq.w  #8,d4
    bhi.s   +
    moveq   #1,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a1),a1
+
    cmp.w   bumper_x(a1),d4
    bhi.s   -
    bra.s   +
; ===========================================================================
-
    subq.w  #next_bumper,a1
+
    cmp.w   prev_bumper_x(a1),d4
    bls.s   -
    move.l  a1,(CNZ_Visible_bumpers_start_P2).w
    movea.l (CNZ_Visible_bumpers_end_P2).w,a2
    addi.w  #$150,d4
    bra.s   +
; ===========================================================================
-
    lea next_bumper(a2),a2
+
    cmp.w   bumper_x(a2),d4
    bhi.s   -
    bra.s   +
; ===========================================================================
-
    subq.w  #next_bumper,a2
+
    cmp.w   prev_bumper_x(a2),d4
    bls.s   -
    move.l  a2,(CNZ_Visible_bumpers_end_P2).w
    rts
; ===========================================================================
 
Check_CNZ_bumpers:
    movea.l (CNZ_Visible_bumpers_start).w,a1
    movea.l (CNZ_Visible_bumpers_end).w,a2
    cmpa.w  #MainCharacter,a0
    beq.s   +
    movea.l (CNZ_Visible_bumpers_start_P2).w,a1
    movea.l (CNZ_Visible_bumpers_end_P2).w,a2
+
    cmpa.l  a1,a2
    beq.w   return_17578
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    subi.w  #9,d2
    moveq   #0,d5
    move.b  y_radius(a0),d5
    subq.b  #3,d5
    sub.w   d5,d3
    cmpi.b  #$4D,mapping_frame(a0)
    bne.s   +
    addi.w  #$C,d3
    moveq   #$A,d5
+
    move.w  #$12,d4
    add.w   d5,d5
 
CNZ_Bumper_loop:
    move.w  bumper_id(a1),d0
    andi.w  #$E,d0
    lea byte_17558(pc,d0.w),a3
    moveq   #0,d1
    move.b  (a3)+,d1
    move.w  bumper_x(a1),d0
    sub.w   d1,d0
    sub.w   d2,d0
    bcc.s   loc_17530
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   loc_17536
    bra.w   CNZ_Bumper_next
; ===========================================================================
 
loc_17530:
    cmp.w   d4,d0
    bhi.w   CNZ_Bumper_next
 
loc_17536:
    moveq   #0,d1
    move.b  (a3)+,d1
    move.w  bumper_y(a1),d0
    sub.w   d1,d0
    sub.w   d3,d0
    bcc.s   loc_17550
    add.w   d1,d1
    add.w   d1,d0
    bcs.w   loc_17564
    bra.w   CNZ_Bumper_next
; ===========================================================================
 
loc_17550:
    cmp.w   d5,d0
    bhi.w   CNZ_Bumper_next
    bra.s   loc_17564
; ===========================================================================
byte_17558:
    dc.b $20
    dc.b $20    ; 1
    dc.b $20    ; 2
    dc.b $20    ; 3
    dc.b $40    ; 4
    dc.b   8    ; 5
    dc.b $40    ; 6
    dc.b   8    ; 7
    dc.b   8    ; 8
    dc.b $40    ; 9
    dc.b   8    ; 10
    dc.b $40    ; 11
; ===========================================================================
 
loc_17564:
    move.w  (a1),d0
    move.w  off_1757A(pc,d0.w),d0
    jmp off_1757A(pc,d0.w)
; ===========================================================================
 
CNZ_Bumper_next:
    lea next_bumper(a1),a1
    cmpa.l  a1,a2
    bne.w   CNZ_Bumper_loop
 
return_17578:
    rts
; ===========================================================================
off_1757A:  offsetTable
        offsetTableEntry.w loc_17586    ;  0
        offsetTableEntry.w loc_17638    ;  2
        offsetTableEntry.w loc_1769E    ;  4
        offsetTableEntry.w loc_176F6    ;  6
        offsetTableEntry.w loc_1774C    ;  8
        offsetTableEntry.w loc_177A4    ; $A
; ===========================================================================
 
loc_17586:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    neg.w   d0
    cmpi.w  #$20,d0
    blt.s   loc_175A0
    move.w  #$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_175A0:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    neg.w   d0
    cmpi.w  #$20,d0
    blt.s   loc_175BA
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_175BA:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #$20,d0
    blt.s   loc_175CC
    move.w  #$20,d0
 
loc_175CC:
    add.w   bumper_y(a1),d0
    subq.w  #8,d0
    move.w  y_pos(a0),d1
    addi.w  #$E,d1
    sub.w   d1,d0
    bcc.s   return_175E8
    move.w  #$20,d3
    bsr.s   loc_175EA
    bra.w   loc_177FA
; ===========================================================================
 
return_175E8:
    rts
; ===========================================================================
 
loc_175EA:
    move.w  x_vel(a0),d1
    move.w  y_vel(a0),d2
    jsr (CalcAngle).l
    move.b  d0,(unk_FFDC).w
    sub.w   d3,d0
    mvabs.w d0,d1
    neg.w   d0
    add.w   d3,d0
    move.b  d0,(unk_FFDD).w
    move.b  d1,(unk_FFDF).w
    cmpi.b  #$38,d1
    blo.s   loc_17618
    move.w  d3,d0
 
loc_17618:
    move.b  d0,(unk_FFDE).w
    jsr (CalcSine).l
    muls.w  #-$A00,d1
    asr.l   #8,d1
    move.w  d1,x_vel(a0)
    muls.w  #-$A00,d0
    asr.l   #8,d0
    move.w  d0,y_vel(a0)
    rts
; ===========================================================================
 
loc_17638:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    neg.w   d0
    cmpi.w  #$20,d0
    blt.s   loc_17652
    move.w  #$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_17652:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #$20,d0
    blt.s   loc_1766A
    move.w  #-$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_1766A:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    neg.w   d0
    cmpi.w  #$20,d0
    blt.s   loc_1767E
    move.w  #$20,d0
 
loc_1767E:
    add.w   bumper_y(a1),d0
    subq.w  #8,d0
    move.w  y_pos(a0),d1
    addi.w  #$E,d1
    sub.w   d1,d0
    bcc.s   return_1769C
    move.w  #$60,d3
    bsr.w   loc_175EA
    bra.w   loc_177FA
; ===========================================================================
 
return_1769C:
    rts
; ===========================================================================
 
loc_1769E:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    neg.w   d0
    cmpi.w  #8,d0
    blt.s   loc_176B8
    move.w  #$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_176B8:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #$40,d0
    blt.s   loc_176D0
    move.w  #-$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_176D0:
    neg.w   d0
    cmpi.w  #$40,d0
    blt.s   loc_176E2
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_176E2:
    move.w  #$38,d3
    tst.w   d0
    bmi.s   loc_176EE
    move.w  #$48,d3
 
loc_176EE:
    bsr.w   loc_175EA
    bra.w   loc_177FA
; ===========================================================================
 
loc_176F6:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    cmpi.w  #8,d0
    blt.s   loc_1770E
    move.w  #-$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_1770E:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #$40,d0
    blt.s   loc_17726
    move.w  #-$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_17726:
    neg.w   d0
    cmpi.w  #$40,d0
    blt.s   loc_17738
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_17738:
    move.w  #$C8,d3
    tst.w   d0
    bmi.s   loc_17744
    move.w  #$B8,d3
 
loc_17744:
    bsr.w   loc_175EA
    bra.w   loc_177FA
; ===========================================================================
 
loc_1774C:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    neg.w   d0
    cmpi.w  #8,d0
    blt.s   loc_17766
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_17766:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    cmpi.w  #$40,d0
    blt.s   loc_1777E
    move.w  #-$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_1777E:
    neg.w   d0
    cmpi.w  #$40,d0
    blt.s   loc_17790
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_17790:
    move.w  #8,d3
    tst.w   d0
    bmi.s   loc_1779C
    move.w  #$F8,d3
 
loc_1779C:
    bsr.w   loc_175EA
    bra.w   loc_177FA
; ===========================================================================
 
loc_177A4:
    move.w  bumper_x(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #8,d0
    blt.s   loc_177BC
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_177BC:
    move.w  bumper_y(a1),d0
    sub.w   y_pos(a0),d0
    cmpi.w  #$40,d0
    blt.s   loc_177D4
    move.w  #-$A00,y_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_177D4:
    neg.w   d0
    cmpi.w  #$40,d0
    blt.s   loc_177E6
    move.w  #$A00,x_vel(a0)
    bra.w   loc_177FA
; ===========================================================================
 
loc_177E6:
    move.w  #$78,d3
    tst.w   d0
    bmi.s   loc_177F2
    move.w  #$88,d3
 
loc_177F2:
    bsr.w   loc_175EA
    bra.w   loc_177FA
loc_177FA:
    bset    #1,status(a0)
    bclr    #4,status(a0)
    bclr    #5,status(a0)
    clr.b   jumping(a0)
    move.w  #SndID_LargeBumper,d0
    jmp (PlaySound).l
; ===========================================================================
SpecialCNZBumpers_Act1: BINCLUDE    "level/objects/CNZ 1 bumpers.bin"   ; byte_1781A
SpecialCNZBumpers_Act2: BINCLUDE    "level/objects/CNZ 2 bumpers.bin"   ; byte_1795E
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Objects Manager
; Subroutine that keeps track of any objects that need to remember
; their state, such as monitors or enemies.
;
; input variables:
;  -none-
;
; writes:
;  d0, d1
;  d2 = respawn index of object to load
;  d6 = camera position
;
;  a0 = address in object placement list
;  a2 = respawn table
; ---------------------------------------------------------------------------
 
; loc_17AA4
ObjectsManager:
    moveq   #0,d0
    move.b  (Obj_placement_routine).w,d0
    move.w  ObjectsManager_States(pc,d0.w),d0
    jmp ObjectsManager_States(pc,d0.w)
; ===========================================================================
ObjectsManager_States: offsetTable
    offsetTableEntry.w ObjectsManager_Init      ; 0
    offsetTableEntry.w ObjectsManager_Main      ; 2
    offsetTableEntry.w ObjectsManager_2P_Main   ; 4
; ===========================================================================
; loc_17AB8
ObjectsManager_Init:
    addq.b  #2,(Obj_placement_routine).w
    move.w  (Current_ZoneAndAct).w,d0 ; If level == $0F01 (ARZ 2)...
    ror.b   #1,d0           ; then this yields $0F80...
    lsr.w   #6,d0           ; and this yields $003E.
    lea (Off_Objects).l,a0  ; Next, we load the first pointer in the object layout list pointer index,
    movea.l a0,a1           ; then copy it for quicker use later.
    adda.w  (a0,d0.w),a0        ; (Point1 * 2) + $003E
    tst.w   (Two_player_mode).w ; skip if not in 2-player vs mode
    beq.s   +
    cmpi.b  #casino_night_zone,(Current_Zone).w ; skip if not Casino Night Zone
    bne.s   +
    lea (Objects_CNZ1_2P).l,a0  ; CNZ 1 2-player object layout
    tst.b   (Current_Act).w     ; skip if not past act 1
    beq.s   +
    lea (Objects_CNZ2_2P).l,a0  ; CNZ 2 2-player object layout
+
    ; initialize each object load address with the first object in the layout
    move.l  a0,(Obj_load_addr_right).w
    move.l  a0,(Obj_load_addr_left).w
    move.l  a0,(Obj_load_addr_2).w
    move.l  a0,(Obj_load_addr_3).w
    lea (Object_Respawn_Table).w,a2
    move.w  #$101,(a2)+ ; the first two bytes are not used as respawn values
    ; instead, they are used to keep track of the current respawn indexes
 
    ; Bug: The '+7E' shouldn't be here; this loop accidentally clears an additional $7E bytes
    move.w  #bytesToLcnt(Obj_respawn_data_End-Obj_respawn_data+$7E),d0 ; set loop counter
-   clr.l   (a2)+       ; loop clears all other respawn values
    dbf d0,-
 
    lea (Obj_respawn_index).w,a2    ; reset a2
    moveq   #0,d2
    move.w  (Camera_X_pos).w,d6
    subi.w  #$80,d6 ; look one chunk to the left
    bcc.s   +   ; if the result was negative,
    moveq   #0,d6   ; cap at zero
+
    andi.w  #$FF80,d6   ; limit to increments of $80 (width of a chunk)
    movea.l (Obj_load_addr_right).w,a0  ; load address of object placement list
 
-   ; at the beginning of a level this gives respawn table entries to any object that is one chunk
    ; behind the left edge of the screen that needs to remember its state (Monitors, Badniks, etc.)
    cmp.w   (a0),d6     ; is object's x position >= d6?
    bls.s   loc_17B3E   ; if yes, branch
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    move.b  (a2),d2
    addq.b  #1,(a2) ; respawn index of next object to the right
+
    addq.w  #6,a0   ; next object
    bra.s   -
; ---------------------------------------------------------------------------
 
loc_17B3E:
    move.l  a0,(Obj_load_addr_right).w  ; remember rightmost object that has been processed, so far (we still need to look forward)
    move.l  a0,(Obj_load_addr_2).w
    movea.l (Obj_load_addr_left).w,a0   ; reset a0
    subi.w  #$80,d6     ; look even farther left (any object behind this is out of range)
    bcs.s   loc_17B62   ; branch, if camera position would be behind level's left boundary
 
-   ; count how many objects are behind the screen that are not in range and need to remember their state
    cmp.w   (a0),d6     ; is object's x position >= d6?
    bls.s   loc_17B62   ; if yes, branch
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    addq.b  #1,1(a2)    ; respawn index of current object to the left
 
+
    addq.w  #6,a0
    bra.s   -   ; continue with next object
; ---------------------------------------------------------------------------
 
loc_17B62:
    move.l  a0,(Obj_load_addr_left).w   ; remember current object from the left
    move.l  a0,(Obj_load_addr_3).w
    move.w  #-1,(Camera_X_pos_last).w   ; make sure ObjectsManager_GoingForward is run
    move.w  #-1,(Camera_X_pos_last_P2).w
    tst.w   (Two_player_mode).w ; is it two player mode?
    beq.s   ObjectsManager_Main ; if not, branch
    addq.b  #2,(Obj_placement_routine).w
    bra.w   ObjectsManager_2P_Init
; ---------------------------------------------------------------------------
; loc_17B84
ObjectsManager_Main:
    move.w  (Camera_X_pos).w,d1
    subi.w  #$80,d1
    andi.w  #$FF80,d1
    move.w  d1,(Camera_X_pos_coarse).w
 
    lea (Obj_respawn_index).w,a2
    moveq   #0,d2
    move.w  (Camera_X_pos).w,d6
    andi.w  #$FF80,d6
    cmp.w   (Camera_X_pos_last).w,d6    ; is the X range the same as last time?
    beq.w   ObjectsManager_SameXRange   ; if yes, branch (rts)
    bge.s   ObjectsManager_GoingForward ; if new pos is greater than old pos, branch
    ; if the player is moving back
    move.w  d6,(Camera_X_pos_last).w    ; remember current position for next time
    movea.l (Obj_load_addr_left).w,a0   ; get current object from the left
    subi.w  #$80,d6     ; look one chunk to the left
    bcs.s   loc_17BE6   ; branch, if camera position would be behind level's left boundary
 
-   ; load all objects left of the screen that are now in range
    cmp.w   -6(a0),d6   ; is the previous object's X pos less than d6?
    bge.s   loc_17BE6   ; if it is, branch
    subq.w  #6,a0       ; get object's address
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    subq.b  #1,1(a2)    ; respawn index of this object
    move.b  1(a2),d2
+
    bsr.w   ChkLoadObj  ; load object
    bne.s   +       ; branch, if SST is full
    subq.w  #6,a0
    bra.s   -   ; continue with previous object
; ---------------------------------------------------------------------------
 
+   ; undo a few things, if the object couldn't load
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    addq.b  #1,1(a2)    ; since we didn't load the object, undo last change
+
    addq.w  #6,a0   ; go back to last object
 
loc_17BE6:
    move.l  a0,(Obj_load_addr_left).w   ; remember current object from the left
    movea.l (Obj_load_addr_right).w,a0  ; get next object from the right
    addi.w  #$300,d6    ; look two chunks beyond the right edge of the screen
 
-   ; subtract number of objects that have been moved out of range (from the right side)
    cmp.w   -6(a0),d6   ; is the previous object's X pos less than d6?
    bgt.s   loc_17C04   ; if it is, branch
    tst.b   -4(a0)  ; does the previous object get a respawn table entry?
    bpl.s   +   ; if not, branch
    subq.b  #1,(a2)     ; respawn index of next object to the right
+
    subq.w  #6,a0
    bra.s   -   ; continue with previous object
; ---------------------------------------------------------------------------
 
loc_17C04:
    move.l  a0,(Obj_load_addr_right).w  ; remember next object from the right
    rts
; ---------------------------------------------------------------------------
 
ObjectsManager_GoingForward:
    move.w  d6,(Camera_X_pos_last).w
    movea.l (Obj_load_addr_right).w,a0  ; get next object from the right
    addi.w  #$280,d6    ; look two chunks forward
 
-   ; load all objects right of the screen that are now in range
    cmp.w   (a0),d6     ; is object's x position >= d6?
    bls.s   loc_17C2A   ; if yes, branch
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    move.b  (a2),d2     ; respawn index of this object
    addq.b  #1,(a2)     ; respawn index of next object to the right
+
    bsr.w   ChkLoadObj  ; load object (and get address of next object)
    beq.s   -   ; continue loading objects, if the SST isn't full
 
loc_17C2A:
    move.l  a0,(Obj_load_addr_right).w  ; remember next object from the right
    movea.l (Obj_load_addr_left).w,a0   ; get current object from the left
    subi.w  #$300,d6    ; look one chunk behind the left edge of the screen
    bcs.s   loc_17C4A   ; branch, if camera position would be behind level's left boundary
 
-   ; subtract number of objects that have been moved out of range (from the left)
    cmp.w   (a0),d6     ; is object's x position >= d6?
    bls.s   loc_17C4A   ; if yes, branch
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    addq.b  #1,1(a2)    ; respawn index of next object to the left
+
    addq.w  #6,a0
    bra.s   -   ; continue with previous object
; ---------------------------------------------------------------------------
 
loc_17C4A:
    move.l  a0,(Obj_load_addr_left).w   ; remember current object from the left
 
ObjectsManager_SameXRange:
    rts
; ---------------------------------------------------------------------------
; loc_17C50
ObjectsManager_2P_Init:
    moveq   #-1,d0
    move.l  d0,(unk_F780).w
    move.l  d0,(unk_F780+4).w
    move.l  d0,(unk_F780+8).w
    move.l  d0,(Camera_X_pos_last_P2).w ; both words that this sets to -1 are overwritten directly underneath, so this line is rather pointless...
    move.w  #0,(Camera_X_pos_last).w
    move.w  #0,(Camera_X_pos_last_P2).w
    lea (Obj_respawn_index).w,a2
    move.w  (a2),(Obj_respawn_index_P2).w   ; mirrior first two bytes (respawn indices) for player 2(?)
    moveq   #0,d2
    ; run initialization for player 1
    lea (Obj_respawn_index).w,a5
    lea (Obj_load_addr_right).w,a4
    lea (unk_F786).w,a1 ; = -1, -1, -1
    lea (unk_F789).w,a6 ; = -1, -1, -1
    moveq   #-2,d6
    bsr.w   ObjMan2P_GoingForward
    lea (unk_F786).w,a1
    moveq   #-1,d6
    bsr.w   ObjMan2P_GoingForward
    lea (unk_F786).w,a1
    moveq   #0,d6
    bsr.w   ObjMan2P_GoingForward
    ; run initialization for player 2
    lea (Obj_respawn_index_P2).w,a5
    lea (Obj_load_addr_2).w,a4
    lea (unk_F789).w,a1
    lea (unk_F786).w,a6
    moveq   #-2,d6
    bsr.w   ObjMan2P_GoingForward
    lea (unk_F789).w,a1
    moveq   #-1,d6
    bsr.w   ObjMan2P_GoingForward
    lea (unk_F789).w,a1
    moveq   #0,d6
    bsr.w   ObjMan2P_GoingForward
 
; loc_17CCC
ObjectsManager_2P_Main:
    move.w  (Camera_X_pos).w,d1
    andi.w  #$FF00,d1
    move.w  d1,(Camera_X_pos_coarse).w
 
    move.w  (Camera_X_pos_P2).w,d1
    andi.w  #$FF00,d1
    move.w  d1,(Camera_X_pos_coarse_P2).w
 
    move.b  (Camera_X_pos).w,d6 ; get upper byte of camera positon
    andi.w  #$FF,d6
    move.w  (Camera_X_pos_last).w,d0
    cmp.w   (Camera_X_pos_last).w,d6    ; is the X range the same as last time?
    beq.s   +               ; if yes, branch
    move.w  d6,(Camera_X_pos_last).w    ; remember current position for next time
    lea (Obj_respawn_index).w,a5
    lea (Obj_load_addr_right).w,a4
    lea (unk_F786).w,a1
    lea (unk_F789).w,a6
    bsr.s   ObjectsManager_2P_Run
+
    move.b  (Camera_X_pos_P2).w,d6  ; get upper byte of camera positon
    andi.w  #$FF,d6
    move.w  (Camera_X_pos_last_P2).w,d0
    cmp.w   (Camera_X_pos_last_P2).w,d6 ; is the X range the same as last time?
    beq.s   return_17D34            ; if yes, branch (rts)
    move.w  d6,(Camera_X_pos_last_P2).w
    lea (Obj_respawn_index_P2).w,a5
    lea (Obj_load_addr_2).w,a4
    lea (unk_F789).w,a1
    lea (unk_F786).w,a6
    bsr.s   ObjectsManager_2P_Run
 
return_17D34:
    rts
; ===========================================================================
 
ObjectsManager_2P_Run:
    lea (Obj_respawn_index).w,a2
    moveq   #0,d2
    cmp.w   d0,d6               ; is the X range the same as last time?
    beq.w   ObjectsManager_SameXRange   ; if yes, branch (rts)
    bge.w   ObjMan2P_GoingForward   ; if new pos is greater than old pos, branch
    ; if the player is moving back
    move.b  2(a1),d2
    move.b  1(a1),2(a1)
    move.b  (a1),1(a1)
    move.b  d6,(a1)
    cmp.b   (a6),d2
    beq.s   +
    cmp.b   1(a6),d2
    beq.s   +
    cmp.b   2(a6),d2
    beq.s   +
    bsr.w   ObjectsManager_2P_UnkSub3
    bra.s   loc_17D70
; ---------------------------------------------------------------------------
 
+
    bsr.w   ObjMan_2P_UnkSub2
 
loc_17D70:
    bsr.w   ObjMan_2P_UnkSub1
    bne.s   loc_17D94   ; if whatever checks were just performed were all not equal, branch
    movea.l 4(a4),a0
 
-
    cmp.b   -6(a0),d6
    bne.s   loc_17D8E
    tst.b   -4(a0)
    bpl.s   +
    subq.b  #1,1(a5)
+
    subq.w  #6,a0
    bra.s   -
; ---------------------------------------------------------------------------
 
loc_17D8E:
    move.l  a0,4(a4)
    bra.s   loc_17DCA
; ---------------------------------------------------------------------------
 
loc_17D94:
    movea.l 4(a4),a0
    move.b  d6,(a1)
 
-
    cmp.b   -6(a0),d6
    bne.s   loc_17DC6
    subq.w  #6,a0
    tst.b   2(a0)
    bpl.s   +
    subq.b  #1,1(a5)
    move.b  1(a5),d2
+
    bsr.w   ChkLoadObj_2P
    bne.s   loc_17DBA
    subq.w  #6,a0
    bra.s   -
; ---------------------------------------------------------------------------
 
loc_17DBA:
    tst.b   2(a0)
    bpl.s   +
    addq.b  #1,1(a5)
+
    addq.w  #6,a0
 
loc_17DC6:
    move.l  a0,4(a4)
 
loc_17DCA:
    movea.l (a4),a0
    addq.w  #3,d6
 
-
    cmp.b   -6(a0),d6
    bne.s   loc_17DE0
    tst.b   -4(a0)
    bpl.s   +
    subq.b  #1,(a5)
+
    subq.w  #6,a0
    bra.s   -
; ---------------------------------------------------------------------------
 
loc_17DE0:
    move.l  a0,(a4)
    rts
; ===========================================================================
;loc_17DE4:
ObjMan2P_GoingForward:
    addq.w  #2,d6       ; look forward two chunks
 
    move.b  (a1),d2     ; shift positions in array left once
    move.b  1(a1),(a1)  ; nearest chunk to the right
    move.b  2(a1),1(a1) ; middle chunk to the right
    move.b  d6,2(a1)    ; farthest chunk to the right
 
    cmp.b   (a6),d2     ; compare farthset distance
    beq.s   +
    cmp.b   1(a6),d2
    beq.s   +
    cmp.b   2(a6),d2
    beq.s   +
 
    bsr.w   ObjectsManager_2P_UnkSub3   ; if not, run this sub-routine
    bra.s   loc_17E10
; ---------------------------------------------------------------------------
 
+
    bsr.w   ObjMan_2P_UnkSub2
 
loc_17E10:
    bsr.w   ObjMan_2P_UnkSub1
    bne.s   loc_17E2C   ; if whatever checks were just performed were all not equal, branch
    movea.l (a4),a0
 
-
    cmp.b   (a0),d6
    bne.s   loc_17E28
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    addq.b  #1,(a5)
+
    addq.w  #6,a0
    bra.s   -
; ===========================================================================
 
loc_17E28:
    move.l  a0,(a4)
    bra.s   loc_17E46
; ===========================================================================
 
loc_17E2C:
    movea.l (a4),a0
    move.b  d6,(a1)
 
-
    cmp.b   (a0),d6
    bne.s   loc_17E44
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    move.b  (a5),d2
    addq.b  #1,(a5)
+
    bsr.w   ChkLoadObj_2P
    beq.s   -
 
loc_17E44:
    move.l  a0,(a4)
 
loc_17E46:
    movea.l 4(a4),a0
    subq.w  #3,d6
    bcs.s   loc_17E60
 
loc_17E4E:
    cmp.b   (a0),d6
    bne.s   loc_17E60
    tst.b   2(a0)
    bpl.s   loc_17E5C
    addq.b  #1,1(a5)
 
loc_17E5C:
    addq.w  #6,a0
    bra.s   loc_17E4E
; ===========================================================================
 
loc_17E60:
    move.l  a0,4(a4)
    rts
; ===========================================================================
;loc_17E66:
ObjMan_2P_UnkSub1:
    move.l  a1,-(sp)
    lea (unk_F780).w,a1
    cmp.b   (a1)+,d6
    beq.s   +
    cmp.b   (a1)+,d6
    beq.s   +
    cmp.b   (a1)+,d6
    beq.s   +
    cmp.b   (a1)+,d6
    beq.s   +
    cmp.b   (a1)+,d6
    beq.s   +
    cmp.b   (a1)+,d6
    beq.s   +
    moveq   #1,d0
+
    movea.l (sp)+,a1
    rts
; ===========================================================================
;loc_17E8A:
ObjMan_2P_UnkSub2:
    lea (unk_F780).w,a1
    lea (Dynamic_Object_RAM_2P_End).w,a3
    tst.b   (a1)+
    bmi.s   +
    lea (Dynamic_Object_RAM_2P_End+$C*object_size).w,a3
    tst.b   (a1)+
    bmi.s   +
    lea (Dynamic_Object_RAM_2P_End+$18*object_size).w,a3
    tst.b   (a1)+
    bmi.s   +
    lea (Dynamic_Object_RAM_2P_End+$24*object_size).w,a3
    tst.b   (a1)+
    bmi.s   +
    lea (Dynamic_Object_RAM_2P_End+$30*object_size).w,a3
    tst.b   (a1)+
    bmi.s   +
    lea (Dynamic_Object_RAM_2P_End+$3C*object_size).w,a3
    tst.b   (a1)+
    bmi.s   +
    nop
    nop
+
    subq.w  #1,a1
    rts
; ===========================================================================
; this sub-routine appears to determine which 12 byte block of object RAM
; corresponds to the current out-of-range camera positon (in d2) and deletes
; the objects in this block. This most likely takes over the functionality
; of markObjGone, as that routine isn't called in two player mode.
;loc_17EC6:
ObjectsManager_2P_UnkSub3:
    lea (unk_F780).w,a1
    lea (Dynamic_Object_RAM_2P_End).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +  
    lea (Dynamic_Object_RAM_2P_End+$C*object_size).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +  
    lea (Dynamic_Object_RAM_2P_End+$18*object_size).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +  
    lea (Dynamic_Object_RAM_2P_End+$24*object_size).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +  
    lea (Dynamic_Object_RAM_2P_End+$30*object_size).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +  
    lea (Dynamic_Object_RAM_2P_End+$3C*object_size).w,a3
    cmp.b   (a1)+,d2   
    beq.s   +
    nop
    nop
+
    move.b  #-1,-(a1)
    movem.l a1/a3,-(sp)
    moveq   #0,d1       ; used later to delete objects
    moveq   #$C-1,d2
 
;loc_17F0A:
ObjMan2P_UnkSub3_DeleteBlockLoop:
    tst.b   (a3)
    beq.s   ObjMan2P_UnkSub3_DeleteBlock_SkipObj    ; branch if slot is empty
    movea.l a3,a1
    moveq   #0,d0
    move.b  respawn_index(a1),d0    ; does object remember its state?
    beq.s   +           ; if not, branch
    bclr    #7,2(a2,d0.w)   ; else, clear entry in respawn table
 
    ; inlined DeleteObject2:
+
    moveq   #bytesToLcnt(next_object),d0 ; we want to clear up to the next object
    ; note: d1 is already 0
 
    ; delete the object by setting all of its bytes to 0
-   move.l  d1,(a1)+
    dbf d0,-
    if object_size&3
    move.w  d1,(a1)+
    endif
 
;loc_17F26:
ObjMan2P_UnkSub3_DeleteBlock_SkipObj:
    lea next_object(a3),a3 ; a3=object
    dbf d2,ObjMan2P_UnkSub3_DeleteBlockLoop
    moveq   #0,d2
    movem.l (sp)+,a1/a3
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Subroutine to check if an object needs to be loaded.
;
; input variables:
;  d2 = respawn index of object to be loaded
;
;  a0 = address in object placement list
;  a2 = object respawn table
;
; writes:
;  d0, d1
;  a1 = object
; ---------------------------------------------------------------------------
;loc_17F36:
ChkLoadObj:
    tst.b   2(a0)   ; does the object get a respawn table entry?
    bpl.s   +   ; if not, branch
    bset    #7,2(a2,d2.w)   ; mark object as loaded
    beq.s   +       ; branch if it wasn't already loaded
    addq.w  #6,a0   ; next object
    moveq   #0,d0   ; let the objects manager know that it can keep going
    rts
; ---------------------------------------------------------------------------
 
+
    bsr.w   SingleObjLoad   ; find empty slot
    bne.s   return_17F7E    ; branch, if there is no room left in the SST
    move.w  (a0)+,x_pos(a1)
    move.w  (a0)+,d0    ; there are three things stored in this word
    bpl.s   +       ; branch, if the object doesn't get a respawn table entry
    move.b  d2,respawn_index(a1)
+
    move.w  d0,d1       ; copy for later
    andi.w  #$FFF,d0    ; get y-position
    move.w  d0,y_pos(a1)
    rol.w   #3,d1   ; adjust bits
    andi.b  #3,d1   ; get render flags
    move.b  d1,render_flags(a1)
    move.b  d1,status(a1)
    _move.b (a0)+,id(a1) ; load obj
    move.b  (a0)+,subtype(a1)
    moveq   #0,d0
 
return_17F7E:
    rts
; ===========================================================================
;loc_17F80:
ChkLoadObj_2P:
    tst.b   2(a0)       ; does the object get a respawn table entry?
    bpl.s   +       ; if not, branch
    bset    #7,2(a2,d2.w)   ; mark object as loaded
    beq.s   +       ; branch if it wasn't already loaded
    addq.w  #6,a0   ; next object
    moveq   #0,d0   ; let the objects manager know that it can keep going
    rts
; ---------------------------------------------------------------------------
 
+
    btst    #4,2(a0)    ; the bit that's being tested for here should always be zero,
    beq.s   +       ; but assuming it weren't and this branch isn't taken,
    bsr.w   SingleObjLoad   ; then this object would not be loaded into one of the 12
    bne.s   return_17FD8    ; byte blocks after Dynamic_Object_RAM_2P_End and would most
    bra.s   ChkLoadObj_2P_LoadData  ; likely end up somwhere before this in Dynamic_Object_RAM
; ---------------------------------------------------------------------------
 
+
    bsr.w   SingleObjLoad3  ; find empty slot in current 12 object block
    bne.s   return_17FD8    ; branch, if there is no room left in this block
;loc_17FAA:
ChkLoadObj_2P_LoadData:
    move.w  (a0)+,x_pos(a1)
    move.w  (a0)+,d0    ; there are three things stored in this word
    bpl.s   +       ; branch, if the object doesn't get a respawn table entry
    move.b  d2,respawn_index(a1)
+
    move.w  d0,d1       ; copy for later
    andi.w  #$FFF,d0    ; get y-position
    move.w  d0,y_pos(a1)
    rol.w   #3,d1   ; adjust bits
    andi.b  #3,d1   ; get render flags
    move.b  d1,render_flags(a1)
    move.b  d1,status(a1)
    _move.b (a0)+,id(a1) ; load obj
    move.b  (a0)+,subtype(a1)
    moveq   #0,d0
 
return_17FD8:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Single object loading subroutine
; Find an empty object array
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_17FDA: ; allocObject:
SingleObjLoad:
    lea (Dynamic_Object_RAM).w,a1 ; a1=object
    move.w  #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d0 ; search to end of table
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  #(Dynamic_Object_RAM_2P_End-Dynamic_Object_RAM)/object_size-1,d0 ; search to $BF00 exclusive
 
/
    tst.b   id(a1)  ; is object RAM slot empty?
    beq.s   return_17FF8    ; if yes, branch
    lea next_object(a1),a1 ; load obj address ; goto next object RAM slot
    dbf d0,-    ; repeat until end
 
return_17FF8:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Single object loading subroutine
; Find an empty object array AFTER the current one in the table
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_17FFA: ; allocObjectAfterCurrent:
SingleObjLoad2:
    movea.l a0,a1
    move.w  #Dynamic_Object_RAM_End,d0  ; $D000
    sub.w   a0,d0   ; subtract current object location
    if object_size=$40
    lsr.w   #6,d0   ; divide by $40
    else
    divu.w  #object_size,d0
    endif
    subq.w  #1,d0   ; keep from going over the object zone
    bcs.s   return_18014
 
-
    tst.b   id(a1)  ; is object RAM slot empty?
    beq.s   return_18014    ; if yes, branch
    lea next_object(a1),a1 ; load obj address ; goto next object RAM slot
    dbf d0,-    ; repeat until end
 
return_18014:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Single object loading subroutine
; Find an empty object at or within < 12 slots after a3
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_18016:
SingleObjLoad3:
    movea.l a3,a1
    move.w  #$B,d0
 
-
    tst.b   id(a1)  ; is object RAM slot empty?
    beq.s   return_18028    ; if yes, branch
    lea next_object(a1),a1 ; load obj address ; goto next object RAM slot
    dbf d0,-    ; repeat until end
 
return_18028:
    rts
; ===========================================================================
 
;---------------------------------------------------------------------------------------
; CNZ act 1 object layout for 2-player mode (various objects were deleted)
;---------------------------------------------------------------------------------------
; byte_1802A;
    if gameRevision=0
Objects_CNZ1_2P:    BINCLUDE    "level/objects/CNZ_1_2P (REV00).bin"
    else
    ; a Crawl badnik was moved slightly further away from a ledge
    ; 2 flippers were moved closer to a wall
Objects_CNZ1_2P:    BINCLUDE    "level/objects/CNZ_1_2P.bin"
    endif
;---------------------------------------------------------------------------------------
; CNZ act 2 object layout for 2-player mode (various objects were deleted)
;---------------------------------------------------------------------------------------
; byte_18492:
    if gameRevision=0
Objects_CNZ2_2P:    BINCLUDE    "level/objects/CNZ_2_2P (REV00).bin"
    else
    ; 4 Crawl badniks were slightly moved, placing them closer/farther away from ledges
    ; 2 flippers were moved away from a wall to keep players from getting stuck behind them
Objects_CNZ2_2P:    BINCLUDE    "level/objects/CNZ_2_2P.bin"
    endif
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 41 - Spring
; ----------------------------------------------------------------------------
; Sprite_18888:
Obj41:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj41_Index(pc,d0.w),d1
    jsr Obj41_Index(pc,d1.w)
    jmp (MarkObjGone).l
; ===========================================================================
; off_1889C:
Obj41_Index:    offsetTable
        offsetTableEntry.w Obj41_Init       ;  0
        offsetTableEntry.w Obj41_Up     ;  2
        offsetTableEntry.w Obj41_Horizontal ;  4
        offsetTableEntry.w Obj41_Down       ;  6
        offsetTableEntry.w Obj41_DiagonallyUp   ;  8
        offsetTableEntry.w Obj41_DiagonallyDown ; $A
; ===========================================================================
; loc_188A8:
Obj41_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj41_MapUnc_1901C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_VrtclSprng,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$E,d0
    move.w  Obj41_Init_Subtypes(pc,d0.w),d0
    jmp Obj41_Init_Subtypes(pc,d0.w)
; ===========================================================================
; off_188DE:
Obj41_Init_Subtypes: offsetTable
    offsetTableEntry.w Obj41_Init_Up        ; 0
    offsetTableEntry.w Obj41_Init_Horizontal    ; 2
    offsetTableEntry.w Obj41_Init_Down      ; 4
    offsetTableEntry.w Obj41_Init_DiagonallyUp  ; 6
    offsetTableEntry.w Obj41_Init_DiagonallyDown    ; 8
; ===========================================================================
; loc_188E8:
Obj41_Init_Horizontal:
    move.b  #4,routine(a0)
    move.b  #2,anim(a0)
    move.b  #3,mapping_frame(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HrzntlSprng,0,0),art_tile(a0)
    move.b  #8,width_pixels(a0)
    bra.s   Obj41_Init_Common
; ===========================================================================
; loc_18908:
Obj41_Init_Down:
    move.b  #6,routine(a0)
    move.b  #6,mapping_frame(a0)
    bset    #1,status(a0)
    bra.s   Obj41_Init_Common
; ===========================================================================
; loc_1891C:
Obj41_Init_DiagonallyUp:
    move.b  #8,routine(a0)
    move.b  #4,anim(a0)
    move.b  #7,mapping_frame(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_DignlSprng,0,0),art_tile(a0)
    bra.s   Obj41_Init_Common
; ===========================================================================
; loc_18936:
Obj41_Init_DiagonallyDown:
    move.b  #$A,routine(a0)
    move.b  #4,anim(a0)
    move.b  #$A,mapping_frame(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_DignlSprng,0,0),art_tile(a0)
    bset    #1,status(a0)
; loc_18954:
Obj41_Init_Up:
Obj41_Init_Common:
    ; checks color of spring
    move.b  subtype(a0),d0
    andi.w  #2,d0
    move.w  Obj41_Strengths(pc,d0.w),objoff_30(a0)
    btst    #1,d0
    beq.s   +
    bset    #palette_bit_0,art_tile(a0)
    move.l  #Obj41_MapUnc_19032,mappings(a0)
+
    bsr.w   Adjust2PArtPointer
    rts
; ===========================================================================
; word_1897C:
Obj41_Strengths:
    ; Speed applied on Sonic
    dc.w -$1000
    dc.w  -$A00
; ===========================================================================
; loc_18980:
Obj41_Up:
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SolidObject_Always_SingleCharacter
    btst    #p1_standing_bit,status(a0)
    beq.s   loc_189A8
    bsr.s   loc_189CA
 
loc_189A8:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SolidObject_Always_SingleCharacter
    btst    #p2_standing_bit,status(a0)
    beq.s   loc_189C0
    bsr.s   loc_189CA
 
loc_189C0:
    lea (Ani_obj41).l,a1
    bra.w   AnimateSprite
; ===========================================================================
 
loc_189CA:
    move.w  #$100,anim(a0)
    addq.w  #8,y_pos(a1)
    move.w  objoff_30(a0),y_vel(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  subtype(a0),d0
    bpl.s   loc_189FE
    move.w  #0,x_vel(a1)
 
loc_189FE:
    btst    #0,d0
    beq.s   loc_18A3E
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_18A2E
    move.b  #1,flips_remaining(a1)
 
loc_18A2E:
    btst    #0,status(a1)
    beq.s   loc_18A3E
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_18A3E:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_18A54
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_18A54:
    cmpi.b  #8,d0
    bne.s   loc_18A66
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_18A66:
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_18A70:
Obj41_Horizontal:
    move.w  #$13,d1
    move.w  #$E,d2
    move.w  #$F,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SolidObject_Always_SingleCharacter
    btst    #p1_pushing_bit,status(a0)
    beq.s   loc_18AB0
    move.b  status(a0),d1
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcs.s   loc_18AA8
    eori.b  #1,d1
 
loc_18AA8:
    andi.b  #1,d1
    bne.s   loc_18AB0
    bsr.s   loc_18AEE
 
loc_18AB0:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SolidObject_Always_SingleCharacter
    btst    #p2_pushing_bit,status(a0)
    beq.s   loc_18AE0
    move.b  status(a0),d1
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcs.s   loc_18AD8
    eori.b  #1,d1
 
loc_18AD8:
    andi.b  #1,d1
    bne.s   loc_18AE0
    bsr.s   loc_18AEE
 
loc_18AE0:
    bsr.w   loc_18BC6
    lea (Ani_obj41).l,a1
    bra.w   AnimateSprite
; ===========================================================================
 
loc_18AEE:
    move.w  #$300,anim(a0)
    move.w  objoff_30(a0),x_vel(a1)
    addq.w  #8,x_pos(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_18B1C
    bclr    #0,status(a1)
    subi.w  #$10,x_pos(a1)
    neg.w   x_vel(a1)
 
loc_18B1C:
    move.w  #$F,move_lock(a1)
    move.w  x_vel(a1),inertia(a1)
    btst    #2,status(a1)
    bne.s   loc_18B36
    move.b  #AniIDSonAni_Walk,anim(a1)
 
loc_18B36:
    move.b  subtype(a0),d0
    bpl.s   loc_18B42
    move.w  #0,y_vel(a1)
 
loc_18B42:
    btst    #0,d0
    beq.s   loc_18B82
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_18B72
    move.b  #3,flips_remaining(a1)
 
loc_18B72:
    btst    #0,status(a1)
    beq.s   loc_18B82
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_18B82:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_18B98
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_18B98:
    cmpi.b  #8,d0
    bne.s   loc_18BAA
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_18BAA:
    bclr    #p1_pushing_bit,status(a0)
    bclr    #p2_pushing_bit,status(a0)
    bclr    #5,status(a1)
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
 
loc_18BC6:
    cmpi.b  #3,anim(a0)
    beq.w   return_18C7E
    move.w  x_pos(a0),d0
    move.w  d0,d1
    addi.w  #$28,d1
    btst    #0,status(a0)
    beq.s   loc_18BE8
    move.w  d0,d1
    subi.w  #$28,d0
 
loc_18BE8:
    move.w  y_pos(a0),d2
    move.w  d2,d3
    subi.w  #$18,d2
    addi.w  #$18,d3
    lea (MainCharacter).w,a1 ; a1=character
    btst    #1,status(a1)
    bne.s   loc_18C3C
    move.w  inertia(a1),d4
    btst    #0,status(a0)
    beq.s   loc_18C10
    neg.w   d4
 
loc_18C10:
    tst.w   d4
    bmi.s   loc_18C3C
    move.w  x_pos(a1),d4
    cmp.w   d0,d4
    blo.w   loc_18C3C
    cmp.w   d1,d4
    bhs.w   loc_18C3C
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.w   loc_18C3C
    cmp.w   d3,d4
    bhs.w   loc_18C3C
    move.w  d0,-(sp)
    bsr.w   loc_18AEE
    move.w  (sp)+,d0
 
loc_18C3C:
    lea (Sidekick).w,a1 ; a1=character
    btst    #1,status(a1)
    bne.s   return_18C7E
    move.w  inertia(a1),d4
    btst    #0,status(a0)
    beq.s   loc_18C56
    neg.w   d4
 
loc_18C56:
    tst.w   d4
    bmi.s   return_18C7E
    move.w  x_pos(a1),d4
    cmp.w   d0,d4
    blo.w   return_18C7E
    cmp.w   d1,d4
    bhs.w   return_18C7E
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.w   return_18C7E
    cmp.w   d3,d4
    bhs.w   return_18C7E
    bsr.w   loc_18AEE
 
return_18C7E:
    rts
; ===========================================================================
; loc_18C80:
Obj41_Down:
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SolidObject_Always_SingleCharacter
    cmpi.w  #-2,d4
    bne.s   loc_18CA6
    bsr.s   loc_18CC6
 
loc_18CA6:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SolidObject_Always_SingleCharacter
    cmpi.w  #-2,d4
    bne.s   loc_18CBC
    bsr.s   loc_18CC6
 
loc_18CBC:
    lea (Ani_obj41).l,a1
    bra.w   AnimateSprite
; ===========================================================================
 
loc_18CC6:
    move.w  #$100,anim(a0)
    subq.w  #8,y_pos(a1)
    move.w  objoff_30(a0),y_vel(a1)
    neg.w   y_vel(a1)
    move.b  subtype(a0),d0
    bpl.s   loc_18CE6
    move.w  #0,x_vel(a1)
 
loc_18CE6:
    btst    #0,d0
    beq.s   loc_18D26
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_18D16
    move.b  #1,flips_remaining(a1)
 
loc_18D16:
    btst    #0,status(a1)
    beq.s   loc_18D26
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_18D26:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_18D3C
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_18D3C:
    cmpi.b  #8,d0
    bne.s   loc_18D4E
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_18D4E:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_18D6A:
Obj41_DiagonallyUp:
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  x_pos(a0),d4
    lea Obj41_SlopeData_DiagUp(pc),a2
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SlopedSolid_SingleCharacter
    btst    #p1_standing_bit,status(a0)
    beq.s   loc_18D92
    bsr.s   loc_18DB4
 
loc_18D92:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SlopedSolid_SingleCharacter
    btst    #p2_standing_bit,status(a0)
    beq.s   loc_18DAA
    bsr.s   loc_18DB4
 
loc_18DAA:
    lea (Ani_obj41).l,a1
    bra.w   AnimateSprite
; ===========================================================================
 
loc_18DB4:
    btst    #0,status(a0)
    bne.s   loc_18DCA
    move.w  x_pos(a0),d0
    subq.w  #4,d0
    cmp.w   x_pos(a1),d0
    blo.s   loc_18DD8
    rts
; ===========================================================================
 
loc_18DCA:
    move.w  x_pos(a0),d0
    addq.w  #4,d0
    cmp.w   x_pos(a1),d0
    bhs.s   loc_18DD8
    rts
; ===========================================================================
 
loc_18DD8:
    move.w  #$500,anim(a0)
    move.w  objoff_30(a0),y_vel(a1)
    move.w  objoff_30(a0),x_vel(a1)
    addq.w  #6,y_pos(a1)
    addq.w  #6,x_pos(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_18E10
    bclr    #0,status(a1)
    subi.w  #$C,x_pos(a1)
    neg.w   x_vel(a1)
 
loc_18E10:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  subtype(a0),d0
    btst    #0,d0
    beq.s   loc_18E6C
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_18E5C
    move.b  #3,flips_remaining(a1)
 
loc_18E5C:
    btst    #0,status(a1)
    beq.s   loc_18E6C
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_18E6C:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_18E82
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_18E82:
    cmpi.b  #8,d0
    bne.s   loc_18E94
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_18E94:
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_18E9E:
Obj41_DiagonallyDown:
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  x_pos(a0),d4
    lea Obj41_SlopeData_DiagDown(pc),a2
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   SlopedSolid_SingleCharacter
    cmpi.w  #-2,d4
    bne.s   loc_18EC4
    bsr.s   loc_18EE6
 
loc_18EC4:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   SlopedSolid_SingleCharacter
    cmpi.w  #-2,d4
    bne.s   loc_18EDA
    bsr.s   loc_18EE6
 
loc_18EDA:
    lea (Ani_obj41).l,a1
    bra.w   AnimateSprite
; ===========================================================================
    rts
; ===========================================================================
 
loc_18EE6:
    move.w  #$500,anim(a0)
    move.w  objoff_30(a0),y_vel(a1)
    neg.w   y_vel(a1)
    move.w  objoff_30(a0),x_vel(a1)
    subq.w  #6,y_pos(a1)
    addq.w  #6,x_pos(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_18F22
    bclr    #0,status(a1)
    subi.w  #$C,x_pos(a1)
    neg.w   x_vel(a1)
 
loc_18F22:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.b  subtype(a0),d0
    btst    #0,d0
    beq.s   loc_18F78
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_18F68
    move.b  #3,flips_remaining(a1)
 
loc_18F68:
    btst    #0,status(a1)
    beq.s   loc_18F78
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_18F78:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_18F8E
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_18F8E:
    cmpi.b  #8,d0
    bne.s   loc_18FA0
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_18FA0:
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
;byte_18FAA:
Obj41_SlopeData_DiagUp:
    dc.b $10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10,$10, $E, $C, $A,  8
    dc.b   6,  4,  2,  0,$FE,$FC,$FC,$FC,$FC,$FC,$FC,$FC; 16
;byte_18FC6:
Obj41_SlopeData_DiagDown:
    dc.b $F4,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F2,$F4,$F6,$F8
    dc.b $FA,$FC,$FE,  0,  2,  4,  4,  4,  4,  4,  4,  4; 16
 
; animation script
; off_18FE2:
Ani_obj41:  offsetTable
        offsetTableEntry.w byte_18FEE   ; 0
        offsetTableEntry.w byte_18FF1   ; 1
        offsetTableEntry.w byte_18FFD   ; 2
        offsetTableEntry.w byte_19000   ; 3
        offsetTableEntry.w byte_1900C   ; 4
        offsetTableEntry.w byte_1900F   ; 5
byte_18FEE:
    dc.b  $F
    dc.b   0    ; 1
    dc.b $FF    ; 2
    rev02even
byte_18FF1:
    dc.b   0
    dc.b   1    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   2    ; 4
    dc.b   2    ; 5
    dc.b   2    ; 6
    dc.b   2    ; 7
    dc.b   2    ; 8
    dc.b   2    ; 9
    dc.b $FD    ; 10
    dc.b   0    ; 11
    rev02even
byte_18FFD:
    dc.b  $F
    dc.b   3    ; 1
    dc.b $FF    ; 2
    rev02even
byte_19000:
    dc.b   0
    dc.b   4    ; 1
    dc.b   3    ; 2
    dc.b   3    ; 3
    dc.b   5    ; 4
    dc.b   5    ; 5
    dc.b   5    ; 6
    dc.b   5    ; 7
    dc.b   5    ; 8
    dc.b   5    ; 9
    dc.b $FD    ; 10
    dc.b   2    ; 11
    rev02even
byte_1900C:
    dc.b  $F
    dc.b   7    ; 1
    dc.b $FF    ; 2
    rev02even
byte_1900F:
    dc.b   0
    dc.b   8    ; 1
    dc.b   7    ; 2
    dc.b   7    ; 3
    dc.b   9    ; 4
    dc.b   9    ; 5
    dc.b   9    ; 6
    dc.b   9    ; 7
    dc.b   9    ; 8
    dc.b   9    ; 9
    dc.b $FD    ; 10
    dc.b   4    ; 11
    even
 
; ----------------------------------------------------------------------------
; Primary sprite mappings for springs
; ----------------------------------------------------------------------------
Obj41_MapUnc_1901C: offsetTable
    offsetTableEntry.w word_19048   ;  0
    offsetTableEntry.w word_1905A   ;  1
    offsetTableEntry.w word_19064   ;  2
    offsetTableEntry.w word_19076   ;  3
    offsetTableEntry.w word_19088   ;  4
    offsetTableEntry.w word_19092   ;  5
    offsetTableEntry.w word_190A4   ;  6
    offsetTableEntry.w word_190B6   ;  7
    offsetTableEntry.w word_190D8   ;  8
    offsetTableEntry.w word_190F2   ;  9
    offsetTableEntry.w word_19114   ; $A
; -------------------------------------------------------------------------------
; Secondary sprite mappings for springs
; merged with the above mappings; can't split to file in a useful way...
; -------------------------------------------------------------------------------
Obj41_MapUnc_19032: offsetTable
    offsetTableEntry.w word_19048   ;  0
    offsetTableEntry.w word_1905A   ;  1
    offsetTableEntry.w word_19064   ;  2
    offsetTableEntry.w word_19076   ;  3
    offsetTableEntry.w word_19088   ;  4
    offsetTableEntry.w word_19092   ;  5
    offsetTableEntry.w word_190A4   ;  6
    offsetTableEntry.w word_19136   ;  7
    offsetTableEntry.w word_19158   ;  8
    offsetTableEntry.w word_19172   ;  9
    offsetTableEntry.w word_19194   ; $A
word_19048:
    dc.w 2
    dc.w $F00D,    0,    0,$FFF0
    dc.w     5,    8,    4,$FFF8; 4
word_1905A:
    dc.w 1
    dc.w $F80D,    0,    0,$FFF0
word_19064:
    dc.w 2
    dc.w $E00D,    0,    0,$FFF0
    dc.w $F007,   $C,    6,$FFF8; 4
word_19076:
    dc.w 2
    dc.w $F003,    0,    0,    0
    dc.w $F801,    4,    2,$FFF8; 4
word_19088:
    dc.w 1
    dc.w $F003,    0,    0,$FFF8
word_19092:
    dc.w 2
    dc.w $F003,    0,    0,  $10
    dc.w $F809,    6,    3,$FFF8; 4
word_190A4:
    dc.w 2
    dc.w    $D,$1000,$1000,$FFF0
    dc.w $F005,$1008,$1004,$FFF8; 4
word_190B6:
    dc.w 4
    dc.w $F00D,    0,    0,$FFF0
    dc.w     5,    8,    4,    0; 4
    dc.w $FB05,   $C,    6,$FFF6; 8
    dc.w     5,$201C,$200E,$FFF0; 12
word_190D8:
    dc.w 3
    dc.w $F60D,    0,    0,$FFEA
    dc.w  $605,    8,    4,$FFFA; 4
    dc.w     5,$201C,$200E,$FFF0; 8
word_190F2:
    dc.w 4
    dc.w $E60D,    0,    0,$FFFB
    dc.w $F605,    8,    4,   $B; 4
    dc.w $F30B,  $10,    8,$FFF6; 8
    dc.w     5,$201C,$200E,$FFF0; 12
word_19114:
    dc.w 4
    dc.w    $D,$1000,$1000,$FFF0
    dc.w $F005,$1008,$1004,    0; 4
    dc.w $F505,$100C,$1006,$FFF6; 8
    dc.w $F005,$301C,$300E,$FFF0; 12
word_19136:
    dc.w 4
    dc.w $F00D,    0,    0,$FFF0
    dc.w     5,    8,    4,    0; 4
    dc.w $FB05,   $C,    6,$FFF6; 8
    dc.w     5,  $1C,   $E,$FFF0; 12
word_19158:
    dc.w 3
    dc.w $F60D,    0,    0,$FFEA
    dc.w  $605,    8,    4,$FFFA; 4
    dc.w     5,  $1C,   $E,$FFF0; 8
word_19172:
    dc.w 4
    dc.w $E60D,    0,    0,$FFFB
    dc.w $F605,    8,    4,   $B; 4
    dc.w $F30B,  $10,    8,$FFF6; 8
    dc.w     5,  $1C,   $E,$FFF0; 12
word_19194:
    dc.w 4
    dc.w    $D,$1000,$1000,$FFF0
    dc.w $F005,$1008,$1004,    0; 4
    dc.w $F505,$100C,$1006,$FFF6; 8
    dc.w $F005,$101C,$100E,$FFF0; 12
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ----------------------------------------------------------------------------
; Object 0D - End of level sign post
; ----------------------------------------------------------------------------
; OST:
obj0D_spinframe     = objoff_30 ; $30(a0)
obj0D_sparkleframe  = objoff_34 ; $34(a0)
obj0D_finalanim     = objoff_36 ; $36(a0) ; 4 if Tails only, 3 otherwise (determines what character to show)
; ----------------------------------------------------------------------------
 
Obj0D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0D_Index(pc,d0.w),d1
    jsr Obj0D_Index(pc,d1.w)
    lea (Ani_obj0D).l,a1
    bsr.w   AnimateSprite
    bsr.w   PLCLoad_Signpost
    bra.w   MarkObjGone
; ===========================================================================
; off_191D8: Obj_0D_subtbl: Obj0D_States:
Obj0D_Index:    offsetTable
        offsetTableEntry.w Obj0D_Init   ; 0
        offsetTableEntry.w Obj0D_Main   ; 2
; ===========================================================================
; loc_191DC: Obj_0D_sub_0:
Obj0D_Init:
    tst.w   (Two_player_mode).w
    beq.s   loc_19208
    move.l  #Obj0D_MapUnc_19656,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_2p_Signpost,0,0),art_tile(a0)
    move.b  #-1,(Signpost_prev_frame).w
    moveq   #0,d1
    move.w  #$1020,d1
    move.w  #-$80,d4
    moveq   #0,d5
    bsr.w   loc_19564
    bra.s   loc_1922C
; ---------------------------------------------------------------------------
 
loc_19208:
    cmpi.w  #metropolis_zone_act_2,(Current_ZoneAndAct).w
    beq.s   loc_1921E
    tst.b   (Current_Act).w
    beq.s   loc_1921E
    move.w  #0,x_pos(a0)
    rts
; ---------------------------------------------------------------------------
loc_1921E:
    move.l  #Obj0D_MapUnc_195BE,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Signpost,0,0),art_tile(a0)
 
loc_1922C:
    addq.b  #2,routine(a0) ; => Obj0D_Main
    bsr.w   Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  #$3C3C,(Loser_Time_Left).w
 
; loc_1924C: Obj_0D_sub_2:
Obj0D_Main:
    tst.b   (Update_HUD_timer).w
    beq.w   loc_192D6
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    bcs.s   loc_192D6
    cmpi.w  #$20,d0
    bhs.s   loc_192D6
    move.w  #SndID_Signpost,d0
    jsr (PlayMusic).l   ; play spinning sound
    clr.b   (Update_HUD_timer).w
    move.w  #1,anim(a0)
    move.w  #0,obj0D_spinframe(a0)
    move.w  (Camera_Max_X_pos).w,(Camera_Min_X_pos).w   ; lock screen
    move.b  #2,routine_secondary(a0) ; => Obj0D_Main_State2
    cmpi.b  #$C,(Loser_Time_Left).w
    bhi.s   loc_192A0
    move.w  (Level_Music).w,d0
    jsr (PlayMusic).l   ; play zone music
 
loc_192A0:
    tst.b   obj0D_finalanim(a0)
    bne.w   loc_19350
    move.b  #3,obj0D_finalanim(a0)
    cmpi.w  #2,(Player_mode).w
    bne.s   loc_192BC
    move.b  #4,obj0D_finalanim(a0)
 
loc_192BC:
    tst.w   (Two_player_mode).w
    beq.w   loc_19350
    move.w  #$3C3C,(Loser_Time_Left).w
    move.w  #SndID_Signpost2P,d0    ; play different spinning sound
    jsr (PlaySound).l
    bra.s   loc_19350
; ---------------------------------------------------------------------------
 
loc_192D6:
    tst.w   (Two_player_mode).w
    beq.s   loc_19350
    tst.b   (Update_HUD_timer_2P).w
    beq.s   loc_19350
    lea (Sidekick).w,a1 ; a1=character
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    bcs.s   loc_19350
    cmpi.w  #$20,d0
    bhs.s   loc_19350
    move.w  #SndID_Signpost,d0
    jsr (PlayMusic).l
    clr.b   (Update_HUD_timer_2P).w
    move.w  #1,anim(a0)
    move.w  #0,obj0D_spinframe(a0)
    move.w  (Tails_Max_X_pos).w,(Tails_Min_X_pos).w
    move.b  #2,routine_secondary(a0) ; => Obj0D_Main_State2
    cmpi.b  #$C,(Loser_Time_Left).w
    bhi.s   loc_1932E
    move.w  (Level_Music).w,d0
    jsr (PlayMusic).l
 
loc_1932E:
    tst.b   obj0D_finalanim(a0)
    bne.s   loc_19350
    move.b  #4,obj0D_finalanim(a0)
    tst.w   (Two_player_mode).w
    beq.s   loc_19350
    move.w  #$3C3C,(Loser_Time_Left).w
    move.w  #SndID_Signpost2P,d0
    jsr (PlaySound).l
 
loc_19350:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj0D_Main_States(pc,d0.w),d1
    jmp Obj0D_Main_States(pc,d1.w)
; ===========================================================================
Obj0D_Main_States: offsetTable
    offsetTableEntry.w Obj0D_Main_StateNull ; 0
    offsetTableEntry.w Obj0D_Main_State2    ; 2
    offsetTableEntry.w Obj0D_Main_State3    ; 4
    offsetTableEntry.w Obj0D_Main_State4    ; 6
; ===========================================================================
; return_19366:
Obj0D_Main_StateNull:
    rts
; ===========================================================================
; loc_19368:
Obj0D_Main_State2:
    subq.w  #1,obj0D_spinframe(a0)
    bpl.s   loc_19398
    move.w  #$3C,obj0D_spinframe(a0)
    addq.b  #1,anim(a0)
    cmpi.b  #3,anim(a0)
    bne.s   loc_19398
    move.b  #4,routine_secondary(a0) ; => Obj0D_Main_State3
    move.b  obj0D_finalanim(a0),anim(a0)
    tst.w   (Two_player_mode).w
    beq.s   loc_19398
    move.b  #6,routine_secondary(a0) ; => Obj0D_Main_State4
 
loc_19398:
    subq.w  #1,objoff_32(a0)
    bpl.s   return_19406
    move.w  #$B,objoff_32(a0)
    moveq   #0,d0
    move.b  obj0D_sparkleframe(a0),d0
    addq.b  #2,obj0D_sparkleframe(a0)
    andi.b  #$E,obj0D_sparkleframe(a0)
    lea Obj0D_RingSparklePositions(pc,d0.w),a2
    bsr.w   SingleObjLoad
    bne.s   return_19406
    _move.b #ObjID_Ring,id(a1) ; load obj25 (a ring) for the sparkly effects over the signpost
    move.b  #6,routine(a1) ; => Obj_25_sub_6
    move.b  (a2)+,d0
    ext.w   d0
    add.w   x_pos(a0),d0
    move.w  d0,x_pos(a1)
    move.b  (a2)+,d0
    ext.w   d0
    add.w   y_pos(a0),d0
    move.w  d0,y_pos(a1)
    move.l  #Obj25_MapUnc_12382,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #2,priority(a1)
    move.b  #8,width_pixels(a1)
 
return_19406:
    rts
; ===========================================================================
; byte_19408:
Obj0D_RingSparklePositions:
    dc.b -24,-16    ; 1
    dc.b   8,  8    ; 3
    dc.b -16,  0    ; 5
    dc.b  24, -8    ; 7
    dc.b   0, -8    ; 9
    dc.b  16,  0    ; 11
    dc.b -24,  8    ; 13
    dc.b  24, 16    ; 15
; ===========================================================================
; loc_19418:
Obj0D_Main_State3:
    tst.w   (Debug_placement_mode).w
    bne.w   return_194D0
    btst    #1,(MainCharacter+status).w
    bne.s   loc_19434
    move.b  #1,(Control_Locked).w
    move.w  #(button_right_mask<<8)|0,(Ctrl_1_Logical).w
 
loc_19434:
    tst.b   (MainCharacter).w
    beq.s   loc_1944C
    move.w  (MainCharacter+x_pos).w,d0
    move.w  (Camera_Max_X_pos).w,d1
    addi.w  #$128,d1
    cmp.w   d1,d0
    blo.w   return_194D0
 
loc_1944C:
    move.b  #0,routine_secondary(a0) ; => Obj0D_Main_StateNull
;loc_19452:
Load_EndOfAct:
    lea (MainCharacter).w,a1 ; a1=character
    clr.b   status_secondary(a1)
    clr.b   (Update_HUD_timer).w
    bsr.w   SingleObjLoad
    bne.s   +
    move.b  #ObjID_Results,id(a1) ; load obj3A (end of level results screen)
+
    moveq   #PLCID_Results,d0
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    moveq   #PLCID_ResultsTails,d0
+
    jsr (LoadPLC2).l
    move.b  #1,(Update_Bonus_score).w
    moveq   #0,d0
    move.b  (Timer_minute).w,d0
    mulu.w  #$3C,d0
    moveq   #0,d1
    move.b  (Timer_second).w,d1
    add.w   d1,d0
    divu.w  #$F,d0
    moveq   #$14,d1
    cmp.w   d1,d0
    blo.s   +
    move.w  d1,d0
+
    add.w   d0,d0
    move.w  TimeBonuses(pc,d0.w),(Bonus_Countdown_1).w
    move.w  (Ring_count).w,d0
    mulu.w  #$A,d0
    move.w  d0,(Bonus_Countdown_2).w
    clr.w   (Total_Bonus_Countdown).w
    clr.w   (Bonus_Countdown_3).w
    tst.w   (Perfect_rings_left).w
    bne.s   +
    move.w  #5000,(Bonus_Countdown_3).w
+
    move.w  #MusID_EndLevel,d0
    jsr (PlayMusic).l
 
return_194D0:
    rts
; ===========================================================================
; word_194D2:
TimeBonuses:
    dc.w 5000, 5000, 1000, 500, 400, 400, 300, 300
    dc.w  200,  200,  200, 200, 100, 100, 100, 100
    dc.w   50,   50,   50,  50,   0
; ===========================================================================
; loc_194FC:
Obj0D_Main_State4:
    subq.w  #1,obj0D_spinframe(a0)
    bpl.s   return_19532
    tst.b   (Time_Over_flag).w
    bne.s   return_19532
    tst.b   (Time_Over_flag_2P).w
    bne.s   return_19532
    tst.b   (Update_HUD_timer).w
    bne.s   return_19532
    tst.b   (Update_HUD_timer_2P).w
    bne.s   return_19532
    move.b  #0,(Last_star_pole_hit).w
    move.b  #0,(Last_star_pole_hit_2P).w
    move.b  #GameModeID_2PResults,(Game_Mode).w ; => TwoPlayerResults
    move.w  #VsRSID_Act,(Results_Screen_2P).w
 
return_19532:
    rts
; ===========================================================================
 
PLCLoad_Signpost:
    tst.w   (Two_player_mode).w
    beq.s   return_1958C
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    cmp.b   (Signpost_prev_frame).w,d0
    beq.s   return_1958C
    move.b  d0,(Signpost_prev_frame).w
    lea (Obj0D_MapRUnc_196EE).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_1958C
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_Signpost),d4
 
loc_19560:
    moveq   #0,d1
    move.w  (a2)+,d1
 
loc_19564:
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.l   #5,d1
    addi.l  #ArtUnc_Signpost,d1
    move.w  d4,d2
    add.w   d3,d4
    add.w   d3,d4
    jsr (QueueDMATransfer).l
    dbf d5,loc_19560
 
return_1958C:
    rts
; ===========================================================================
; animation script
; off_1958E:
Ani_obj0D:  offsetTable
        offsetTableEntry.w byte_19598   ; 0
        offsetTableEntry.w byte_1959B   ; 1
        offsetTableEntry.w byte_195A9   ; 2
        offsetTableEntry.w byte_195B7   ; 3
        offsetTableEntry.w byte_195BA   ; 4
byte_19598: dc.b    $0F, $02, $FF
    rev02even
byte_1959B: dc.b    $01, $02, $03, $04, $05, $01, $03, $04, $05, $00, $03, $04, $05, $FF
    rev02even
byte_195A9: dc.b    $01, $02, $03, $04, $05, $01, $03, $04, $05, $00, $03, $04, $05, $FF
    rev02even
byte_195B7: dc.b    $0F, $00, $FF
    rev02even
byte_195BA: dc.b    $0F, $01, $FF
    even
; -------------------------------------------------------------------------------
; sprite mappings - Primary sprite table for object 0D (signpost)
; -------------------------------------------------------------------------------
; SprTbl_0D_Primary:
Obj0D_MapUnc_195BE: BINCLUDE "mappings/sprite/obj0D_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings - Secondary sprite table for object 0D (signpost)
; -------------------------------------------------------------------------------
; SprTbl_0D_Scndary:
Obj0D_MapUnc_19656: BINCLUDE "mappings/sprite/obj0D_b.bin"
; -------------------------------------------------------------------------------
; dynamic pattern loading cues
; -------------------------------------------------------------------------------
Obj0D_MapRUnc_196EE:    BINCLUDE "mappings/spriteDPLC/obj0D.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Solid object subroutines (includes spikes, blocks, rocks etc)
; These check collision of Sonic/Tails with objects on the screen
;
; input variables:
; d1 = object width
; d2 = object height / 2 (when jumping)
; d3 = object height / 2 (when walking)
; d4 = object x-axis position
;
; address registers:
; a0 = the object to check collision with
; a1 = sonic or tails (set inside these subroutines)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_19718:
SolidObject:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp) ; store input registers
    bsr.s   +   ; first check collision with Sonic
    movem.l (sp)+,d1-d4 ; restore input registers
    lea (Sidekick).w,a1 ; a1=character ; now check collision with Tails
    tst.b   render_flags(a1)
    bpl.w   return_19776    ; return if no Tails
    addq.b  #1,d6
+
    btst    d6,status(a0)
    beq.w   SolidObject_OnScreenTest
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_1975A
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_1975A
    cmp.w   d2,d0
    blo.s   loc_1976E
 
loc_1975A:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_1976E:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
 
return_19776:
    rts
 
; ===========================================================================
; there are a few slightly different SolidObject functions
; specialized for certain objects, in this case, obj74 and obj30
; These check for solidity even if the object is off-screen
; loc_19778: SolidObject74_30:
SolidObject_Always:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   SolidObject_Always_SingleCharacter
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
;loc_1978E:
SolidObject_Always_SingleCharacter:
    btst    d6,status(a0)
    beq.w   SolidObject_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_197B2
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_197B2
    cmp.w   d2,d0
    blo.s   loc_197C6
 
loc_197B2:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_197C6:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
    rts
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Subroutine to collide Sonic/Tails with the top of a sloped solid like diagonal springs
; ---------------------------------------------------------------------------
;
; input variables:
; d1 = object width
; d2 = object height / 2 (when jumping)
; d3 = object height / 2 (when walking)
; d4 = object x-axis position
;
; address registers:
; a0 = the object to check collision with
; a1 = sonic or tails (set inside these subroutines)
; a2 = height data for slope
; loc_197D0: SolidObject86_30:
SlopedSolid:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   SlopedSolid_SingleCharacter
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
 
; this gets called from a few more places...
; loc_197E6: SolidObject_Simple:
SlopedSolid_SingleCharacter:
    btst    d6,status(a0)
    beq.w   SlopedSolid_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_1980A
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_1980A
    cmp.w   d2,d0
    blo.s   loc_1981E
 
loc_1980A:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_1981E:
    move.w  d4,d2
    bsr.w   MvSonicOnSlope
    moveq   #0,d4
    rts
 
; ===========================================================================
; unused/dead code for some SolidObject check
; This is for a sloped object that is sloped at the top and at the bottom.
; SolidObject_Unk: loc_19828:
;DoubleSlopedSolid:
    ; a0=object
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   +
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
+
    btst    d6,status(a0)
    beq.w   DoubleSlopedSolid_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_19862
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_19862
    cmp.w   d2,d0
    blo.s   loc_19876
 
loc_19862:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_19876:
    move.w  d4,d2
    bsr.w   MvSonicOnDoubleSlope
    moveq   #0,d4
    rts
 
; ===========================================================================
; loc_19880:
SolidObject45:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   loc_19896
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
 
loc_19896:
    btst    d6,status(a0)
    beq.w   SolidObject45_cont
    btst    #1,status(a1)
    bne.s   loc_198B8
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_198B8
    add.w   d1,d1
    cmp.w   d1,d0
    blo.s   loc_198CC
 
loc_198B8:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_198CC:
    ; Inlined call to MvSonicOnPtfm
    move.w  y_pos(a0),d0
    sub.w   d2,d0
    add.w   d3,d0
    moveq   #0,d1
    move.b  y_radius(a1),d1
    sub.w   d1,d0
    move.w  d0,y_pos(a1)
    sub.w   x_pos(a0),d4
    sub.w   d4,x_pos(a1)
    moveq   #0,d4
    rts
; ===========================================================================
; loc_198EC: SolidObject45_alt:
SolidObject45_cont:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   SolidObject_TestClearPush
    move.w  d1,d4
    add.w   d4,d4
    cmp.w   d4,d0
    bhi.w   SolidObject_TestClearPush
    move.w  y_pos(a0),d5
    add.w   d3,d5
    move.b  y_radius(a1),d3
    ext.w   d3
    add.w   d3,d2
    move.w  y_pos(a1),d3
    sub.w   d5,d3
    addq.w  #4,d3
    add.w   d2,d3
    bmi.w   SolidObject_TestClearPush
    move.w  d2,d4
    add.w   d4,d4
    cmp.w   d4,d3
    bhs.w   SolidObject_TestClearPush
    bra.w   SolidObject_ChkBounds
; ===========================================================================
; loc_1992E: SolidObject86_30_alt:
SlopedSolid_cont:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   SolidObject_TestClearPush
    move.w  d1,d3
    add.w   d3,d3
    cmp.w   d3,d0
    bhi.w   SolidObject_TestClearPush
    move.w  d0,d5
    btst    #0,render_flags(a0)
    beq.s   +
    not.w   d5
    add.w   d3,d5
+
    lsr.w   #1,d5
    move.b  (a2,d5.w),d3
    sub.b   (a2),d3
    ext.w   d3
    move.w  y_pos(a0),d5
    sub.w   d3,d5
    move.b  y_radius(a1),d3
    ext.w   d3
    add.w   d3,d2
    move.w  y_pos(a1),d3
    sub.w   d5,d3
    addq.w  #4,d3
    add.w   d2,d3
    bmi.w   SolidObject_TestClearPush
    move.w  d2,d4
    add.w   d4,d4
    cmp.w   d4,d3
    bhs.w   SolidObject_TestClearPush
    bra.w   SolidObject_ChkBounds
; ===========================================================================
; unused/dead code
; loc_19988: SolidObject_Unk_cont:
DoubleSlopedSolid_cont:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   SolidObject_TestClearPush
    move.w  d1,d3
    add.w   d3,d3
    cmp.w   d3,d0
    bhi.w   SolidObject_TestClearPush
    move.w  d0,d5
    btst    #0,render_flags(a0)
    beq.s   +
    not.w   d5
    add.w   d3,d5
+
    andi.w  #$FFFE,d5
    move.b  (a2,d5.w),d3
    move.b  1(a2,d5.w),d2
    ext.w   d2
    ext.w   d3
    move.w  y_pos(a0),d5
    sub.w   d3,d5
    move.w  y_pos(a1),d3
    sub.w   d5,d3
    move.b  y_radius(a1),d5
    ext.w   d5
    add.w   d5,d3
    addq.w  #4,d3
    bmi.w   SolidObject_TestClearPush
    add.w   d5,d2
    move.w  d2,d4
    add.w   d5,d4
    cmp.w   d4,d3
    bhs.w   SolidObject_TestClearPush
    bra.w   SolidObject_ChkBounds
; ===========================================================================
; loc_199E8: SolidObject_cont:
SolidObject_OnScreenTest:
    tst.b   render_flags(a0)
    bpl.w   SolidObject_TestClearPush
;loc_199F0:
SolidObject_cont:
    ; We now perform the x portion of a bounding box check.  To do this, we assume a
    ; coordinate system where the x origin is at the object's left edge.
    move.w  x_pos(a1),d0        ; load Sonic's x position...
    sub.w   x_pos(a0),d0        ; ... and calculate his x position relative to the object
    add.w   d1,d0           ; assume object's left edge is at (0,0).  This is also Sonic's distance to the object's left edge.
    bmi.w   SolidObject_TestClearPush   ; branch, if Sonic is outside the object's left edge
    move.w  d1,d3
    add.w   d3,d3           ; calculate object's width
    cmp.w   d3,d0
    bhi.w   SolidObject_TestClearPush   ; branch, if Sonic is outside the object's right edge
    ; We now perform the y portion of a bounding box check.  To do this, we assume a
    ; coordinate system where the y origin is at the highest y position relative to the object
    ; at which Sonic would still collide with it.  This point is
    ;   y_pos(object) - width(object)/2 - y_radius(Sonic) - 4,
    ; where object is stored in (a0), Sonic in (a1), and height(object)/2 in d2.  This way
    ; of doing it causes the object's hitbox to be vertically off-center by -4 pixels.
    move.b  y_radius(a1),d3     ; load Sonic's y radius
    ext.w   d3
    add.w   d3,d2           ; calculate maximum distance for a top collision
    move.w  y_pos(a1),d3        ; load Sonic's y position...
    sub.w   y_pos(a0),d3        ; ... and calculate his y position relative to the object
    addq.w  #4,d3           ; assume a slightly lower position for Sonic
    add.w   d2,d3           ; assume the highest position where Sonic would still be colliding with the object to be (0,0)
    bmi.w   SolidObject_TestClearPush   ; branch, if Sonic is above this point
    andi.w  #$7FF,d3
    move.w  d2,d4
    add.w   d4,d4           ; calculate minimum distance for a bottom collision
    cmp.w   d4,d3
    bhs.w   SolidObject_TestClearPush   ; branch, if Sonic is below this point
;loc_19A2E:
SolidObject_ChkBounds:
    tst.b   obj_control(a1)
    bmi.w   SolidObject_TestClearPush   ; branch, if object collisions are disabled for Sonic
    cmpi.b  #6,routine(a1)      ; is Sonic dead?
    bhs.w   loc_19AEA       ; if yes, branch
    tst.w   (Debug_placement_mode).w
    bne.w   loc_19AEA       ; branch, if in debug mode
 
    move.w  d0,d5
    cmp.w   d0,d1
    bhs.s   +           ; branch, if Sonic is to the object's left
    add.w   d1,d1
    sub.w   d1,d0
    move.w  d0,d5           ; calculate Sonic's distance to the object's right edge...
    neg.w   d5          ; ... and calculate the absolute value
+
    move.w  d3,d1
    cmp.w   d3,d2
    bhs.s   +
    subq.w  #4,d3
    sub.w   d4,d3
    move.w  d3,d1
    neg.w   d1
+
    cmp.w   d1,d5
    bhi.w   loc_19AEE       ; branch, if horizontal distance is greater than vertical distance
 
loc_19A6A:
    cmpi.w  #4,d1
    bls.s   loc_19AB6
    tst.w   d0
    beq.s   loc_19A90
    bmi.s   loc_19A7E
    tst.w   x_vel(a1)
    bmi.s   loc_19A90
    bra.s   loc_19A84
; ===========================================================================
 
loc_19A7E:
    tst.w   x_vel(a1)
    bpl.s   loc_19A90
 
loc_19A84:
    move.w  #0,inertia(a1)
    move.w  #0,x_vel(a1)
 
loc_19A90:
    sub.w   d0,x_pos(a1)
    btst    #1,status(a1)
    bne.s   loc_19AB6
    move.l  d6,d4
    addq.b  #pushing_bit_delta,d4   ; Character is pushing, not standing
    bset    d4,status(a0)
    bset    #5,status(a1)
    move.w  d6,d4
    addi.b  #($10-p1_standing_bit+p1_touch_side_bit),d4
    bset    d4,d6   ; This sets bits 0 (Sonic) or 1 (Tails) of high word of d6
    moveq   #1,d4
    rts
; ===========================================================================
 
loc_19AB6:
    bsr.s   loc_19ADC
    move.w  d6,d4
    addi.b  #($10-p1_standing_bit+p1_touch_side_bit),d4
    bset    d4,d6   ; This sets bits 0 (Sonic) or 1 (Tails) of high word of d6
    moveq   #1,d4
    rts
; ===========================================================================
;loc_19AC4:
SolidObject_TestClearPush:
    move.l  d6,d4
    addq.b  #pushing_bit_delta,d4
    btst    d4,status(a0)
    beq.s   loc_19AEA
    cmpi.b  #AniIDSonAni_Roll,anim(a1)
    beq.s   loc_19ADC
    move.w  #AniIDSonAni_Run,anim(a1)
 
loc_19ADC:
    move.l  d6,d4
    addq.b  #pushing_bit_delta,d4
    bclr    d4,status(a0)
    bclr    #5,status(a1)
 
loc_19AEA:
    moveq   #0,d4
    rts
; ===========================================================================
 
loc_19AEE:
    tst.w   d3
    bmi.s   loc_19B06
    cmpi.w  #$10,d3
    blo.s   loc_19B56
    cmpi.b  #ObjID_LauncherSpring,id(a0)
    bne.s   SolidObject_TestClearPush
    cmpi.w  #$14,d3
    blo.s   loc_19B56
    bra.s   SolidObject_TestClearPush
; ===========================================================================
 
loc_19B06:
    tst.w   y_vel(a1)
    beq.s   loc_19B28
    bpl.s   loc_19B1C
    tst.w   d3
    bpl.s   loc_19B1C
    sub.w   d3,y_pos(a1)
    move.w  #0,y_vel(a1)
 
loc_19B1C:
    move.w  d6,d4
    addi.b  #($10-p1_standing_bit+p1_touch_bottom_bit),d4
    bset    d4,d6   ; This sets bits 2 (Sonic) or 3 (Tails) of high word of d6
    moveq   #-2,d4
    rts
; ===========================================================================
 
loc_19B28:
    btst    #1,status(a1)
    bne.s   loc_19B1C
    mvabs.w d0,d4
    cmpi.w  #$10,d4
    blo.w   loc_19A6A
    move.l  a0,-(sp)
    movea.l a1,a0
    jsr (KillCharacter).l
    movea.l (sp)+,a0 ; load 0bj address
    move.w  d6,d4
    addi.b  #($10-p1_standing_bit+p1_touch_bottom_bit),d4
    bset    d4,d6   ; This sets bits 2 (Sonic) or 3 (Tails) of high word of d6
    moveq   #-2,d4
    rts
; ===========================================================================
 
loc_19B56:
    subq.w  #4,d3
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  d1,d2
    add.w   d2,d2
    add.w   x_pos(a1),d1
    sub.w   x_pos(a0),d1
    bmi.s   loc_19B8E
    cmp.w   d2,d1
    bhs.s   loc_19B8E
    tst.w   y_vel(a1)
    bmi.s   loc_19B8E
    sub.w   d3,y_pos(a1)
    subq.w  #1,y_pos(a1)
    bsr.w   RideObject_SetRide
    move.w  d6,d4
    addi.b  #($10-p1_standing_bit+p1_touch_top_bit),d4
    bset    d4,d6   ; This sets bits 4 (Sonic) or 5 (Tails) of high word of d6
    moveq   #-1,d4
    rts
; ===========================================================================
 
loc_19B8E:
    moveq   #0,d4
    rts
; ===========================================================================
 
; Subroutine to change Sonic's position with a platform
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; loc_19B92:
 
MvSonicOnPtfm:
    move.w  y_pos(a0),d0
    sub.w   d3,d0
    bra.s   loc_19BA2
; ===========================================================================
    ; a couple lines of unused/leftover/dead code from Sonic 1 ; a0=object
    move.w  y_pos(a0),d0
    subi.w  #9,d0
 
loc_19BA2:
    tst.b   obj_control(a1)
    bmi.s   return_19BCA
    cmpi.b  #6,routine(a1)
    bhs.s   return_19BCA
    tst.w   (Debug_placement_mode).w
    bne.s   return_19BCA
    moveq   #0,d1
    move.b  y_radius(a1),d1
    sub.w   d1,d0
    move.w  d0,y_pos(a1)
    sub.w   x_pos(a0),d2
    sub.w   d2,x_pos(a1)
 
return_19BCA:
    rts
; ===========================================================================
;loc_19BCC:
MvSonicOnSlope:
    btst    #3,status(a1)
    beq.s   return_19C0C
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    lsr.w   #1,d0
    btst    #0,render_flags(a0)
    beq.s   loc_19BEC
    not.w   d0
    add.w   d1,d0
 
loc_19BEC:
    move.b  (a2,d0.w),d1
    ext.w   d1
    move.w  y_pos(a0),d0
    sub.w   d1,d0
    moveq   #0,d1
    move.b  y_radius(a1),d1
    sub.w   d1,d0
    move.w  d0,y_pos(a1)
    sub.w   x_pos(a0),d2
    sub.w   d2,x_pos(a1)
 
return_19C0C:
    rts
; ===========================================================================
; unused/dead code.
; loc_19C0E:
MvSonicOnDoubleSlope:
    btst    #3,status(a1)
    beq.s   return_19C0C
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    btst    #0,render_flags(a0)
    beq.s   loc_19C2C
    not.w   d0
    add.w   d1,d0
 
loc_19C2C:
    andi.w  #$FFFE,d0
    bra.s   loc_19BEC
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to collide Sonic/Tails with the top of a platform
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
;
; input variables:
; d1 = object width
; d3 = object height / 2
; d4 = object x-axis position
;
; address registers:
; a0 = the object to check collision with
; a1 = sonic or tails (set inside these subroutines)
; loc_19C32:
PlatformObject:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   PlatformObject_SingleCharacter
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
; loc_19C48:
PlatformObject_SingleCharacter:
    btst    d6,status(a0)
    beq.w   PlatformObject_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   +
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   +
    cmp.w   d2,d0
    blo.s   loc_19C80
+
 
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_19C80:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to collide Sonic/Tails with the top of a sloped platform like a seesaw
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
;
; input variables:
; d1 = object width
; d3 = object height
; d4 = object x-axis position
;
; address registers:
; a0 = the object to check collision with
; a1 = sonic or tails (set inside these subroutines)
; a2 = height data for slope
; loc_19C8A: SlopeObject:
SlopedPlatform:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   SlopedPlatform_SingleCharacter
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
; loc_19CA0:
SlopedPlatform_SingleCharacter:
    btst    d6,status(a0)
    beq.w   SlopedPlatform_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_19CC4
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_19CC4
    cmp.w   d2,d0
    blo.s   loc_19CD8
 
loc_19CC4:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ---------------------------------------------------------------------------
loc_19CD8:
    move.w  d4,d2
    bsr.w   MvSonicOnSlope
    moveq   #0,d4
    rts
; ===========================================================================
; Identical to PlatformObject.
;loc_19CE2:
PlatformObject2:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   loc_19CF8
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
 
loc_19CF8:
    btst    d6,status(a0)
    beq.w   PlatformObject2_cont
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_19D1C
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_19D1C
    cmp.w   d2,d0
    blo.s   loc_19D30
 
loc_19D1C:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
    moveq   #0,d4
    rts
; ===========================================================================
 
loc_19D30:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
    rts
; ===========================================================================
; Almost identical to PlatformObject, except that this function does nothing if
; the character is already standing on a platform. Used only by the elevators
; in CNZ.
;loc_19D3A:
PlatformObjectD5:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   loc_19D50
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
 
loc_19D50:
    btst    d6,status(a0)
    bne.s   loc_19D62
    btst    #3,status(a1)
    bne.s   loc_19D8E
    bra.w   PlatformObject_cont
; ===========================================================================
 
loc_19D62:
    move.w  d1,d2
    add.w   d2,d2
    btst    #1,status(a1)
    bne.s   loc_19D7E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   loc_19D7E
    cmp.w   d2,d0
    blo.s   loc_19D92
 
loc_19D7E:
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    d6,status(a0)
 
loc_19D8E:
    moveq   #0,d4
    rts
; ===========================================================================
 
loc_19D92:
    move.w  d4,d2
    bsr.w   MvSonicOnPtfm
    moveq   #0,d4
    rts
; ===========================================================================
; Used only by EHZ/HPZ log bridges. Very similar to PlatformObject_cont, but
; d2 already has the full width of the log.
;loc_19D9C:
PlatformObject11_cont:
    tst.w   y_vel(a1)
    bmi.w   return_19E8E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   return_19E8E
    cmp.w   d2,d0
    bhs.w   return_19E8E
    bra.s   loc_19DD8
; ===========================================================================
;loc_19DBA:
PlatformObject_cont:
    tst.w   y_vel(a1)
    bmi.w   return_19E8E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   return_19E8E
    add.w   d1,d1
    cmp.w   d1,d0
    bhs.w   return_19E8E
 
loc_19DD8:
    move.w  y_pos(a0),d0
    sub.w   d3,d0
;loc_19DDE:
PlatformObject_ChkYRange:
    move.w  y_pos(a1),d2
    move.b  y_radius(a1),d1
    ext.w   d1
    add.w   d2,d1
    addq.w  #4,d1
    sub.w   d1,d0
    bhi.w   return_19E8E
    cmpi.w  #-$10,d0
    blo.w   return_19E8E
    tst.b   obj_control(a1)
    bmi.w   return_19E8E
    cmpi.b  #6,routine(a1)
    bhs.w   return_19E8E
    add.w   d0,d2
    addq.w  #3,d2
    move.w  d2,y_pos(a1)
;loc_19E14:
RideObject_SetRide:
    btst    #3,status(a1)
    beq.s   loc_19E30
    moveq   #0,d0
    move.b  interact(a1),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a3   ; a3=object
    bclr    d6,status(a3)
 
loc_19E30:
    move.w  a0,d0
    subi.w  #Object_RAM,d0
    if object_size=$40
    lsr.w   #6,d0
    else
    divu.w  #object_size,d0
    endif
    andi.w  #$7F,d0
    move.b  d0,interact(a1)
    move.b  #0,angle(a1)
    move.w  #0,y_vel(a1)
    move.w  x_vel(a1),inertia(a1)
    btst    #1,status(a1)
    beq.s   loc_19E7E
    move.l  a0,-(sp)
    movea.l a1,a0
    move.w  a0,d1
    subi.w  #Object_RAM,d1
    bne.s   loc_19E76
    cmpi.w  #2,(Player_mode).w
    beq.s   loc_19E76
    jsr (Sonic_ResetOnFloor_Part2).l
    bra.s   loc_19E7C
; ===========================================================================
 
loc_19E76:
    jsr (Tails_ResetOnFloor_Part2).l
 
loc_19E7C:
    movea.l (sp)+,a0 ; a0=character
 
loc_19E7E:
    bset    #3,status(a1)
    bclr    #1,status(a1)
    bset    d6,status(a0)
 
return_19E8E:
    rts
; ===========================================================================
;loc_19E90:
SlopedPlatform_cont:
    tst.w   y_vel(a1)
    bmi.w   return_19E8E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.s   return_19E8E
    add.w   d1,d1
    cmp.w   d1,d0
    bhs.s   return_19E8E
    btst    #0,render_flags(a0)
    beq.s   loc_19EB6
    not.w   d0
    add.w   d1,d0
 
loc_19EB6:
    lsr.w   #1,d0
    move.b  (a2,d0.w),d3
    ext.w   d3
    move.w  y_pos(a0),d0
    sub.w   d3,d0
    bra.w   PlatformObject_ChkYRange
; ===========================================================================
; Basically identical to PlatformObject_cont
;loc_19EC8:
PlatformObject2_cont:
    tst.w   y_vel(a1)
    bmi.w   return_19E8E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d1,d0
    bmi.w   return_19E8E
    add.w   d1,d1
    cmp.w   d1,d0
    bhs.w   return_19E8E
    move.w  y_pos(a0),d0
    sub.w   d3,d0
    bra.w   PlatformObject_ChkYRange
; ===========================================================================
; If a character is being dragged through terrain by this object, drop the
; character on terrain instead.
;loc_19EF0:
DropOnFloor:
    lea (MainCharacter).w,a1 ; a1=character
    btst    #p1_standing_bit,status(a0)
    beq.s   loc_19F1E
    jsr (ChkFloorEdge2).l
    tst.w   d1
    beq.s   loc_19F08
    bpl.s   loc_19F1E
 
loc_19F08:
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    #p1_standing_bit,status(a0)
 
loc_19F1E:
    lea (Sidekick).w,a1 ; a1=character
    btst    #p2_standing_bit,status(a0)
    beq.s   loc_19F4C
    jsr (ChkFloorEdge2).l
    tst.w   d1
    beq.s   loc_19F36
    bpl.s   loc_19F4C
 
loc_19F36:
    lea (Sidekick).w,a1 ; a1=character
    bclr    #3,status(a1)
    bset    #1,status(a1)
    bclr    #p2_standing_bit,status(a0)
 
loc_19F4C:
    moveq   #0,d4
    rts
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 01 - Sonic
; ----------------------------------------------------------------------------
; Sprite_19F50: Object_Sonic:
Obj01:
    ; a0=character
    tst.w   (Debug_placement_mode).w    ; is debug mode being used?
    beq.s   Obj01_Normal            ; if not, branch
    jmp (DebugMode).l
; ---------------------------------------------------------------------------
; loc_19F5C:
Obj01_Normal:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj01_Index(pc,d0.w),d1
    jmp Obj01_Index(pc,d1.w)
; ===========================================================================
; off_19F6A: Obj01_States:
Obj01_Index:    offsetTable
        offsetTableEntry.w Obj01_Init       ;  0
        offsetTableEntry.w Obj01_Control    ;  2
        offsetTableEntry.w Obj01_Hurt       ;  4
        offsetTableEntry.w Obj01_Dead       ;  6
        offsetTableEntry.w Obj01_Gone       ;  8
        offsetTableEntry.w Obj01_Respawning ; $A
; ===========================================================================
; loc_19F76: Obj_01_Sub_0: Obj01_Main:
Obj01_Init:
    addq.b  #2,routine(a0)  ; => Obj01_Control
    move.b  #$13,y_radius(a0) ; this sets Sonic's collision height (2*pixels)
    move.b  #9,x_radius(a0)
    move.l  #Mapunc_Sonic,mappings(a0)
    move.b  #2,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #4,render_flags(a0)
    move.w  #$600,(Sonic_top_speed).w   ; set Sonic's top speed
    move.w  #$C,(Sonic_acceleration).w  ; set Sonic's acceleration
    move.w  #$80,(Sonic_deceleration).w ; set Sonic's deceleration
    tst.b   (Last_star_pole_hit).w
    bne.s   Obj01_Init_Continued
    ; only happens when not starting at a checkpoint:
    move.w  #make_art_tile(ArtTile_ArtUnc_Sonic,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$C,top_solid_bit(a0)
    move.b  #$D,lrb_solid_bit(a0)
    move.w  x_pos(a0),(Saved_x_pos).w
    move.w  y_pos(a0),(Saved_y_pos).w
    move.w  art_tile(a0),(Saved_art_tile).w
    move.w  top_solid_bit(a0),(Saved_Solid_bits).w
 
Obj01_Init_Continued:
    move.b  #0,flips_remaining(a0)
    move.b  #4,flip_speed(a0)
    move.b  #0,(Super_Sonic_flag).w
    move.b  #$1E,air_left(a0)
    subi.w  #$20,x_pos(a0)
    addi_.w #4,y_pos(a0)
    move.w  #0,(Sonic_Pos_Record_Index).w
 
    move.w  #$3F,d2
-   bsr.w   Sonic_RecordPos
    subq.w  #4,a1
    move.l  #0,(a1)
    dbf d2,-
 
    addi.w  #$20,x_pos(a0)
    subi_.w #4,y_pos(a0)
 
; ---------------------------------------------------------------------------
; Normal state for Sonic
; ---------------------------------------------------------------------------
; loc_1A030: Obj_01_Sub_2:
Obj01_Control:
    tst.w   (Debug_mode_flag).w ; is debug cheat enabled?
    beq.s   +           ; if not, branch
    btst    #button_B,(Ctrl_1_Press).w  ; is button B pressed?
    beq.s   +           ; if not, branch
    move.w  #1,(Debug_placement_mode).w ; change Sonic into a ring/item
    clr.b   (Control_Locked).w      ; unlock control
    rts
; -----------------------------------------------------------------------
+   tst.b   (Control_Locked).w  ; are controls locked?
    bne.s   +           ; if yes, branch
    move.w  (Ctrl_1).w,(Ctrl_1_Logical).w   ; copy new held buttons, to enable joypad control
+
    btst    #0,obj_control(a0)  ; is Sonic interacting with another object that holds him in place or controls his movement somehow?
    bne.s   +           ; if yes, branch to skip Sonic's control
    moveq   #0,d0
    move.b  status(a0),d0
    andi.w  #6,d0   ; %0000 %0110
    move.w  Obj01_Modes(pc,d0.w),d1
    jsr Obj01_Modes(pc,d1.w)    ; run Sonic's movement control code
+
    cmpi.w  #-$100,(Camera_Min_Y_pos).w ; is vertical wrapping enabled?
    bne.s   +               ; if not, branch
    andi.w  #$7FF,y_pos(a0)         ; perform wrapping of Sonic's y position
+
    bsr.s   Sonic_Display
    bsr.w   Sonic_Super
    bsr.w   Sonic_RecordPos
    bsr.w   Sonic_Water
    move.b  (Primary_Angle).w,next_tilt(a0)
    move.b  (Secondary_Angle).w,tilt(a0)
    tst.b   (WindTunnel_flag).w
    beq.s   +
    tst.b   anim(a0)
    bne.s   +
    move.b  next_anim(a0),anim(a0)
+
    bsr.w   Sonic_Animate
    tst.b   obj_control(a0)
    bmi.s   +
    jsr (TouchResponse).l
+
    bra.w   LoadSonicDynPLC
 
; ===========================================================================
; secondary states under state Obj01_Control
; off_1A0BE:
Obj01_Modes:    offsetTable
        offsetTableEntry.w Obj01_MdNormal_Checks    ; 0 - not airborne or rolling
        offsetTableEntry.w Obj01_MdAir          ; 2 - airborne
        offsetTableEntry.w Obj01_MdRoll         ; 4 - rolling
        offsetTableEntry.w Obj01_MdJump         ; 6 - jumping
; ===========================================================================
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A0C6:
Sonic_Display:
    move.w  invulnerable_time(a0),d0
    beq.s   Obj01_Display
    subq.w  #1,invulnerable_time(a0)
    lsr.w   #3,d0
    bcc.s   Obj01_ChkInvin
; loc_1A0D4:
Obj01_Display:
    jsr (DisplaySprite).l
; loc_1A0DA:
Obj01_ChkInvin:     ; Checks if invincibility has expired and disables it if it has.
    btst    #status_sec_isInvincible,status_secondary(a0)
    beq.s   Obj01_ChkShoes
    tst.w   invincibility_time(a0)
    beq.s   Obj01_ChkShoes  ; If there wasn't any time left, that means we're in Super Sonic mode.
    subq.w  #1,invincibility_time(a0)
    bne.s   Obj01_ChkShoes
    tst.b   (Current_Boss_ID).w ; Don't change music if in a boss fight
    bne.s   Obj01_RmvInvin
    cmpi.b  #$C,air_left(a0)    ; Don't change music if drowning
    blo.s   Obj01_RmvInvin
    move.w  (Level_Music).w,d0
    jsr (PlayMusic).l
;loc_1A106:
Obj01_RmvInvin:
    bclr    #status_sec_isInvincible,status_secondary(a0)
; loc_1A10C:
Obj01_ChkShoes:     ; Checks if Speed Shoes have expired and disables them if they have.
    btst    #status_sec_hasSpeedShoes,status_secondary(a0)
    beq.s   Obj01_ExitChk
    tst.w   speedshoes_time(a0)
    beq.s   Obj01_ExitChk
    subq.w  #1,speedshoes_time(a0)
    bne.s   Obj01_ExitChk
    move.w  #$600,(Sonic_top_speed).w
    move.w  #$C,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
    tst.b   (Super_Sonic_flag).w
    beq.s   Obj01_RmvSpeed
    move.w  #$A00,(Sonic_top_speed).w
    move.w  #$30,(Sonic_acceleration).w
    move.w  #$100,(Sonic_deceleration).w
; loc_1A14A:
Obj01_RmvSpeed:
    bclr    #status_sec_hasSpeedShoes,status_secondary(a0)
    move.w  #MusID_SlowDown,d0  ; Slow down tempo
    jmp (PlayMusic).l
; ---------------------------------------------------------------------------
; return_1A15A:
Obj01_ExitChk:
    rts
; End of subroutine Sonic_Display
 
; ---------------------------------------------------------------------------
; Subroutine to record Sonic's previous positions for invincibility stars
; and input/status flags for Tails' AI to follow
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A15C:
Sonic_RecordPos:
    move.w  (Sonic_Pos_Record_Index).w,d0
    lea (Sonic_Pos_Record_Buf).w,a1
    lea (a1,d0.w),a1
    move.w  x_pos(a0),(a1)+
    move.w  y_pos(a0),(a1)+
    addq.b  #4,(Sonic_Pos_Record_Index+1).w
 
    lea (Sonic_Stat_Record_Buf).w,a1
    lea (a1,d0.w),a1
    move.w  (Ctrl_1_Logical).w,(a1)+
    move.w  status(a0),(a1)+
 
    rts
; End of subroutine Sonic_RecordPos
 
; ---------------------------------------------------------------------------
; Subroutine for Sonic when he's underwater
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A186:
Sonic_Water:
    tst.b   (Water_flag).w  ; does level have water?
    bne.s   Obj01_InWater   ; if yes, branch
 
return_1A18C:
    rts
; ---------------------------------------------------------------------------
; loc_1A18E:
Obj01_InWater:
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0    ; is Sonic above the water?
    bge.s   Obj01_OutWater  ; if yes, branch
 
    bset    #6,status(a0)   ; set underwater flag
    bne.s   return_1A18C    ; if already underwater, branch
 
    movea.l a0,a1
    bsr.w   ResumeMusic
    move.b  #ObjID_SmallBubbles,(Sonic_BreathingBubbles+id).w ; load Obj0A (sonic's breathing bubbles) at $FFFFD080
    move.b  #$81,(Sonic_BreathingBubbles+subtype).w
    move.l  a0,(Sonic_BreathingBubbles+$3C).w
    move.w  #$300,(Sonic_top_speed).w
    move.w  #6,(Sonic_acceleration).w
    move.w  #$40,(Sonic_deceleration).w
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    move.w  #$500,(Sonic_top_speed).w
    move.w  #$18,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
+
    asr.w   x_vel(a0)
    asr.w   y_vel(a0)   ; memory operands can only be shifted one bit at a time
    asr.w   y_vel(a0)
    beq.s   return_1A18C
    move.w  #$100,(Sonic_Dust+anim).w   ; splash animation
    move.w  #SndID_Splash,d0    ; splash sound
    jmp (PlaySound).l
; ---------------------------------------------------------------------------
; loc_1A1FE:
Obj01_OutWater:
    bclr    #6,status(a0) ; unset underwater flag
    beq.s   return_1A18C ; if already above water, branch
 
    movea.l a0,a1
    bsr.w   ResumeMusic
    move.w  #$600,(Sonic_top_speed).w
    move.w  #$C,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    move.w  #$A00,(Sonic_top_speed).w
    move.w  #$30,(Sonic_acceleration).w
    move.w  #$100,(Sonic_deceleration).w
+
    cmpi.b  #4,routine(a0)  ; is Sonic falling back from getting hurt?
    beq.s   +       ; if yes, branch
    asl y_vel(a0)
+
    tst.w   y_vel(a0)
    beq.w   return_1A18C
    move.w  #$100,(Sonic_Dust+anim).w   ; splash animation
    movea.l a0,a1
    bsr.w   ResumeMusic
    cmpi.w  #-$1000,y_vel(a0)
    bgt.s   +
    move.w  #-$1000,y_vel(a0)   ; limit upward y velocity exiting the water
+
    move.w  #SndID_Splash,d0    ; splash sound
    jmp (PlaySound).l
; End of subroutine Sonic_Water
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Start of subroutine Obj01_MdNormal
; Called if Sonic is neither airborne nor rolling this frame
; ---------------------------------------------------------------------------
; loc_1A26E:
Obj01_MdNormal_Checks:
    move.b  (Ctrl_1_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    bne.s   Obj01_MdNormal
    cmpi.b  #$A,anim(a0)
    beq.s   return_1A2DE
    cmpi.b  #$B,anim(a0)
    beq.s   return_1A2DE
    cmpi.b  #5,anim(a0)
    bne.s   Obj01_MdNormal
    cmpi.b  #$1E,anim_frame(a0)
    blo.s   Obj01_MdNormal
    move.b  (Ctrl_1_Held_Logical).w,d0
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask|button_B_mask|button_C_mask|button_A_mask,d0
    beq.s   return_1A2DE
    move.b  #$A,anim(a0)
    cmpi.b  #$AC,anim_frame(a0)
    blo.s   return_1A2DE
    move.b  #$B,anim(a0)
    bra.s   return_1A2DE
; ---------------------------------------------------------------------------
; loc_1A2B8:
Obj01_MdNormal:
    bsr.w   Sonic_CheckSpindash
    bsr.w   Sonic_Jump
    bsr.w   Sonic_SlopeResist
    bsr.w   Sonic_Move
    bsr.w   Sonic_Roll
    bsr.w   Sonic_LevelBound
    jsr (ObjectMove).l
    bsr.w   AnglePos
    bsr.w   Sonic_SlopeRepel
 
return_1A2DE:
    rts
; End of subroutine Obj01_MdNormal
; ===========================================================================
; Start of subroutine Obj01_MdAir
; Called if Sonic is airborne, but not in a ball (thus, probably not jumping)
; loc_1A2E0: Obj01_MdJump
Obj01_MdAir:
    bsr.w   Sonic_JumpHeight
    bsr.w   Sonic_ChgJumpDir
    bsr.w   Sonic_LevelBound
    jsr (ObjectMoveAndFall).l
    btst    #6,status(a0)   ; is Sonic underwater?
    beq.s   +       ; if not, branch
    subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
+
    bsr.w   Sonic_JumpAngle
    bsr.w   Sonic_DoLevelCollision
    rts
; End of subroutine Obj01_MdAir
; ===========================================================================
; Start of subroutine Obj01_MdRoll
; Called if Sonic is in a ball, but not airborne (thus, probably rolling)
; loc_1A30A:
Obj01_MdRoll:
    tst.b   pinball_mode(a0)
    bne.s   +
    bsr.w   Sonic_Jump
+
    bsr.w   Sonic_RollRepel
    bsr.w   Sonic_RollSpeed
    bsr.w   Sonic_LevelBound
    jsr (ObjectMove).l
    bsr.w   AnglePos
    bsr.w   Sonic_SlopeRepel
    rts
; End of subroutine Obj01_MdRoll
; ===========================================================================
; Start of subroutine Obj01_MdJump
; Called if Sonic is in a ball and airborne (he could be jumping but not necessarily)
; Notes: This is identical to Obj01_MdAir, at least at this outer level.
;        Why they gave it a separate copy of the code, I don't know.
; loc_1A330: Obj01_MdJump2:
Obj01_MdJump:
    bsr.w   Sonic_JumpHeight
    bsr.w   Sonic_ChgJumpDir
    bsr.w   Sonic_LevelBound
    jsr (ObjectMoveAndFall).l
    btst    #6,status(a0)   ; is Sonic underwater?
    beq.s   +       ; if not, branch
    subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
+
    bsr.w   Sonic_JumpAngle
    bsr.w   Sonic_DoLevelCollision
    rts
; End of subroutine Obj01_MdJump
 
; ---------------------------------------------------------------------------
; Subroutine to make Sonic walk/run
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A35A:
Sonic_Move:
    move.w  (Sonic_top_speed).w,d6
    move.w  (Sonic_acceleration).w,d5
    move.w  (Sonic_deceleration).w,d4
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.w   Obj01_Traction
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.w   Obj01_Traction
    endif
    tst.w   move_lock(a0)
    bne.w   Obj01_ResetScr
    btst    #button_left,(Ctrl_1_Held_Logical).w    ; is left being pressed?
    beq.s   Obj01_NotLeft           ; if not, branch
    bsr.w   Sonic_MoveLeft
; loc_1A382:
Obj01_NotLeft:
    btst    #button_right,(Ctrl_1_Held_Logical).w   ; is right being pressed?
    beq.s   Obj01_NotRight          ; if not, branch
    bsr.w   Sonic_MoveRight
; loc_1A38E:
Obj01_NotRight:
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0     ; is Sonic on a slope?
    bne.w   Obj01_ResetScr  ; if yes, branch
    tst.w   inertia(a0) ; is Sonic moving?
    bne.w   Obj01_ResetScr  ; if yes, branch
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Wait,anim(a0)  ; use "standing" animation
    btst    #3,status(a0)
    beq.w   Sonic_Balance
    moveq   #0,d0
    move.b  interact(a0),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    lea (Object_RAM).w,a1 ; a1=character
    lea (a1,d0.w),a1 ; a1=object
    tst.b   status(a1)
    bmi.w   Sonic_Lookup
    moveq   #0,d1
    move.b  width_pixels(a1),d1
    move.w  d1,d2
    add.w   d2,d2
    subq.w  #2,d2
    add.w   x_pos(a0),d1
    sub.w   x_pos(a1),d1
    tst.b   (Super_Sonic_flag).w
    bne.w   SuperSonic_Balance
    cmpi.w  #2,d1
    blt.s   Sonic_BalanceOnObjLeft
    cmp.w   d2,d1
    bge.s   Sonic_BalanceOnObjRight
    bra.w   Sonic_Lookup
; ---------------------------------------------------------------------------
; loc_1A3FE:
SuperSonic_Balance:
    cmpi.w  #2,d1
    blt.w   SuperSonic_BalanceOnObjLeft
    cmp.w   d2,d1
    bge.w   SuperSonic_BalanceOnObjRight
    bra.w   Sonic_Lookup
; ---------------------------------------------------------------------------
; balancing checks for when you're on the right edge of an object
; loc_1A410:
Sonic_BalanceOnObjRight:
    btst    #0,status(a0)
    bne.s   +
    move.b  #AniIDSonAni_Balance,anim(a0)
    addq.w  #6,d2
    cmp.w   d2,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance2,anim(a0)
    bra.w   Obj01_ResetScr
    ; on right edge of object but facing left:
+   move.b  #AniIDSonAni_Balance3,anim(a0)
    addq.w  #6,d2
    cmp.w   d2,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance4,anim(a0)
    bclr    #0,status(a0)
    bra.w   Obj01_ResetScr
; ---------------------------------------------------------------------------
; balancing checks for when you're on the left edge of an object
; loc_1A44E:
Sonic_BalanceOnObjLeft:
    btst    #0,status(a0)
    beq.s   +
    move.b  #AniIDSonAni_Balance,anim(a0)
    cmpi.w  #-4,d1
    bge.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance2,anim(a0)
    bra.w   Obj01_ResetScr
    ; on left edge of object but facing right:
+   move.b  #AniIDSonAni_Balance3,anim(a0)
    cmpi.w  #-4,d1
    bge.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance4,anim(a0)
    bset    #0,status(a0)
    bra.w   Obj01_ResetScr
; ---------------------------------------------------------------------------
; balancing checks for when you're on the edge of part of the level
; loc_1A48C:
Sonic_Balance:
    jsr (ChkFloorEdge).l
    cmpi.w  #$C,d1
    blt.w   Sonic_Lookup
    tst.b   (Super_Sonic_flag).w
    bne.w   SuperSonic_Balance2
    cmpi.b  #3,next_tilt(a0)
    bne.s   Sonic_BalanceLeft
    btst    #0,status(a0)
    bne.s   +
    move.b  #AniIDSonAni_Balance,anim(a0)
    move.w  x_pos(a0),d3
    subq.w  #6,d3
    jsr (ChkFloorEdge_Part2).l
    cmpi.w  #$C,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance2,anim(a0)
    bra.w   Obj01_ResetScr
    ; on right edge but facing left:
+   move.b  #AniIDSonAni_Balance3,anim(a0)
    move.w  x_pos(a0),d3
    subq.w  #6,d3
    jsr (ChkFloorEdge_Part2).l
    cmpi.w  #$C,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance4,anim(a0)
    bclr    #0,status(a0)
    bra.w   Obj01_ResetScr
; ---------------------------------------------------------------------------
Sonic_BalanceLeft:
    cmpi.b  #3,tilt(a0)
    bne.s   Sonic_Lookup
    btst    #0,status(a0)
    beq.s   +
    move.b  #AniIDSonAni_Balance,anim(a0)
    move.w  x_pos(a0),d3
    addq.w  #6,d3
    jsr (ChkFloorEdge_Part2).l
    cmpi.w  #$C,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance2,anim(a0)
    bra.w   Obj01_ResetScr
    ; on left edge but facing right:
+   move.b  #AniIDSonAni_Balance3,anim(a0)
    move.w  x_pos(a0),d3
    addq.w  #6,d3
    jsr (ChkFloorEdge_Part2).l
    cmpi.w  #$C,d1
    blt.w   Obj01_ResetScr
    move.b  #AniIDSonAni_Balance4,anim(a0)
    bset    #0,status(a0)
    bra.w   Obj01_ResetScr
; ---------------------------------------------------------------------------
; loc_1A55E:
SuperSonic_Balance2:
    cmpi.b  #3,next_tilt(a0)
    bne.s   loc_1A56E
 
; loc_1A566:
SuperSonic_BalanceOnObjRight:
    bclr    #0,status(a0)
    bra.s   loc_1A57C
; ---------------------------------------------------------------------------
loc_1A56E:
    cmpi.b  #3,tilt(a0)
    bne.s   Sonic_Lookup
 
; loc_1A576:
SuperSonic_BalanceOnObjLeft:
    bset    #0,status(a0)
 
loc_1A57C:
    move.b  #AniIDSonAni_Balance,anim(a0)
    bra.s   Obj01_ResetScr
; ---------------------------------------------------------------------------
; loc_1A584:
Sonic_Lookup:
    btst    #button_up,(Ctrl_1_Held_Logical).w  ; is up being pressed?
    beq.s   Sonic_Duck          ; if not, branch
    move.b  #AniIDSonAni_LookUp,anim(a0)            ; use "looking up" animation
    addq.w  #1,(Sonic_Look_delay_counter).w
    cmpi.w  #$78,(Sonic_Look_delay_counter).w
    blo.s   Obj01_ResetScr_Part2
    move.w  #$78,(Sonic_Look_delay_counter).w
    cmpi.w  #$C8,(Camera_Y_pos_bias).w
    beq.s   Obj01_UpdateSpeedOnGround
    addq.w  #2,(Camera_Y_pos_bias).w
    bra.s   Obj01_UpdateSpeedOnGround
; ---------------------------------------------------------------------------
; loc_1A5B2:
Sonic_Duck:
    btst    #button_down,(Ctrl_1_Held_Logical).w    ; is down being pressed?
    beq.s   Obj01_ResetScr          ; if not, branch
    move.b  #AniIDSonAni_Duck,anim(a0)          ; use "ducking" animation
    addq.w  #1,(Sonic_Look_delay_counter).w
    cmpi.w  #$78,(Sonic_Look_delay_counter).w
    blo.s   Obj01_ResetScr_Part2
    move.w  #$78,(Sonic_Look_delay_counter).w
    cmpi.w  #8,(Camera_Y_pos_bias).w
    beq.s   Obj01_UpdateSpeedOnGround
    subq.w  #2,(Camera_Y_pos_bias).w
    bra.s   Obj01_UpdateSpeedOnGround
 
; ===========================================================================
; moves the screen back to its normal position after looking up or down
; loc_1A5E0:
Obj01_ResetScr:
    move.w  #0,(Sonic_Look_delay_counter).w
; loc_1A5E6:
Obj01_ResetScr_Part2:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias).w   ; is screen in its default position?
    beq.s   Obj01_UpdateSpeedOnGround   ; if yes, branch.
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias).w    ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias).w    ; or subtract 2
 
; ---------------------------------------------------------------------------
; updates Sonic's speed on the ground
; ---------------------------------------------------------------------------
; sub_1A5F8:
Obj01_UpdateSpeedOnGround:
    tst.b   (Super_Sonic_flag).w
    beq.w   +
    move.w  #$C,d5
+
    move.b  (Ctrl_1_Held_Logical).w,d0
    andi.b  #button_left_mask|button_right_mask,d0 ; is left/right pressed?
    bne.s   Obj01_Traction  ; if yes, branch
    move.w  inertia(a0),d0
    beq.s   Obj01_Traction
    bmi.s   Obj01_SettleLeft
 
; slow down when facing right and not pressing a direction
; Obj01_SettleRight:
    sub.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
    bra.s   Obj01_Traction
; ---------------------------------------------------------------------------
; slow down when facing left and not pressing a direction
; loc_1A624:
Obj01_SettleLeft:
    add.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
 
; increase or decrease speed on the ground
; loc_1A630:
Obj01_Traction:
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  inertia(a0),d1
    asr.l   #8,d1
    move.w  d1,x_vel(a0)
    muls.w  inertia(a0),d0
    asr.l   #8,d0
    move.w  d0,y_vel(a0)
 
; stops Sonic from running through walls that meet the ground
; loc_1A64E:
Obj01_CheckWallsOnGround:
    move.b  angle(a0),d0
    addi.b  #$40,d0
    bmi.s   return_1A6BE
    move.b  #$40,d1         ; Rotate 90 degrees clockwise
    tst.w   inertia(a0)     ; Check inertia
    beq.s   return_1A6BE    ; If not moving, don't do anything
    bmi.s   +               ; If negative, branch
    neg.w   d1              ; Otherwise, we want to rotate counterclockwise
+
    move.b  angle(a0),d0
    add.b   d1,d0
    move.w  d0,-(sp)
    bsr.w   CalcRoomInFront
    move.w  (sp)+,d0
    tst.w   d1
    bpl.s   return_1A6BE
    asl.w   #8,d1
    addi.b  #$20,d0
    andi.b  #$C0,d0
    beq.s   loc_1A6BA
    cmpi.b  #$40,d0
    beq.s   loc_1A6A8
    cmpi.b  #$80,d0
    beq.s   loc_1A6A2
    add.w   d1,x_vel(a0)
    bset    #5,status(a0)
    move.w  #0,inertia(a0)
    rts
; ---------------------------------------------------------------------------
loc_1A6A2:
    sub.w   d1,y_vel(a0)
    rts
; ---------------------------------------------------------------------------
loc_1A6A8:
    sub.w   d1,x_vel(a0)
    bset    #5,status(a0)
    move.w  #0,inertia(a0)
    rts
; ---------------------------------------------------------------------------
loc_1A6BA:
    add.w   d1,y_vel(a0)
 
return_1A6BE:
    rts
; End of subroutine Sonic_Move
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A6C0:
Sonic_MoveLeft:
    move.w  inertia(a0),d0
    beq.s   +
    bpl.s   Sonic_TurnLeft ; if Sonic is already moving to the right, branch
+
    bset    #0,status(a0)
    bne.s   +
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
+
    sub.w   d5,d0   ; add acceleration to the left
    move.w  d6,d1
    neg.w   d1
    cmp.w   d1,d0   ; compare new speed with top speed
    bgt.s   +   ; if new speed is less than the maximum, branch
    add.w   d5,d0   ; remove this frame's acceleration change
    cmp.w   d1,d0   ; compare speed with top speed
    ble.s   +   ; if speed was already greater than the maximum, branch
    move.w  d1,d0   ; limit speed on ground going left
+
    move.w  d0,inertia(a0)
    move.b  #AniIDSonAni_Walk,anim(a0)  ; use walking animation
    rts
; ---------------------------------------------------------------------------
; loc_1A6FA:
Sonic_TurnLeft:
    sub.w   d4,d0
    bcc.s   +
    move.w  #-$80,d0
+
    move.w  d0,inertia(a0)
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    bne.s   return_1A744
    cmpi.w  #$400,d0
    blt.s   return_1A744
    move.b  #AniIDSonAni_Stop,anim(a0)  ; use "stopping" animation
    bclr    #0,status(a0)
    move.w  #SndID_Skidding,d0
    jsr (PlaySound).l
    cmpi.b  #$C,air_left(a0)
    blo.s   return_1A744    ; if he's drowning, branch to not make dust
    move.b  #6,(Sonic_Dust+routine).w
    move.b  #$15,(Sonic_Dust+mapping_frame).w
 
return_1A744:
    rts
; End of subroutine Sonic_MoveLeft
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A746:
Sonic_MoveRight:
    move.w  inertia(a0),d0
    bmi.s   Sonic_TurnRight ; if Sonic is already moving to the left, branch
    bclr    #0,status(a0)
    beq.s   +
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
+
    add.w   d5,d0   ; add acceleration to the right
    cmp.w   d6,d0   ; compare new speed with top speed
    blt.s   +   ; if new speed is less than the maximum, branch
    sub.w   d5,d0   ; remove this frame's acceleration change
    cmp.w   d6,d0   ; compare speed with top speed
    bge.s   +   ; if speed was already greater than the maximum, branch
    move.w  d6,d0   ; limit speed on ground going right
+
    move.w  d0,inertia(a0)
    move.b  #AniIDSonAni_Walk,anim(a0)  ; use walking animation
    rts
; ---------------------------------------------------------------------------
; loc_1A77A:
Sonic_TurnRight:
    add.w   d4,d0
    bcc.s   +
    move.w  #$80,d0
+
    move.w  d0,inertia(a0)
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    bne.s   return_1A7C4
    cmpi.w  #-$400,d0
    bgt.s   return_1A7C4
    move.b  #AniIDSonAni_Stop,anim(a0)  ; use "stopping" animation
    bset    #0,status(a0)
    move.w  #SndID_Skidding,d0  ; use "stopping" sound
    jsr (PlaySound).l
    cmpi.b  #$C,air_left(a0)
    blo.s   return_1A7C4    ; if he's drowning, branch to not make dust
    move.b  #6,(Sonic_Dust+routine).w
    move.b  #$15,(Sonic_Dust+mapping_frame).w
 
return_1A7C4:
    rts
; End of subroutine Sonic_MoveRight
 
; ---------------------------------------------------------------------------
; Subroutine to change Sonic's speed as he rolls
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A7C6:
Sonic_RollSpeed:
    move.w  (Sonic_top_speed).w,d6
    asl.w   #1,d6
    move.w  (Sonic_acceleration).w,d5
    asr.w   #1,d5   ; natural roll deceleration = 1/2 normal acceleration
    move.w  #$20,d4 ; controlled roll deceleration... interestingly,
            ; this should be Sonic_deceleration/4 according to Tails_RollSpeed,
            ; which means Sonic is much better than Tails at slowing down his rolling when he's underwater
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.w   Obj01_Roll_ResetScr
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.w   Obj01_Roll_ResetScr
    endif
    tst.w   move_lock(a0)
    bne.s   Sonic_ApplyRollSpeed
    btst    #button_left,(Ctrl_1_Held_Logical).w    ; is left being pressed?
    beq.s   +               ; if not, branch
    bsr.w   Sonic_RollLeft
+
    btst    #button_right,(Ctrl_1_Held_Logical).w   ; is right being pressed?
    beq.s   Sonic_ApplyRollSpeed        ; if not, branch
    bsr.w   Sonic_RollRight
 
; loc_1A7FC:
Sonic_ApplyRollSpeed:
    move.w  inertia(a0),d0
    beq.s   Sonic_CheckRollStop
    bmi.s   Sonic_ApplyRollSpeedLeft
 
; Sonic_ApplyRollSpeedRight:
    sub.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
    bra.s   Sonic_CheckRollStop
; ---------------------------------------------------------------------------
; loc_1A812:
Sonic_ApplyRollSpeedLeft:
    add.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
 
; loc_1A81E:
Sonic_CheckRollStop:
    tst.w   inertia(a0)
    bne.s   Obj01_Roll_ResetScr
    tst.b   pinball_mode(a0) ; note: the spindash flag has a different meaning when Sonic's already rolling -- it's used to mean he's not allowed to stop rolling
    bne.s   Sonic_KeepRolling
    bclr    #2,status(a0)
    move.b  #$13,y_radius(a0)
    move.b  #9,x_radius(a0)
    move.b  #AniIDSonAni_Wait,anim(a0)
    subq.w  #5,y_pos(a0)
    bra.s   Obj01_Roll_ResetScr
 
; ---------------------------------------------------------------------------
; magically gives Sonic an extra push if he's going to stop rolling where it's not allowed
; (such as in an S-curve in HTZ or a stopper chamber in CNZ)
; loc_1A848:
Sonic_KeepRolling:
    move.w  #$400,inertia(a0)
    btst    #0,status(a0)
    beq.s   Obj01_Roll_ResetScr
    neg.w   inertia(a0)
 
; resets the screen to normal while rolling, like Obj01_ResetScr
; loc_1A85A:
Obj01_Roll_ResetScr:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias).w   ; is screen in its default position?
    beq.s   Sonic_SetRollSpeeds     ; if yes, branch
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias).w    ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias).w    ; or subtract 2
 
; loc_1A86C:
Sonic_SetRollSpeeds:
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  inertia(a0),d0
    asr.l   #8,d0
    move.w  d0,y_vel(a0)    ; set y velocity based on $14 and angle
    muls.w  inertia(a0),d1
    asr.l   #8,d1
    cmpi.w  #$1000,d1
    ble.s   +
    move.w  #$1000,d1   ; limit Sonic's speed rolling right
+
    cmpi.w  #-$1000,d1
    bge.s   +
    move.w  #-$1000,d1  ; limit Sonic's speed rolling left
+
    move.w  d1,x_vel(a0)    ; set x velocity based on $14 and angle
    bra.w   Obj01_CheckWallsOnGround
; End of function Sonic_RollSpeed
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; loc_1A8A2:
Sonic_RollLeft:
    move.w  inertia(a0),d0
    beq.s   +
    bpl.s   Sonic_BrakeRollingRight
+
    bset    #0,status(a0)
    move.b  #AniIDSonAni_Roll,anim(a0)  ; use "rolling" animation
    rts
; ---------------------------------------------------------------------------
; loc_1A8B8:
Sonic_BrakeRollingRight:
    sub.w   d4,d0   ; reduce rightward rolling speed
    bcc.s   +
    move.w  #-$80,d0
+
    move.w  d0,inertia(a0)
    rts
; End of function Sonic_RollLeft
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; loc_1A8C6:
Sonic_RollRight:
    move.w  inertia(a0),d0
    bmi.s   Sonic_BrakeRollingLeft
    bclr    #0,status(a0)
    move.b  #AniIDSonAni_Roll,anim(a0)  ; use "rolling" animation
    rts
; ---------------------------------------------------------------------------
; loc_1A8DA:
Sonic_BrakeRollingLeft:
    add.w   d4,d0   ; reduce leftward rolling speed
    bcc.s   +
    move.w  #$80,d0
+
    move.w  d0,inertia(a0)
    rts
; End of subroutine Sonic_RollRight
 
 
; ---------------------------------------------------------------------------
; Subroutine for moving Sonic left or right when he's in the air
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A8E8:
Sonic_ChgJumpDir:
    move.w  (Sonic_top_speed).w,d6
    move.w  (Sonic_acceleration).w,d5
    asl.w   #1,d5
    btst    #4,status(a0)       ; did Sonic jump from rolling?
    bne.s   Obj01_Jump_ResetScr ; if yes, branch to skip midair control
    move.w  x_vel(a0),d0
    btst    #button_left,(Ctrl_1_Held_Logical).w
    beq.s   +   ; if not holding left, branch
 
    bset    #0,status(a0)
    sub.w   d5,d0   ; add acceleration to the left
    move.w  d6,d1
    neg.w   d1
    cmp.w   d1,d0   ; compare new speed with top speed
    bgt.s   +   ; if new speed is less than the maximum, branch
    move.w  d1,d0   ; limit speed in air going left, even if Sonic was already going faster (speed limit/cap)
+
    btst    #button_right,(Ctrl_1_Held_Logical).w
    beq.s   +   ; if not holding right, branch
 
    bclr    #0,status(a0)
    add.w   d5,d0   ; accelerate right in the air
    cmp.w   d6,d0   ; compare new speed with top speed
    blt.s   +   ; if new speed is less than the maximum, branch
    move.w  d6,d0   ; limit speed in air going right, even if Sonic was already going faster (speed limit/cap)
; Obj01_JumpMove:
+   move.w  d0,x_vel(a0)
 
; loc_1A932: Obj01_ResetScr2:
Obj01_Jump_ResetScr:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias).w   ; is screen in its default position?
    beq.s   Sonic_JumpPeakDecelerate    ; if yes, branch
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias).w    ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias).w    ; or subtract 2
 
; loc_1A944:
Sonic_JumpPeakDecelerate:
    cmpi.w  #-$400,y_vel(a0)    ; is Sonic moving faster than -$400 upwards?
    blo.s   return_1A972        ; if yes, return
    move.w  x_vel(a0),d0
    move.w  d0,d1
    asr.w   #5,d1       ; d1 = x_velocity / 32
    beq.s   return_1A972    ; return if d1 is 0
    bmi.s   Sonic_JumpPeakDecelerateLeft    ; branch if moving left
 
; Sonic_JumpPeakDecelerateRight:
    sub.w   d1,d0   ; reduce x velocity by d1
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,x_vel(a0)
    rts
;-------------------------------------------------------------
; loc_1A966:
Sonic_JumpPeakDecelerateLeft:
    sub.w   d1,d0   ; reduce x velocity by d1
    bcs.s   +
    move.w  #0,d0
+
    move.w  d0,x_vel(a0)
 
return_1A972:
    rts
; End of subroutine Sonic_ChgJumpDir
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to prevent Sonic from leaving the boundaries of a level
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A974:
Sonic_LevelBound:
    move.l  x_pos(a0),d1
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d1
    swap    d1
    move.w  (Camera_Min_X_pos).w,d0
    addi.w  #$10,d0
    cmp.w   d1,d0           ; has Sonic touched the left boundary?
    bhi.s   Sonic_Boundary_Sides    ; if yes, branch
    move.w  (Camera_Max_X_pos).w,d0
    addi.w  #$128,d0
    tst.b   (Current_Boss_ID).w
    bne.s   +
    addi.w  #$40,d0
+
    cmp.w   d1,d0           ; has Sonic touched the right boundary?
    bls.s   Sonic_Boundary_Sides    ; if yes, branch
 
; loc_1A9A6:
Sonic_Boundary_CheckBottom:
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0        ; has Sonic touched the bottom boundary?
    blt.s   Sonic_Boundary_Bottom   ; if yes, branch
    rts
; ---------------------------------------------------------------------------
Sonic_Boundary_Bottom: ;;
    jmpto   (KillCharacter).l, JmpTo_KillCharacter
; ===========================================================================
 
; loc_1A9BA:
Sonic_Boundary_Sides:
    move.w  d0,x_pos(a0)
    move.w  #0,2+x_pos(a0) ; subpixel x
    move.w  #0,x_vel(a0)
    move.w  #0,inertia(a0)
    bra.s   Sonic_Boundary_CheckBottom
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine allowing Sonic to start rolling when he's moving
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1A9D2:
Sonic_Roll:
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.s   Obj01_NoRoll
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.s   Obj01_NoRoll
    endif
    mvabs.w inertia(a0),d0
    cmpi.w  #$80,d0     ; is Sonic moving at $80 speed or faster?
    blo.s   Obj01_NoRoll    ; if not, branch
    move.b  (Ctrl_1_Held_Logical).w,d0
    andi.b  #button_left_mask|button_right_mask,d0 ; is left/right being pressed?
    bne.s   Obj01_NoRoll    ; if yes, branch
    btst    #button_down,(Ctrl_1_Held_Logical).w ; is down being pressed?
    bne.s   Obj01_ChkRoll           ; if yes, branch
; return_1A9F8:
Obj01_NoRoll:
    rts
 
; ---------------------------------------------------------------------------
; loc_1A9FA:
Obj01_ChkRoll:
    btst    #2,status(a0)   ; is Sonic already rolling?
    beq.s   Obj01_DoRoll    ; if not, branch
    rts
 
; ---------------------------------------------------------------------------
; loc_1AA04:
Obj01_DoRoll:
    bset    #2,status(a0)
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDSonAni_Roll,anim(a0)  ; use "rolling" animation
    addq.w  #5,y_pos(a0)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l   ; play rolling sound
    tst.w   inertia(a0)
    bne.s   return_1AA36
    move.w  #$200,inertia(a0)
 
return_1AA36:
    rts
; End of function Sonic_Roll
 
 
; ---------------------------------------------------------------------------
; Subroutine allowing Sonic to jump
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AA38:
Sonic_Jump:
    move.b  (Ctrl_1_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is A, B or C pressed?
    beq.w   return_1AAE6    ; if not, return
    moveq   #0,d0
    move.b  angle(a0),d0
    addi.b  #$80,d0
    bsr.w   CalcRoomOverHead
    cmpi.w  #6,d1           ; does Sonic have enough room to jump?
    blt.w   return_1AAE6        ; if not, branch
    move.w  #$680,d2
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    move.w  #$800,d2    ; set higher jump speed if super
+
    btst    #6,status(a0)   ; Test if underwater
    beq.s   +
    move.w  #$380,d2    ; set lower jump speed if under
+
    moveq   #0,d0
    move.b  angle(a0),d0
    subi.b  #$40,d0
    jsr (CalcSine).l
    muls.w  d2,d1
    asr.l   #8,d1
    add.w   d1,x_vel(a0)    ; make Sonic jump (in X... this adds nothing on level ground)
    muls.w  d2,d0
    asr.l   #8,d0
    add.w   d0,y_vel(a0)    ; make Sonic jump (in Y)
    bset    #1,status(a0)
    bclr    #5,status(a0)
    addq.l  #4,sp
    move.b  #1,jumping(a0)
    clr.b   stick_to_convex(a0)
    move.w  #SndID_Jump,d0
    jsr (PlaySound).l   ; play jumping sound
    move.b  #$13,y_radius(a0)
    move.b  #9,x_radius(a0)
    btst    #2,status(a0)
    bne.s   Sonic_RollJump
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDSonAni_Roll,anim(a0)  ; use "jumping" animation
    bset    #2,status(a0)
    addq.w  #5,y_pos(a0)
 
return_1AAE6:
    rts
; ---------------------------------------------------------------------------
; loc_1AAE8:
Sonic_RollJump:
    bset    #4,status(a0)   ; set the rolling+jumping flag
    rts
; End of function Sonic_Jump
 
 
; ---------------------------------------------------------------------------
; Subroutine letting Sonic control the height of the jump
; when the jump button is released
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; ===========================================================================
; loc_1AAF0:
Sonic_JumpHeight:
    tst.b   jumping(a0) ; is Sonic jumping?
    beq.s   Sonic_UpVelCap  ; if not, branch
 
    move.w  #-$400,d1
    btst    #6,status(a0)   ; is Sonic underwater?
    beq.s   +       ; if not, branch
    move.w  #-$200,d1
+
    cmp.w   y_vel(a0),d1    ; is Sonic going up faster than d1?
    ble.s   +       ; if not, branch
    move.b  (Ctrl_1_Held_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    bne.s   +       ; if yes, branch
    move.w  d1,y_vel(a0)    ; immediately reduce Sonic's upward speed to d1
+
    tst.b   y_vel(a0)       ; is Sonic exactly at the height of his jump?
    beq.s   Sonic_CheckGoSuper  ; if yes, test for turning into Super Sonic
    rts
; ---------------------------------------------------------------------------
; loc_1AB22:
Sonic_UpVelCap:
    tst.b   pinball_mode(a0)    ; is Sonic charging a spindash or in a rolling-only area?
    bne.s   return_1AB36        ; if yes, return
    cmpi.w  #-$FC0,y_vel(a0)    ; is Sonic moving up really fast?
    bge.s   return_1AB36        ; if not, return
    move.w  #-$FC0,y_vel(a0)    ; cap upward speed
 
return_1AB36:
    rts
; End of subroutine Sonic_JumpHeight
 
; ---------------------------------------------------------------------------
; Subroutine called at the peak of a jump that transforms Sonic into Super Sonic
; if he has enough rings and emeralds
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AB38: test_set_SS:
Sonic_CheckGoSuper:
    tst.b   (Super_Sonic_flag).w    ; is Sonic already Super?
    bne.s   return_1ABA4        ; if yes, branch
    cmpi.b  #7,(Emerald_count).w    ; does Sonic have exactly 7 emeralds?
    bne.s   return_1ABA4        ; if not, branch
    cmpi.w  #50,(Ring_count).w  ; does Sonic have at least 50 rings?
    blo.s   return_1ABA4        ; if not, branch
    if gameRevision=2
    ; fixes a bug where the player can get stuck if transforming at the end of a level
    tst.b   (Update_HUD_timer).w    ; has Sonic reached the end of the act?
    beq.s   return_1ABA4        ; if yes, branch
    endif
 
    move.b  #1,(Super_Sonic_palette).w
    move.b  #$F,(Palette_timer).w
    move.b  #1,(Super_Sonic_flag).w
    move.b  #$81,obj_control(a0)
    move.b  #AniIDSupSonAni_Transform,anim(a0)          ; use transformation animation
    move.b  #ObjID_SuperSonicStars,(SuperSonicStars+id).w ; load Obj7E (super sonic stars object) at $FFFFD040
    move.w  #$A00,(Sonic_top_speed).w
    move.w  #$30,(Sonic_acceleration).w
    move.w  #$100,(Sonic_deceleration).w
    move.w  #0,invincibility_time(a0)
    bset    #status_sec_isInvincible,status_secondary(a0)   ; make Sonic invincible
    move.w  #SndID_SuperTransform,d0
    jsr (PlaySound).l   ; Play transformation sound effect.
    move.w  #MusID_SuperSonic,d0
    jmp (PlayMusic).l   ; load the Super Sonic song and return
 
; ---------------------------------------------------------------------------
return_1ABA4:
    rts
; End of subroutine Sonic_CheckGoSuper
 
 
; ---------------------------------------------------------------------------
; Subroutine doing the extra logic for Super Sonic
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1ABA6:
Sonic_Super:
    tst.b   (Super_Sonic_flag).w    ; Ignore all this code if not Super Sonic
    beq.w   return_1AC3C
    tst.b   (Update_HUD_timer).w
    beq.s   Sonic_RevertToNormal ; ?
    subq.w  #1,(Super_Sonic_frame_count).w
    bpl.w   return_1AC3C
    move.w  #60,(Super_Sonic_frame_count).w ; Reset frame counter to 60
    tst.w   (Ring_count).w
    beq.s   Sonic_RevertToNormal
    ori.b   #1,(Update_HUD_rings).w
    cmpi.w  #1,(Ring_count).w
    beq.s   +
    cmpi.w  #10,(Ring_count).w
    beq.s   +
    cmpi.w  #100,(Ring_count).w
    bne.s   ++
+
    ori.b   #$80,(Update_HUD_rings).w
+
    subq.w  #1,(Ring_count).w
    bne.s   return_1AC3C
; loc_1ABF2:
Sonic_RevertToNormal:
    move.b  #2,(Super_Sonic_palette).w  ; Remove rotating palette
    move.w  #$28,(Palette_frame).w
    move.b  #0,(Super_Sonic_flag).w
    move.b  #1,next_anim(a0)    ; Change animation back to normal ?
    move.w  #1,invincibility_time(a0)   ; Remove invincibility
    move.w  #$600,(Sonic_top_speed).w
    move.w  #$C,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
    btst    #6,status(a0)   ; Check if underwater, return if not
    beq.s   return_1AC3C
    move.w  #$300,(Sonic_top_speed).w
    move.w  #6,(Sonic_acceleration).w
    move.w  #$40,(Sonic_deceleration).w
 
return_1AC3C:
    rts
; End of subroutine Sonic_Super
 
; ---------------------------------------------------------------------------
; Subroutine to check for starting to charge a spindash
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AC3E:
Sonic_CheckSpindash:
    tst.b   spindash_flag(a0)
    bne.s   Sonic_UpdateSpindash
    cmpi.b  #AniIDSonAni_Duck,anim(a0)
    bne.s   return_1AC8C
    move.b  (Ctrl_1_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   return_1AC8C
    move.b  #AniIDSonAni_Spindash,anim(a0)
    move.w  #SndID_SpindashRev,d0
    jsr (PlaySound).l
    addq.l  #4,sp
    move.b  #1,spindash_flag(a0)
    move.w  #0,spindash_counter(a0)
    cmpi.b  #$C,air_left(a0)    ; if he's drowning, branch to not make dust
    blo.s   +
    move.b  #2,(Sonic_Dust+anim).w
+
    bsr.w   Sonic_LevelBound
    bsr.w   AnglePos
 
return_1AC8C:
    rts
; End of subroutine Sonic_CheckSpindash
 
 
; ---------------------------------------------------------------------------
; Subrouting to update an already-charging spindash
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AC8E:
Sonic_UpdateSpindash:
    move.b  (Ctrl_1_Held_Logical).w,d0
    btst    #button_down,d0
    bne.w   Sonic_ChargingSpindash
 
    ; unleash the charged spindash and start rolling quickly:
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDSonAni_Roll,anim(a0)
    addq.w  #5,y_pos(a0)    ; add the difference between Sonic's rolling and standing heights
    move.b  #0,spindash_flag(a0)
    moveq   #0,d0
    move.b  spindash_counter(a0),d0
    add.w   d0,d0
    move.w  SpindashSpeeds(pc,d0.w),inertia(a0)
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    move.w  SpindashSpeedsSuper(pc,d0.w),inertia(a0)
+
    move.w  inertia(a0),d0
    subi.w  #$800,d0
    add.w   d0,d0
    andi.w  #$1F00,d0
    neg.w   d0
    addi.w  #$2000,d0
    move.w  d0,(Horiz_scroll_delay_val).w
    btst    #0,status(a0)
    beq.s   +
    neg.w   inertia(a0)
+
    bset    #2,status(a0)
    move.b  #0,(Sonic_Dust+anim).w
    move.w  #SndID_SpindashRelease,d0   ; spindash zoom sound
    jsr (PlaySound).l
    bra.s   Obj01_Spindash_ResetScr
; ===========================================================================
; word_1AD0C:
SpindashSpeeds:
    dc.w  $800  ; 0
    dc.w  $880  ; 1
    dc.w  $900  ; 2
    dc.w  $980  ; 3
    dc.w  $A00  ; 4
    dc.w  $A80  ; 5
    dc.w  $B00  ; 6
    dc.w  $B80  ; 7
    dc.w  $C00  ; 8
; word_1AD1E:
SpindashSpeedsSuper:
    dc.w  $B00  ; 0
    dc.w  $B80  ; 1
    dc.w  $C00  ; 2
    dc.w  $C80  ; 3
    dc.w  $D00  ; 4
    dc.w  $D80  ; 5
    dc.w  $E00  ; 6
    dc.w  $E80  ; 7
    dc.w  $F00  ; 8
; ===========================================================================
; loc_1AD30:
Sonic_ChargingSpindash:         ; If still charging the dash...
    tst.w   spindash_counter(a0)
    beq.s   +
    move.w  spindash_counter(a0),d0
    lsr.w   #5,d0
    sub.w   d0,spindash_counter(a0)
    bcc.s   +
    move.w  #0,spindash_counter(a0)
+
    move.b  (Ctrl_1_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   Obj01_Spindash_ResetScr
    move.w  #(AniIDSonAni_Spindash<<8),anim(a0)
    move.w  #SndID_SpindashRev,d0
    jsr (PlaySound).l
    addi.w  #$200,spindash_counter(a0)
    cmpi.w  #$800,spindash_counter(a0)
    blo.s   Obj01_Spindash_ResetScr
    move.w  #$800,spindash_counter(a0)
 
; loc_1AD78:
Obj01_Spindash_ResetScr:
    addq.l  #4,sp
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias).w
    beq.s   loc_1AD8C
    bhs.s   +
    addq.w  #4,(Camera_Y_pos_bias).w
+   subq.w  #2,(Camera_Y_pos_bias).w
 
loc_1AD8C:
    bsr.w   Sonic_LevelBound
    bsr.w   AnglePos
    rts
; End of subroutine Sonic_UpdateSpindash
 
 
; ---------------------------------------------------------------------------
; Subroutine to slow Sonic walking up a slope
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AD96:
Sonic_SlopeResist:
    move.b  angle(a0),d0
    addi.b  #$60,d0
    cmpi.b  #$C0,d0
    bhs.s   return_1ADCA
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  #$20,d0
    asr.l   #8,d0
    tst.w   inertia(a0)
    beq.s   return_1ADCA
    bmi.s   loc_1ADC6
    tst.w   d0
    beq.s   +
    add.w   d0,inertia(a0)  ; change Sonic's $14
+
    rts
; ---------------------------------------------------------------------------
 
loc_1ADC6:
    add.w   d0,inertia(a0)
 
return_1ADCA:
    rts
; End of subroutine Sonic_SlopeResist
 
; ---------------------------------------------------------------------------
; Subroutine to push Sonic down a slope while he's rolling
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1ADCC:
Sonic_RollRepel:
    move.b  angle(a0),d0
    addi.b  #$60,d0
    cmpi.b  #-$40,d0
    bhs.s   return_1AE06
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  #$50,d0
    asr.l   #8,d0
    tst.w   inertia(a0)
    bmi.s   loc_1ADFC
    tst.w   d0
    bpl.s   loc_1ADF6
    asr.l   #2,d0
 
loc_1ADF6:
    add.w   d0,inertia(a0)
    rts
; ===========================================================================
 
loc_1ADFC:
    tst.w   d0
    bmi.s   loc_1AE02
    asr.l   #2,d0
 
loc_1AE02:
    add.w   d0,inertia(a0)
 
return_1AE06:
    rts
; End of function Sonic_RollRepel
 
; ---------------------------------------------------------------------------
; Subroutine to push Sonic down a slope
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AE08:
Sonic_SlopeRepel:
    nop
    tst.b   stick_to_convex(a0)
    bne.s   return_1AE42
    tst.w   move_lock(a0)
    bne.s   loc_1AE44
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    beq.s   return_1AE42
    mvabs.w inertia(a0),d0
    cmpi.w  #$280,d0
    bhs.s   return_1AE42
    clr.w   inertia(a0)
    bset    #1,status(a0)
    move.w  #$1E,move_lock(a0)
 
return_1AE42:
    rts
; ===========================================================================
 
loc_1AE44:
    subq.w  #1,move_lock(a0)
    rts
; End of function Sonic_SlopeRepel
 
; ---------------------------------------------------------------------------
; Subroutine to return Sonic's angle to 0 as he jumps
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AE4A:
Sonic_JumpAngle:
    move.b  angle(a0),d0    ; get Sonic's angle
    beq.s   Sonic_JumpFlip  ; if already 0, branch
    bpl.s   loc_1AE5A   ; if higher than 0, branch
 
    addq.b  #2,d0       ; increase angle
    bcc.s   BranchTo_Sonic_JumpAngleSet
    moveq   #0,d0
 
BranchTo_Sonic_JumpAngleSet 
    bra.s   Sonic_JumpAngleSet
; ===========================================================================
 
loc_1AE5A:
    subq.b  #2,d0       ; decrease angle
    bcc.s   Sonic_JumpAngleSet
    moveq   #0,d0
 
; loc_1AE60:
Sonic_JumpAngleSet:
    move.b  d0,angle(a0)
; End of function Sonic_JumpAngle
    ; continue straight to Sonic_JumpFlip
 
; ---------------------------------------------------------------------------
; Updates Sonic's secondary angle if he's tumbling
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AE64:
Sonic_JumpFlip:
    move.b  flip_angle(a0),d0
    beq.s   return_1AEA8
    tst.w   inertia(a0)
    bmi.s   Sonic_JumpLeftFlip
; loc_1AE70:
Sonic_JumpRightFlip:
    move.b  flip_speed(a0),d1
    add.b   d1,d0
    bcc.s   BranchTo_Sonic_JumpFlipSet
    subq.b  #1,flips_remaining(a0)
    bcc.s   BranchTo_Sonic_JumpFlipSet
    move.b  #0,flips_remaining(a0)
    moveq   #0,d0
 
BranchTo_Sonic_JumpFlipSet 
    bra.s   Sonic_JumpFlipSet
; ===========================================================================
; loc_1AE88:
Sonic_JumpLeftFlip:
    tst.b   flip_turned(a0)
    bne.s   Sonic_JumpRightFlip
    move.b  flip_speed(a0),d1
    sub.b   d1,d0
    bcc.s   Sonic_JumpFlipSet
    subq.b  #1,flips_remaining(a0)
    bcc.s   Sonic_JumpFlipSet
    move.b  #0,flips_remaining(a0)
    moveq   #0,d0
; loc_1AEA4:
Sonic_JumpFlipSet:
    move.b  d0,flip_angle(a0)
 
return_1AEA8:
    rts
; End of function Sonic_JumpFlip
 
; ---------------------------------------------------------------------------
; Subroutine for Sonic to interact with the floor and walls when he's in the air
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1AEAA: Sonic_Floor:
Sonic_DoLevelCollision:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  lrb_solid_bit(a0),d5
    move.w  x_vel(a0),d1
    move.w  y_vel(a0),d2
    jsr (CalcAngle).l
    subi.b  #$20,d0
    andi.b  #$C0,d0
    cmpi.b  #$40,d0
    beq.w   Sonic_HitLeftWall
    cmpi.b  #$80,d0
    beq.w   Sonic_HitCeilingAndWalls
    cmpi.b  #$C0,d0
    beq.w   Sonic_HitRightWall
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   +
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0) ; stop Sonic since he hit a wall
+
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   +
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0) ; stop Sonic since he hit a wall
+
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1AF8A
    move.b  y_vel(a0),d2
    addq.b  #8,d2
    neg.b   d2
    cmp.b   d2,d1
    bge.s   +
    cmp.b   d2,d0
    blt.s   return_1AF8A
+
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Sonic_ResetOnFloor
    move.b  d3,d0
    addi.b  #$20,d0
    andi.b  #$40,d0
    bne.s   loc_1AF68
    move.b  d3,d0
    addi.b  #$10,d0
    andi.b  #$20,d0
    beq.s   loc_1AF5A
    asr y_vel(a0)
    bra.s   loc_1AF7C
; ===========================================================================
 
loc_1AF5A:
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
    rts
; ===========================================================================
 
loc_1AF68:
    move.w  #0,x_vel(a0) ; stop Sonic since he hit a wall
    cmpi.w  #$FC0,y_vel(a0)
    ble.s   loc_1AF7C
    move.w  #$FC0,y_vel(a0)
 
loc_1AF7C:
    move.w  y_vel(a0),inertia(a0)
    tst.b   d3
    bpl.s   return_1AF8A
    neg.w   inertia(a0)
 
return_1AF8A:
    rts
; ===========================================================================
; loc_1AF8C:
Sonic_HitLeftWall:
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   Sonic_HitCeiling ; branch if distance is positive (not inside wall)
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0) ; stop Sonic since he hit a wall
    move.w  y_vel(a0),inertia(a0)
    rts
; ===========================================================================
; loc_1AFA6:
Sonic_HitCeiling:
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   Sonic_HitFloor ; branch if distance is positive (not inside ceiling)
    sub.w   d1,y_pos(a0)
    tst.w   y_vel(a0)
    bpl.s   return_1AFBE
    move.w  #0,y_vel(a0) ; stop Sonic in y since he hit a ceiling
 
return_1AFBE:
    rts
; ===========================================================================
; loc_1AFC0:
Sonic_HitFloor:
    tst.w   y_vel(a0)
    bmi.s   return_1AFE6
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1AFE6
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Sonic_ResetOnFloor
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
 
return_1AFE6:
    rts
; ===========================================================================
; loc_1AFE8:
Sonic_HitCeilingAndWalls:
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   +
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Sonic since he hit a wall
+
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   +
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Sonic since he hit a wall
+
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   return_1B042
    sub.w   d1,y_pos(a0)
    move.b  d3,d0
    addi.b  #$20,d0
    andi.b  #$40,d0
    bne.s   loc_1B02C
    move.w  #0,y_vel(a0) ; stop Sonic in y since he hit a ceiling
    rts
; ===========================================================================
 
loc_1B02C:
    move.b  d3,angle(a0)
    bsr.w   Sonic_ResetOnFloor
    move.w  y_vel(a0),inertia(a0)
    tst.b   d3
    bpl.s   return_1B042
    neg.w   inertia(a0)
 
return_1B042:
    rts
; ===========================================================================
; loc_1B044:
Sonic_HitRightWall:
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   Sonic_HitCeiling2
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0) ; stop Sonic since he hit a wall
    move.w  y_vel(a0),inertia(a0)
    rts
; ===========================================================================
; identical to Sonic_HitCeiling...
; loc_1B05E:
Sonic_HitCeiling2:
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   Sonic_HitFloor2
    sub.w   d1,y_pos(a0)
    tst.w   y_vel(a0)
    bpl.s   return_1B076
    move.w  #0,y_vel(a0) ; stop Sonic in y since he hit a ceiling
 
return_1B076:
    rts
; ===========================================================================
; identical to Sonic_HitFloor...
; loc_1B078:
Sonic_HitFloor2:
    tst.w   y_vel(a0)
    bmi.s   return_1B09E
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1B09E
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Sonic_ResetOnFloor
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
 
return_1B09E:
    rts
; End of function Sonic_DoLevelCollision
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to reset Sonic's mode when he lands on the floor
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1B0A0:
Sonic_ResetOnFloor:
    tst.b   pinball_mode(a0)
    bne.s   Sonic_ResetOnFloor_Part3
    move.b  #AniIDSonAni_Walk,anim(a0)
; loc_1B0AC:
Sonic_ResetOnFloor_Part2:
    ; some routines outside of Tails' code can call Sonic_ResetOnFloor_Part2
    ; when they mean to call Tails_ResetOnFloor_Part2, so fix that here
    _cmpi.b #ObjID_Sonic,id(a0) ; is this object ID Sonic (obj01)?
    bne.w   Tails_ResetOnFloor_Part2    ; if not, branch to the Tails version of this code
 
    btst    #2,status(a0)
    beq.s   Sonic_ResetOnFloor_Part3
    bclr    #2,status(a0)
    move.b  #$13,y_radius(a0) ; this increases Sonic's collision height to standing
    move.b  #9,x_radius(a0)
    move.b  #AniIDSonAni_Walk,anim(a0)  ; use running/walking/standing animation
    subq.w  #5,y_pos(a0)    ; move Sonic up 5 pixels so the increased height doesn't push him into the ground
; loc_1B0DA:
Sonic_ResetOnFloor_Part3:
    bclr    #1,status(a0)
    bclr    #5,status(a0)
    bclr    #4,status(a0)
    move.b  #0,jumping(a0)
    move.w  #0,(Chain_Bonus_counter).w
    move.b  #0,flip_angle(a0)
    move.b  #0,flip_turned(a0)
    move.b  #0,flips_remaining(a0)
    move.w  #0,(Sonic_Look_delay_counter).w
    cmpi.b  #AniIDSonAni_Hang2,anim(a0)
    bne.s   return_1B11E
    move.b  #AniIDSonAni_Walk,anim(a0)
 
return_1B11E:
    rts
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Sonic when he gets hurt
; ---------------------------------------------------------------------------
; loc_1B120: Obj_01_Sub_4:
Obj01_Hurt:
    tst.w   (Debug_mode_flag).w
    beq.s   Obj01_Hurt_Normal
    btst    #button_B,(Ctrl_1_Press).w
    beq.s   Obj01_Hurt_Normal
    move.w  #1,(Debug_placement_mode).w
    clr.b   (Control_Locked).w
    rts
; ---------------------------------------------------------------------------
; loc_1B13A:
Obj01_Hurt_Normal:
    tst.b   routine_secondary(a0)
    bmi.w   Sonic_HurtInstantRecover
    jsr (ObjectMove).l
    addi.w  #$30,y_vel(a0)
    btst    #6,status(a0)
    beq.s   +
    subi.w  #$20,y_vel(a0)
+
    cmpi.w  #-$100,(Camera_Min_Y_pos).w
    bne.s   +
    andi.w  #$7FF,y_pos(a0)
+
    bsr.w   Sonic_HurtStop
    bsr.w   Sonic_LevelBound
    bsr.w   Sonic_RecordPos
    bsr.w   Sonic_Animate
    bsr.w   LoadSonicDynPLC
    jmp (DisplaySprite).l
; ===========================================================================
; loc_1B184:
Sonic_HurtStop:
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    blt.w   JmpTo_KillCharacter
    bsr.w   Sonic_DoLevelCollision
    btst    #1,status(a0)
    bne.s   return_1B1C8
    moveq   #0,d0
    move.w  d0,y_vel(a0)
    move.w  d0,x_vel(a0)
    move.w  d0,inertia(a0)
    move.b  d0,obj_control(a0)
    move.b  #AniIDSonAni_Walk,anim(a0)
    subq.b  #2,routine(a0)  ; => Obj01_Control
    move.w  #$78,invulnerable_time(a0)
    move.b  #0,spindash_flag(a0)
 
return_1B1C8:
    rts
; ===========================================================================
; makes Sonic recover control after being hurt before landing
; seems to be unused
; loc_1B1CA:
Sonic_HurtInstantRecover:
    subq.b  #2,routine(a0)  ; => Obj01_Control
    move.b  #0,routine_secondary(a0)
    bsr.w   Sonic_RecordPos
    bsr.w   Sonic_Animate
    bsr.w   LoadSonicDynPLC
    jmp (DisplaySprite).l
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Sonic when he dies
; ...poor Sonic
; ---------------------------------------------------------------------------
 
; loc_1B1E6: Obj_01_Sub_6:
Obj01_Dead:
    tst.w   (Debug_mode_flag).w
    beq.s   +
    btst    #button_B,(Ctrl_1_Press).w
    beq.s   +
    move.w  #1,(Debug_placement_mode).w
    clr.b   (Control_Locked).w
    rts
+
    bsr.w   CheckGameOver
    jsr (ObjectMoveAndFall).l
    bsr.w   Sonic_RecordPos
    bsr.w   Sonic_Animate
    bsr.w   LoadSonicDynPLC
    jmp (DisplaySprite).l
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1B21C:
CheckGameOver:
    move.b  #1,(Scroll_lock).w
    move.b  #0,spindash_flag(a0)
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$100,d0
    cmp.w   y_pos(a0),d0
    bge.w   return_1B31A
    move.b  #8,routine(a0)  ; => Obj01_Gone
    move.w  #$3C,restart_countdown(a0)
    addq.b  #1,(Update_HUD_lives).w ; update lives counter
    subq.b  #1,(Life_count).w   ; subtract 1 from number of lives
    bne.s   Obj01_ResetLevel    ; if it's not a game over, branch
    move.w  #0,restart_countdown(a0)
    move.b  #ObjID_GameOver,(GameOver_GameText+id).w ; load Obj39 (game over text)
    move.b  #ObjID_GameOver,(GameOver_OverText+id).w ; load Obj39 (game over text)
    move.b  #1,(GameOver_OverText+mapping_frame).w
    move.w  a0,(GameOver_GameText+parent).w
    clr.b   (Time_Over_flag).w
; loc_1B26E:
Obj01_Finished:
    clr.b   (Update_HUD_timer).w
    clr.b   (Update_HUD_timer_2P).w
    move.b  #8,routine(a0)  ; => Obj01_Gone
    move.w  #MusID_GameOver,d0
    jsr (PlayMusic).l
    moveq   #PLCID_GameOver,d0
    jmp (LoadPLC).l
; End of function CheckGameOver
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Sonic when the level is restarted
; ---------------------------------------------------------------------------
; loc_1B28E:
Obj01_ResetLevel:
    tst.b   (Time_Over_flag).w
    beq.s   Obj01_ResetLevel_Part2
    move.w  #0,restart_countdown(a0)
    move.b  #ObjID_TimeOver,(TimeOver_TimeText+id).w ; load Obj39
    move.b  #ObjID_TimeOver,(TimeOver_OverText+id).w ; load Obj39
    move.b  #2,(TimeOver_TimeText+mapping_frame).w
    move.b  #3,(TimeOver_OverText+mapping_frame).w
    move.w  a0,(TimeOver_TimeText+parent).w
    bra.s   Obj01_Finished
; ---------------------------------------------------------------------------
Obj01_ResetLevel_Part2:
    tst.w   (Two_player_mode).w
    beq.s   return_1B31A
    move.b  #0,(Scroll_lock).w
    move.b  #$A,routine(a0) ; => Obj01_Respawning
    move.w  (Saved_x_pos).w,x_pos(a0)
    move.w  (Saved_y_pos).w,y_pos(a0)
    move.w  (Saved_art_tile).w,art_tile(a0)
    move.w  (Saved_Solid_bits).w,top_solid_bit(a0)
    clr.w   (Ring_count).w
    clr.b   (Extra_life_flags).w
    move.b  #0,obj_control(a0)
    move.b  #5,anim(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    move.w  #0,inertia(a0)
    move.b  #2,status(a0)
    move.w  #0,move_lock(a0)
    move.w  #0,restart_countdown(a0)
 
return_1B31A:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Sonic when he's offscreen and waiting for the level to restart
; ---------------------------------------------------------------------------
; loc_1B31C: Obj_01_Sub_8:
Obj01_Gone:
    tst.w   restart_countdown(a0)
    beq.s   +
    subq.w  #1,restart_countdown(a0)
    bne.s   +
    move.w  #1,(Level_Inactive_flag).w
+
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Sonic when he's waiting for the camera to scroll back to where he respawned
; ---------------------------------------------------------------------------
; loc_1B330: Obj_01_Sub_A:
Obj01_Respawning:
    tst.w   (Camera_X_pos_diff).w
    bne.s   +
    tst.w   (Camera_Y_pos_diff).w
    bne.s   +
    move.b  #2,routine(a0)  ; => Obj01_Control
+
    bsr.w   Sonic_Animate
    bsr.w   LoadSonicDynPLC
    jmp (DisplaySprite).l
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to animate Sonic's sprites
; See also: AnimateSprite
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1B350:
Sonic_Animate:
    lea (SonicAniData).l,a1
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    lea (SuperSonicAniData).l,a1
+
    moveq   #0,d0
    move.b  anim(a0),d0
    cmp.b   next_anim(a0),d0    ; has animation changed?
    beq.s   SAnim_Do        ; if not, branch
    move.b  d0,next_anim(a0)    ; set to next animation
    move.b  #0,anim_frame(a0)   ; reset animation frame
    move.b  #0,anim_frame_duration(a0)  ; reset frame duration
    bclr    #5,status(a0)
; loc_1B384:
SAnim_Do:
    add.w   d0,d0
    adda.w  (a1,d0.w),a1    ; calculate address of appropriate animation script
    move.b  (a1),d0
    bmi.s   SAnim_WalkRun   ; if animation is walk/run/roll/jump, branch
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.s   SAnim_Delay         ; if time remains, branch
    move.b  d0,anim_frame_duration(a0)  ; load frame duration
; loc_1B3AA:
SAnim_Do2:
    moveq   #0,d1
    move.b  anim_frame(a0),d1   ; load current frame number
    move.b  1(a1,d1.w),d0       ; read sprite number from script
    cmpi.b  #$F0,d0
    bhs.s   SAnim_End_FF        ; if animation is complete, branch
; loc_1B3BA:
SAnim_Next:
    move.b  d0,mapping_frame(a0)    ; load sprite number
    addq.b  #1,anim_frame(a0)   ; go to next frame
; return_1B3C2:
SAnim_Delay:
    rts
; ===========================================================================
; loc_1B3C4:
SAnim_End_FF:
    addq.b  #1,d0       ; is the end flag = $FF ?
    bne.s   SAnim_End_FE    ; if not, branch
    move.b  #0,anim_frame(a0)   ; restart the animation
    move.b  1(a1),d0    ; read sprite number
    bra.s   SAnim_Next
; ===========================================================================
; loc_1B3D4:
SAnim_End_FE:
    addq.b  #1,d0       ; is the end flag = $FE ?
    bne.s   SAnim_End_FD    ; if not, branch
    move.b  2(a1,d1.w),d0   ; read the next byte in the script
    sub.b   d0,anim_frame(a0)   ; jump back d0 bytes in the script
    sub.b   d0,d1
    move.b  1(a1,d1.w),d0   ; read sprite number
    bra.s   SAnim_Next
; ===========================================================================
; loc_1B3E8:
SAnim_End_FD:
    addq.b  #1,d0           ; is the end flag = $FD ?
    bne.s   SAnim_End       ; if not, branch
    move.b  2(a1,d1.w),anim(a0) ; read next byte, run that animation
; return_1B3F2:
SAnim_End:
    rts
; ===========================================================================
; loc_1B3F4:
SAnim_WalkRun:
    addq.b  #1,d0       ; is the start flag = $FF ?
    bne.w   SAnim_Roll  ; if not, branch
    moveq   #0,d0       ; is animation walking/running?
    move.b  flip_angle(a0),d0   ; if not, branch
    bne.w   SAnim_Tumble
    moveq   #0,d1
    move.b  angle(a0),d0    ; get Sonic's angle
    bmi.s   +
    beq.s   +
    subq.b  #1,d0
+
    move.b  status(a0),d2
    andi.b  #1,d2       ; is Sonic mirrored horizontally?
    bne.s   +       ; if yes, branch
    not.b   d0      ; reverse angle
+
    addi.b  #$10,d0     ; add $10 to angle
    bpl.s   +       ; if angle is $0-$7F, branch
    moveq   #3,d1
+
    andi.b  #$FC,render_flags(a0)
    eor.b   d1,d2
    or.b    d2,render_flags(a0)
    btst    #5,status(a0)
    bne.w   SAnim_Push
    lsr.b   #4,d0       ; divide angle by 16
    andi.b  #6,d0       ; angle must be 0, 2, 4 or 6
    mvabs.w inertia(a0),d2  ; get Sonic's "speed" for animation purposes
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bpl.w   +
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    beq.w   +
    endif
    add.w   d2,d2
+
    tst.b   (Super_Sonic_flag).w
    bne.s   SAnim_Super
    lea (SonAni_Run).l,a1   ; use running animation
    cmpi.w  #$600,d2        ; is Sonic at running speed?
    bhs.s   +           ; use running animation
    lea (SonAni_Walk).l,a1  ; if yes, branch
    add.b   d0,d0
+
    add.b   d0,d0
    move.b  d0,d3
    moveq   #0,d1
    move.b  anim_frame(a0),d1
    move.b  1(a1,d1.w),d0
    cmpi.b  #-1,d0
    bne.s   +
    move.b  #0,anim_frame(a0)
    move.b  1(a1),d0
+
    move.b  d0,mapping_frame(a0)
    add.b   d3,mapping_frame(a0)
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   return_1B4AC
    neg.w   d2
    addi.w  #$800,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #8,d2
    move.b  d2,anim_frame_duration(a0)  ; modify frame duration
    addq.b  #1,anim_frame(a0)       ; modify frame number
 
return_1B4AC:
    rts
; ===========================================================================
; loc_1B4AE:
SAnim_Super:
    lea (SupSonAni_Run).l,a1    ; use fast animation
    cmpi.w  #$800,d2        ; is Sonic moving fast?
    bhs.s   SAnim_SuperRun      ; if yes, branch
    lea (SupSonAni_Walk).l,a1   ; use slower animation
    add.b   d0,d0
    add.b   d0,d0
    bra.s   SAnim_SuperWalk
; ---------------------------------------------------------------------------
; loc_1B4C6:
SAnim_SuperRun:
    lsr.b   #1,d0
; loc_1B4C8:
SAnim_SuperWalk:
    move.b  d0,d3
    moveq   #0,d1
    move.b  anim_frame(a0),d1
    move.b  1(a1,d1.w),d0
    cmpi.b  #-1,d0
    bne.s   +
    move.b  #0,anim_frame(a0)
    move.b  1(a1),d0
+
    move.b  d0,mapping_frame(a0)
    add.b   d3,mapping_frame(a0)
    move.b  (Timer_frames+1).w,d1
    andi.b  #3,d1
    bne.s   +
    cmpi.b  #$B5,mapping_frame(a0)
    bhs.s   +
    addi.b  #$20,mapping_frame(a0)
+
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   return_1B51E
    neg.w   d2
    addi.w  #$800,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #8,d2
    move.b  d2,anim_frame_duration(a0)
    addq.b  #1,anim_frame(a0)
 
return_1B51E:
    rts
; ===========================================================================
; loc_1B520:
SAnim_Tumble:
    move.b  flip_angle(a0),d0
    moveq   #0,d1
    move.b  status(a0),d2
    andi.b  #1,d2
    bne.s   SAnim_Tumble_Left
 
    andi.b  #$FC,render_flags(a0)
    addi.b  #$B,d0
    divu.w  #$16,d0
    addi.b  #$5F,d0
    move.b  d0,mapping_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    rts
; ===========================================================================
; loc_1B54E:
SAnim_Tumble_Left:
    andi.b  #$FC,render_flags(a0)
    tst.b   flip_turned(a0)
    beq.s   loc_1B566
    ori.b   #1,render_flags(a0)
    addi.b  #$B,d0
    bra.s   loc_1B572
; ===========================================================================
 
loc_1B566:
    ori.b   #3,render_flags(a0)
    neg.b   d0
    addi.b  #$8F,d0
 
loc_1B572:
    divu.w  #$16,d0
    addi.b  #$5F,d0
    move.b  d0,mapping_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    rts
; ===========================================================================
; loc_1B586:
SAnim_Roll:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.w   SAnim_Delay         ; if time remains, branch
    addq.b  #1,d0       ; is the start flag = $FE ?
    bne.s   SAnim_Push  ; if not, branch
    mvabs.w inertia(a0),d2
    lea (SonAni_Roll2).l,a1
    cmpi.w  #$600,d2
    bhs.s   +
    lea (SonAni_Roll).l,a1
+
    neg.w   d2
    addi.w  #$400,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #8,d2
    move.b  d2,anim_frame_duration(a0)
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    bra.w   SAnim_Do2
; ===========================================================================
 
SAnim_Push:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.w   SAnim_Delay         ; if time remains, branch
    move.w  inertia(a0),d2
    bmi.s   +
    neg.w   d2
+
    addi.w  #$800,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #6,d2
    move.b  d2,anim_frame_duration(a0)
    lea (SonAni_Push).l,a1
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    lea (SupSonAni_Push).l,a1
+
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    bra.w   SAnim_Do2
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Animation script - Sonic
; ---------------------------------------------------------------------------
; off_1B618:
SonicAniData:           offsetTable
SonAni_Walk_ptr:        offsetTableEntry.w SonAni_Walk      ;  0 ;   0
SonAni_Run_ptr:         offsetTableEntry.w SonAni_Run       ;  1 ;   1
SonAni_Roll_ptr:        offsetTableEntry.w SonAni_Roll      ;  2 ;   2
SonAni_Roll2_ptr:       offsetTableEntry.w SonAni_Roll2     ;  3 ;   3
SonAni_Push_ptr:        offsetTableEntry.w SonAni_Push      ;  4 ;   4
SonAni_Wait_ptr:        offsetTableEntry.w SonAni_Wait      ;  5 ;   5
SonAni_Balance_ptr:     offsetTableEntry.w SonAni_Balance   ;  6 ;   6
SonAni_LookUp_ptr:      offsetTableEntry.w SonAni_LookUp    ;  7 ;   7
SonAni_Duck_ptr:        offsetTableEntry.w SonAni_Duck      ;  8 ;   8
SonAni_Spindash_ptr:        offsetTableEntry.w SonAni_Spindash  ;  9 ;   9
SonAni_Blink_ptr:       offsetTableEntry.w SonAni_Blink     ; 10 ;  $A
SonAni_GetUp_ptr:       offsetTableEntry.w SonAni_GetUp     ; 11 ;  $B
SonAni_Balance2_ptr:        offsetTableEntry.w SonAni_Balance2  ; 12 ;  $C
SonAni_Stop_ptr:        offsetTableEntry.w SonAni_Stop      ; 13 ;  $D
SonAni_Float_ptr:       offsetTableEntry.w SonAni_Float     ; 14 ;  $E
SonAni_Float2_ptr:      offsetTableEntry.w SonAni_Float2    ; 15 ;  $F
SonAni_Spring_ptr:      offsetTableEntry.w SonAni_Spring    ; 16 ; $10
SonAni_Hang_ptr:        offsetTableEntry.w SonAni_Hang      ; 17 ; $11
SonAni_Dash2_ptr:       offsetTableEntry.w SonAni_Dash2     ; 18 ; $12
SonAni_Dash3_ptr:       offsetTableEntry.w SonAni_Dash3     ; 19 ; $13
SonAni_Hang2_ptr:       offsetTableEntry.w SonAni_Hang2     ; 20 ; $14
SonAni_Bubble_ptr:      offsetTableEntry.w SonAni_Bubble    ; 21 ; $15
SonAni_DeathBW_ptr:     offsetTableEntry.w SonAni_DeathBW   ; 22 ; $16
SonAni_Drown_ptr:       offsetTableEntry.w SonAni_Drown     ; 23 ; $17
SonAni_Death_ptr:       offsetTableEntry.w SonAni_Death     ; 24 ; $18
SonAni_Hurt_ptr:        offsetTableEntry.w SonAni_Hurt      ; 25 ; $19
SonAni_Hurt2_ptr:       offsetTableEntry.w SonAni_Hurt      ; 26 ; $1A
SonAni_Slide_ptr:       offsetTableEntry.w SonAni_Slide     ; 27 ; $1B
SonAni_Blank_ptr:       offsetTableEntry.w SonAni_Blank     ; 28 ; $1C
SonAni_Balance3_ptr:        offsetTableEntry.w SonAni_Balance3  ; 29 ; $1D
SonAni_Balance4_ptr:        offsetTableEntry.w SonAni_Balance4  ; 30 ; $1E
SupSonAni_Transform_ptr:    offsetTableEntry.w SupSonAni_Transform  ; 31 ; $1F
SonAni_Lying_ptr:       offsetTableEntry.w SonAni_Lying     ; 32 ; $20
SonAni_LieDown_ptr:     offsetTableEntry.w SonAni_LieDown   ; 33 ; $21
 
SonAni_Walk:    dc.b $FF, $F,$10,$11,$12,$13,$14, $D, $E,$FF
    rev02even
SonAni_Run: dc.b $FF,$2D,$2E,$2F,$30,$FF,$FF,$FF,$FF,$FF
    rev02even
SonAni_Roll:    dc.b $FE,$3D,$41,$3E,$41,$3F,$41,$40,$41,$FF
    rev02even
SonAni_Roll2:   dc.b $FE,$3D,$41,$3E,$41,$3F,$41,$40,$41,$FF
    rev02even
SonAni_Push:    dc.b $FD,$48,$49,$4A,$4B,$FF,$FF,$FF,$FF,$FF
    rev02even
SonAni_Wait:
    dc.b   5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1
    dc.b   1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2
    dc.b   3,  3,  3,  3,  3,  4,  4,  4,  5,  5,  5,  4,  4,  4,  5,  5
    dc.b   5,  4,  4,  4,  5,  5,  5,  4,  4,  4,  5,  5,  5,  6,  6,  6
    dc.b   6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  5,  5,  5,  4,  4,  4
    dc.b   5,  5,  5,  4,  4,  4,  5,  5,  5,  4,  4,  4,  5,  5,  5,  6
    dc.b   6,  6,  6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  5,  5,  5,  4
    dc.b   4,  4,  5,  5,  5,  4,  4,  4,  5,  5,  5,  4,  4,  4,  5,  5
    dc.b   5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  5,  5
    dc.b   5,  4,  4,  4,  5,  5,  5,  4,  4,  4,  5,  5,  5,  4,  4,  4
    dc.b   5,  5,  5,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  7,  8,  8
    dc.b   8,  9,  9,  9,$FE,  6
    rev02even
SonAni_Balance: dc.b   9,$CC,$CD,$CE,$CD,$FF
    rev02even
SonAni_LookUp:  dc.b   5, $B, $C,$FE,  1
    rev02even
SonAni_Duck:    dc.b   5,$4C,$4D,$FE,  1
    rev02even
SonAni_Spindash:dc.b   0,$42,$43,$42,$44,$42,$45,$42,$46,$42,$47,$FF
    rev02even
SonAni_Blink:   dc.b   1,  2,$FD,  0
    rev02even
SonAni_GetUp:   dc.b   3, $A,$FD,  0
    rev02even
SonAni_Balance2:dc.b   3,$C8,$C9,$CA,$CB,$FF
    rev02even
SonAni_Stop:    dc.b   5,$D2,$D3,$D4,$D5,$FD,  0 ; halt/skidding animation
    rev02even
SonAni_Float:   dc.b   7,$54,$59,$FF
    rev02even
SonAni_Float2:  dc.b   7,$54,$55,$56,$57,$58,$FF
    rev02even
SonAni_Spring:  dc.b $2F,$5B,$FD,  0
    rev02even
SonAni_Hang:    dc.b   1,$50,$51,$FF
    rev02even
SonAni_Dash2:   dc.b  $F,$43,$43,$43,$FE,  1
    rev02even
SonAni_Dash3:   dc.b  $F,$43,$44,$FE,  1
    rev02even
SonAni_Hang2:   dc.b $13,$6B,$6C,$FF
    rev02even
SonAni_Bubble:  dc.b  $B,$5A,$5A,$11,$12,$FD,  0 ; breathe
    rev02even
SonAni_DeathBW: dc.b $20,$5E,$FF
    rev02even
SonAni_Drown:   dc.b $20,$5D,$FF
    rev02even
SonAni_Death:   dc.b $20,$5C,$FF
    rev02even
SonAni_Hurt:    dc.b $40,$4E,$FF
    rev02even
SonAni_Slide:   dc.b   9,$4E,$4F,$FF
    rev02even
SonAni_Blank:   dc.b $77,  0,$FD,  0
    rev02even
SonAni_Balance3:dc.b $13,$D0,$D1,$FF
    rev02even
SonAni_Balance4:dc.b   3,$CF,$C8,$C9,$CA,$CB,$FE,  4
    rev02even
SonAni_Lying:   dc.b   9,  8,  9,$FF
    rev02even
SonAni_LieDown: dc.b   3,  7,$FD,  0
    even
 
; ---------------------------------------------------------------------------
; Animation script - Super Sonic
; (many of these point to the data above this)
; ---------------------------------------------------------------------------
SuperSonicAniData: offsetTable
    offsetTableEntry.w SupSonAni_Walk   ;  0 ;   0
    offsetTableEntry.w SupSonAni_Run    ;  1 ;   1
    offsetTableEntry.w SonAni_Roll      ;  2 ;   2
    offsetTableEntry.w SonAni_Roll2     ;  3 ;   3
    offsetTableEntry.w SupSonAni_Push   ;  4 ;   4
    offsetTableEntry.w SupSonAni_Stand  ;  5 ;   5
    offsetTableEntry.w SupSonAni_Balance    ;  6 ;   6
    offsetTableEntry.w SonAni_LookUp    ;  7 ;   7
    offsetTableEntry.w SupSonAni_Duck   ;  8 ;   8
    offsetTableEntry.w SonAni_Spindash  ;  9 ;   9
    offsetTableEntry.w SonAni_Blink     ; 10 ;  $A
    offsetTableEntry.w SonAni_GetUp     ; 11 ;  $B
    offsetTableEntry.w SonAni_Balance2  ; 12 ;  $C
    offsetTableEntry.w SonAni_Stop      ; 13 ;  $D
    offsetTableEntry.w SonAni_Float     ; 14 ;  $E
    offsetTableEntry.w SonAni_Float2    ; 15 ;  $F
    offsetTableEntry.w SonAni_Spring    ; 16 ; $10
    offsetTableEntry.w SonAni_Hang      ; 17 ; $11
    offsetTableEntry.w SonAni_Dash2     ; 18 ; $12
    offsetTableEntry.w SonAni_Dash3     ; 19 ; $13
    offsetTableEntry.w SonAni_Hang2     ; 20 ; $14
    offsetTableEntry.w SonAni_Bubble    ; 21 ; $15
    offsetTableEntry.w SonAni_DeathBW   ; 22 ; $16
    offsetTableEntry.w SonAni_Drown     ; 23 ; $17
    offsetTableEntry.w SonAni_Death     ; 24 ; $18
    offsetTableEntry.w SonAni_Hurt      ; 25 ; $19
    offsetTableEntry.w SonAni_Hurt      ; 26 ; $1A
    offsetTableEntry.w SonAni_Slide     ; 27 ; $1B
    offsetTableEntry.w SonAni_Blank     ; 28 ; $1C
    offsetTableEntry.w SonAni_Balance3  ; 29 ; $1D
    offsetTableEntry.w SonAni_Balance4  ; 30 ; $1E
    offsetTableEntry.w SupSonAni_Transform  ; 31 ; $1F
 
SupSonAni_Walk:     dc.b $FF,$77,$78,$79,$7A,$7B,$7C,$75,$76,$FF
    rev02even
SupSonAni_Run:      dc.b $FF,$B5,$B9,$FF,$FF,$FF,$FF,$FF,$FF,$FF
    rev02even
SupSonAni_Push:     dc.b $FD,$BD,$BE,$BF,$C0,$FF,$FF,$FF,$FF,$FF
    rev02even
SupSonAni_Stand:    dc.b   7,$72,$73,$74,$73,$FF
    rev02even
SupSonAni_Balance:  dc.b   9,$C2,$C3,$C4,$C3,$C5,$C6,$C7,$C6,$FF
    rev02even
SupSonAni_Duck:     dc.b   5,$C1,$FF
    rev02even
SupSonAni_Transform:    dc.b   2,$6D,$6D,$6E,$6E,$6F,$70,$71,$70,$71,$70,$71,$70,$71,$FD,  0
    even
 
; ---------------------------------------------------------------------------
; Sonic pattern loading subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1B848:
LoadSonicDynPLC:
 
    moveq   #0,d0
    move.b  mapping_frame(a0),d0    ; load frame number
; loc_1B84E:
LoadSonicDynPLC_Part2:
    cmp.b   (Sonic_LastLoadedDPLC).w,d0
    beq.s   return_1B89A
    move.b  d0,(Sonic_LastLoadedDPLC).w
    lea (MapRUnc_Sonic).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_1B89A
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_Sonic),d4
; loc_1B86E:
SPLC_ReadEntry:
    moveq   #0,d1
    move.w  (a2)+,d1
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.l   #5,d1
    addi.l  #ArtUnc_Sonic,d1
    move.w  d4,d2
    add.w   d3,d4
    add.w   d3,d4
    jsr (QueueDMATransfer).l
    dbf d5,SPLC_ReadEntry   ; repeat for number of entries
 
return_1B89A:
    rts
; ===========================================================================
 
JmpTo_KillCharacter 
    jmp (KillCharacter).l
 
    if ~~removeJmpTos
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 02 - Tails
; ----------------------------------------------------------------------------
; Sprite_1B8A4: Object_Tails:
Obj02:
    ; a0=character
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    move.w  (Camera_Min_X_pos).w,(Tails_Min_X_pos).w
    move.w  (Camera_Max_X_pos).w,(Tails_Max_X_pos).w
    move.w  (Camera_Max_Y_pos_now).w,(Tails_Max_Y_pos).w
+
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj02_Index(pc,d0.w),d1
    jmp Obj02_Index(pc,d1.w)
; ===========================================================================
; off_1B8CC: Obj02_States:
Obj02_Index:    offsetTable
        offsetTableEntry.w Obj02_Init       ;  0
        offsetTableEntry.w Obj02_Control    ;  2
        offsetTableEntry.w Obj02_Hurt       ;  4
        offsetTableEntry.w Obj02_Dead       ;  6
        offsetTableEntry.w Obj02_Gone       ;  8
        offsetTableEntry.w Obj02_Respawning ; $A
; ===========================================================================
; loc_1B8D8: Obj02_Main:
Obj02_Init:
    addq.b  #2,routine(a0)  ; => Obj02_Normal
    move.b  #$F,y_radius(a0) ; this sets Tails' collision height (2*pixels) to less than Sonic's height
    move.b  #9,x_radius(a0)
    move.l  #MapUnc_Tails,mappings(a0)
    move.b  #2,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #$84,render_flags(a0) ; render_flags(Tails) = $80 | initial render_flags(Sonic)
    move.w  #$600,(Tails_top_speed).w   ; set Tails' top speed
    move.w  #$C,(Tails_acceleration).w  ; set Tails' acceleration
    move.w  #$80,(Tails_deceleration).w ; set Tails' deceleration
    cmpi.w  #2,(Player_mode).w
    bne.s   Obj02_Init_2Pmode
    tst.b   (Last_star_pole_hit).w
    bne.s   Obj02_Init_Continued
    ; only happens when not starting at a checkpoint:
    move.w  #make_art_tile(ArtTile_ArtUnc_Tails,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #$C,top_solid_bit(a0)
    move.b  #$D,lrb_solid_bit(a0)
    move.w  x_pos(a0),(Saved_x_pos).w
    move.w  y_pos(a0),(Saved_y_pos).w
    move.w  art_tile(a0),(Saved_art_tile).w
    move.w  top_solid_bit(a0),(Saved_Solid_bits).w
    bra.s   Obj02_Init_Continued
; ===========================================================================
; loc_1B952:
Obj02_Init_2Pmode:
    move.w  #make_art_tile(ArtTile_ArtUnc_Tails,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.w  (MainCharacter+top_solid_bit).w,top_solid_bit(a0)
    tst.w   (MainCharacter+art_tile).w
    bpl.s   Obj02_Init_Continued
    ori.w   #high_priority,art_tile(a0)
; loc_1B96E:
Obj02_Init_Continued:
    move.w  x_pos(a0),(Saved_x_pos_2P).w
    move.w  y_pos(a0),(Saved_y_pos_2P).w
    move.w  art_tile(a0),(Saved_art_tile_2P).w
    move.w  top_solid_bit(a0),(Saved_Solid_bits_2P).w
    move.b  #0,flips_remaining(a0)
    move.b  #4,flip_speed(a0)
    move.b  #$1E,air_left(a0)
    move.w  #0,(Tails_CPU_routine).w    ; set AI state to TailsCPU_Init
    move.w  #0,(Tails_control_counter).w
    move.w  #0,(Tails_respawn_counter).w
    move.b  #ObjID_TailsTails,(Tails_Tails+id).w ; load Obj05 (Tails' Tails) at $FFFFD000
    move.w  a0,(Tails_Tails+parent).w ; set its parent object to this
 
; ---------------------------------------------------------------------------
; Normal state for Tails
; ---------------------------------------------------------------------------
; loc_1B9B4:
Obj02_Control:
    cmpa.w  #MainCharacter,a0
    bne.s   Obj02_Control_Joypad2
    move.w  (Ctrl_1_Logical).w,(Ctrl_2_Logical).w
    tst.b   (Control_Locked).w  ; are controls locked?
    bne.s   Obj02_Control_Part2 ; if yes, branch
    move.w  (Ctrl_1).w,(Ctrl_2_Logical).w   ; copy new held buttons, to enable joypad control
    move.w  (Ctrl_1).w,(Ctrl_1_Logical).w
    bra.s   Obj02_Control_Part2
; ---------------------------------------------------------------------------
; loc_1B9D4:
Obj02_Control_Joypad2:
    tst.b   (Control_Locked_P2).w
    bne.s   +
    move.w  (Ctrl_2).w,(Ctrl_2_Logical).w
+
    tst.w   (Two_player_mode).w
    bne.s   Obj02_Control_Part2
    bsr.w   TailsCPU_Control
; loc_1B9EA:
Obj02_Control_Part2:
    btst    #0,obj_control(a0)  ; is Tails flying, or interacting with another object that holds him in place or controls his movement somehow?
    bne.s   +           ; if yes, branch to skip Tails' control
    moveq   #0,d0
    move.b  status(a0),d0
    andi.w  #6,d0   ; %0000 %0110
    move.w  Obj02_Modes(pc,d0.w),d1
    jsr Obj02_Modes(pc,d1.w)    ; run Tails' movement control code
+
    cmpi.w  #-$100,(Camera_Min_Y_pos).w ; is vertical wrapping enabled?
    bne.s   +                               ; if not, branch
    andi.w  #$7FF,y_pos(a0)                 ; perform wrapping of Sonic's y position
+
    bsr.s   Tails_Display
    bsr.w   Tails_RecordPos
    bsr.w   Tails_Water
    move.b  (Primary_Angle).w,next_tilt(a0)
    move.b  (Secondary_Angle).w,tilt(a0)
    tst.b   (WindTunnel_flag).w
    beq.s   +
    tst.b   anim(a0)
    bne.s   +
    move.b  next_anim(a0),anim(a0)
+
    bsr.w   Tails_Animate
    tst.b   obj_control(a0)
    bmi.s   +
    jsr (TouchResponse).l
+
    bra.w   LoadTailsDynPLC
 
; ===========================================================================
; secondary states under state Obj02_Normal
; off_1BA4E:
Obj02_Modes:    offsetTable
        offsetTableEntry.w Obj02_MdNormal   ; 0 - not airborne or rolling
        offsetTableEntry.w Obj02_MdAir      ; 2 - airborne
        offsetTableEntry.w Obj02_MdRoll     ; 4 - rolling
        offsetTableEntry.w Obj02_MdJump     ; 6 - jumping
; ===========================================================================
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1BA56:
Tails_Display:
    move.w  invulnerable_time(a0),d0
    beq.s   Obj02_Display
    subq.w  #1,invulnerable_time(a0)
    lsr.w   #3,d0
    bcc.s   Obj02_ChkInvinc
; loc_1BA64:
Obj02_Display:
    jsr (DisplaySprite).l
; loc_1BA6A:
Obj02_ChkInvinc:    ; Checks if invincibility has expired and disables it if it has.
    btst    #status_sec_isInvincible,status_secondary(a0)
    beq.s   Obj02_ChkShoes
    tst.w   invincibility_time(a0)
    beq.s   Obj02_ChkShoes
    subq.w  #1,invincibility_time(a0)
    bne.s   Obj02_ChkShoes
    tst.b   (Current_Boss_ID).w ; Don't change music if in a boss fight
    bne.s   Obj02_RmvInvin
    cmpi.b  #$C,air_left(a0)    ; Don't change music if drowning
    blo.s   Obj02_RmvInvin
    move.w  (Level_Music).w,d0
    jsr (PlayMusic).l
; loc_1BA96:
Obj02_RmvInvin:
    bclr    #status_sec_isInvincible,status_secondary(a0)
; loc_1BA9C:
Obj02_ChkShoes:     ; Checks if Speed Shoes have expired and disables them if they have.
    btst    #status_sec_hasSpeedShoes,status_secondary(a0)
    beq.s   Obj02_ExitChk
    tst.w   speedshoes_time(a0)
    beq.s   Obj02_ExitChk
    subq.w  #1,speedshoes_time(a0)
    bne.s   Obj02_ExitChk
    move.w  #$600,(Tails_top_speed).w
    move.w  #$C,(Tails_acceleration).w
    move.w  #$80,(Tails_deceleration).w
; Obj02_RmvSpeed:
    bclr    #status_sec_hasSpeedShoes,status_secondary(a0)
    move.w  #MusID_SlowDown,d0  ; Slow down tempo
    jmp (PlayMusic).l
; ===========================================================================
; return_1BAD2:
Obj02_ExitChk:
    rts
; End of subroutine Tails_Display
 
 
; ---------------------------------------------------------------------------
; Tails' AI code for the Sonic and Tails mode 1-player game
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1BAD4:
TailsCPU_Control: ; a0=Tails
    move.b  (Ctrl_2_Held).w,d0  ; did the real player 2 hit something?
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask|button_B_mask|button_C_mask|button_A_mask,d0
    beq.s   +           ; if not, branch
    move.w  #600,(Tails_control_counter).w ; give player 2 control for 10 seconds (minimum)
+
    lea (MainCharacter).w,a1 ; a1=character ; a1=Sonic
    move.w  (Tails_CPU_routine).w,d0
    move.w  TailsCPU_States(pc,d0.w),d0
    jmp TailsCPU_States(pc,d0.w)
; ===========================================================================
; off_1BAF4:
TailsCPU_States: offsetTable
    offsetTableEntry.w TailsCPU_Init    ; 0
    offsetTableEntry.w TailsCPU_Spawning    ; 2
    offsetTableEntry.w TailsCPU_Flying  ; 4
    offsetTableEntry.w TailsCPU_Normal  ; 6
    offsetTableEntry.w TailsCPU_Panic   ; 8
 
; ===========================================================================
; initial AI State
; ---------------------------------------------------------------------------
; loc_1BAFE:
TailsCPU_Init:
    move.w  #6,(Tails_CPU_routine).w    ; => TailsCPU_Normal
    move.b  #0,obj_control(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    move.w  #0,inertia(a0)
    move.b  #0,status(a0)
    move.w  #0,(Tails_respawn_counter).w
    rts
 
; ===========================================================================
; AI State where Tails is waiting to respawn
; ---------------------------------------------------------------------------
; loc_1BB30:
TailsCPU_Spawning:
    move.b  (Ctrl_2_Held_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask|button_start_mask,d0
    bne.s   TailsCPU_Respawn
    move.w  (Timer_frames).w,d0
    andi.w  #$3F,d0
    bne.s   return_1BB88
    tst.b   obj_control(a1)
    bne.s   return_1BB88
    move.b  status(a1),d0
    andi.b  #$D2,d0
    bne.s   return_1BB88
; loc_1BB54:
TailsCPU_Respawn:
    move.w  #4,(Tails_CPU_routine).w    ; => TailsCPU_Flying
    move.w  x_pos(a1),d0
    move.w  d0,x_pos(a0)
    move.w  d0,(Tails_CPU_target_x).w
    move.w  y_pos(a1),d0
    move.w  d0,(Tails_CPU_target_y).w
    subi.w  #$C0,d0
    move.w  d0,y_pos(a0)
    ori.w   #high_priority,art_tile(a0)
    move.b  #0,spindash_flag(a0)
    move.w  #0,spindash_counter(a0)
 
return_1BB88:
    rts
 
; ===========================================================================
; AI State where Tails pretends to be a helicopter
; ---------------------------------------------------------------------------
; loc_1BB8A:
TailsCPU_Flying:
    tst.b   render_flags(a0)
    bmi.s   TailsCPU_FlyingOnscreen
    addq.w  #1,(Tails_respawn_counter).w
    cmpi.w  #$12C,(Tails_respawn_counter).w
    blo.s   TailsCPU_Flying_Part2
    move.w  #0,(Tails_respawn_counter).w
    move.w  #2,(Tails_CPU_routine).w    ; => TailsCPU_Spawning
    move.b  #$81,obj_control(a0)
    move.b  #2,status(a0)
    move.w  #0,x_pos(a0)
    move.w  #0,y_pos(a0)
    move.b  #AniIDTailsAni_Fly,anim(a0)
    rts
; ---------------------------------------------------------------------------
; loc_1BBC8:
TailsCPU_FlyingOnscreen:
    move.w  #0,(Tails_respawn_counter).w
; loc_1BBCE:
TailsCPU_Flying_Part2:
    lea (Sonic_Pos_Record_Buf).w,a2
    move.w  #$10,d2
    lsl.b   #2,d2
    addq.b  #4,d2
    move.w  (Sonic_Pos_Record_Index).w,d3
    sub.b   d2,d3
    move.w  (a2,d3.w),(Tails_CPU_target_x).w
    move.w  2(a2,d3.w),(Tails_CPU_target_y).w
    tst.b   (Water_flag).w
    beq.s   +
    move.w  (Water_Level_1).w,d0
    subi.w  #$10,d0
    cmp.w   (Tails_CPU_target_y).w,d0
    bge.s   +
    move.w  d0,(Tails_CPU_target_y).w
+
    move.w  x_pos(a0),d0
    sub.w   (Tails_CPU_target_x).w,d0
    beq.s   loc_1BC54
    mvabs.w d0,d2
    lsr.w   #4,d2
    cmpi.w  #$C,d2
    blo.s   +
    moveq   #$C,d2
+
    mvabs.b x_vel(a1),d1
    add.b   d1,d2
    addq.w  #1,d2
    tst.w   d0
    bmi.s   loc_1BC40
    bset    #0,status(a0)
    cmp.w   d0,d2
    blo.s   +
    move.w  d0,d2
    moveq   #0,d0
+
    neg.w   d2
    bra.s   loc_1BC50
; ---------------------------------------------------------------------------
 
loc_1BC40:
    bclr    #0,status(a0)
    neg.w   d0
    cmp.w   d0,d2
    blo.s   loc_1BC50
    move.b  d0,d2
    moveq   #0,d0
 
loc_1BC50:
    add.w   d2,x_pos(a0)
 
loc_1BC54:
    moveq   #1,d2
    move.w  y_pos(a0),d1
    sub.w   (Tails_CPU_target_y).w,d1
    beq.s   loc_1BC68
    bmi.s   loc_1BC64
    neg.w   d2
 
loc_1BC64:
    add.w   d2,y_pos(a0)
 
loc_1BC68:
    lea (Sonic_Stat_Record_Buf).w,a2
    move.b  2(a2,d3.w),d2
    andi.b  #$D2,d2
    bne.s   return_1BCDE
    or.w    d0,d1
    bne.s   return_1BCDE
    move.w  #6,(Tails_CPU_routine).w    ; => TailsCPU_Normal
    move.b  #0,obj_control(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    move.w  #0,inertia(a0)
    move.b  #2,status(a0)
    move.w  #0,move_lock(a0)
    andi.w  #drawing_mask,art_tile(a0)
    tst.b   art_tile(a1)
    bpl.s   +
    ori.w   #high_priority,art_tile(a0)
+
    move.b  top_solid_bit(a1),top_solid_bit(a0)
    move.b  lrb_solid_bit(a1),lrb_solid_bit(a0)
    cmpi.b  #AniIDTailsAni_Spindash,anim(a1)
    beq.s   return_1BCDE
    move.b  spindash_flag(a0),d0
    beq.s   return_1BCDE
    move.b  d0,spindash_flag(a1)
    bsr.w   loc_212C4
 
return_1BCDE:
    rts
 
; ===========================================================================
; AI State where Tails follows the player normally
; ---------------------------------------------------------------------------
; loc_1BCE0:
TailsCPU_Normal:
    cmpi.b  #6,(MainCharacter+routine).w    ; is Sonic dead?
    blo.s   TailsCPU_Normal_SonicOK     ; if not, branch
    ; Sonic's dead; fly down to his corpse
    move.w  #4,(Tails_CPU_routine).w    ; => TailsCPU_Flying
    move.b  #0,spindash_flag(a0)
    move.w  #0,spindash_counter(a0)
    move.b  #$81,obj_control(a0)
    move.b  #2,status(a0)
    move.b  #AniIDTailsAni_Fly,anim(a0)
    rts
; ---------------------------------------------------------------------------
; loc_1BD0E:
TailsCPU_Normal_SonicOK:
    bsr.w   TailsCPU_CheckDespawn
    tst.w   (Tails_control_counter).w   ; if CPU has control
    bne.w   TailsCPU_Normal_HumanControl        ; (if not, branch)
    tst.b   obj_control(a0)         ; and Tails isn't fully object controlled (&$80)
    bmi.w   TailsCPU_Normal_HumanControl        ; (if not, branch)
    tst.w   move_lock(a0)           ; and Tails' movement is locked (usually because he just fell down a slope)
    beq.s   +                   ; (if not, branch)
    tst.w   inertia(a0)         ; and Tails is stopped, then...
    bne.s   +                   ; (if not, branch)
    move.w  #8,(Tails_CPU_routine).w    ; => TailsCPU_Panic
+
    lea (Sonic_Pos_Record_Buf).w,a1
    move.w  #$10,d1
    lsl.b   #2,d1
    addq.b  #4,d1
    move.w  (Sonic_Pos_Record_Index).w,d0
    sub.b   d1,d0
    move.w  (a1,d0.w),d2    ; d2 = earlier x position of Sonic
    move.w  2(a1,d0.w),d3   ; d3 = earlier y position of Sonic
    lea (Sonic_Stat_Record_Buf).w,a1
    move.w  (a1,d0.w),d1    ; d1 = earlier input of Sonic
    move.b  2(a1,d0.w),d4   ; d4 = earlier status of Sonic
    move.w  d1,d0
    btst    #5,status(a0)   ; is Tails pushing against something?
    beq.s   +       ; if not, branch
    btst    #5,d4       ; was Sonic pushing against something?
    beq.w   TailsCPU_Normal_FilterAction_Part2 ; if not, branch elsewhere
 
; either Tails isn't pushing, or Tails and Sonic are both pushing
+   sub.w   x_pos(a0),d2
    beq.s   TailsCPU_Normal_Stand ; branch if Tails is already lined up horizontally with Sonic
    bpl.s   TailsCPU_Normal_FollowRight
    neg.w   d2
 
; Tails wants to go left because that's where Sonic is
; loc_1BD76: TailsCPU_Normal_FollowLeft:
    cmpi.w  #$10,d2
    blo.s   +
    andi.w  #~(((button_left_mask|button_right_mask)<<8)|(button_left_mask|button_right_mask)),d1   ; AND out Sonic's left/right input...
    ori.w   #(button_left_mask<<8)|button_left_mask,d1  ; ...and give Tails his own
+
    tst.w   inertia(a0)
    beq.s   TailsCPU_Normal_FilterAction
    btst    #0,status(a0)
    beq.s   TailsCPU_Normal_FilterAction
    subq.w  #1,x_pos(a0)
    bra.s   TailsCPU_Normal_FilterAction
; ===========================================================================
; Tails wants to go right because that's where Sonic is
; loc_1BD98:
TailsCPU_Normal_FollowRight:
    cmpi.w  #$10,d2
    blo.s   +
    andi.w  #~(((button_left_mask|button_right_mask)<<8)|(button_left_mask|button_right_mask)),d1   ; AND out Sonic's left/right input
    ori.w   #(button_right_mask<<8)|button_right_mask,d1    ; ...and give Tails his own
+
    tst.w   inertia(a0)
    beq.s   TailsCPU_Normal_FilterAction
    btst    #0,status(a0)
    bne.s   TailsCPU_Normal_FilterAction
    addq.w  #1,x_pos(a0)
    bra.s   TailsCPU_Normal_FilterAction
; ===========================================================================
; Tails is happy where he is
; loc_1BDBA:
TailsCPU_Normal_Stand:
    bclr    #0,status(a0)
    move.b  d4,d0
    andi.b  #1,d0
    beq.s   TailsCPU_Normal_FilterAction
    bset    #0,status(a0)
 
; Filter the action we chose depending on a few things
; loc_1BDCE:
TailsCPU_Normal_FilterAction:
    tst.b   (Tails_CPU_jumping).w
    beq.s   +
    ori.w   #((button_B_mask|button_C_mask|button_A_mask)<<8),d1
    btst    #1,status(a0)
    bne.s   TailsCPU_Normal_SendAction
    move.b  #0,(Tails_CPU_jumping).w
+
    move.w  (Timer_frames).w,d0
    andi.w  #$FF,d0
    beq.s   +
    cmpi.w  #$40,d2
    bhs.s   TailsCPU_Normal_SendAction
+
    sub.w   y_pos(a0),d3
    beq.s   TailsCPU_Normal_SendAction
    bpl.s   TailsCPU_Normal_SendAction
    neg.w   d3
    cmpi.w  #$20,d3
    blo.s   TailsCPU_Normal_SendAction
; loc_1BE06:
TailsCPU_Normal_FilterAction_Part2:
    move.b  (Timer_frames+1).w,d0
    andi.b  #$3F,d0
    bne.s   TailsCPU_Normal_SendAction
    cmpi.b  #AniIDTailsAni_Duck,anim(a0)
    beq.s   TailsCPU_Normal_SendAction
    ori.w   #((button_B_mask|button_C_mask|button_A_mask)<<8)|(button_B_mask|button_C_mask|button_A_mask),d1
    move.b  #1,(Tails_CPU_jumping).w
 
; Send the action we chose by storing it into player 2's input
; loc_1BE22:
TailsCPU_Normal_SendAction:
    move.w  d1,(Ctrl_2_Logical).w
    rts
 
; ===========================================================================
; Follow orders from controller 2
; and decrease the counter to when the CPU will regain control
; loc_1BE28:
TailsCPU_Normal_HumanControl:
    tst.w   (Tails_control_counter).w
    beq.s   +   ; don't decrease if it's already 0
    subq.w  #1,(Tails_control_counter).w
+
    rts
 
; ===========================================================================
; loc_1BE34:
TailsCPU_Despawn:
    move.w  #0,(Tails_control_counter).w
    move.w  #0,(Tails_respawn_counter).w
    move.w  #2,(Tails_CPU_routine).w    ; => TailsCPU_Spawning
    move.b  #$81,obj_control(a0)
    move.b  #2,status(a0)
    move.w  #$4000,x_pos(a0)
    move.w  #0,y_pos(a0)
    move.b  #AniIDTailsAni_Fly,anim(a0)
    rts
; ===========================================================================
; sub_1BE66:
TailsCPU_CheckDespawn:
    tst.b   render_flags(a0)
    bmi.s   TailsCPU_ResetRespawnTimer
    btst    #3,status(a0)
    beq.s   TailsCPU_TickRespawnTimer
 
    moveq   #0,d0
    move.b  interact(a0),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a3   ; a3=object
    move.b  (Tails_interact_ID).w,d0
    cmp.b   (a3),d0
    bne.s   BranchTo_TailsCPU_Despawn
 
; loc_1BE8C:
TailsCPU_TickRespawnTimer:
    addq.w  #1,(Tails_respawn_counter).w
    cmpi.w  #$12C,(Tails_respawn_counter).w
    blo.s   TailsCPU_UpdateObjInteract
 
BranchTo_TailsCPU_Despawn 
    bra.w   TailsCPU_Despawn
; ===========================================================================
; loc_1BE9C:
TailsCPU_ResetRespawnTimer:
    move.w  #0,(Tails_respawn_counter).w
; loc_1BEA2:
TailsCPU_UpdateObjInteract:
    moveq   #0,d0
    move.b  interact(a0),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a3   ; a3=object
    move.b  (a3),(Tails_interact_ID).w
    rts
 
; ===========================================================================
; AI State where Tails stops, drops, and spindashes in Sonic's direction
; ---------------------------------------------------------------------------
; loc_1BEB8:
TailsCPU_Panic:
    bsr.w   TailsCPU_CheckDespawn
    tst.w   (Tails_control_counter).w
    bne.w   return_1BF36
    tst.w   move_lock(a0)
    bne.s   return_1BF36
    tst.b   spindash_flag(a0)
    bne.s   TailsCPU_Panic_ChargingDash
 
    tst.w   inertia(a0)
    bne.s   return_1BF36
    bclr    #0,status(a0)
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcs.s   +
    bset    #0,status(a0)
+
    move.w  #(button_down_mask<<8)|button_down_mask,(Ctrl_2_Logical).w
    move.b  (Timer_frames+1).w,d0
    andi.b  #$7F,d0
    beq.s   TailsCPU_Panic_ReleaseDash
 
    cmpi.b  #AniIDTailsAni_Duck,anim(a0)
    bne.s   return_1BF36
    move.w  #((button_down_mask|button_B_mask|button_C_mask|button_A_mask)<<8)|(button_down_mask|button_B_mask|button_C_mask|button_A_mask),(Ctrl_2_Logical).w
    rts
; ---------------------------------------------------------------------------
; loc_1BF0C:
TailsCPU_Panic_ChargingDash:
    move.w  #(button_down_mask<<8)|button_down_mask,(Ctrl_2_Logical).w
    move.b  (Timer_frames+1).w,d0
    andi.b  #$7F,d0
    bne.s   TailsCPU_Panic_RevDash
 
; loc_1BF1C:
TailsCPU_Panic_ReleaseDash:
    move.w  #0,(Ctrl_2_Logical).w
    move.w  #6,(Tails_CPU_routine).w    ; => TailsCPU_Normal
    rts
; ---------------------------------------------------------------------------
; loc_1BF2A:
TailsCPU_Panic_RevDash:
    andi.b  #$1F,d0
    bne.s   return_1BF36
    ori.w   #((button_B_mask|button_C_mask|button_A_mask)<<8)|(button_B_mask|button_C_mask|button_A_mask),(Ctrl_2_Logical).w
 
return_1BF36:
    rts
; End of function TailsCPU_Control
 
 
; ---------------------------------------------------------------------------
; Subroutine to record Tails' previous positions for invincibility stars
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1BF38:
Tails_RecordPos:
    move.w  (Tails_Pos_Record_Index).w,d0
    lea (Tails_Pos_Record_Buf).w,a1
    lea (a1,d0.w),a1
    move.w  x_pos(a0),(a1)+
    move.w  y_pos(a0),(a1)+
    addq.b  #4,(Tails_Pos_Record_Index+1).w
 
    rts
; End of subroutine Tails_RecordPos
 
; ---------------------------------------------------------------------------
; Subroutine for Tails when he's underwater
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1BF52:
Tails_Water:
    tst.b   (Water_flag).w  ; does level have water?
    bne.s   Obj02_InWater   ; if yes, branch
 
return_1BF58:
    rts
; ---------------------------------------------------------------------------
; loc_1BF5A:
Obj02_InWater:
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0    ; is Sonic above the water?
    bge.s   Obj02_OutWater  ; if yes, branch
 
    bset    #6,status(a0)   ; set underwater flag
    bne.s   return_1BF58    ; if already underwater, branch
 
    movea.l a0,a1
    bsr.w   ResumeMusic
    move.b  #ObjID_SmallBubbles,(Tails_BreathingBubbles+id).w ; load Obj0A (tail's breathing bubbles) at $FFFFD0C0
    move.b  #$81,(Tails_BreathingBubbles+subtype).w
    move.l  a0,(Tails_BreathingBubbles+$3C).w ; set its parent to be this (obj0A uses $3C instead of $3E for some reason)
    move.w  #$300,(Tails_top_speed).w
    move.w  #6,(Tails_acceleration).w
    move.w  #$40,(Tails_deceleration).w
    asr x_vel(a0)
    asr y_vel(a0)
    asr y_vel(a0)
    beq.s   return_1BF58
    move.w  #$100,(Tails_Dust+anim).w   ; splash animation
    move.w  #SndID_Splash,d0    ; splash sound
    jmp (PlaySound).l
; ---------------------------------------------------------------------------
; loc_1BFB2:
Obj02_OutWater:
    bclr    #6,status(a0)   ; unset underwater flag
    beq.s   return_1BF58    ; if already above water, branch
 
    movea.l a0,a1
    bsr.w   ResumeMusic
    move.w  #$600,(Tails_top_speed).w
    move.w  #$C,(Tails_acceleration).w
    move.w  #$80,(Tails_deceleration).w
 
    cmpi.b  #4,routine(a0)  ; is Tails falling back from getting hurt?
    beq.s   +       ; if yes, branch
    asl y_vel(a0)
+
    tst.w   y_vel(a0)
    beq.w   return_1BF58
    move.w  #$100,(Tails_Dust+anim).w   ; splash animation
    movea.l a0,a1
    bsr.w   ResumeMusic
    cmpi.w  #-$1000,y_vel(a0)
    bgt.s   +
    move.w  #-$1000,y_vel(a0)   ; limit upward y velocity exiting the water
+
    move.w  #SndID_Splash,d0    ; splash sound
    jmp (PlaySound).l
; End of subroutine Tails_Water
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Start of subroutine Obj02_MdNormal
; Called if Tails is neither airborne nor rolling this frame
; ---------------------------------------------------------------------------
; loc_1C00A:
Obj02_MdNormal:
    bsr.w   Tails_CheckSpindash
    bsr.w   Tails_Jump
    bsr.w   Tails_SlopeResist
    bsr.w   Tails_Move
    bsr.w   Tails_Roll
    bsr.w   Tails_LevelBound
    jsr (ObjectMove).l
    bsr.w   AnglePos
    bsr.w   Tails_SlopeRepel
    rts
; End of subroutine Obj02_MdNormal
; ===========================================================================
; Start of subroutine Obj02_MdAir
; Called if Tails is airborne, but not in a ball (thus, probably not jumping)
; loc_1C032: Obj02_MdJump
Obj02_MdAir:
    bsr.w   Tails_JumpHeight
    bsr.w   Tails_ChgJumpDir
    bsr.w   Tails_LevelBound
    jsr (ObjectMoveAndFall).l
    btst    #6,status(a0)   ; is Tails underwater?
    beq.s   +       ; if not, branch
    subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
+
    bsr.w   Tails_JumpAngle
    bsr.w   Tails_DoLevelCollision
    rts
; End of subroutine Obj02_MdAir
; ===========================================================================
; Start of subroutine Obj02_MdRoll
; Called if Tails is in a ball, but not airborne (thus, probably rolling)
; loc_1C05C:
Obj02_MdRoll:
    tst.b   pinball_mode(a0)
    bne.s   +
    bsr.w   Tails_Jump
+
    bsr.w   Tails_RollRepel
    bsr.w   Tails_RollSpeed
    bsr.w   Tails_LevelBound
    jsr (ObjectMove).l
    bsr.w   AnglePos
    bsr.w   Tails_SlopeRepel
    rts
; End of subroutine Obj02_MdRoll
; ===========================================================================
; Start of subroutine Obj02_MdJump
; Called if Tails is in a ball and airborne (he could be jumping but not necessarily)
; Notes: This is identical to Obj02_MdAir, at least at this outer level.
;        Why they gave it a separate copy of the code, I don't know.
; loc_1C082: Obj02_MdJump2:
Obj02_MdJump:
    bsr.w   Tails_JumpHeight
    bsr.w   Tails_ChgJumpDir
    bsr.w   Tails_LevelBound
    jsr (ObjectMoveAndFall).l
    btst    #6,status(a0)   ; is Tails underwater?
    beq.s   +       ; if not, branch
    subi.w  #$28,y_vel(a0)  ; reduce gravity by $28 ($38-$28=$10)
+
    bsr.w   Tails_JumpAngle
    bsr.w   Tails_DoLevelCollision
    rts
; End of subroutine Obj02_MdJump
 
; ---------------------------------------------------------------------------
; Subroutine to make Tails walk/run
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C0AC:
Tails_Move:
    move.w  (Tails_top_speed).w,d6
    move.w  (Tails_acceleration).w,d5
    move.w  (Tails_deceleration).w,d4
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.w   Obj02_Traction
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.w   Obj02_Traction
    endif
    tst.w   move_lock(a0)
    bne.w   Obj02_ResetScr
    btst    #button_left,(Ctrl_2_Held_Logical).w    ; is left being pressed?
    beq.s   Obj02_NotLeft           ; if not, branch
    bsr.w   Tails_MoveLeft
; loc_1C0D4:
Obj02_NotLeft:
    btst    #button_right,(Ctrl_2_Held_Logical).w   ; is right being pressed?
    beq.s   Obj02_NotRight          ; if not, branch
    bsr.w   Tails_MoveRight
; loc_1C0E0:
Obj02_NotRight:
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0     ; is Tails on a slope?
    bne.w   Obj02_ResetScr  ; if yes, branch
    tst.w   inertia(a0) ; is Tails moving?
    bne.w   Obj02_ResetScr  ; if yes, branch
    bclr    #5,status(a0)
    move.b  #AniIDTailsAni_Wait,anim(a0)    ; use "standing" animation
    btst    #3,status(a0)
    beq.s   Tails_Balance
    moveq   #0,d0
    move.b  interact(a0),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    lea (Object_RAM).w,a1 ; a1=character
    lea (a1,d0.w),a1 ; a1=object
    tst.b   status(a1)
    bmi.s   Tails_Lookup
    moveq   #0,d1
    move.b  width_pixels(a1),d1
    move.w  d1,d2
    add.w   d2,d2
    subq.w  #4,d2
    add.w   x_pos(a0),d1
    sub.w   x_pos(a1),d1
    cmpi.w  #4,d1
    blt.s   Tails_BalanceOnObjLeft
    cmp.w   d2,d1
    bge.s   Tails_BalanceOnObjRight
    bra.s   Tails_Lookup
; ---------------------------------------------------------------------------
; balancing checks for Tails
; loc_1C142:
Tails_Balance:
    jsr (ChkFloorEdge).l
    cmpi.w  #$C,d1
    blt.s   Tails_Lookup
    cmpi.b  #3,next_tilt(a0)
    bne.s   Tails_BalanceLeft
; loc_1C156:
Tails_BalanceOnObjRight:
    bclr    #0,status(a0)
    bra.s   Tails_BalanceDone
; ---------------------------------------------------------------------------
; loc_1C15E:
Tails_BalanceLeft:
    cmpi.b  #3,tilt(a0)
    bne.s   Tails_Lookup
; loc_1C166:
Tails_BalanceOnObjLeft:
    bset    #0,status(a0)
; loc_1C16C:
Tails_BalanceDone:
    move.b  #AniIDTailsAni_Balance,anim(a0)
    bra.s   Obj02_ResetScr
; ---------------------------------------------------------------------------
; loc_1C174:
Tails_Lookup:
    btst    #button_up,(Ctrl_2_Held_Logical).w  ; is up being pressed?
    beq.s   Tails_Duck          ; if not, branch
    move.b  #AniIDTailsAni_LookUp,anim(a0)          ; use "looking up" animation
    addq.w  #1,(Tails_Look_delay_counter).w
    cmpi.w  #$78,(Tails_Look_delay_counter).w
    blo.s   Obj02_ResetScr_Part2
    move.w  #$78,(Tails_Look_delay_counter).w
    cmpi.w  #$C8,(Camera_Y_pos_bias_P2).w
    beq.s   Obj02_UpdateSpeedOnGround
    addq.w  #2,(Camera_Y_pos_bias_P2).w
    bra.s   Obj02_UpdateSpeedOnGround
; ---------------------------------------------------------------------------
; loc_1C1A2:
Tails_Duck:
    btst    #button_down,(Ctrl_2_Held_Logical).w    ; is down being pressed?
    beq.s   Obj02_ResetScr          ; if not, branch
    move.b  #AniIDTailsAni_Duck,anim(a0)            ; use "ducking" animation
    addq.w  #1,(Tails_Look_delay_counter).w
    cmpi.w  #$78,(Tails_Look_delay_counter).w
    blo.s   Obj02_ResetScr_Part2
    move.w  #$78,(Tails_Look_delay_counter).w
    cmpi.w  #8,(Camera_Y_pos_bias_P2).w
    beq.s   Obj02_UpdateSpeedOnGround
    subq.w  #2,(Camera_Y_pos_bias_P2).w
    bra.s   Obj02_UpdateSpeedOnGround
 
; ===========================================================================
; moves the screen back to its normal position after looking up or down
; loc_1C1D0:
Obj02_ResetScr:
    move.w  #0,(Tails_Look_delay_counter).w
; loc_1C1D6:
Obj02_ResetScr_Part2:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias_P2).w    ; is screen in its default position?
    beq.s   Obj02_UpdateSpeedOnGround   ; if yes, branch.
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias_P2).w ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias_P2).w ; or subtract 2
 
; ---------------------------------------------------------------------------
; updates Tails' speed on the ground
; ---------------------------------------------------------------------------
; loc_1C1E8:
Obj02_UpdateSpeedOnGround:
    move.b  (Ctrl_2_Held_Logical).w,d0
    andi.b  #button_left_mask|button_right_mask,d0      ; is left/right pressed?
    bne.s   Obj02_Traction  ; if yes, branch
    move.w  inertia(a0),d0
    beq.s   Obj02_Traction
    bmi.s   Obj02_SettleLeft
 
; slow down when facing right and not pressing a direction
; Obj02_SettleRight:
    sub.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
    bra.s   Obj02_Traction
; ---------------------------------------------------------------------------
; slow down when facing left and not pressing a direction
; loc_1C208:
Obj02_SettleLeft:
    add.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
 
; increase or decrease speed on the ground
; loc_1C214:
Obj02_Traction:
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  inertia(a0),d1
    asr.l   #8,d1
    move.w  d1,x_vel(a0)
    muls.w  inertia(a0),d0
    asr.l   #8,d0
    move.w  d0,y_vel(a0)
 
; stops Tails from running through walls that meet the ground
; loc_1C232:
Obj02_CheckWallsOnGround:
    move.b  angle(a0),d0
    addi.b  #$40,d0
    bmi.s   return_1C2A2
    move.b  #$40,d1
    tst.w   inertia(a0)
    beq.s   return_1C2A2
    bmi.s   +
    neg.w   d1
+
    move.b  angle(a0),d0
    add.b   d1,d0
    move.w  d0,-(sp)
    bsr.w   CalcRoomInFront
    move.w  (sp)+,d0
    tst.w   d1
    bpl.s   return_1C2A2
    asl.w   #8,d1
    addi.b  #$20,d0
    andi.b  #$C0,d0
    beq.s   loc_1C29E
    cmpi.b  #$40,d0
    beq.s   loc_1C28C
    cmpi.b  #$80,d0
    beq.s   loc_1C286
    add.w   d1,x_vel(a0)
    bset    #5,status(a0)
    move.w  #0,inertia(a0)
    rts
; ---------------------------------------------------------------------------
 
loc_1C286:
    sub.w   d1,y_vel(a0)
    rts
; ---------------------------------------------------------------------------
 
loc_1C28C:
    sub.w   d1,x_vel(a0)
    bset    #5,status(a0)
    move.w  #0,inertia(a0)
    rts
; ---------------------------------------------------------------------------
loc_1C29E:
    add.w   d1,y_vel(a0)
 
return_1C2A2:
    rts
; End of subroutine Tails_Move
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C2A4:
Tails_MoveLeft:
    move.w  inertia(a0),d0
    beq.s   +
    bpl.s   Tails_TurnLeft  ; if Tails is already moving to the right, branch
+
    bset    #0,status(a0)
    bne.s   +
    bclr    #5,status(a0)
    move.b  #AniIDTailsAni_Run,next_anim(a0)
+
    sub.w   d5,d0   ; add acceleration to the left
    move.w  d6,d1
    neg.w   d1
    cmp.w   d1,d0   ; compare new speed with top speed
    bgt.s   +   ; if new speed is less than the maximum, branch
    add.w   d5,d0   ; remove this frame's acceleration change
    cmp.w   d1,d0   ; compare speed with top speed
    ble.s   +   ; if speed was already greater than the maximum, branch
    move.w  d1,d0   ; limit speed on ground going left
+
    move.w  d0,inertia(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)    ; use walking animation
    rts
; ---------------------------------------------------------------------------
; loc_1C2DE:
Tails_TurnLeft:
    sub.w   d4,d0
    bcc.s   +
    move.w  #-$80,d0
+
    move.w  d0,inertia(a0)
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    bne.s   return_1C328
    cmpi.w  #$400,d0
    blt.s   return_1C328
    move.b  #AniIDTailsAni_Stop,anim(a0)    ; use "stopping" animation
    bclr    #0,status(a0)
    move.w  #SndID_Skidding,d0
    jsr (PlaySound).l
    cmpi.b  #$C,air_left(a0)
    blo.s   return_1C328    ; if he's drowning, branch to not make dust
    move.b  #6,(Tails_Dust+routine).w
    move.b  #$15,(Tails_Dust+mapping_frame).w
 
return_1C328:
    rts
; End of subroutine Tails_MoveLeft
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C32A:
Tails_MoveRight:
    move.w  inertia(a0),d0
    bmi.s   Tails_TurnRight
    bclr    #0,status(a0)
    beq.s   +
    bclr    #5,status(a0)
    move.b  #AniIDTailsAni_Run,next_anim(a0)
+
    add.w   d5,d0   ; add acceleration to the right
    cmp.w   d6,d0   ; compare new speed with top speed
    blt.s   +   ; if new speed is less than the maximum, branch
    sub.w   d5,d0   ; remove this frame's acceleration change
    cmp.w   d6,d0   ; compare speed with top speed
    bge.s   +   ; if speed was already greater than the maximum, branch
    move.w  d6,d0   ; limit speed on ground going right
+
    move.w  d0,inertia(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)    ; use walking animation
    rts
; ---------------------------------------------------------------------------
; loc_1C35E:
Tails_TurnRight:
    add.w   d4,d0
    bcc.s   +
    move.w  #$80,d0
+
    move.w  d0,inertia(a0)
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    bne.s   return_1C3A8
    cmpi.w  #-$400,d0
    bgt.s   return_1C3A8
    move.b  #AniIDTailsAni_Stop,anim(a0)    ; use "stopping" animation
    bset    #0,status(a0)
    move.w  #SndID_Skidding,d0  ; use "stopping" sound
    jsr (PlaySound).l
    cmpi.b  #$C,air_left(a0)
    blo.s   return_1C3A8    ; if he's drowning, branch to not make dust
    move.b  #6,(Tails_Dust+routine).w
    move.b  #$15,(Tails_Dust+mapping_frame).w
 
return_1C3A8:
    rts
; End of subroutine Tails_MoveRight
 
; ---------------------------------------------------------------------------
; Subroutine to change Tails' speed as he rolls
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C3AA:
Tails_RollSpeed:
    move.w  (Tails_top_speed).w,d6
    asl.w   #1,d6
    move.w  (Tails_acceleration).w,d5
    asr.w   #1,d5   ; natural roll deceleration = 1/2 normal acceleration
    move.w  (Tails_deceleration).w,d4
    asr.w   #2,d4   ; controlled roll deceleration...
            ; interestingly, Tails is much worse at this than Sonic when underwater
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.w   Obj02_Roll_ResetScr
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.w   Obj02_Roll_ResetScr
    endif
    tst.w   move_lock(a0)
    bne.s   Tails_ApplyRollSpeed
    btst    #button_left,(Ctrl_2_Held_Logical).w    ; is left being pressed?
    beq.s   +               ; if not, branch
    bsr.w   Tails_RollLeft
+
    btst    #button_right,(Ctrl_2_Held_Logical).w   ; is right being pressed?
    beq.s   Tails_ApplyRollSpeed        ; if not, branch
    bsr.w   Tails_RollRight
 
; loc_1C3E2:
Tails_ApplyRollSpeed:
    move.w  inertia(a0),d0
    beq.s   Tails_CheckRollStop
    bmi.s   Tails_ApplyRollSpeedLeft
 
; Tails_ApplyRollSpeedRight:
    sub.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
    bra.s   Tails_CheckRollStop
; ---------------------------------------------------------------------------
; loc_1C3F8:
Tails_ApplyRollSpeedLeft:
    add.w   d5,d0
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,inertia(a0)
 
; loc_1C404
Tails_CheckRollStop:
    tst.w   inertia(a0)
    bne.s   Obj02_Roll_ResetScr
    tst.b   pinball_mode(a0)  ; note: the spindash flag has a different meaning when Tails is already rolling -- it's used to mean he's not allowed to stop rolling
    bne.s   Tails_KeepRolling
    bclr    #2,status(a0)
    move.b  #$F,y_radius(a0) ; sets standing height to only slightly higher than rolling height, unlike Sonic
    move.b  #9,x_radius(a0)
    move.b  #AniIDTailsAni_Wait,anim(a0)
    subq.w  #1,y_pos(a0)
    bra.s   Obj02_Roll_ResetScr
 
; ---------------------------------------------------------------------------
; magically gives Tails an extra push if he's going to stop rolling where it's not allowed
; (such as in an S-curve in HTZ or a stopper chamber in CNZ)
; loc_1C42E:
Tails_KeepRolling:
    move.w  #$400,inertia(a0)
    btst    #0,status(a0)
    beq.s   Obj02_Roll_ResetScr
    neg.w   inertia(a0)
 
; resets the screen to normal while rolling, like Obj02_ResetScr
; loc_1C440:
Obj02_Roll_ResetScr:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias_P2).w    ; is screen in its default position?
    beq.s   Tails_SetRollSpeed      ; if yes, branch
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias_P2).w ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias_P2).w ; or subtract 2
 
; loc_1C452:
Tails_SetRollSpeed:
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  inertia(a0),d0
    asr.l   #8,d0
    move.w  d0,y_vel(a0)    ; set y velocity based on $14 and angle
    muls.w  inertia(a0),d1
    asr.l   #8,d1
    cmpi.w  #$1000,d1
    ble.s   +
    move.w  #$1000,d1   ; limit Tails' speed rolling right
+
    cmpi.w  #-$1000,d1
    bge.s   +
    move.w  #-$1000,d1  ; limit Tails' speed rolling left
+
    move.w  d1,x_vel(a0)    ; set x velocity based on $14 and angle
    bra.w   Obj02_CheckWallsOnGround
; End of function Tails_RollSpeed
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; loc_1C488:
Tails_RollLeft:
    move.w  inertia(a0),d0
    beq.s   +
    bpl.s   Tails_BrakeRollingRight
+
    bset    #0,status(a0)
    move.b  #AniIDTailsAni_Roll,anim(a0)    ; use "rolling" animation
    rts
; ---------------------------------------------------------------------------
; loc_1C49E:
Tails_BrakeRollingRight:
    sub.w   d4,d0   ; reduce rightward rolling speed
    bcc.s   +
    move.w  #-$80,d0
+
    move.w  d0,inertia(a0)
    rts
; End of function Tails_RollLeft
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
; loc_1C4AC:
Tails_RollRight:
    move.w  inertia(a0),d0
    bmi.s   Tails_BrakeRollingLeft
    bclr    #0,status(a0)
    move.b  #AniIDTailsAni_Roll,anim(a0)    ; use "rolling" animation
    rts
; ---------------------------------------------------------------------------
; loc_1C4C0:
Tails_BrakeRollingLeft:
    add.w   d4,d0       ; reduce leftward rolling speed
    bcc.s   +
    move.w  #$80,d0
+
    move.w  d0,inertia(a0)
    rts
; End of subroutine Tails_RollRight
 
 
; ---------------------------------------------------------------------------
; Subroutine for moving Tails left or right when he's in the air
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C4CE:
Tails_ChgJumpDir:
    move.w  (Tails_top_speed).w,d6
    move.w  (Tails_acceleration).w,d5
    asl.w   #1,d5
    btst    #4,status(a0)       ; did Tails jump from rolling?
    bne.s   Obj02_Jump_ResetScr ; if yes, branch to skip midair control
    move.w  x_vel(a0),d0
    btst    #button_left,(Ctrl_2_Held_Logical).w
    beq.s   +   ; if not holding left, branch
 
    bset    #0,status(a0)
    sub.w   d5,d0   ; add acceleration to the left
    move.w  d6,d1
    neg.w   d1
    cmp.w   d1,d0   ; compare new speed with top speed
    bgt.s   +   ; if new speed is less than the maximum, branch
    move.w  d1,d0   ; limit speed in air going left, even if Tails was already going faster (speed limit/cap)
+
    btst    #button_right,(Ctrl_2_Held_Logical).w
    beq.s   +   ; if not holding right, branch
 
    bclr    #0,status(a0)
    add.w   d5,d0   ; accelerate right in the air
    cmp.w   d6,d0   ; compare new speed with top speed
    blt.s   +   ; if new speed is less than the maximum, branch
    move.w  d6,d0   ; limit speed in air going right, even if Tails was already going faster (speed limit/cap)
; Obj02_JumpMove:
+   move.w  d0,x_vel(a0)
 
; loc_1C518: Obj02_ResetScr2:
Obj02_Jump_ResetScr:
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias_P2).w    ; is screen in its default position?
    beq.s   Tails_JumpPeakDecelerate            ; if yes, branch
    bhs.s   +               ; depending on the sign of the difference,
    addq.w  #4,(Camera_Y_pos_bias_P2).w ; either add 2
+   subq.w  #2,(Camera_Y_pos_bias_P2).w ; or subtract 2
 
; loc_1C52A:
Tails_JumpPeakDecelerate:
    cmpi.w  #-$400,y_vel(a0)    ; is Tails moving faster than -$400 upwards?
    blo.s   return_1C558        ; if yes, return
    move.w  x_vel(a0),d0
    move.w  d0,d1
    asr.w   #5,d1       ; d1 = x_velocity / 32
    beq.s   return_1C558    ; return if d1 is 0
    bmi.s   Tails_JumpPeakDecelerateLeft
 
; Tails_JumpPeakDecelerateRight:
    sub.w   d1,d0   ; reduce x velocity by d1
    bcc.s   +
    move.w  #0,d0
+
    move.w  d0,x_vel(a0)
    rts
; ---------------------------------------------------------------------------
; loc_1C54C:
Tails_JumpPeakDecelerateLeft:
    sub.w   d1,d0   ; reduce x velocity by d1
    bcs.s   +
    move.w  #0,d0
+
    move.w  d0,x_vel(a0)
 
return_1C558:
    rts
; End of subroutine Tails_ChgJumpDir
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to prevent Tails from leaving the boundaries of a level
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C55A:
Tails_LevelBound:
    move.l  x_pos(a0),d1
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d1
    swap    d1
    move.w  (Tails_Min_X_pos).w,d0
    addi.w  #$10,d0
    cmp.w   d1,d0           ; has Tails touched the left boundary?
    bhi.s   Tails_Boundary_Sides    ; if yes, branch
    move.w  (Tails_Max_X_pos).w,d0
    addi.w  #$128,d0
    tst.b   (Current_Boss_ID).w
    bne.s   +
    addi.w  #$40,d0
+
    cmp.w   d1,d0           ; has Tails touched the right boundary?
    bls.s   Tails_Boundary_Sides    ; if yes, branch
 
; loc_1C58C:
Tails_Boundary_CheckBottom:
    move.w  (Tails_Max_Y_pos).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0        ; has Tails touched the bottom boundary?
    blt.s   Tails_Boundary_Bottom   ; if yes, branch
    rts
; ---------------------------------------------------------------------------
Tails_Boundary_Bottom: ;;
    jmpto   (KillCharacter).l, JmpTo2_KillCharacter
; ===========================================================================
 
; loc_1C5A0:
Tails_Boundary_Sides:
    move.w  d0,x_pos(a0)
    move.w  #0,2+x_pos(a0) ; subpixel x
    move.w  #0,x_vel(a0)
    move.w  #0,inertia(a0)
    bra.s   Tails_Boundary_CheckBottom
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine allowing Tails to start rolling when he's moving
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C5B8:
Tails_Roll:
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bmi.s   Obj02_NoRoll
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    bne.w   Obj02_NoRoll
    endif
    mvabs.w inertia(a0),d0
    cmpi.w  #$80,d0     ; is Tails moving at $80 speed or faster?
    blo.s   Obj02_NoRoll    ; if not, branch
    move.b  (Ctrl_2_Held_Logical).w,d0
    andi.b  #button_left_mask|button_right_mask,d0      ; is left/right being pressed?
    bne.s   Obj02_NoRoll    ; if yes, branch
    btst    #button_down,(Ctrl_2_Held_Logical).w    ; is down being pressed?
    bne.s   Obj02_ChkRoll           ; if yes, branch
; return_1C5DE:
Obj02_NoRoll:
    rts
 
; ---------------------------------------------------------------------------
; loc_1C5E0:
Obj02_ChkRoll:
    btst    #2,status(a0)   ; is Tails already rolling?
    beq.s   Obj02_DoRoll    ; if not, branch
    rts
 
; ---------------------------------------------------------------------------
; loc_1C5EA:
Obj02_DoRoll:
    bset    #2,status(a0)
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDTailsAni_Roll,anim(a0)    ; use "rolling" animation
    addq.w  #1,y_pos(a0)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l   ; play rolling sound
    tst.w   inertia(a0)
    bne.s   return_1C61C
    move.w  #$200,inertia(a0)
 
return_1C61C:
    rts
; End of function Tails_Roll
 
 
; ---------------------------------------------------------------------------
; Subroutine allowing Tails to jump
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C61E:
Tails_Jump:
    move.b  (Ctrl_2_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is A, B or C pressed?
    beq.w   return_1C6C2    ; if not, return
    moveq   #0,d0
    move.b  angle(a0),d0
    addi.b  #$80,d0
    bsr.w   CalcRoomOverHead
    cmpi.w  #6,d1       ; does Tails have enough room to jump?
    blt.w   return_1C6C2    ; if not, branch
    move.w  #$680,d2
    btst    #6,status(a0)   ; Test if underwater
    beq.s   +
    move.w  #$380,d2    ; set lower jump speed if underwater
+
    moveq   #0,d0
    move.b  angle(a0),d0
    subi.b  #$40,d0
    jsr (CalcSine).l
    muls.w  d2,d1
    asr.l   #8,d1
    add.w   d1,x_vel(a0)    ; make Tails jump (in X... this adds nothing on level ground)
    muls.w  d2,d0
    asr.l   #8,d0
    add.w   d0,y_vel(a0)    ; make Tails jump (in Y)
    bset    #1,status(a0)
    bclr    #5,status(a0)
    addq.l  #4,sp
    move.b  #1,jumping(a0)
    clr.b   stick_to_convex(a0)
    move.w  #SndID_Jump,d0
    jsr (PlaySound).l   ; play jumping sound
    move.b  #$F,y_radius(a0)
    move.b  #9,x_radius(a0)
    btst    #2,status(a0)
    bne.s   Tails_RollJump
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDTailsAni_Roll,anim(a0)    ; use "jumping" animation
    bset    #2,status(a0)
    addq.w  #1,y_pos(a0)
 
return_1C6C2:
    rts
; ---------------------------------------------------------------------------
; loc_1C6C4:
Tails_RollJump:
    bset    #4,status(a0) ; set the rolling+jumping flag
    rts
; End of function Tails_Jump
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; ===========================================================================
; loc_1C6CC:
Tails_JumpHeight:
    tst.b   jumping(a0) ; is Tails jumping?
    beq.s   Tails_UpVelCap  ; if not, branch
 
    move.w  #-$400,d1
    btst    #6,status(a0)   ; is Tails underwater?
    beq.s   +       ; if not, branch
    move.w  #-$200,d1
+
    cmp.w   y_vel(a0),d1    ; is Tails going up faster than d1?
    ble.s   +       ; if not, branch
    move.b  (Ctrl_2_Held_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0 ; is a jump button pressed?
    bne.s   +       ; if yes, branch
    move.w  d1,y_vel(a0)    ; immediately reduce Tails's upward speed to d1
+
    rts
; ---------------------------------------------------------------------------
; loc_1C6F8:
Tails_UpVelCap:
    tst.b   pinball_mode(a0)    ; is Tails charging a spindash or in a rolling-only area?
    bne.s   return_1C70C        ; if yes, return
    cmpi.w  #-$FC0,y_vel(a0)    ; is Tails moving up really fast?
    bge.s   return_1C70C        ; if not, return
    move.w  #-$FC0,y_vel(a0)    ; cap upward speed
 
return_1C70C:
    rts
; End of subroutine Tails_JumpHeight
 
; ---------------------------------------------------------------------------
; Subroutine to check for starting to charge a spindash
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C70E:
Tails_CheckSpindash:
    tst.b   spindash_flag(a0)
    bne.s   Tails_UpdateSpindash
    cmpi.b  #AniIDTailsAni_Duck,anim(a0)
    bne.s   return_1C75C
    move.b  (Ctrl_2_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   return_1C75C
    move.b  #AniIDTailsAni_Spindash,anim(a0)
    move.w  #SndID_SpindashRev,d0
    jsr (PlaySound).l
    addq.l  #4,sp
    move.b  #1,spindash_flag(a0)
    move.w  #0,spindash_counter(a0)
    cmpi.b  #$C,air_left(a0)    ; if he's drowning, branch to not make dust
    blo.s   loc_1C754
    move.b  #2,(Tails_Dust+anim).w
 
loc_1C754:
    bsr.w   Tails_LevelBound
    bsr.w   AnglePos
 
return_1C75C:
    rts
; End of subroutine Tails_CheckSpindash
 
 
; ---------------------------------------------------------------------------
; Subrouting to update an already-charging spindash
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C75E:
Tails_UpdateSpindash:
    move.b  (Ctrl_2_Held_Logical).w,d0
    btst    #button_down,d0
    bne.s   Tails_ChargingSpindash
 
    ; unleash the charged spindash and start rolling quickly:
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.b  #AniIDTailsAni_Roll,anim(a0)
    addq.w  #1,y_pos(a0)    ; add the difference between Tails' rolling and standing heights
    move.b  #0,spindash_flag(a0)
    moveq   #0,d0
    move.b  spindash_counter(a0),d0
    add.w   d0,d0
    move.w  Tails_SpindashSpeeds(pc,d0.w),inertia(a0)
    move.w  inertia(a0),d0
    subi.w  #$800,d0
    add.w   d0,d0
    andi.w  #$1F00,d0
    neg.w   d0
    addi.w  #$2000,d0
    move.w  d0,(Horiz_scroll_delay_val_P2).w
    btst    #0,status(a0)
    beq.s   +
    neg.w   inertia(a0)
+
    bset    #2,status(a0)
    move.b  #0,(Tails_Dust+anim).w
    move.w  #SndID_SpindashRelease,d0   ; spindash zoom sound
    jsr (PlaySound).l
    bra.s   loc_1C828
; ===========================================================================
; word_1C7CE:
Tails_SpindashSpeeds:
    dc.w  $800  ; 0
    dc.w  $880  ; 1
    dc.w  $900  ; 2
    dc.w  $980  ; 3
    dc.w  $A00  ; 4
    dc.w  $A80  ; 5
    dc.w  $B00  ; 6
    dc.w  $B80  ; 7
    dc.w  $C00  ; 8
; ===========================================================================
; loc_1C7E0:
Tails_ChargingSpindash:         ; If still charging the dash...
    tst.w   spindash_counter(a0)
    beq.s   loc_1C7F8
    move.w  spindash_counter(a0),d0
    lsr.w   #5,d0
    sub.w   d0,spindash_counter(a0)
    bcc.s   loc_1C7F8
    move.w  #0,spindash_counter(a0)
 
loc_1C7F8:
    move.b  (Ctrl_2_Press_Logical).w,d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   loc_1C828
    move.w  #(AniIDTailsAni_Spindash<<8),anim(a0)
    move.w  #SndID_SpindashRev,d0
    jsr (PlaySound).l
    addi.w  #$200,spindash_counter(a0)
    cmpi.w  #$800,spindash_counter(a0)
    blo.s   loc_1C828
    move.w  #$800,spindash_counter(a0)
 
loc_1C828:
    addq.l  #4,sp
    cmpi.w  #(224/2)-16,(Camera_Y_pos_bias_P2).w
    beq.s   loc_1C83C
    bhs.s   +
    addq.w  #4,(Camera_Y_pos_bias_P2).w
+   subq.w  #2,(Camera_Y_pos_bias_P2).w
 
loc_1C83C:
    bsr.w   Tails_LevelBound
    bsr.w   AnglePos
    rts
; End of subroutine Tails_UpdateSpindash
 
 
; ---------------------------------------------------------------------------
; Subroutine to slow Tails walking up a slope
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C846:
Tails_SlopeResist:
    move.b  angle(a0),d0
    addi.b  #$60,d0
    cmpi.b  #$C0,d0
    bhs.s   return_1C87A
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  #$20,d0
    asr.l   #8,d0
    tst.w   inertia(a0)
    beq.s   return_1C87A
    bmi.s   loc_1C876
    tst.w   d0
    beq.s   +
    add.w   d0,inertia(a0)  ; change Tails' $14
+
    rts
; ---------------------------------------------------------------------------
 
loc_1C876:
    add.w   d0,inertia(a0)
 
return_1C87A:
    rts
; End of subroutine Tails_SlopeResist
 
; ---------------------------------------------------------------------------
; Subroutine to push Tails down a slope while he's rolling
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C87C:
Tails_RollRepel:
    move.b  angle(a0),d0
    addi.b  #$60,d0
    cmpi.b  #-$40,d0
    bhs.s   return_1C8B6
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  #$50,d0
    asr.l   #8,d0
    tst.w   inertia(a0)
    bmi.s   loc_1C8AC
    tst.w   d0
    bpl.s   loc_1C8A6
    asr.l   #2,d0
 
loc_1C8A6:
    add.w   d0,inertia(a0)
    rts
; ===========================================================================
 
loc_1C8AC:
    tst.w   d0
    bmi.s   loc_1C8B2
    asr.l   #2,d0
 
loc_1C8B2:
    add.w   d0,inertia(a0)
 
return_1C8B6:
    rts
; End of function Tails_RollRepel
 
; ---------------------------------------------------------------------------
; Subroutine to push Tails down a slope
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C8B8:
Tails_SlopeRepel:
    nop
    tst.b   stick_to_convex(a0)
    bne.s   return_1C8F2
    tst.w   move_lock(a0)
    bne.s   loc_1C8F4
    move.b  angle(a0),d0
    addi.b  #$20,d0
    andi.b  #$C0,d0
    beq.s   return_1C8F2
    mvabs.w inertia(a0),d0
    cmpi.w  #$280,d0
    bhs.s   return_1C8F2
    clr.w   inertia(a0)
    bset    #1,status(a0)
    move.w  #$1E,move_lock(a0)
 
return_1C8F2:
    rts
; ===========================================================================
 
loc_1C8F4:
    subq.w  #1,move_lock(a0)
    rts
; End of function Tails_SlopeRepel
 
; ---------------------------------------------------------------------------
; Subroutine to return Tails' angle to 0 as he jumps
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C8FA:
Tails_JumpAngle:
    move.b  angle(a0),d0    ; get Tails' angle
    beq.s   Tails_JumpFlip  ; if already 0, branch
    bpl.s   loc_1C90A   ; if higher than 0, branch
 
    addq.b  #2,d0       ; increase angle
    bcc.s   BranchTo_Tails_JumpAngleSet
    moveq   #0,d0
 
BranchTo_Tails_JumpAngleSet 
    bra.s   Tails_JumpAngleSet
; ===========================================================================
 
loc_1C90A:
    subq.b  #2,d0       ; decrease angle
    bcc.s   Tails_JumpAngleSet
    moveq   #0,d0
 
; loc_1C910:
Tails_JumpAngleSet:
    move.b  d0,angle(a0)
; End of function Tails_JumpAngle
    ; continue straight to Tails_JumpFlip
 
; ---------------------------------------------------------------------------
; Updates Tails' secondary angle if he's tumbling
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C914:
Tails_JumpFlip:
    move.b  flip_angle(a0),d0
    beq.s   return_1C958
    tst.w   inertia(a0)
    bmi.s   Tails_JumpLeftFlip
; loc_1C920:
Tails_JumpRightFlip:
    move.b  flip_speed(a0),d1
    add.b   d1,d0
    bcc.s   BranchTo_Tails_JumpFlipSet
    subq.b  #1,flips_remaining(a0)
    bcc.s   BranchTo_Tails_JumpFlipSet
    move.b  #0,flips_remaining(a0)
    moveq   #0,d0
 
BranchTo_Tails_JumpFlipSet 
    bra.s   Tails_JumpFlipSet
; ===========================================================================
; loc_1C938:
Tails_JumpLeftFlip:
    tst.b   flip_turned(a0)
    bne.s   Tails_JumpRightFlip
    move.b  flip_speed(a0),d1
    sub.b   d1,d0
    bcc.s   Tails_JumpFlipSet
    subq.b  #1,flips_remaining(a0)
    bcc.s   Tails_JumpFlipSet
    move.b  #0,flips_remaining(a0)
    moveq   #0,d0
; loc_1C954:
Tails_JumpFlipSet:
    move.b  d0,flip_angle(a0)
 
return_1C958:
    rts
; End of function Tails_JumpFlip
 
; ---------------------------------------------------------------------------
; Subroutine for Tails to interact with the floor and walls when he's in the air
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1C95A: Tails_Floor:
Tails_DoLevelCollision:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  lrb_solid_bit(a0),d5
    move.w  x_vel(a0),d1
    move.w  y_vel(a0),d2
    jsr (CalcAngle).l
    subi.b  #$20,d0
    andi.b  #$C0,d0
    cmpi.b  #$40,d0
    beq.w   Tails_HitLeftWall
    cmpi.b  #$80,d0
    beq.w   Tails_HitCeilingAndWalls
    cmpi.b  #$C0,d0
    beq.w   Tails_HitRightWall
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   +
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
+
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   +
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
+
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1CA3A
    move.b  y_vel(a0),d2
    addq.b  #8,d2
    neg.b   d2
    cmp.b   d2,d1
    bge.s   +
    cmp.b   d2,d0
    blt.s   return_1CA3A
+
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Tails_ResetOnFloor
    move.b  d3,d0
    addi.b  #$20,d0
    andi.b  #$40,d0
    bne.s   loc_1CA18
    move.b  d3,d0
    addi.b  #$10,d0
    andi.b  #$20,d0
    beq.s   loc_1CA0A
    asr y_vel(a0)
    bra.s   loc_1CA2C
; ===========================================================================
 
loc_1CA0A:
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
    rts
; ===========================================================================
 
loc_1CA18:
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
    cmpi.w  #$FC0,y_vel(a0)
    ble.s   loc_1CA2C
    move.w  #$FC0,y_vel(a0)
 
loc_1CA2C:
    move.w  y_vel(a0),inertia(a0)
    tst.b   d3
    bpl.s   return_1CA3A
    neg.w   inertia(a0)
 
return_1CA3A:
    rts
; ===========================================================================
; loc_1CA3C:
Tails_HitLeftWall:
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   Tails_HitCeiling ; branch if distance is positive (not inside wall)
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
    move.w  y_vel(a0),inertia(a0)
    rts
; ===========================================================================
; loc_1CA56:
Tails_HitCeiling:
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   Tails_HitFloor  ; branch if distance is positive (not inside ceiling)
    sub.w   d1,y_pos(a0)
    tst.w   y_vel(a0)
    bpl.s   return_1CA6E
    move.w  #0,y_vel(a0)    ; stop Tails in y since he hit a ceiling
 
return_1CA6E:
    rts
; ===========================================================================
; loc_1CA70:
Tails_HitFloor:
    tst.w   y_vel(a0)
    bmi.s   return_1CA96
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1CA96
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Tails_ResetOnFloor
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
 
return_1CA96:
    rts
; ===========================================================================
; loc_1CA98:
Tails_HitCeilingAndWalls:
    bsr.w   CheckLeftWallDist
    tst.w   d1
    bpl.s   +
    sub.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
+
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   +
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
+
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   return_1CAF2
    sub.w   d1,y_pos(a0)
    move.b  d3,d0
    addi.b  #$20,d0
    andi.b  #$40,d0
    bne.s   loc_1CADC
    move.w  #0,y_vel(a0)    ; stop Tails in y since he hit a ceiling
    rts
; ===========================================================================
 
loc_1CADC:
    move.b  d3,angle(a0)
    bsr.w   Tails_ResetOnFloor
    move.w  y_vel(a0),inertia(a0)
    tst.b   d3
    bpl.s   return_1CAF2
    neg.w   inertia(a0)
 
return_1CAF2:
    rts
; ===========================================================================
; loc_1CAF4:
Tails_HitRightWall:
    bsr.w   CheckRightWallDist
    tst.w   d1
    bpl.s   Tails_HitCeiling2
    add.w   d1,x_pos(a0)
    move.w  #0,x_vel(a0)    ; stop Tails since he hit a wall
    move.w  y_vel(a0),inertia(a0)
    rts
; ===========================================================================
; identical to Tails_HitCeiling...
; loc_1CB0E:
Tails_HitCeiling2:
    bsr.w   Sonic_CheckCeiling
    tst.w   d1
    bpl.s   Tails_HitFloor2
    sub.w   d1,y_pos(a0)
    tst.w   y_vel(a0)
    bpl.s   return_1CB26
    move.w  #0,y_vel(a0)    ; stop Tails in y since he hit a ceiling
 
return_1CB26:
    rts
; ===========================================================================
; identical to Tails_HitFloor...
; loc_1CB28:
Tails_HitFloor2:
    tst.w   y_vel(a0)
    bmi.s   return_1CB4E
    bsr.w   Sonic_CheckFloor
    tst.w   d1
    bpl.s   return_1CB4E
    add.w   d1,y_pos(a0)
    move.b  d3,angle(a0)
    bsr.w   Tails_ResetOnFloor
    move.w  #0,y_vel(a0)
    move.w  x_vel(a0),inertia(a0)
 
return_1CB4E:
    rts
; End of function Tails_DoLevelCollision
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to reset Tails' mode when he lands on the floor
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1CB50:
Tails_ResetOnFloor:
    tst.b   pinball_mode(a0)
    bne.s   Tails_ResetOnFloor_Part3
    move.b  #AniIDTailsAni_Walk,anim(a0)
; loc_1CB5C:
Tails_ResetOnFloor_Part2:
    btst    #2,status(a0)
    beq.s   Tails_ResetOnFloor_Part3
    bclr    #2,status(a0)
    move.b  #$F,y_radius(a0) ; this slightly increases Tails' collision height to standing
    move.b  #9,x_radius(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)    ; use running/walking/standing animation
    subq.w  #1,y_pos(a0)    ; move Tails up 1 pixel so the increased height doesn't push him slightly into the ground
; loc_1CB80:
Tails_ResetOnFloor_Part3:
    bclr    #1,status(a0)
    bclr    #5,status(a0)
    bclr    #4,status(a0)
    move.b  #0,jumping(a0)
    move.w  #0,(Chain_Bonus_counter).w
    move.b  #0,flip_angle(a0)
    move.b  #0,flip_turned(a0)
    move.b  #0,flips_remaining(a0)
    move.w  #0,(Tails_Look_delay_counter).w
    cmpi.b  #AniIDTailsAni_Hang2,anim(a0)
    bne.s   return_1CBC4
    move.b  #AniIDTailsAni_Walk,anim(a0)
 
return_1CBC4:
    rts
; End of subroutine Tails_ResetOnFloor
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Tails when he gets hurt
; ---------------------------------------------------------------------------
; loc_1CBC6:
Obj02_Hurt:
    jsr (ObjectMove).l
    addi.w  #$30,y_vel(a0)
    btst    #6,status(a0)
    beq.s   +
    subi.w  #$20,y_vel(a0)
+
    cmpi.w  #-$100,(Camera_Min_Y_pos).w
    bne.s   +
    andi.w  #$7FF,y_pos(a0)
+
    bsr.w   Tails_HurtStop
    bsr.w   Tails_LevelBound
    bsr.w   Tails_RecordPos
    bsr.w   Tails_Animate
    bsr.w   LoadTailsDynPLC
    jmp (DisplaySprite).l
; ===========================================================================
; loc_1CC08:
Tails_HurtStop:
    move.w  (Tails_Max_Y_pos).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    blt.w   JmpTo2_KillCharacter
    bsr.w   Tails_DoLevelCollision
    btst    #1,status(a0)
    bne.s   return_1CC4E
    moveq   #0,d0
    move.w  d0,y_vel(a0)
    move.w  d0,x_vel(a0)
    move.w  d0,inertia(a0)
    move.b  d0,obj_control(a0)
    move.b  #AniIDTailsAni_Walk,anim(a0)
    move.b  #2,routine(a0)  ; => Obj02_Control
    move.w  #$78,invulnerable_time(a0)
    move.b  #0,spindash_flag(a0)
 
return_1CC4E:
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Tails when he dies
; .
; ---------------------------------------------------------------------------
 
; loc_1CC50:
Obj02_Dead:
    bsr.w   Obj02_CheckGameOver
    jsr (ObjectMoveAndFall).l
    bsr.w   Tails_RecordPos
    bsr.w   Tails_Animate
    bsr.w   LoadTailsDynPLC
    jmp (DisplaySprite).l
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1CC6C:
Obj02_CheckGameOver:
    cmpi.w  #2,(Player_mode).w  ; is it a Tails Alone game?
    beq.w   CheckGameOver       ; if yes, branch... goodness, code reuse
    move.b  #1,(Scroll_lock_P2).w
    move.b  #0,spindash_flag(a0)
    move.w  (Tails_Max_Y_pos).w,d0
    addi.w  #$100,d0
    cmp.w   y_pos(a0),d0
    bge.w   return_1CD8E
    move.b  #2,routine(a0)
    tst.w   (Two_player_mode).w
    bne.s   Obj02_CheckGameOver_2Pmode
    bra.w   TailsCPU_Despawn
; ---------------------------------------------------------------------------
; loc_1CCA2:
Obj02_CheckGameOver_2Pmode:
    addq.b  #1,(Update_HUD_lives_2P).w
    subq.b  #1,(Life_count_2P).w
    bne.s   Obj02_ResetLevel
    move.w  #0,restart_countdown(a0)
    move.b  #ObjID_GameOver,(GameOver_GameText+id).w ; load Obj39
    move.b  #ObjID_GameOver,(GameOver_OverText+id).w ; load Obj39
    move.b  #1,(GameOver_OverText+mapping_frame).w
    move.w  a0,(GameOver_GameText+parent).w
    clr.b   (Time_Over_flag_2P).w
; loc_1CCCC:
Obj02_Finished:
    clr.b   (Update_HUD_timer).w
    clr.b   (Update_HUD_timer_2P).w
    move.b  #8,routine(a0)
    move.w  #MusID_GameOver,d0
    jsr (PlayMusic).l
    moveq   #PLCID_GameOver,d0
    jmp (LoadPLC).l
; End of function Obj02_CheckGameOver
 
; ===========================================================================
; ---------------------------------------------------------------------------
; Tails when the level is restarted
; ---------------------------------------------------------------------------
; loc_1CCEC:
Obj02_ResetLevel:
    tst.b   (Time_Over_flag).w
 
    if gameRevision=0
    bne.s   Obj02_ResetLevel_Part3
    else
    beq.s   Obj02_ResetLevel_Part2
    tst.b   (Time_Over_flag_2P).w
    beq.s   Obj02_ResetLevel_Part3
    move.w  #0,restart_countdown(a0)
    clr.b   (Update_HUD_timer).w
    clr.b   (Update_HUD_timer_2P).w
    move.b  #8,routine(a0)
    rts
    endif
 
; ---------------------------------------------------------------------------
Obj02_ResetLevel_Part2:
    tst.b   (Time_Over_flag_2P).w
    beq.s   Obj02_ResetLevel_Part3
    move.w  #0,restart_countdown(a0)
    move.b  #ObjID_TimeOver,(TimeOver_TimeText+id).w ; load Obj39
    move.b  #ObjID_TimeOver,(TimeOver_OverText+id).w ; load Obj39
    move.b  #2,(TimeOver_TimeText+mapping_frame).w
    move.b  #3,(TimeOver_OverText+mapping_frame).w
    move.w  a0,(TimeOver_TimeText+parent).w
    bra.s   Obj02_Finished
; ---------------------------------------------------------------------------
Obj02_ResetLevel_Part3:
    move.b  #0,(Scroll_lock_P2).w
    move.b  #$A,routine(a0) ; => Obj02_Respawning
    move.w  (Saved_x_pos_2P).w,x_pos(a0)
    move.w  (Saved_y_pos_2P).w,y_pos(a0)
    move.w  (Saved_art_tile_2P).w,art_tile(a0)
    move.w  (Saved_Solid_bits_2P).w,top_solid_bit(a0)
    clr.w   (Ring_count_2P).w
    clr.b   (Extra_life_flags_2P).w
    move.b  #0,obj_control(a0)
    move.b  #5,anim(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    move.w  #0,inertia(a0)
    move.b  #2,status(a0)
    move.w  #0,move_lock(a0)
 
return_1CD8E:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Tails when he's offscreen and waiting for the level to restart
; ---------------------------------------------------------------------------
; loc_1CD90:
Obj02_Gone:
    tst.w   restart_countdown(a0)
    beq.s   +
    subq.w  #1,restart_countdown(a0)
    bne.s   +
    move.w  #1,(Level_Inactive_flag).w
+
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Tails when he's waiting for the camera to scroll back to where he respawned
; ---------------------------------------------------------------------------
; loc_1CDA4:
Obj02_Respawning:
    tst.w   (Camera_X_pos_diff_P2).w
    bne.s   +
    tst.w   (Camera_Y_pos_diff_P2).w
    bne.s   +
    move.b  #2,routine(a0)
+
    bsr.w   Tails_Animate
    bsr.w   LoadTailsDynPLC
    jmp (DisplaySprite).l
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to animate Tails' sprites
; See also: AnimateSprite and Sonic_Animate
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1CDC4:
Tails_Animate:
    lea (TailsAniData).l,a1
; loc_1CDCA:
Tails_Animate_Part2:
    moveq   #0,d0
    move.b  anim(a0),d0
    cmp.b   next_anim(a0),d0    ; has animation changed?
    beq.s   TAnim_Do        ; if not, branch
    move.b  d0,next_anim(a0)    ; set to next animation
    move.b  #0,anim_frame(a0)   ; reset animation frame
    move.b  #0,anim_frame_duration(a0)  ; reset frame duration
    bclr    #5,status(a0)
; loc_1CDEC:
TAnim_Do:
    add.w   d0,d0
    adda.w  (a1,d0.w),a1    ; calculate address of appropriate animation script
    move.b  (a1),d0
    bmi.s   TAnim_WalkRunZoom   ; if animation is walk/run/roll/jump, branch
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.s   TAnim_Delay         ; if time remains, branch
    move.b  d0,anim_frame_duration(a0)  ; load frame duration
; loc_1CE12:
TAnim_Do2:
    moveq   #0,d1
    move.b  anim_frame(a0),d1   ; load current frame number
    move.b  1(a1,d1.w),d0       ; read sprite number from script
    cmpi.b  #$F0,d0
    bhs.s   TAnim_End_FF        ; if animation is complete, branch
; loc_1CE22:
TAnim_Next:
    move.b  d0,mapping_frame(a0)    ; load sprite number
    addq.b  #1,anim_frame(a0)   ; go to next frame
; return_1CE2A:
TAnim_Delay:
    rts
; ===========================================================================
; loc_1CE2C:
TAnim_End_FF:
    addq.b  #1,d0       ; is the end flag = $FF ?
    bne.s   TAnim_End_FE    ; if not, branch
    move.b  #0,anim_frame(a0)   ; restart the animation
    move.b  1(a1),d0    ; read sprite number
    bra.s   TAnim_Next
; ===========================================================================
; loc_1CE3C:
TAnim_End_FE:
    addq.b  #1,d0       ; is the end flag = $FE ?
    bne.s   TAnim_End_FD    ; if not, branch
    move.b  2(a1,d1.w),d0   ; read the next byte in the script
    sub.b   d0,anim_frame(a0)   ; jump back d0 bytes in the script
    sub.b   d0,d1
    move.b  1(a1,d1.w),d0   ; read sprite number
    bra.s   TAnim_Next
; ===========================================================================
; loc_1CE50:
TAnim_End_FD:
    addq.b  #1,d0           ; is the end flag = $FD ?
    bne.s   TAnim_End       ; if not, branch
    move.b  2(a1,d1.w),anim(a0) ; read next byte, run that animation
; return_1CE5A:
TAnim_End:
    rts
; ===========================================================================
; loc_1CE5C:
TAnim_WalkRunZoom: ; a0=character
    ; note: for some reason SAnim_WalkRun doesn't need to do this here...
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from Tails' frame duration
    bpl.s   TAnim_Delay         ; if time remains, branch
 
    addq.b  #1,d0       ; is the end flag = $FF ?
    bne.w   TAnim_Roll  ; if not, branch
    moveq   #0,d0       ; is animation walking/running?
    move.b  flip_angle(a0),d0   ; if not, branch
    bne.w   TAnim_Tumble
    moveq   #0,d1
    move.b  angle(a0),d0    ; get Tails' angle
    bmi.s   +
    beq.s   +
    subq.b  #1,d0
+
    move.b  status(a0),d2
    andi.b  #1,d2       ; is Tails mirrored horizontally?
    bne.s   +       ; if yes, branch
    not.b   d0      ; reverse angle
+
    addi.b  #$10,d0     ; add $10 to angle
    bpl.s   +       ; if angle is $0-$7F, branch
    moveq   #3,d1
+
    andi.b  #$FC,render_flags(a0)
    eor.b   d1,d2
    or.b    d2,render_flags(a0)
    btst    #5,status(a0)
    bne.w   TAnim_Push
    lsr.b   #4,d0       ; divide angle by 16
    andi.b  #6,d0       ; angle must be 0, 2, 4 or 6
    mvabs.w inertia(a0),d2  ; get Tails' "speed" for animation purposes
    if status_sec_isSliding = 7
    tst.b   status_secondary(a0)
    bpl.w   +
    else
    btst    #status_sec_isSliding,status_secondary(a0)
    beq.w   +
    endif
    add.w   d2,d2
+
    move.b  d0,d3
    add.b   d3,d3
    add.b   d3,d3
    lea (TailsAni_Walk).l,a1
 
    cmpi.w  #$600,d2        ; is Tails going pretty fast?
    blo.s   TAnim_SpeedSelected ; if not, branch
    lea (TailsAni_Run).l,a1
    move.b  d0,d1
    lsr.b   #1,d1
    add.b   d1,d0
    add.b   d0,d0
    move.b  d0,d3
 
    cmpi.w  #$700,d2        ; is Tails going really fast?
    blo.s   TAnim_SpeedSelected ; if not, branch
    lea (TailsAni_HaulAss).l,a1
 
; loc_1CEEE:
TAnim_SpeedSelected:
    neg.w   d2
    addi.w  #$800,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #8,d2
    move.b  d2,anim_frame_duration(a0)  ; modify frame duration
    bsr.w   TAnim_Do2
    add.b   d3,mapping_frame(a0)
    rts
; ===========================================================================
; loc_1CF08
TAnim_Tumble:
    move.b  flip_angle(a0),d0
    moveq   #0,d1
    move.b  status(a0),d2
    andi.b  #1,d2
    bne.s   TAnim_Tumble_Left
    andi.b  #$FC,render_flags(a0)
    addi.b  #$B,d0
    divu.w  #$16,d0
    addi.b  #$75,d0
    move.b  d0,mapping_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    rts
; ===========================================================================
; loc_1CF36
TAnim_Tumble_Left:
    andi.b  #$FC,render_flags(a0)
    tst.b   flip_turned(a0)
    beq.s   +
    ori.b   #1,render_flags(a0)
    addi.b  #$B,d0
    bra.s   ++
; ===========================================================================
+
    ori.b   #3,render_flags(a0)
    neg.b   d0
    addi.b  #$8F,d0
+
    divu.w  #$16,d0
    addi.b  #$75,d0
    move.b  d0,mapping_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    rts
 
; ===========================================================================
; loc_1CF6E:
TAnim_Roll:
    addq.b  #1,d0       ; is the end flag = $FE ?
    bne.s   TAnim_GetTailFrame  ; if not, branch
    mvabs.w inertia(a0),d2
    lea (TailsAni_Roll2).l,a1
    cmpi.w  #$600,d2
    bhs.s   +
    lea (TailsAni_Roll).l,a1
+
    neg.w   d2
    addi.w  #$400,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #8,d2
    move.b  d2,anim_frame_duration(a0)
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    bra.w   TAnim_Do2
; ===========================================================================
; loc_1CFB2
TAnim_Push:
    move.w  inertia(a0),d2
    bmi.s   +
    neg.w   d2
+
    addi.w  #$800,d2
    bpl.s   +
    moveq   #0,d2
+
    lsr.w   #6,d2
    move.b  d2,anim_frame_duration(a0)
    lea (TailsAni_Push).l,a1
    move.b  status(a0),d1
    andi.b  #1,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    bra.w   TAnim_Do2
 
; ===========================================================================
; loc_1CFE4:
TAnim_GetTailFrame:
    move.w  x_vel(a2),d1
    move.w  y_vel(a2),d2
    jsr (CalcAngle).l
    moveq   #0,d1
    move.b  status(a0),d2
    andi.b  #1,d2
    bne.s   loc_1D002
    not.b   d0
    bra.s   loc_1D006
; ===========================================================================
 
loc_1D002:
    addi.b  #$80,d0
 
loc_1D006:
    addi.b  #$10,d0
    bpl.s   +
    moveq   #3,d1
+
    andi.b  #$FC,render_flags(a0)
    eor.b   d1,d2
    or.b    d2,render_flags(a0)
    lsr.b   #3,d0
    andi.b  #$C,d0
    move.b  d0,d3
    lea (Obj05Ani_Directional).l,a1
    move.b  #3,anim_frame_duration(a0)
    bsr.w   TAnim_Do2
    add.b   d3,mapping_frame(a0)
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Animation script - Tails
; ---------------------------------------------------------------------------
; off_1D038:
TailsAniData:       offsetTable
TailsAni_Walk_ptr:  offsetTableEntry.w TailsAni_Walk    ;  0 ;   0
TailsAni_Run_ptr:   offsetTableEntry.w TailsAni_Run     ;  1 ;   1
TailsAni_Roll_ptr:  offsetTableEntry.w TailsAni_Roll    ;  2 ;   2
TailsAni_Roll2_ptr: offsetTableEntry.w TailsAni_Roll2   ;  3 ;   3
TailsAni_Push_ptr:  offsetTableEntry.w TailsAni_Push    ;  4 ;   4
TailsAni_Wait_ptr:  offsetTableEntry.w TailsAni_Wait    ;  5 ;   5
TailsAni_Balance_ptr:   offsetTableEntry.w TailsAni_Balance ;  6 ;   6
TailsAni_LookUp_ptr:    offsetTableEntry.w TailsAni_LookUp  ;  7 ;   7
TailsAni_Duck_ptr:  offsetTableEntry.w TailsAni_Duck    ;  8 ;   8
TailsAni_Spindash_ptr:  offsetTableEntry.w TailsAni_Spindash    ;  9 ;   9
TailsAni_Dummy1_ptr:    offsetTableEntry.w TailsAni_Dummy1  ; 10 ;  $A
TailsAni_Dummy2_ptr:    offsetTableEntry.w TailsAni_Dummy2  ; 11 ;  $B
TailsAni_Dummy3_ptr:    offsetTableEntry.w TailsAni_Dummy3  ; 12 ;  $C
TailsAni_Stop_ptr:  offsetTableEntry.w TailsAni_Stop    ; 13 ;  $D
TailsAni_Float_ptr: offsetTableEntry.w TailsAni_Float   ; 14 ;  $E
TailsAni_Float2_ptr:    offsetTableEntry.w TailsAni_Float2  ; 15 ;  $F
TailsAni_Spring_ptr:    offsetTableEntry.w TailsAni_Spring  ; 16 ; $10
TailsAni_Hang_ptr:  offsetTableEntry.w TailsAni_Hang    ; 17 ; $11
TailsAni_Blink_ptr: offsetTableEntry.w TailsAni_Blink   ; 18 ; $12
TailsAni_Blink2_ptr:    offsetTableEntry.w TailsAni_Blink2  ; 19 ; $13
TailsAni_Hang2_ptr: offsetTableEntry.w TailsAni_Hang2   ; 20 ; $14
TailsAni_Bubble_ptr:    offsetTableEntry.w TailsAni_Bubble  ; 21 ; $15
TailsAni_DeathBW_ptr:   offsetTableEntry.w TailsAni_DeathBW ; 22 ; $16
TailsAni_Drown_ptr: offsetTableEntry.w TailsAni_Drown   ; 23 ; $17
TailsAni_Death_ptr: offsetTableEntry.w TailsAni_Death   ; 24 ; $18
TailsAni_Hurt_ptr:  offsetTableEntry.w TailsAni_Hurt    ; 25 ; $19
TailsAni_Hurt2_ptr: offsetTableEntry.w TailsAni_Hurt2   ; 26 ; $1A
TailsAni_Slide_ptr: offsetTableEntry.w TailsAni_Slide   ; 27 ; $1B
TailsAni_Blank_ptr: offsetTableEntry.w TailsAni_Blank   ; 28 ; $1C
TailsAni_Dummy4_ptr:    offsetTableEntry.w TailsAni_Dummy4  ; 29 ; $1D
TailsAni_Dummy5_ptr:    offsetTableEntry.w TailsAni_Dummy5  ; 30 ; $1E
TailsAni_HaulAss_ptr:   offsetTableEntry.w TailsAni_HaulAss ; 31 ; $1F
TailsAni_Fly_ptr:   offsetTableEntry.w TailsAni_Fly     ; 32 ; $20
 
TailsAni_Walk:  dc.b $FF,$10,$11,$12,$13,$14,$15, $E, $F,$FF
    rev02even
TailsAni_Run:   dc.b $FF,$2E,$2F,$30,$31,$FF,$FF,$FF,$FF,$FF
    rev02even
TailsAni_Roll:  dc.b   1,$48,$47,$46,$FF
    rev02even
TailsAni_Roll2: dc.b   1,$48,$47,$46,$FF
    rev02even
TailsAni_Push:  dc.b $FD,$63,$64,$65,$66,$FF,$FF,$FF,$FF,$FF
    rev02even
TailsAni_Wait:  dc.b   7,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  2,  1,  1,  1
        dc.b   1,  1,  1,  1,  1,  3,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1
        dc.b   5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5
        dc.b   6,  7,  8,  7,  8,  7,  8,  7,  8,  7,  8,  6,$FE,$1C
    rev02even
TailsAni_Balance:   dc.b   9,$69,$69,$6A,$6A,$69,$69,$6A,$6A,$69,$69,$6A,$6A,$69,$69,$6A
            dc.b $6A,$69,$69,$6A,$6A,$69,$6A,$FF
    rev02even
TailsAni_LookUp:    dc.b $3F,  4,$FF
    rev02even
TailsAni_Duck:      dc.b $3F,$5B,$FF
    rev02even
TailsAni_Spindash:  dc.b   0,$60,$61,$62,$FF
    rev02even
TailsAni_Dummy1:    dc.b $3F,$82,$FF
    rev02even
TailsAni_Dummy2:    dc.b   7,  8,  8,  9,$FD,  5
    rev02even
TailsAni_Dummy3:    dc.b   7,  9,$FD,  5
    rev02even
TailsAni_Stop:      dc.b   7,$67,$68,$67,$68,$FD,  0
    rev02even
TailsAni_Float:     dc.b   9,$6E,$73,$FF
    rev02even
TailsAni_Float2:    dc.b   9,$6E,$6F,$70,$71,$72,$FF
    rev02even
TailsAni_Spring:    dc.b   3,$59,$5A,$59,$5A,$59,$5A,$59,$5A,$59,$5A,$59,$5A,$FD,  0
    rev02even
TailsAni_Hang:      dc.b   5,$6C,$6D,$FF
    rev02even
TailsAni_Blink:     dc.b  $F,  1,  2,  3,$FE,  1
    rev02even
TailsAni_Blink2:    dc.b  $F,  1,  2,$FE,  1
    rev02even
TailsAni_Hang2:     dc.b $13,$85,$86,$FF
    rev02even
TailsAni_Bubble:    dc.b  $B,$74,$74,$12,$13,$FD,  0
    rev02even
TailsAni_DeathBW:   dc.b $20,$5D,$FF
    rev02even
TailsAni_Drown:     dc.b $2F,$5D,$FF
    rev02even
TailsAni_Death:     dc.b   3,$5D,$FF
    rev02even
TailsAni_Hurt:      dc.b   3,$5D,$FF
    rev02even
TailsAni_Hurt2:     dc.b   3,$5C,$FF
    rev02even
TailsAni_Slide:     dc.b   9,$6B,$5C,$FF
    rev02even
TailsAni_Blank:     dc.b $77,  0,$FD,  0
    rev02even
TailsAni_Dummy4:    dc.b   3,  1,  2,  3,  4,  5,  6,  7,  8,$FF
    rev02even
TailsAni_Dummy5:    dc.b   3,  1,  2,  3,  4,  5,  6,  7,  8,$FF
    rev02even
TailsAni_HaulAss:   dc.b $FF,$32,$33,$FF
            dc.b $FF,$FF,$FF,$FF,$FF,$FF
    rev02even
TailsAni_Fly:       dc.b   1,$5E,$5F,$FF
    even
 
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Tails' Tails pattern loading subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1D184:
LoadTailsTailsDynPLC:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    cmp.b   (TailsTails_LastLoadedDPLC).w,d0
    beq.s   return_1D1FE
    move.b  d0,(TailsTails_LastLoadedDPLC).w
    lea (MapRUnc_Tails).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_1D1FE
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_Tails_Tails),d4
    bra.s   TPLC_ReadEntry
 
; ---------------------------------------------------------------------------
; Tails pattern loading subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1D1AC:
LoadTailsDynPLC:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0    ; load frame number
; loc_1D1B2:
LoadTailsDynPLC_Part2:
    cmp.b   (Tails_LastLoadedDPLC).w,d0
    beq.s   return_1D1FE
    move.b  d0,(Tails_LastLoadedDPLC).w
    lea (MapRUnc_Tails).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_1D1FE
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_Tails),d4
; loc_1D1D2:
TPLC_ReadEntry:
    moveq   #0,d1
    move.w  (a2)+,d1
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.l   #5,d1
    addi.l  #ArtUnc_Tails,d1
    move.w  d4,d2
    add.w   d3,d4
    add.w   d3,d4
    jsr (QueueDMATransfer).l
    dbf d5,TPLC_ReadEntry   ; repeat for number of entries
 
return_1D1FE:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 05 - Tails' tails
; ----------------------------------------------------------------------------
; Sprite_1D200:
Obj05:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj05_Index(pc,d0.w),d1
    jmp Obj05_Index(pc,d1.w)
; ===========================================================================
; off_1D20E: Obj05_States:
Obj05_Index:    offsetTable
        offsetTableEntry.w Obj05_Init   ; 0
        offsetTableEntry.w Obj05_Main   ; 2
; ===========================================================================
 
Obj05_parent_prev_anim = objoff_30
 
; loc_1D212
Obj05_Init:
    addq.b  #2,routine(a0) ; => Obj05_Main
    move.l  #MapUnc_Tails,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtUnc_Tails_Tails,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    move.b  #2,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #4,render_flags(a0)
 
; loc_1D23A:
Obj05_Main:
    movea.w parent(a0),a2 ; a2=character
    move.b  angle(a2),angle(a0)
    move.b  status(a2),status(a0)
    move.w  x_pos(a2),x_pos(a0)
    move.w  y_pos(a2),y_pos(a0)
    andi.w  #drawing_mask,art_tile(a0)
    tst.w   art_tile(a2)
    bpl.s   +
    ori.w   #high_priority,art_tile(a0)
+
    moveq   #0,d0
    move.b  anim(a2),d0
    btst    #5,status(a2)
    beq.s   +
    moveq   #4,d0
+
    ; This is here so Obj05Ani_Flick works
    ; It changes anim(a0) itself, so we don't want the below code changing it as well
    cmp.b   Obj05_parent_prev_anim(a0),d0   ; Did Tails' animation change?
    beq.s   .display
    move.b  d0,Obj05_parent_prev_anim(a0)
    move.b  Obj05AniSelection(pc,d0.w),anim(a0) ; If so, update Tails' tails' animation
; loc_1D288:
.display:
    lea (Obj05AniData).l,a1
    bsr.w   Tails_Animate_Part2
    bsr.w   LoadTailsTailsDynPLC
    jsr (DisplaySprite).l
    rts
; ===========================================================================
; animation master script table for the tails
; chooses which animation script to run depending on what Tails is doing
; byte_1D29E:
Obj05AniSelection:
    dc.b    0,0 ; TailsAni_Walk,Run ->
    dc.b    3   ; TailsAni_Roll     -> Directional
    dc.b    3   ; TailsAni_Roll2    -> Directional
    dc.b    9   ; TailsAni_Push     -> Pushing
    dc.b    1   ; TailsAni_Wait     -> Swish
    dc.b    0   ; TailsAni_Balance  -> Blank
    dc.b    2   ; TailsAni_LookUp   -> Flick
    dc.b    1   ; TailsAni_Duck     -> Swish
    dc.b    7   ; TailsAni_Spindash -> Spindash
    dc.b    0,0,0   ; TailsAni_Dummy1,2,3   ->
    dc.b    8   ; TailsAni_Stop     -> Skidding
    dc.b    0,0 ; TailsAni_Float,2  ->
    dc.b    0   ; TailsAni_Spring   ->
    dc.b    0   ; TailsAni_Hang     ->
    dc.b    0,0 ; TailsAni_Blink,2  ->
    dc.b    $A  ; TailsAni_Hang2    -> Hanging
    dc.b    0   ; TailsAni_Bubble   ->
    dc.b    0,0,0,0 ; TailsAni_Death,2,3,4  ->
    dc.b    0,0 ; TailsAni_Hurt,Slide   ->
    dc.b    0   ; TailsAni_Blank    ->
    dc.b    0,0 ; TailsAni_Dummy4,5 ->
    dc.b    0   ; TailsAni_HaulAss  ->
    dc.b    0   ; TailsAni_Fly      ->
    even
 
; ---------------------------------------------------------------------------
; Animation script - Tails' tails
; ---------------------------------------------------------------------------
; off_1D2C0:
Obj05AniData:   offsetTable
        offsetTableEntry.w Obj05Ani_Blank   ;  0
        offsetTableEntry.w Obj05Ani_Swish   ;  1
        offsetTableEntry.w Obj05Ani_Flick   ;  2
        offsetTableEntry.w Obj05Ani_Directional ;  3
        offsetTableEntry.w Obj05Ani_DownLeft    ;  4
        offsetTableEntry.w Obj05Ani_Down    ;  5
        offsetTableEntry.w Obj05Ani_DownRight   ;  6
        offsetTableEntry.w Obj05Ani_Spindash    ;  7
        offsetTableEntry.w Obj05Ani_Skidding    ;  8
        offsetTableEntry.w Obj05Ani_Pushing ;  9
        offsetTableEntry.w Obj05Ani_Hanging ; $A
 
Obj05Ani_Blank:     dc.b $20,  0,$FF
    rev02even
Obj05Ani_Swish:     dc.b   7,  9, $A, $B, $C, $D,$FF
    rev02even
Obj05Ani_Flick:     dc.b   3,  9, $A, $B, $C, $D,$FD,  1
    rev02even
Obj05Ani_Directional:   dc.b $FC,$49,$4A,$4B,$4C,$FF ; Tails is moving right
    rev02even
Obj05Ani_DownLeft:  dc.b   3,$4D,$4E,$4F,$50,$FF ; Tails is moving up-right
    rev02even
Obj05Ani_Down:      dc.b   3,$51,$52,$53,$54,$FF ; Tails is moving up
    rev02even
Obj05Ani_DownRight: dc.b   3,$55,$56,$57,$58,$FF ; Tails is moving up-left
    rev02even
Obj05Ani_Spindash:  dc.b   2,$81,$82,$83,$84,$FF
    rev02even
Obj05Ani_Skidding:  dc.b   2,$87,$88,$89,$8A,$FF
    rev02even
Obj05Ani_Pushing:   dc.b   9,$87,$88,$89,$8A,$FF
    rev02even
Obj05Ani_Hanging:   dc.b   9,$81,$82,$83,$84,$FF
    even
 
; ===========================================================================
 
JmpTo2_KillCharacter 
    jmp (KillCharacter).l
; ===========================================================================
    align 4
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 0A - Small bubbles from Sonic's face while underwater
; ----------------------------------------------------------------------------
; Sprite_1D320:
Obj0A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0A_Index(pc,d0.w),d1
    jmp Obj0A_Index(pc,d1.w)
; ===========================================================================
; off_1D32E: Obj0A_States:
Obj0A_Index:    offsetTable
        offsetTableEntry.w Obj0A_Init       ;   0
        offsetTableEntry.w Obj0A_Animate    ;   2
        offsetTableEntry.w Obj0A_ChkWater   ;   4
        offsetTableEntry.w Obj0A_Display    ;   6
        offsetTableEntry.w JmpTo5_DeleteObject  ;   8
        offsetTableEntry.w Obj0A_Countdown  ;  $A
        offsetTableEntry.w Obj0A_AirLeft    ;  $C
        offsetTableEntry.w Obj0A_DisplayNumber  ;  $E
        offsetTableEntry.w JmpTo5_DeleteObject  ; $10
; ===========================================================================
; loc_1D340: Obj0A_Main:
Obj0A_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj24_MapUnc_1FBF6,mappings(a0)
    tst.b   parent+1(a0)
    beq.s   +
    move.l  #Obj24_MapUnc_1FC18,mappings(a0)
+
    move.w  #make_art_tile(ArtTile_ArtNem_BigBubbles,0,1),art_tile(a0)
    move.b  #$84,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  subtype(a0),d0
    bpl.s   loc_1D388
    addq.b  #8,routine(a0)
    andi.w  #$7F,d0
    move.b  d0,objoff_33(a0)
    bra.w   Obj0A_Countdown
; ===========================================================================
 
loc_1D388:
    move.b  d0,anim(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  #-$88,y_vel(a0)
 
; loc_1D398:
Obj0A_Animate:
    lea (Ani_obj0A).l,a1
    jsr (AnimateSprite).l
 
; loc_1D3A4:
Obj0A_ChkWater:
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0        ; has bubble reached the water surface?
    blo.s   Obj0A_Wobble        ; if not, branch
    ; pop the bubble:
    move.b  #6,routine(a0)
    addq.b  #7,anim(a0)
    cmpi.b  #$D,anim(a0)
    beq.s   Obj0A_Display
    blo.s   Obj0A_Display
    move.b  #$D,anim(a0)
    bra.s   Obj0A_Display
; ===========================================================================
; loc_1D3CA:
Obj0A_Wobble:
    tst.b   (WindTunnel_flag).w
    beq.s   +
    addq.w  #4,objoff_30(a0)
+
    move.b  angle(a0),d0
    addq.b  #1,angle(a0)
    andi.w  #$7F,d0
    lea (Obj0A_WobbleData).l,a1
    move.b  (a1,d0.w),d0
    ext.w   d0
    add.w   objoff_30(a0),d0
    move.w  d0,x_pos(a0)
    bsr.s   Obj0A_ShowNumber
    jsr (ObjectMove).l
    tst.b   render_flags(a0)
    bpl.s   JmpTo4_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo4_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; loc_1D40E:
Obj0A_DisplayNumber:
    movea.l objoff_3C(a0),a2 ; a2=character
    cmpi.b  #$C,air_left(a2)
    bhi.s   JmpTo5_DeleteObject
 
; loc_1D41A:
Obj0A_Display:
    bsr.s   Obj0A_ShowNumber
    lea (Ani_obj0A).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo5_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; loc_1D434:
Obj0A_AirLeft:
    movea.l objoff_3C(a0),a2 ; a2=character
    cmpi.b  #$C,air_left(a2)    ; check air remaining
    bhi.s   JmpTo6_DeleteObject ; if higher than $C, branch
    subq.w  #1,objoff_38(a0)
    bne.s   Obj0A_Display2
    move.b  #$E,routine(a0)
    addq.b  #7,anim(a0)
    bra.s   Obj0A_Display
; ===========================================================================
; loc_1D452:
Obj0A_Display2:
    lea (Ani_obj0A).l,a1
    jsr (AnimateSprite).l
    bsr.w   Obj0A_LoadCountdownArt
    tst.b   render_flags(a0)
    bpl.s   JmpTo6_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo6_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; loc_1D474:
Obj0A_ShowNumber:
    tst.w   objoff_38(a0)
    beq.s   return_1D4BE
    subq.w  #1,objoff_38(a0)
    bne.s   return_1D4BE
    cmpi.b  #7,anim(a0)
    bhs.s   return_1D4BE
    move.w  #$F,objoff_38(a0)
    clr.w   y_vel(a0)
    move.b  #$80,render_flags(a0)
    move.w  x_pos(a0),d0
    sub.w   (Camera_X_pos).w,d0
    addi.w  #$80,d0
    move.w  d0,x_pixel(a0)
    move.w  y_pos(a0),d0
    sub.w   (Camera_Y_pos).w,d0
    addi.w  #$80,d0
    move.w  d0,y_pixel(a0)
    move.b  #$C,routine(a0)
 
return_1D4BE:
    rts
; ===========================================================================
; byte_1D4C0:
Obj0A_WobbleData:
    dc.b  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2;16
    dc.b  2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3;32
    dc.b  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2;48
    dc.b  2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0;64
    dc.b  0,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-3,-3,-3,-3,-3;80
    dc.b -3,-3,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4;96
    dc.b -4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-3;112
    dc.b -3,-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1;128
 
    ; Unused S1 leftover
    ; This was used by LZ's water ripple effect in REV01
    dc.b  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2;144
    dc.b  2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3;160
    dc.b  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2;176
    dc.b  2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0;192
    dc.b  0,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-3,-3,-3,-3,-3;208
    dc.b -3,-3,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4;224
    dc.b -4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-3;240
    dc.b -3,-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1;256
; ===========================================================================
; the countdown numbers go over the dust and splash effect tiles in VRAM
; loc_1D5C0:
Obj0A_LoadCountdownArt:
    moveq   #0,d1
    move.b  mapping_frame(a0),d1
    cmpi.b  #8,d1
    blo.s   return_1D604
    cmpi.b  #$E,d1
    bhs.s   return_1D604
    cmp.b   objoff_2E(a0),d1
    beq.s   return_1D604
    move.b  d1,objoff_2E(a0)
    subq.w  #8,d1
    move.w  d1,d0
    add.w   d1,d1
    add.w   d0,d1
    lsl.w   #6,d1
    addi.l  #ArtUnc_Countdown,d1
    move.w  #tiles_to_bytes(ArtTile_ArtNem_SonicDust),d2
    tst.b   parent+1(a0)
    beq.s   +
    move.w  #tiles_to_bytes(ArtTile_ArtNem_TailsDust),d2
+
    move.w  #$60,d3
    jsr (QueueDMATransfer).l
 
return_1D604:
    rts
; ===========================================================================
 
; loc_1D606:
Obj0A_Countdown:
    movea.l objoff_3C(a0),a2 ; a2=character
    tst.w   objoff_2C(a0)
    bne.w   loc_1D708
    cmpi.b  #6,routine(a2)
    bhs.w   return_1D81C
    btst    #6,status(a2)
    beq.w   return_1D81C
    subq.w  #1,objoff_38(a0)
    bpl.w   loc_1D72C
    move.w  #$3B,objoff_38(a0)
    move.w  #1,objoff_36(a0)
    jsr (RandomNumber).l
    andi.w  #1,d0
    move.b  d0,objoff_34(a0)
    moveq   #0,d0
    move.b  air_left(a2),d0 ; check air remaining
    cmpi.w  #$19,d0
    beq.s   Obj0A_WarnSound ; play ding sound if air is $19
    cmpi.w  #$14,d0
    beq.s   Obj0A_WarnSound ; play ding sound if air is $14
    cmpi.w  #$F,d0
    beq.s   Obj0A_WarnSound ; play ding sound if air is $F
    cmpi.w  #$C,d0
    bhi.s   Obj0A_ReduceAir ; if air is above $C, branch
    bne.s   +
    tst.b   parent+1(a0)
    bne.s   +
    move.w  #MusID_Countdown,d0
    jsr (PlayMusic).l   ; play countdown music
+
    subq.b  #1,objoff_32(a0)
    bpl.s   Obj0A_ReduceAir
    move.b  objoff_33(a0),objoff_32(a0)
    bset    #7,objoff_36(a0)
    bra.s   Obj0A_ReduceAir
; ===========================================================================
; loc_1D68C:
Obj0A_WarnSound:
    tst.b   parent+1(a0)
    bne.s   Obj0A_ReduceAir
    move.w  #SndID_WaterWarning,d0
    jsr (PlaySound).l   ; play "ding-ding" warning sound
 
; loc_1D69C:
Obj0A_ReduceAir:
    subq.b  #1,air_left(a2)     ; subtract 1 from air remaining
    bcc.w   BranchTo_Obj0A_MakeItem ; if air is above 0, branch
    move.b  #$81,obj_control(a2)    ; lock controls
    move.w  #SndID_Drown,d0
    jsr (PlaySound).l       ; play drowning sound
    move.b  #$A,objoff_34(a0)
    move.w  #1,objoff_36(a0)
    move.w  #$78,objoff_2C(a0)
    movea.l a2,a1
    bsr.w   ResumeMusic
    move.l  a0,-(sp)
    movea.l a2,a0
    bsr.w   Sonic_ResetOnFloor_Part2
    move.b  #$17,anim(a0)   ; use Sonic's drowning animation
    bset    #1,status(a0)
    bset    #high_priority_bit,art_tile(a0)
    move.w  #0,y_vel(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,inertia(a0)
    movea.l (sp)+,a0 ; load 0bj address ; restore a0 = obj0A
    cmpa.w  #MainCharacter,a2
    bne.s   +   ; if it isn't player 1, branch
    move.b  #1,(Deform_lock).w
+
    rts
; ===========================================================================
 
loc_1D708:
    subq.w  #1,objoff_2C(a0)
    bne.s   +
    move.b  #6,routine(a2)
    rts
; ---------------------------------------------------------------------------
+   move.l  a0,-(sp)
    movea.l a2,a0
    jsr (ObjectMove).l
    addi.w  #$10,y_vel(a0)
    movea.l (sp)+,a0 ; load 0bj address
    bra.s   loc_1D72C
; ===========================================================================
 
BranchTo_Obj0A_MakeItem 
    bra.s   Obj0A_MakeItem
; ===========================================================================
 
loc_1D72C:
    tst.w   objoff_36(a0)
    beq.w   return_1D81C
    subq.w  #1,objoff_3A(a0)
    bpl.w   return_1D81C
 
; loc_1D73C:
Obj0A_MakeItem:
    jsr (RandomNumber).l
    andi.w  #$F,d0
    addq.w  #8,d0
    move.w  d0,objoff_3A(a0)
    jsr (SingleObjLoad).l
    bne.w   return_1D81C
    _move.b id(a0),id(a1)       ; load obj0A
    move.w  x_pos(a2),x_pos(a1) ; match its X position to Sonic
    moveq   #6,d0
    btst    #0,status(a2)
    beq.s   +
    neg.w   d0
    move.b  #$40,angle(a1)
+
    add.w   d0,x_pos(a1)
    move.w  y_pos(a2),y_pos(a1)
    move.l  objoff_3C(a0),objoff_3C(a1)
    move.b  #6,subtype(a1)
    tst.w   objoff_2C(a0)
    beq.w   loc_1D7C6
 
    andi.w  #7,objoff_3A(a0)
    addi.w  #0,objoff_3A(a0)
    move.w  y_pos(a2),d0
    subi.w  #$C,d0
    move.w  d0,y_pos(a1)
    jsr (RandomNumber).l
    move.b  d0,angle(a1)
    move.w  (Timer_frames).w,d0
    andi.b  #3,d0
    bne.s   loc_1D812
    move.b  #$E,subtype(a1)
    bra.s   loc_1D812
; ---------------------------------------------------------------------------
; has something to do with making bubbles come out less regularly
; when Sonic is almost drowning
loc_1D7C6:
    btst    #7,objoff_36(a0)
    beq.s   loc_1D812
    moveq   #0,d2
    move.b  air_left(a2),d2
    cmpi.b  #$C,d2
    bhs.s   loc_1D812
    lsr.w   #1,d2
    jsr (RandomNumber).l
    andi.w  #3,d0
    bne.s   +
    bset    #6,objoff_36(a0)
    bne.s   loc_1D812
    move.b  d2,subtype(a1)
    move.w  #$1C,objoff_38(a1)
+
    tst.b   objoff_34(a0)
    bne.s   loc_1D812
    bset    #6,objoff_36(a0)
    bne.s   loc_1D812
    move.b  d2,subtype(a1)
    move.w  #$1C,objoff_38(a1)
 
loc_1D812:
    subq.b  #1,objoff_34(a0)
    bpl.s   return_1D81C
    clr.w   objoff_36(a0)
 
return_1D81C:
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to play music after a countdown (when Sonic leaves the water)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1D81E:
ResumeMusic:
    cmpi.b  #$C,air_left(a1)
    bhi.s   ResumeMusic_Done    ; branch if countdown hasn't started yet
 
    cmpa.w  #MainCharacter,a1
    bne.s   ResumeMusic_Done    ; branch if it isn't player 1
 
    move.w  (Level_Music).w,d0  ; prepare to play current level's music
 
    btst    #status_sec_isInvincible,status_secondary(a1)
    beq.s   +       ; branch if Sonic is not invincible
    move.w  #MusID_Invincible,d0    ; prepare to play invincibility music
+
    tst.b   (Super_Sonic_flag).w
    beq.w   +       ; branch if it isn't Super Sonic
    move.w  #MusID_SuperSonic,d0    ; prepare to play super sonic music
+
    tst.b   (Current_Boss_ID).w
    beq.s   +       ; branch if not in a boss fight
    move.w  #MusID_Boss,d0  ; prepare to play boss music
+
    jsr (PlayMusic).l
; return_1D858:
ResumeMusic_Done:
    move.b  #$1E,air_left(a1)   ; reset air to full
    rts
 
; ===========================================================================
; animation script for the bubbles
; off_1D860:
Ani_obj0A:  offsetTable
        offsetTableEntry.w byte_1D87E   ;  0
        offsetTableEntry.w byte_1D887   ;  1
        offsetTableEntry.w byte_1D890   ;  2
        offsetTableEntry.w byte_1D899   ;  3
        offsetTableEntry.w byte_1D8A2   ;  4
        offsetTableEntry.w byte_1D8AB   ;  5
        offsetTableEntry.w byte_1D8B4   ;  6
        offsetTableEntry.w byte_1D8B9   ;  7
        offsetTableEntry.w byte_1D8C1   ;  8
        offsetTableEntry.w byte_1D8C9   ;  9
        offsetTableEntry.w byte_1D8D1   ; $A
        offsetTableEntry.w byte_1D8D9   ; $B
        offsetTableEntry.w byte_1D8E1   ; $C
        offsetTableEntry.w byte_1D8E9   ; $D
        offsetTableEntry.w byte_1D8EB   ; $E
byte_1D87E: dc.b   5,  0,  1,  2,  3,  4,  8,  8,$FC
    rev02even
byte_1D887: dc.b   5,  0,  1,  2,  3,  4,  9,  9,$FC
    rev02even
byte_1D890: dc.b   5,  0,  1,  2,  3,  4, $A, $A,$FC
    rev02even
byte_1D899: dc.b   5,  0,  1,  2,  3,  4, $B, $B,$FC
    rev02even
byte_1D8A2: dc.b   5,  0,  1,  2,  3,  4, $C, $C,$FC
    rev02even
byte_1D8AB: dc.b   5,  0,  1,  2,  3,  4, $D, $D,$FC
    rev02even
byte_1D8B4: dc.b  $E,  0,  1,  2,$FC
    rev02even
byte_1D8B9: dc.b   7,$10,  8,$10,  8,$10,  8,$FC
    rev02even
byte_1D8C1: dc.b   7,$10,  9,$10,  9,$10,  9,$FC
    rev02even
byte_1D8C9: dc.b   7,$10, $A,$10, $A,$10, $A,$FC
    rev02even
byte_1D8D1: dc.b   7,$10, $B,$10, $B,$10, $B,$FC
    rev02even
byte_1D8D9: dc.b   7,$10, $C,$10, $C,$10, $C,$FC
    rev02even
byte_1D8E1: dc.b   7,$10, $D,$10, $D,$10, $D,$FC
    rev02even
byte_1D8E9: dc.b  $E,$FC
    rev02even
byte_1D8EB: dc.b  $E,  1,  2,  3,  4,$FC
    even
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 38 - Shield
; ----------------------------------------------------------------------------
; Sprite_1D8F2:
Obj38:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj38_Index(pc,d0.w),d1
    jmp Obj38_Index(pc,d1.w)
; ===========================================================================
; off_1D900:
Obj38_Index:    offsetTable
        offsetTableEntry.w Obj38_Main   ; 0
        offsetTableEntry.w Obj38_Shield ; 2
; ===========================================================================
; loc_1D904:
Obj38_Main:
    addq.b  #2,routine(a0)
    move.l  #Obj38_MapUnc_1DBE4,mappings(a0)
    move.b  #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Shield,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
; loc_1D92C:
Obj38_Shield:
    movea.w parent(a0),a2 ; a2=character
    btst    #status_sec_isInvincible,status_secondary(a2)
    bne.s   return_1D976
    btst    #status_sec_hasShield,status_secondary(a2)
    beq.s   JmpTo7_DeleteObject
    move.w  x_pos(a2),x_pos(a0)
    move.w  y_pos(a2),y_pos(a0)
    move.b  status(a2),status(a0)
    andi.w  #drawing_mask,art_tile(a0)
    tst.w   art_tile(a2)
    bpl.s   Obj38_Display
    ori.w   #high_priority,art_tile(a0)
; loc_1D964:
Obj38_Display:
    lea (Ani_obj38).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
return_1D976:
    rts
; ===========================================================================
 
JmpTo7_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 35 - Invincibility Stars
; ----------------------------------------------------------------------------
; Sprite_1D97E:
Obj35:
    moveq   #0,d0
    move.b  objoff_A(a0),d0
    move.w  Obj35_Index(pc,d0.w),d1
    jmp Obj35_Index(pc,d1.w)
; ===========================================================================
; off_1D98C:
Obj35_Index:    offsetTable
        offsetTableEntry.w loc_1D9A4    ; 0
        offsetTableEntry.w loc_1DA0C    ; 2
        offsetTableEntry.w loc_1DA80    ; 4
 
off_1D992:
    dc.l byte_1DB8F
    dc.w $B
    dc.l byte_1DBA4
    dc.w $160D
    dc.l byte_1DBBD
    dc.w $2C0D
; ===========================================================================
 
loc_1D9A4:
    moveq   #0,d2
    lea off_1D992-6(pc),a2
    lea (a0),a1
 
    moveq   #3,d1
-   _move.b id(a0),id(a1) ; load obj35
    move.b  #4,objoff_A(a1)     ; => loc_1DA80
    move.l  #Obj35_MapUnc_1DCBC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Invincible_stars,0,0),art_tile(a1)
    bsr.w   Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #$10,mainspr_width(a1)
    move.b  #2,mainspr_childsprites(a1)
    move.w  parent(a0),parent(a1)
    move.b  d2,objoff_36(a1)
    addq.w  #1,d2
    move.l  (a2)+,objoff_30(a1)
    move.w  (a2)+,objoff_34(a1)
    lea next_object(a1),a1 ; a1=object
    dbf d1,-
 
    move.b  #2,objoff_A(a0)     ; => loc_1DA0C
    move.b  #4,objoff_34(a0)
 
loc_1DA0C:
    movea.w parent(a0),a1 ; a1=character
    btst    #status_sec_isInvincible,status_secondary(a1)
    beq.w   DeleteObject
    move.w  x_pos(a1),d0
    move.w  d0,x_pos(a0)
    move.w  y_pos(a1),d1
    move.w  d1,y_pos(a0)
    lea sub2_x_pos(a0),a2
    lea byte_1DB82(pc),a3
    moveq   #0,d5
 
loc_1DA34:
    move.w  objoff_38(a0),d2
    move.b  (a3,d2.w),d5
    bpl.s   loc_1DA44
    clr.w   objoff_38(a0)
    bra.s   loc_1DA34
; ===========================================================================
 
loc_1DA44:
    addq.w  #1,objoff_38(a0)
    lea byte_1DB42(pc),a6
    move.b  objoff_34(a0),d6
    jsr loc_1DB2C(pc)
    move.w  d2,(a2)+    ; sub2_x_pos
    move.w  d3,(a2)+    ; sub2_y_pos
    move.w  d5,(a2)+    ; sub2_mapframe
    addi.w  #$20,d6
    jsr loc_1DB2C(pc)
    move.w  d2,(a2)+    ; sub3_x_pos
    move.w  d3,(a2)+    ; sub3_y_pos
    move.w  d5,(a2)+    ; sub3_mapframe
    moveq   #$12,d0
    btst    #0,status(a1)
    beq.s   loc_1DA74
    neg.w   d0
 
loc_1DA74:
    add.b   d0,objoff_34(a0)
    move.w  #$80,d0
    bra.w   DisplaySprite3
; ===========================================================================
 
loc_1DA80:
    movea.w parent(a0),a1 ; a1=character
    btst    #status_sec_isInvincible,status_secondary(a1)
    beq.w   DeleteObject
    cmpi.w  #2,(Player_mode).w
    beq.s   loc_1DAA4
    lea (Sonic_Pos_Record_Index).w,a5
    lea (Sonic_Pos_Record_Buf).w,a6
    tst.b   parent+1(a0)
    beq.s   loc_1DAAC
 
loc_1DAA4:
    lea (Tails_Pos_Record_Index).w,a5
    lea (Tails_Pos_Record_Buf).w,a6
 
loc_1DAAC:
    move.b  objoff_36(a0),d1
    lsl.b   #2,d1
    move.w  d1,d2
    add.w   d1,d1
    add.w   d2,d1
    move.w  (a5),d0
    sub.b   d1,d0
    lea (a6,d0.w),a2
    move.w  (a2)+,d0
    move.w  (a2)+,d1
    move.w  d0,x_pos(a0)
    move.w  d1,y_pos(a0)
    lea sub2_x_pos(a0),a2
    movea.l objoff_30(a0),a3
 
loc_1DAD4:
    move.w  objoff_38(a0),d2
    move.b  (a3,d2.w),d5
    bpl.s   loc_1DAE4
    clr.w   objoff_38(a0)
    bra.s   loc_1DAD4
; ===========================================================================
 
loc_1DAE4:
    swap    d5
    add.b   objoff_35(a0),d2
    move.b  (a3,d2.w),d5
    addq.w  #1,objoff_38(a0)
    lea byte_1DB42(pc),a6
    move.b  objoff_34(a0),d6
    jsr loc_1DB2C(pc)
    move.w  d2,(a2)+    ; sub2_x_pos
    move.w  d3,(a2)+    ; sub2_y_pos
    move.w  d5,(a2)+    ; sub2_mapframe
    addi.w  #$20,d6
    swap    d5
    jsr loc_1DB2C(pc)
    move.w  d2,(a2)+    ; sub3_x_pos
    move.w  d3,(a2)+    ; sub3_y_pos
    move.w  d5,(a2)+    ; sub3_mapframe
    moveq   #2,d0
    btst    #0,status(a1)
    beq.s   loc_1DB20
    neg.w   d0
 
loc_1DB20:
    add.b   d0,objoff_34(a0)
    move.w  #$80,d0
    bra.w   DisplaySprite3
; ===========================================================================
 
loc_1DB2C:
    andi.w  #$3E,d6
    move.b  (a6,d6.w),d2
    move.b  1(a6,d6.w),d3
    ext.w   d2
    ext.w   d3
    add.w   d0,d2
    add.w   d1,d3
    rts
; ===========================================================================
; unknown
byte_1DB42: dc.w   $F00,  $F03,  $E06,  $D08,  $B0B,  $80D,  $60E,  $30F
        dc.w    $10, -$3F1, -$6F2, -$8F3, -$BF5, -$DF8, -$EFA, -$FFD
        dc.w  $F000, -$F04, -$E07, -$D09, -$B0C, -$80E, -$60F, -$310
        dc.w   -$10,  $3F0,  $6F1,  $8F2,  $BF4,  $DF7,  $EF9,  $FFC
 
byte_1DB82: dc.b   8,  5,  7,  6,  6,  7,  5,  8,  6,  7,  7,  6,$FF
    rev02even
byte_1DB8F: dc.b   8,  7,  6,  5,  4,  3,  4,  5,  6,  7,$FF
        dc.b   3,  4,  5,  6,  7,  8,  7,  6,  5,  4
    rev02even
byte_1DBA4: dc.b   8,  7,  6,  5,  4,  3,  2,  3,  4,  5,  6,  7,$FF
        dc.b   2,  3,  4,  5,  6,  7,  8,  7,  6,  5,  4,  3
    rev02even
byte_1DBBD: dc.b   7,  6,  5,  4,  3,  2,  1,  2,  3,  4,  5,  6,$FF
        dc.b   1,  2,  3,  4,  5,  6,  7,  6,  5,  4,  3,  2
    even
 
; animation script
; byte_1DBD6
Ani_obj38:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   0,  5,  0,  5,  1,  5,  2,  5,  3,  5,  4,$FF
 
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj38_MapUnc_1DBE4: BINCLUDE "mappings/sprite/obj38.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj35_MapUnc_1DCBC: BINCLUDE "mappings/sprite/obj35.bin"
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 08 - Water splash in Aquatic Ruin Zone, Spindash dust
; ----------------------------------------------------------------------------
; Sprite_1DD20:
Obj08:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj08_Index(pc,d0.w),d1
    jmp Obj08_Index(pc,d1.w)
; ===========================================================================
; off_1DD2E:
Obj08_Index:    offsetTable
        offsetTableEntry.w Obj08_Init           ; 0
        offsetTableEntry.w Obj08_Main           ; 2
        offsetTableEntry.w BranchTo16_DeleteObject  ; 4
        offsetTableEntry.w Obj08_CheckSkid      ; 6
; ===========================================================================
; loc_1DD36:
Obj08_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj08_MapUnc_1DF5E,mappings(a0)
    ori.b   #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SonicDust,0,0),art_tile(a0)
    move.w  #MainCharacter,parent(a0)
    move.w  #tiles_to_bytes(ArtTile_ArtNem_SonicDust),objoff_3C(a0)
    cmpa.w  #Sonic_Dust,a0
    beq.s   +
    move.b  #1,objoff_34(a0)
    cmpi.w  #2,(Player_mode).w
    beq.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_TailsDust,0,0),art_tile(a0)
    move.w  #Sidekick,parent(a0)
    move.w  #tiles_to_bytes(ArtTile_ArtNem_TailsDust),objoff_3C(a0)
+
    bsr.w   Adjust2PArtPointer
 
; loc_1DD90:
Obj08_Main:
    movea.w parent(a0),a2 ; a2=character
    moveq   #0,d0
    move.b  anim(a0),d0 ; use current animation as a secondary routine counter
    add.w   d0,d0
    move.w  Obj08_DisplayModes(pc,d0.w),d1
    jmp Obj08_DisplayModes(pc,d1.w)
; ===========================================================================
; off_1DDA4:
Obj08_DisplayModes: offsetTable
    offsetTableEntry.w Obj08_Display    ; 0
    offsetTableEntry.w Obj08_MdSplash   ; 2
    offsetTableEntry.w Obj08_MdSpindashDust ; 4
    offsetTableEntry.w Obj08_MdSkidDust ; 6
; ===========================================================================
; loc_1DDAC:
Obj08_MdSplash:
    move.w  (Water_Level_1).w,y_pos(a0)
    tst.b   next_anim(a0)
    bne.s   Obj08_Display
    move.w  x_pos(a2),x_pos(a0)
    move.b  #0,status(a0)
    andi.w  #drawing_mask,art_tile(a0)
    bra.s   Obj08_Display
; ===========================================================================
; loc_1DDCC:
Obj08_MdSpindashDust:
    cmpi.b  #$C,air_left(a2)
    blo.s   Obj08_ResetDisplayMode
    cmpi.b  #4,routine(a2)
    bhs.s   Obj08_ResetDisplayMode
    tst.b   spindash_flag(a2)
    beq.s   Obj08_ResetDisplayMode
    move.w  x_pos(a2),x_pos(a0)
    move.w  y_pos(a2),y_pos(a0)
    move.b  status(a2),status(a0)
    andi.b  #1,status(a0)
    tst.b   objoff_34(a0)
    beq.s   +
    subi_.w #4,y_pos(a0)
+
    tst.b   next_anim(a0)
    bne.s   Obj08_Display
    andi.w  #drawing_mask,art_tile(a0)
    tst.w   art_tile(a2)
    bpl.s   Obj08_Display
    ori.w   #high_priority,art_tile(a0)
    bra.s   Obj08_Display
; ===========================================================================
; loc_1DE20:
Obj08_MdSkidDust:
    cmpi.b  #$C,air_left(a2)
    blo.s   Obj08_ResetDisplayMode
 
; loc_1DE28:
Obj08_Display:
    lea (Ani_obj08).l,a1
    jsr (AnimateSprite).l
    bsr.w   Obj08_LoadDustOrSplashArt
    jmp (DisplaySprite).l
; ===========================================================================
; loc_1DE3E:
Obj08_ResetDisplayMode:
    move.b  #0,anim(a0)
    rts
; ===========================================================================
 
BranchTo16_DeleteObject 
    bra.w   DeleteObject
; ===========================================================================
; loc_1DE4A:
Obj08_CheckSkid:
    movea.w parent(a0),a2 ; a2=character
    cmpi.b  #AniIDSonAni_Stop,anim(a2)  ; SonAni_Stop
    beq.s   Obj08_SkidDust
    move.b  #2,routine(a0)
    move.b  #0,objoff_32(a0)
    rts
; ===========================================================================
; loc_1DE64:
Obj08_SkidDust:
    subq.b  #1,objoff_32(a0)
    bpl.s   loc_1DEE0
    move.b  #3,objoff_32(a0)
    bsr.w   SingleObjLoad
    bne.s   loc_1DEE0
    _move.b id(a0),id(a1) ; load obj08
    move.w  x_pos(a2),x_pos(a1)
    move.w  y_pos(a2),y_pos(a1)
    addi.w  #$10,y_pos(a1)
    tst.b   objoff_34(a0)
    beq.s   +
    subi_.w #4,y_pos(a1)
+
    move.b  #0,status(a1)
    move.b  #3,anim(a1)
    addq.b  #2,routine(a1)
    move.l  mappings(a0),mappings(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #1,priority(a1)
    move.b  #4,width_pixels(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.w  parent(a0),parent(a1)
    andi.w  #drawing_mask,art_tile(a1)
    tst.w   art_tile(a2)
    bpl.s   loc_1DEE0
    ori.w   #high_priority,art_tile(a1)
 
loc_1DEE0:
    bsr.s   Obj08_LoadDustOrSplashArt
    rts
; ===========================================================================
; loc_1DEE4:
Obj08_LoadDustOrSplashArt:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    cmp.b   objoff_30(a0),d0
    beq.s   return_1DF36
    move.b  d0,objoff_30(a0)
    lea (Obj08_MapRUnc_1E074).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_1DF36
    move.w  objoff_3C(a0),d4
 
-   moveq   #0,d1
    move.w  (a2)+,d1
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.l   #5,d1
    addi.l  #ArtUnc_Splash,d1
    move.w  d4,d2
    add.w   d3,d4
    add.w   d3,d4
    jsr (QueueDMATransfer).l
    dbf d5,-
 
return_1DF36:
    rts
; ===========================================================================
; animation script
; off_1DF38:
Ani_obj08:  offsetTable
        offsetTableEntry.w Obj08Ani_Null    ; 0
        offsetTableEntry.w Obj08Ani_Splash  ; 1
        offsetTableEntry.w Obj08Ani_Dash    ; 2
        offsetTableEntry.w Obj08Ani_Skid    ; 3
Obj08Ani_Null:  dc.b $1F,  0,$FF
    rev02even
Obj08Ani_Splash:dc.b   3,  1,  2,  3,  4,  5,  6,  7,  8,  9,$FD,  0
    rev02even
Obj08Ani_Dash:  dc.b   1, $A, $B, $C, $D, $E, $F,$10,$FF
    rev02even
Obj08Ani_Skid:  dc.b   3,$11,$12,$13,$14,$FC
    even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj08_MapUnc_1DF5E: BINCLUDE "mappings/sprite/obj08.bin"
; -------------------------------------------------------------------------------
; dynamic pattern loading cues
; -------------------------------------------------------------------------------
Obj08_MapRUnc_1E074:    BINCLUDE "mappings/spriteDPLC/obj08.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7E - Super Sonic's stars
; ----------------------------------------------------------------------------
; Sprite_1E0F0:
Obj7E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7E_Index(pc,d0.w),d1
    jmp Obj7E_Index(pc,d1.w)
; ===========================================================================
; off_1E0FE: Obj7E_States:
Obj7E_Index:    offsetTable
        offsetTableEntry.w Obj7E_Init   ; 0
        offsetTableEntry.w Obj7E_Main   ; 2
; ===========================================================================
; loc_1E102:
Obj7E_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj7E_MapUnc_1E1BE,mappings(a0)
    move.b  #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SuperSonic_stars,0,0),art_tile(a0)
    bsr.w   Adjust2PArtPointer
    btst    #high_priority_bit,(MainCharacter+art_tile).w
    beq.s   Obj7E_Main
    bset    #high_priority_bit,art_tile(a0)
; loc_1E138:
Obj7E_Main:
    tst.b   (Super_Sonic_flag).w
    beq.s   JmpTo8_DeleteObject
    tst.b   objoff_30(a0)
    beq.s   loc_1E188
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_1E170
    move.b  #1,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #6,mapping_frame(a0)
    blo.s   loc_1E170
    move.b  #0,mapping_frame(a0)
    move.b  #0,objoff_30(a0)
    move.b  #1,objoff_31(a0)
    rts
; ===========================================================================
 
loc_1E170:
    tst.b   objoff_31(a0)
    bne.s   JmpTo6_DisplaySprite
 
loc_1E176:
    move.w  (MainCharacter+x_pos).w,x_pos(a0)
    move.w  (MainCharacter+y_pos).w,y_pos(a0)
 
JmpTo6_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_1E188:
    tst.b   (MainCharacter+obj_control).w
    bne.s   loc_1E1AA
    mvabs.w (MainCharacter+inertia).w,d0
    cmpi.w  #$800,d0
    blo.s   loc_1E1AA
    move.b  #0,mapping_frame(a0)
    move.b  #1,objoff_30(a0)
    bra.s   loc_1E176
; ===========================================================================
 
loc_1E1AA:
    move.b  #0,objoff_30(a0)
    move.b  #0,objoff_31(a0)
    rts
; ===========================================================================
 
JmpTo8_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj7E_MapUnc_1E1BE: BINCLUDE "mappings/sprite/obj7E.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to change Sonic's angle & position as he walks along the floor
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1E234: Sonic_AnglePos:
AnglePos:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  top_solid_bit(a0),d5
    btst    #3,status(a0)
    beq.s   +
    moveq   #0,d0
    move.b  d0,(Primary_Angle).w
    move.b  d0,(Secondary_Angle).w
    rts
; ---------------------------------------------------------------------------
+   moveq   #3,d0
    move.b  d0,(Primary_Angle).w
    move.b  d0,(Secondary_Angle).w
    move.b  angle(a0),d0
    addi.b  #$20,d0
    bpl.s   loc_1E286
    move.b  angle(a0),d0
    bpl.s   +
    subq.b  #1,d0
+
    addi.b  #$20,d0
    bra.s   loc_1E292
; ---------------------------------------------------------------------------
loc_1E286:
    move.b  angle(a0),d0
    bpl.s   loc_1E28E
    addq.b  #1,d0
 
loc_1E28E:
    addi.b  #$1F,d0
 
loc_1E292:
    andi.b  #$C0,d0
    cmpi.b  #$40,d0
    beq.w   Sonic_WalkVertL
    cmpi.b  #$80,d0
    beq.w   Sonic_WalkCeiling
    cmpi.b  #$C0,d0
    beq.w   Sonic_WalkVertR
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindFloor
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    neg.w   d0
    add.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindFloor
    move.w  (sp)+,d0
    bsr.w   Sonic_Angle
    tst.w   d1
    beq.s   return_1E31C
    bpl.s   loc_1E31E
    cmpi.w  #-$E,d1
    blt.s   return_1E31C
    add.w   d1,y_pos(a0)
 
return_1E31C:
    rts
; ===========================================================================
 
loc_1E31E:
    mvabs.b x_vel(a0),d0
    addq.b  #4,d0
    cmpi.b  #$E,d0
    blo.s   +
    move.b  #$E,d0
+
    cmp.b   d0,d1
    bgt.s   loc_1E33C
 
loc_1E336:
    add.w   d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_1E33C:
    tst.b   stick_to_convex(a0)
    bne.s   loc_1E336
    bset    #1,status(a0)
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to change Sonic's angle as he walks along the floor
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1E356:
Sonic_Angle:
    move.b  (Secondary_Angle).w,d2
    cmp.w   d0,d1
    ble.s   +
    move.b  (Primary_Angle).w,d2
    move.w  d0,d1
+
    btst    #0,d2
    bne.s   loc_1E380
    move.b  d2,d0
    sub.b   angle(a0),d0
    bpl.s   +
    neg.b   d0
+
    cmpi.b  #$20,d0
    bhs.s   loc_1E380
    move.b  d2,angle(a0)
    rts
; ===========================================================================
 
loc_1E380:
    move.b  angle(a0),d2
    addi.b  #$20,d2
    andi.b  #$C0,d2
    move.b  d2,angle(a0)
    rts
; End of function Sonic_Angle
 
; ---------------------------------------------------------------------------
; Subroutine allowing Sonic to walk up a vertical slope/wall to his right
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1E392:
Sonic_WalkVertR:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    neg.w   d0
    add.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindWall
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindWall
    move.w  (sp)+,d0
    bsr.w   Sonic_Angle
    tst.w   d1
    beq.s   return_1E400
    bpl.s   loc_1E402
    cmpi.w  #-$E,d1
    blt.s   return_1E400
    add.w   d1,x_pos(a0)
 
return_1E400:
    rts
; ===========================================================================
 
loc_1E402:
    mvabs.b y_vel(a0),d0
    addq.b  #4,d0
    cmpi.b  #$E,d0
    blo.s   +
    move.b  #$E,d0
+
    cmp.b   d0,d1
    bgt.s   loc_1E420
 
loc_1E41A:
    add.w   d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_1E420:
    tst.b   stick_to_convex(a0)
    bne.s   loc_1E41A
    bset    #1,status(a0)
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
    rts
; ===========================================================================
;loc_1E43A
Sonic_WalkCeiling:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    eori.w  #$F,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    bsr.w   FindFloor
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    eori.w  #$F,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    bsr.w   FindFloor
    move.w  (sp)+,d0
    bsr.w   Sonic_Angle
    tst.w   d1
    beq.s   return_1E4AE
    bpl.s   loc_1E4B0
    cmpi.w  #-$E,d1
    blt.s   return_1E4AE
    sub.w   d1,y_pos(a0)
 
return_1E4AE:
    rts
; ===========================================================================
 
loc_1E4B0:
    mvabs.b x_vel(a0),d0
    addq.b  #4,d0
    cmpi.b  #$E,d0
    blo.s   +
    move.b  #$E,d0
+
    cmp.b   d0,d1
    bgt.s   loc_1E4CE
 
loc_1E4C8:
    sub.w   d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_1E4CE:
    tst.b   stick_to_convex(a0)
    bne.s   loc_1E4C8
    bset    #1,status(a0)
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
    rts
; ===========================================================================
;loc_1E4E8
Sonic_WalkVertL:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    eori.w  #$F,d3
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$400,d6
    bsr.w   FindWall
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    eori.w  #$F,d3
    lea (Secondary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$400,d6
    bsr.w   FindWall
    move.w  (sp)+,d0
    bsr.w   Sonic_Angle
    tst.w   d1
    beq.s   return_1E55C
    bpl.s   loc_1E55E
    cmpi.w  #-$E,d1
    blt.s   return_1E55C
    sub.w   d1,x_pos(a0)
 
return_1E55C:
    rts
; ===========================================================================
 
loc_1E55E:
    mvabs.b y_vel(a0),d0
    addq.b  #4,d0
    cmpi.b  #$E,d0
    blo.s   +
    move.b  #$E,d0
+
    cmp.b   d0,d1
    bgt.s   loc_1E57C
 
loc_1E576:
    sub.w   d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_1E57C:
    tst.b   stick_to_convex(a0)
    bne.s   loc_1E576
    bset    #1,status(a0)
    bclr    #5,status(a0)
    move.b  #AniIDSonAni_Run,next_anim(a0)
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Subroutine to find which tile is in the specified location
; d2 = y_pos
; d3 = x_pos
; returns relevant block ID in (a1)
; a1 is pointer to block in chunk table
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1E596: Floor_ChkTile:
Find_Tile:
    move.w  d2,d0   ; y_pos
    add.w   d0,d0
    andi.w  #$F00,d0    ; rounded 2*y_pos
    move.w  d3,d1   ; x_pos
    lsr.w   #3,d1
    move.w  d1,d4
    lsr.w   #4,d1   ; x_pos/128 = x_of_chunk
    andi.w  #$7F,d1
    add.w   d1,d0   ; d0 is relevant chunk ID now
    moveq   #-1,d1
    clr.w   d1      ; d1 is now $FFFF0000 = Chunk_Table
    lea (Level_Layout).w,a1
    move.b  (a1,d0.w),d1    ; move 128*128 chunk ID to d1
    add.w   d1,d1
    move.w  word_1E5D0(pc,d1.w),d1
    move.w  d2,d0   ; y_pos
    andi.w  #$70,d0
    add.w   d0,d1
    andi.w  #$E,d4  ; x_pos/8
    add.w   d4,d1
    movea.l d1,a1   ; address of block ID
    rts
; ===========================================================================
; precalculated values for Find_Tile
; (Sonic 1 calculated it every time instead of using a table)
word_1E5D0:
c := 0
    rept 256
        dc.w    c
c := c+$80
    endm
; ===========================================================================
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Scans vertically for up to 2 16x16 blocks to find solid ground or ceiling.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; d6 = $0000 for no flip, $0800 for vertical flip
; a3 = delta-y for next location to check if current one is empty
; a4 = pointer to angle buffer
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in (a4)
 
; loc_1E7D0:
FindFloor:
    bsr.w   Find_Tile
    move.w  (a1),d0
    move.w  d0,d4
    andi.w  #$3FF,d0
    beq.s   loc_1E7E2
    btst    d5,d4
    bne.s   loc_1E7F0
 
loc_1E7E2:
    add.w   a3,d2
    bsr.w   FindFloor2
    sub.w   a3,d2
    addi.w  #$10,d1
    rts
; ===========================================================================
 
loc_1E7F0:  ; block has some solidity
    movea.l (Collision_addr).w,a2   ; pointer to collision data, i.e. blockID -> collisionID array
    move.b  (a2,d0.w),d0    ; get collisionID
    andi.w  #$FF,d0
    beq.s   loc_1E7E2
    lea (ColCurveMap).l,a2
    move.b  (a2,d0.w),(a4)  ; get angle from AngleMap --> (a4)
    lsl.w   #4,d0
    move.w  d3,d1   ; x_pos
    btst    #$A,d4  ; adv.blockID in d4 - X flipping
    beq.s   +
    not.w   d1
    neg.b   (a4)
+
    btst    #$B,d4  ; Y flipping
    beq.s   +
    addi.b  #$40,(a4)
    neg.b   (a4)
    subi.b  #$40,(a4)
+
    andi.w  #$F,d1  ; x_pos (mod 16)
    add.w   d0,d1   ; d0 = 16*blockID -> offset in ColArray to look up
    lea (ColArray).l,a2
    move.b  (a2,d1.w),d0    ; heigth from ColArray
    ext.w   d0
    eor.w   d6,d4
    btst    #$B,d4  ; Y flipping
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    beq.s   loc_1E7E2   ; no collision
    bmi.s   loc_1E85E
    cmpi.b  #$10,d0
    beq.s   loc_1E86A
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    move.w  #$F,d1
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1E85E:
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    bpl.w   loc_1E7E2
 
loc_1E86A:
    sub.w   a3,d2
    bsr.w   FindFloor2
    add.w   a3,d2
    subi.w  #$10,d1
    rts
; End of function FindFloor
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Checks a 16x16 block to find solid ground or ceiling.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; d6 = $0000 for no flip, $0800 for vertical flip
; a4 = pointer to angle buffer
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in (a4)
 
; loc_1E878:
FindFloor2:
    bsr.w   Find_Tile
    move.w  (a1),d0
    move.w  d0,d4
    andi.w  #$3FF,d0
    beq.s   loc_1E88A
    btst    d5,d4
    bne.s   loc_1E898
 
loc_1E88A:
    move.w  #$F,d1
    move.w  d2,d0
    andi.w  #$F,d0
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1E898:
    movea.l (Collision_addr).w,a2
    move.b  (a2,d0.w),d0
    andi.w  #$FF,d0
    beq.s   loc_1E88A
    lea (ColCurveMap).l,a2
    move.b  (a2,d0.w),(a4)
    lsl.w   #4,d0
    move.w  d3,d1
    btst    #$A,d4
    beq.s   +
    not.w   d1
    neg.b   (a4)
+
    btst    #$B,d4
    beq.s   +
    addi.b  #$40,(a4)
    neg.b   (a4)
    subi.b  #$40,(a4)
+
    andi.w  #$F,d1
    add.w   d0,d1
    lea (ColArray).l,a2
    move.b  (a2,d1.w),d0
    ext.w   d0
    eor.w   d6,d4
    btst    #$B,d4
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    beq.s   loc_1E88A
    bmi.s   loc_1E900
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    move.w  #$F,d1
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1E900:
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    bpl.w   loc_1E88A
    not.w   d1
    rts
; ===========================================================================
 
; Checks a 16x16 block to find solid ground or ceiling. May check an additional
; 16x16 block up for ceilings.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; d6 = $0000 for no flip, $0800 for vertical flip
; a4 = pointer to angle buffer
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in (a4)
 
; loc_1E910: Obj_CheckInFloor:
Ring_FindFloor:
    bsr.w   Find_Tile
    move.w  (a1),d0
    move.w  d0,d4
    andi.w  #$3FF,d0
    beq.s   loc_1E922
    btst    d5,d4
    bne.s   loc_1E928
 
loc_1E922:
    move.w  #$10,d1
    rts
; ===========================================================================
 
loc_1E928:
    movea.l (Collision_addr).w,a2
    move.b  (a2,d0.w),d0
    andi.w  #$FF,d0
    beq.s   loc_1E922
    lea (ColCurveMap).l,a2
    move.b  (a2,d0.w),(a4)
    lsl.w   #4,d0
    move.w  d3,d1
    btst    #$A,d4
    beq.s   +
    not.w   d1
    neg.b   (a4)
+
    btst    #$B,d4
    beq.s   +
    addi.b  #$40,(a4)
    neg.b   (a4)
    subi.b  #$40,(a4)
+
    andi.w  #$F,d1
    add.w   d0,d1
    lea (ColArray).l,a2
    move.b  (a2,d1.w),d0
    ext.w   d0
    eor.w   d6,d4
    btst    #$B,d4
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    beq.s   loc_1E922
    bmi.s   loc_1E996
    cmpi.b  #$10,d0
    beq.s   loc_1E9A2
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    move.w  #$F,d1
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1E996:
    move.w  d2,d1
    andi.w  #$F,d1
    add.w   d1,d0
    bpl.w   loc_1E922
 
loc_1E9A2:
    sub.w   a3,d2
    bsr.w   FindFloor2
    add.w   a3,d2
    subi.w  #$10,d1
    rts
; ===========================================================================
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Scans horizontally for up to 2 16x16 blocks to find solid walls.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; d6 = $0000 for no flip, $0400 for horizontal flip
; a3 = delta-x for next location to check if current one is empty
; a4 = pointer to angle buffer
; returns relevant block ID in (a1)
; returns distance to left/right in d1
; returns angle in (a4)
 
; loc_1E9B0:
FindWall:
    bsr.w   Find_Tile
    move.w  (a1),d0
    move.w  d0,d4
    andi.w  #$3FF,d0    ; plain blockID
    beq.s   loc_1E9C2   ; no collision
    btst    d5,d4
    bne.s   loc_1E9D0
 
loc_1E9C2:
    add.w   a3,d3
    bsr.w   FindWall2
    sub.w   a3,d3
    addi.w  #$10,d1
    rts
; ===========================================================================
 
loc_1E9D0:
    movea.l (Collision_addr).w,a2
    move.b  (a2,d0.w),d0
    andi.w  #$FF,d0 ; relevant collisionArrayEntry
    beq.s   loc_1E9C2
    lea (ColCurveMap).l,a2
    move.b  (a2,d0.w),(a4)
    lsl.w   #4,d0   ; offset in collision array
    move.w  d2,d1   ; y
    btst    #$B,d4  ; y-mirror?
    beq.s   +
    not.w   d1
    addi.b  #$40,(a4)
    neg.b   (a4)
    subi.b  #$40,(a4)
+
    btst    #$A,d4  ; x-mirror?
    beq.s   +
    neg.b   (a4)
+
    andi.w  #$F,d1  ; y
    add.w   d0,d1   ; line to look up
    lea (ColArray2).l,a2    ; rotated collision array
    move.b  (a2,d1.w),d0    ; collision value
    ext.w   d0
    eor.w   d6,d4   ; set x-flip flag if from the right
    btst    #$A,d4  ; x-mirror?
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    beq.s   loc_1E9C2
    bmi.s   loc_1EA3E
    cmpi.b  #$10,d0
    beq.s   loc_1EA4A
    move.w  d3,d1   ; x
    andi.w  #$F,d1
    add.w   d1,d0
    move.w  #$F,d1
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1EA3E:
    move.w  d3,d1
    andi.w  #$F,d1
    add.w   d1,d0
    bpl.w   loc_1E9C2   ; no collision
 
loc_1EA4A:
    sub.w   a3,d3
    bsr.w   FindWall2
    add.w   a3,d3
    subi.w  #$10,d1
    rts
; End of function FindWall
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Checks a 16x16 blocks to find solid walls.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; d6 = $0000 for no flip, $0400 for horizontal flip
; a4 = pointer to angle buffer
; returns relevant block ID in (a1)
; returns distance to left/right in d1
; returns angle in (a4)
 
; loc_1EA58:
FindWall2:
    bsr.w   Find_Tile
    move.w  (a1),d0
    move.w  d0,d4
    andi.w  #$3FF,d0
    beq.s   loc_1EA6A
    btst    d5,d4
    bne.s   loc_1EA78
 
loc_1EA6A:
    move.w  #$F,d1
    move.w  d3,d0
    andi.w  #$F,d0
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1EA78:
    movea.l (Collision_addr).w,a2
    move.b  (a2,d0.w),d0
    andi.w  #$FF,d0
    beq.s   loc_1EA6A
    lea (ColCurveMap).l,a2
    move.b  (a2,d0.w),(a4)
    lsl.w   #4,d0
    move.w  d2,d1
    btst    #$B,d4
    beq.s   +
    not.w   d1
    addi.b  #$40,(a4)
    neg.b   (a4)
    subi.b  #$40,(a4)
+
    btst    #$A,d4
    beq.s   +
    neg.b   (a4)
+
    andi.w  #$F,d1
    add.w   d0,d1
    lea (ColArray2).l,a2
    move.b  (a2,d1.w),d0
    ext.w   d0
    eor.w   d6,d4
    btst    #$A,d4
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    beq.s   loc_1EA6A
    bmi.s   loc_1EAE0
    move.w  d3,d1
    andi.w  #$F,d1
    add.w   d1,d0
    move.w  #$F,d1
    sub.w   d0,d1
    rts
; ===========================================================================
 
loc_1EAE0:
    move.w  d3,d1
    andi.w  #$F,d1
    add.w   d1,d0
    bpl.w   loc_1EA6A
    not.w   d1
    rts
; End of function FindWall2
 
; ---------------------------------------------------------------------------
; Unused floor/wall subroutine - logs something to do with collision
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; return_1EAF0:
FloorLog_Unk:
    rts
; ---------------------------------------------------------------------------
    lea (ColArray).l,a1
    lea (ColArray).l,a2
 
    ; for d3 from 255 to 0
    move.w  #$FF,d3
-   moveq   #$10,d5
 
    ; for d2 from 15 to 0
    move.w  #$F,d2
-   moveq   #0,d4
 
    ; for d1 from 15 to 0
    move.w  #$F,d1
-   move.w  (a1)+,d0
    lsr.l   d5,d0
    addx.w  d4,d4
    dbf d1,- ; end for d1
 
    move.w  d4,(a2)+
    suba.w  #$20,a1
    subq.w  #1,d5
    dbf d2,-- ; end for d2
 
    adda.w  #$20,a1
    dbf d3,--- ; end for d3
 
    lea (ColArray).l,a1
    lea (ColArray2).l,a2
    bsr.s   FloorLog_Unk2
    lea (ColArray).l,a1
    lea (ColArray).l,a2
 
; End of function FloorLog_Unk
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EB46:
FloorLog_Unk2:
    move.w  #$FFF,d3
 
-   moveq   #0,d2
    move.w  #$F,d1
    move.w  (a1)+,d0
    beq.s   loc_1EB78
    bmi.s   ++
 
-   lsr.w   #1,d0
    bcc.s   +
    addq.b  #1,d2
+   dbf d1,-
 
    bra.s   loc_1EB7A
; ===========================================================================
+
    cmpi.w  #-1,d0
    beq.s   ++
 
-   lsl.w   #1,d0
    bcc.s   +
    subq.b  #1,d2
+   dbf d1,-
 
    bra.s   loc_1EB7A
; ===========================================================================
+
    move.w  #$10,d0
 
loc_1EB78:
    move.w  d0,d2
 
loc_1EB7A:
    move.b  d2,(a2)+
    dbf d3,---
 
    rts
 
; End of function FloorLog_Unk2
 
    if gameRevision<2
    nop
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to calculate how much space is in front of Sonic or Tails on the ground
; d0 = some input angle
; d1 = output about how many pixels (up to some high enough amount)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EB84: Sonic_WalkSpeed:
CalcRoomInFront:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  lrb_solid_bit(a0),d5            ; Want walls or ceilings
    move.l  x_pos(a0),d3
    move.l  y_pos(a0),d2
    move.w  x_vel(a0),d1
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d3
    move.w  y_vel(a0),d1
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d2
    swap    d2
    swap    d3
    move.b  d0,(Primary_Angle).w
    move.b  d0,(Secondary_Angle).w
    move.b  d0,d1
    addi.b  #$20,d0
    bpl.s   loc_1EBDC
 
    move.b  d1,d0
    bpl.s   +
    subq.b  #1,d0
+
    addi.b  #$20,d0
    bra.s   loc_1EBE6
; ---------------------------------------------------------------------------
loc_1EBDC:
    move.b  d1,d0
    bpl.s   +
    addq.b  #1,d0
+
    addi.b  #$1F,d0
 
loc_1EBE6:
    andi.b  #$C0,d0
    beq.w   CheckFloorDist_Part2        ; Player is going mostly down
    cmpi.b  #$80,d0
    beq.w   CheckCeilingDist_Part2      ; Player is going mostly up
    andi.b  #$38,d1
    bne.s   +
    addq.w  #8,d2
+
    cmpi.b  #$40,d0
    beq.w   CheckLeftWallDist_Part2     ; Player is going mostly left
    bra.w   CheckRightWallDist_Part2    ; Player is going mostly right
 
; End of function CalcRoomInFront
 
 
; ---------------------------------------------------------------------------
; Subroutine to calculate how much space is empty above Sonic's/Tails' head
; d0 = input angle perpendicular to the spine
; d1 = output about how many pixels are overhead (up to some high enough amount)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_1EC0A:
CalcRoomOverHead:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  lrb_solid_bit(a0),d5
    move.b  d0,(Primary_Angle).w
    move.b  d0,(Secondary_Angle).w
    addi.b  #$20,d0
    andi.b  #$C0,d0
    cmpi.b  #$40,d0
    beq.w   CheckLeftCeilingDist
    cmpi.b  #$80,d0
    beq.w   Sonic_CheckCeiling
    cmpi.b  #$C0,d0
    beq.w   CheckRightCeilingDist
 
; End of function CalcRoomOverHead
 
; ---------------------------------------------------------------------------
; Subroutine to check if Sonic/Tails is near the floor
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EC4E: Sonic_HitFloor:
Sonic_CheckFloor:
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    move.b  top_solid_bit(a0),d5
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindFloor
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindFloor
    move.w  (sp)+,d0
    move.b  #0,d2
 
loc_1ECC6:
    move.b  (Secondary_Angle).w,d3
    cmp.w   d0,d1
    ble.s   loc_1ECD4
    move.b  (Primary_Angle).w,d3
    exg d0,d1
 
loc_1ECD4:
    btst    #0,d3
    beq.s   +
    move.b  d2,d3
+
    rts
; ===========================================================================
 
    ; a bit of unused/dead code here
;CheckFloorDist:
    move.w  y_pos(a0),d2 ; a0=character
    move.w  x_pos(a0),d3
 
; Checks a 16x16 block to find solid ground. May check an additional
; 16x16 block up for ceilings.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in d3, or zero if angle was odd
;loc_1ECE6:
CheckFloorDist_Part2:
    addi.w  #$A,d2
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindFloor
    move.b  #0,d2
 
; d2 what to use as angle if (Primary_Angle).w is odd
; returns angle in d3, or value in d2 if angle was odd
loc_1ECFE:
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  d2,d3
+
    rts
; ===========================================================================
 
    ; Unused collision checking subroutine
 
    move.w  x_pos(a0),d3 ; a0=character
    move.w  y_pos(a0),d2
    subq.w  #4,d2
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$D,lrb_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    move.b  lrb_solid_bit(a0),d5
    bsr.w   FindFloor
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #0,d3
+
    rts
 
; ===========================================================================
; loc_1ED56:
ChkFloorEdge:
    move.w  x_pos(a0),d3
; loc_1ED5A:
ChkFloorEdge_Part2:
    move.w  y_pos(a0),d2
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a0)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    move.b  top_solid_bit(a0),d5
    bsr.w   FindFloor
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #0,d3
+
    rts
; ===========================================================================
; Identical to ChkFloorEdge except that this uses a1 instead of a0
;loc_1EDA8:
ChkFloorEdge2:
    move.w  x_pos(a1),d3
    move.w  y_pos(a1),d2
    moveq   #0,d0
    move.b  y_radius(a1),d0
    ext.w   d0
    add.w   d0,d2
    move.l  #Primary_Collision,(Collision_addr).w
    cmpi.b  #$C,top_solid_bit(a1)
    beq.s   +
    move.l  #Secondary_Collision,(Collision_addr).w
+
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    move.b  top_solid_bit(a1),d5
    bsr.w   FindFloor
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   return_1EDF8
    move.b  #0,d3
 
return_1EDF8:
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine checking if an object should interact with the floor
; (objects such as a monitor Sonic bumps from underneath)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EDFA: ObjHitFloor:
ObjCheckFloorDist:
    move.w  x_pos(a0),d3
    move.w  y_pos(a0),d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    moveq   #$C,d5
    bsr.w   FindFloor
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #0,d3
+
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Collision check used to let the HTZ boss fire attack to hit the ground
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EE30:
FireCheckFloorDist:
    move.w  x_pos(a1),d3
    move.w  y_pos(a1),d2
    move.b  y_radius(a1),d0
    ext.w   d0
    add.w   d0,d2
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    moveq   #$C,d5
    bra.w   FindFloor
; End of function FireCheckFloorDist
 
; ---------------------------------------------------------------------------
; Collision check used to let scattered rings bounce on the ground
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EE56:
RingCheckFloorDist:
    move.w  x_pos(a0),d3
    move.w  y_pos(a0),d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    moveq   #$C,d5
    bra.w   Ring_FindFloor
; End of function RingCheckFloorDist
 
; ---------------------------------------------------------------------------
; Stores a distance to the nearest wall above Sonic/Tails,
; where "above" = right, into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EE7C:
CheckRightCeilingDist:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindWall
    move.w  d1,-(sp)
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindWall
    move.w  (sp)+,d0
    move.b  #-$40,d2
    bra.w   loc_1ECC6
; End of function CheckRightCeilingDist
 
; ---------------------------------------------------------------------------
; Stores a distance to the nearest wall on the right of Sonic/Tails into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Checks a 16x16 block to find solid walls. May check an additional
; 16x16 block up for walls.
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in d3, or zero if angle was odd
; sub_1EEDC:
CheckRightWallDist:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
; loc_1EEE4:
CheckRightWallDist_Part2:
    addi.w  #$A,d3
    lea (Primary_Angle).w,a4
    movea.w #$10,a3
    move.w  #0,d6
    bsr.w   FindWall
    move.b  #-$40,d2
    bra.w   loc_1ECFE
; End of function CheckRightWallDist
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EF00: ObjCheckLeftWallDist:
ObjCheckRightWallDist:
    add.w   x_pos(a0),d3
    move.w  y_pos(a0),d2
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #$10,a3
    move.w  #0,d6
    moveq   #$D,d5
    bsr.w   FindWall
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #-$40,d3
+
    rts
; End of function ObjCheckRightWallDist
 
; ---------------------------------------------------------------------------
; Stores a distance from Sonic/Tails to the nearest ceiling into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EF2E: Sonic_DontRunOnWalls: CheckCeilingDist:
Sonic_CheckCeiling:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    eori.w  #$F,d2 ; flip position upside-down within the current 16x16 block?
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d3
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    bsr.w   FindFloor
    move.w  d1,-(sp)
 
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    eori.w  #$F,d2
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    lea (Secondary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    bsr.w   FindFloor
    move.w  (sp)+,d0
 
    move.b  #$80,d2
    bra.w   loc_1ECC6
; End of function Sonic_CheckCeiling
 
; ===========================================================================
    ; a bit of unused/dead code here
;CheckCeilingDist:
    move.w  y_pos(a0),d2 ; a0=character
    move.w  x_pos(a0),d3
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Checks a 16x16 block to find solid ceiling. May check an additional
; 16x16 block up for ceilings.
; d2 = y_pos
; d3 = x_pos
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in d3, or zero if angle was odd
; loc_1EF9E: CheckSlopeDist:
CheckCeilingDist_Part2:
    subi.w  #$A,d2
    eori.w  #$F,d2
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    bsr.w   FindFloor
    move.b  #$80,d2
    bra.w   loc_1ECFE
; End of function CheckCeilingDist
 
; ---------------------------------------------------------------------------
; Stores a distance to the nearest wall above the object into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EFBE: ObjHitCeiling:
ObjCheckCeilingDist:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    eori.w  #$F,d2
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$800,d6
    moveq   #$D,d5
    bsr.w   FindFloor
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #$80,d3
+
    rts
; End of function ObjCheckCeilingDist
 
; ---------------------------------------------------------------------------
; Stores a distance to the nearest wall above Sonic/Tails,
; where "above" = left, into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1EFF6:
CheckLeftCeilingDist:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    sub.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    eori.w  #$F,d3
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$400,d6
    bsr.w   FindWall
    move.w  d1,-(sp)
 
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
    moveq   #0,d0
    move.b  x_radius(a0),d0
    ext.w   d0
    add.w   d0,d2
    move.b  y_radius(a0),d0
    ext.w   d0
    sub.w   d0,d3
    eori.w  #$F,d3
    lea (Secondary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$400,d6
    bsr.w   FindWall
    move.w  (sp)+,d0
    move.b  #$40,d2
    bra.w   loc_1ECC6
; End of function CheckLeftCeilingDist
 
; ---------------------------------------------------------------------------
; Stores a distance to the nearest wall on the left of Sonic/Tails into d1
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; Checks a 16x16 block to find solid walls. May check an additional
; 16x16 block up for walls.
; d5 = ($c,$d) or ($e,$f) - solidity type bit (L/R/B or top)
; returns relevant block ID in (a1)
; returns distance in d1
; returns angle in d3, or zero if angle was odd
; loc_1F05E: Sonic_HitWall:
CheckLeftWallDist:
    move.w  y_pos(a0),d2
    move.w  x_pos(a0),d3
; loc_1F066:
CheckLeftWallDist_Part2:
    subi.w  #$A,d3
    eori.w  #$F,d3
    lea (Primary_Angle).w,a4
    movea.w #-$10,a3
    move.w  #$400,d6
    bsr.w   FindWall
    move.b  #$40,d2
    bra.w   loc_1ECFE
; End of function CheckLeftWallDist
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_1F086: ObjCheckRightWallDist:
ObjCheckLeftWallDist:
    add.w   x_pos(a0),d3
    move.w  y_pos(a0),d2
    ; Engine bug: colliding with left walls is erratic with this function.
    ; The cause is this: a missing instruction to flip collision on the found
    ; 16x16 block; this one:
    ;eori.w #$F,d3
    lea (Primary_Angle).w,a4
    move.b  #0,(a4)
    movea.w #-$10,a3
    move.w  #$400,d6
    moveq   #$D,d5
    bsr.w   FindWall
    move.b  (Primary_Angle).w,d3
    btst    #0,d3
    beq.s   +
    move.b  #$40,d3
+
    rts
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 79 - Star pole / starpost / checkpoint
; ----------------------------------------------------------------------------
; Sprite_1F0B4:
Obj79:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj79_Index(pc,d0.w),d1
    jmp Obj79_Index(pc,d1.w)
; ===========================================================================
; off_1F0C2: Obj79_States:
Obj79_Index:    offsetTable
        offsetTableEntry.w Obj79_Init       ; 0
        offsetTableEntry.w Obj79_Main       ; 2
        offsetTableEntry.w Obj79_Animate    ; 4
        offsetTableEntry.w Obj79_Dongle     ; 6
        offsetTableEntry.w Obj79_Star       ; 8
; ===========================================================================
; loc_1F0CC:
Obj79_Init:
    addq.b  #2,routine(a0) ; => Obj79_Main
    move.l  #Obj79_MapUnc_1F424,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Checkpoint,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo3_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #8,width_pixels(a0)
    move.b  #5,priority(a0)
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    bclr    #7,2(a2,d0.w)
    btst    #0,2(a2,d0.w)
    bne.s   loc_1F120
    move.b  (Last_star_pole_hit).w,d1
    andi.b  #$7F,d1
    move.b  subtype(a0),d2
    andi.b  #$7F,d2
    cmp.b   d2,d1
    blo.s   Obj79_Main
 
loc_1F120:
    bset    #0,2(a2,d0.w)
    move.b  #2,anim(a0)
 
; loc_1F12C:
Obj79_Main:
    tst.w   (Debug_placement_mode).w
    bne.w   Obj79_Animate
    lea (MainCharacter).w,a3 ; a3=character
    move.b  (Last_star_pole_hit).w,d1
    bsr.s   Obj79_CheckActivation
    tst.w   (Two_player_mode).w
    beq.w   Obj79_Animate
    lea (Sidekick).w,a3 ; a3=character
    move.b  (Last_star_pole_hit_2P).w,d1
    bsr.s   Obj79_CheckActivation
    bra.w   Obj79_Animate
; ---------------------------------------------------------------------------
; loc_1F154:
Obj79_CheckActivation:
    andi.b  #$7F,d1
    move.b  subtype(a0),d2
    andi.b  #$7F,d2
    cmp.b   d2,d1
    bhs.w   loc_1F222
    move.w  x_pos(a3),d0
    sub.w   x_pos(a0),d0
    addi_.w #8,d0
    cmpi.w  #$10,d0
    bhs.w   return_1F220
    move.w  y_pos(a3),d0
    sub.w   y_pos(a0),d0
    addi.w  #$40,d0
    cmpi.w  #$68,d0
    bhs.w   return_1F220
    move.w  #SndID_Checkpoint,d0 ; checkpoint ding-dong sound
    jsr (PlaySound).l
    jsr (SingleObjLoad).l
    bne.s   loc_1F206
    _move.b #ObjID_Starpost,id(a1) ; load obj79
    move.b  #6,routine(a1) ; => Obj79_Dongle
    move.w  x_pos(a0),objoff_30(a1)
    move.w  y_pos(a0),objoff_32(a1)
    subi.w  #$14,objoff_32(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #8,width_pixels(a1)
    move.b  #4,priority(a1)
    move.b  #2,mapping_frame(a1)
    move.w  #$20,objoff_36(a1)
    move.w  a0,parent(a1)
    tst.w   (Two_player_mode).w
    bne.s   loc_1F206
    cmpi.b  #7,(Emerald_count).w
    beq.s   loc_1F206
    cmpi.w  #50,(Ring_count).w
    blo.s   loc_1F206
    bsr.w   Obj79_MakeSpecialStars
 
loc_1F206:
    move.b  #1,anim(a0)
    bsr.w   Obj79_SaveData
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    bset    #0,2(a2,d0.w)
 
return_1F220:
    rts
; ===========================================================================
 
loc_1F222:
    tst.b   anim(a0)
    bne.s   return_1F22E
    move.b  #2,anim(a0)
 
return_1F22E:
    rts
; ===========================================================================
; loc_1F230:
Obj79_Animate:
    lea (Ani_obj79).l,a1
    jsrto   (AnimateSprite).l, JmpTo2_AnimateSprite
    jmp (MarkObjGone).l
; ===========================================================================
; loc_1F240:
Obj79_Dongle:
    subq.w  #1,objoff_36(a0)
    bpl.s   Obj79_MoveDonglyThing
    movea.w parent(a0),a1 ; a1=object
    cmpi.b  #ObjID_Starpost,id(a1)
    bne.s   +
    move.b  #2,anim(a1)
    move.b  #0,mapping_frame(a1)
+
    jmp (DeleteObject).l
; ===========================================================================
; loc_1F262:
Obj79_MoveDonglyThing:
    move.b  angle(a0),d0
    subi.b  #$10,angle(a0)
    subi.b  #$40,d0
    jsr (CalcSine).l
    muls.w  #$C00,d1
    swap    d1
    add.w   objoff_30(a0),d1
    move.w  d1,x_pos(a0)
    muls.w  #$C00,d0
    swap    d0
    add.w   objoff_32(a0),d0
    move.w  d0,y_pos(a0)
    jmp (MarkObjGone).l
; ===========================================================================
; hit a starpost / save checkpoint
; loc_1F298:
Obj79_SaveData:
    cmpa.w  #MainCharacter,a3   ; is it player 1?
    bne.w   Obj79_SaveDataPlayer2   ; if not, branch
    move.b  subtype(a0),(Last_star_pole_hit).w
    move.b  (Last_star_pole_hit).w,(Saved_Last_star_pole_hit).w
    move.w  x_pos(a0),(Saved_x_pos).w
    move.w  y_pos(a0),(Saved_y_pos).w
    move.w  (MainCharacter+art_tile).w,(Saved_art_tile).w
    move.w  (MainCharacter+top_solid_bit).w,(Saved_Solid_bits).w
    move.w  (Ring_count).w,(Saved_Ring_count).w
    move.b  (Extra_life_flags).w,(Saved_Extra_life_flags).w
    move.l  (Timer).w,(Saved_Timer).w
    move.b  (Dynamic_Resize_Routine).w,(Saved_Dynamic_Resize_Routine).w
    move.w  (Camera_Max_Y_pos_now).w,(Saved_Camera_Max_Y_pos).w
    move.w  (Camera_X_pos).w,(Saved_Camera_X_pos).w
    move.w  (Camera_Y_pos).w,(Saved_Camera_Y_pos).w
    move.w  (Camera_BG_X_pos).w,(Saved_Camera_BG_X_pos).w
    move.w  (Camera_BG_Y_pos).w,(Saved_Camera_BG_Y_pos).w
    move.w  (Camera_BG2_X_pos).w,(Saved_Camera_BG2_X_pos).w
    move.w  (Camera_BG2_Y_pos).w,(Saved_Camera_BG2_Y_pos).w
    move.w  (Camera_BG3_X_pos).w,(Saved_Camera_BG3_X_pos).w
    move.w  (Camera_BG3_Y_pos).w,(Saved_Camera_BG3_Y_pos).w
    move.w  (Water_Level_2).w,(Saved_Water_Level).w
    move.b  (Water_routine).w,(Saved_Water_routine).w
    move.b  (Water_fullscreen_flag).w,(Saved_Water_move).w
    rts
; ===========================================================================
; second player hit a checkpoint in 2-player mode
; loc_1F326:
Obj79_SaveDataPlayer2:
    move.b  subtype(a0),(Last_star_pole_hit_2P).w
    move.b  (Last_star_pole_hit_2P).w,(Saved_Last_star_pole_hit_2P).w
    move.w  x_pos(a0),(Saved_x_pos_2P).w
    move.w  y_pos(a0),(Saved_y_pos_2P).w
    move.w  (Sidekick+art_tile).w,(Saved_art_tile_2P).w
    move.w  (Sidekick+top_solid_bit).w,(Saved_Solid_bits_2P).w
    move.w  (Ring_count_2P).w,(Saved_Ring_count_2P).w
    move.b  (Extra_life_flags_2P).w,(Saved_Extra_life_flags_2P).w
    move.l  (Timer_2P).w,(Saved_Timer_2P).w
    rts
; ===========================================================================
; continue from a starpost / load checkpoint
; loc_1F35E:
Obj79_LoadData:
    move.b  (Saved_Last_star_pole_hit).w,(Last_star_pole_hit).w
    move.w  (Saved_x_pos).w,(MainCharacter+x_pos).w
    move.w  (Saved_y_pos).w,(MainCharacter+y_pos).w
    move.w  (Saved_Ring_count).w,(Ring_count).w
    move.b  (Saved_Extra_life_flags).w,(Extra_life_flags).w
    clr.w   (Ring_count).w
    clr.b   (Extra_life_flags).w
    move.l  (Saved_Timer).w,(Timer).w
    move.b  #59,(Timer_frame).w
    subq.b  #1,(Timer_second).w
    move.w  (Saved_art_tile).w,(MainCharacter+art_tile).w
    move.w  (Saved_Solid_bits).w,(MainCharacter+top_solid_bit).w
    move.b  (Saved_Dynamic_Resize_Routine).w,(Dynamic_Resize_Routine).w
    move.b  (Saved_Water_routine).w,(Water_routine).w
    move.w  (Saved_Camera_Max_Y_pos).w,(Camera_Max_Y_pos_now).w
    move.w  (Saved_Camera_Max_Y_pos).w,(Camera_Max_Y_pos).w
    move.w  (Saved_Camera_X_pos).w,(Camera_X_pos).w
    move.w  (Saved_Camera_Y_pos).w,(Camera_Y_pos).w
    move.w  (Saved_Camera_BG_X_pos).w,(Camera_BG_X_pos).w
    move.w  (Saved_Camera_BG_Y_pos).w,(Camera_BG_Y_pos).w
    move.w  (Saved_Camera_BG2_X_pos).w,(Camera_BG2_X_pos).w
    move.w  (Saved_Camera_BG2_Y_pos).w,(Camera_BG2_Y_pos).w
    move.w  (Saved_Camera_BG3_X_pos).w,(Camera_BG3_X_pos).w
    move.w  (Saved_Camera_BG3_Y_pos).w,(Camera_BG3_Y_pos).w
    tst.b   (Water_flag).w  ; does the level have water?
    beq.s   +       ; if not, branch to skip loading water stuff
    move.w  (Saved_Water_Level).w,(Water_Level_2).w
    move.b  (Saved_Water_routine).w,(Water_routine).w
    move.b  (Saved_Water_move).w,(Water_fullscreen_flag).w
+
    tst.b   (Last_star_pole_hit).w
    bpl.s   return_1F412
    move.w  (Saved_x_pos).w,d0
    subi.w  #$A0,d0
    move.w  d0,(Camera_Min_X_pos).w
 
return_1F412:
    rts
; ===========================================================================
; animation script
; off_1F414:
Ani_obj79:  offsetTable
        offsetTableEntry.w byte_1F41A   ; 0
        offsetTableEntry.w byte_1F41D   ; 1
        offsetTableEntry.w byte_1F420   ; 2
byte_1F41A:
    dc.b  $F,  0,$FF
    rev02even
byte_1F41D:
    dc.b  $F,  1,$FF
    rev02even
byte_1F420:
    dc.b   3,  0,  4,$FF
    even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj79_MapUnc_1F424: BINCLUDE "mappings/sprite/obj79_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj79_MapUnc_1F4A0: BINCLUDE "mappings/sprite/obj79_b.bin"
; ===========================================================================
 
; loc_1F4C4:
Obj79_MakeSpecialStars:
    moveq   #4-1,d1 ; execute the loop 4 times (1 for each star)
    moveq   #0,d2
 
-   bsr.w   SingleObjLoad2
    bne.s   +   ; rts
    _move.b id(a0),id(a1) ; load obj79
    move.l  #Obj79_MapUnc_1F4A0,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Checkpoint,0,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #8,routine(a1) ; => Obj79_Star
    move.w  x_pos(a0),d0
    move.w  d0,x_pos(a1)
    move.w  d0,objoff_30(a1)
    move.w  y_pos(a0),d0
    subi.w  #$30,d0
    move.w  d0,y_pos(a1)
    move.w  d0,objoff_32(a1)
    move.b  priority(a0),priority(a1)
    move.b  #8,width_pixels(a1)
    move.b  #1,mapping_frame(a1)
    move.w  #-$400,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.w  d2,objoff_34(a1) ; set the angle
    addi.w  #$40,d2 ; increase the angle for next time
    dbf d1,- ; loop
+
    rts
; ===========================================================================
; loc_1F536:
Obj79_Star:
    move.b  collision_property(a0),d0
    beq.w   loc_1F554
    andi.b  #1,d0
    beq.s   +
    move.b  #1,(SpecialStage_flag_2P).w
    move.b  #GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
+
    clr.b   collision_property(a0)
 
loc_1F554:
    addi.w  #$A,objoff_34(a0)
    move.w  objoff_34(a0),d0
    andi.w  #$FF,d0
    jsr (CalcSine).l
    asr.w   #5,d0
    asr.w   #3,d1
    move.w  d1,d3
    move.w  objoff_34(a0),d2
    andi.w  #$3E0,d2
    lsr.w   #5,d2
    moveq   #2,d5
    moveq   #0,d4
    cmpi.w  #$10,d2
    ble.s   +
    neg.w   d1
+
    andi.w  #$F,d2
    cmpi.w  #8,d2
    ble.s   loc_1F594
    neg.w   d2
    andi.w  #7,d2
 
loc_1F594:
    lsr.w   #1,d2
    beq.s   +
    add.w   d1,d4
+
    asl.w   #1,d1
    dbf d5,loc_1F594
 
    asr.w   #4,d4
    add.w   d4,d0
    addq.w  #1,objoff_36(a0)
    move.w  objoff_36(a0),d1
    cmpi.w  #$80,d1
    beq.s   loc_1F5BE
    bgt.s   loc_1F5C4
 
loc_1F5B4:
    muls.w  d1,d0
    muls.w  d1,d3
    asr.w   #7,d0
    asr.w   #7,d3
    bra.s   loc_1F5D6
; ===========================================================================
 
loc_1F5BE:
    move.b  #$D8,collision_flags(a0)
 
loc_1F5C4:
    cmpi.w  #$180,d1
    ble.s   loc_1F5D6
    neg.w   d1
    addi.w  #$200,d1
    bmi.w   JmpTo10_DeleteObject
    bra.s   loc_1F5B4
; ===========================================================================
 
loc_1F5D6:
    move.w  objoff_30(a0),d2
    add.w   d3,d2
    move.w  d2,x_pos(a0)
    move.w  objoff_32(a0),d2
    add.w   d0,d2
    move.w  d2,y_pos(a0)
    addq.b  #1,anim_frame(a0)
    move.b  anim_frame(a0),d0
    andi.w  #6,d0
    lsr.w   #1,d0
    cmpi.b  #3,d0
    bne.s   +
    moveq   #1,d0
+
    move.b  d0,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo_MarkObjGone
; ===========================================================================
 
JmpTo10_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo2_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo3_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7D - Points that can be gotten at the end of an act (leftover from S1)  (unused)
; ----------------------------------------------------------------------------
; Sprite_1F624:
Obj7D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7D_Index(pc,d0.w),d1
    jmp Obj7D_Index(pc,d1.w)
; ===========================================================================
; off_1F632: Obj7D_States:
Obj7D_Index:    offsetTable
        offsetTableEntry.w Obj7D_Init   ; 0
        offsetTableEntry.w Obj7D_Main   ; 2
; ===========================================================================
; loc_1F636:
Obj7D_Init:
    moveq   #$10,d2
    move.w  d2,d3
    add.w   d3,d3
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d2,d0
    cmp.w   d3,d0
    bhs.s   Obj7D_NoAdd
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    add.w   d2,d1
    cmp.w   d3,d1
    bhs.s   Obj7D_NoAdd
    tst.w   (Debug_placement_mode).w
    bne.s   Obj7D_NoAdd
    tst.b   (SpecialStage_flag_2P).w
    bne.s   Obj7D_NoAdd
    addq.b  #2,routine(a0)
    move.l  #Obj7D_MapUnc_1F6FE,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_EndPoints,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo4_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #0,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.b  subtype(a0),mapping_frame(a0)
    move.w  #$77,objoff_30(a0)
    move.w  #SndID_Bonus,d0
    jsr (PlaySound).l
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.w  word_1F6D2(pc,d0.w),d0
    jsr (AddPoints).l
 
Obj7D_NoAdd:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   JmpTo11_DeleteObject
    rts
; ===========================================================================
 
JmpTo11_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
word_1F6D2:
    dc.w     0
    dc.w  1000  ; 1
    dc.w   100  ; 2
    dc.w     1  ; 3
; ===========================================================================
; loc_1F6DA:
Obj7D_Main:
    subq.w  #1,objoff_30(a0)
    bmi.s   JmpTo12_DeleteObject
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   JmpTo12_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo12_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; -------------------------------------------------------------------------------
; Unused sprite mappings
; -------------------------------------------------------------------------------
Obj7D_MapUnc_1F6FE: BINCLUDE "mappings/sprite/obj7D.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo4_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 44 - Round bumper from Casino Night Zone
; ----------------------------------------------------------------------------
; Sprite_1F730:
Obj44:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj44_Index(pc,d0.w),d1
    jmp Obj44_Index(pc,d1.w)
; ===========================================================================
; off_1F73E: Obj44_States:
Obj44_Index:    offsetTable
        offsetTableEntry.w Obj44_Init   ; 0
        offsetTableEntry.w Obj44_Main   ; 2
; ===========================================================================
; loc_1F742:
Obj44_Init:
    addq.b  #2,routine(a0) ; => Obj44_Main
    move.l  #Obj44_MapUnc_1F85A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZRoundBumper,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo5_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  #$D7,collision_flags(a0)
 
; loc_1F770:
Obj44_Main:
    move.b  collision_property(a0),d0
    beq.w   loc_1F83E
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #0,collision_property(a0)
    beq.s   +
    bsr.s   Obj44_BumpCharacter
+
    lea (Sidekick).w,a1 ; a1=character
    bclr    #1,collision_property(a0)
    beq.s   +
    bsr.s   Obj44_BumpCharacter
+
    clr.b   collision_property(a0)
    bra.w   loc_1F83E
; ===========================================================================
; loc_1F79C:
Obj44_BumpCharacter:
    move.w  x_pos(a0),d1
    move.w  y_pos(a0),d2
    sub.w   x_pos(a1),d1
    sub.w   y_pos(a1),d2
    jsr (CalcAngle).l
    move.b  (Timer_frames).w,d1
    andi.w  #3,d1
    add.w   d1,d0
    jsr (CalcSine).l
    muls.w  #-$700,d1
    asr.l   #8,d1
    move.w  d1,x_vel(a1)
    muls.w  #-$700,d0
    asr.l   #8,d0
    move.w  d0,y_vel(a1)
    bset    #1,status(a1)
    bclr    #4,status(a1)
    bclr    #5,status(a1)
    clr.b   jumping(a1)
    move.b  #1,anim(a0)
    move.w  #SndID_Bumper,d0
    jsr (PlaySound).l
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    cmpi.b  #$8A,2(a2,d0.w)
    bhs.s   return_1F83C
    addq.b  #1,2(a2,d0.w)
+
    moveq   #1,d0
    movea.w a1,a3
    jsr (AddPoints2).l
    bsr.w   SingleObjLoad
    bne.s   return_1F83C
    _move.b #ObjID_Points,id(a1) ; load obj29
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #4,mapping_frame(a1)
 
return_1F83C:
    rts
; ===========================================================================
 
loc_1F83E:
    lea (Ani_obj44).l,a1
    jsrto   (AnimateSprite).l, JmpTo3_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo2_MarkObjGone
; ===========================================================================
; animation script
; off_1F84C:
Ani_obj44:  offsetTable
        offsetTableEntry.w byte_1F850   ; 0
        offsetTableEntry.w byte_1F853   ; 1
byte_1F850: dc.b  $F,  0,$FF
        rev02even
byte_1F853: dc.b   3,  1,  0,  1,$FD,  0
        even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj44_MapUnc_1F85A: BINCLUDE "mappings/sprite/obj44.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo3_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo5_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 24 - Bubbles in Aquatic Ruin Zone
; ----------------------------------------------------------------------------
; Sprite_1F8A8:
Obj24:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj24_Index(pc,d0.w),d1
    jmp Obj24_Index(pc,d1.w)
; ===========================================================================
; off_1F8B6:
Obj24_Index:    offsetTable
        offsetTableEntry.w Obj24_Init               ;  0
        offsetTableEntry.w loc_1F924                ;  2
        offsetTableEntry.w loc_1F93E                ;  4
        offsetTableEntry.w loc_1F99E                ;  6
        offsetTableEntry.w BranchTo_JmpTo15_DeleteObject    ;  8
        offsetTableEntry.w loc_1F9C0                ; $A
; ===========================================================================
; loc_1F8C2:
Obj24_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj24_MapUnc_1FBF6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BigBubbles,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo6_Adjust2PArtPointer
    move.b  #$84,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  subtype(a0),d0
    bpl.s   loc_1F90A
    addq.b  #8,routine(a0)
    andi.w  #$7F,d0
    move.b  d0,objoff_32(a0)
    move.b  d0,objoff_33(a0)
    move.b  #6,anim(a0)
    bra.w   loc_1F9C0
; ===========================================================================
 
loc_1F90A:
    move.b  d0,anim(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  #-$88,y_vel(a0)
    jsr (RandomNumber).l
    move.b  d0,angle(a0)
 
loc_1F924:
    lea (Ani_obj24).l,a1
    jsr (AnimateSprite).l
    cmpi.b  #6,mapping_frame(a0)
    bne.s   loc_1F93E
    move.b  #1,objoff_2E(a0)
 
loc_1F93E:
 
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0
    blo.s   loc_1F956
    move.b  #6,routine(a0)
    addq.b  #3,anim(a0)
    bra.w   loc_1F99E
; ===========================================================================
 
loc_1F956:
    move.b  angle(a0),d0
    addq.b  #1,angle(a0)
    andi.w  #$7F,d0
    lea (Obj0A_WobbleData).l,a1
    move.b  (a1,d0.w),d0
    ext.w   d0
    add.w   objoff_30(a0),d0
    move.w  d0,x_pos(a0)
    tst.b   objoff_2E(a0)
    beq.s   loc_1F988
    bsr.w   loc_1FB02
    cmpi.b  #6,routine(a0)
    beq.s   loc_1F99E
 
loc_1F988:
    jsrto   (ObjectMove).l, JmpTo3_ObjectMove
    tst.b   render_flags(a0)
    bpl.s   JmpTo13_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo13_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
loc_1F99E:
 
    lea (Ani_obj24).l,a1
    jsr (AnimateSprite).l
    tst.b   render_flags(a0)
    bpl.s   JmpTo14_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo14_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
    if removeJmpTos
JmpTo15_DeleteObject 
    endif
 
BranchTo_JmpTo15_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo15_DeleteObject
; ===========================================================================
 
loc_1F9C0:
 
    tst.w   objoff_36(a0)
    bne.s   loc_1FA22
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0
    bhs.w   loc_1FACE
    tst.b   render_flags(a0)
    bpl.w   loc_1FACE
    subq.w  #1,objoff_38(a0)
    bpl.w   loc_1FAC2
    move.w  #1,objoff_36(a0)
 
loc_1F9E8:
    jsr (RandomNumber).l
    move.w  d0,d1
    andi.w  #7,d0
    cmpi.w  #6,d0
    bhs.s   loc_1F9E8
    move.b  d0,objoff_34(a0)
    andi.w  #$C,d1
    lea (byte_1FAF0).l,a1
    adda.w  d1,a1
    move.l  a1,objoff_3C(a0)
    subq.b  #1,objoff_32(a0)
    bpl.s   BranchTo_loc_1FA2A
    move.b  objoff_33(a0),objoff_32(a0)
    bset    #7,objoff_36(a0)
 
BranchTo_loc_1FA2A 
    bra.s   loc_1FA2A
; ===========================================================================
 
loc_1FA22:
    subq.w  #1,objoff_38(a0)
    bpl.w   loc_1FAC2
 
loc_1FA2A:
    jsr (RandomNumber).l
    andi.w  #$1F,d0
    move.w  d0,objoff_38(a0)
    bsr.w   SingleObjLoad
    bne.s   loc_1FAA6
    _move.b id(a0),id(a1) ; load obj24
    move.w  x_pos(a0),x_pos(a1)
    jsr (RandomNumber).l
    andi.w  #$F,d0
    subq.w  #8,d0
    add.w   d0,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    moveq   #0,d0
    move.b  objoff_34(a0),d0
    movea.l objoff_3C(a0),a2 ; a2=object
    move.b  (a2,d0.w),subtype(a1)
    btst    #7,objoff_36(a0)
    beq.s   loc_1FAA6
    jsr (RandomNumber).l
    andi.w  #3,d0
    bne.s   loc_1FA92
    bset    #6,objoff_36(a0)
    bne.s   loc_1FAA6
    move.b  #2,subtype(a1)
 
loc_1FA92:
    tst.b   objoff_34(a0)
    bne.s   loc_1FAA6
    bset    #6,objoff_36(a0)
    bne.s   loc_1FAA6
    move.b  #2,subtype(a1)
 
loc_1FAA6:
    subq.b  #1,objoff_34(a0)
    bpl.s   loc_1FAC2
    jsr (RandomNumber).l
    andi.w  #$7F,d0
    addi.w  #$80,d0
    add.w   d0,objoff_38(a0)
    clr.w   objoff_36(a0)
 
loc_1FAC2:
    lea (Ani_obj24).l,a1
    jsr (AnimateSprite).l
 
loc_1FACE:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo15_DeleteObject
    move.w  (Water_Level_1).w,d0
    cmp.w   y_pos(a0),d0
    blo.w   JmpTo7_DisplaySprite
    rts
 
    if removeJmpTos
JmpTo7_DisplaySprite 
    jmp (DisplaySprite).l
    endif
; ===========================================================================
byte_1FAF0:
    dc.b   0
    dc.b   1    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   0    ; 4
    dc.b   0    ; 5
    dc.b   1    ; 6
    dc.b   0    ; 7
    dc.b   0    ; 8
    dc.b   0    ; 9
    dc.b   0    ; 10
    dc.b   1    ; 11
    dc.b   0    ; 12
    dc.b   1    ; 13
    dc.b   0    ; 14
    dc.b   0    ; 15
    dc.b   1    ; 16
    dc.b   0    ; 17
; ===========================================================================
 
loc_1FB02:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_1FB0C
    lea (Sidekick).w,a1 ; a1=character
 
loc_1FB0C:
    tst.b   obj_control(a1)
    bmi.w   return_1FBCA
    move.w  x_pos(a1),d0
    move.w  x_pos(a0),d1
    subi.w  #$10,d1
    cmp.w   d0,d1
    bhs.w   return_1FBCA
    addi.w  #$20,d1
    cmp.w   d0,d1
    blo.w   return_1FBCA
    move.w  y_pos(a1),d0
    move.w  y_pos(a0),d1
    cmp.w   d0,d1
    bhs.w   return_1FBCA
    addi.w  #$10,d1
    cmp.w   d0,d1
    blo.w   return_1FBCA
    bsr.w   ResumeMusic
    move.w  #SndID_InhalingBubble,d0
    jsr (PlaySound).l
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    move.b  #AniIDSonAni_Bubble,anim(a1)
    move.w  #$23,move_lock(a1)
    move.b  #0,jumping(a1)
    bclr    #5,status(a1)
    bclr    #4,status(a1)
    btst    #2,status(a1)
    beq.w   loc_1FBB8
    cmpi.b  #1,(a1)
    bne.s   loc_1FBA8
    bclr    #2,status(a1)
    move.b  #$13,y_radius(a1)
    move.b  #9,x_radius(a1)
    subq.w  #5,y_pos(a1)
    bra.s   loc_1FBB8
; ===========================================================================
 
loc_1FBA8:
    move.b  #$F,y_radius(a1)
    move.b  #9,x_radius(a1)
    subq.w  #1,y_pos(a1)
 
loc_1FBB8:
    cmpi.b  #6,routine(a0)
    beq.s   return_1FBCA
    move.b  #6,routine(a0)
    addq.b  #3,anim(a0)
 
return_1FBCA:
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite animations
; -------------------------------------------------------------------------------
; animation script
; off_1FBCC:
Ani_obj24:  offsetTable
        offsetTableEntry.w byte_1FBDA   ; 0
        offsetTableEntry.w byte_1FBDF   ; 1
        offsetTableEntry.w byte_1FBE5   ; 2
        offsetTableEntry.w byte_1FBEC   ; 3
        offsetTableEntry.w byte_1FBEC   ; 4
        offsetTableEntry.w byte_1FBEE   ; 5
        offsetTableEntry.w byte_1FBF2   ; 6
byte_1FBDA: dc.b  $E,  0,  1,  2,$FC
        rev02even
byte_1FBDF: dc.b  $E,  1,  2,  3,  4,$FC
        rev02even
byte_1FBE5: dc.b  $E,  2,  3,  4,  5,  6,$FC
        rev02even
byte_1FBEC: dc.b   4,$FC
        rev02even
byte_1FBEE: dc.b   4,  6,  7,$FC
        rev02even
byte_1FBF2: dc.b  $F, $E, $F,$FF
        even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj24_MapUnc_1FBF6: offsetTable
    offsetTableEntry.w word_1FC3A   ;   0
    offsetTableEntry.w word_1FC44   ;   1
    offsetTableEntry.w word_1FC44   ;   2
    offsetTableEntry.w word_1FC4E   ;   3
    offsetTableEntry.w word_1FC58   ;   4
    offsetTableEntry.w word_1FC62   ;   5
    offsetTableEntry.w word_1FC6C   ;   6
    offsetTableEntry.w word_1FC76   ;   7
    offsetTableEntry.w word_1FC98   ;   8
    offsetTableEntry.w word_1FC98   ;   9
    offsetTableEntry.w word_1FC98   ;  $A
    offsetTableEntry.w word_1FC98   ;  $B
    offsetTableEntry.w word_1FC98   ;  $C
    offsetTableEntry.w word_1FC98   ;  $D
    offsetTableEntry.w word_1FCA2   ;  $E
    offsetTableEntry.w word_1FCAC   ;  $F
    offsetTableEntry.w word_1FCB6   ; $10
; -------------------------------------------------------------------------------
; sprite mappings
; merged with the above mappings, can't split to file in a useful way...
; -------------------------------------------------------------------------------
Obj24_MapUnc_1FC18: offsetTable
    offsetTableEntry.w word_1FC3A   ;   0
    offsetTableEntry.w word_1FC44   ;   1
    offsetTableEntry.w word_1FC44   ;   2
    offsetTableEntry.w word_1FC4E   ;   3
    offsetTableEntry.w word_1FC58   ;   4
    offsetTableEntry.w word_1FC62   ;   5
    offsetTableEntry.w word_1FC6C   ;   6
    offsetTableEntry.w word_1FC76   ;   7
    offsetTableEntry.w word_1FCB8   ;   8
    offsetTableEntry.w word_1FCB8   ;   9
    offsetTableEntry.w word_1FCB8   ;  $A
    offsetTableEntry.w word_1FCB8   ;  $B
    offsetTableEntry.w word_1FCB8   ;  $C
    offsetTableEntry.w word_1FCB8   ;  $D
    offsetTableEntry.w word_1FCA2   ;  $E
    offsetTableEntry.w word_1FCAC   ;  $F
    offsetTableEntry.w word_1FCB6   ; $10
word_1FC3A:                          
    dc.w    1
    dc.w    $FC00, $008D, $0046, $FFFC
word_1FC44:
    dc.w    1
    dc.w    $FC00, $008E, $0047, $FFFC
word_1FC4E:
    dc.w    1
    dc.w    $F805, $008F, $0047, $FFF8
word_1FC58:
    dc.w    1
    dc.w    $F805, $0093, $0049, $FFF8
word_1FC62:
    dc.w    1
    dc.w    $F40A, $001C, $000E, $FFF4
word_1FC6C:
    dc.w    1
    dc.w    $F00F, $0008, $0004, $FFF0
word_1FC76:
    dc.w    4
    dc.w    $F005, $0018, $000C, $FFF0
    dc.w    $F005, $0818, $080C, $0000
    dc.w    $0005, $1018, $100C, $FFF0
    dc.w    $0005, $1818, $180C, $0000
word_1FC98:
    dc.w    1
    dc.w    $F406, $1F41, $1BA0, $FFF8
word_1FCA2:
    dc.w    1
    dc.w    $F805, $0000, $0000, $FFF8
word_1FCAC:
    dc.w    1
    dc.w    $F805, $0004, $0002, $FFF8
word_1FCB6:
    dc.w    0
word_1FCB8:
    dc.w    1
    dc.w    $F406, $1F31, $1B98, $FFF8
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo7_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo15_DeleteObject 
    jmp (DeleteObject).l
JmpTo6_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
; loc_1FCD6:
JmpTo3_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 03 - Collision plane/layer switcher
; ----------------------------------------------------------------------------
; Sprite_1FCDC:
Obj03:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj03_Index(pc,d0.w),d1
    jsr Obj03_Index(pc,d1.w)
    jmp (MarkObjGone3).l
; ===========================================================================
; off_1FCF0:
Obj03_Index:    offsetTable
        offsetTableEntry.w Obj03_Init   ; 0
        offsetTableEntry.w Obj03_MainX  ; 2
        offsetTableEntry.w Obj03_MainY  ; 4
; ===========================================================================
; loc_1FCF6:
Obj03_Init:
    addq.b  #2,routine(a0) ; => Obj03_MainX
    move.l  #Obj03_MapUnc_1FFB8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo7_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #5,priority(a0)
    move.b  subtype(a0),d0
    btst    #2,d0
    beq.s   Obj03_Init_CheckX
;Obj03_Init_CheckY:
    addq.b  #2,routine(a0) ; => Obj03_MainY
    andi.w  #7,d0
    move.b  d0,mapping_frame(a0)
    andi.w  #3,d0
    add.w   d0,d0
    move.w  word_1FD68(pc,d0.w),objoff_32(a0)
    move.w  y_pos(a0),d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.w   y_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_34(a0)
+
    lea (Sidekick).w,a1 ; a1=character
    cmp.w   y_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_35(a0)
+
    bra.w   Obj03_MainY
; ===========================================================================
word_1FD68:
    dc.w   $20
    dc.w   $40  ; 1
    dc.w   $80  ; 2
    dc.w  $100  ; 3
; ===========================================================================
; loc_1FD70:
Obj03_Init_CheckX:
    andi.w  #3,d0
    move.b  d0,mapping_frame(a0)
    add.w   d0,d0
    move.w  word_1FD68(pc,d0.w),objoff_32(a0)
    move.w  x_pos(a0),d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_34(a0)
+
    lea (Sidekick).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_35(a0)
+
 
; loc_1FDA4:
Obj03_MainX:
    tst.w   (Debug_placement_mode).w
    bne.w   return_1FEAC
    move.w  x_pos(a0),d1
    lea objoff_34(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
 
+   tst.b   (a2)+
    bne.s   Obj03_MainX_Alt
    cmp.w   x_pos(a1),d1
    bhi.w   return_1FEAC
    move.b  #1,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blt.w   return_1FEAC
    cmp.w   d3,d4
    bge.w   return_1FEAC
    move.b  subtype(a0),d0
    bpl.s   +
    btst    #1,status(a1)
    bne.w   return_1FEAC
+
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
    btst    #3,d0
    beq.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    andi.w  #drawing_mask,art_tile(a1)
    btst    #5,d0
    beq.s   return_1FEAC
    ori.w   #high_priority,art_tile(a1)
    bra.s   return_1FEAC
; ===========================================================================
; loc_1FE38:
Obj03_MainX_Alt:
    cmp.w   x_pos(a1),d1
    bls.w   return_1FEAC
    move.b  #0,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blt.w   return_1FEAC
    cmp.w   d3,d4
    bge.w   return_1FEAC
    move.b  subtype(a0),d0
    bpl.s   +
    btst    #1,status(a1)
    bne.w   return_1FEAC
+
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
    btst    #4,d0
    beq.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    andi.w  #drawing_mask,art_tile(a1)
    btst    #6,d0
    beq.s   return_1FEAC
    ori.w   #high_priority,art_tile(a1)
 
return_1FEAC:
    rts
; ===========================================================================
 
Obj03_MainY:
    tst.w   (Debug_placement_mode).w
    bne.w   return_1FFB6
    move.w  y_pos(a0),d1
    lea objoff_34(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
 
+   tst.b   (a2)+
    bne.s   Obj03_MainY_Alt
    cmp.w   y_pos(a1),d1
    bhi.w   return_1FFB6
    move.b  #1,-1(a2)
    move.w  x_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  x_pos(a1),d4
    cmp.w   d2,d4
    blt.w   return_1FFB6
    cmp.w   d3,d4
    bge.w   return_1FFB6
    move.b  subtype(a0),d0
    bpl.s   +
    btst    #1,status(a1)
    bne.w   return_1FFB6
+
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
    btst    #3,d0
    beq.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    andi.w  #drawing_mask,art_tile(a1)
    btst    #5,d0
    beq.s   return_1FFB6
    ori.w   #high_priority,art_tile(a1)
    bra.s   return_1FFB6
; ===========================================================================
; loc_1FF42:
Obj03_MainY_Alt:
    cmp.w   y_pos(a1),d1
    bls.w   return_1FFB6
    move.b  #0,-1(a2)
    move.w  x_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  x_pos(a1),d4
    cmp.w   d2,d4
    blt.w   return_1FFB6
    cmp.w   d3,d4
    bge.w   return_1FFB6
    move.b  subtype(a0),d0
    bpl.s   +
    btst    #1,status(a1)
    bne.w   return_1FFB6
+
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
    btst    #4,d0
    beq.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    andi.w  #drawing_mask,art_tile(a1)
    btst    #6,d0
    beq.s   return_1FFB6
    ori.w   #high_priority,art_tile(a1)
 
return_1FFB6:
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj03_MapUnc_1FFB8: BINCLUDE "mappings/sprite/obj03.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo7_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 0B - Section of pipe that tips you off from CPZ
; ----------------------------------------------------------------------------
; Sprite_2009C:
Obj0B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0B_Index(pc,d0.w),d1
    jmp Obj0B_Index(pc,d1.w)
; ===========================================================================
; off_200AA:
Obj0B_Index:    offsetTable
        offsetTableEntry.w Obj0B_Init   ; 0
        offsetTableEntry.w loc_20104    ; 2
        offsetTableEntry.w loc_20112    ; 4
; ===========================================================================
 
obj0B_duration_current = objoff_30
obj0B_duration_initial = objoff_32
obj0B_delay = objoff_36
 
; loc_200B0:
Obj0B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj0B_MapUnc_201A0,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZAnimatedBits,3,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo8_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F0,d0
    addi.w  #$10,d0
    move.w  d0,d1
    subq.w  #1,d0
    move.w  d0,obj0B_duration_current(a0)
    move.w  d0,obj0B_duration_initial(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    addq.w  #1,d0
    lsl.w   #4,d0
    move.b  d0,obj0B_delay(a0)
 
loc_20104:
    move.b  (Vint_runcount+3).w,d0
    add.b   obj0B_delay(a0),d0
    bne.s   loc_2013C
    addq.b  #2,routine(a0)
 
loc_20112:
    subq.w  #1,obj0B_duration_current(a0)
    bpl.s   loc_20130
    move.w  #$7F,obj0B_duration_current(a0)
    tst.b   anim(a0)
    beq.s   +
    move.w  obj0B_duration_initial(a0),obj0B_duration_current(a0)
+
    bchg    #0,anim(a0)
 
loc_20130:
    lea (Ani_obj0B).l,a1
    jsr (AnimateSprite).l
 
loc_2013C:
    tst.b   mapping_frame(a0)
    bne.s   +
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #$11,d3
    move.w  x_pos(a0),d4
    bsr.w   PlatformObject
    jmpto   (MarkObjGone).l, JmpTo3_MarkObjGone
; ---------------------------------------------------------------------------
+
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   BranchTo_JmpTo3_MarkObjGone
    bclr    #p1_standing_bit,status(a0)
    beq.s   +
    bclr    #3,(MainCharacter+status).w
    bset    #1,(MainCharacter+status).w
+
    bclr    #p2_standing_bit,status(a0)
    beq.s   BranchTo_JmpTo3_MarkObjGone
    bclr    #3,(Sidekick+status).w
    bset    #1,(Sidekick+status).w
 
BranchTo_JmpTo3_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo3_MarkObjGone
; ===========================================================================
; animation script
; off_2018C:
Ani_obj0B:  offsetTable
        offsetTableEntry.w byte_20190   ; 0
        offsetTableEntry.w byte_20198   ; 1
byte_20190:
    dc.b   7,  0,  1,  2,  3,  4,$FE,  1
byte_20198:
    dc.b   7,  4,  3,  2,  1,  0,$FE,  1
    even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj0B_MapUnc_201A0: BINCLUDE "mappings/sprite/obj0B.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo3_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo8_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 0C - Small floating platform (unused)
; (used in CPZ in the Nick Arcade prototype)
; ----------------------------------------------------------------------------
; Sprite_20210:
Obj0C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj0C_Index(pc,d0.w),d1
    jmp Obj0C_Index(pc,d1.w)
; ===========================================================================
; off_2021E
Obj0C_Index:    offsetTable
        offsetTableEntry.w Obj0C_Init   ; 0
        offsetTableEntry.w Obj0C_Main   ; 2
; ===========================================================================
; loc_20222:
Obj0C_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj0C_MapUnc_202FA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_FloatPlatform,3,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo9_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),d0
    subi.w  #$10,d0
    move.w  d0,objoff_3A(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F0,d0
    addi.w  #$10,d0
    move.w  d0,d1
    subq.w  #1,d0
    move.w  d0,objoff_30(a0)
    move.w  d0,objoff_32(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    move.b  d0,objoff_3E(a0)
    move.b  d0,objoff_3F(a0)
; loc_20282:
Obj0C_Main:
    move.b  objoff_3C(a0),d0
    beq.s   loc_202C0
    cmpi.b  #$80,d0
    bne.s   loc_202D0
    move.b  objoff_3D(a0),d1
    bne.s   loc_202A2
    subq.b  #1,objoff_3E(a0)
    bpl.s   loc_202A2
    move.b  objoff_3F(a0),objoff_3E(a0)
    bra.s   loc_202D0
; ===========================================================================
 
loc_202A2:
    addq.b  #1,objoff_3D(a0)
    move.b  d1,d0
    jsrto   (CalcSine).l, JmpTo5_CalcSine
    addi_.w #8,d0
    asr.w   #6,d0
    subi.w  #$10,d0
    add.w   objoff_3A(a0),d0
    move.w  d0,y_pos(a0)
    bra.s   loc_202E6
; ===========================================================================
 
loc_202C0:
    move.w  (Vint_runcount+2).w,d1
    andi.w  #$3FF,d1
    bne.s   loc_202D4
    move.b  #1,objoff_3D(a0)
 
loc_202D0:
    addq.b  #1,objoff_3C(a0)
 
loc_202D4:
    jsrto   (CalcSine).l, JmpTo5_CalcSine
    addi_.w #8,d1
    asr.w   #4,d1
    add.w   objoff_3A(a0),d1
    move.w  d1,y_pos(a0)
 
loc_202E6:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #9,d3
    move.w  x_pos(a0),d4
    bsr.w   PlatformObject
    jmpto   (MarkObjGone).l, JmpTo4_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Unused sprite mappings
; ----------------------------------------------------------------------------
Obj0C_MapUnc_202FA: BINCLUDE "mappings/sprite/obj0C.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo4_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo9_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo5_CalcSine 
    jmp (CalcSine).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 12 - Emerald from Hidden Palace Zone (unused)
; ----------------------------------------------------------------------------
; Sprite_2031C:
Obj12:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj12_Index(pc,d0.w),d1
    jmp Obj12_Index(pc,d1.w)
; ===========================================================================
; off_2032A
Obj12_Index:    offsetTable
        offsetTableEntry.w Obj12_Init   ; 0
        offsetTableEntry.w Obj12_Main   ; 2
; ===========================================================================
; loc_2032E:
Obj12_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj12_MapUnc_20382,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HPZ_Emerald,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo10_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #4,priority(a0)
; loc_20356:
Obj12_Main:
    move.w  #$20,d1
    move.w  #$10,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo16_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo8_DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings (unused)
; -------------------------------------------------------------------------------
Obj12_MapUnc_20382: BINCLUDE "mappings/sprite/obj12.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo8_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo16_DeleteObject 
    jmp (DeleteObject).l
JmpTo10_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    else
JmpTo16_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 13 - Waterfall in Hidden Palace Zone (unused)
; ----------------------------------------------------------------------------
; Sprite_203AC:
Obj13:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj13_Index(pc,d0.w),d1
    jmp Obj13_Index(pc,d1.w)
; ===========================================================================
; off_203BA
Obj13_Index:    offsetTable
        offsetTableEntry.w Obj13_Init   ; 0
        offsetTableEntry.w Obj13_Main   ; 2
        offsetTableEntry.w Obj13_ChkDel ; 4
; ===========================================================================
; loc_203C0:
Obj13_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj13_MapUnc_20528,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HPZ_Waterfall,3,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo11_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  #$12,mapping_frame(a0)
    bsr.s   Obj13_LoadSubObject
    move.b  #$A0,y_radius(a1)
    bset    #4,render_flags(a1)
    move.l  a1,objoff_38(a0)
    move.w  y_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_36(a0)
    cmpi.b  #$10,subtype(a0)
    blo.s   loc_2046C
    bsr.s   Obj13_LoadSubObject
    move.l  a1,objoff_3C(a0)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$98,y_pos(a1)
    bra.s   loc_2046C
; ===========================================================================
; loc_20428:
Obj13_LoadSubObject:
    jsr (SingleObjLoad2).l
    bne.s   +   ; rts
    _move.b #ObjID_HPZWaterfall,id(a1) ; load obj13
    addq.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  #Obj13_MapUnc_20528,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_HPZ_Waterfall,3,1),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo2_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #1,priority(a1)
+   rts
; ===========================================================================
 
loc_2046C:
    moveq   #0,d1
    move.b  subtype(a0),d1
    move.w  objoff_34(a0),d0
    subi.w  #$78,d0
    lsl.w   #4,d1
    add.w   d1,d0
    move.w  d0,y_pos(a0)
    move.w  d0,objoff_34(a0)
; loc_20486:
Obj13_Main:
    movea.l objoff_38(a0),a1 ; a1=object
    move.b  #$12,mapping_frame(a0)
    move.w  objoff_34(a0),d0
    move.w  (Water_Level_1).w,d1
    cmp.w   d0,d1
    bhs.s   +
    move.w  d1,d0
+
    move.w  d0,y_pos(a0)
    sub.w   objoff_36(a0),d0
    addi.w  #$80,d0
    bmi.s   loc_204F0
    lsr.w   #4,d0
    move.w  d0,d1
    cmpi.w  #$F,d0
    blo.s   +
    moveq   #$F,d0
+
    move.b  d0,mapping_frame(a1)
    cmpi.b  #$10,subtype(a0)
    blo.s   loc_204D8
    movea.l objoff_3C(a0),a1 ; a1=object
    subi.w  #$F,d1
    bcc.s   +
    moveq   #0,d1
+
    addi.w  #$13,d1
    move.b  d1,mapping_frame(a1)
 
loc_204D8:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo17_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo9_DisplaySprite
; ===========================================================================
 
loc_204F0:
    moveq   #$13,d0
    move.b  d0,mapping_frame(a0)
    move.b  d0,mapping_frame(a1)
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo17_DeleteObject
    rts
; ===========================================================================
; loc_20510:
Obj13_ChkDel:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo17_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo9_DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings (unused)
; -------------------------------------------------------------------------------
Obj13_MapUnc_20528: BINCLUDE "mappings/sprite/obj13.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo9_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo17_DeleteObject 
    jmp (DeleteObject).l
JmpTo2_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo11_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    else
JmpTo17_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 04 - Surface of the water - water surface
; ----------------------------------------------------------------------------
 
Obj04:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj04_Index(pc,d0.w),d1
    jmp Obj04_Index(pc,d1.w)
; ===========================================================================
; off_208EA:
Obj04_Index:    offsetTable
        offsetTableEntry.w Obj04_Init       ; 0
        offsetTableEntry.w Obj04_Action     ; 2
        offsetTableEntry.w Obj04_Action2    ; 4
; ===========================================================================
; loc_208F0: Obj04_Main:
Obj04_Init:
    addq.b  #2,routine(a0) ; => Obj04_Action
    move.l  #Obj04_MapUnc_20A0E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_WaterSurface,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$80,width_pixels(a0)
    move.w  x_pos(a0),objoff_30(a0)
    cmpi.b  #aquatic_ruin_zone,(Current_Zone).w
    bne.s   Obj04_Action
    addq.b  #2,routine(a0) ; Obj04_Action2
    move.l  #Obj04_MapUnc_20AFE,mappings(a0)
    bra.w   Obj04_Action2
; ===========================================================================
; loc_20930:
Obj04_Action:
    move.w  (Water_Level_1).w,d1
    move.w  d1,y_pos(a0)
    tst.b   objoff_32(a0)
    bne.s   Obj04_Animate
    btst    #button_start,(Ctrl_1_Press).w  ; is Start button pressed?
    beq.s   loc_20962   ; if not, branch
    addq.b  #3,mapping_frame(a0)    ; use different frames
    move.b  #1,objoff_32(a0)    ; stop animation
    bra.s   loc_20962
; ===========================================================================
; loc_20952:
Obj04_Animate:
    tst.w   (Game_paused).w ; is the game paused?
    bne.s   loc_20962       ; if yes, branch
    move.b  #0,objoff_32(a0)    ; resume animation
    subq.b  #3,mapping_frame(a0)    ; use normal frames
 
loc_20962:
    lea (Anim_obj04).l,a1
    moveq   #0,d1
    move.b  anim_frame(a0),d1
    move.b  (a1,d1.w),mapping_frame(a0)
    addq.b  #1,anim_frame(a0)
    andi.b  #$3F,anim_frame(a0)
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ===========================================================================
; water sprite animation 'script' (custom format for this object)
; byte_20982:
Anim_obj04:
    dc.b 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1
    dc.b 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2
    dc.b 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1
    dc.b 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0
; ===========================================================================
; loc_209C2:
Obj04_Action2:
    move.w  (Water_Level_1).w,d1
    move.w  d1,y_pos(a0)
    tst.b   objoff_32(a0)
    bne.s   Obj04_Animate2
    btst    #button_start,(Ctrl_1_Press).w  ; is Start button pressed?
    beq.s   loc_209F4       ; if not, branch
    addq.b  #2,mapping_frame(a0)    ; use different frames
    move.b  #1,objoff_32(a0)        ; stop animation
    bra.s   BranchTo_JmpTo10_DisplaySprite
; ===========================================================================
; loc_209E4:
Obj04_Animate2:
    tst.w   (Game_paused).w ; is the game paused?
    bne.s   BranchTo_JmpTo10_DisplaySprite  ; if yes, branch
    move.b  #0,objoff_32(a0)    ; resume animation
    subq.b  #2,mapping_frame(a0)    ; use normal frames
 
loc_209F4:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo_JmpTo10_DisplaySprite
    move.b  #5,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #1,mapping_frame(a0)
 
BranchTo_JmpTo10_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj04_MapUnc_20A0E: BINCLUDE "mappings/sprite/obj04_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj04_MapUnc_20AFE: BINCLUDE "mappings/sprite/obj04_b.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 49 - Waterfall from EHZ
; ----------------------------------------------------------------------------
; Sprite_20B9E:
Obj49:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj49_Index(pc,d0.w),d1
    jmp Obj49_Index(pc,d1.w)
; ===========================================================================
; off_20BAC:
Obj49_Index:    offsetTable
        offsetTableEntry.w Obj49_Init   ; 0
        offsetTableEntry.w Obj49_ChkDel ; 2
; ===========================================================================
; loc_20BB0: Obj49_Main:
Obj49_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj49_MapUnc_20C50,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Waterfall,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.b  #0,priority(a0)
    move.b  #$80,y_radius(a0)
    bset    #4,render_flags(a0)
; loc_20BEA:
Obj49_ChkDel:
    tst.w   (Two_player_mode).w
    bne.s   +
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo18_DeleteObject
+
    move.w  x_pos(a0),d1
    move.w  d1,d2
    subi.w  #$40,d1
    addi.w  #$40,d2
    move.b  subtype(a0),d3
    move.b  #0,mapping_frame(a0)
    move.w  (MainCharacter+x_pos).w,d0
    cmp.w   d1,d0
    blo.s   loc_20C36
    cmp.w   d2,d0
    bhs.s   loc_20C36
    move.b  #1,mapping_frame(a0)
    add.b   d3,mapping_frame(a0)
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ===========================================================================
 
loc_20C36:
    move.w  (Sidekick+x_pos).w,d0
    cmp.w   d1,d0
    blo.s   Obj49_Display
    cmp.w   d2,d0
    bhs.s   Obj49_Display
    move.b  #1,mapping_frame(a0)
; loc_20C48:
Obj49_Display:
    add.b   d3,mapping_frame(a0)
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj49_MapUnc_20C50: BINCLUDE "mappings/sprite/obj49.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 31 - Lava collision marker
; ----------------------------------------------------------------------------
; Sprite_20DEC:
Obj31:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj31_Index(pc,d0.w),d1
    jmp Obj31_Index(pc,d1.w)
; ===========================================================================
; off_20DFA: Obj31_States:
Obj31_Index:    offsetTable
        offsetTableEntry.w Obj31_Init   ; 0
        offsetTableEntry.w Obj31_Main   ; 2
; ---------------------------------------------------------------------------
; byte_20DFE:
Obj31_CollisionFlagsBySubtype:
    dc.b $96    ; 0
    dc.b $94    ; 1
    dc.b $95    ; 2
    dc.b   0    ; 3
; ===========================================================================
; loc_20E02:
Obj31_Init:
    addq.b  #2,routine(a0) ; => Obj31_Main
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.b  Obj31_CollisionFlagsBySubtype(pc,d0.w),collision_flags(a0)
    move.l  #Obj31_MapUnc_20E6C,mappings(a0)
    tst.w   (Debug_placement_mode).w
    beq.s   +
    move.l  #Obj31_MapUnc_20E74,mappings(a0)
+
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    move.b  #$84,render_flags(a0)
    move.b  #$80,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),mapping_frame(a0)
 
; loc_20E46:
Obj31_Main:
    tst.w   (Two_player_mode).w
    bne.s   +
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo18_DeleteObject
+
    tst.w   (Debug_placement_mode).w
    beq.s   +   ; rts
    jsrto   (DisplaySprite).l, JmpTo10_DisplaySprite
+
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite non-mappings
; -------------------------------------------------------------------------------
Obj31_MapUnc_20E6C: BINCLUDE "mappings/sprite/obj31_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj31_MapUnc_20E74: BINCLUDE "mappings/sprite/obj31_b.bin"
; ===========================================================================
 
 
 
 
; ----------------------------------------------------------------------------
; Object 74 - Invisible solid block
; ----------------------------------------------------------------------------
; Sprite_20EE0:
Obj74:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj74_Index(pc,d0.w),d1
    jmp Obj74_Index(pc,d1.w)
; ===========================================================================
; off_20EEE: Obj74_States:
Obj74_Index:    offsetTable
        offsetTableEntry.w Obj74_Init   ; 0
        offsetTableEntry.w Obj74_Main   ; 2
; ===========================================================================
; loc_20EF2:
Obj74_Init:
    addq.b  #2,routine(a0) ; => Obj74_Main
    move.l  #Obj74_MapUnc_20F66,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  subtype(a0),d0
    move.b  d0,d1
    andi.w  #$F0,d0
    addi.w  #$10,d0
    lsr.w   #1,d0
    move.b  d0,width_pixels(a0)
    andi.w  #$F,d1
    addq.w  #1,d1
    lsl.w   #3,d1
    move.b  d1,y_radius(a0)
 
; loc_20F2E:
Obj74_Main:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    bsr.w   SolidObject_Always
    tst.w   (Two_player_mode).w
    bne.s   +
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo18_DeleteObject
    if gameRevision=0
    ; this object was visible with debug mode in REV00
+
    tst.w   (Debug_placement_mode).w
    beq.s   +   ; rts
    jmp (DisplaySprite).l
    endif
+
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj74_MapUnc_20F66: BINCLUDE "mappings/sprite/obj74.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7C - Big pylon in foreground of CPZ
; ----------------------------------------------------------------------------
; Sprite_20FD2:
Obj7C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7C_Index(pc,d0.w),d1
    jmp Obj7C_Index(pc,d1.w)
; ===========================================================================
; off_20FE0: Obj7C_States:
Obj7C_Index:    offsetTable
        offsetTableEntry.w Obj7C_Init   ; 0
        offsetTableEntry.w Obj7C_Main   ; 2
; ===========================================================================
; loc_20FE4:
Obj7C_Init:
    addq.b  #2,routine(a0) ; => Obj7C_Main
    move.l  #Obj7C_MapUnc_2103C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZMetalThings,2,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    move.b  #$10,width_pixels(a0)
    move.b  #7,priority(a0)
 
; loc_21006:
Obj7C_Main:
    move.w  (Camera_X_pos).w,d1
    andi.w  #$3FF,d1
    cmpi.w  #$2E0,d1
    bhs.s   +   ; rts
    asr.w   #1,d1
    move.w  d1,d0
    asr.w   #1,d1
    add.w   d1,d0
    neg.w   d0
    move.w  d0,x_pixel(a0)
    move.w  (Camera_Y_pos).w,d1
    asr.w   #1,d1
    andi.w  #$3F,d1
    neg.w   d1
    addi.w  #$100,d1
    move.w  d1,y_pixel(a0)
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ---------------------------------------------------------------------------
+   rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj7C_MapUnc_2103C: BINCLUDE "mappings/sprite/obj7C.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 27 - An explosion, giving off an animal and 100 points
; ----------------------------------------------------------------------------
; Sprite_21088:
Obj27:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj27_Index(pc,d0.w),d1
    jmp Obj27_Index(pc,d1.w)
; ===========================================================================
; off_21096: Obj27_States:
Obj27_Index:    offsetTable
        offsetTableEntry.w Obj27_InitWithAnimal ; 0
        offsetTableEntry.w Obj27_Init       ; 2
        offsetTableEntry.w Obj27_Main       ; 4
; ===========================================================================
; loc_2109C: Obj27_Init:
Obj27_InitWithAnimal:
    addq.b  #2,routine(a0) ; => Obj27_Init
    jsrto   (SingleObjLoad).l, JmpTo2_SingleObjLoad
    bne.s   Obj27_Init
    _move.b #ObjID_Animal,id(a1) ; load obj28 (Animal and 100 points)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  parent(a0),parent(a1)
 
; loc_210BE: Obj27_Init2:
Obj27_Init:
    addq.b  #2,routine(a0) ; => Obj27_Main
    move.l  #Obj27_MapUnc_21120,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Explosion,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #1,priority(a0)
    move.b  #0,collision_flags(a0)
    move.b  #$C,width_pixels(a0)
    move.b  #3,anim_frame_duration(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #SndID_Explosion,d0
    jsr (PlaySound).l
 
; loc_21102:
Obj27_Main:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #5,mapping_frame(a0)
    beq.w   JmpTo18_DeleteObject
+
    jmpto   (DisplaySprite).l, JmpTo10_DisplaySprite
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj27_MapUnc_21120: BINCLUDE "mappings/sprite/obj27.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 84 - Pinball mode enable/disable
; (used in Casino Night Zone to determine when Sonic should stay in a ball)
; ----------------------------------------------------------------------------
; Sprite_2115C:
Obj84:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj84_Index(pc,d0.w),d1
    jsr Obj84_Index(pc,d1.w)
    jmp (MarkObjGone3).l
; ===========================================================================
; off_21170: Obj84_States:
Obj84_Index:    offsetTable
        offsetTableEntry.w Obj84_Init   ; 0
        offsetTableEntry.w Obj84_MainX  ; 2
        offsetTableEntry.w Obj84_MainY  ; 4
; ===========================================================================
; loc_21176:
Obj84_Init:
    addq.b  #2,routine(a0) ; => Obj84_MainX
    move.l  #Obj03_MapUnc_1FFB8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #5,priority(a0)
    move.b  subtype(a0),d0
    btst    #2,d0
    beq.s   Obj84_Init_CheckX
    addq.b  #2,routine(a0) ; => Obj84_MainY
    andi.w  #7,d0
    move.b  d0,mapping_frame(a0)
    andi.w  #3,d0
    add.w   d0,d0
    move.w  word_211E8(pc,d0.w),objoff_32(a0)
    move.w  y_pos(a0),d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.w   y_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_34(a0)
+
    lea (Sidekick).w,a1 ; a1=character
    cmp.w   y_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_35(a0)
+
    bra.w   Obj84_MainY
; ===========================================================================
word_211E8:
    dc.w   $20
    dc.w   $40  ; 1
    dc.w   $80  ; 2
    dc.w  $100  ; 3
; ===========================================================================
; loc_211F0:
Obj84_Init_CheckX:
    andi.w  #3,d0
    move.b  d0,mapping_frame(a0)
    add.w   d0,d0
    move.w  word_211E8(pc,d0.w),objoff_32(a0)
    move.w  x_pos(a0),d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   +
    move.b  #1,objoff_34(a0)
+
    lea (Sidekick).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   Obj84_MainX
    move.b  #1,objoff_35(a0)
 
; loc_21224:
Obj84_MainX:
 
    tst.w   (Debug_placement_mode).w
    bne.s   return_21284
    move.w  x_pos(a0),d1
    lea objoff_34(a0),a2 ; a2=object
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    cmpi.w  #4,(Tails_CPU_routine).w    ; TailsCPU_Flying
    beq.s   return_21284
 
+   tst.b   (a2)+
    bne.s   Obj84_MainX_Alt
    cmp.w   x_pos(a1),d1
    bhi.s   return_21284
    move.b  #1,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_21284
    cmp.w   d3,d4
    bhs.s   return_21284
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #1,pinball_mode(a1) ; enable must-roll "pinball mode"
    bra.s   loc_212C4
; ---------------------------------------------------------------------------
+   move.b  #0,pinball_mode(a1) ; disable pinball mode
 
return_21284:
    rts
; ===========================================================================
; loc_21286:
Obj84_MainX_Alt:
    cmp.w   x_pos(a1),d1
    bls.s   return_21284
    move.b  #0,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_21284
    cmp.w   d3,d4
    bhs.s   return_21284
    btst    #0,render_flags(a0)
    beq.s   +
    move.b  #1,pinball_mode(a1)
    bra.s   loc_212C4
; ---------------------------------------------------------------------------
+   move.b  #0,pinball_mode(a1)
    rts
; ===========================================================================
 
loc_212C4:
    btst    #2,status(a1)
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+   bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    addq.w  #5,y_pos(a1)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
    rts
 
; ===========================================================================
; loc_212F6:
Obj84_MainY:
 
    tst.w   (Debug_placement_mode).w
    bne.s   return_21350
    move.w  y_pos(a0),d1
    lea objoff_34(a0),a2 ; a2=object
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
+
    tst.b   (a2)+
    bne.s   Obj84_MainY_Alt
    cmp.w   y_pos(a1),d1
    bhi.s   return_21350
    move.b  #1,-1(a2)
    move.w  x_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  x_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_21350
    cmp.w   d3,d4
    bhs.s   return_21350
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #1,pinball_mode(a1)
    bra.w   loc_212C4
; ---------------------------------------------------------------------------
+   move.b  #0,pinball_mode(a1)
 
return_21350:
    rts
; ===========================================================================
; loc_21352:
Obj84_MainY_Alt:
    cmp.w   y_pos(a1),d1
    bls.s   return_21350
    move.b  #0,-1(a2)
    move.w  x_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  x_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_21350
    cmp.w   d3,d4
    bhs.s   return_21350
    btst    #0,render_flags(a0)
    beq.s   +
    move.b  #1,pinball_mode(a1)
    bra.w   loc_212C4
; ---------------------------------------------------------------------------
+   move.b  #0,pinball_mode(a1)
    rts
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 8B - Cycling palette switcher from Wing Fortress Zone
; ----------------------------------------------------------------------------
; Sprite_21392:
Obj8B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj8B_Index(pc,d0.w),d1
    jsr Obj8B_Index(pc,d1.w)
    jmp (MarkObjGone3).l
; ===========================================================================
; off_213A6:
Obj8B_Index:    offsetTable
        offsetTableEntry.w Obj8B_Init   ; 0
        offsetTableEntry.w Obj8B_Main   ; 2
; ===========================================================================
word_213AA:
    dc.w   $20
    dc.w   $40  ; 1
    dc.w   $80  ; 2
    dc.w  $100  ; 3
; ===========================================================================
; loc_213B2:
Obj8B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj03_MapUnc_1FFB8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo12_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #5,priority(a0)
    move.b  subtype(a0),d0
    andi.w  #3,d0
    move.b  d0,mapping_frame(a0)
    add.w   d0,d0
    move.w  word_213AA(pc,d0.w),objoff_32(a0)
    move.w  x_pos(a0),d1
    lea (MainCharacter).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   loc_21402
    move.b  #1,objoff_34(a0)
 
loc_21402:
    lea (Sidekick).w,a1 ; a1=character
    cmp.w   x_pos(a1),d1
    bhs.s   Obj8B_Main
    move.b  #1,objoff_35(a0)
; loc_21412:
Obj8B_Main:
    tst.w   (Debug_placement_mode).w
    bne.s   return_2146A
    move.w  x_pos(a0),d1
    lea objoff_34(a0),a2 ; a2=object
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_2142A
    lea (Sidekick).w,a1 ; a1=character
 
loc_2142A:
    tst.b   (a2)+
    bne.s   loc_2146C
    cmp.w   x_pos(a1),d1
    bhi.s   return_2146A
    move.b  #1,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_2146A
    cmp.w   d3,d4
    bhs.s   return_2146A
    btst    #0,render_flags(a0)
    bne.s   +
    move.b  #1,(WFZ_SCZ_Fire_Toggle).w
    rts
; ---------------------------------------------------------------------------
+   move.b  #0,(WFZ_SCZ_Fire_Toggle).w
 
return_2146A:
    rts
; ===========================================================================
 
loc_2146C:
    cmp.w   x_pos(a1),d1
    bls.s   return_2146A
    move.b  #0,-1(a2)
    move.w  y_pos(a0),d2
    move.w  d2,d3
    move.w  objoff_32(a0),d4
    sub.w   d4,d2
    add.w   d4,d3
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.s   return_2146A
    cmp.w   d3,d4
    bhs.s   return_2146A
    btst    #0,render_flags(a0)
    beq.s   +
    move.b  #1,(WFZ_SCZ_Fire_Toggle).w
    rts
; ---------------------------------------------------------------------------
+   move.b  #0,(WFZ_SCZ_Fire_Toggle).w
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
; loc_214AC:
JmpTo10_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo18_DeleteObject 
    jmp (DeleteObject).l
JmpTo2_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo12_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    else
JmpTo18_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 06 - Rotating cylinder in MTZ, twisting spiral pathway in EHZ
; ----------------------------------------------------------------------------
; Sprite_214C4:
Obj06:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj06_Index(pc,d0.w),d1
    jsr Obj06_Index(pc,d1.w)
    tst.w   (Two_player_mode).w
    beq.s   Obj06_ChkDel
    rts
; ---------------------------------------------------------------------------
; seems to be an optimization to delete the object the instant it goes offscreen
; only in 1-player mode, because it would screw up the other player
; loc_214DA:
Obj06_ChkDel:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   JmpTo19_DeleteObject
    rts
; ---------------------------------------------------------------------------
JmpTo19_DeleteObject 
    jmp (DeleteObject).l
 
; ===========================================================================
; off_214F4:
Obj06_Index:    offsetTable
        offsetTableEntry.w Obj06_Init       ; 0
        offsetTableEntry.w Obj06_Spiral     ; 2
        offsetTableEntry.w Obj06_Cylinder   ; 4
; ===========================================================================
; loc_214FA:
Obj06_Init:
    addq.b  #2,routine(a0) ; => Obj06_Spiral
    move.b  #$D0,width_pixels(a0)
    tst.b   subtype(a0)
    bpl.s   Obj06_Spiral
    addq.b  #2,routine(a0) ; => Obj06_Cylinder
    bra.w   Obj06_Cylinder
 
; ===========================================================================
; spiral pathway from EHZ
; loc_21512:
Obj06_Spiral:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
+
    btst    d6,status(a0)
    bne.w   loc_215C0
    btst    #1,status(a1)
    bne.w   return_215BE
    btst    #3,status(a1)
    bne.s   loc_21580
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    tst.w   x_vel(a1)
    bmi.s   loc_21556
    cmpi.w  #-$C0,d0
    bgt.s   return_215BE
    cmpi.w  #-$D0,d0
    blt.s   return_215BE
    bra.s   loc_21562
; ---------------------------------------------------------------------------
 
loc_21556:
    cmpi.w  #$C0,d0
    blt.s   return_215BE
    cmpi.w  #$D0,d0
    bgt.s   return_215BE
 
loc_21562:
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    subi.w  #$10,d1
    cmpi.w  #$30,d1
    bhs.s   return_215BE
    tst.b   obj_control(a1)
    bne.s   return_215BE
    bsr.w   RideObject_SetRide
    rts
; ---------------------------------------------------------------------------
 
loc_21580:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    tst.w   x_vel(a1)
    bmi.s   loc_2159C
    cmpi.w  #-$B0,d0
    bgt.s   return_215BE
    cmpi.w  #-$C0,d0
    blt.s   return_215BE
    bra.s   loc_215A8
; ---------------------------------------------------------------------------
 
loc_2159C:
    cmpi.w  #$B0,d0
    blt.s   return_215BE
    cmpi.w  #$C0,d0
    bgt.s   return_215BE
 
loc_215A8:
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    subi.w  #$10,d1
    cmpi.w  #$30,d1
    bhs.s   return_215BE
    bsr.w   RideObject_SetRide
 
return_215BE:
    rts
; ---------------------------------------------------------------------------
 
loc_215C0:
    mvabs.w inertia(a1),d0
    cmpi.w  #$600,d0
    blo.s   Obj06_Spiral_CharacterFallsOff
    btst    #1,status(a1)
    bne.s   Obj06_Spiral_CharacterFallsOff
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$D0,d0
    bmi.s   Obj06_Spiral_CharacterFallsOff
    cmpi.w  #$1A0,d0
    blo.s   Obj06_Spiral_MoveCharacter
 
; loc_215EA:
Obj06_Spiral_CharacterFallsOff:
    bclr    #3,status(a1)
    bclr    d6,status(a0)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    rts
 
; ---------------------------------------------------------------------------
; loc_21602:
Obj06_Spiral_MoveCharacter:
    btst    #3,status(a1)
    beq.s   return_215BE
    move.b  Obj06_CosineTable(pc,d0.w),d1
    ext.w   d1
    move.w  y_pos(a0),d2
    add.w   d1,d2
    moveq   #0,d1
    move.b  y_radius(a1),d1
    subi.w  #$13,d1
    sub.w   d1,d2
    move.w  d2,y_pos(a1)
    lsr.w   #3,d0
    andi.w  #$3F,d0
    move.b  Obj06_FlipAngleTable(pc,d0.w),flip_angle(a1)
    rts
 
; ===========================================================================
; byte_21634:
Obj06_FlipAngleTable:
    dc.b     0,    0,    1,    1; 4
    dc.b   $16,  $16,  $16,  $16; 8
    dc.b   $2C,  $2C,  $2C,  $2C; 12
    dc.b   $42,  $42,  $42,  $42; 16
    dc.b   $58,  $58,  $58,  $58; 20
    dc.b   $6E,  $6E,  $6E,  $6E; 24
    dc.b   $84,  $84,  $84,  $84; 28
    dc.b   $9A,  $9A,  $9A,  $9A; 32
    dc.b   $B0,  $B0,  $B0,  $B0; 36
    dc.b   $C6,  $C6,  $C6,  $C6; 40
    dc.b   $DC,  $DC,  $DC,  $DC; 44
    dc.b   $F2,  $F2,  $F2,  $F2; 48
    dc.b     1,    1,    0,    0; 52
; byte_21668:
Obj06_CosineTable:
    dc.b  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32;  16
    dc.b  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 31, 31;  32
    dc.b  31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 30, 30, 30;  48
    dc.b  30, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, 28, 28, 27;  64
    dc.b  27, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 24, 23, 23, 22, 22;  80
    dc.b  21, 21, 20, 20, 19, 18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12;  96
    dc.b  11, 10, 10,  9,  8,  8,  7,  6,  6,  5,  4,  4,  3,  2,  2,  1; 112
    dc.b   0, -1, -2, -2, -3, -4, -4, -5, -6, -7, -7, -8, -9, -9,-10,-10; 128
    dc.b -11,-11,-12,-12,-13,-14,-14,-15,-15,-16,-16,-17,-17,-18,-18,-19; 144
    dc.b -19,-19,-20,-21,-21,-22,-22,-23,-23,-24,-24,-25,-25,-26,-26,-27; 160
    dc.b -27,-28,-28,-28,-29,-29,-30,-30,-30,-31,-31,-31,-32,-32,-32,-33; 176
    dc.b -33,-33,-33,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-36,-36; 192
    dc.b -36,-36,-36,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37; 208
    dc.b -37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37; 224
    dc.b -37,-37,-37,-37,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-35,-35; 240
    dc.b -35,-35,-35,-34,-34,-34,-33,-33,-33,-33,-32,-32,-32,-31,-31,-31; 256
    dc.b -30,-30,-30,-29,-29,-28,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24; 272
    dc.b -23,-23,-22,-22,-21,-21,-20,-19,-19,-18,-18,-17,-16,-16,-15,-14; 288
    dc.b -14,-13,-12,-11,-11,-10, -9, -8, -7, -7, -6, -5, -4, -3, -2, -1; 304
    dc.b   0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9, 10, 10, 11, 12, 13; 320
    dc.b  13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21; 336
    dc.b  21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26; 352
    dc.b  27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29; 368
    dc.b  29, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31; 384
    dc.b  31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32; 400
    dc.b  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32; 416
 
; ===========================================================================
; rotating meshed cage from MTZ
; loc_21808:
Obj06_Cylinder:
    lea (MainCharacter).w,a1 ; a1=character
    lea (MTZCylinder_Angle_Sonic).w,a2
    moveq   #p1_standing_bit,d6
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    lea (MTZCylinder_Angle_Tails).w,a2
    addq.b  #1,d6
+
    btst    d6,status(a0)
    bne.w   loc_2188C
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    cmpi.w  #-$C0,d0
    blt.s   return_2188A
    cmpi.w  #$C0,d0
    bge.s   return_2188A
    move.w  y_pos(a0),d0
    addi.w  #$3C,d0
    move.w  y_pos(a1),d2
    move.b  y_radius(a1),d1
    ext.w   d1
    add.w   d2,d1
    addq.w  #4,d1
    sub.w   d1,d0
    bhi.s   return_2188A
    cmpi.w  #-$10,d0
    blo.s   return_2188A
    cmpi.b  #6,routine(a1)
    bhs.s   return_2188A
    add.w   d0,d2
    addq.w  #3,d2
    move.w  d2,y_pos(a1)
    move.b  #1,flip_turned(a1) ; face the other way
    bsr.w   RideObject_SetRide
    move.w  #AniIDSonAni_Run,anim(a1)
    move.b  #0,(a2)
    tst.w   inertia(a1)
    bne.s   return_2188A
    move.w  #1,inertia(a1)
 
return_2188A:
    rts
; ===========================================================================
 
loc_2188C:
    btst    #1,status(a1)
    bne.s   loc_218C6
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$C0,d0
    bmi.s   loc_218A8
    cmpi.w  #$180,d0
    blo.s   loc_218E0
 
loc_218A8:
    bclr    #3,status(a1)
    bclr    d6,status(a0)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    bset    #1,status(a1)
    rts
; ---------------------------------------------------------------------------
loc_218C6:
    move.b  (a2),d0
    addi.b  #$20,d0
    cmpi.b  #$40,d0
    bhs.s   +
    asr y_vel(a1)
    bra.s   loc_218A8
; ---------------------------------------------------------------------------
+   move.w  #0,y_vel(a1)
    bra.s   loc_218A8
; ===========================================================================
 
loc_218E0:
    btst    #3,status(a1)
    beq.s   return_2188A
    move.b  (a2),d0
    jsrto   (CalcSine).l, JmpTo6_CalcSine
    muls.w  #$2800,d1
    swap    d1
    move.w  y_pos(a0),d2
    add.w   d1,d2
    moveq   #0,d1
    move.b  y_radius(a1),d1
    subi.w  #$13,d1
    sub.w   d1,d2
    move.w  d2,y_pos(a1)
    move.b  (a2),d0
    move.b  d0,flip_angle(a1)
    addq.b  #4,(a2)
    tst.w   inertia(a1)
    bne.s   return_2191E
    move.w  #1,inertia(a1)
 
return_2191E:
    rts
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo6_CalcSine 
    jmp (CalcSine).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 14 - See saw from Hill Top Zone
; ----------------------------------------------------------------------------
; Sprite_21928:
Obj14:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj14_Index(pc,d0.w),d1
    jsr Obj14_Index(pc,d1.w)
    move.w  objoff_30(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo_MarkObjGone2
; ===========================================================================
; off_2193E:
Obj14_Index:    offsetTable
        offsetTableEntry.w Obj14_Init       ;  0
        offsetTableEntry.w Obj14_Main       ;  2
        offsetTableEntry.w return_21A74     ;  4
        offsetTableEntry.w Obj14_Ball_Init  ;  6
        offsetTableEntry.w Obj14_Ball_Main  ;  8
        offsetTableEntry.w Obj14_Ball_Fly       ; $A
; ===========================================================================
; loc_2194A:
Obj14_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj14_MapUnc_21CF0,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HtzSeeSaw,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo13_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$30,width_pixels(a0)
    move.w  x_pos(a0),objoff_30(a0)
    tst.b   subtype(a0)
    bne.s   loc_219A4
    jsrto   (SingleObjLoad2).l, JmpTo3_SingleObjLoad2
    bne.s   loc_219A4
    _move.b #ObjID_Seesaw,id(a1) ; load obj14
    addq.b  #6,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  status(a0),status(a1)
    move.l  a0,objoff_3C(a1)
 
loc_219A4:
    btst    #0,status(a0)
    beq.s   loc_219B2
    move.b  #2,mapping_frame(a0)
 
loc_219B2:
    move.b  mapping_frame(a0),objoff_3A(a0)
 
Obj14_Main:
    move.b  objoff_3A(a0),d1
    btst    #p1_standing_bit,status(a0)
    beq.s   loc_21A12
    moveq   #2,d1
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   +
    neg.w   d0
    moveq   #0,d1
+
    cmpi.w  #8,d0
    bhs.s   +
    moveq   #1,d1
+
    btst    #p2_standing_bit,status(a0)
    beq.s   Obj14_UpdateMappingAndCollision
    moveq   #2,d2
    lea (Sidekick).w,a1 ; a1=character
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   +
    neg.w   d0
    moveq   #0,d2
+
    cmpi.w  #8,d0
    bhs.s   +
    moveq   #1,d2
+
    add.w   d2,d1
    cmpi.w  #3,d1
    bne.s   +
    addq.w  #1,d1
+
    lsr.w   #1,d1
    bra.s   Obj14_UpdateMappingAndCollision
; ===========================================================================
 
loc_21A12:
    btst    #p2_standing_bit,status(a0)
    beq.s   loc_21A38
    moveq   #2,d1
    lea (Sidekick).w,a1 ; a1=character
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   +
    neg.w   d0
    moveq   #0,d1
+
    cmpi.w  #8,d0
    bhs.s   Obj14_UpdateMappingAndCollision
    moveq   #1,d1
    bra.s   Obj14_UpdateMappingAndCollision
; ===========================================================================
 
loc_21A38:
    move.w  (MainCharacter+y_vel).w,d0
    move.w  (Sidekick+y_vel).w,d2
    cmp.w   d0,d2
    blt.s   +
    move.w  d2,d0
+
    move.w  d0,objoff_38(a0)
 
; loc_21A4A:
Obj14_UpdateMappingAndCollision:
    bsr.w   Obj14_SetMapping
    lea (byte_21C8E).l,a2
    btst    #0,mapping_frame(a0)
    beq.s   +
    lea (byte_21CBF).l,a2
+
    move.w  x_pos(a0),-(sp)
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #8,d3
    move.w  (sp)+,d4
    bra.w   SlopedPlatform
; ===========================================================================
 
return_21A74:
    rts
; ===========================================================================
 
; loc_21A76:
Obj14_SetMapping:
    move.b  mapping_frame(a0),d0
    cmp.b   d1,d0
    beq.s   return_21AA0
    bhs.s   +
    addq.b  #2,d0
+
    subq.b  #1,d0
    move.b  d0,mapping_frame(a0)
    move.b  d1,objoff_3A(a0)
    bclr    #0,render_flags(a0)
    btst    #1,mapping_frame(a0)
    beq.s   return_21AA0
    bset    #0,render_flags(a0)
 
return_21AA0:
    rts
; ===========================================================================
; loc_21AA2:
Obj14_Ball_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj14_MapUnc_21D7C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Sol,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo13_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$8B,collision_flags(a0)
    move.b  #$C,width_pixels(a0)
    move.w  x_pos(a0),objoff_30(a0) ; save seesaw x position
    addi.w  #$28,x_pos(a0)
    addi.w  #$10,y_pos(a0)
    move.w  y_pos(a0),objoff_34(a0) ; save bottom of seesaw y position
    btst    #0,status(a0)
    beq.s   Obj14_Ball_Main
    subi.w  #$50,x_pos(a0)
    move.b  #2,objoff_3A(a0)
; loc_21AFC:
Obj14_Ball_Main:
    bsr.w   Obj14_Animate
    movea.l objoff_3C(a0),a1 ; a1=parent object (seesaw)
    moveq   #0,d0
    move.b  objoff_3A(a0),d0 ; d0 = ball angle - seesaw angle
    sub.b   objoff_3A(a1),d0
    beq.s   Obj14_SetBallToRestOnSeeSaw
    bcc.s   +
    neg.b   d0
+
    move.w  #-$818,d1
    move.w  #-$114,d2
    cmpi.b  #1,d0
    beq.s   +
    move.w  #-$AF0,d1
    move.w  #-$CC,d2
    cmpi.w  #$A00,objoff_38(a1) ; check if character y_vel that jumped on
    blt.s   +                   ; seesaw > 2560
    move.w  #-$E00,d1
    move.w  #-$A0,d2
+
    move.w  d1,y_vel(a0)
    move.w  d2,x_vel(a0)
    move.w  x_pos(a0),d0
    sub.w   objoff_30(a0),d0
    bcc.s   +
    neg.w   x_vel(a0)
+
    addq.b  #2,routine(a0)
    bra.s   Obj14_Ball_Fly
; ===========================================================================
 
; loc_21B56:
Obj14_SetBallToRestOnSeeSaw:
    lea (Obj14_YOffsets).l,a2
    moveq   #0,d0
    move.b  mapping_frame(a1),d0
    move.w  #$28,d2
    move.w  x_pos(a0),d1
    sub.w   objoff_30(a0),d1
    bcc.s   +
    neg.w   d2
    addq.w  #2,d0
+
    add.w   d0,d0
    move.w  objoff_34(a0),d1 ; d1 = bottom of seesaw y position
    add.w   (a2,d0.w),d1     ;    + offset for current angle
    move.w  d1,y_pos(a0)     ; set y position so ball rests on seesaw
    add.w   objoff_30(a0),d2
    move.w  d2,x_pos(a0)
    clr.w   y_sub(a0)
    clr.w   x_sub(a0)
    rts
; ===========================================================================
 
Obj14_Ball_Fly:
 
    bsr.w   Obj14_Animate
    tst.w   y_vel(a0)
    bpl.s   loc_21BB6
    jsrto   (ObjectMoveAndFall).l, JmpTo_ObjectMoveAndFall
    move.w  objoff_34(a0),d0 ; d0 = bottom of seesaw y position
    subi.w  #$2F,d0
    cmp.w   y_pos(a0),d0
    bgt.s   return_21BB4
    jsrto   (ObjectMoveAndFall).l, JmpTo_ObjectMoveAndFall
 
return_21BB4:
    rts
; ===========================================================================
 
loc_21BB6:
    jsrto   (ObjectMoveAndFall).l, JmpTo_ObjectMoveAndFall
    movea.l objoff_3C(a0),a1 ; a1=parent object (seesaw)
    lea (Obj14_YOffsets).l,a2
    moveq   #0,d0
    move.b  mapping_frame(a1),d0
    move.w  x_pos(a0),d1
    sub.w   objoff_30(a0),d1
    bcc.s   +
    addq.w  #2,d0
+
    add.w   d0,d0
    move.w  objoff_34(a0),d1 ; d1 = bottom of seesaw y position
    add.w   (a2,d0.w),d1     ;    + offset for current angle
    cmp.w   y_pos(a0),d1     ; return if y position < d1
    bgt.s   return_21C2A
    movea.l objoff_3C(a0),a1 ; a1=parent object (seesaw)
    moveq   #2,d1            ; d1 = x_vel >= 0 ? 0 : 2
    tst.w   x_vel(a0)
    bmi.s   +
    moveq   #0,d1
+
    move.b  d1,objoff_3A(a1) ; set seesaw angle to d1
    move.b  d1,objoff_3A(a0) ; set ball angle to d1
    cmp.b   mapping_frame(a1),d1
    beq.s   loc_21C1E
    
    ; launch main character if stood on seesaw
    lea (MainCharacter).w,a2 ; a2=character
    bclr    #p1_standing_bit,status(a1)
    beq.s   +
    bsr.s   Obj14_LaunchCharacter
+
    ; launch sidekick if stood on seesaw
    lea (Sidekick).w,a2 ; a2=character
    bclr    #p2_standing_bit,status(a1)
    beq.s   loc_21C1E
    bsr.s   Obj14_LaunchCharacter
 
loc_21C1E:
    clr.w   x_vel(a0)      ; clear ball velocity
    clr.w   y_vel(a0)
    subq.b  #2,routine(a0) ; set ball to main state
 
return_21C2A:
    rts
; ===========================================================================
 
; loc_21C2C:
Obj14_LaunchCharacter:
    move.w  y_vel(a0),y_vel(a2) ; set character y velocity to inverse of sol
    neg.w   y_vel(a2)           ; y velocity
    bset    #1,status(a2)       ; set character airborne flag
    bclr    #3,status(a2)       ; clear character on object flag
    clr.b   jumping(a2)         ; clear character jumping flag
    move.b  #AniIDSonAni_Spring,anim(a2) ; set character to spring animation
    move.b  #2,routine(a2)      ; set character to airborne state
    move.w  #SndID_Spring,d0    ; play spring sound
    jmp (PlaySound).l
; ===========================================================================
; heights of the contact point of the ball on the seesaw
; word_21C5C:
Obj14_YOffsets:
    dc.w -8, -28, -47, -28, -8 ; low, balanced, high, balanced, low
; ===========================================================================
 
; loc_21C66:
Obj14_Animate:
    move.b  (Timer_frames+1).w,d0
    andi.b  #3,d0
    bne.s   Obj14_SetSolToFaceMainCharacter
    bchg    #palette_bit_0,art_tile(a0)
    
Obj14_SetSolToFaceMainCharacter:
    andi.b  #$FE,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    bcs.s   return_21C8C
    ori.b   #1,render_flags(a0)
 
return_21C8C:
    rts
; ===========================================================================
byte_21C8E:
    dc.b $14,$14,$16,$18,$1A,$1C,$1A,$18,$16,$14,$13,$12,$11,$10, $F, $E
    dc.b  $D, $C, $B, $A,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,$FF,$FE; 16
    dc.b $FD,$FC,$FB,$FA,$F9,$F8,$F7,$F6,$F5,$F4,$F3,$F2,$F2,$F2,$F2,$F2; 32
    dc.b $F2    ; 48
 
    rev02even
byte_21CBF:
    dc.b   5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5
    dc.b   5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5; 16
    dc.b   5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5; 32
 
    even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj14_MapUnc_21CF0: BINCLUDE "mappings/sprite/obj14_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj14_MapUnc_21D7C: BINCLUDE "mappings/sprite/obj14_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo3_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo13_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
JmpTo_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 16 - Diagonally moving lift from HTZ
; ----------------------------------------------------------------------------
; Sprite_21DAC:
Obj16:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj16_Index(pc,d0.w),d1
    jmp Obj16_Index(pc,d1.w)
; ===========================================================================
; off_21DBA:
Obj16_Index:    offsetTable
        offsetTableEntry.w Obj16_Init   ; 0
        offsetTableEntry.w Obj16_Main   ; 2
; ===========================================================================
; loc_21DBE:
Obj16_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj16_MapUnc_21F14,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HtzZipline,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo14_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #0,mapping_frame(a0)
    move.b  #1,priority(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  #$40,y_radius(a0)
    bset    #4,render_flags(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #3,d0
    move.w  d0,objoff_34(a0)
; loc_21E10:
Obj16_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   Obj16_RunSecondaryRoutine
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  #-$28,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject).l, JmpTo3_PlatformObject
    jmpto   (MarkObjGone).l, JmpTo5_MarkObjGone
; ===========================================================================
; loc_21E2C:
Obj16_RunSecondaryRoutine:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj16_Main_States(pc,d0.w),d1
    jmp Obj16_Main_States(pc,d1.w)
; ===========================================================================
; off_21E3A:
Obj16_Main_States: offsetTable
    offsetTableEntry.w Obj16_Wait   ; 0
    offsetTableEntry.w Obj16_Slide  ; 2
    offsetTableEntry.w Obj16_Fall   ; 4
; ===========================================================================
; loc_21E40:
Obj16_Wait:
    move.b  status(a0),d0   ; get the status flags
    andi.b  #standing_mask,d0   ; is one of the players standing on it?
    beq.s   ++      ; if not, branch
    addq.b  #2,routine_secondary(a0)
    move.w  #$200,x_vel(a0)
    btst    #0,status(a0)
    beq.s   +
    neg.w   x_vel(a0)
+
    move.w  #$100,y_vel(a0)
+
    rts
; ===========================================================================
; loc_21E68:
Obj16_Slide:
    move.w  (Timer_frames).w,d0
    andi.w  #$F,d0  ; play the sound only every 16 frames
    bne.s   +
    move.w  #SndID_HTZLiftClick,d0
    jsr (PlaySound).l
+
    jsrto   (ObjectMove).l, JmpTo4_ObjectMove
    subq.w  #1,objoff_34(a0)
    bne.s   +   ; rts
    addq.b  #2,routine_secondary(a0)
    move.b  #2,mapping_frame(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    jsrto   (SingleObjLoad2).l, JmpTo4_SingleObjLoad2
    bne.s   +   ; rts
    _move.b #ObjID_Scenery,id(a1) ; load obj1C
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #6,subtype(a1)
+   rts
; ===========================================================================
; loc_21EC2:
Obj16_Fall:
    jsrto   (ObjectMove).l, JmpTo4_ObjectMove
    addi.w  #$38,y_vel(a0)
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    bhs.s   +++ ; rts
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   ++
    bclr    #p1_standing_bit,status(a0)
    beq.s   +
    bclr    #3,(MainCharacter+status).w
    bset    #1,(MainCharacter+status).w
+
    bclr    #p2_standing_bit,status(a0)
    beq.s   +
    bclr    #3,(Sidekick+status).w
    bset    #1,(Sidekick+status).w
+
    move.w  #$4000,x_pos(a0)
+
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj16_MapUnc_21F14: BINCLUDE "mappings/sprite/obj16.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo5_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo4_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo14_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo3_PlatformObject 
    jmp (PlatformObject).l
; loc_22010:
JmpTo4_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
    dc.b    $01,$02,$1E,$42 ; ??? (unused)
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 19 - Platform from CPZ, OOZ and WFZ
; ----------------------------------------------------------------------------
; Sprite_22018:
Obj19:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj19_Index(pc,d0.w),d1
    jmp Obj19_Index(pc,d1.w)
; ===========================================================================
; off_22026: Obj19_States:
Obj19_Index:    offsetTable
        offsetTableEntry.w Obj19_Init   ; 0
        offsetTableEntry.w Obj19_Main   ; 2
; ---------------------------------------------------------------------------
; word_2202A:
Obj19_SubtypeProperties:
    ;    width_pixels
    ;     mapping_frame
    dc.b $20, 0
    dc.b $18, 1
    dc.b $40, 2
    dc.b $20, 3
; ===========================================================================
; loc_22032:
Obj19_Init:
    addq.b  #2,routine(a0) ; => Obj19_Main
    move.l  #Obj19_MapUnc_2222A,mappings(a0)
 
    move.w  #make_art_tile(ArtTile_ArtNem_CPZElevator,3,0),art_tile(a0) ; set default art
 
    cmpi.b  #oil_ocean_zone,(Current_Zone).w ; are we in OOZ?
    bne.s   +           ; if not, branch
    move.w  #make_art_tile(ArtTile_ArtNem_OOZElevator,3,0),art_tile(a0) ; set OOZ art
+
    cmpi.b  #wing_fortress_zone,(Current_Zone).w ; are we in WFZ?
    bne.s   +           ; if not, branch
    move.w  #make_art_tile(ArtTile_ArtNem_WfzFloatingPlatform,1,1),art_tile(a0) ; set WTZ art
+
    jsrto   (Adjust2PArtPointer).l, JmpTo15_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$1E,d0
    lea Obj19_SubtypeProperties(pc,d0.w),a2
    move.b  (a2)+,width_pixels(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.b  #4,priority(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    andi.b  #$F,subtype(a0)
    cmpi.b  #3,subtype(a0)
    bne.s   loc_220AA
    btst    #0,status(a0)
    bne.s   loc_220B2
 
loc_220AA:
    cmpi.b  #7,subtype(a0)
    bne.s   Obj19_Main
 
loc_220B2:
    subi.w  #$C0,y_pos(a0)
 
; loc_220B8:
Obj19_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   Obj19_Move
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  #$11,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject).l, JmpTo4_PlatformObject
    move.w  objoff_30(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo20_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo11_DisplaySprite
; ---------------------------------------------------------------------------
; loc_220E8:
Obj19_Move:
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    add.w   d0,d0
    move.w  Obj19_MoveTypes(pc,d0.w),d1
    jmp Obj19_MoveTypes(pc,d1.w)
; ===========================================================================
; platform movement routine table
; off_220FC:
Obj19_MoveTypes:offsetTable
        offsetTableEntry.w Obj19_MoveRoutine1       ;  0
        offsetTableEntry.w Obj19_MoveRoutine2       ;  1
        offsetTableEntry.w Obj19_MoveRoutine3       ;  2
        offsetTableEntry.w Obj19_MoveRoutine4       ;  3
        offsetTableEntry.w Obj19_MoveRoutine5       ;  4
        offsetTableEntry.w Obj19_MoveRoutineNull    ;  5
        offsetTableEntry.w Obj19_MoveRoutine6       ;  6
        offsetTableEntry.w Obj19_MoveRoutine6       ;  7
        offsetTableEntry.w Obj19_MoveRoutine7       ;  8
        offsetTableEntry.w Obj19_MoveRoutine7       ;  9
        offsetTableEntry.w Obj19_MoveRoutine7       ; $A
        offsetTableEntry.w Obj19_MoveRoutine7       ; $B
        offsetTableEntry.w Obj19_MoveRoutine8       ; $C
        offsetTableEntry.w Obj19_MoveRoutine8       ; $D
        offsetTableEntry.w Obj19_MoveRoutine8       ; $E
        offsetTableEntry.w Obj19_MoveRoutine8       ; $F
 
; ===========================================================================
; loc_2211C:
Obj19_MoveRoutine1:
    move.b  (Oscillating_Data+8).w,d0
    move.w  #$40,d1
    bra.s   Obj19_MoveRoutine2_Part2
 
; ===========================================================================
; loc_22126:
Obj19_MoveRoutine2:
    move.b  (Oscillating_Data+$C).w,d0
    move.w  #$60,d1
; loc_2212E:
Obj19_MoveRoutine2_Part2:
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    add.w   d1,d0
+
    move.w  objoff_30(a0),d1
    sub.w   d0,d1
    move.w  d1,x_pos(a0)
    rts
 
; ===========================================================================
; loc_22146:
Obj19_MoveRoutine3:
    move.b  (Oscillating_Data+$1C).w,d0
    move.w  #$80,d1
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    add.w   d1,d0
+
    move.w  objoff_32(a0),d1
    sub.w   d0,d1
    move.w  d1,y_pos(a0)
    rts
 
; ===========================================================================
; loc_22166:
Obj19_MoveRoutine4:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   +   ; rts
    addq.b  #1,subtype(a0)
+   rts
 
; ===========================================================================
; loc_22176:
Obj19_MoveRoutine5:
    jsrto   (ObjectMove).l, JmpTo5_ObjectMove
    moveq   #8,d1
    move.w  objoff_32(a0),d0
    subi.w  #$60,d0
    cmp.w   y_pos(a0),d0
    bhs.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    bne.s   Obj19_MoveRoutineNull
    addq.b  #1,subtype(a0)
 
; return_22196:
Obj19_MoveRoutineNull:
    rts
 
; ===========================================================================
; loc_22198:
Obj19_MoveRoutine6:
    jsrto   (ObjectMove).l, JmpTo5_ObjectMove
    moveq   #8,d1
    move.w  objoff_32(a0),d0
    subi.w  #$60,d0
    cmp.w   y_pos(a0),d0
    bhs.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    rts
 
; ===========================================================================
; loc_221B4:
Obj19_MoveRoutine7:
    move.b  (Oscillating_Data+$38).w,d1
    subi.b  #$40,d1
    ext.w   d1
    move.b  (Oscillating_Data+$3C).w,d2
    subi.b  #$40,d2
    ext.w   d2
    btst    #2,d0
    beq.s   +
    neg.w   d1
    neg.w   d2
+
    btst    #1,d0
    beq.s   +
    neg.w   d1
    exg d1,d2
+
    add.w   objoff_30(a0),d1
    move.w  d1,x_pos(a0)
    add.w   objoff_32(a0),d2
    move.w  d2,y_pos(a0)
    rts
 
; ===========================================================================
; loc_221EE:
Obj19_MoveRoutine8:
    move.b  (Oscillating_Data+$38).w,d1
    subi.b  #$40,d1
    ext.w   d1
    move.b  (Oscillating_Data+$3C).w,d2
    subi.b  #$40,d2
    ext.w   d2
    btst    #2,d0
    beq.s   +
    neg.w   d1
    neg.w   d2
+
    btst    #1,d0
    beq.s   +
    neg.w   d1
    exg d1,d2
+
    neg.w   d1
    add.w   objoff_30(a0),d1
    move.w  d1,x_pos(a0)
    add.w   objoff_32(a0),d2
    move.w  d2,y_pos(a0)
    rts
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj19_MapUnc_2222A: BINCLUDE "mappings/sprite/obj19.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo11_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo20_DeleteObject 
    jmp (DeleteObject).l
JmpTo15_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo4_PlatformObject 
    jmp (PlatformObject).l
; loc_222A4:
JmpTo5_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo20_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1B - Speed booster from CPZ
; ----------------------------------------------------------------------------
speedbooster_boostspeed =   objoff_30
; Sprite_222AC:
Obj1B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1B_Index(pc,d0.w),d1
    jmp Obj1B_Index(pc,d1.w)
; ===========================================================================
; off_222BA:
Obj1B_Index:    offsetTable
        offsetTableEntry.w Obj1B_Init   ; 0
        offsetTableEntry.w Obj1B_Main   ; 2
; ---------------------------------------------------------------------------
; word_222BE:
Obj1B_BoosterSpeeds:
    dc.w $1000
    dc.w  $A00
; ===========================================================================
; loc_222C2:
Obj1B_Init:
    addq.b  #2,routine(a0) ; => Obj1B_Main
    move.l  #Obj1B_MapUnc_223E2,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBooster,3,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo16_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  subtype(a0),d0
    andi.w  #2,d0
    move.w  Obj1B_BoosterSpeeds(pc,d0.w),speedbooster_boostspeed(a0)
 
; loc_222F8:
Obj1B_Main:
    move.b  (Timer_frames+1).w,d0
    andi.b  #2,d0
    move.b  d0,mapping_frame(a0)
    move.w  x_pos(a0),d0
    move.w  d0,d1
    subi.w  #$10,d0
    addi.w  #$10,d1
    move.w  y_pos(a0),d2
    move.w  d2,d3
    subi.w  #$10,d2
    addi.w  #$10,d3
 
    lea (MainCharacter).w,a1 ; a1=character
    btst    #1,status(a1)
    bne.s   +
    move.w  x_pos(a1),d4
    cmp.w   d0,d4
    blo.w   +
    cmp.w   d1,d4
    bhs.w   +
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.w   +
    cmp.w   d3,d4
    bhs.w   +
    move.w  d0,-(sp)
    bsr.w   Obj1B_GiveBoost
    move.w  (sp)+,d0
+
    lea (Sidekick).w,a1 ; a1=character
    btst    #1,status(a1)
    bne.s   +
    move.w  x_pos(a1),d4
    cmp.w   d0,d4
    blo.w   +
    cmp.w   d1,d4
    bhs.w   +
    move.w  y_pos(a1),d4
    cmp.w   d2,d4
    blo.w   +
    cmp.w   d3,d4
    bhs.w   +
    bsr.w   Obj1B_GiveBoost
+
    jmpto   (MarkObjGone).l, JmpTo6_MarkObjGone
 
; ===========================================================================
; sub_22388:
Obj1B_GiveBoost:
    move.w  x_vel(a1),d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0 ; d0 = absolute value of character's x velocity
+
    cmpi.w  #$1000,d0       ; is the character already going super fast?
    bge.s   Obj1B_GiveBoost_Done    ; if yes, branch to not change the speed
    move.w  speedbooster_boostspeed(a0),x_vel(a1) ; make the character go super fast
    bclr    #0,status(a1)   ; turn him right
    btst    #0,status(a0)   ; was that the correct direction?
    beq.s   +       ; if yes, branch
    bset    #0,status(a1)   ; turn him left
    neg.w   x_vel(a1)   ; make the boosting direction left
+
    move.w  #$F,move_lock(a1)   ; don't let him turn around for a few frames
    move.w  x_vel(a1),inertia(a1)   ; update his inertia value
    bclr    #5,status(a0)
    bclr    #6,status(a0)
    bclr    #5,status(a1)
; loc_223D8:
Obj1B_GiveBoost_Done:
    move.w  #SndID_Spring,d0 ; spring boing sound
    jmp (PlaySound).l
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj1B_MapUnc_223E2: BINCLUDE "mappings/sprite/obj1B.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo6_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo16_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1D - Blue balls in CPZ
; ----------------------------------------------------------------------------
; Sprite_22408:
Obj1D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1D_Index(pc,d0.w),d1
    jmp Obj1D_Index(pc,d1.w)
; ===========================================================================
; off_22416: Obj1D_States:
Obj1D_Index:    offsetTable
        offsetTableEntry.w Obj1D_Init       ; 0
        offsetTableEntry.w Obj1D_Wait       ; 2
        offsetTableEntry.w Obj1D_MoveArc    ; 4
        offsetTableEntry.w Obj1D_Wait       ; 6
        offsetTableEntry.w Obj1D_MoveStraight   ; 8
; ---------------------------------------------------------------------------
; unused table of speed values
; word_22420:
    dc.w -$480
    dc.w -$500
    dc.w -$600
    dc.w -$700
; ===========================================================================
; loc_22428:
Obj1D_Init:
    addq.b  #2,routine(a0) ; => Obj1D_Wait
    move.w  #-$480,y_vel(a0)
    moveq   #0,d1
    move.b  subtype(a0),d1
    move.b  d1,d0
    andi.b  #$F,d1  ; number of blue balls
    moveq   #2,d5   ; routine number
    andi.b  #$F0,d0
    beq.s   +
    moveq   #6,d5   ; routine number
+
    move.b  status(a0),d4
    moveq   #0,d2
    movea.l a0,a1
    bra.s   Obj1D_InitBall
; ---------------------------------------------------------------------------
Obj1D_LoadBall:
    jsrto   (SingleObjLoad2).l, JmpTo5_SingleObjLoad2
    bne.s   ++
; loc_22458:
Obj1D_InitBall:
    _move.b id(a0),id(a1) ; load obj1D
    move.b  d5,routine(a1) ; => Obj1D_Wait (either one)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  #Obj1D_MapUnc_22576,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZDroplet,3,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo3_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #%10001011,collision_flags(a1)
    move.w  x_pos(a1),objoff_38(a1)
    move.w  y_pos(a1),objoff_30(a1)
    move.w  y_vel(a0),y_vel(a1)
    move.w  y_vel(a1),objoff_34(a1)
    move.b  #8,width_pixels(a1)
    move.w  #$60,objoff_3A(a1)
    move.w  #$B,objoff_36(a1)
    andi.b  #1,d4
    beq.s   +
    neg.w   objoff_36(a1)
    neg.w   objoff_3A(a1)
+
    move.w  d2,objoff_32(a1)
    addq.w  #3,d2
+
    dbf d1,Obj1D_LoadBall
    rts
; ===========================================================================
; loc_224D6:
Obj1D_Wait:
    subq.w  #1,objoff_32(a0)
    bpl.s   BranchTo_JmpTo7_MarkObjGone
    addq.b  #2,routine(a0) ; => Obj1D_MoveArc or Obj1D_MoveStraight
    move.w  #$3B,objoff_32(a0)
    move.w  #SndID_Gloop,d0
    jsr (PlaySoundLocal).l
 
BranchTo_JmpTo7_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo7_MarkObjGone
; ===========================================================================
; loc_224F4:
Obj1D_MoveArc:
    jsrto   (ObjectMove).l, JmpTo6_ObjectMove
    move.w  objoff_36(a0),d0
    add.w   d0,x_vel(a0)
    addi.w  #$18,y_vel(a0)
    bne.s   +
    neg.w   objoff_36(a0)
+
    move.w  objoff_30(a0),d0
    cmp.w   y_pos(a0),d0
    bhi.s   BranchTo2_JmpTo7_MarkObjGone
    move.w  objoff_34(a0),y_vel(a0)
    clr.w   x_vel(a0)
    subq.b  #2,routine(a0) ; => Obj1D_Wait
 
BranchTo2_JmpTo7_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo7_MarkObjGone
; ===========================================================================
; loc_22528:
Obj1D_MoveStraight:
    jsrto   (ObjectMove).l, JmpTo6_ObjectMove
    addi.w  #$18,y_vel(a0)
    bne.s   +
    move.w  objoff_3A(a0),d0
    add.w   objoff_38(a0),d0
    move.w  d0,x_pos(a0)
+
    cmpi.w  #$180,y_vel(a0)
    bne.s   +
    move.w  #SndID_Gloop,d0
    jsr (PlaySoundLocal).l
+
    move.w  objoff_30(a0),d0
    cmp.w   y_pos(a0),d0
    bhi.s   BranchTo3_JmpTo7_MarkObjGone
    move.w  objoff_34(a0),y_vel(a0)
    move.w  objoff_38(a0),x_pos(a0)
    move.w  #SndID_Gloop,d0
    jsr (PlaySoundLocal).l
 
BranchTo3_JmpTo7_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo7_MarkObjGone
; ===========================================================================
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj1D_MapUnc_22576: BINCLUDE "mappings/sprite/obj1D.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo7_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo5_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo3_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
; loc_22596:
JmpTo6_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 1E - Spin tube from CPZ
; ----------------------------------------------------------------------------
; Sprite_2259C:
Obj1E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj1E_Index(pc,d0.w),d1
    jsr Obj1E_Index(pc,d1.w)
    move.b  objoff_2C(a0),d0
    add.b   objoff_36(a0),d0
    beq.w   JmpTo_MarkObjGone3
    rts
 
    if removeJmpTos
JmpTo_MarkObjGone3 
    jmp (MarkObjGone3).l
    endif
; ===========================================================================
; JmpTbl_225B8: Obj1E_States:
Obj1E_Index:    offsetTable
        offsetTableEntry.w Obj1E_Init   ; 0
        offsetTableEntry.w Obj1E_Main   ; 2
; ===========================================================================
word_225BC:
    dc.w   $A0  ; 0
    dc.w  $100  ; 2
    dc.w  $120  ; 4
; ===========================================================================
; loc_225C2: LoadSubtype_1E:
Obj1E_Init:
    addq.b  #2,routine(a0)
    move.b  subtype(a0),d0
    add.w   d0,d0
    andi.w  #6,d0
    move.w  word_225BC(pc,d0.w),objoff_2A(a0)
; loc_225D6:
Obj1E_Main:
    lea (MainCharacter).w,a1 ; a1=character
    lea objoff_2C(a0),a4
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    lea objoff_36(a0),a4
+
    moveq   #0,d0
    move.b  (a4),d0
    move.w  Obj1E_Modes(pc,d0.w),d0
    jmp Obj1E_Modes(pc,d0.w)
; ===========================================================================
; off_225F4:
Obj1E_Modes:    offsetTable
        offsetTableEntry.w loc_225FC    ; 0
        offsetTableEntry.w loc_2271A    ; 2
        offsetTableEntry.w loc_227FE    ; 4
        offsetTableEntry.w loc_2286A    ; 6
; ===========================================================================
 
loc_225FC:
    tst.w   (Debug_placement_mode).w
    bne.w   return_22718
    move.w  objoff_2A(a0),d2
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    cmp.w   d2,d0
    bhs.w   return_22718
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    cmpi.w  #$80,d1
    bhs.w   return_22718
    cmpi.b  #$20,anim(a1)
    beq.w   return_22718
 
    moveq   #0,d3
    cmpi.w  #$A0,d2
    beq.s   +
    moveq   #8,d3
    cmpi.w  #$120,d2
    beq.s   +
    moveq   #4,d3
    neg.w   d0
    addi.w  #$100,d0
+
    cmpi.w  #$80,d0
    blo.s   loc_2267E
    moveq   #0,d2
    move.b  subtype(a0),d0
    lsr.w   #2,d0
    andi.w  #$F,d0
    move.b  byte_2266E(pc,d0.w),d2
    cmpi.b  #2,d2
    bne.s   loc_22688
    move.b  (Timer_second).w,d2
    andi.b  #1,d2
    bra.s   loc_22688
; ===========================================================================
byte_2266E:
    dc.b   2
    dc.b   2    ; 1
    dc.b   2    ; 2
    dc.b   2    ; 3
    dc.b   2    ; 4
    dc.b   2    ; 5
    dc.b   2    ; 6
    dc.b   2    ; 7
    dc.b   2    ; 8
    dc.b   2    ; 9
    dc.b   0    ; 10
    dc.b   2    ; 11
    dc.b   0    ; 12
    dc.b   1    ; 13
    dc.b   2    ; 14
    dc.b   1    ; 15
; ===========================================================================
 
loc_2267E:
    moveq   #2,d2
    cmpi.w  #$40,d1
    bhs.s   loc_22688
    moveq   #3,d2
 
loc_22688:
    move.b  d2,1(a4)
    add.w   d3,d2
    add.w   d2,d2
    andi.w  #$1E,d2
    lea off_22980(pc),a2
    adda.w  (a2,d2.w),a2
    move.w  (a2)+,4(a4)
    subq.w  #4,4(a4)
    move.w  (a2)+,d4
    add.w   x_pos(a0),d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    add.w   y_pos(a0),d5
    move.w  d5,y_pos(a1)
    move.l  a2,6(a4)
    move.w  (a2)+,d4
    add.w   x_pos(a0),d4
    move.w  (a2)+,d5
    add.w   y_pos(a0),d5
    addq.b  #2,(a4)
    move.b  #$81,obj_control(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  #$800,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    bclr    #5,status(a0)
    bclr    #5,status(a1)
    bset    #1,status(a1)
    move.b  #0,jumping(a1)
    bclr    #high_priority_bit,art_tile(a1)
    move.w  #$800,d2
    bsr.w   loc_22902
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
 
return_22718:
    rts
; ===========================================================================
 
loc_2271A:
    subq.b  #1,2(a4)
    bpl.s   Obj1E_MoveCharacter
    movea.l 6(a4),a2
    move.w  (a2)+,d4
    add.w   x_pos(a0),d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    add.w   y_pos(a0),d5
    move.w  d5,y_pos(a1)
    tst.b   1(a4)
    bpl.s   +
    subq.w  #8,a2
+
    move.l  a2,6(a4)
    subq.w  #4,4(a4)
    beq.s   loc_22784
    move.w  (a2)+,d4
    add.w   x_pos(a0),d4
    move.w  (a2)+,d5
    add.w   y_pos(a0),d5
    move.w  #$800,d2
    bra.w   loc_22902
; ===========================================================================
; update the position of Sonic/Tails in the CPZ tube
; loc_2275E:
Obj1E_MoveCharacter:
    move.l  x_pos(a1),d2
    move.l  y_pos(a1),d3
    move.w  x_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,x_pos(a1)
    move.l  d3,y_pos(a1)
    rts
; ===========================================================================
 
loc_22784:
    cmpi.b  #4,1(a4)
    bhs.s   loc_227A6
    move.b  subtype(a0),d0
    andi.w  #$FC,d0
    add.b   1(a4),d0
    move.b  #4,1(a4)
    move.b  byte_227BE(pc,d0.w),d0
    bne.w   loc_22892
 
loc_227A6:
    andi.w  #$7FF,y_pos(a1)
    move.b  #6,(a4)
    clr.b   obj_control(a1)
    move.w  #SndID_SpindashRelease,d0
    jmp (PlaySound).l
; ===========================================================================
byte_227BE:
    dc.b   2,  1,  0,  0
    dc.b  -1,  3,  0,  0
    dc.b   4, -2,  0,  0
    dc.b  -3, -4,  0,  0
    dc.b  -5, -5,  0,  0
    dc.b   7,  6,  0,  0
    dc.b  -7, -6,  0,  0
    dc.b   8,  9,  0,  0
    dc.b  -8, -9,  0,  0
    dc.b  11, 10,  0,  0
    dc.b  12,  0,  0,  0
    dc.b -11,-10,  0,  0
    dc.b -12,  0,  0,  0
    dc.b   0, 13,  0,  0
    dc.b -13, 14,  0,  0
    dc.b   0,-14,  0,  0
; ===========================================================================
 
loc_227FE:
    subq.b  #1,2(a4)
    bpl.s   Obj1E_MoveCharacter_2
    movea.l 6(a4),a2
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
    tst.b   1(a4)
    bpl.s   loc_2281C
    subq.w  #8,a2
 
loc_2281C:
    move.l  a2,6(a4)
    subq.w  #4,4(a4)
    beq.s   loc_22858
    move.w  (a2)+,d4
    move.w  (a2)+,d5
    move.w  #$800,d2
    bra.w   loc_22902
; ===========================================================================
; update the position of Sonic/Tails in the CPZ tube
; loc_22832:
Obj1E_MoveCharacter_2:
    move.l  x_pos(a1),d2
    move.l  y_pos(a1),d3
    move.w  x_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,x_pos(a1)
    move.l  d3,y_pos(a1)
    rts
; ===========================================================================
 
loc_22858:
    andi.w  #$7FF,y_pos(a1)
    clr.b   (a4)
    move.w  #SndID_SpindashRelease,d0
    jmp (PlaySound).l
; ===========================================================================
 
loc_2286A:
    move.w  objoff_2A(a0),d2
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    cmp.w   d2,d0
    bhs.w   loc_2288E
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    cmpi.w  #$80,d1
    bhs.w   loc_2288E
    rts
; ===========================================================================
 
loc_2288E:
    clr.b   (a4)
    rts
; ===========================================================================
 
loc_22892:
    bpl.s   loc_228C4
    neg.b   d0
    move.b  #-4,1(a4)
    add.w   d0,d0
    lea (off_22E88).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d0
    subq.w  #4,d0
    move.w  d0,4(a4)
    lea (a2,d0.w),a2
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
    subq.w  #8,a2
    bra.s   loc_228E4
; ===========================================================================
 
loc_228C4:
    add.w   d0,d0
    lea (off_22E88).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,4(a4)
    subq.w  #4,4(a4)
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
 
loc_228E4:
    move.l  a2,6(a4)
    move.w  (a2)+,d4
    move.w  (a2)+,d5
    move.w  #$800,d2
    bsr.w   loc_22902
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
    addq.b  #2,(a4)
    rts
; ===========================================================================
 
loc_22902:
    moveq   #0,d0
    move.w  d2,d3
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    bge.s   +
    neg.w   d0
    neg.w   d2
+
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    bge.s   +
    neg.w   d1
    neg.w   d3
+
    cmp.w   d0,d1
    blo.s   loc_22952
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    swap    d1
    divs.w  d3,d1
    moveq   #0,d0
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    beq.s   +
    swap    d0
    divs.w  d1,d0
+
    move.w  d0,x_vel(a1)
    move.w  d3,y_vel(a1)
    abs.w   d1
    move.w  d1,2(a4)
    rts
; ===========================================================================
 
loc_22952:
    moveq   #0,d0
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    swap    d0
    divs.w  d2,d0
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    beq.s   +
    swap    d1
    divs.w  d0,d1
+
    move.w  d1,y_vel(a1)
    move.w  d2,x_vel(a1)
    abs.w   d0
    move.w  d0,2(a4)
    rts
; ===========================================================================
obj1E67Size macro {INTLABEL}
__LABEL__ label *
    dc.w __LABEL___End-__LABEL__-2
    endm
; -------------------------------------------------------------------------------
; spin tube data - entry/exit
; -------------------------------------------------------------------------------
; off_22980:
    include "misc/obj1E_a.asm"
; -------------------------------------------------------------------------------
; spin tube data - main tube
; -------------------------------------------------------------------------------
; off_22E88:
    include "misc/obj1E_b.asm"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_MarkObjGone3 
    jmp (MarkObjGone3).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 20 - Lava bubble from Hill Top Zone (boss weapon)
; ----------------------------------------------------------------------------
; Sprite_22FF8:
Obj20:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj20_Index(pc,d0.w),d1
    jmp Obj20_Index(pc,d1.w)
; ===========================================================================
; off_23006:
Obj20_Index:    offsetTable
        offsetTableEntry.w Obj20_Init               ;  0
        offsetTableEntry.w loc_23076                ;  2
        offsetTableEntry.w loc_23084                ;  4
        offsetTableEntry.w loc_2311E                ;  6
        offsetTableEntry.w loc_23144                ;  8
        offsetTableEntry.w loc_231D2                ; $A
        offsetTableEntry.w BranchTo_JmpTo21_DeleteObject    ; $C
; ===========================================================================
; loc_23014:
Obj20_Init:
    addq.b  #2,routine(a0)
    move.b  #8,y_radius(a0)
    move.b  #8,x_radius(a0)
    move.l  #Obj20_MapUnc_23254,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HtzFireball,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo17_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #8,width_pixels(a0)
    move.w  y_pos(a0),objoff_30(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #3,d0
    andi.w  #$780,d0
    neg.w   d0
    move.w  d0,x_vel(a0)
    move.w  d0,y_vel(a0)
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lsl.w   #4,d0
    move.w  d0,objoff_32(a0)
    move.w  d0,objoff_34(a0)
 
loc_23076:
    lea (Ani_obj20).l,a1
    jsrto   (AnimateSprite).l, JmpTo4_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo8_MarkObjGone
; ===========================================================================
 
loc_23084:
    cmpi.b  #5,anim_frame_duration(a0)
    bne.s   loc_230B4
    jsrto   (SingleObjLoad2).l, JmpTo6_SingleObjLoad2
    bne.s   loc_230A6
    bsr.s   loc_230C2
    jsrto   (SingleObjLoad2).l, JmpTo6_SingleObjLoad2
    bne.s   loc_230A6
    bsr.s   loc_230C2
    neg.w   x_vel(a1)
    bset    #0,render_flags(a1)
 
loc_230A6:
    move.w  #SndID_ArrowFiring,d0
    jsr (PlaySound).l
    addq.b  #2,routine(a0)
 
loc_230B4:
    lea (Ani_obj20).l,a1
    jsrto   (AnimateSprite).l, JmpTo4_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo8_MarkObjGone
; ===========================================================================
 
loc_230C2:
    _move.b #ObjID_LavaBubble,id(a1) ; load obj20
    move.b  #8,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  x_vel(a0),x_vel(a1)
    move.w  y_vel(a0),y_vel(a1)
    move.b  #8,y_radius(a1)
    move.b  #8,x_radius(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #8,width_pixels(a1)
    move.b  #$8B,collision_flags(a1)
    move.w  y_pos(a1),objoff_30(a1)
    rts
; ===========================================================================
 
loc_2311E:
    subq.w  #1,objoff_32(a0)
    bpl.s   loc_23136
    move.w  objoff_34(a0),objoff_32(a0)
    move.b  #2,routine(a0)
    move.w  #1,anim(a0)
 
loc_23136:
    lea (Ani_obj20).l,a1
    jsrto   (AnimateSprite).l, JmpTo4_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo8_MarkObjGone
; ===========================================================================
 
loc_23144:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_2315A
    move.b  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #1,mapping_frame(a0)
 
loc_2315A:
    jsrto   (ObjectMove).l, JmpTo7_ObjectMove
    addi.w  #$18,y_vel(a0)
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    bhs.s   loc_23176
    jmpto   (DeleteObject).l, JmpTo21_DeleteObject
; ===========================================================================
 
loc_23176:
    bclr    #1,render_flags(a0)
    tst.w   y_vel(a0)
    bmi.s   BranchTo_JmpTo8_MarkObjGone
    bset    #1,render_flags(a0)
    bsr.w   ObjCheckFloorDist
    tst.w   d1
    bpl.s   BranchTo_JmpTo8_MarkObjGone
    add.w   d1,y_pos(a0)
    addq.b  #2,routine(a0)
    move.b  #2,anim(a0)
    move.b  #4,mapping_frame(a0)
    move.w  #0,y_vel(a0)
    move.l  #Obj20_MapUnc_23294,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Buzzer_Fireball_1,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo17_Adjust2PArtPointer
    move.b  #0,mapping_frame(a0)
    move.w  #9,objoff_32(a0)
    move.b  #3,objoff_36(a0)
 
BranchTo_JmpTo8_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo8_MarkObjGone
; ===========================================================================
 
loc_231D2:
    subq.w  #1,objoff_32(a0)
    bpl.s   loc_23224
    move.w  #$7F,objoff_32(a0)
    subq.b  #1,objoff_36(a0)
    bmi.s   loc_23224
    jsrto   (SingleObjLoad2).l, JmpTo6_SingleObjLoad2
    bne.s   loc_23224
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
 
loc_231F0:
    move.l  (a0,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,loc_231F0
    if object_size&3
    move.w  (a0,d0.w),(a1,d0.w)
    endif
 
    move.w  #9,objoff_32(a1)
    move.w  #$200,anim(a1)
    move.w  #$E,d0
    tst.w   x_vel(a1)
    bpl.s   loc_23214
    neg.w   d0
 
loc_23214:
    add.w   d0,x_pos(a1)
    move.l  a1,-(sp)
    bsr.w   FireCheckFloorDist
    movea.l (sp)+,a1 ; a1=object
    add.w   d1,y_pos(a1)
 
loc_23224:
    lea (Ani_obj20).l,a1
    jsrto   (AnimateSprite).l, JmpTo4_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo8_MarkObjGone
; ===========================================================================
 
BranchTo_JmpTo21_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo21_DeleteObject
; ===========================================================================
; animation script
; off_23236:
Ani_obj20:  offsetTable
        offsetTableEntry.w byte_2323C   ; 0
        offsetTableEntry.w byte_23243   ; 1
        offsetTableEntry.w byte_23246   ; 2
byte_2323C: dc.b  $B,  2,  3,$FC,  4,$FD,  1
    rev02even
byte_23243: dc.b $7F,  5,$FF
    rev02even
byte_23246: dc.b   5,  4,  5,  2,  3,  0,  1,  0,  1,  2,  3,  4,  5,$FC
    even
 
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj20_MapUnc_23254: BINCLUDE "mappings/sprite/obj20_a.bin"
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj20_MapUnc_23294: BINCLUDE "mappings/sprite/obj20_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo21_DeleteObject 
    jmp (DeleteObject).l
JmpTo8_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo6_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo4_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo17_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
; loc_232FA:
JmpTo7_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 2F - Smashable ground in Hill Top Zone
; ----------------------------------------------------------------------------
; Sprite_23300:
Obj2F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2F_Index(pc,d0.w),d1
    jmp Obj2F_Index(pc,d1.w)
; ===========================================================================
; off_2330E:
Obj2F_Index:    offsetTable
        offsetTableEntry.w Obj2F_Init       ; 0
        offsetTableEntry.w Obj2F_Main       ; 2
        offsetTableEntry.w Obj2F_Fragment   ; 4
; ===========================================================================
; byte_23314:
Obj2F_Properties:
    ;    y_radius
    ;     mapping_frame
    dc.b $24, 0 ; 0
    dc.b $20, 2 ; 2
    dc.b $18, 4 ; 4
    dc.b $10, 6 ; 6
    dc.b   8, 8 ; 8
; ===========================================================================
; loc_2331E:
Obj2F_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj2F_MapUnc_236FA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,2,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo18_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$1E,d0
    lea Obj2F_Properties(pc,d0.w),a2
    move.b  (a2)+,y_radius(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.b  #$20,y_radius(a0)
    bset    #4,render_flags(a0)
; loc_23368:
Obj2F_Main:
    move.w  (Chain_Bonus_counter).w,objoff_38(a0)
    move.b  (MainCharacter+anim).w,objoff_32(a0)
    move.b  (Sidekick+anim).w,objoff_33(a0)
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo3_SolidObject
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
 
BranchTo_JmpTo9_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo9_MarkObjGone
; ===========================================================================
+
    cmpi.b  #standing_mask,d0
    bne.s   loc_23408
    cmpi.b  #AniIDSonAni_Roll,objoff_32(a0)
    bne.s   loc_233C0
    tst.b   subtype(a0)
    bmi.s   loc_233F0
    cmpi.b  #$E,(MainCharacter+top_solid_bit).w
    beq.s   loc_233F0
 
loc_233C0:
    move.b  #$C,(MainCharacter+top_solid_bit).w
    move.b  #$D,(MainCharacter+lrb_solid_bit).w
    cmpi.b  #AniIDSonAni_Roll,objoff_33(a0)
    bne.s   loc_233E2
    tst.b   subtype(a0)
    bmi.s   loc_233F0
    cmpi.b  #$E,(Sidekick+top_solid_bit).w
    beq.s   loc_233F0
 
loc_233E2:
    move.b  #$C,(Sidekick+top_solid_bit).w
    move.b  #$D,(Sidekick+lrb_solid_bit).w
    bra.s   BranchTo_JmpTo9_MarkObjGone
; ===========================================================================
 
loc_233F0:
    lea (MainCharacter).w,a1 ; a1=character
    move.b  objoff_32(a0),d0
    bsr.s   loc_2343E
    lea (Sidekick).w,a1 ; a1=character
    move.b  objoff_33(a0),d0
    bsr.s   loc_2343E
    bra.w   loc_234A4
; ===========================================================================
 
loc_23408:
    move.b  d0,d1
    andi.b  #p1_standing,d1
    beq.s   loc_23470
    cmpi.b  #AniIDSonAni_Roll,objoff_32(a0)
    bne.s   loc_23426
    tst.b   subtype(a0)
    bmi.s   loc_23436
    cmpi.b  #$E,(MainCharacter+top_solid_bit).w
    beq.s   loc_23436
 
loc_23426:
    move.b  #$C,(MainCharacter+top_solid_bit).w
    move.b  #$D,(MainCharacter+lrb_solid_bit).w
    bra.w   BranchTo_JmpTo9_MarkObjGone
; ===========================================================================
 
loc_23436:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_23444
    bra.s   loc_234A4
; ===========================================================================
 
loc_2343E:
    cmpi.b  #AniIDSonAni_Roll,d0
    bne.s   loc_2345C
 
loc_23444:
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
 
loc_2345C:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    rts
; ===========================================================================
 
loc_23470:
    andi.b  #p2_standing,d0
    beq.w   BranchTo_JmpTo9_MarkObjGone
    cmpi.b  #AniIDSonAni_Roll,objoff_33(a0)
    bne.s   loc_2348E
    tst.b   subtype(a0)
    bmi.s   loc_2349E
    cmpi.b  #$E,(Sidekick+top_solid_bit).w
    beq.s   loc_2349E
 
loc_2348E:
    move.b  #$C,(Sidekick+top_solid_bit).w
    move.b  #$D,(Sidekick+lrb_solid_bit).w
    bra.w   BranchTo_JmpTo9_MarkObjGone
; ===========================================================================
 
loc_2349E:
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   loc_23444
 
loc_234A4:
    move.w  objoff_38(a0),(Chain_Bonus_counter).w
    andi.b  #~standing_mask,status(a0)
    lea (byte_234F2).l,a4
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    addq.b  #1,mapping_frame(a0)
    move.l  d0,d1
    add.w   d0,d0
    add.w   d0,d0
    lea (a4,d0.w),a4
    neg.w   d1
    addi.w  #9,d1
    move.w  #$18,d2
    jsrto   (BreakObjectToPieces).l, JmpTo_BreakObjectToPieces
    bsr.w   SmashableObject_LoadPoints
; loc_234DC:
Obj2F_Fragment:
    jsrto   (ObjectMove).l, JmpTo8_ObjectMove
    addi.w  #$18,y_vel(a0)
    tst.b   render_flags(a0)
    bpl.w   JmpTo22_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo12_DisplaySprite
; ===========================================================================
byte_234F2:
    dc.b $FF
    dc.b   0    ; 1
    dc.b $F8    ; 2
    dc.b   0    ; 3
    dc.b   1    ; 4
    dc.b   0    ; 5
    dc.b $F8    ; 6
    dc.b   0    ; 7
    dc.b $FF    ; 8
    dc.b $20    ; 9
    dc.b $F9    ; 10
    dc.b   0    ; 11
    dc.b   0    ; 12
    dc.b $E0    ; 13
    dc.b $F9    ; 14
    dc.b   0    ; 15
    dc.b $FF    ; 16
    dc.b $40    ; 17
    dc.b $FA    ; 18
    dc.b   0    ; 19
    dc.b   0    ; 20
    dc.b $C0    ; 21
    dc.b $FA    ; 22
    dc.b   0    ; 23
    dc.b $FF    ; 24
    dc.b $60    ; 25
    dc.b $FB    ; 26
    dc.b   0    ; 27
    dc.b   0    ; 28
    dc.b $A0    ; 29
    dc.b $FB    ; 30
    dc.b   0    ; 31
    dc.b $FF    ; 32
    dc.b $80    ; 33
    dc.b $FC    ; 34
    dc.b   0    ; 35
    dc.b   0    ; 36
    dc.b $80    ; 37
    dc.b $FC    ; 38
    dc.b   0    ; 39
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 32 - Breakable block/rock from CPZ and HTZ
; ----------------------------------------------------------------------------
breakableblock_mainchar_anim =  objoff_32
breakableblock_sidekick_anim =  objoff_33
; Sprite_2351A:
Obj32:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj32_Index(pc,d0.w),d1
    jmp Obj32_Index(pc,d1.w)
; ===========================================================================
; off_23528:
Obj32_Index:    offsetTable
        offsetTableEntry.w Obj32_Init       ; 0
        offsetTableEntry.w Obj32_Main       ; 2
        offsetTableEntry.w Obj32_Fragment   ; 4
; ===========================================================================
; loc_2352E:
Obj32_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj32_MapUnc_23852,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HtzRock,2,0),art_tile(a0)
    move.b  #$18,width_pixels(a0)
    move.l  #Obj32_VelArray1,objoff_3C(a0)
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj32_MapUnc_23886,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZMetalBlock,3,0),art_tile(a0)
    move.b  #$10,width_pixels(a0)
    move.l  #Obj32_VelArray2,objoff_3C(a0)
+
    jsrto   (Adjust2PArtPointer).l, JmpTo18_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
; loc_23582:
Obj32_Main:
    move.w  (Chain_Bonus_counter).w,objoff_38(a0)
    move.b  (MainCharacter+anim).w,breakableblock_mainchar_anim(a0)
    move.b  (Sidekick+anim).w,breakableblock_sidekick_anim(a0)
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo3_SolidObject
    move.b  status(a0),d0
    andi.b  #standing_mask,d0   ; is at least one player standing on the object?
    bne.s   Obj32_SupportingSomeone
 
BranchTo2_JmpTo9_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo9_MarkObjGone
; ===========================================================================
; loc_235BC:
Obj32_SupportingSomeone:
    cmpi.b  #standing_mask,d0   ; are BOTH players standing on the object?
    bne.s   Obj32_SupportingOnePlayerOnly   ; if not, branch
    cmpi.b  #AniIDSonAni_Roll,breakableblock_mainchar_anim(a0)
    beq.s   +
    cmpi.b  #AniIDSonAni_Roll,breakableblock_sidekick_anim(a0)
    bne.s   BranchTo2_JmpTo9_MarkObjGone
+
    lea (MainCharacter).w,a1 ; a1=character
    move.b  breakableblock_mainchar_anim(a0),d0
    bsr.s   Obj32_SetCharacterOffBlock
    lea (Sidekick).w,a1 ; a1=character
    move.b  breakableblock_sidekick_anim(a0),d0
    bsr.s   Obj32_SetCharacterOffBlock
    bra.w   Obj32_Destroy
; ===========================================================================
; loc_235EA:
Obj32_SupportingOnePlayerOnly:
    move.b  d0,d1
    andi.b  #p1_standing,d1          ; is the main character standing on the object?
    beq.s   Obj32_SupportingSidekick ; if not, branch
    cmpi.b  #AniIDSonAni_Roll,breakableblock_mainchar_anim(a0)
    bne.s   BranchTo2_JmpTo9_MarkObjGone
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj32_BouncePlayer
    bra.s   Obj32_Destroy
; ===========================================================================
; loc_23602:
Obj32_SetCharacterOffBlock:
    cmpi.b  #AniIDSonAni_Roll,d0
    bne.s   +
; loc_23608:
Obj32_BouncePlayer:
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  #-$300,y_vel(a1)
+
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    rts
; ===========================================================================
; loc_2363A:
Obj32_SupportingSidekick:
    andi.b  #p2_standing,d0 ; is the sidekick standing on the object? (at this point, it should...)
    beq.w   BranchTo2_JmpTo9_MarkObjGone ; if, by miracle, he's not, branch
    cmpi.b  #2,breakableblock_sidekick_anim(a0)
    bne.w   BranchTo2_JmpTo9_MarkObjGone
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   Obj32_BouncePlayer
; loc_23652:
Obj32_Destroy:
    move.w  objoff_38(a0),(Chain_Bonus_counter).w
    andi.b  #~standing_mask,status(a0)
    movea.l objoff_3C(a0),a4
    jsrto   (BreakObjectToPieces).l, JmpTo_BreakObjectToPieces
    bsr.w   SmashableObject_LoadPoints
; loc_2366A:
Obj32_Fragment:
    jsrto   (ObjectMove).l, JmpTo8_ObjectMove
    addi.w  #$18,y_vel(a0)
    tst.b   render_flags(a0)
    bpl.w   JmpTo22_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo12_DisplaySprite
; ===========================================================================
; velocity array for smashed bits, two words for each fragment
; byte_23680:
Obj32_VelArray1:
    ;    x_vel y_vel
    dc.w -$200,-$200
    dc.w     0,-$280
    dc.w  $200,-$200
    dc.w -$1C0,-$1C0
    dc.w     0,-$200
    dc.w  $1C0,-$1C0
;byte_23698:
Obj32_VelArray2:
    ;    x_vel y_vel
    dc.w -$100,-$200
    dc.w  $100,-$200
    dc.w  -$C0,-$1C0
    dc.w   $C0,-$1C0
 
; ===========================================================================
; loc_236A8:
SmashableObject_LoadPoints:
    jsrto   (SingleObjLoad).l, JmpTo3_SingleObjLoad
    bne.s   +++ ; rts
    _move.b #ObjID_Points,id(a1) ; load obj29
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  (Chain_Bonus_counter).w,d2
    addq.w  #2,(Chain_Bonus_counter).w
    cmpi.w  #6,d2
    blo.s   +
    moveq   #6,d2
+
    moveq   #0,d0
    move.w  SmashableObject_ScoreBonus(pc,d2.w),d0
    cmpi.w  #$20,(Chain_Bonus_counter).w
    blo.s   +
    move.w  #1000,d0
    moveq   #$A,d2
+
    jsr (AddPoints).l
    lsr.w   #1,d2
    move.b  d2,mapping_frame(a1)
+
    rts
; ===========================================================================
; word_236F2:
SmashableObject_ScoreBonus:
    dc.w    10
    dc.w    20  ; 1
    dc.w    50  ; 2
    dc.w   100  ; 3
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj2F_MapUnc_236FA: BINCLUDE "mappings/sprite/obj2F.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj32_MapUnc_23852: BINCLUDE "mappings/sprite/obj32_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj32_MapUnc_23886: BINCLUDE "mappings/sprite/obj32_b.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo12_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo22_DeleteObject 
    jmp (DeleteObject).l
JmpTo3_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo9_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo18_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_BreakObjectToPieces 
    jmp (BreakObjectToPieces).l
JmpTo3_SolidObject 
    jmp (SolidObject).l
; loc_238D6:
JmpTo8_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo22_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 30 - Large rising lava during earthquake in HTZ
; ----------------------------------------------------------------------------
; Sprite_238DC:
Obj30:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj30_Index(pc,d0.w),d1
    jmp Obj30_Index(pc,d1.w)
; ===========================================================================
; off_238EA:
Obj30_Index:    offsetTable
        offsetTableEntry.w Obj30_Init   ; 0
        offsetTableEntry.w Obj30_Main   ; 2
; ===========================================================================
; byte_238EE:
Obj30_Widths:
    dc.b $C0
    dc.b   0    ; 1
    dc.b $C0    ; 2
    dc.b   0    ; 3
    dc.b $C0    ; 4
    dc.b   0    ; 5
    dc.b $E0    ; 6
    dc.b   0    ; 7
    dc.b $C0    ; 8
    dc.b   0    ; 9
; ===========================================================================
; loc_238F8:
Obj30_Init:
    addq.b  #2,routine(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.w  x_pos(a0),objoff_30(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.b  Obj30_Widths(pc,d0.w),width_pixels(a0)
    cmpi.b  #6,d0
    blo.s   Obj30_Main
    bne.s   +
    cmpi.w  #$380,(Camera_Y_pos).w
    bhs.s   Obj30_Main
    bra.s   ++
; ===========================================================================
+
    cmpi.w  #$380,(Camera_Y_pos).w
    blo.s   Obj30_Main
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    jmpto   (DeleteObject).l, JmpTo23_DeleteObject
; ===========================================================================
; loc_23944:
Obj30_Main:
    move.w  objoff_32(a0),d0
    add.w   (Camera_BG_Y_offset).w,d0
    move.w  d0,y_pos(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.w  Obj30_Modes(pc,d0.w),d1
    jsr Obj30_Modes(pc,d1.w)
    tst.b   (Screen_Shaking_Flag_HTZ).w
    beq.w   JmpTo2_MarkObjGone3
    rts
; ===========================================================================
; off_23968:
Obj30_Modes:    offsetTable
        offsetTableEntry.w loc_23972    ; 0
        offsetTableEntry.w loc_23972    ; 2
        offsetTableEntry.w loc_2398A    ; 4
        offsetTableEntry.w loc_239D0    ; 6
        offsetTableEntry.w loc_239EA    ; 8
; ===========================================================================
 
loc_23972:
    move.w  #$CB,d1
    move.w  #$80,d2
    move.w  #$81,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject_Always).l, JmpTo_SolidObject_Always
    jmpto   (DropOnFloor).l, JmpTo_DropOnFloor
; ===========================================================================
 
loc_2398A:
    move.w  #$CB,d1
    move.w  #$78,d2
    move.w  #$79,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject_Always).l, JmpTo_SolidObject_Always
    jsrto   (DropOnFloor).l, JmpTo_DropOnFloor
; loc_239A2:
Obj30_HurtSupportedPlayers:
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    move.l  a0,-(sp)
    movea.l a0,a1
    lea (MainCharacter).w,a0 ; a0=character
    jsrto   (Touch_ChkHurt).l, JmpTo_Touch_ChkHurt
    movea.l (sp)+,a0 ; load 0bj address
+
    btst    #p2_standing_bit,status(a0)
    beq.s   +
    move.l  a0,-(sp)
    movea.l a0,a1
    lea (Sidekick).w,a0 ; a0=character
    jsrto   (Touch_ChkHurt).l, JmpTo_Touch_ChkHurt
    movea.l (sp)+,a0 ; load 0bj address
+
    rts
; ===========================================================================
 
loc_239D0:
    move.w  #$EB,d1
    move.w  #$78,d2
    move.w  #$79,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject_Always).l, JmpTo_SolidObject_Always
    jsrto   (DropOnFloor).l, JmpTo_DropOnFloor
    bra.s   Obj30_HurtSupportedPlayers
; ===========================================================================
 
loc_239EA:
    move.w  #$CB,d1
    move.w  #$2E,d2
    move.w  x_pos(a0),d4
    lea (Obj30_SlopeData).l,a2
    jsrto   (SlopedSolid).l, JmpTo_SlopedSolid
    jmpto   (DropOnFloor).l, JmpTo_DropOnFloor
; ===========================================================================
;byte_23A04:
Obj30_SlopeData:
    dc.b $30,$30,$30,$30,$30,$30,$30,$30,$2F,$2F,$2E,$2E,$2D,$2D,$2C,$2C
    dc.b $2B,$2B,$2A,$2A,$29,$29,$28,$28,$27,$27,$26,$26,$25,$25,$24,$24; 16
    dc.b $23,$23,$22,$22,$21,$21,$20,$20,$1F,$1F,$1E,$1E,$1D,$1D,$1C,$1C; 32
    dc.b $1B,$1B,$1A,$1A,$19,$19,$18,$18,$17,$17,$16,$16,$15,$15,$14,$14; 48
    dc.b $13,$13,$12,$12,$11,$11,$10,$10, $F, $F, $E, $E, $D, $D, $C, $C; 64
    dc.b  $B, $B, $A, $A,  9,  9,  8,  8,  7,  7,  6,  6,  5,  5,  4,  4; 80
    dc.b   3,  3,  2,  2,  1,  1,  0,  0,$FF,$FF,$FE,$FE,$FD,$FD,$FC,$FC; 96
    dc.b $FB,$FB,$FA,$FA,$F9,$F9,$F8,$F8,$F7,$F7,$F6,$F6,$F5,$F5,$F4,$F4; 112
    dc.b $F3,$F3,$F2,$F2,$F1,$F1,$F0,$F0,$EF,$EF,$EE,$EE,$ED,$ED,$EC,$EC; 128
    dc.b $EB,$EB,$EA,$EA,$E9,$E9,$E8,$E8,$E7,$E7,$E6,$E6,$E5,$E5,$E4,$E4; 144
    dc.b $E3,$E3,$E2,$E2,$E1,$E1,$E0,$E0,$DF,$DF,$DE,$DE,$DD,$DD,$DC,$DC; 160
    dc.b $DB,$DB,$DA,$DA,$D9,$D9,$D8,$D8,$D7,$D7,$D6,$D6,$D5,$D5,$D4,$D4; 176
    dc.b $D3,$D3,$D2,$D2,$D1,$D1,$D0,$D0,$D0,$D0,$D0,$D0; 192
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo23_DeleteObject 
    jmp (DeleteObject).l
JmpTo_Touch_ChkHurt 
    jmp (Touch_ChkHurt).l
JmpTo2_MarkObjGone3 
    jmp (MarkObjGone3).l
JmpTo_DropOnFloor 
    jmp (DropOnFloor).l
JmpTo_SolidObject_Always 
    jmp (SolidObject_Always).l
JmpTo_SlopedSolid 
    jmp (SlopedSolid).l
 
    align 4
    else
JmpTo2_MarkObjGone3 
    jmp (MarkObjGone3).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 33 - Green platform from OOZ
; ----------------------------------------------------------------------------
; Sprite_23AF4:
Obj33:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj33_Index(pc,d0.w),d1
    jmp Obj33_Index(pc,d1.w)
; ===========================================================================
; off_23B02:
Obj33_Index:    offsetTable
        offsetTableEntry.w Obj33_Init   ; 0
        offsetTableEntry.w Obj33_Main   ; 2
        offsetTableEntry.w Obj33_Flame  ; 4
; ===========================================================================
; loc_23B08:
Obj33_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj33_MapUnc_23DDC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BurnerLid,3,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #$18,width_pixels(a0)
    move.w  y_pos(a0),objoff_30(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #$78,objoff_36(a0)
    tst.b   subtype(a0)
    beq.s   +
    move.b  #4,routine_secondary(a0)
+
    jsrto   (SingleObjLoad2).l, JmpTo7_SingleObjLoad2
    bne.s   Obj33_Main
    _move.b id(a0),id(a1) ; load obj33
    move.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    subi.w  #$10,y_pos(a1)
    move.l  #Obj33_MapUnc_23DF0,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZBurn,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.l  a0,objoff_3C(a1)
; loc_23B90:
Obj33_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj33_Modes(pc,d0.w),d1
    jsr Obj33_Modes(pc,d1.w)
    move.w  (sp)+,d4
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #8,d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo4_SolidObject
    jmpto   (MarkObjGone).l, JmpTo10_MarkObjGone
; ===========================================================================
; off_23BBC:
Obj33_Modes:    offsetTable
        offsetTableEntry.w loc_23BC6    ; 0
        offsetTableEntry.w loc_23BEA    ; 2
        offsetTableEntry.w loc_23C26    ; 4
        offsetTableEntry.w loc_23D20    ; 6
        offsetTableEntry.w return_23D98 ; 8
; ===========================================================================
 
loc_23BC6:
    subq.w  #1,objoff_36(a0)
    bpl.s   +   ; rts
    move.w  #$78,objoff_36(a0)
    move.l  #-$96800,objoff_32(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #SndID_OOZLidPop,d0
    jsr (PlaySoundLocal).l
+
    rts
; ===========================================================================
 
loc_23BEA:
    move.l  y_pos(a0),d1
    add.l   objoff_32(a0),d1
    move.l  d1,y_pos(a0)
    addi.l  #$3800,objoff_32(a0)
    swap    d1
    cmp.w   objoff_30(a0),d1
    blo.s   ++  ; rts
    move.l  objoff_32(a0),d0
    cmpi.l  #$10000,d0
    bhs.s   +
    subq.b  #2,routine_secondary(a0)
+
    lsr.l   #2,d0
    neg.l   d0
    move.l  d0,objoff_32(a0)
    move.w  objoff_30(a0),y_pos(a0)
+
    rts
; ===========================================================================
 
loc_23C26:
    move.w  x_pos(a0),d2
    move.w  d2,d3
    subi.w  #$10,d2
    addi.w  #$10,d3
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   ++  ; rts
    cmpi.b  #standing_mask,d0
    beq.s   loc_23CA0
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    bsr.s   +
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
+
    btst    d6,status(a0)
    beq.s   +   ; rts
    move.w  x_pos(a1),d0
    cmp.w   d2,d0
    blo.s   +   ; rts
    cmp.w   d3,d0
    bhs.s   +   ; rts
 
    move.b  #1,obj_control(a1)
    move.w  #0,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    bclr    #5,status(a1)
    bclr    #high_priority_bit,art_tile(a1)
    move.l  #-$96800,objoff_32(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #SndID_OOZLidPop,d0
    jsr (PlaySoundLocal).l
+
    rts
; ===========================================================================
 
loc_23CA0:
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),d0
    cmp.w   d2,d0
    blo.s   +   ; rts
    cmp.w   d3,d0
    bhs.s   +   ; rts
    lea (Sidekick).w,a2 ; a2=character
    move.w  x_pos(a2),d0
    cmp.w   d2,d0
    blo.s   +   ; rts
    cmp.w   d3,d0
    bhs.s   +   ; rts
 
    move.b  #1,obj_control(a1)
    move.w  #0,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    bclr    #5,status(a1)
    bclr    #high_priority_bit,art_tile(a1)
    move.b  #1,obj_control(a2)
    move.w  #0,inertia(a2)
    move.w  #0,x_vel(a2)
    move.w  #0,y_vel(a2)
    bclr    #5,status(a2)
    bclr    #high_priority_bit,art_tile(a2)
    move.l  #-$96800,objoff_32(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #SndID_OOZLidPop,d0
    jsr (PlaySoundLocal).l
+
    rts
; ===========================================================================
 
loc_23D20:
    move.l  y_pos(a0),d1
    add.l   objoff_32(a0),d1
    move.l  d1,y_pos(a0)
    addi.l  #$3800,objoff_32(a0)
    swap    d1
    move.w  objoff_30(a0),d0
    subi.w  #$7D,d0
    cmp.w   d0,d1
    bne.s   +   ; rts
    addq.b  #2,routine_secondary(a0)
    lea (MainCharacter).w,a1 ; a1=character
    move.b  status(a0),d0
    andi.b  #p1_standing,d0
    bsr.s   loc_23D60
    lea (Sidekick).w,a1 ; a1=character
    move.b  status(a0),d0
    andi.b  #p2_standing,d0
 
loc_23D60:
    beq.s   +   ; rts
    move.w  x_pos(a0),x_pos(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  #$800,inertia(a1)
    bset    #1,status(a1)
    move.w  #-$1000,y_vel(a1)
    bclr    #3,status(a1)
    move.b  #0,obj_control(a1)
    move.w  #SndID_Spring,d0
    jsr (PlaySoundLocal).l
+
    rts
; ===========================================================================
 
return_23D98:
    rts
; ===========================================================================
; loc_23D9A:
Obj33_Flame:
    movea.l objoff_3C(a0),a1 ; a1=object
    move.w  y_pos(a0),d0
    sub.w   y_pos(a1),d0
    cmpi.w  #$14,d0
    blt.s   Obj33_FlameOff
    move.b  #$9B,collision_flags(a0)
    lea (Ani_obj33).l,a1
    jsr (AnimateSprite).l
    jmpto   (MarkObjGone).l, JmpTo10_MarkObjGone
; ===========================================================================
; loc_23DC2:
Obj33_FlameOff:
    move.b  #0,collision_flags(a0)
    move.b  #0,anim_frame(a0)
    rts
; ===========================================================================
; animation script
; off_23DD0:
Ani_obj33:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   2,  2,  0,  2,  0,  2,  0,  1,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj33_MapUnc_23DDC: BINCLUDE "mappings/sprite/obj33_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj33_MapUnc_23DF0: BINCLUDE "mappings/sprite/obj33_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo10_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo7_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo4_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 43 - Sliding spike obstacle thing from OOZ
; ----------------------------------------------------------------------------
; Sprite_23E40:
Obj43:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj43_Index(pc,d0.w),d1
    jmp Obj43_Index(pc,d1.w)
; ===========================================================================
; off_23E4E:
Obj43_Index:    offsetTable
        offsetTableEntry.w Obj43_Init   ; 0
        offsetTableEntry.w loc_23F0A    ; 2
        offsetTableEntry.w loc_23F5C    ; 4
; ---------------------------------------------------------------------------
byte_23E54:
    dc.b   0
    dc.b $68    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   0    ; 4
    dc.b   0    ; 5
    dc.b   1    ; 6
    dc.b $E8    ; 7
    dc.b $FF    ; 8
    dc.b $E8    ; 9
    dc.b   0    ; 10
    dc.b $18    ; 11
    dc.b   1    ; 12
    dc.b $A8    ; 13
    dc.b $FF    ; 14
    dc.b $A8    ; 15
    dc.b $FF    ; 16
    dc.b $D8    ; 17
; ===========================================================================
; loc_23E66:
Obj43_Init:
    addq.b  #2,routine(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpikyThing,2,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo19_Adjust2PArtPointer
    moveq   #0,d1
    move.b  subtype(a0),d1
    lea byte_23E54(pc,d1.w),a2
    move.b  (a2)+,d1
    movea.l a0,a1
    bra.s   loc_23EA8
; ===========================================================================
 
loc_23E84:
    jsrto   (SingleObjLoad2).l, JmpTo8_SingleObjLoad2
    bne.s   loc_23ED4
    _move.b id(a0),id(a1) ; load obj43
    move.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #1,objoff_36(a1)
 
loc_23EA8:
    move.l  #Obj43_MapUnc_23FE0,mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #$18,width_pixels(a1)
    move.b  #$A5,collision_flags(a1)
    move.w  x_pos(a1),objoff_30(a1)
 
loc_23ED4:
    dbf d1,loc_23E84
    move.l  a0,objoff_3C(a1)
    move.l  a1,objoff_3C(a0)
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  objoff_30(a0),d0
    sub.w   d1,d0
    move.w  d0,objoff_32(a0)
    move.w  d0,objoff_32(a1)
    add.w   d1,d0
    add.w   d1,d0
    move.w  d0,objoff_34(a0)
    move.w  d0,objoff_34(a1)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a0)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a1)
 
loc_23F0A:
    bsr.s   loc_23F66
    move.w  objoff_32(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bls.s   JmpTo13_DisplaySprite
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   loc_23F36
 
JmpTo13_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_23F36:
    movea.l objoff_3C(a0),a1 ; a1=object
    cmpa.l  a0,a1
    beq.s   loc_23F44
    jsr (DeleteObject2).l
 
loc_23F44:
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   JmpTo24_DeleteObject
    bclr    #7,2(a2,d0.w)
 
JmpTo24_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
loc_23F5C:
    bsr.s   loc_23F66
    bsr.s   loc_23FB0
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_23F66:
    tst.b   objoff_36(a0)
    bne.s   loc_23F8E
    move.w  x_pos(a0),d1
    subq.w  #1,d1
    cmp.w   objoff_32(a0),d1
    bne.s   loc_23F88
    move.b  #1,objoff_36(a0)
    move.w  #SndID_SlidingSpike,d0
    jsr (PlaySoundLocal).l
 
loc_23F88:
    move.w  d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_23F8E:
    move.w  x_pos(a0),d1
    addq.w  #1,d1
    cmp.w   objoff_34(a0),d1
    bne.s   loc_23FAA
    move.b  #0,objoff_36(a0)
    move.w  #SndID_SlidingSpike,d0
    jsr (PlaySoundLocal).l
 
loc_23FAA:
    move.w  d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_23FB0:
    movea.l objoff_3C(a0),a1 ; a1=object
    move.w  x_pos(a0),d0
    subi.w  #$18,d0
    move.w  x_pos(a1),d2
    addi.w  #$18,d2
    cmp.w   d0,d2
    bne.s   return_23FDE
    eori.b  #1,objoff_36(a0)
    eori.b  #1,objoff_36(a1)
    move.w  #SndID_SlidingSpike,d0
    jsr (PlaySoundLocal).l
 
return_23FDE:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj43_MapUnc_23FE0: BINCLUDE "mappings/sprite/obj43.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo8_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo19_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 07 - Oil Ocean in OOZ
; ----------------------------------------------------------------------------
; OST:
oil_char1submersion = objoff_38 ; $38(a0)
oil_char2submersion = objoff_3A ; $3A(a0)
; ----------------------------------------------------------------------------
; Sprite_24020:
Obj07:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj07_Index(pc,d0.w),d1
    jmp Obj07_Index(pc,d1.w)
; ===========================================================================
; off_2402E: Obj07_States:
Obj07_Index:    offsetTable
        offsetTableEntry.w Obj07_Init   ; 0
        offsetTableEntry.w Obj07_Main   ; 2
; ===========================================================================
; loc_24032:
Obj07_Init:
    addq.b  #2,routine(a0) ; => Obj07_Main
    move.w  #$758,y_pos(a0)
    move.b  #$20,width_pixels(a0)
    move.w  y_pos(a0),objoff_30(a0)
    move.b  #$30,oil_char1submersion(a0)
    bset    #7,status(a0)
 
; loc_24054:
Obj07_Main:
    ; check player 1
    tst.w   (Debug_placement_mode).w
    bne.w   Obj07_End
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing,d1
    move.b  status(a0),d0
    and.b   d1,d0
    bne.s   Obj07_CheckKillChar1
    cmpi.b  #$30,oil_char1submersion(a0)
    beq.s   Obj07_CheckSupportChar1
    addq.b  #1,oil_char1submersion(a0)
    bra.s   Obj07_CheckSupportChar1
; ---------------------------------------------------------------------------
; loc_24078:
Obj07_CheckKillChar1:
    tst.b   oil_char1submersion(a0)
    beq.s   Obj07_SuffocateCharacter
    subq.b  #1,oil_char1submersion(a0)
 
; loc_24082:
Obj07_CheckSupportChar1:
    moveq   #$20,d1
    moveq   #0,d3
    move.b  oil_char1submersion(a0),d3
    moveq   #p1_standing_bit,d6
    move.w  x_pos(a1),d4
    move.w  d4,x_pos(a0)
    jsrto   (PlatformObject_SingleCharacter).l, JmpTo_PlatformObject_SingleCharacter ; stop the character from falling past the oil
 
    ; check player 2
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing,d1
    move.b  status(a0),d0
    and.b   d1,d0
    bne.s   Obj07_CheckKillChar2
    cmpi.b  #$30,oil_char2submersion(a0)
    beq.s   Obj07_CheckSupportChar2
    addq.b  #1,oil_char2submersion(a0)
    bra.s   Obj07_CheckSupportChar2
; ---------------------------------------------------------------------------
; loc_240B4:
Obj07_CheckKillChar2:
    tst.b   oil_char2submersion(a0)
    beq.s   Obj07_SuffocateCharacter
    subq.b  #1,oil_char2submersion(a0)
 
; loc_240BE:
Obj07_CheckSupportChar2:
    moveq   #$20,d1
    moveq   #0,d3
    move.b  oil_char2submersion(a0),d3
    moveq   #p2_standing_bit,d6
    move.w  x_pos(a1),d4
    move.w  d4,x_pos(a0)
    jsrto   (PlatformObject_SingleCharacter).l, JmpTo_PlatformObject_SingleCharacter ; stop the character from falling past the oil
 
    rts
; ---------------------------------------------------------------------------
; loc_240D6:
Obj07_SuffocateCharacter:
    not.b   d1
    and.b   d1,status(a0)
    move.l  a0,-(sp)
    movea.l a0,a2
    movea.l a1,a0
    jsrto   (KillCharacter).l, JmpTo3_KillCharacter
    movea.l (sp)+,a0 ; load 0bj address
 
Obj07_End:
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo3_KillCharacter 
    jmp (KillCharacter).l
JmpTo_PlatformObject_SingleCharacter 
    jmp (PlatformObject_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 45 - Pressure spring from OOZ
; ----------------------------------------------------------------------------
; Sprite_240F8:
Obj45:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj45_Index(pc,d0.w),d1
    jsr Obj45_Index(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo11_MarkObjGone
; ===========================================================================
; off_2410A:
Obj45_Index:    offsetTable
        offsetTableEntry.w Obj45_Init   ; 0
        offsetTableEntry.w loc_24186    ; 2
        offsetTableEntry.w loc_2427A    ; 4
; ===========================================================================
; loc_24110:
Obj45_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj45_MapUnc_2451A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_PushSpring,2,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$E,d0
    move.w  Obj45_InitRoutines(pc,d0.w),d0
    jmp Obj45_InitRoutines(pc,d0.w)
; ===========================================================================
; off_24146:
Obj45_InitRoutines: offsetTable
    offsetTableEntry.w loc_2416E    ; 0
    offsetTableEntry.w loc_2414A    ; 2
; ===========================================================================
 
loc_2414A:
    move.b  #4,routine(a0)
    move.b  #1,anim(a0)
    move.b  #$A,mapping_frame(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_PushSpring,2,0),art_tile(a0)
    move.b  #$14,width_pixels(a0)
    move.w  x_pos(a0),objoff_34(a0)
 
loc_2416E:
    move.b  subtype(a0),d0
    andi.w  #2,d0
    move.w  word_24182(pc,d0.w),objoff_30(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo20_Adjust2PArtPointer
    rts
; ===========================================================================
word_24182:
    dc.w $F000
    dc.w $F600  ; 1
; ===========================================================================
 
loc_24186:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   loc_2419C
    tst.b   objoff_32(a0)
    beq.s   loc_241A8
    subq.b  #1,objoff_32(a0)
    bra.s   loc_241A8
; ===========================================================================
 
loc_2419C:
    cmpi.b  #9,objoff_32(a0)
    beq.s   loc_241C6
    addq.b  #1,objoff_32(a0)
 
loc_241A8:
    moveq   #0,d3
    move.b  objoff_32(a0),d3
    move.b  d3,mapping_frame(a0)
    add.w   d3,d3
    move.w  #$1B,d1
    move.w  #$14,d2
    move.w  x_pos(a0),d4
    jsrto   (SolidObject45).l, JmpTo_SolidObject45
    rts
; ===========================================================================
 
loc_241C6:
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    bsr.s   loc_241D4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
 
loc_241D4:
    bclr    d6,status(a0)
    beq.w   return_24278
    move.w  objoff_30(a0),y_vel(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  subtype(a0),d0
    bpl.s   loc_24206
    move.w  #0,x_vel(a1)
 
loc_24206:
    btst    #0,d0
    beq.s   loc_24246
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_24236
    move.b  #1,flips_remaining(a1)
 
loc_24236:
    btst    #0,status(a1)
    beq.s   loc_24246
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_24246:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_2425C
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_2425C:
    cmpi.b  #8,d0
    bne.s   loc_2426E
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_2426E:
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
 
return_24278:
    rts
; ===========================================================================
 
loc_2427A:
    move.b  #0,objoff_36(a0)
    move.w  #$1F,d1
    move.w  #$C,d2
    move.w  #$D,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo_SolidObject_Always_SingleCharacter
    cmpi.w  #1,d4
    bne.s   loc_242C0
    move.b  status(a0),d1
    move.w  x_pos(a0),d2
    sub.w   x_pos(a1),d2
    bcs.s   loc_242B6
    eori.b  #1,d1
 
loc_242B6:
    andi.b  #1,d1
    bne.s   loc_242C0
    bsr.w   loc_2433C
 
loc_242C0:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo_SolidObject_Always_SingleCharacter
    cmpi.w  #1,d4
    bne.s   loc_242EE
    move.b  status(a0),d1
    move.w  x_pos(a0),d2
    sub.w   x_pos(a1),d2
    bcs.s   loc_242E6
    eori.b  #1,d1
 
loc_242E6:
    andi.b  #1,d1
    bne.s   loc_242EE
    bsr.s   loc_2433C
 
loc_242EE:
    tst.b   objoff_36(a0)
    bne.s   return_2433A
    move.w  objoff_34(a0),d0
    cmp.w   x_pos(a0),d0
    beq.s   return_2433A
    bhs.s   loc_2431C
    subq.b  #4,mapping_frame(a0)
    subq.w  #4,x_pos(a0)
    cmp.w   x_pos(a0),d0
    blo.s   loc_24336
    move.b  #$A,mapping_frame(a0)
    move.w  objoff_34(a0),x_pos(a0)
    bra.s   loc_24336
; ===========================================================================
 
loc_2431C:
    subq.b  #4,mapping_frame(a0)
    addq.w  #4,x_pos(a0)
    cmp.w   x_pos(a0),d0
    bhs.s   loc_24336
    move.b  #$A,mapping_frame(a0)
    move.w  objoff_34(a0),x_pos(a0)
 
loc_24336:
    bsr.w   loc_243D0
 
return_2433A:
    rts
; ===========================================================================
 
loc_2433C:
    btst    #0,status(a0)
    beq.s   loc_24378
    btst    #0,status(a1)
    bne.w   return_243CE
    tst.w   d0
    bne.w   loc_2435E
    tst.w   inertia(a1)
    beq.s   return_243CE
    bpl.s   loc_243C8
    bra.s   return_243CE
; ===========================================================================
 
loc_2435E:
    move.w  objoff_34(a0),d0
    addi.w  #$12,d0
    cmp.w   x_pos(a0),d0
    beq.s   loc_243C8
    addq.w  #1,x_pos(a0)
    moveq   #1,d0
    move.w  #$40,d1
    bra.s   loc_243A6
; ===========================================================================
 
loc_24378:
    btst    #0,status(a1)
    beq.s   return_243CE
    tst.w   d0
    bne.w   loc_2438E
    tst.w   inertia(a1)
    bmi.s   loc_243C8
    bra.s   return_243CE
; ===========================================================================
 
loc_2438E:
    move.w  objoff_34(a0),d0
    subi.w  #$12,d0
    cmp.w   x_pos(a0),d0
    beq.s   loc_243C8
    subq.w  #1,x_pos(a0)
    moveq   #-1,d0
    move.w  #-$40,d1
 
loc_243A6:
    add.w   d0,x_pos(a1)
    move.w  d1,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  objoff_34(a0),d0
    sub.w   x_pos(a0),d0
    bcc.s   loc_243C0
    neg.w   d0
 
loc_243C0:
    addi.w  #$A,d0
    move.b  d0,mapping_frame(a0)
 
loc_243C8:
    move.b  #1,objoff_36(a0)
 
return_243CE:
    rts
; ===========================================================================
 
loc_243D0:
    move.b  status(a0),d0
    andi.b  #pushing_mask,d0
    beq.w   return_244D0
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_pushing_bit,d6
    bsr.s   loc_243EA
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_pushing_bit,d6
 
loc_243EA:
    bclr    d6,status(a0)
    beq.w   return_244D0
    move.w  objoff_34(a0),d0
    sub.w   x_pos(a0),d0
    bcc.s   loc_243FE
    neg.w   d0
 
loc_243FE:
    addi.w  #$A,d0
    lsl.w   #7,d0
    neg.w   d0
    move.w  d0,x_vel(a1)
    subq.w  #4,x_pos(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_2442C
    bclr    #0,status(a1)
    addi_.w #8,x_pos(a1)
    neg.w   x_vel(a1)
 
loc_2442C:
    move.w  #$F,move_lock(a1)
    move.w  x_vel(a1),inertia(a1)
    btst    #2,status(a1)
    bne.s   loc_24446
    move.b  #AniIDSonAni_Walk,anim(a1)
 
loc_24446:
    move.b  subtype(a0),d0
    bpl.s   loc_24452
    move.w  #0,y_vel(a1)
 
loc_24452:
    btst    #0,d0
    beq.s   loc_24492
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_24482
    move.b  #3,flips_remaining(a1)
 
loc_24482:
    btst    #0,status(a1)
    beq.s   loc_24492
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_24492:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_244A8
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_244A8:
    cmpi.b  #8,d0
    bne.s   loc_244BA
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_244BA:
    bclr    #5,status(a1)
    move.b  #AniIDSonAni_Run,next_anim(a1)
    move.w  #SndID_Spring,d0 ; play spring bounce sound
    jmp (PlaySound).l
; ===========================================================================
 
return_244D0:
    rts
; ===========================================================================
; off_244D2:
; Unused animation script
Ani_obj45:  offsetTable
        offsetTableEntry.w byte_244D6   ; 0
        offsetTableEntry.w byte_244F8   ; 1
byte_244D6:
    dc.b   0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9,  9,  9,  9,  9
    dc.b   9,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,  0,  0,  0,  0,  0; 16
    dc.b   0,$FF    ; 32
byte_244F8:
    dc.b   0, $A, $B, $C, $D, $E, $F,$10,$11,$12,$13,$13,$13,$13,$13,$13
    dc.b $13,$13,$12,$11,$10, $F, $E, $D, $C, $B, $A, $A, $A, $A, $A, $A; 16
    dc.b  $A,$FF    ; 32
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj45_MapUnc_2451A: BINCLUDE "mappings/sprite/obj45.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 46 - Ball from OOZ (unused, beta leftover)
; ----------------------------------------------------------------------------
; Sprite_24A16:
Obj46:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj46_Index(pc,d0.w),d1
    jmp Obj46_Index(pc,d1.w)
; ===========================================================================
; off_24A24:
Obj46_Index:    offsetTable
        offsetTableEntry.w Obj46_Init       ; 0 - Init
        offsetTableEntry.w Obj46_Inactive   ; 2 - Ball inactive
        offsetTableEntry.w Obj46_Moving     ; 4 - Ball moving
        offsetTableEntry.w Obj46_PressureSpring ; 6 - Pressure Spring
; ===========================================================================
; loc_24A2C:
Obj46_Init:
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
    bset    #0,2(a2,d0.w)
    bne.w   JmpTo25_DeleteObject
+
    ; loads the ball itself
    addq.b  #2,routine(a0)
    move.b  #$F,y_radius(a0)
    move.b  #$F,x_radius(a0)
    move.l  #Obj46_MapUnc_24C52,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BallThing,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo20_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_36(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #0,objoff_14(a0)
    move.b  #1,objoff_1F(a0)
 
; Obj46_InitPressureSpring: ; loads the spring under the ball
    jsrto   (SingleObjLoad).l, JmpTo4_SingleObjLoad
    bne.s   +
    _move.b #ObjID_OOZBall,id(a1) ; load obj46
    addq.b  #6,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$12,y_pos(a1)
    move.l  #Obj45_MapUnc_2451A,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_PushSpring,2,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #4,priority(a1)
    move.b  #9,mapping_frame(a1)
    move.l  a0,objoff_3C(a1)
+
    move.l  a1,objoff_3C(a0)
; loc_24AEA:
Obj46_Inactive:
    btst    #button_A,(Ctrl_2_Press).w
    bne.s   +
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #4,d0
    tst.b   (a2,d0.w)
    beq.s   ++
+
    addq.b  #2,routine(a0)
    bset    #1,status(a0)
    move.w  #-$300,y_vel(a0)
    move.w  #$100,objoff_14(a0)
    movea.l objoff_3C(a0),a1 ; a1=object
    move.b  #1,objoff_30(a1)
    btst    #0,status(a0)
    beq.s   +
    neg.w   objoff_14(a0)
+
    bsr.w   loc_24BF0
    jmpto   (MarkObjGone).l, JmpTo11_MarkObjGone
; ===========================================================================
; loc_24B38:
Obj46_Moving:
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo9_ObjectMove
    btst    #1,status(a0)
    beq.s   loc_24B8C
    addi.w  #$18,y_vel(a0)
    bmi.s   +
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    blo.s   loc_24BC4
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.w   +
    add.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    bclr    #1,status(a0)
    move.w  #$100,x_vel(a0)
    btst    #0,status(a0)
    beq.s   +
    neg.w   x_vel(a0)
+
    bra.s   loc_24BA4
; ===========================================================================
 
loc_24B8C:
    jsr (ObjCheckFloorDist).l
    cmpi.w  #8,d1
    blt.s   loc_24BA0
    bset    #1,status(a0)
    bra.s   loc_24BA4
; ===========================================================================
 
loc_24BA0:
    add.w   d1,y_pos(a0)
 
loc_24BA4:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo5_SolidObject
    bsr.w   loc_24BF0
    jmpto   (MarkObjGone).l, JmpTo11_MarkObjGone
; ===========================================================================
 
loc_24BC4:
    move.w  (sp)+,d4
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   BranchTo_JmpTo25_DeleteObject
    bclr    #7,2(a2,d0.w)
 
    if removeJmpTos
JmpTo25_DeleteObject 
    endif
 
BranchTo_JmpTo25_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo25_DeleteObject
; ===========================================================================
; loc_24BDC:
Obj46_PressureSpring:
    tst.b   objoff_30(a0)
    beq.s   +
    subq.b  #1,mapping_frame(a0)
    bne.s   +
    clr.b   objoff_30(a0)
+
    jmpto   (MarkObjGone).l, JmpTo11_MarkObjGone
; ===========================================================================
 
loc_24BF0:
    tst.b   mapping_frame(a0)
    beq.s   +
    move.b  #0,mapping_frame(a0)
    rts
; ===========================================================================
+
    move.b  objoff_14(a0),d0
    beq.s   loc_24C2A
    bmi.s   loc_24C32
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_24C2A
    neg.b   d0
    addq.b  #8,d0
    bcs.s   +
    moveq   #0,d0
+
    move.b  d0,anim_frame_duration(a0)
    move.b  objoff_1F(a0),d0
    addq.b  #1,d0
    cmpi.b  #4,d0
    bne.s   +
    moveq   #1,d0
+
    move.b  d0,objoff_1F(a0)
 
loc_24C2A:
    move.b  objoff_1F(a0),mapping_frame(a0)
    rts
; ===========================================================================
 
loc_24C32:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_24C2A
    addq.b  #8,d0
    bcs.s   +
    moveq   #0,d0
+
    move.b  d0,anim_frame_duration(a0)
    move.b  objoff_1F(a0),d0
    subq.b  #1,d0
    bne.s   +
    moveq   #3,d0
+
    move.b  d0,objoff_1F(a0)
    bra.s   loc_24C2A
; ===========================================================================
; ----------------------------------------------------------------------------
; Unused sprite mappings
; ----------------------------------------------------------------------------
Obj46_MapUnc_24C52: BINCLUDE "mappings/sprite/obj46.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo25_DeleteObject 
    jmp (DeleteObject).l
JmpTo4_SingleObjLoad 
    jmp (SingleObjLoad).l
; some of these are still used, for some reason:
JmpTo11_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo20_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo5_SolidObject 
    jmp (SolidObject).l
JmpTo_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
JmpTo_SolidObject45 
    jmp (SolidObject45).l
; loc_24CEE:
JmpTo9_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 47 - Button
; ----------------------------------------------------------------------------
; Sprite_24CF4:
Obj47:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj47_Index(pc,d0.w),d1
    jmp Obj47_Index(pc,d1.w)
; ===========================================================================
; off_24D02:
Obj47_Index:    offsetTable
        offsetTableEntry.w Obj47_Init   ; 0
        offsetTableEntry.w Obj47_Main   ; 2
; ===========================================================================
; loc_24D06:
Obj47_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj47_MapUnc_24D96,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Button,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo21_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    addq.w  #4,y_pos(a0)
; loc_24D32:
Obj47_Main:
    tst.b   render_flags(a0)
    bpl.s   BranchTo_JmpTo12_MarkObjGone
    move.w  #$1B,d1
    move.w  #4,d2
    move.w  #5,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo6_SolidObject
    move.b  #0,mapping_frame(a0)
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lea (ButtonVine_Trigger).w,a3
    lea (a3,d0.w),a3
    moveq   #0,d3
    btst    #6,subtype(a0)
    beq.s   +
    moveq   #7,d3
+
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    bclr    d3,(a3)
    bra.s   BranchTo_JmpTo12_MarkObjGone
; ===========================================================================
+
    tst.b   (a3)
    bne.s   +
    move.w  #SndID_Blip,d0
    jsr (PlaySound).l
+
    bset    d3,(a3)
    move.b  #1,mapping_frame(a0)
 
BranchTo_JmpTo12_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo12_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj47_MapUnc_24D96: BINCLUDE "mappings/sprite/obj47.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo12_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo21_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo6_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3D - Block thingy in OOZ that launches you into the round ball things
; ----------------------------------------------------------------------------
; Sprite_24DD0:
Obj3D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3D_Index(pc,d0.w),d1
    jmp Obj3D_Index(pc,d1.w)
; ===========================================================================
; off_24DDE:
Obj3D_Index:    offsetTable
        offsetTableEntry.w Obj3D_Init           ; 0
        offsetTableEntry.w Obj3D_Main           ; 2
        offsetTableEntry.w Obj3D_Fragment       ; 4
        offsetTableEntry.w Obj3D_InvisibleLauncher  ; 6
; ===========================================================================
; loc_24DE6:
Obj3D_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj3D_MapUnc_250BA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_StripedBlocksVert,3,0),art_tile(a0)
    tst.b   subtype(a0)
    beq.s   +
    move.w  #make_art_tile(ArtTile_ArtNem_StripedBlocksHoriz,3,0),art_tile(a0)
    move.b  #2,mapping_frame(a0)
+
    jsrto   (Adjust2PArtPointer).l, JmpTo22_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    bset    #7,status(a0)
    move.b  #4,priority(a0)
; loc_24E26:
Obj3D_Main:
    move.b  (MainCharacter+anim).w,objoff_32(a0)
    move.b  (Sidekick+anim).w,objoff_33(a0)
    move.w  (MainCharacter+y_vel).w,objoff_34(a0)
    move.w  (Sidekick+y_vel).w,objoff_36(a0)
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo7_SolidObject
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   loc_24E60
 
BranchTo_JmpTo13_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo13_MarkObjGone
; ===========================================================================
 
loc_24E60:
    cmpi.b  #standing_mask,d0
    bne.s   loc_24E96
    cmpi.b  #AniIDSonAni_Roll,objoff_32(a0)
    beq.s   loc_24E76
    cmpi.b  #AniIDSonAni_Roll,objoff_33(a0)
    bne.s   BranchTo_JmpTo13_MarkObjGone
 
loc_24E76:
    lea (MainCharacter).w,a1 ; a1=character
    move.b  objoff_32(a0),d0
    move.w  objoff_34(a0),d1
    bsr.s   loc_24EB2
    lea (Sidekick).w,a1 ; a1=character
    move.b  objoff_33(a0),d0
    move.w  objoff_36(a0),d1
    bsr.s   loc_24EB2
    bra.w   loc_24F04
; ===========================================================================
 
loc_24E96:
    move.b  d0,d1
    andi.b  #p1_standing,d1
    beq.s   loc_24EE8
    cmpi.b  #AniIDSonAni_Roll,objoff_32(a0)
    bne.s   BranchTo_JmpTo13_MarkObjGone
    lea (MainCharacter).w,a1 ; a1=character
    move.w  objoff_34(a0),d1
    bsr.s   loc_24EB8
    bra.s   loc_24F04
; ===========================================================================
 
loc_24EB2:
    cmpi.b  #AniIDSonAni_Roll,d0
    bne.s   loc_24ED4
 
loc_24EB8:
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  d1,y_vel(a1)
 
loc_24ED4:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    rts
; ===========================================================================
 
loc_24EE8:
    andi.b  #p2_standing,d0
    beq.w   BranchTo_JmpTo13_MarkObjGone
    cmpi.b  #AniIDSonAni_Roll,objoff_33(a0)
    bne.w   BranchTo_JmpTo13_MarkObjGone
    lea (Sidekick).w,a1 ; a1=character
    move.w  objoff_36(a0),d1
    bsr.s   loc_24EB8
 
loc_24F04:
    andi.b  #~standing_mask,status(a0)
    jsrto   (SingleObjLoad2).l, JmpTo9_SingleObjLoad2
    bne.s   loc_24F28
    moveq   #0,d0
    move.w  #$A,d1
 
loc_24F16:
    move.l  (a0,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,loc_24F16
    move.b  #6,routine(a1)
 
loc_24F28:
    lea (word_2507A).l,a4
    addq.b  #1,mapping_frame(a0)
    moveq   #$F,d1
    move.w  #$18,d2
    jsrto   (BreakObjectToPieces).l, JmpTo2_BreakObjectToPieces
; loc_24F3C:
Obj3D_Fragment:
    jsrto   (ObjectMove).l, JmpTo10_ObjectMove
    addi.w  #$18,y_vel(a0)
    tst.b   render_flags(a0)
    bpl.w   JmpTo26_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo14_DisplaySprite
; ===========================================================================
; loc_24F52:
Obj3D_InvisibleLauncher:
    lea (MainCharacter).w,a1 ; a1=character
    lea objoff_2C(a0),a4
    bsr.s   loc_24F74
    lea (Sidekick).w,a1 ; a1=character
    lea objoff_36(a0),a4
    bsr.s   loc_24F74
    move.b  objoff_2C(a0),d0
    add.b   objoff_36(a0),d0
    beq.w   JmpTo3_MarkObjGone3
    rts
; ===========================================================================
 
loc_24F74:
    moveq   #0,d0
    move.b  (a4),d0
    move.w  off_24F80(pc,d0.w),d0
    jmp off_24F80(pc,d0.w)
; ===========================================================================
off_24F80:  offsetTable
        offsetTableEntry.w loc_24F84    ; 0
        offsetTableEntry.w loc_25036    ; 2
; ===========================================================================
 
loc_24F84:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$10,d0
    cmpi.w  #$20,d0
    bhs.w   return_25034
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    tst.b   subtype(a0)
    beq.s   loc_24FAA
    addi.w  #$10,d1
 
loc_24FAA:
    cmpi.w  #$10,d1
    bhs.w   return_25034
    cmpa.w  #Sidekick,a1
    bne.s   loc_24FC2
    cmpi.w  #4,(Tails_CPU_routine).w ; TailsCPU_Flying
    beq.w   return_25034
 
loc_24FC2:
    addq.b  #2,(a4)
    move.b  #$81,obj_control(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  #$800,inertia(a1)
    tst.b   subtype(a0)
    beq.s   loc_24FF0
    move.w  x_pos(a0),x_pos(a1)
    move.w  #0,x_vel(a1)
    move.w  #-$800,y_vel(a1)
    bra.s   loc_25002
; ===========================================================================
 
loc_24FF0:
    move.w  y_pos(a0),y_pos(a1)
    move.w  #$800,x_vel(a1)
    move.w  #0,y_vel(a1)
 
loc_25002:
    bclr    #5,status(a0)
    bclr    #5,status(a1)
    bset    #1,status(a1)
    bset    #3,status(a1)
    move.w  a0,d0
    subi.w  #Object_RAM,d0
    if object_size=$40
    lsr.w   #6,d0
    else
    divu.w  #object_size,d0
    endif
    andi.w  #$7F,d0
    move.b  d0,interact(a1)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
 
return_25034:
    rts
; ===========================================================================
 
loc_25036:
    tst.b   render_flags(a1)
    bmi.s   Obj3D_MoveCharacter
    move.b  #0,obj_control(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #0,(a4)
    rts
; ===========================================================================
; update the position of Sonic/Tails from the block thing to the launcher
; loc_25054:
Obj3D_MoveCharacter:
    move.l  x_pos(a1),d2
    move.l  y_pos(a1),d3
    move.w  x_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,x_pos(a1)
    move.l  d3,y_pos(a1)
    rts
; ===========================================================================
word_2507A:
    dc.w -$400,-$400 ; 0
    dc.w -$200,-$400 ; 2
    dc.w  $200,-$400 ; 4
    dc.w  $400,-$400 ; 6
    dc.w -$3C0,-$200 ; 8
    dc.w -$1C0,-$200 ; 10
    dc.w  $1C0,-$200 ; 12
    dc.w  $3C0,-$200 ; 14
    dc.w -$380, $200 ; 16
    dc.w -$180, $200 ; 18
    dc.w  $180, $200 ; 20
    dc.w  $380, $200 ; 22
    dc.w -$340, $400 ; 24
    dc.w -$140, $400 ; 26
    dc.w  $140, $400 ; 28
    dc.w  $340, $400 ; 30
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj3D_MapUnc_250BA: BINCLUDE "mappings/sprite/obj3D.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo14_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo26_DeleteObject 
    jmp (DeleteObject).l
JmpTo13_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo9_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo3_MarkObjGone3 
    jmp (MarkObjGone3).l
JmpTo22_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo2_BreakObjectToPieces 
    jmp (BreakObjectToPieces).l
JmpTo7_SolidObject 
    jmp (SolidObject).l
; loc_2523C:
JmpTo10_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo3_MarkObjGone3 
    jmp (MarkObjGone3).l
JmpTo26_DeleteObject 
    jmp (DeleteObject).l
; Unused
;JmpTo13_MarkObjGone 
    jmp (MarkObjGone).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 48 - Round ball thing from OOZ that fires you off in a different direction (sphere)
; ----------------------------------------------------------------------------
; Sprite_25244:
Obj48:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj48_Index(pc,d0.w),d1
    jsr Obj48_Index(pc,d1.w)
    move.b  objoff_2C(a0),d0
    add.b   objoff_36(a0),d0
    beq.w   JmpTo14_MarkObjGone
    jmpto   (DisplaySprite).l, JmpTo15_DisplaySprite
 
    if removeJmpTos
JmpTo14_MarkObjGone 
    jmp (MarkObjGone).l
    endif
; ===========================================================================
; off_25262:
Obj48_Index:    offsetTable
        offsetTableEntry.w Obj48_Init   ; 0
        offsetTableEntry.w Obj48_Main   ; 2
; ===========================================================================
; byte_25266:
Obj48_Properties:
    ;      render_flags
    ;      objoff_3F
    dc.b   4,  0    ; 0
    dc.b   6,  7    ; 2
    dc.b   7,  0    ; 4
    dc.b   5,  7    ; 6
    dc.b   5,  0    ; 8
    dc.b   4,  7    ; 10
    dc.b   6,  0    ; 12
    dc.b   7,  7    ; 14
; ===========================================================================
; loc_25276:
Obj48_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj48_MapUnc_254FE,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_LaunchBall,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo23_Adjust2PArtPointer
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    btst    #0,status(a0)
    beq.s   +
    addq.w  #4,d0
+
    add.w   d0,d0
    move.b  Obj48_Properties(pc,d0.w),render_flags(a0)
    move.b  Obj48_Properties+1(pc,d0.w),objoff_3F(a0)
    beq.s   +
    move.b  #1,objoff_3E(a0)
+
    move.b  objoff_3F(a0),mapping_frame(a0)
    move.b  #$28,width_pixels(a0)
    move.b  #1,priority(a0)
; loc_252C6:
Obj48_Main:
    lea (MainCharacter).w,a1 ; a1=character
    lea objoff_2C(a0),a4
    moveq   #objoff_2C,d2
    bsr.s   loc_252DC
    lea (Sidekick).w,a1 ; a1=character
    lea objoff_36(a0),a4
    moveq   #objoff_36,d2
 
loc_252DC:
    moveq   #0,d0
    move.b  (a4),d0
    move.w  Obj48_Modes(pc,d0.w),d0
    jmp Obj48_Modes(pc,d0.w)
; ===========================================================================
; off_252E8:
Obj48_Modes:    offsetTable
        offsetTableEntry.w loc_252F0    ; 0
        offsetTableEntry.w loc_253C6    ; 2
        offsetTableEntry.w loc_25474    ; 4
        offsetTableEntry.w loc_254F2    ; 6
; ===========================================================================
 
loc_252F0:
    tst.w   (Debug_placement_mode).w
    bne.w   return_253C4
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$10,d0
    cmpi.w  #$20,d0
    bhs.w   return_253C4
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    addi.w  #$10,d1
    cmpi.w  #$20,d1
    bhs.w   return_253C4
    cmpa.w  #Sidekick,a1
    bne.s   +
    cmpi.w  #4,(Tails_CPU_routine).w    ; TailsCPU_Flying
    beq.w   return_253C4
+
    cmpi.b  #6,routine(a1)
    bhs.w   return_253C4
    tst.w   (Debug_placement_mode).w
    bne.w   return_253C4
    btst    #3,status(a1)
    beq.s   +
    moveq   #0,d0
    move.b  interact(a1),d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a3   ; a3=object
    move.b  #0,(a3,d2.w)
+
    move.w  a0,d0
    subi.w  #Object_RAM,d0
    if object_size=$40
    lsr.w   #6,d0
    else
    divu.w  #object_size,d0
    endif
    andi.w  #$7F,d0
    move.b  d0,interact(a1)
    addq.b  #2,(a4)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #$81,obj_control(a1)
    move.b  #2,anim(a1)
    move.w  #$1000,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    bclr    #5,status(a0)
    bclr    #5,status(a1)
    bset    #1,status(a1)
    bset    #3,status(a1)
    move.b  objoff_3F(a0),mapping_frame(a0)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
 
return_253C4:
    rts
; ===========================================================================
 
loc_253C6:
    tst.b   objoff_3E(a0)
    bne.s   loc_253EE
    cmpi.b  #7,mapping_frame(a0)
    beq.s   loc_25408
    subq.w  #1,anim_frame_duration(a0)
    bpl.s   return_253EC
    move.w  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #7,mapping_frame(a0)
    beq.s   loc_25408
 
return_253EC:
    rts
; ===========================================================================
 
loc_253EE:
    tst.b   mapping_frame(a0)
    beq.s   loc_25408
    subq.w  #1,anim_frame_duration(a0)
    bpl.s   return_253EC
    move.w  #7,anim_frame_duration(a0)
    subq.b  #1,mapping_frame(a0)
    beq.s   loc_25408
    rts
; ===========================================================================
 
loc_25408:
    addq.b  #2,(a4)
    move.b  subtype(a0),d0
    addq.b  #1,d0
    btst    #0,status(a0)
    beq.s   +
    subq.b  #2,d0
+
    andi.w  #3,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  word_25464(pc,d0.w),x_vel(a1)
    move.w  word_25464+2(pc,d0.w),y_vel(a1)
    move.w  #3,anim_frame_duration(a0)
    tst.b   subtype(a0)
    bpl.s   return_25462
    move.b  #0,obj_control(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #0,jumping(a1)
    move.b  #2,routine(a1)
    move.b  #6,(a4)
    move.w  #7,objoff_3C(a0)
 
return_25462:
    rts
; ===========================================================================
word_25464:
    dc.w      0,-$1000
    dc.w  $1000,     0  ; 2
    dc.w      0, $1000  ; 4
    dc.w -$1000,     0  ; 6
; ===========================================================================
 
loc_25474:
    tst.b   render_flags(a1)
    bmi.s   loc_25492
    move.b  #0,obj_control(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #0,(a4)
    rts
; ===========================================================================
 
loc_25492:
    cmpi.b  #2,objoff_2C(a0)
    beq.s   Obj48_MoveCharacter
    cmpi.b  #2,objoff_36(a0)
    beq.s   Obj48_MoveCharacter
    subq.w  #1,anim_frame_duration(a0)
    bpl.s   Obj48_MoveCharacter
    move.w  #1,anim_frame_duration(a0)
    tst.b   objoff_3E(a0)
    beq.s   loc_254C2
    cmpi.b  #7,mapping_frame(a0)
    beq.s   Obj48_MoveCharacter
    addq.b  #1,mapping_frame(a0)
    bra.s   Obj48_MoveCharacter
; ===========================================================================
 
loc_254C2:
    tst.b   mapping_frame(a0)
    beq.s   Obj48_MoveCharacter
    subq.b  #1,mapping_frame(a0)
 
; update the position of Sonic/Tails between launchers
; loc_254CC:
Obj48_MoveCharacter:
    move.l  x_pos(a1),d2
    move.l  y_pos(a1),d3
    move.w  x_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,x_pos(a1)
    move.l  d3,y_pos(a1)
    rts
; ===========================================================================
 
loc_254F2:
    subq.w  #1,objoff_3C(a0)
    bpl.s   +   ; rts
    move.b  #0,(a4)
+
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj48_MapUnc_254FE: BINCLUDE "mappings/sprite/obj48.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo15_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo14_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo23_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 22 - Arrow shooter from ARZ
; ----------------------------------------------------------------------------
; Sprite_25694:
Obj22:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj22_Index(pc,d0.w),d1
    jmp Obj22_Index(pc,d1.w)
; ===========================================================================
; off_256A2:
Obj22_Index:    offsetTable
        offsetTableEntry.w Obj22_Init       ; 0
        offsetTableEntry.w Obj22_Main       ; 2
        offsetTableEntry.w Obj22_ShootArrow ; 4
        offsetTableEntry.w Obj22_Arrow_Init ; 6
        offsetTableEntry.w Obj22_Arrow      ; 8
; ===========================================================================
; loc_256AC:
Obj22_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj22_MapUnc_25804,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_ArrowAndShooter,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo24_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,mapping_frame(a0)
    andi.b  #$F,subtype(a0)
; loc_256E0:
Obj22_Main:
    cmpi.b  #2,anim(a0)
    beq.s   Obj22_Animate
    moveq   #0,d2
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj22_DetectPlayer
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   Obj22_DetectPlayer
    tst.b   d2
    bne.s   +
    tst.b   anim(a0)
    beq.s   +
    moveq   #2,d2
+
    move.b  d2,anim(a0)
; loc_25706:
Obj22_Animate:
    lea (Ani_obj22).l,a1
    jsrto   (AnimateSprite).l, JmpTo5_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo15_MarkObjGone
; ===========================================================================
; loc_25714:
Obj22_DetectPlayer:
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0    ; is the player on the left of the shooter?
    bcc.s   +       ; if yes, branch
    neg.w   d0
+
    cmpi.w  #$40,d0     ; is the player within $40 pixels of the shooter?
    bhs.s   +       ; if not, branch
    moveq   #1,d2       ; change the shooter's animation
+
    rts
; ===========================================================================
; loc_2572A:
Obj22_ShootArrow:
    jsrto   (SingleObjLoad).l, JmpTo5_SingleObjLoad
    bne.s   +
    _move.b id(a0),id(a1) ; load obj22
    addq.b  #6,routine(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  status(a0),status(a1)
    move.w  #SndID_PreArrowFiring,d0
    jsr (PlaySound).l
+
    subq.b  #2,routine(a0)
    lea (Ani_obj22).l,a1
    jsrto   (AnimateSprite).l, JmpTo5_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo15_MarkObjGone
; ===========================================================================
; loc_2577A:
Obj22_Arrow_Init:
    addq.b  #2,routine(a0)
    move.b  #8,y_radius(a0)
    move.b  #$10,x_radius(a0)
    move.b  #4,priority(a0)
    move.b  #$9B,collision_flags(a0)
    move.b  #8,width_pixels(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #$400,x_vel(a0)
    btst    #0,status(a0)
    beq.s   +
    neg.w   x_vel(a0)
+
    move.w  #SndID_ArrowFiring,d0
    jsr (PlaySound).l
; loc_257BE:
Obj22_Arrow:
    jsrto   (ObjectMove).l, JmpTo11_ObjectMove
    btst    #0,status(a0)
    bne.s   loc_257DE
    moveq   #-8,d3
    bsr.w   ObjCheckLeftWallDist
    tst.w   d1
    bmi.w   BranchTo_JmpTo27_DeleteObject
    jmpto   (MarkObjGone).l, JmpTo15_MarkObjGone
; ===========================================================================
 
BranchTo_JmpTo27_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo27_DeleteObject
; ===========================================================================
 
loc_257DE:
    moveq   #8,d3
    bsr.w   ObjCheckRightWallDist
    tst.w   d1
    bmi.w   BranchTo_JmpTo27_DeleteObject
    jmpto   (MarkObjGone).l, JmpTo15_MarkObjGone
; ===========================================================================
; animation script
; off_257EE:
Ani_obj22:  offsetTable
        offsetTableEntry.w byte_257F4   ; 0
        offsetTableEntry.w byte_257F7   ; 1
        offsetTableEntry.w byte_257FB   ; 2
byte_257F4: dc.b $1F,  1,$FF
    rev02even
byte_257F7: dc.b   3,  1,  2,$FF
    rev02even
byte_257FB: dc.b   7,  3,  4,$FC,  4,  3,  1,$FD,  0
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj22_MapUnc_25804: BINCLUDE "mappings/sprite/obj22.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo27_DeleteObject 
    jmp (DeleteObject).l
JmpTo5_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo15_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo5_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo24_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
; loc_25886:
JmpTo11_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 23 - Pillar that drops its lower part from ARZ
; ----------------------------------------------------------------------------
; Sprite_2588C:
Obj23:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj23_Index(pc,d0.w),d1
    jmp Obj23_Index(pc,d1.w)
; ===========================================================================
; off_2589A:
Obj23_Index:    offsetTable
        offsetTableEntry.w Obj23_Init   ; 0
        offsetTableEntry.w Obj23_Main   ; 2
; ===========================================================================
; loc_2589E:
Obj23_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj23_MapUnc_259E6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo25_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #$20,y_radius(a0)
    move.b  #4,priority(a0)
    jsrto   (SingleObjLoad2).l, JmpTo10_SingleObjLoad2
    bne.s   Obj23_Main
    _move.b id(a0),id(a1) ; load obj23
    addq.b  #2,routine(a1)
    addq.b  #2,routine_secondary(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  x_pos(a0),objoff_30(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$30,y_pos(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #$10,y_radius(a1)
    move.b  #4,priority(a1)
    move.b  #1,mapping_frame(a1)
; loc_25922:
Obj23_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   loc_25948
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo8_SolidObject
    jmpto   (MarkObjGone).l, JmpTo16_MarkObjGone
; ===========================================================================
 
loc_25948:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj23_Modes(pc,d0.w),d1
    jmp Obj23_Modes(pc,d1.w)
; ===========================================================================
; off_25956:
Obj23_Modes:    offsetTable
        offsetTableEntry.w return_2598C ; 0
        offsetTableEntry.w loc_2595E    ; 2
        offsetTableEntry.w loc_2598E    ; 4
        offsetTableEntry.w loc_259B8    ; 6
; ===========================================================================
 
loc_2595E:
    tst.w   (Debug_placement_mode).w
    bne.s   return_2598C
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_2596E
    lea (Sidekick).w,a1 ; a1=character
 
loc_2596E:
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   +
    neg.w   d0
+
    cmpi.w  #$80,d0
    bhs.s   return_2598C
    move.b  #4,routine_secondary(a0)
    move.w  #8,objoff_34(a0)
 
return_2598C:
    rts
; ===========================================================================
 
loc_2598E:
    move.w  objoff_34(a0),d0
    subq.w  #1,d0
    bcc.s   loc_2599C
    addq.b  #2,routine_secondary(a0)
    rts
; ===========================================================================
 
loc_2599C:
    move.w  d0,objoff_34(a0)
    move.b  byte_259B0(pc,d0.w),d0
    ext.w   d0
    add.w   objoff_30(a0),d0
    move.w  d0,x_pos(a0)
    rts
; ===========================================================================
byte_259B0:
    dc.b  0 ; 0
    dc.b  1 ; 1
    dc.b -1 ; 2
    dc.b  1 ; 3
    dc.b  0 ; 4
    dc.b -1 ; 5
    dc.b  0 ; 6
    dc.b  1 ; 7
; ===========================================================================
 
loc_259B8:
    jsrto   (ObjectMove).l, JmpTo12_ObjectMove
    addi.w  #$38,y_vel(a0)
    bsr.w   ObjCheckFloorDist
    tst.w   d1
    bpl.w   +
    add.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  #2,mapping_frame(a0)
    clr.b   routine_secondary(a0)
+
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj23_MapUnc_259E6: BINCLUDE "mappings/sprite/obj23.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 2B - Rising pillar from ARZ
; ----------------------------------------------------------------------------
; Sprite_25A5A:
Obj2B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2B_Index(pc,d0.w),d1
    jmp Obj2B_Index(pc,d1.w)
; ===========================================================================
; off_25A68:
Obj2B_Index:    offsetTable
        offsetTableEntry.w Obj2B_Init   ; 0
        offsetTableEntry.w Obj2B_Main   ; 2
        offsetTableEntry.w loc_25B8E    ; 4
; ===========================================================================
; loc_25A6E:
Obj2B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj2B_MapUnc_25C6E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo25_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #$18,y_radius(a0)
    move.b  #4,priority(a0)
; loc_25A9C:
Obj2B_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   loc_25B28
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo8_SolidObject
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.w   loc_25ACE
    jmpto   (MarkObjGone).l, JmpTo16_MarkObjGone
; ===========================================================================
 
loc_25ACE:
    lea (word_25BBE).l,a4
    lea (byte_25BB0).l,a2
    addq.b  #7,mapping_frame(a0)
    bsr.w   loc_25BF6
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    bsr.s   loc_25AF6
    lea (Sidekick).w,a1 ; a1=character
    addq.b  #1,d6
    bsr.s   loc_25AF6
    bra.w   loc_25B8E
; ===========================================================================
 
loc_25AF6:
    bclr    d6,status(a0)
    beq.s   return_25B26
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
 
return_25B26:
    rts
; ===========================================================================
 
loc_25B28:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_25B36(pc,d0.w),d1
    jmp off_25B36(pc,d1.w)
; ===========================================================================
off_25B36:  offsetTable
        offsetTableEntry.w loc_25B3C    ; 0
        offsetTableEntry.w loc_25B66    ; 2
        offsetTableEntry.w return_25B64 ; 4
; ===========================================================================
 
loc_25B3C:
    tst.w   (Debug_placement_mode).w
    bne.s   return_25B64
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_25B4C
    lea (Sidekick).w,a1 ; a1=character
 
loc_25B4C:
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   loc_25B58
    neg.w   d0
 
loc_25B58:
    cmpi.w  #$40,d0
    bhs.s   return_25B64
    move.b  #2,routine_secondary(a0)
 
return_25B64:
 
    rts
; ===========================================================================
 
loc_25B66:
    subq.w  #1,objoff_34(a0)
    bcc.s   return_25B8C
    move.w  #3,objoff_34(a0)
    subq.w  #4,y_pos(a0)
    addq.b  #4,y_radius(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #6,mapping_frame(a0)
    bne.s   return_25B8C
    move.b  #4,routine_secondary(a0)
 
return_25B8C:
    rts
; ===========================================================================
 
loc_25B8E:
 
    tst.b   objoff_3F(a0)
    beq.s   loc_25B9A
    subq.b  #1,objoff_3F(a0)
    bra.s   loc_25BA4
; ===========================================================================
 
loc_25B9A:
    jsrto   (ObjectMove).l, JmpTo12_ObjectMove
    addi.w  #$18,y_vel(a0)
 
loc_25BA4:
    tst.b   render_flags(a0)
    bpl.w   JmpTo28_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo16_DisplaySprite
; ===========================================================================
byte_25BB0:
    dc.b   0
    dc.b   0    ; 1
    dc.b   0    ; 2
    dc.b   0    ; 3
    dc.b   4    ; 4
    dc.b   4    ; 5
    dc.b   8    ; 6
    dc.b   8    ; 7
    dc.b  $C    ; 8
    dc.b  $C    ; 9
    dc.b $10    ; 10
    dc.b $10    ; 11
    dc.b $14    ; 12
    dc.b $14    ; 13
word_25BBE:
    dc.w -$200,-$200,$200,-$200 ; 0
    dc.w -$1C0,-$1C0,$1C0,-$1C0 ; 4
    dc.w -$180,-$180,$180,-$180 ; 8
    dc.w -$140,-$140,$140,-$140 ; 12
    dc.w -$100,-$100,$100,-$100 ; 16
    dc.w  -$C0, -$C0, $C0, -$C0 ; 20
    dc.w  -$80, -$80, $80, -$80 ; 24
; ===========================================================================
 
loc_25BF6:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    add.w   d0,d0
    movea.l mappings(a0),a3
    adda.w  (a3,d0.w),a3
    move.w  (a3)+,d1
    subq.w  #1,d1
    bset    #5,render_flags(a0)
    _move.b id(a0),d4
    move.b  render_flags(a0),d5
    movea.l a0,a1
    bra.s   loc_25C24
; ===========================================================================
 
loc_25C1C:
    jsrto   (SingleObjLoad2).l, JmpTo10_SingleObjLoad2
    bne.s   loc_25C64
    addq.w  #8,a3
 
loc_25C24:
    move.b  #4,routine(a1)
    _move.b d4,id(a1) ; load obj2B?
    move.l  a3,mappings(a1)
    move.b  d5,render_flags(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  priority(a0),priority(a1)
    move.b  width_pixels(a0),width_pixels(a1)
    move.w  (a4)+,x_vel(a1)
    move.w  (a4)+,y_vel(a1)
    move.b  (a2)+,objoff_3F(a1)
    dbf d1,loc_25C1C
 
loc_25C64:
    move.w  #SndID_SlowSmash,d0
    jmp (PlaySound).l
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj2B_MapUnc_25C6E: BINCLUDE "mappings/sprite/obj2B.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo16_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo28_DeleteObject 
    jmp (DeleteObject).l
JmpTo16_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo10_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo25_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo8_SolidObject 
    jmp (SolidObject).l
; loc_260FC:
JmpTo12_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo28_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 2C - Sprite that makes leaves fly off when you hit it from ARZ
; ----------------------------------------------------------------------------
; Sprite_26104:
Obj2C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj2C_Index(pc,d0.w),d1
    jmp Obj2C_Index(pc,d1.w)
; ===========================================================================
; off_26112:
Obj2C_Index:    offsetTable
        offsetTableEntry.w Obj2C_Init   ; 0
        offsetTableEntry.w Obj2C_Main   ; 2
        offsetTableEntry.w loc_26296    ; 4
; ===========================================================================
; byte_26118:
Obj2C_CollisionFlags:
    dc.b $D6
    dc.b $D4    ; 1
    dc.b $D5    ; 2
    dc.b   0    ; 3
; ===========================================================================
; loc_2611C:
Obj2C_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.b  Obj2C_CollisionFlags(pc,d0.w),collision_flags(a0)
    move.l  #Obj31_MapUnc_20E74,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    move.b  #$84,render_flags(a0)
    move.b  #$80,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  subtype(a0),mapping_frame(a0)
; loc_26152:
Obj2C_Main:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo29_DeleteObject
    move.b  collision_property(a0),d0
    beq.s   loc_261C2
    move.w  objoff_2E(a0),d0
    beq.s   +
    add.b   (Timer_frames+1).w,d0
    andi.w  #$F,d0
    bne.s   loc_26198
+
    lea (MainCharacter).w,a2 ; a2=character
    bclr    #0,collision_property(a0)
    beq.s   Obj2C_RemoveCollision
    bsr.s   loc_261C8
    tst.w   objoff_2E(a0)
    bne.s   Obj2C_RemoveCollision
    move.w  (Timer_frames).w,objoff_2E(a0)
    bra.s   Obj2C_RemoveCollision
; ===========================================================================
 
loc_26198:
    addi_.w #8,d0
    andi.w  #$F,d0
    bne.s   Obj2C_RemoveCollision
    lea (Sidekick).w,a2 ; a2=character
    bclr    #1,collision_property(a0)
    beq.s   Obj2C_RemoveCollision
    bsr.s   loc_261C8
    tst.w   objoff_2E(a0)
    bne.s   Obj2C_RemoveCollision
    move.w  (Timer_frames).w,objoff_2E(a0)
; loc_261BC:
Obj2C_RemoveCollision:
    clr.b   collision_property(a0)
    rts
; ===========================================================================
 
loc_261C2:
    clr.w   objoff_2E(a0)
    rts
; ===========================================================================
 
loc_261C8:
    mvabs.w x_vel(a2),d0
    cmpi.w  #$200,d0
    bhs.s   loc_261E4
    mvabs.w y_vel(a2),d0
    cmpi.w  #$200,d0
    blo.s   loc_261C2
 
loc_261E4:
    lea (Obj2C_Speeds).l,a3
    moveq   #3,d6
 
loc_261EC:
    jsrto   (SingleObjLoad).l, JmpTo6_SingleObjLoad
    bne.w   loc_26278
    _move.b #ObjID_LeavesGenerator,id(a1) ; load obj2C
    move.b  #4,routine(a1)
    move.w  x_pos(a2),x_pos(a1)
    move.w  y_pos(a2),y_pos(a1)
    jsrto   (RandomNumber).l, JmpTo2_RandomNumber
    andi.w  #$F,d0
    subq.w  #8,d0
    add.w   d0,x_pos(a1)
    swap    d0
    andi.w  #$F,d0
    subq.w  #8,d0
    add.w   d0,y_pos(a1)
    move.w  (a3)+,x_vel(a1)
    move.w  (a3)+,y_vel(a1)
    btst    #0,status(a2)
    beq.s   +
    neg.w   x_vel(a1)
+
    move.w  x_pos(a1),objoff_30(a1)
    move.w  y_pos(a1),objoff_34(a1)
    andi.b  #1,d0
    move.b  d0,mapping_frame(a1)
    move.l  #Obj2C_MapUnc_2631E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Leaves,3,1),art_tile(a1)
    move.b  #$84,render_flags(a1)
    move.b  #8,width_pixels(a1)
    move.b  #1,priority(a1)
    move.b  #4,objoff_38(a1)
    move.b  d1,angle(a0)
 
loc_26278:
    dbf d6,loc_261EC
    move.w  #SndID_Leaves,d0
    jmp (PlaySound).l
; ===========================================================================
; byte_26286: word_26286:
Obj2C_Speeds:
    dc.w -$80,-$80  ; 0
    dc.w  $C0,-$40  ; 1
    dc.w -$C0, $40  ; 2
    dc.w  $80, $80  ; 3
; ===========================================================================
 
loc_26296:
    move.b  objoff_38(a0),d0
    add.b   d0,angle(a0)
    add.b   (Vint_runcount+3).w,d0
    andi.w  #$1F,d0
    bne.s   +
    add.b   d7,d0
    andi.b  #1,d0
    beq.s   +
    neg.b   objoff_38(a0)
+
    move.l  objoff_30(a0),d2
    move.l  objoff_34(a0),d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,objoff_30(a0)
    move.l  d3,objoff_34(a0)
    swap    d2
    andi.w  #3,d3
    addq.w  #4,d3
    add.w   d3,y_vel(a0)
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo7_CalcSine
    asr.w   #6,d0
    add.w   objoff_30(a0),d0
    move.w  d0,x_pos(a0)
    asr.w   #6,d1
    add.w   objoff_34(a0),d1
    move.w  d1,y_pos(a0)
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #$B,anim_frame_duration(a0)
    bchg    #1,mapping_frame(a0)
+
    tst.b   render_flags(a0)
    bpl.w   JmpTo29_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo17_DisplaySprite
 
    if removeJmpTos
JmpTo29_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj2C_MapUnc_2631E: BINCLUDE "mappings/sprite/obj2C.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo17_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo29_DeleteObject 
    jmp (DeleteObject).l
JmpTo6_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo2_RandomNumber 
    jmp (RandomNumber).l
JmpTo7_CalcSine 
    jmp (CalcSine).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 40 - Pressure spring from CPZ, ARZ, and MCZ (the red "diving board" springboard)
; ----------------------------------------------------------------------------
; Sprite_26370:
Obj40:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj40_Index(pc,d0.w),d1
    jsr Obj40_Index(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo17_MarkObjGone
; ===========================================================================
; off_26382:
Obj40_Index:    offsetTable
        offsetTableEntry.w Obj40_Init   ; 0
        offsetTableEntry.w Obj40_Main   ; 2
; ---------------------------------------------------------------------------
; it seems this object's strength was once controlled by subtype
; these would be applied to the player's y_vel
; word_26386:
Obj40_Strengths:
    dc.w -$400  ; 0
    dc.w -$A00  ; 2
    ; inaccessible
    dc.w -$800  ; 4
; ===========================================================================
; loc_2638C:
Obj40_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj40_MapUnc_265F4,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_LeverSpring,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo26_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$1C,width_pixels(a0)
    move.b  #4,priority(a0)
    bset    #7,status(a0)
    move.b  subtype(a0),d0
    andi.w  #2,d0       ; there is enough data for this to be capped at 4
    move.w  Obj40_Strengths(pc,d0.w),objoff_30(a0)  ; this is never read
; loc_263C8:
Obj40_Main:
    lea (Ani_obj40).l,a1
    jsrto   (AnimateSprite).l, JmpTo6_AnimateSprite
    move.w  #$27,d1
    move.w  #8,d2
    move.w  x_pos(a0),d4
    lea Obj40_SlopeData_DiagUp(pc),a2
    tst.b   mapping_frame(a0)
    beq.s   +
    lea Obj40_SlopeData_Straight(pc),a2
+
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SlopedSolid_SingleCharacter).l, JmpTo_SlopedSolid_SingleCharacter
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    bsr.s   loc_2641E
+
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SlopedSolid_SingleCharacter).l, JmpTo_SlopedSolid_SingleCharacter
    btst    #p2_standing_bit,status(a0)
    beq.s   +   ; rts
    bsr.s   loc_2641E
+
    rts
; ===========================================================================
 
loc_2641E:
    btst    #0,status(a0)
    bne.s   loc_26436
    move.w  x_pos(a0),d0
    subi.w  #$10,d0
    cmp.w   x_pos(a1),d0
    blo.s   loc_26446
    rts
; ===========================================================================
 
loc_26436:
    move.w  x_pos(a0),d0
    addi.w  #$10,d0
    cmp.w   x_pos(a1),d0
    bhs.s   loc_26446
    rts
; ===========================================================================
 
loc_26446:
    cmpi.b  #1,anim(a0)
    beq.s   loc_26456
    move.w  #$100,anim(a0)
    rts
; ===========================================================================
 
loc_26456:
    tst.b   mapping_frame(a0)
    beq.s   loc_2645E
    rts
; ===========================================================================
 
loc_2645E:
    move.w  x_pos(a0),d0
    subi.w  #$1C,d0
    sub.w   x_pos(a1),d0
    neg.w   d0
    btst    #0,status(a0)
    beq.s   loc_2647A
    not.w   d0
    addi.w  #$27,d0
 
loc_2647A:
    tst.w   d0
    bpl.s   loc_26480
    moveq   #0,d0
 
loc_26480:
    lea (byte_26550).l,a3
    move.b  (a3,d0.w),d0
    move.w  #-$400,y_vel(a1)
    sub.b   d0,y_vel(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_264AA
    bclr    #0,status(a1)
    neg.b   d0
 
loc_264AA:
    mvabs.w x_vel(a1),d1
    cmpi.w  #$400,d1
    blo.s   loc_264BC
    sub.b   d0,x_vel(a1)
 
loc_264BC:
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  #0,spindash_flag(a1)
    move.b  subtype(a0),d0
    btst    #0,d0
    beq.s   loc_2651E
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   loc_2650E
    move.b  #3,flips_remaining(a1)
 
loc_2650E:
    btst    #0,status(a1)
    beq.s   loc_2651E
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_2651E:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   loc_26534
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
 
loc_26534:
    cmpi.b  #8,d0
    bne.s   loc_26546
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
 
loc_26546:
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
byte_26550:
    dc.b   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
    dc.b   0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1; 16
    dc.b   1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2; 32
    dc.b   3,  3,  3,  3,  3,  3,  4,  4,  0,  0,  0,  0,  0,  0,  0,  0; 48
    dc.b   0,  0,  0,  0,  0,  0,  0,  0; 64
;byte_26598:
Obj40_SlopeData_DiagUp:
    dc.b   8,  8,  8,  8,  8,  8,  8,  9, $A, $B, $C, $D, $E, $F,$10,$10
    dc.b $11,$12,$13,$14,$14,$15,$15,$16,$17,$18,$18,$18,$18,$18,$18,$18; 16
    dc.b $18,$18,$18,$18,$18,$18,$18,$18; 32
;byte_265C0:
Obj40_SlopeData_Straight:
    dc.b   8,  8,  8,  8,  8,  8,  8,  9, $A, $B, $C, $C, $C, $C, $D, $D
    dc.b  $D, $D, $D, $D, $E, $E, $F, $F,$10,$10,$10,$10, $F, $F, $E, $E; 16
    dc.b  $D, $D, $D, $D, $D, $D, $D, $D; 32
 
; animation script
; off_265E8:
Ani_obj40:  offsetTable
        offsetTableEntry.w byte_265EC   ; 0
        offsetTableEntry.w byte_265EF   ; 1
byte_265EC: dc.b  $F,  0,$FF
    rev02even
byte_265EF: dc.b   3,  1,  0,$FD,  0
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj40_MapUnc_265F4: BINCLUDE "mappings/sprite/obj40.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo17_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo6_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo26_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_SlopedSolid_SingleCharacter 
    jmp (SlopedSolid_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 42 - Steam Spring from MTZ
; ----------------------------------------------------------------------------
; Sprite_26634:
Obj42:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj42_Index(pc,d0.w),d1
    jmp Obj42_Index(pc,d1.w)
; ===========================================================================
; off_26642:
Obj42_Index:    offsetTable
        offsetTableEntry.w Obj42_Init   ; 0
        offsetTableEntry.w loc_26688    ; 2
        offsetTableEntry.w loc_2683A    ; 4
; ===========================================================================
; loc_26648:
Obj42_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj42_MapUnc_2686C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo27_Adjust2PArtPointer
    move.b  #7,mapping_frame(a0)
    move.w  y_pos(a0),objoff_34(a0)
    move.w  #$10,objoff_36(a0)
    addi.w  #$10,y_pos(a0)
 
loc_26688:
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo2_SolidObject_Always_SingleCharacter
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    bsr.w   loc_2678E
+
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo2_SolidObject_Always_SingleCharacter
    btst    #p2_standing_bit,status(a0)
    beq.s   +
    bsr.w   loc_2678E
+
    move.b  routine_secondary(a0),d0
    bne.s   loc_266E4
    subq.w  #1,objoff_32(a0)
    bpl.s   BranchTo_JmpTo18_MarkObjGone
    move.w  #$3B,objoff_32(a0)
    addq.b  #2,routine_secondary(a0)
    bra.s   BranchTo_JmpTo18_MarkObjGone
; ===========================================================================
 
loc_266E4:
    subq.b  #2,d0
    bne.s   loc_26716
    subq.w  #8,objoff_36(a0)
    bne.s   loc_26708
    addq.b  #2,routine_secondary(a0)
    bsr.s   loc_2674C
    addi.w  #$28,x_pos(a1)
    bsr.s   loc_2674C
    subi.w  #$28,x_pos(a1)
    bset    #0,render_flags(a1)
 
loc_26708:
    move.w  objoff_36(a0),d0
    add.w   objoff_34(a0),d0
    move.w  d0,y_pos(a0)
    bra.s   BranchTo_JmpTo18_MarkObjGone
; ===========================================================================
 
loc_26716:
    subq.b  #2,d0
    bne.s   loc_2672C
    subq.w  #1,objoff_32(a0)
    bpl.s   BranchTo_JmpTo18_MarkObjGone
    move.w  #$3B,objoff_32(a0)
    addq.b  #2,routine_secondary(a0)
    bra.s   BranchTo_JmpTo18_MarkObjGone
; ===========================================================================
 
loc_2672C:
    addq.w  #8,objoff_36(a0)
    cmpi.w  #$10,objoff_36(a0)
    bne.s   loc_2673C
    clr.b   routine_secondary(a0)
 
loc_2673C:
    move.w  objoff_36(a0),d0
    add.w   objoff_34(a0),d0
    move.w  d0,y_pos(a0)
 
BranchTo_JmpTo18_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo18_MarkObjGone
; ===========================================================================
 
loc_2674C:
    jsrto   (SingleObjLoad).l, JmpTo7_SingleObjLoad
    bne.s   +
    _move.b id(a0),id(a1) ; load obj42
    addq.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  objoff_34(a0),y_pos(a1)
    move.b  #7,anim_frame_duration(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzSteam,1,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #$18,width_pixels(a1)
    move.b  #4,priority(a1)
+
    rts
; ===========================================================================
 
loc_2678E:
    cmpi.b  #2,routine_secondary(a0)
    beq.s   loc_26798
    rts
; ===========================================================================
 
loc_26798:
    move.w  #-$A00,y_vel(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  #0,spindash_flag(a1)
    move.b  subtype(a0),d0
    bpl.s   +
    move.w  #0,x_vel(a1)
+
    btst    #0,d0
    beq.s   loc_26808
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    btst    #1,d0
    bne.s   +
    move.b  #1,flips_remaining(a1)
+
    btst    #0,status(a1)
    beq.s   loc_26808
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_26808:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
+
    cmpi.b  #8,d0
    bne.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
 
loc_2683A:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   ++
    move.b  #7,anim_frame_duration(a0)
    move.b  #0,collision_flags(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #3,mapping_frame(a0)
    bne.s   +
    move.b  #$A6,collision_flags(a0)
+
    cmpi.b  #7,mapping_frame(a0)
    beq.w   JmpTo30_DeleteObject
+
    jmpto   (DisplaySprite).l, JmpTo18_DisplaySprite
 
    if removeJmpTos
JmpTo30_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj42_MapUnc_2686C: BINCLUDE "mappings/sprite/obj42.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo18_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo30_DeleteObject 
    jmp (DeleteObject).l
JmpTo7_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo18_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo27_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo2_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 64 - Twin stompers from MTZ
; ----------------------------------------------------------------------------
; Sprite_26920:
Obj64:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj64_Index(pc,d0.w),d1
    jmp Obj64_Index(pc,d1.w)
; ===========================================================================
; off_2692E:
Obj64_Index:    offsetTable
        offsetTableEntry.w Obj64_Init   ; 0
        offsetTableEntry.w Obj64_Main   ; 2
; ===========================================================================
; byte_26932:
Obj64_Properties:
    ;    width_pixels
    ;     objoff_2E
    dc.b $40, $C
    dc.b $40,  1    ; 2
    dc.b $10,$20    ; 4
    dc.b $40,  1    ; 6
; ===========================================================================
; loc_2693A:
Obj64_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #2,d0
    andi.w  #$1C,d0
    lea Obj64_Properties(pc,d0.w),a3
    move.b  (a3)+,width_pixels(a0)
    move.b  (a3)+,objoff_2E(a0)
    lsr.w   #2,d0
    move.b  d0,mapping_frame(a0)
    bne.s   +
    move.b  #$6C,y_radius(a0)
    bset    #4,render_flags(a0)
+
    move.l  #Obj64_MapUnc_26A5C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo28_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    moveq   #0,d0
    move.b  (a3)+,d0
    move.w  d0,objoff_3C(a0)
    andi.b  #$F,subtype(a0)
; loc_269A2:
Obj64_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.w  Obj64_Modes(pc,d0.w),d1
    jsr Obj64_Modes(pc,d1.w)
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   +
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  objoff_2E(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo9_SolidObject
+
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   JmpTo31_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
JmpTo31_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; off_269F4:
Obj64_Modes:    offsetTable
        offsetTableEntry.w return_269F8 ; 0
        offsetTableEntry.w loc_269FA    ; 2
; ===========================================================================
 
return_269F8:
    rts
; ===========================================================================
 
loc_269FA:
    tst.b   objoff_38(a0)
    bne.s   loc_26A1E
    tst.w   objoff_3A(a0)
    beq.s   loc_26A0C
    subq.w  #8,objoff_3A(a0)
    bra.s   loc_26A3E
; ===========================================================================
 
loc_26A0C:
    subq.w  #1,objoff_36(a0)
    bpl.s   loc_26A3E
    move.w  #$5A,objoff_36(a0)
    move.b  #1,objoff_38(a0)
 
loc_26A1E:
    move.w  objoff_3A(a0),d0
    cmp.w   objoff_3C(a0),d0
    beq.s   loc_26A2E
    addq.w  #8,objoff_3A(a0)
    bra.s   loc_26A3E
; ===========================================================================
 
loc_26A2E:
    subq.w  #1,objoff_36(a0)
    bpl.s   loc_26A3E
    move.w  #$5A,objoff_36(a0)
    clr.b   objoff_38(a0)
 
loc_26A3E:
    move.w  objoff_3A(a0),d0
    btst    #0,status(a0)
    beq.s   loc_26A50
    neg.w   d0
    addi.w  #$40,d0
 
loc_26A50:
    move.w  objoff_30(a0),d1
    add.w   d0,d1
    move.w  d1,y_pos(a0)
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj64_MapUnc_26A5C: BINCLUDE "mappings/sprite/obj64.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo28_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo9_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 65 - Long moving platform from MTZ
; ----------------------------------------------------------------------------
; Sprite_26AE0:
Obj65:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj65_Index(pc,d0.w),d1
    jmp Obj65_Index(pc,d1.w)
; ===========================================================================
; off_26AEE:
Obj65_Index:    offsetTable
        offsetTableEntry.w Obj65_Init   ; 0
        offsetTableEntry.w loc_26C1C    ; 2
        offsetTableEntry.w loc_26EA4    ; 4
        offsetTableEntry.w loc_26EC2    ; 6
; ---------------------------------------------------------------------------
; byte_26AF6:
Obj65_Properties:
    ;    width_pixels
    ;    radius
    dc.b $40, $C
    dc.b $80,  1    ; 2
    dc.b $20, $C    ; 4
    dc.b $40,  3    ; 6
    dc.b $10,$10    ; 8
    dc.b $20,  0    ; 10
    dc.b $40, $C    ; 12
    dc.b $80,  7    ; 14
; ===========================================================================
; loc_26B06:
Obj65_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj65_Obj6A_Obj6B_MapUnc_26EC8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo29_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #2,d0
    andi.w  #$1C,d0
    lea Obj65_Properties(pc,d0.w),a3
    move.b  (a3)+,width_pixels(a0)
    move.b  (a3)+,y_radius(a0)
    lsr.w   #2,d0
    move.b  d0,mapping_frame(a0)
    cmpi.b  #1,d0
    bne.s   +
    bset    #7,status(a0)
+
    cmpi.b  #2,d0
    bne.s   loc_26B6E
    addq.b  #4,routine(a0)
    move.l  #Obj65_MapUnc_26F04,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzCog,3,0),art_tile(a0)
    bra.w   loc_26EC2
; ===========================================================================
 
loc_26B6E:
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    moveq   #0,d0
    move.b  (a3)+,d0
    move.w  d0,objoff_3C(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    bpl.w   loc_26C16
    andi.b  #$F,d0
    move.b  d0,objoff_3E(a0)
    move.b  (a3),subtype(a0)
    cmpi.b  #7,(a3)
    bne.s   +
    move.w  objoff_3C(a0),objoff_3A(a0)
+
    jsrto   (SingleObjLoad2).l, JmpTo11_SingleObjLoad2
    bne.s   loc_26C04
    _move.b id(a0),id(a1) ; load obj65
    addq.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #-$4C,x_pos(a1)
    addi.w  #$14,y_pos(a1)
    btst    #0,status(a0)
    bne.s   +
    subi.w  #-$18,x_pos(a1)
    bset    #0,render_flags(a1)
+
    move.l  #Obj65_MapUnc_26F04,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzCog,3,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  a0,objoff_3C(a1)
 
loc_26C04:
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   loc_26C16
    bclr    #7,2(a2,d0.w)
 
loc_26C16:
    andi.b  #$F,subtype(a0)
 
loc_26C1C:
    move.w  x_pos(a0),objoff_2E(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.w  off_26C7E(pc,d0.w),d1
    jsr off_26C7E(pc,d1.w)
    move.w  objoff_2E(a0),d4
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi_.w #5,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo10_SolidObject
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   loc_26C66
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_26C66:
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    jmp (DeleteObject).l
; ===========================================================================
off_26C7E:  offsetTable
        offsetTableEntry.w return_26C8E ; 0
        offsetTableEntry.w loc_26CA4    ; 1
        offsetTableEntry.w loc_26D34    ; 2
        offsetTableEntry.w loc_26D94    ; 3
        offsetTableEntry.w loc_26E3C    ; 4
        offsetTableEntry.w loc_26E4A    ; 5
        offsetTableEntry.w loc_26C90    ; 6
        offsetTableEntry.w loc_26D14    ; 7
; ===========================================================================
 
return_26C8E:
    rts
; ===========================================================================
 
loc_26C90:
    tst.b   objoff_38(a0)
    bne.s   BranchTo_loc_26CC2
    subq.w  #1,objoff_36(a0)
    bne.s   loc_26CD0
    move.b  #1,objoff_38(a0)
 
BranchTo_loc_26CC2 
    bra.s   loc_26CC2
; ===========================================================================
 
loc_26CA4:
    tst.b   objoff_38(a0)
    bne.s   loc_26CC2
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  objoff_3E(a0),d0
    btst    #0,(a2,d0.w)
    beq.s   loc_26CD0
    move.b  #1,objoff_38(a0)
 
loc_26CC2:
    move.w  objoff_3C(a0),d0
    cmp.w   objoff_3A(a0),d0
    beq.s   loc_26CF2
    addq.w  #2,objoff_3A(a0)
 
loc_26CD0:
    move.w  objoff_3A(a0),d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    addi.w  #$80,d0
+
    move.w  objoff_34(a0),d1
    sub.w   d0,d1
    move.w  d1,x_pos(a0)
    move.w  d1,objoff_2E(a0)
    rts
; ===========================================================================
 
loc_26CF2:
    addq.b  #1,subtype(a0)
    move.w  #$B4,objoff_36(a0)
    clr.b   objoff_38(a0)
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   loc_26CD0
    bset    #0,2(a2,d0.w)
    bra.s   loc_26CD0
; ===========================================================================
 
loc_26D14:
    tst.b   objoff_38(a0)
    bne.s   +
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  objoff_3E(a0),d0
    btst    #0,(a2,d0.w)
    beq.s   loc_26D50
    move.b  #1,objoff_38(a0)
+
    bra.s   loc_26D46
; ===========================================================================
 
loc_26D34:
    tst.b   objoff_38(a0)
    bne.s   loc_26D46
    subq.w  #1,objoff_36(a0)
    bne.s   loc_26D50
    move.b  #1,objoff_38(a0)
 
loc_26D46:
    tst.w   objoff_3A(a0)
    beq.s   loc_26D72
    subq.w  #2,objoff_3A(a0)
 
loc_26D50:
    move.w  objoff_3A(a0),d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    addi.w  #$80,d0
+
    move.w  objoff_34(a0),d1
    sub.w   d0,d1
    move.w  d1,x_pos(a0)
    move.w  d1,objoff_2E(a0)
    rts
; ===========================================================================
 
loc_26D72:
    subq.b  #1,subtype(a0)
    move.w  #$B4,objoff_36(a0)
    clr.b   objoff_38(a0)
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   loc_26D50
    bclr    #0,2(a2,d0.w)
    bra.s   loc_26D50
; ===========================================================================
 
loc_26D94:
    move.w  objoff_34(a0),d4
    move.w  d4,d5
    btst    #0,status(a0)
    bne.s   loc_26DAC
    subi.w  #$20,d4
    addi.w  #$60,d5
    bra.s   loc_26DB4
; ===========================================================================
 
loc_26DAC:
    subi.w  #$A0,d4
    subi.w  #$20,d5
 
loc_26DB4:
    move.w  y_pos(a0),d2
    move.w  d2,d3
    subi.w  #$10,d2
    addi.w  #$40,d3
    moveq   #0,d1
    move.w  (MainCharacter+x_pos).w,d0
    cmp.w   d4,d0
    blo.s   +
    cmp.w   d5,d0
    bhs.s   +
    move.w  (MainCharacter+y_pos).w,d0
    cmp.w   d2,d0
    blo.s   +
    cmp.w   d3,d0
    bhs.s   +
    moveq   #1,d1
+
    move.w  (Sidekick+x_pos).w,d0
    cmp.w   d4,d0
    blo.s   +
    cmp.w   d5,d0
    bhs.s   +
    move.w  (Sidekick+y_pos).w,d0
    cmp.w   d2,d0
    blo.s   +
    cmp.w   d3,d0
    bhs.s   +
    moveq   #1,d1
+
    tst.b   d1
    beq.s   loc_26E0E
    move.w  objoff_3C(a0),d0
    cmp.w   objoff_3A(a0),d0
    beq.s   return_26E3A
    addi.w  #$10,objoff_3A(a0)
    bra.s   loc_26E1A
; ===========================================================================
 
loc_26E0E:
    tst.w   objoff_3A(a0)
    beq.s   loc_26E1A
    subi.w  #$10,objoff_3A(a0)
 
loc_26E1A:
    move.w  objoff_3A(a0),d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    addi.w  #$40,d0
+
    move.w  objoff_34(a0),d1
    sub.w   d0,d1
    move.w  d1,x_pos(a0)
    move.w  d1,objoff_2E(a0)
 
return_26E3A:
    rts
; ===========================================================================
 
loc_26E3C:
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    addq.b  #1,subtype(a0)
+
    rts
; ===========================================================================
 
loc_26E4A:
    tst.b   objoff_38(a0)
    bne.s   loc_26E84
    addq.w  #2,x_pos(a0)
    cmpi.b  #metropolis_zone_2,(Current_Zone).w
    bne.s   loc_26E74
    cmpi.w  #$1CC0,x_pos(a0)
    beq.s   loc_26E6C
    cmpi.w  #$2940,x_pos(a0)
    bne.s   loc_26E96
 
loc_26E6C:
    move.b  #0,subtype(a0)
    bra.s   loc_26E96
; ===========================================================================
 
loc_26E74:
    cmpi.w  #$1BC0,x_pos(a0)
    bne.s   loc_26E96
    move.b  #1,objoff_38(a0)
    bra.s   loc_26E96
; ===========================================================================
 
loc_26E84:
    subq.w  #2,x_pos(a0)
    cmpi.w  #$1880,x_pos(a0)
    bne.s   loc_26E96
    move.b  #0,objoff_38(a0)
 
loc_26E96:
    move.w  x_pos(a0),objoff_34(a0)
    move.w  x_pos(a0),(MTZ_Platform_Cog_X).w
    rts
; ===========================================================================
 
loc_26EA4:
    movea.l objoff_3C(a0),a1 ; a1=object
    move.w  objoff_3A(a1),d0
 
loc_26EAC:
    andi.w  #7,d0
    move.b  byte_26EBA(pc,d0.w),mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo19_MarkObjGone
; ===========================================================================
byte_26EBA:
    dc.b   0
    dc.b   0    ; 1
    dc.b   2    ; 2
    dc.b   2    ; 3
    dc.b   2    ; 4
    dc.b   1    ; 5
    dc.b   1    ; 6
    dc.b   1    ; 7
; ===========================================================================
 
loc_26EC2:
    move.w  (MTZ_Platform_Cog_X).w,d0
    bra.s   loc_26EAC
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj65_Obj6A_Obj6B_MapUnc_26EC8: BINCLUDE "mappings/sprite/obj65_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj65_MapUnc_26F04: BINCLUDE "mappings/sprite/obj65_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo19_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo11_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo29_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo10_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 66 - Yellow spring walls from MTZ
; ----------------------------------------------------------------------------
; Sprite_26F58:
Obj66:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj66_Index(pc,d0.w),d1
    jmp Obj66_Index(pc,d1.w)
; ===========================================================================
; off_26F66:
Obj66_Index:    offsetTable
        offsetTableEntry.w Obj66_Init   ; 0
        offsetTableEntry.w Obj66_Main   ; 2
; ===========================================================================
; loc_26F6A:
Obj66_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj66_MapUnc_27120,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo30_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #8,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  #$40,y_radius(a0)
    move.b  subtype(a0),d0
    lsr.b   #4,d0
    andi.b  #7,d0
    move.b  d0,mapping_frame(a0)
    beq.s   Obj66_Main
    move.b  #$80,y_radius(a0)
; loc_26FAE:
Obj66_Main:
    move.w  #$13,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo3_SolidObject_Always_SingleCharacter
    cmpi.b  #1,d4
    bne.s   loc_26FF6
    btst    #1,status(a1)
    beq.s   loc_26FF6
    move.b  status(a0),d1
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcs.s   +
    eori.b  #1,d1
+
    andi.b  #1,d1
    bne.s   loc_26FF6
    bsr.s   loc_27042
 
loc_26FF6:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo3_SolidObject_Always_SingleCharacter
    cmpi.b  #1,d4
    bne.s   loc_2702C
    btst    #1,status(a1)
    beq.s   loc_2702C
    move.b  status(a0),d1
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcs.s   +
    eori.b  #1,d1
+
    andi.b  #1,d1
    bne.s   loc_2702C
    bsr.s   loc_27042
 
loc_2702C:
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo33_DeleteObject
    if gameRevision=0
       ; this object was visible with debug mode in REV00
    tst.w   (Debug_placement_mode).w
    beq.s   +   ; rts
    jsrto   (DisplaySprite).l, JmpTo47_DisplaySprite
+
    endif
    rts
 
    if removeJmpTos
JmpTo33_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
loc_27042:
    if gameRevision>0
    ; REV00 didn't prevent the player from bouncing if they were hurt or dead
    cmpi.b  #4,routine(a1)
    blo.s   loc_2704C
    rts
    endif
; ===========================================================================
 
loc_2704C:
    move.w  objoff_30(a0),x_vel(a1)
    move.w  #-$800,x_vel(a1)
    move.w  #-$800,y_vel(a1)
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   +
    bclr    #0,status(a1)
    neg.w   x_vel(a1)
+
    move.w  #$F,move_lock(a1)
    move.w  x_vel(a1),inertia(a1)
    btst    #2,status(a1)
    bne.s   +
    move.b  #AniIDSonAni_Walk,anim(a1)
+
    move.b  subtype(a0),d0
    bpl.s   +
    move.w  #0,y_vel(a1)
+
    btst    #0,d0
    beq.s   loc_270DC
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #1,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
    btst    #1,d0
    bne.s   +
    move.b  #3,flips_remaining(a1)
+
    btst    #0,status(a1)
    beq.s   loc_270DC
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_270DC:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
+
    cmpi.b  #8,d0
    bne.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    bclr    #p1_pushing_bit,status(a0)
    bclr    #p2_pushing_bit,status(a0)
    bclr    #5,status(a1)
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj66_MapUnc_27120: BINCLUDE "mappings/sprite/obj66.bin"
; ===========================================================================
 
    if ~~removeJmpTos
 
     if gameRevision=0
JmpTo47_DisplaySprite 
    jmp (DisplaySprite).l
     endif
 
JmpTo33_DeleteObject 
    jmp (DeleteObject).l
JmpTo30_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo3_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 67 - Spin tube from MTZ
; ----------------------------------------------------------------------------
; Sprite_2715C:
Obj67:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj67_Index(pc,d0.w),d1
    jsr Obj67_Index(pc,d1.w)
    move.b  objoff_2C(a0),d0
    add.b   objoff_36(a0),d0
    beq.w   JmpTo4_MarkObjGone3
    lea (Ani_obj67).l,a1
    jsrto   (AnimateSprite).l, JmpTo7_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo19_DisplaySprite
; ===========================================================================
; off_27184:
Obj67_Index:    offsetTable
        offsetTableEntry.w Obj67_Init   ; 0
        offsetTableEntry.w Obj67_Main   ; 2
; ===========================================================================
; loc_27188:
Obj67_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj67_MapUnc_27548,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzSpinTubeFlash,3,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #5,priority(a0)
; loc_271AC:
Obj67_Main:
    lea (MainCharacter).w,a1 ; a1=character
    lea objoff_2C(a0),a4
    bsr.s   loc_271BE
    lea (Sidekick).w,a1 ; a1=character
    lea objoff_36(a0),a4
 
loc_271BE:
    moveq   #0,d0
    move.b  (a4),d0
    move.w  off_271CA(pc,d0.w),d0
    jmp off_271CA(pc,d0.w)
; ===========================================================================
off_271CA:  offsetTable
        offsetTableEntry.w loc_271D0    ; 0
        offsetTableEntry.w loc_27260    ; 2
        offsetTableEntry.w loc_27294    ; 4
; ===========================================================================
 
loc_271D0:
    tst.w   (Debug_placement_mode).w
    bne.w   return_2725E
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addq.w  #3,d0
    btst    #0,status(a0)
    beq.s   +
    addi.w  #$A,d0
+
    cmpi.w  #$10,d0
    bhs.s   return_2725E
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    addi.w  #$20,d1
    cmpi.w  #$40,d1
    bhs.s   return_2725E
    tst.b   obj_control(a1)
    bne.s   return_2725E
    addq.b  #2,(a4)
    move.b  #$81,obj_control(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.w  #$800,inertia(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    bclr    #5,status(a0)
    bclr    #5,status(a1)
    bset    #1,status(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    clr.b   1(a4)
    move.w  #SndID_Roll,d0
    jsr (PlaySound).l
    move.w  #$100,anim(a0)
 
return_2725E:
    rts
; ===========================================================================
 
loc_27260:
    move.b  1(a4),d0
    addq.b  #2,1(a4)
    jsr (CalcSine).l
    asr.w   #5,d0
    move.w  y_pos(a0),d2
    sub.w   d0,d2
    move.w  d2,y_pos(a1)
    cmpi.b  #$80,1(a4)
    bne.s   +
    bsr.w   loc_27310
    addq.b  #2,(a4)
    move.w  #SndID_SpindashRelease,d0
    jsr (PlaySound).l
+
    rts
; ===========================================================================
 
loc_27294:
    subq.b  #1,2(a4)
    bpl.s   Obj67_MoveCharacter
    movea.l 6(a4),a2
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
    tst.b   subtype(a0)
    bpl.s   +
    subq.w  #8,a2
+
    move.l  a2,6(a4)
    subq.w  #4,4(a4)
    beq.s   loc_272EE
    move.w  (a2)+,d4
    move.w  (a2)+,d5
    move.w  #$1000,d2
    bra.w   loc_27374
; ===========================================================================
; update the position of Sonic/Tails in the MTZ tube
; loc_272C8:
Obj67_MoveCharacter:
    move.l  x_pos(a1),d2
    move.l  y_pos(a1),d3
    move.w  x_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a1),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,x_pos(a1)
    move.l  d3,y_pos(a1)
    rts
; ===========================================================================
 
loc_272EE:
    andi.w  #$7FF,y_pos(a1)
    clr.b   (a4)
    clr.b   obj_control(a1)
    btst    #4,subtype(a0)
    bne.s   +
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
+
    rts
; ===========================================================================
 
loc_27310:
    move.b  subtype(a0),d0
    bpl.s   loc_27344
    neg.b   d0
    andi.w  #$F,d0
    add.w   d0,d0
    lea (off_273F2).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d0
    subq.w  #4,d0
    move.w  d0,4(a4)
    lea (a2,d0.w),a2
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
    subq.w  #8,a2
    bra.s   loc_27368
; ===========================================================================
 
loc_27344:
    andi.w  #$F,d0
    add.w   d0,d0
    lea (off_273F2).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,4(a4)
    subq.w  #4,4(a4)
    move.w  (a2)+,d4
    move.w  d4,x_pos(a1)
    move.w  (a2)+,d5
    move.w  d5,y_pos(a1)
 
loc_27368:
    move.l  a2,6(a4)
    move.w  (a2)+,d4
    move.w  (a2)+,d5
    move.w  #$1000,d2
 
loc_27374:
    moveq   #0,d0
    move.w  d2,d3
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    bge.s   loc_27384
    neg.w   d0
    neg.w   d2
 
loc_27384:
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    bge.s   loc_27392
    neg.w   d1
    neg.w   d3
 
loc_27392:
    cmp.w   d0,d1
    blo.s   loc_273C4
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    swap    d1
    divs.w  d3,d1
    moveq   #0,d0
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    beq.s   loc_273B0
    swap    d0
    divs.w  d1,d0
 
loc_273B0:
    move.w  d0,x_vel(a1)
    move.w  d3,y_vel(a1)
    abs.w   d1
    move.w  d1,2(a4)
    rts
; ===========================================================================
 
loc_273C4:
    moveq   #0,d0
    move.w  d4,d0
    sub.w   x_pos(a1),d0
    swap    d0
    divs.w  d2,d0
    moveq   #0,d1
    move.w  d5,d1
    sub.w   y_pos(a1),d1
    beq.s   loc_273DE
    swap    d1
    divs.w  d0,d1
 
loc_273DE:
    move.w  d1,y_vel(a1)
    move.w  d2,x_vel(a1)
    abs.w   d0
    move.w  d0,2(a4)
    rts
; ===========================================================================
; MTZ tube position data
; off_273F2:
    include "misc/obj67.asm"
; animation script
; byte_2752E:
Ani_obj67:  offsetTable
        offsetTableEntry.w byte_27532   ; 0
        offsetTableEntry.w byte_27535   ; 1
byte_27532:
    dc.b $1F,  0,$FF
    rev02even
byte_27535:
    dc.b   1,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  1,  0,$FE,  2
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj67_MapUnc_27548: BINCLUDE "mappings/sprite/obj67.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo19_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo7_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo4_MarkObjGone3 
    jmp (MarkObjGone3).l
 
    align 4
    else
JmpTo4_MarkObjGone3 
    jmp (MarkObjGone3).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 68 - Block with a spike that comes out of each side sequentially from MTZ
; ----------------------------------------------------------------------------
spikearoundblock_initial_x_pos =    objoff_30
spikearoundblock_initial_y_pos =    objoff_32
spikearoundblock_offset =       objoff_34 ; offset from the center
spikearoundblock_position =     objoff_36 ; 0 = retracted or expanding, 1 = expanded or retracting
spikearoundblock_waiting =      objoff_38 ; 0 = moving, 1 = waiting
; Sprite_27594:
Obj68:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj68_Index(pc,d0.w),d1
    jmp Obj68_Index(pc,d1.w)
; ===========================================================================
; off_275A2:
Obj68_Index:    offsetTable
        offsetTableEntry.w Obj68_Init   ; 0
        offsetTableEntry.w Obj68_Block  ; 2
        offsetTableEntry.w Obj68_Spike  ; 4
; ===========================================================================
; loc_275A8:
Obj68_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj68_Obj6D_MapUnc_27750,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzSpikeBlock,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo31_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    jsrto   (SingleObjLoad2).l, JmpTo12_SingleObjLoad2
    bne.s   +
    _move.b id(a0),id(a1) ; load obj68
    addq.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  x_pos(a1),spikearoundblock_initial_x_pos(a1)
    move.w  y_pos(a1),spikearoundblock_initial_y_pos(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzSpike,1,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #4,priority(a1)
    move.w  (Timer_frames).w,d0
    lsr.w   #6,d0
    move.w  d0,d1
    andi.w  #1,d0
    move.w  d0,spikearoundblock_position(a1)
    lsr.w   #1,d1
    add.b   subtype(a0),d1
    andi.w  #3,d1
    move.b  d1,routine_secondary(a1)
    move.b  d1,mapping_frame(a1)
    lea (Obj68_CollisionFlags).l,a2
    move.b  (a2,d1.w),collision_flags(a1)
+
    move.b  #4,mapping_frame(a0)
; loc_2764A:
Obj68_Block:
    move.w  #$1B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo11_SolidObject
    jmpto   (MarkObjGone).l, JmpTo20_MarkObjGone
; ===========================================================================
; loc_27662:
Obj68_Spike:
    bsr.w   Obj68_Spike_Action
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    add.w   d0,d0
    move.w  Obj68_Spike_Directions(pc,d0.w),d1
    jsr Obj68_Spike_Directions(pc,d1.w)
    move.w  spikearoundblock_initial_x_pos(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo2_MarkObjGone2
; ===========================================================================
; off_2767E:
Obj68_Spike_Directions: offsetTable
    offsetTableEntry.w Obj68_Spike_Up   ; 0
    offsetTableEntry.w Obj68_Spike_Right    ; 1
    offsetTableEntry.w Obj68_Spike_Down ; 2
    offsetTableEntry.w Obj68_Spike_Left ; 3
; ===========================================================================
; These routines update the position of the spike.
; ===========================================================================
; loc_27686:
Obj68_Spike_Up:
    moveq   #0,d0
    move.b  spikearoundblock_offset(a0),d0
    neg.w   d0
    add.w   spikearoundblock_initial_y_pos(a0),d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
; loc_27698:
Obj68_Spike_Right:
    moveq   #0,d0
    move.b  spikearoundblock_offset(a0),d0
    add.w   spikearoundblock_initial_x_pos(a0),d0
    move.w  d0,x_pos(a0)
    rts
; ===========================================================================
; loc_276A8:
Obj68_Spike_Down:
    moveq   #0,d0
    move.b  spikearoundblock_offset(a0),d0
    add.w   spikearoundblock_initial_y_pos(a0),d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
; loc_276B8:
Obj68_Spike_Left:
    moveq   #0,d0
    move.b  spikearoundblock_offset(a0),d0
    neg.w   d0
    add.w   spikearoundblock_initial_x_pos(a0),d0
    move.w  d0,x_pos(a0)
    rts
; ===========================================================================
; loc_276CA:
Obj68_Spike_Action:
    tst.w   spikearoundblock_waiting(a0)
    beq.s   +
    move.b  (Timer_frames+1).w,d0
    andi.b  #$3F,d0
    bne.s   Obj68_Spike_Action_End
    clr.w   spikearoundblock_waiting(a0)
    tst.b   render_flags(a0)    ; is the spike on the screen?
    bpl.s   +           ; if not, branch
    move.w  #SndID_SpikesMove,d0
    jsr (PlaySound).l
+
    tst.w   spikearoundblock_position(a0)
    beq.s   Obj68_Spike_Expanding
; Obj68_Spike_Retracting:
    subi.w  #$800,spikearoundblock_offset(a0)   ; retract the spike
    bcc.s   Obj68_Spike_Action_End
    move.w  #0,spikearoundblock_offset(a0)
    move.w  #0,spikearoundblock_position(a0)
    move.w  #1,spikearoundblock_waiting(a0)
    addq.b  #1,routine_secondary(a0)
    andi.b  #3,routine_secondary(a0)
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.b  d0,mapping_frame(a0)
    move.b  Obj68_CollisionFlags(pc,d0.w),collision_flags(a0)
    rts
; ===========================================================================
; loc_2772A:
Obj68_Spike_Expanding:
    addi.w  #$800,spikearoundblock_offset(a0)   ; expand the spike
    cmpi.w  #$2000,spikearoundblock_offset(a0)  ; did it reach full expansion?
    blo.s   Obj68_Spike_Action_End          ; if not, return
    move.w  #$2000,spikearoundblock_offset(a0)
    move.w  #1,spikearoundblock_position(a0)
    move.w  #1,spikearoundblock_waiting(a0)
; return_2774A:
Obj68_Spike_Action_End:
    rts
; ===========================================================================
; byte_2774C:
Obj68_CollisionFlags:
    dc.b $84    ; 0
    dc.b $A6    ; 1
    dc.b $84    ; 2
    dc.b $A6    ; 3
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj68_Obj6D_MapUnc_27750:   BINCLUDE "mappings/sprite/obj68.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6D - Floor spike from MTZ
; ----------------------------------------------------------------------------
floorspike_initial_x_pos =  objoff_30
floorspike_initial_y_pos =  objoff_32
floorspike_offset =     objoff_34 ; on the y axis
floorspike_position =       objoff_36 ; 0 = retracted or expanding, 1 = expanded or retracting
floorspike_waiting =        objoff_38 ; 0 = moving, 1 = waiting
floorspike_delay =      objoff_3A ; short delay before the spike retracts
; Sprite_27794:
Obj6D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj6D_Index(pc,d0.w),d1
    jmp Obj6D_Index(pc,d1.w)
; ===========================================================================
; off_277A2:
Obj6D_Index:    offsetTable
        offsetTableEntry.w Obj6D_Init   ; 0
        offsetTableEntry.w Obj6D_Main   ; 2
; ===========================================================================
; loc_277A6:
Obj6D_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj68_Obj6D_MapUnc_27750,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzSpike,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo31_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  x_pos(a0),floorspike_initial_x_pos(a0)
    move.w  y_pos(a0),floorspike_initial_y_pos(a0)
    move.b  #$84,collision_flags(a0)
; loc_277E0:
Obj6D_Main:
    bsr.w   Obj6D_Action
    moveq   #0,d0
    move.b  floorspike_offset(a0),d0
    neg.w   d0
    add.w   floorspike_initial_y_pos(a0),d0
    move.w  d0,y_pos(a0)
    move.w  floorspike_initial_x_pos(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo2_MarkObjGone2
; ===========================================================================
; loc_277FC:
Obj6D_Action:
    tst.w   floorspike_delay(a0)
    beq.s   +
    subq.w  #1,floorspike_delay(a0)
    rts
; ---------------------------------------------------------------------------
+
    tst.w   floorspike_waiting(a0)
    beq.s   +
    move.b  (Timer_frames+1).w,d0
    sub.b   subtype(a0),d0
    andi.b  #$7F,d0
    bne.s   Obj6D_Action_End
    clr.w   floorspike_waiting(a0)
+
    tst.w   floorspike_position(a0)
    beq.s   Obj6D_Expanding
; Obj6D_Retracting:
    subi.w  #$400,floorspike_offset(a0)
    bcc.s   Obj6D_Action_End
    move.w  #0,floorspike_offset(a0)
    move.w  #0,floorspike_position(a0)
    move.w  #1,floorspike_waiting(a0)
    rts
; ===========================================================================
; loc_27842:
Obj6D_Expanding:
    addi.w  #$400,floorspike_offset(a0)
    cmpi.w  #$2000,floorspike_offset(a0)
    blo.s   Obj6D_Action_End
    move.w  #$2000,floorspike_offset(a0)
    move.w  #1,floorspike_position(a0)
    move.w  #3,floorspike_delay(a0)
; return_27862:
Obj6D_Action_End:
    rts
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo20_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo12_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo31_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo11_SolidObject 
    jmp (SolidObject).l
JmpTo2_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 69 - Nut from MTZ
; ----------------------------------------------------------------------------
; Sprite_27884:
Obj69:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj69_Index(pc,d0.w),d1
    jmp Obj69_Index(pc,d1.w)
; ===========================================================================
; off_27892:
Obj69_Index:    offsetTable
        offsetTableEntry.w Obj69_Init   ; 0
        offsetTableEntry.w Obj69_Main   ; 2
        offsetTableEntry.w loc_279FC    ; 4
        offsetTableEntry.w loc_278F4    ; 6
; ===========================================================================
; loc_2789A:
Obj69_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj69_MapUnc_27A26,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzAsstBlocks,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo32_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #$B,y_radius(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  subtype(a0),d0
    andi.w  #$7F,d0
    lsl.w   #3,d0
    move.w  d0,objoff_36(a0)
; loc_278DC:
Obj69_Main:
    lea (MainCharacter).w,a1 ; a1=character
    lea objoff_38(a0),a4
    moveq   #p1_standing_bit,d6
    bsr.s   Obj69_Action
    lea (Sidekick).w,a1 ; a1=character
    lea objoff_3C(a0),a4
    moveq   #p2_standing_bit,d6
    bsr.s   Obj69_Action
 
loc_278F4:
 
    andi.w  #$7FF,y_pos(a0)
    move.w  #$2B,d1
    move.w  #$C,d2
    move.w  #$D,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo12_SolidObject
    jmpto   (MarkObjGone).l, JmpTo21_MarkObjGone
; ===========================================================================
; loc_27912:
Obj69_Action:
    btst    d6,status(a0)
    bne.s   +
    clr.b   (a4)
+
    moveq   #0,d0
    move.b  (a4),d0
    move.w  Obj69_Modes(pc,d0.w),d0
    jmp Obj69_Modes(pc,d0.w)
; ===========================================================================
; off_27926:
Obj69_Modes:    offsetTable
        offsetTableEntry.w loc_2792C    ; 0
        offsetTableEntry.w loc_2794C    ; 2
        offsetTableEntry.w loc_2796E    ; 4
; ===========================================================================
 
loc_2792C:
    btst    d6,status(a0)
    bne.s   +
    rts
; ===========================================================================
+
    addq.b  #2,(a4)
    move.b  #0,1(a4)
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   loc_2794C
    move.b  #1,1(a4)
 
loc_2794C:
 
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    tst.b   1(a4)
    beq.s   +
    addi.w  #$F,d0
+
    cmpi.w  #$10,d0
    bhs.s   +   ; rts
    move.w  x_pos(a0),x_pos(a1)
    addq.b  #2,(a4)
+
    rts
; ===========================================================================
 
loc_2796E:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    bcc.s   loc_279D4
    add.w   d0,objoff_34(a0)
    move.w  x_pos(a0),x_pos(a1)
    move.w  objoff_34(a0),d0
    asr.w   #3,d0
    move.w  d0,d1
    asr.w   #1,d0
    andi.w  #3,d0
    move.b  d0,mapping_frame(a0)
    neg.w   d1
    add.w   objoff_32(a0),d1
    move.w  d1,y_pos(a0)
    sub.w   objoff_32(a0),d1
    move.w  objoff_36(a0),d0
    cmp.w   d0,d1
    blt.s   return_279D2
    move.w  d0,d1
    add.w   objoff_32(a0),d1
    move.w  d1,y_pos(a0)
    lsl.w   #3,d0
    neg.w   d0
    move.w  d0,objoff_34(a0)
    move.b  #0,mapping_frame(a0)
    tst.b   subtype(a0)
    bmi.s   loc_279CC
    clr.b   (a4)
    rts
; ===========================================================================
 
loc_279CC:
    move.b  #4,routine(a0)
 
return_279D2:
    rts
; ===========================================================================
 
loc_279D4:
    add.w   d0,objoff_34(a0)
    move.w  x_pos(a0),x_pos(a1)
    move.w  objoff_34(a0),d0
    asr.w   #3,d0
    move.w  d0,d1
    asr.w   #1,d0
    andi.w  #3,d0
    move.b  d0,mapping_frame(a0)
    neg.w   d1
    add.w   objoff_32(a0),d1
    move.w  d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_279FC:
    jsrto   (ObjectMove).l, JmpTo13_ObjectMove
    addi.w  #$38,y_vel(a0)
    jsrto   (ObjCheckFloorDist).l, JmpTo_ObjCheckFloorDist
    tst.w   d1
    bpl.w   +
    add.w   d1,y_pos(a0)
    andi.w  #$7FF,y_pos(a0)
    clr.w   y_vel(a0)
    addq.b  #2,routine(a0)
+
    bra.w   loc_278F4
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj69_MapUnc_27A26: BINCLUDE "mappings/sprite/obj69.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo21_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo_ObjCheckFloorDist 
    jmp (ObjCheckFloorDist).l
JmpTo32_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo12_SolidObject 
    jmp (SolidObject).l
; loc_27AA8:
JmpTo13_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6A - Platform that moves when you walk off of it, from MTZ
; ----------------------------------------------------------------------------
; Sprite_27AB0:
Obj6A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj6A_Index(pc,d0.w),d1
    jmp Obj6A_Index(pc,d1.w)
; ===========================================================================
; off_27ABE:
Obj6A_Index:    offsetTable
        offsetTableEntry.w Obj6A_Init   ; 0
        offsetTableEntry.w loc_27BDE    ; 2
        offsetTableEntry.w loc_27C66    ; 4
; ===========================================================================
; loc_27AC4:
Obj6A_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj65_Obj6A_Obj6B_MapUnc_26EC8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #$C,y_radius(a0)
    move.l  #byte_27CDC,objoff_2C(a0)
    move.b  #1,mapping_frame(a0)
    cmpi.b  #mystic_cave_zone,(Current_Zone).w
    bne.w   loc_27BC4
    addq.b  #2,routine(a0)
    move.l  #Obj6A_MapUnc_27D30,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Crate,3,0),art_tile(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #$20,y_radius(a0)
    move.l  #byte_27CF4,objoff_2C(a0)
    btst    #0,status(a0)
    beq.s   +
    move.l  #byte_27D12,objoff_2C(a0)
+
    move.b  #0,mapping_frame(a0)
    cmpi.b  #$18,subtype(a0)
    bne.w   loc_27BD0
    jsrto   (SingleObjLoad2).l, JmpTo13_SingleObjLoad2
    bne.s   ++
    bsr.s   Obj6A_InitSubObject
    addi.w  #$40,x_pos(a1)
    addi.w  #$40,y_pos(a1)
    move.b  #6,subtype(a1)
    btst    #0,status(a0)
    beq.s   +
    move.b  #$C,subtype(a1)
+
    jsrto   (SingleObjLoad2).l, JmpTo13_SingleObjLoad2
    bne.s   +
    bsr.s   Obj6A_InitSubObject
    subi.w  #$40,x_pos(a1)
    addi.w  #$40,y_pos(a1)
    move.b  #$C,subtype(a1)
    btst    #0,status(a0)
    beq.s   +
    move.b  #6,subtype(a1)
+
    bra.s   loc_27BC4
; ===========================================================================
; loc_27B9E:
Obj6A_InitSubObject:
    _move.b id(a0),id(a1) ; load obj6A
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  x_pos(a0),objoff_32(a1)
    move.w  y_pos(a0),objoff_30(a1)
    move.b  status(a0),status(a1)
    rts
; ===========================================================================
 
loc_27BC4:
    move.w  x_pos(a0),objoff_32(a0)
    move.w  y_pos(a0),objoff_30(a0)
 
loc_27BD0:
    jsrto   (Adjust2PArtPointer).l, JmpTo33_Adjust2PArtPointer
    move.b  subtype(a0),objoff_38(a0)
    bra.w   loc_27CA2
; ===========================================================================
 
loc_27BDE:
    move.w  x_pos(a0),-(sp)
    tst.w   objoff_36(a0)
    bne.s   loc_27C2E
    move.b  objoff_3C(a0),d1
    move.b  status(a0),d0
    btst    #p1_standing_bit,d0
    bne.s   loc_27C0A
    btst    #p1_standing_bit,d1
    beq.s   loc_27C0E
    move.b  #1,objoff_36(a0)
    move.b  #0,objoff_3C(a0)
    bra.s   loc_27C3E
; ===========================================================================
 
loc_27C0A:
    move.b  d0,objoff_3C(a0)
 
loc_27C0E:
    btst    #p2_standing_bit,d0
    bne.s   loc_27C28
    btst    #p2_standing_bit,d1
    beq.s   loc_27C3E
    move.b  #1,objoff_36(a0)
    move.b  #0,objoff_3C(a0)
    bra.s   loc_27C3E
; ===========================================================================
 
loc_27C28:
    move.b  d0,objoff_3C(a0)
    bra.s   loc_27C3E
; ===========================================================================
loc_27C2E:
    jsr (ObjectMove).l
    subq.w  #1,objoff_34(a0)
    bne.s   loc_27C3E
    bsr.w   loc_27CA2
 
loc_27C3E:
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   loc_27C5E
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo13_SolidObject
 
loc_27C5E:
    move.w  objoff_32(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo3_MarkObjGone2
; ===========================================================================
 
loc_27C66:
    move.w  x_pos(a0),-(sp)
    jsr (ObjectMove).l
    subq.w  #1,objoff_34(a0)
    bne.s   loc_27C7A
    bsr.w   loc_27CA2
 
loc_27C7A:
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   loc_27C9A
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo13_SolidObject
 
loc_27C9A:
    move.w  objoff_32(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo3_MarkObjGone2
; ===========================================================================
 
loc_27CA2:
    moveq   #0,d0
    move.b  objoff_38(a0),d0
    movea.l objoff_2C(a0),a1 ; a1=object
    lea (a1,d0.w),a1
    move.w  (a1)+,x_vel(a0)
    move.w  (a1)+,y_vel(a0)
    move.w  (a1)+,objoff_34(a0)
    move.w  #7,objoff_3A(a0)
    move.b  #0,objoff_36(a0)
    addq.b  #6,objoff_38(a0)
    cmpi.b  #$18,objoff_38(a0)
    blo.s   return_27CDA
    move.b  #0,objoff_38(a0)
 
return_27CDA:
    rts
; ===========================================================================
byte_27CDC:
    dc.b   0,  0,  4,  0,  0,$10,  4,  0,$FE,  0,  0,$20,  0,  0,  4,  0
    dc.b   0,$10,$FC,  0,$FE,  0,  0,$20; 16
byte_27CF4:
    dc.b   0,  0,  1,  0,  0,$40,$FF,  0,  0,  0,  0,$80,  0,  0,$FF,  0
    dc.b   0,$40,  1,  0,  0,  0,  0,$80,  1,  0,  0,  0,  0,$40; 16
byte_27D12:
    dc.b   0,  0,  1,  0,  0,$40,  1,  0,  0,  0,  0,$80,  0,  0,$FF,  0
    dc.b   0,$40,$FF,  0,  0,  0,  0,$80,$FF,  0,  0,  0,  0,$40; 16
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj6A_MapUnc_27D30: BINCLUDE "mappings/sprite/obj6A.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo13_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo33_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo13_SolidObject 
    jmp (SolidObject).l
JmpTo3_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6B - Immobile platform from MTZ
; ----------------------------------------------------------------------------
; Sprite_27D6C:
Obj6B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj6B_Index(pc,d0.w),d1
    jmp Obj6B_Index(pc,d1.w)
; ===========================================================================
; off_27D7A:
Obj6B_Index:    offsetTable
        offsetTableEntry.w Obj6B_Init   ; 0
        offsetTableEntry.w Obj6B_Main   ; 2
; ===========================================================================
byte_27D7E:
    dc.b $20
    dc.b  $C    ; 1
    dc.b   1    ; 2
    dc.b   0    ; 3
    dc.b $10    ; 4
    dc.b $10    ; 5
    dc.b   0    ; 6
    dc.b   0    ; 7
; ===========================================================================
; loc_27D86:
Obj6B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj65_Obj6A_Obj6B_MapUnc_26EC8,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj6B_MapUnc_2800E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZStairBlock,3,0),art_tile(a0)
+
    jsrto   (Adjust2PArtPointer).l, JmpTo34_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #2,d0
    andi.w  #$1C,d0
    lea byte_27D7E(pc,d0.w),a2
    move.b  (a2)+,width_pixels(a0)
    move.b  (a2)+,y_radius(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    move.b  status(a0),objoff_2E(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    subq.w  #8,d0
    bcs.s   Obj6B_Main
    lsl.w   #2,d0
    lea (Oscillating_Data+$2A).w,a2
    lea (a2,d0.w),a2
    tst.w   (a2)
    bpl.s   Obj6B_Main
    bchg    #0,objoff_2E(a0)
; loc_27E0E:
Obj6B_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    add.w   d0,d0
    move.w  Obj6B_Types(pc,d0.w),d1
    jsr Obj6B_Types(pc,d1.w)
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   +
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo14_SolidObject
+
    move.w  objoff_34(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo4_MarkObjGone2
; ===========================================================================
; off_27E4E:
Obj6B_Types:    offsetTable
        offsetTableEntry.w Obj6B_Type_Immobile  ;  0
        offsetTableEntry.w loc_27E68        ;  1
        offsetTableEntry.w loc_27E74        ;  2
        offsetTableEntry.w loc_27E96        ;  3
        offsetTableEntry.w loc_27EA2        ;  4
        offsetTableEntry.w loc_27EC4        ;  5
        offsetTableEntry.w loc_27EE2        ;  6
        offsetTableEntry.w loc_27F10        ;  7
        offsetTableEntry.w loc_27F4E        ;  8
        offsetTableEntry.w loc_27F60        ;  9
        offsetTableEntry.w loc_27F70        ; $A
        offsetTableEntry.w loc_27F80        ; $B
; ===========================================================================
; return_27E66:
Obj6B_Type_Immobile:
    rts
; ===========================================================================
 
loc_27E68:
    move.w  #$40,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+8).w,d0
    bra.s   +
; ===========================================================================
 
loc_27E74:
    move.w  #$80,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$1C).w,d0
+
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
    add.w   d1,d0
+
    move.w  objoff_34(a0),d1
    sub.w   d0,d1
    move.w  d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_27E96:
    move.w  #$40,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+8).w,d0
    bra.s   loc_27EAC
; ===========================================================================
 
loc_27EA2:
    move.w  #$80,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$1C).w,d0
 
loc_27EAC:
    btst    #0,status(a0)
    beq.s   loc_27EB8
    neg.w   d0
    add.w   d1,d0
 
loc_27EB8:
    move.w  objoff_30(a0),d1
    sub.w   d0,d1
    move.w  d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_27EC4:
    move.b  (Oscillating_Data).w,d0
    lsr.w   #1,d0
    add.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
    move.b  status(a0),d1
    andi.b  #standing_mask,d1
    beq.s   return_27EE0
    addq.b  #1,subtype(a0)
 
return_27EE0:
    rts
; ===========================================================================
 
loc_27EE2:
    move.l  y_pos(a0),d3
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d3,y_pos(a0)
    addi_.w #8,y_vel(a0)
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    bhs.s   return_27F0E
    move.b  #0,subtype(a0)
 
return_27F0E:
    rts
; ===========================================================================
 
loc_27F10:
    tst.b   objoff_38(a0)
    bne.s   loc_27F26
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   return_27F4C
    move.b  #8,objoff_38(a0)
 
loc_27F26:
    jsrto   (ObjectMove).l, JmpTo14_ObjectMove
    andi.w  #$7FF,y_pos(a0)
    cmpi.w  #$2A8,y_vel(a0)
    bne.s   loc_27F3C
    neg.b   objoff_38(a0)
 
loc_27F3C:
    move.b  objoff_38(a0),d1
    ext.w   d1
    add.w   d1,y_vel(a0)
    bne.s   return_27F4C
    clr.b   subtype(a0)
 
return_27F4C:
    rts
; ===========================================================================
 
loc_27F4E:
    move.w  #$10,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$28).w,d0
    lsr.w   #1,d0
    move.w  (Oscillating_Data+$2A).w,d3
    bra.s   loc_27F8E
; ===========================================================================
 
loc_27F60:
    move.w  #$30,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$2C).w,d0
    move.w  (Oscillating_Data+$2E).w,d3
    bra.s   loc_27F8E
; ===========================================================================
 
loc_27F70:
    move.w  #$50,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$30).w,d0
    move.w  (Oscillating_Data+$32).w,d3
    bra.s   loc_27F8E
; ===========================================================================
 
loc_27F80:
    move.w  #$70,d1
    moveq   #0,d0
    move.b  (Oscillating_Data+$34).w,d0
    move.w  (Oscillating_Data+$36).w,d3
 
loc_27F8E:
    tst.w   d3
    bne.s   loc_27F9C
    addq.b  #1,objoff_2E(a0)
    andi.b  #3,objoff_2E(a0)
 
loc_27F9C:
    move.b  objoff_2E(a0),d2
    andi.b  #3,d2
    bne.s   loc_27FBC
    sub.w   d1,d0
    add.w   objoff_34(a0),d0
    move.w  d0,x_pos(a0)
    neg.w   d1
    add.w   objoff_30(a0),d1
    move.w  d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_27FBC:
    subq.b  #1,d2
    bne.s   loc_27FDA
    subq.w  #1,d1
    sub.w   d1,d0
    neg.w   d0
    add.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
    addq.w  #1,d1
    add.w   objoff_34(a0),d1
    move.w  d1,x_pos(a0)
    rts
; ===========================================================================
 
loc_27FDA:
    subq.b  #1,d2
    bne.s   loc_27FF8
    subq.w  #1,d1
    sub.w   d1,d0
    neg.w   d0
    add.w   objoff_34(a0),d0
    move.w  d0,x_pos(a0)
    addq.w  #1,d1
    add.w   objoff_30(a0),d1
    move.w  d1,y_pos(a0)
    rts
; ===========================================================================
 
loc_27FF8:
    sub.w   d1,d0
    add.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
    neg.w   d1
    add.w   objoff_34(a0),d1
    move.w  d1,x_pos(a0)
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj6B_MapUnc_2800E: BINCLUDE "mappings/sprite/obj6B.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo34_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo14_SolidObject 
    jmp (SolidObject).l
JmpTo4_MarkObjGone2 
    jmp (MarkObjGone2).l
; loc_2802E:
JmpTo14_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6C - Small platform on pulleys (like at the start of MTZ2)
; ----------------------------------------------------------------------------
; Sprite_28034:
Obj6C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj6C_Index(pc,d0.w),d1
    jsr Obj6C_Index(pc,d1.w)
    move.w  objoff_30(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   +
    jmpto   (DisplaySprite).l, JmpTo20_DisplaySprite
; ===========================================================================
+   jmpto   (DeleteObject).l, JmpTo34_DeleteObject
; ===========================================================================
; off_2805C:
Obj6C_Index:    offsetTable
        offsetTableEntry.w Obj6C_Init   ; 0
        offsetTableEntry.w Obj6C_Main   ; 2
; ===========================================================================
; loc_28060:
Obj6C_Init:
    move.b  subtype(a0),d0
    bmi.w   loc_28112
    addq.b  #2,routine(a0)
    move.l  #Obj6C_MapUnc_28372,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_LavaCup,3,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo35_Adjust2PArtPointer
    move.b  #0,mapping_frame(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.w  d0,d1
    lsr.w   #3,d0
    andi.w  #$1E,d0
    lea off_28252(pc),a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,objoff_38(a0)
    move.l  a2,objoff_3C(a0)
    andi.w  #$F,d1
    lsl.w   #2,d1
    move.b  d1,objoff_38(a0)
    move.b  #4,objoff_3A(a0)
    btst    #0,status(a0)
    beq.s   loc_280F2
    neg.b   objoff_3A(a0)
    moveq   #0,d1
    move.b  objoff_38(a0),d1
    add.b   objoff_3A(a0),d1
    cmp.b   objoff_39(a0),d1
    blo.s   loc_280EE
    move.b  d1,d0
    moveq   #0,d1
    tst.b   d0
    bpl.s   loc_280EE
    move.b  objoff_39(a0),d1
    subq.b  #4,d1
 
loc_280EE:
    move.b  d1,objoff_38(a0)
 
loc_280F2:
    move.w  (a2,d1.w),d0
    add.w   objoff_30(a0),d0
    move.w  d0,objoff_34(a0)
    move.w  2(a2,d1.w),d0
    add.w   objoff_32(a0),d0
    move.w  d0,objoff_36(a0)
    bsr.w   loc_281DA
    bra.w   Obj6C_Main
; ===========================================================================
 
loc_28112:
    andi.w  #$7F,d0
    add.w   d0,d0
    lea (off_282D6).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d1
    movea.l a0,a1
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    bra.s   Obj6C_LoadSubObject
; ===========================================================================
; loc_28130:
Obj6C_SubObjectsLoop:
    jsrto   (SingleObjLoad).l, JmpTo8_SingleObjLoad
    bne.s   +
; loc_28136:
Obj6C_LoadSubObject:
    _move.b #ObjID_Conveyor,id(a1) ; load obj6C
    move.w  (a2)+,d0
    add.w   d2,d0
    move.w  d0,x_pos(a1)
    move.w  (a2)+,d0
    add.w   d3,d0
    move.w  d0,y_pos(a1)
    move.w  d2,objoff_30(a1)
    move.w  d3,objoff_32(a1)
    move.w  (a2)+,d0
    move.b  d0,subtype(a1)
    move.b  status(a0),status(a1)
+
    dbf d1,Obj6C_SubObjectsLoop
    addq.l  #4,sp
    rts
; ===========================================================================
; loc_28168:
Obj6C_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   loc_2817E
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    moveq   #8,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo5_PlatformObject
; ===========================================================================
 
loc_2817E:
    move.w  x_pos(a0),d0
    cmp.w   objoff_34(a0),d0
    bne.s   loc_281D4
    move.w  y_pos(a0),d0
    cmp.w   objoff_36(a0),d0
    bne.s   loc_281D4
    moveq   #0,d1
    move.b  objoff_38(a0),d1
    add.b   objoff_3A(a0),d1
    cmp.b   objoff_39(a0),d1
    blo.s   loc_281B0
    move.b  d1,d0
    moveq   #0,d1
    tst.b   d0
    bpl.s   loc_281B0
    move.b  objoff_39(a0),d1
    subq.b  #4,d1
 
loc_281B0:
    move.b  d1,objoff_38(a0)
    movea.l objoff_3C(a0),a1 ; a1=object
    move.w  (a1,d1.w),d0
    add.w   objoff_30(a0),d0
    move.w  d0,objoff_34(a0)
    move.w  2(a1,d1.w),d0
    add.w   objoff_32(a0),d0
    move.w  d0,objoff_36(a0)
    bsr.w   loc_281DA
 
loc_281D4:
    jsrto   (ObjectMove).l, JmpTo15_ObjectMove
    rts
; ===========================================================================
 
loc_281DA:
    moveq   #0,d0
    move.w  #-$100,d2
    move.w  x_pos(a0),d0
    sub.w   objoff_34(a0),d0
    bcc.s   loc_281EE
    neg.w   d0
    neg.w   d2
 
loc_281EE:
    moveq   #0,d1
    move.w  #-$100,d3
    move.w  y_pos(a0),d1
    sub.w   objoff_36(a0),d1
    bcc.s   loc_28202
    neg.w   d1
    neg.w   d3
 
loc_28202:
    cmp.w   d0,d1
    blo.s   loc_2822C
    move.w  x_pos(a0),d0
    sub.w   objoff_34(a0),d0
    beq.s   loc_28218
    ext.l   d0
    asl.l   #8,d0
    divs.w  d1,d0
    neg.w   d0
 
loc_28218:
    move.w  d0,x_vel(a0)
    move.w  d3,y_vel(a0)
    swap    d0
    move.w  d0,x_sub(a0)
    clr.w   y_sub(a0)
    rts
; ===========================================================================
 
loc_2822C:
    move.w  y_pos(a0),d1
    sub.w   objoff_36(a0),d1
    beq.s   loc_2823E
    ext.l   d1
    asl.l   #8,d1
    divs.w  d0,d1
    neg.w   d1
 
loc_2823E:
    move.w  d1,y_vel(a0)
    move.w  d2,x_vel(a0)
    swap    d1
    move.w  d1,y_sub(a0)
    clr.w   x_sub(a0)
    rts
; ===========================================================================
off_28252:  offsetTable
        offsetTableEntry.w byte_28258   ; 0
        offsetTableEntry.w byte_28282   ; 1
        offsetTableEntry.w byte_282AC   ; 2
byte_28258:
    dc.b   0,$28,  0,  0,  0,  0,$FF,$EA,  0, $A,$FF,$E0,  0,$20,$FF,$E0
    dc.b   0,$E0,$FF,$EA,  0,$F6,  0,  0,  1,  0,  0,$16,  0,$F6,  0,$20; 16
    dc.b   0,$E0,  0,$20,  0,$20,  0,$16,  0, $A; 32
byte_28282:
    dc.b   0,$28,  0,  0,  0,  0,$FF,$EA,  0, $A,$FF,$E0,  0,$20,$FF,$E0
    dc.b   1,$60,$FF,$EA,  1,$76,  0,  0,  1,$80,  0,$16,  1,$76,  0,$20; 16
    dc.b   1,$60,  0,$20,  0,$20,  0,$16,  0, $A; 32
byte_282AC:
    dc.b   0,$28,  0,  0,  0,  0,$FF,$EA,  0, $A,$FF,$E0,  0,$20,$FF,$E0
    dc.b   1,$E0,$FF,$EA,  1,$F6,  0,  0,  2,  0,  0,$16,  1,$F6,  0,$20; 16
    dc.b   1,$E0,  0,$20,  0,$20,  0,$16,  0, $A; 32
; ---------------------------------------------------------------------------
off_282D6:  offsetTable
        offsetTableEntry.w byte_282DC   ; 0
        offsetTableEntry.w byte_2830E   ; 1
        offsetTableEntry.w byte_28340   ; 2
byte_282DC:
    dc.b   0,  7,  0,  0,  0,  0,  0,  1,$FF,$E0,  0,$3A,  0,  3,$FF,$E0
    dc.b   0,$80,  0,  3,$FF,$E0,  0,$C6,  0,  3,  0,  0,  1,  0,  0,  6; 16
    dc.b   0,$20,  0,$C6,  0,  8,  0,$20,  0,$80,  0,  8,  0,$20,  0,$3A; 32
    dc.b   0,  8    ; 48
byte_2830E:
    dc.b   0,  7,  0,  0,  0,  0,  0,$11,$FF,$E0,  0,$5A,  0,$13,$FF,$E0
    dc.b   0,$C0,  0,$13,$FF,$E0,  1,$26,  0,$13,  0,  0,  1,$80,  0,$16; 16
    dc.b   0,$20,  1,$26,  0,$18,  0,$20,  0,$C0,  0,$18,  0,$20,  0,$5A; 32
    dc.b   0,$18    ; 48
byte_28340:
    dc.b   0,  7,  0,  0,  0,  0,  0,$21,$FF,$E0,  0,$7A,  0,$23,$FF,$E0
    dc.b   1,  0,  0,$23,$FF,$E0,  1,$86,  0,$23,  0,  0,  2,  0,  0,$26; 16
    dc.b   0,$20,  1,$86,  0,$28,  0,$20,  1,  0,  0,$28,  0,$20,  0,$7A; 32
    dc.b   0,$28    ; 48
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj6C_MapUnc_28372: BINCLUDE "mappings/sprite/obj6C.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo20_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo34_DeleteObject 
    jmp (DeleteObject).l
JmpTo8_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo35_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo5_PlatformObject 
    jmp (PlatformObject).l
; loc_283A6:
JmpTo15_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 6E - Platform moving in a circle (like at the start of MTZ3)
; ----------------------------------------------------------------------------
; Sprite_283AC:
Obj6E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj6E_Index(pc,d0.w),d1
    jmp Obj6E_Index(pc,d1.w)
; ===========================================================================
; off_283BA:
Obj6E_Index:    offsetTable
        offsetTableEntry.w Obj6E_Init   ; 0
        offsetTableEntry.w loc_28432    ; 2
        offsetTableEntry.w loc_284BC    ; 4
; ===========================================================================
byte_283C0:
    ;    width_pixels
    ;        radius
    dc.b $10, $C
    dc.b $28,  8    ; 2
    dc.b $60,$18    ; 4
    dc.b  $C, $C    ; 6
; ===========================================================================
; loc_283C8:
Obj6E_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj6E_MapUnc_2852C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo36_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$E,d0
    lea byte_283C0(pc,d0.w),a3
    move.b  (a3)+,width_pixels(a0)
    move.b  (a3)+,y_radius(a0)
    lsr.w   #1,d0
    move.b  d0,mapping_frame(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    cmpi.b  #3,d0
    bne.s   loc_28432
    addq.b  #2,routine(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzWheelIndent,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo36_Adjust2PArtPointer
    move.b  #5,priority(a0)
    bra.w   loc_284BC
; ===========================================================================
 
loc_28432:
 
    move.w  x_pos(a0),-(sp)
    move.b  (Oscillating_Data+$20).w,d1
    subi.b  #$38,d1
    ext.w   d1
    move.b  (Oscillating_Data+$24).w,d2
    subi.b  #$38,d2
    ext.w   d2
    btst    #0,subtype(a0)
    beq.s   +
    neg.w   d1
    neg.w   d2
+
    btst    #1,subtype(a0)
    beq.s   +
    neg.w   d1
    exg d1,d2
+
    add.w   objoff_34(a0),d1
    move.w  d1,x_pos(a0)
    add.w   objoff_30(a0),d2
    move.w  d2,y_pos(a0)
    move.w  (sp)+,d4
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo15_SolidObject
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   +
    jmp (DisplaySprite).l
; ===========================================================================
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+ 
    jmp (DeleteObject).l
; ===========================================================================
 
loc_284BC:
 
    move.b  (Oscillating_Data+$20).w,d1
    lsr.b   #1,d1
    subi.b  #$1C,d1
    ext.w   d1
    move.b  (Oscillating_Data+$24).w,d2
    lsr.b   #1,d2
    subi.b  #$1C,d2
    ext.w   d2
    btst    #0,subtype(a0)
    beq.s   +
    neg.w   d1
    neg.w   d2
+
    btst    #1,subtype(a0)
    beq.s   +
    neg.w   d1
    exg d1,d2
+
    add.w   objoff_34(a0),d1
    move.w  d1,x_pos(a0)
    add.w   objoff_30(a0),d2
    move.w  d2,y_pos(a0)
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   +
    jmp (DisplaySprite).l
; ===========================================================================
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    jmp (DeleteObject).l
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj6E_MapUnc_2852C: BINCLUDE "mappings/sprite/obj6E.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo36_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo15_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 70 - Giant rotating cog from MTZ
; ----------------------------------------------------------------------------
; Sprite_285C0:
Obj70:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj70_Index(pc,d0.w),d1
    jmp Obj70_Index(pc,d1.w)
; ===========================================================================
; off_285CE:
Obj70_Index:    offsetTable
        offsetTableEntry.w Obj70_Init   ; 0
        offsetTableEntry.w Obj70_Main   ; 2
; ===========================================================================
; loc_285D2:
Obj70_Init:
    moveq   #7,d1
    moveq   #0,d4
    lea (Obj70_Positions).l,a2
    movea.l a0,a1
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    bset    #7,status(a0)
    bra.s   Obj70_LoadSubObject
; ===========================================================================
; loc_285EE:
Obj70_SubObjectLoop:
    jsrto   (SingleObjLoad2).l, JmpTo14_SingleObjLoad2
    bne.s   +
; loc_285F4:
Obj70_LoadSubObject:
    _move.b id(a0),id(a1) ; load obj70
    addq.b  #2,routine(a1)
    move.l  #Obj70_MapUnc_28786,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MtzWheel,3,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo4_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.w  d2,objoff_32(a1)
    move.w  d3,objoff_30(a1)
    move.b  (a2)+,d0
    ext.w   d0
    add.w   d2,d0
    move.w  d0,x_pos(a1)
    move.b  (a2)+,d0
    ext.w   d0
    add.w   d3,d0
    move.w  d0,y_pos(a1)
    move.b  (a2)+,mapping_frame(a1)
    move.w  d4,objoff_34(a1)
    addq.w  #3,d4
    move.b  status(a0),status(a1)
+
    dbf d1,Obj70_SubObjectLoop
; loc_28652:
Obj70_Main:
    move.w  x_pos(a0),-(sp)
    move.b  (Timer_frames+1).w,d0
    move.b  d0,d1
    andi.w  #$F,d0
    bne.s   loc_286CA
    move.w  objoff_36(a0),d1
    btst    #0,status(a0)
    beq.s   loc_28684
    subi.w  #$18,d1
    bcc.s   loc_286A2
    moveq   #$48,d1
    subq.w  #3,objoff_34(a0)
    bcc.s   loc_286A2
    move.w  #$15,objoff_34(a0)
    bra.s   loc_286A2
; ===========================================================================
 
loc_28684:
    addi.w  #$18,d1
    cmpi.w  #$60,d1
    blo.s   loc_286A2
    moveq   #0,d1
    addq.w  #3,objoff_34(a0)
    cmpi.w  #$18,objoff_34(a0)
    blo.s   loc_286A2
    move.w  #0,objoff_34(a0)
 
loc_286A2:
    move.w  d1,objoff_36(a0)
    add.w   objoff_34(a0),d1
    lea Obj70_Positions(pc,d1.w),a1
    move.b  (a1)+,d0
    ext.w   d0
    add.w   objoff_32(a0),d0
    move.w  d0,x_pos(a0)
    move.b  (a1)+,d0
    ext.w   d0
    add.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
    move.b  (a1)+,mapping_frame(a0)
 
loc_286CA:
    move.b  mapping_frame(a0),d0
    add.w   d0,d0
    andi.w  #$1E,d0
    moveq   #0,d1
    moveq   #0,d2
    move.b  byte_28706(pc,d0.w),d1
    move.b  byte_28706+1(pc,d0.w),d2
    move.w  d2,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo16_SolidObject
    move.w  objoff_32(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   +
    jmp (DisplaySprite).l
; ===========================================================================
+
    jmp (DeleteObject).l
; ===========================================================================
byte_28706:
    dc.b $10,$10    ; 0
    dc.b $10,$10    ; 2
    dc.b $10,$10    ; 4
    dc.b $10,$10    ; 6
    dc.b $10,$10    ; 8
    dc.b $10,$10    ; 10
    dc.b $10,$10    ; 12
    dc.b $10, $C    ; 14
    dc.b $10,  8    ; 16
    dc.b $10, $C    ; 18
    dc.b $10,$10    ; 20
    dc.b $10,$10    ; 22
    dc.b $10,$10    ; 24
    dc.b $10,$10    ; 26
    dc.b $10,$10    ; 28
    dc.b $10,$10    ; 30
; byte_28726:
Obj70_Positions:
    ; initial positions
    ; x_pos, y_pos, mapping_frame
    dc.b   0,$B8,  0
    dc.b $32,$CE,  4
    dc.b $48,  0,  8
    dc.b $32,$32, $C
    dc.b   0,$48,$10
    dc.b $CE,$32,$14
    dc.b $B8,  0,$18
    dc.b $CE,$CE,$1C
 
    dc.b  $D,$B8,  1
    dc.b $3F,$DA,  5
    dc.b $48, $C,  9
    dc.b $27,$3C, $D
    dc.b $F3,$48,$11
    dc.b $C1,$26,$15
    dc.b $B8,$F4,$19
    dc.b $D9,$C4,$1D
 
    dc.b $19,$BC,  2
    dc.b $46,$E9,  6
    dc.b $46,$17, $A
    dc.b $19,$44, $E
    dc.b $E7,$44,$12
    dc.b $BA,$17,$16
    dc.b $BA,$E9,$1A
    dc.b $E7,$BC,$1E
 
    dc.b $27,$C4,  3
    dc.b $48,$F4,  7
    dc.b $3F,$26, $B
    dc.b  $D,$48, $F
    dc.b $D9,$3C,$13
    dc.b $B8, $C,$17
    dc.b $C1,$DA,$1B
    dc.b $F3,$B8,$1F
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj70_MapUnc_28786: BINCLUDE "mappings/sprite/obj70.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo14_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo4_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo16_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 72 - Conveyor belt from CNZ
; ----------------------------------------------------------------------------
; Sprite_2893C:
Obj72:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj72_Index(pc,d0.w),d1
    jmp Obj72_Index(pc,d1.w)
; ===========================================================================
; off_2894A:
Obj72_Index:    offsetTable
        offsetTableEntry.w Obj72_Init   ; 0
        offsetTableEntry.w Obj72_Main   ; 2
; ===========================================================================
; loc_2894E:
Obj72_Init:
    addq.b  #2,routine(a0)
    move.w  #$30,objoff_3C(a0)
    move.b  subtype(a0),d0
    bpl.s   +
    move.w  #$70,objoff_3C(a0)
+
    andi.b  #$7F,d0
    lsl.b   #4,d0
    move.b  d0,objoff_38(a0)
    move.w  #2,objoff_36(a0)
    btst    #0,status(a0)
    beq.s   Obj72_Main
    neg.w   objoff_36(a0)
; loc_28980:
Obj72_Main:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj72_Action
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   Obj72_Action
    jmpto   (MarkObjGone3).l, JmpTo5_MarkObjGone3
; ===========================================================================
; loc_28990:
Obj72_Action:
    moveq   #0,d2
    move.b  objoff_38(a0),d2
    move.w  d2,d3
    add.w   d3,d3
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    add.w   d2,d0
    cmp.w   d3,d0
    bhs.s   +   ; rts
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    move.w  objoff_3C(a0),d0
    add.w   d0,d1
    cmp.w   d0,d1
    bhs.s   +   ; rts
    btst    #1,status(a1)
    bne.s   +   ; rts
    move.w  objoff_36(a0),d0
    add.w   d0,x_pos(a1)
+
    rts
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo5_MarkObjGone3 
    jmp (MarkObjGone3).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 73 - Solid rotating ring thing from Mystic Cave Zone
; (unused, but can be seen in debug mode)
; ----------------------------------------------------------------------------
; Sprite_289D4:
Obj73:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj73_Index(pc,d0.w),d1
    jmp Obj73_Index(pc,d1.w)
; ===========================================================================
; off_289E2:
Obj73_Index:    offsetTable
        offsetTableEntry.w Obj73_Init       ; 0
        offsetTableEntry.w Obj73_Main       ; 2
        offsetTableEntry.w Obj73_SubObject  ; 4
; ===========================================================================
; loc_289E8:
Obj73_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj73_MapUnc_28B9C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo37_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #8,width_pixels(a0)
    move.w  x_pos(a0),objoff_3A(a0)
    move.w  y_pos(a0),objoff_38(a0)
    move.b  #0,collision_flags(a0)
    bset    #7,status(a0)
    move.b  subtype(a0),d1
    andi.b  #$F0,d1
    ext.w   d1
    asl.w   #3,d1
    move.w  d1,objoff_3E(a0)
    move.b  status(a0),d0
    ror.b   #2,d0
    andi.b  #$C0,d0
    move.b  d0,angle(a0)
    lea objoff_29(a0),a2
    move.b  subtype(a0),d1
    andi.w  #7,d1
    move.b  #0,(a2)+
    move.w  d1,d3
    lsl.w   #4,d3
    move.b  d3,objoff_3C(a0)
    subq.w  #1,d1
    bcs.s   Obj73_LoadSubObject_End
    btst    #3,subtype(a0)
    beq.s   Obj73_LoadSubObject
    subq.w  #1,d1
    bcs.s   Obj73_LoadSubObject_End
; loc_28A6E:
Obj73_LoadSubObject:
    jsrto   (SingleObjLoad).l, JmpTo9_SingleObjLoad
    bne.s   Obj73_LoadSubObject_End
    addq.b  #1,objoff_29(a0)
    move.w  a1,d5
    subi.w  #Object_RAM,d5
    if object_size=$40
    lsr.w   #6,d5
    else
    divu.w  #object_size,d5
    endif
    andi.w  #$7F,d5
    move.b  d5,(a2)+
    move.b  #4,routine(a1)
    _move.b id(a0),id(a1) ; load obj73
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  priority(a0),priority(a1)
    move.b  width_pixels(a0),width_pixels(a1)
    move.b  collision_flags(a0),collision_flags(a1)
    move.b  status(a0),status(a1)
    subi.b  #$10,d3
    move.b  d3,objoff_3C(a1)
    dbf d1,Obj73_LoadSubObject
; loc_28AC8:
Obj73_LoadSubObject_End:
 
    move.w  a0,d5
    subi.w  #Object_RAM,d5
    if object_size=$40
    lsr.w   #6,d5
    else
    divu.w  #object_size,d5
    endif
    andi.w  #$7F,d5
    move.b  d5,(a2)+
; loc_28AD6:
Obj73_Main:
    move.w  x_pos(a0),-(sp)
    bsr.w   loc_28AF4
    move.w  #8,d1
    move.w  #8,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo17_SolidObject
    bra.w   loc_28B46
; ===========================================================================
 
loc_28AF4:
    move.w  objoff_3E(a0),d0
    add.w   d0,angle(a0)
    move.b  angle(a0),d0
    jsr (CalcSine).l
    move.w  objoff_38(a0),d2
    move.w  objoff_3A(a0),d3
    lea objoff_29(a0),a2
    moveq   #0,d6
    move.b  (a2)+,d6
 
loc_28B16:
    moveq   #0,d4
    move.b  (a2)+,d4
    if object_size=$40
    lsl.w   #6,d4
    else
    mulu.w  #object_size,d4
    endif
    addi.l  #Object_RAM,d4
    movea.l d4,a1 ; a1=object
    moveq   #0,d4
    move.b  objoff_3C(a1),d4
    move.l  d4,d5
    muls.w  d0,d4
    asr.l   #8,d4
    muls.w  d1,d5
    asr.l   #8,d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d4,y_pos(a1)
    move.w  d5,x_pos(a1)
    dbf d6,loc_28B16
    rts
; ===========================================================================
 
loc_28B46:
    move.w  objoff_3A(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   +
    jmpto   (DisplaySprite).l, JmpTo21_DisplaySprite
; ===========================================================================
+
    moveq   #0,d2
    lea objoff_29(a0),a2
 
    move.b  (a2)+,d2
-   moveq   #0,d0
    move.b  (a2)+,d0
    if object_size=$40
    lsl.w   #6,d0
    else
    mulu.w  #object_size,d0
    endif
    addi.l  #Object_RAM,d0
    movea.l d0,a1   ; a1=object
    jsrto   (DeleteObject2).l, JmpTo_DeleteObject2
    dbf d2,-
    rts
; ===========================================================================
; loc_28B7E:
Obj73_SubObject:
    move.w  #8,d1
    move.w  #8,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  objoff_36(a0),d4
    jsrto   (SolidObject).l, JmpTo17_SolidObject
    move.w  x_pos(a0),objoff_36(a0)
    jmpto   (DisplaySprite).l, JmpTo21_DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj73_MapUnc_28B9C: BINCLUDE "mappings/sprite/obj73.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo21_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo9_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo37_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo17_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 75 - Brick from MCZ
; ----------------------------------------------------------------------------
; Sprite_28BC8:
Obj75:
    btst    #6,render_flags(a0)
    bne.w   +
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj75_Index(pc,d0.w),d1
    jmp Obj75_Index(pc,d1.w)
; ===========================================================================
+
    move.w  #$280,d0
    jmpto   (DisplaySprite3).l, JmpTo_DisplaySprite3
; ===========================================================================
; off_28BE8:
Obj75_Index:    offsetTable
        offsetTableEntry.w Obj75_Init   ; 0
        offsetTableEntry.w Obj75_Main   ; 2
        offsetTableEntry.w loc_28D6C    ; 4
; ===========================================================================
; loc_28BEE:
Obj75_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj75_MapUnc_28D8A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo38_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #5,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.b  subtype(a0),d1
    move.b  d1,d0
    andi.w  #$F,d1
    andi.b  #$F0,d0
    ext.w   d0
    asl.w   #3,d0
    move.w  d0,objoff_34(a0)
    move.b  status(a0),d0
    ror.b   #2,d0
    andi.b  #$C0,d0
    move.b  d0,angle(a0)
    cmpi.b  #$F,d1
    bne.s   +
    addq.b  #2,routine(a0)
    move.b  #4,priority(a0)
    move.b  #2,mapping_frame(a0)
    rts
; ===========================================================================
+
    move.b  #$9A,collision_flags(a0)
    jsrto   (SingleObjLoad2).l, JmpTo15_SingleObjLoad2
    bne.s   Obj75_Main
    _move.b id(a0),id(a1) ; load obj75
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #$40,mainspr_width(a1)
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    move.b  d1,mainspr_childsprites(a1)
    subq.w  #1,d1
    lea sub2_x_pos(a1),a2
 
-   move.w  d2,(a2)+    ; sub?_x_pos
    move.w  d3,(a2)+    ; sub?_y_pos
    move.w  #1,(a2)+    ; sub?_mapframe
    dbf d1,-
 
    move.w  d2,x_pos(a1)
    move.w  d3,y_pos(a1)
    move.b  #0,mainspr_mapframe(a1)
    move.l  a1,objoff_3C(a0)
    move.b  #$40,mainspr_height(a1)
    bset    #4,render_flags(a1)
; loc_28CCA:
Obj75_Main:
    moveq   #0,d0
    moveq   #0,d1
    move.w  objoff_34(a0),d0
    add.w   d0,angle(a0)
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo8_CalcSine
    move.w  objoff_32(a0),d2
    move.w  objoff_30(a0),d3
    moveq   #0,d6
    movea.l objoff_3C(a0),a1 ; a1=object
    move.b  mainspr_childsprites(a1),d6
    subq.w  #1,d6
    bcs.s   loc_28D3E
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    moveq   #0,d4
    moveq   #0,d5
    lea sub2_x_pos(a1),a2
 
-   movem.l d4-d5,-(sp)
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,(a2)+    ; sub?_x_pos
    move.w  d4,(a2)+    ; sub?_y_pos
    movem.l (sp)+,d4-d5
    add.l   d0,d4
    add.l   d1,d5
    addq.w  #next_subspr-4,a2
    dbf d6,-
 
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,x_pos(a0)
    move.w  d4,y_pos(a0)
    move.w  sub6_x_pos(a1),x_pos(a1)
    move.w  sub6_y_pos(a1),y_pos(a1)
 
loc_28D3E:
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite).l, JmpTo22_DisplaySprite
; ===========================================================================
+
    move.w  objoff_30(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   +
    jmpto   (DisplaySprite).l, JmpTo22_DisplaySprite
; ===========================================================================
+
    movea.l objoff_3C(a0),a1 ; a1=object
    jsrto   (DeleteObject2).l, JmpTo2_DeleteObject2
    jmpto   (DeleteObject).l, JmpTo38_DeleteObject
; ===========================================================================
 
loc_28D6C:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo18_SolidObject
    jmpto   (MarkObjGone).l, JmpTo22_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj75_MapUnc_28D8A: BINCLUDE "mappings/sprite/obj75.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_DisplaySprite3 
    jmp (DisplaySprite3).l
JmpTo22_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo38_DeleteObject 
    jmp (DeleteObject).l
JmpTo22_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo2_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo15_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo38_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo8_CalcSine 
    jmp (CalcSine).l
JmpTo18_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 76 - Spike block that slides out of the wall from MCZ
; ----------------------------------------------------------------------------
sliding_spikes_remaining_movement = objoff_36
; Sprite_28DF8:
Obj76:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj76_Index(pc,d0.w),d1
    jmp Obj76_Index(pc,d1.w)
; ===========================================================================
; off_28E06:
Obj76_Index:    offsetTable
        offsetTableEntry.w Obj76_Init   ; 0
        offsetTableEntry.w Obj76_Main   ; 2
; ===========================================================================
; byte_28E0A:
Obj76_InitData:
    dc.b $40    ; width_pixels
    dc.b $10    ; y_radius
    dc.b   0    ; mapping_frame
    even
; ===========================================================================
; loc_28E0E:
Obj76_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj76_MapUnc_28F3A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo39_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0  ; this is always 0 in the original layouts...
    lsr.w   #2,d0
    andi.w  #$1C,d0
    lea Obj76_InitData(pc,d0.w),a2
    move.b  (a2)+,width_pixels(a0)
    move.b  (a2)+,y_radius(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    andi.w  #$F,subtype(a0)
; loc_28E5E:
Obj76_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.w  Obj76_Modes(pc,d0.w),d1
    jsr Obj76_Modes(pc,d1.w)
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   loc_28EC2
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo19_SolidObject
    swap    d6
    andi.w  #touch_side_mask,d6
    beq.s   loc_28EC2
    move.b  d6,d0
    andi.b  #p1_touch_side,d0
    beq.s   +
    lea (MainCharacter).w,a1 ; a1=character
    jsrto   (Touch_ChkHurt2).l, JmpTo_Touch_ChkHurt2
    bclr    #p1_pushing_bit,status(a0)
+
    andi.b  #p2_touch_side,d6
    beq.s   loc_28EC2
    lea (Sidekick).w,a1 ; a1=character
    jsrto   (Touch_ChkHurt2).l, JmpTo_Touch_ChkHurt2
    bclr    #p2_pushing_bit,status(a0)
 
loc_28EC2:
    move.w  objoff_34(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo5_MarkObjGone2
; ===========================================================================
; off_28ECA:
Obj76_Modes:    offsetTable
        offsetTableEntry.w Obj76_CheckPlayers   ; 0
        offsetTableEntry.w Obj76_SlideOut   ; 2
; ===========================================================================
; loc_28ECE:
Obj76_CheckPlayers:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj76_CheckPlayer
    lea (Sidekick).w,a1 ; a1=character
; loc_28ED8:
Obj76_CheckPlayer:
    btst    #1,status(a1)
    bne.s   ++  ; rts
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$C0,d0
    btst    #0,status(a0)
    beq.s   +
    subi.w  #$100,d0
+
    cmpi.w  #$80,d0
    bhs.s   +   ; rts
    move.w  y_pos(a1),d0
    sub.w   y_pos(a0),d0
    addi.w  #$10,d0
    cmpi.w  #$20,d0
    bhs.s   +   ; rts
    move.b  #2,subtype(a0)
    move.w  #$80,sliding_spikes_remaining_movement(a0)
+   rts
; ===========================================================================
; loc_28F1E:
Obj76_SlideOut:
    tst.w   sliding_spikes_remaining_movement(a0)
    beq.s   ++  ; rts
    subq.w  #1,sliding_spikes_remaining_movement(a0)
    moveq   #-1,d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
+   add.w   d0,x_pos(a0)
+   rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj76_MapUnc_28F3A: BINCLUDE "mappings/sprite/obj76.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_Touch_ChkHurt2 
    jmp (Touch_ChkHurt2).l
JmpTo39_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo19_SolidObject 
    jmp (SolidObject).l
JmpTo5_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 77 - Bridge from MCZ
; ----------------------------------------------------------------------------
; Sprite_28F88:
Obj77:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj77_Index(pc,d0.w),d1
    jmp Obj77_Index(pc,d1.w)
; ===========================================================================
; off_28F96:
Obj77_Index:    offsetTable
        offsetTableEntry.w Obj77_Init   ; 0
        offsetTableEntry.w Obj77_Main   ; 2
; ===========================================================================
; loc_28F9A:
Obj77_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj77_MapUnc_29064,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MCZGateLog,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo40_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$80,width_pixels(a0)
; loc_28FBC:
Obj77_Main:
    tst.b   objoff_34(a0)
    bne.s   +
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  subtype(a0),d0
    btst    #0,(a2,d0.w)
    beq.s   +
    move.b  #1,objoff_34(a0)
    bchg    #0,anim(a0)
    tst.b   render_flags(a0)
    bpl.s   +
    move.w  #SndID_DoorSlam,d0
    jsr (PlaySound).l
+
    lea (Ani_obj77).l,a1
    jsr (AnimateSprite).l
    tst.b   mapping_frame(a0)
    bne.s   Obj77_DropCharacters
    move.w  #$4B,d1
    move.w  #8,d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo20_SolidObject
    jmpto   (MarkObjGone).l, JmpTo23_MarkObjGone
; ===========================================================================
 
; Check if the characters are standing on it. If a character is standing on the
; bridge, the "standing on object" flag is cleared so that it falls.
 
; loc_2901A:
Obj77_DropCharacters:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   +++
    move.b  d0,d1
    andi.b  #p1_standing,d0
    beq.s   +
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #3,status(a1)
+
    andi.b  #p2_standing,d1
    beq.s   +
    lea (Sidekick).w,a1 ; a1=character
    bclr    #3,status(a1)
+
    andi.b  #~standing_mask,status(a0)
+
    jmpto   (MarkObjGone).l, JmpTo23_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; animation script
; ----------------------------------------------------------------------------
; off_29050:
Ani_obj77:  offsetTable
        offsetTableEntry.w Ani_obj77_Close  ; 0
        offsetTableEntry.w Ani_obj77_Open   ; 1
; byte_29054:
Ani_obj77_Close:
    dc.b   3,  4,  3,  2,  1,  0,$FE,  1
; byte_2905C:
Ani_obj77_Open:
    dc.b   3,  0,  1,  2,  3,  4,$FE,  1
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj77_MapUnc_29064: BINCLUDE "mappings/sprite/obj77.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo23_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo40_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo20_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 78 - Stairs from CPZ that move down to open the way
; ----------------------------------------------------------------------------
; Sprite_291CC:
Obj78:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj78_Index(pc,d0.w),d1
    jsr Obj78_Index(pc,d1.w)
    move.w  objoff_30(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo6_MarkObjGone2
; ===========================================================================
; off_291E2:
Obj78_Index:    offsetTable
        offsetTableEntry.w Obj78_Init   ; 0
        offsetTableEntry.w Obj78_Main   ; 2
        offsetTableEntry.w loc_29280    ; 4
; ===========================================================================
; loc_291E8:
Obj78_Init:
    addq.b  #2,routine(a0)
    moveq   #objoff_34,d3
    moveq   #2,d4
    btst    #0,status(a0)
    beq.s   +
    moveq   #objoff_3A,d3
    moveq   #-2,d4
+
    move.w  x_pos(a0),d2
    movea.l a0,a1
    moveq   #3,d1
    bra.s   Obj78_LoadSubObject
; ===========================================================================
; loc_29206:
Obj78_SubObjectLoop:
    jsrto   (SingleObjLoad2).l, JmpTo16_SingleObjLoad2
    bne.w   Obj78_Main
    move.b  #4,routine(a1)
; loc_29214:
Obj78_LoadSubObject:
    _move.b id(a0),id(a1) ; load obj78
    move.l  #Obj6B_MapUnc_2800E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZStairBlock,3,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo5_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.b  subtype(a0),subtype(a1)
    move.w  d2,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  x_pos(a0),objoff_30(a1)
    move.w  y_pos(a1),objoff_32(a1)
    addi.w  #$20,d2
    move.b  d3,objoff_2F(a1)
    move.l  a0,objoff_3C(a1)
    add.b   d4,d3
    dbf d1,Obj78_SubObjectLoop
 
; loc_2926C:
Obj78_Main:
    moveq   #0,d0
    move.b  subtype(a0),d0
    andi.w  #7,d0
    add.w   d0,d0
    move.w  Obj78_Types(pc,d0.w),d1
    jsr Obj78_Types(pc,d1.w)
 
loc_29280:
    movea.l objoff_3C(a0),a2 ; a2=object
    moveq   #0,d0
    move.b  objoff_2F(a0),d0
    move.w  (a2,d0.w),d0
    add.w   objoff_32(a0),d0
    move.w  d0,y_pos(a0)
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo21_SolidObject
    swap    d6
    or.b    d6,objoff_2E(a2)
    rts
; ===========================================================================
; off_292B8:
Obj78_Types:    offsetTable
        offsetTableEntry.w loc_292C8    ; 0
        offsetTableEntry.w loc_29334    ; 1
        offsetTableEntry.w loc_292EC    ; 2
        offsetTableEntry.w loc_29334    ; 3
        offsetTableEntry.w loc_292C8    ; 4
        offsetTableEntry.w loc_2935E    ; 5
        offsetTableEntry.w loc_292EC    ; 6
        offsetTableEntry.w loc_2935E    ; 7
; ===========================================================================
 
loc_292C8:
    tst.w   objoff_2C(a0)
    bne.s   loc_292E0
    move.b  objoff_2E(a0),d0
    andi.b  #touch_top_mask,d0
    beq.s   return_292DE
    move.w  #$1E,objoff_2C(a0)
 
return_292DE:
    rts
; ===========================================================================
 
loc_292E0:
    subq.w  #1,objoff_2C(a0)
    bne.s   return_292DE
    addq.b  #1,subtype(a0)
    rts
; ===========================================================================
 
loc_292EC:
    tst.w   objoff_2C(a0)
    bne.s   loc_29304
    move.b  objoff_2E(a0),d0
    andi.b  #touch_bottom_mask,d0
    beq.s   return_29302
    move.w  #$3C,objoff_2C(a0)
 
return_29302:
    rts
; ===========================================================================
 
loc_29304:
    subq.w  #1,objoff_2C(a0)
    bne.s   loc_29310
    addq.b  #1,subtype(a0)
    rts
; ===========================================================================
 
loc_29310:
    lea objoff_34(a0),a1 ; a1=object
    move.w  objoff_2C(a0),d0
    lsr.b   #2,d0
    andi.b  #1,d0
    move.w  d0,(a1)+
    eori.b  #1,d0
    move.w  d0,(a1)+
    eori.b  #1,d0
    move.w  d0,(a1)+
    eori.b  #1,d0
    move.w  d0,(a1)+
    rts
; ===========================================================================
 
loc_29334:
    lea objoff_34(a0),a1 ; a1=object
    cmpi.w  #$80,(a1)
    beq.s   return_2935C
    addq.w  #1,(a1)
    moveq   #0,d1
    move.w  (a1)+,d1
    swap    d1
    lsr.l   #1,d1
    move.l  d1,d2
    lsr.l   #1,d1
    move.l  d1,d3
    add.l   d2,d3
    swap    d1
    swap    d2
    swap    d3
    move.w  d3,(a1)+
    move.w  d2,(a1)+
    move.w  d1,(a1)+
 
return_2935C:
    rts
; ===========================================================================
 
loc_2935E:
    lea objoff_34(a0),a1 ; a1=object
    cmpi.w  #-$80,(a1)
    beq.s   return_29386
    subq.w  #1,(a1)
    moveq   #0,d1
    move.w  (a1)+,d1
    swap    d1
    asr.l   #1,d1
    move.l  d1,d2
    asr.l   #1,d1
    move.l  d1,d3
    add.l   d2,d3
    swap    d1
    swap    d2
    swap    d3
    move.w  d3,(a1)+
    move.w  d2,(a1)+
    move.w  d1,(a1)+
 
return_29386:
    rts
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo16_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo5_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo21_SolidObject 
    jmp (SolidObject).l
JmpTo6_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7A - Platform that moves back and forth on top of water in CPZ
; ----------------------------------------------------------------------------
; Sprite_293A0:
Obj7A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7A_Index(pc,d0.w),d1
    jmp Obj7A_Index(pc,d1.w)
; ===========================================================================
; off_293AE:
Obj7A_Index:    offsetTable
        offsetTableEntry.w Obj7A_Init       ; 0
        offsetTableEntry.w Obj7A_Main       ; 2
        offsetTableEntry.w Obj7A_SubObject  ; 4
; ===========================================================================
byte_293B4:
    dc.b   0
    dc.b $68    ; 1
    dc.b $FF    ; 2
    dc.b $98    ; 3
    dc.b   0    ; 4
    dc.b   0    ; 5
    dc.b   1    ; 6
    dc.b $A8    ; 7
    dc.b $FF    ; 8
    dc.b $50    ; 9
    dc.b   0    ; 10
    dc.b $40    ; 11
    dc.b   1    ; 12
    dc.b $E8    ; 13
    dc.b $FF    ; 14
    dc.b $80    ; 15
    dc.b   0    ; 16
    dc.b $80    ; 17
    dc.b   0    ; 18
    dc.b $68    ; 19
    dc.b   0    ; 20
    dc.b $67    ; 21
    dc.b   0    ; 22
    dc.b   0    ; 23
; ===========================================================================
; loc_293CC:
Obj7A_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj7A_MapUnc_29564,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZStairBlock,3,1),art_tile(a0)
    cmpi.b  #mystic_cave_zone,(Current_Zone).w
    bne.s   +
    move.l  #Obj15_Obj7A_MapUnc_10256,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
+
    jsrto   (Adjust2PArtPointer).l, JmpTo41_Adjust2PArtPointer
    moveq   #0,d1
    move.b  subtype(a0),d1
    lea byte_293B4(pc,d1.w),a2
    move.b  (a2)+,d1
    movea.l a0,a1
    bra.s   Obj7A_LoadSubObject
; ===========================================================================
; loc_29408:
Obj7A_SubObjectLoop:
    jsrto   (SingleObjLoad2).l, JmpTo17_SingleObjLoad2
    bne.s   Obj7A_SubObjectLoop_End
    _move.b id(a0),id(a1) ; load obj7A
    move.b  #4,routine(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
; loc_29426:
Obj7A_LoadSubObject:
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #$18,width_pixels(a1)
    move.w  x_pos(a1),objoff_30(a1)
; loc_2944A:
Obj7A_SubObjectLoop_End:
    dbf d1,Obj7A_SubObjectLoop
 
    move.l  a0,objoff_3C(a1)
    move.l  a1,objoff_3C(a0)
    cmpi.b  #$C,subtype(a0)
    bne.s   +
    move.b  #1,objoff_36(a0)
+
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  objoff_30(a0),d0
    sub.w   d1,d0
    move.w  d0,objoff_32(a0)
    move.w  d0,objoff_32(a1)
    add.w   d1,d0
    add.w   d1,d0
    move.w  d0,objoff_34(a0)
    move.w  d0,objoff_34(a1)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a0)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a1)
; loc_2948E:
Obj7A_Main:
    bsr.s   loc_294F4
    tst.w   (Two_player_mode).w
    beq.s   +   ; if 2P VS mode is off, branch
    jmpto   (DisplaySprite).l, JmpTo24_DisplaySprite
; ===========================================================================
+
    move.w  objoff_32(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bls.s   +
    move.w  objoff_34(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   loc_294C4
+
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_294C4:
    movea.l objoff_3C(a0),a1 ; a1=object
    cmpa.l  a0,a1
    beq.s   +
    jsr (DeleteObject2).l
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   JmpTo39_DeleteObject
    bclr    #7,2(a2,d0.w)
 
JmpTo39_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; loc_294EA:
Obj7A_SubObject:
    bsr.s   loc_294F4
    bsr.s   loc_2953E
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_294F4:
    move.w  x_pos(a0),-(sp)
    tst.b   objoff_36(a0)
    beq.s   loc_29516
    move.w  x_pos(a0),d0
    subq.w  #1,d0
    cmp.w   objoff_32(a0),d0
    bne.s   +
    move.b  #0,objoff_36(a0)
+
    move.w  d0,x_pos(a0)
    bra.s   loc_2952C
; ===========================================================================
 
loc_29516:
    move.w  x_pos(a0),d0
    addq.w  #1,d0
    cmp.w   objoff_34(a0),d0
    bne.s   +
    move.b  #1,objoff_36(a0)
+
    move.w  d0,x_pos(a0)
 
loc_2952C:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    move.w  #8,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject).l, JmpTo6_PlatformObject
    rts
; ===========================================================================
 
loc_2953E:
    movea.l objoff_3C(a0),a1 ; a1=object
    move.w  x_pos(a0),d0
    subi.w  #$18,d0
    move.w  x_pos(a1),d2
    addi.w  #$18,d2
    cmp.w   d0,d2
    bne.s   +   ; rts
    eori.b  #1,objoff_36(a0)
    eori.b  #1,objoff_36(a1)
+
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj7A_MapUnc_29564: BINCLUDE "mappings/sprite/obj7A.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo24_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo17_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo41_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo6_PlatformObject 
    jmp (PlatformObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7B - Warp pipe exit spring from CPZ
; ----------------------------------------------------------------------------
; Sprite_29590:
Obj7B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7B_Index(pc,d0.w),d1
    jsr Obj7B_Index(pc,d1.w)
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite).l, JmpTo25_DisplaySprite
; ===========================================================================
+
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo40_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo25_DisplaySprite
 
    if removeJmpTos
JmpTo40_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; off_295C0:
Obj7B_Index:    offsetTable
        offsetTableEntry.w Obj7B_Init   ; 0
        offsetTableEntry.w Obj7B_Main   ; 2
; ===========================================================================
; byte_295C4:
Obj7B_Strengths:
    ; Speed applied on Sonic
    dc.w -$1000
    dc.w  -$A80
; ===========================================================================
; loc_295C8:
Obj7B_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj7B_MapUnc_29780,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZTubeSpring,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  subtype(a0),d0
    andi.w  #2,d0
    move.w  Obj7B_Strengths(pc,d0.w),objoff_30(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo42_Adjust2PArtPointer
; loc_295FE:
Obj7B_Main:
    cmpi.b  #1,mapping_frame(a0)
    beq.s   loc_29648
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #$10,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo4_SolidObject_Always_SingleCharacter
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    bsr.w   loc_296C2
+
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo4_SolidObject_Always_SingleCharacter
    btst    #p2_standing_bit,status(a0)
    beq.s   loc_29648
    bsr.s   loc_296C2
 
loc_29648:
    move.w  x_pos(a0),d4
    move.w  d4,d5
    subi.w  #$10,d4
    addi.w  #$10,d5
    move.w  y_pos(a0),d2
    move.w  d2,d3
    addi.w  #$30,d3
    move.w  (MainCharacter+x_pos).w,d0
    cmp.w   d4,d0
    blo.s   loc_29686
    cmp.w   d5,d0
    bhs.s   loc_29686
    move.w  (MainCharacter+y_pos).w,d0
    cmp.w   d2,d0
    blo.s   loc_29686
    cmp.w   d3,d0
    bhs.s   loc_29686
    cmpi.b  #2,next_anim(a0)
    beq.s   loc_29686
    move.b  #2,anim(a0)
 
loc_29686:
    move.w  (Sidekick+x_pos).w,d0
    cmp.w   d4,d0
    blo.s   loc_296B6
    cmp.w   d5,d0
    bhs.s   loc_296B6
    move.w  (Sidekick+y_pos).w,d0
    cmp.w   d2,d0
    blo.s   loc_296B6
    cmp.w   d3,d0
    bhs.s   loc_296B6
    cmpi.w  #4,(Tails_CPU_routine).w    ; TailsCPU_Flying
    beq.w   loc_296B6
    cmpi.b  #3,next_anim(a0)
    beq.s   loc_296B6
    move.b  #3,anim(a0)
 
loc_296B6:
    lea (Ani_obj7B).l,a1
    jmpto   (AnimateSprite).l, JmpTo8_AnimateSprite
; ===========================================================================
    rts
; ===========================================================================
 
loc_296C2:
    move.w  #$100,anim(a0)
    addq.w  #4,y_pos(a1)
    move.w  objoff_30(a0),y_vel(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #AniIDSonAni_Spring,anim(a1)
    move.b  #2,routine(a1)
    move.b  subtype(a0),d0
    bpl.s   +
    move.w  #0,x_vel(a1)
+
    btst    #0,d0
    beq.s   loc_29736
    move.w  #1,inertia(a1)
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #0,flips_remaining(a1)
    move.b  #4,flip_speed(a1)
    btst    #1,d0
    bne.s   +
    move.b  #1,flips_remaining(a1)
+
    btst    #0,status(a1)
    beq.s   loc_29736
    neg.b   flip_angle(a1)
    neg.w   inertia(a1)
 
loc_29736:
    andi.b  #$C,d0
    cmpi.b  #4,d0
    bne.s   +
    move.b  #$C,top_solid_bit(a1)
    move.b  #$D,lrb_solid_bit(a1)
+
    cmpi.b  #8,d0
    bne.s   +
    move.b  #$E,top_solid_bit(a1)
    move.b  #$F,lrb_solid_bit(a1)
+
    move.w  #SndID_Spring,d0
    jmp (PlaySound).l
; ===========================================================================
; animation script
; off_29768:
Ani_obj7B:  offsetTable
        offsetTableEntry.w byte_29770   ; 0
        offsetTableEntry.w byte_29773   ; 1
        offsetTableEntry.w byte_29777   ; 2
        offsetTableEntry.w byte_29777   ; 3
byte_29770: dc.b  $F,  0,$FF
        rev02even
byte_29773: dc.b   0,  3,$FD,  0
        rev02even
byte_29777: dc.b   5,  1,  2,  2,  2,  4,$FD,  0
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj7B_MapUnc_29780: BINCLUDE "mappings/sprite/obj7B.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo25_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo40_DeleteObject 
    jmp (DeleteObject).l
JmpTo8_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo42_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo4_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 7F - Vine switch that you hang off in MCZ
; ----------------------------------------------------------------------------
; Sprite_297E4:
Obj7F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj7F_Index(pc,d0.w),d1
    jmp Obj7F_Index(pc,d1.w)
; ===========================================================================
; off_297F2:
Obj7F_Index:    offsetTable
        offsetTableEntry.w Obj7F_Init   ; 0
        offsetTableEntry.w Obj7F_Main   ; 2
; ===========================================================================
; loc_297F6:
Obj7F_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj7F_MapUnc_29938,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_VineSwitch,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo43_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #8,width_pixels(a0)
    move.b  #4,priority(a0)
; loc_2981E:
Obj7F_Main:
    lea objoff_30(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1).w,d0
    bsr.s   Obj7F_Action
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d0
    bsr.s   Obj7F_Action
    jmpto   (MarkObjGone).l, JmpTo24_MarkObjGone
; ===========================================================================
; loc_2983C:
Obj7F_Action:
    tst.b   (a2)
    beq.s   loc_29890
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   return_29936
    clr.b   obj_control(a1)
    clr.b   (a2)
    move.b  #$12,2(a2)
    andi.w  #(button_up_mask|button_down_mask|button_left_mask|button_right_mask)<<8,d0
    beq.s   +
    move.b  #$3C,2(a2)
+
    move.w  #-$300,y_vel(a1)
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lea (ButtonVine_Trigger).w,a3
    lea (a3,d0.w),a3
    bclr    #0,(a3)
    move.b  #0,mapping_frame(a0)
    tst.w   objoff_30(a0)
    beq.s   +
    move.b  #1,mapping_frame(a0)
+
    bra.w   return_29936
; ===========================================================================
 
loc_29890:
    tst.b   2(a2)
    beq.s   +
    subq.b  #1,2(a2)
    bne.w   return_29936
+
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$C,d0
    cmpi.w  #$18,d0
    bhs.w   return_29936
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    subi.w  #$28,d1
    cmpi.w  #$10,d1
    bhs.w   return_29936
    tst.b   obj_control(a1)
    bmi.s   return_29936
    cmpi.b  #4,routine(a1)
    bhs.s   return_29936
    tst.w   (Debug_placement_mode).w
    bne.s   return_29936
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$30,y_pos(a1)
    move.b  #AniIDSonAni_Hang2,anim(a1)
    move.b  #1,obj_control(a1)
    move.b  #1,(a2)
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lea (ButtonVine_Trigger).w,a3
    bset    #0,(a3,d0.w)
    move.w  #SndID_Blip,d0
    jsr (PlaySound).l
    move.b  #0,mapping_frame(a0)
    tst.w   objoff_30(a0)
    beq.s   return_29936
    move.b  #1,mapping_frame(a0)
 
return_29936:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj7F_MapUnc_29938: BINCLUDE "mappings/sprite/obj7F.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo24_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo43_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 80 - Vine that you hang off and it moves down from MCZ
; ----------------------------------------------------------------------------
; Sprite_2997C:
Obj80:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj80_Index(pc,d0.w),d1
    jmp Obj80_Index(pc,d1.w)
; ===========================================================================
; off_2998A:
Obj80_Index:    offsetTable
        offsetTableEntry.w Obj80_Init       ; 0 - Init
        offsetTableEntry.w Obj80_MCZ_Main   ; 2 - MCZ Vine
        offsetTableEntry.w Obj80_WFZ_Main   ; 4 - WFZ Hook
; ===========================================================================
; loc_29990:
Obj80_Init:
    addq.b  #2,routine(a0)
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.b  #$80,y_radius(a0)
    bset    #4,render_flags(a0)
    move.w  y_pos(a0),objoff_3C(a0)
    cmpi.b  #wing_fortress_zone,(Current_Zone).w
    bne.s   Obj80_MCZ_Init
    addq.b  #2,routine(a0)
    move.l  #Obj80_MapUnc_29DD0,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_WfzHook_Fudge,1,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo44_Adjust2PArtPointer
    move.w  #$A0,objoff_2E(a0)
    move.b  subtype(a0),d0
    move.b  d0,d1
    andi.b  #$F,d0
    beq.s   +
    move.w  #$60,objoff_2E(a0)
+
    move.b  subtype(a0),d0
    move.w  #2,objoff_3A(a0)
    andi.b  #$70,d1
    beq.s   +
    move.w  objoff_2E(a0),d0
    move.w  d0,objoff_38(a0)
    move.b  #1,objoff_36(a0)
    add.w   d0,y_pos(a0)
    lsr.w   #4,d0
    addq.w  #1,d0
    move.b  d0,mapping_frame(a0)
+
    bra.w   Obj80_WFZ_Main
; ===========================================================================
; loc_29A1C:
Obj80_MCZ_Init:
    move.l  #Obj80_MapUnc_29C64,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_VinePulley,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo44_Adjust2PArtPointer
    move.w  #$B0,objoff_2E(a0)
    move.b  subtype(a0),d0
    bpl.s   +
    move.b  #1,objoff_34(a0)
+
    move.w  #2,objoff_3A(a0)
    andi.b  #$70,d0
    beq.s   Obj80_MCZ_Main
    move.w  objoff_2E(a0),d0
    move.w  d0,objoff_38(a0)
    move.b  #1,objoff_36(a0)
    add.w   d0,y_pos(a0)
    lsr.w   #5,d0
    addq.w  #1,d0
    move.b  d0,mapping_frame(a0)
; loc_29A66:
Obj80_MCZ_Main:
    tst.b   objoff_36(a0)
    beq.s   loc_29A74
    tst.w   objoff_30(a0)
    bne.s   loc_29A8A
    bra.s   loc_29A7A
; ===========================================================================
 
loc_29A74:
    tst.w   objoff_30(a0)
    beq.s   loc_29A8A
 
loc_29A7A:
    move.w  objoff_38(a0),d2
    cmp.w   objoff_2E(a0),d2
    beq.s   loc_29AAE
    add.w   objoff_3A(a0),d2
    bra.s   loc_29A94
; ===========================================================================
 
loc_29A8A:
    move.w  objoff_38(a0),d2
    beq.s   loc_29AAE
    sub.w   objoff_3A(a0),d2
 
loc_29A94:
    move.w  d2,objoff_38(a0)
    move.w  objoff_3C(a0),d0
    add.w   d2,d0
    move.w  d0,y_pos(a0)
    move.w  d2,d0
    beq.s   +
    lsr.w   #5,d0
    addq.w  #1,d0
+
    move.b  d0,mapping_frame(a0)
 
loc_29AAE:
    lea objoff_30(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1).w,d0
    bsr.s   Obj80_Action
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d0
    bsr.s   Obj80_Action
    jmpto   (MarkObjGone).l, JmpTo25_MarkObjGone
; ===========================================================================
; loc_29ACC:
Obj80_Action:
    tst.b   (a2)
    beq.w   loc_29B5E
    tst.b   render_flags(a1)
    bpl.s   loc_29B42
    cmpi.b  #4,routine(a1)
    bhs.s   loc_29B42
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   loc_29B50
    clr.b   obj_control(a1)
    clr.b   (a2)
    move.b  #$12,2(a2)
    andi.w  #(button_up_mask|button_down_mask|button_left_mask|button_right_mask)<<8,d0
    beq.w   +
    move.b  #$3C,2(a2)
+
    btst    #(button_left+8),d0
    beq.s   +
    move.w  #-$200,x_vel(a1)
+
    btst    #(button_right+8),d0
    beq.s   +
    move.w  #$200,x_vel(a1)
+
    move.w  #-$380,y_vel(a1)
    bset    #1,status(a1)
    tst.b   objoff_34(a0)
    beq.s   +   ; rts
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lea (ButtonVine_Trigger).w,a3
    lea (a3,d0.w),a3
    bclr    #0,(a3)
+
    rts
; ===========================================================================
 
loc_29B42:
    clr.b   obj_control(a1)
    clr.b   (a2)
    move.b  #$3C,2(a2)
    rts
; ===========================================================================
 
loc_29B50:
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$94,y_pos(a1)
    rts
; ===========================================================================
 
loc_29B5E:
    tst.b   2(a2)
    beq.s   +
    subq.b  #1,2(a2)
    bne.w   return_29BF8
+
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$10,d0
    cmpi.w  #$20,d0
    bhs.w   return_29BF8
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    subi.w  #$88,d1
    cmpi.w  #$18,d1
    bhs.w   return_29BF8
    tst.b   obj_control(a1)
    bmi.s   return_29BF8
    cmpi.b  #4,routine(a1)
    bhs.s   return_29BF8
    tst.w   (Debug_placement_mode).w
    bne.s   return_29BF8
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$94,y_pos(a1)
    move.b  #AniIDSonAni_Hang2,anim(a1)
    move.b  #1,obj_control(a1)
    move.b  #1,(a2)
    tst.b   objoff_34(a0)
    beq.s   return_29BF8
    move.b  subtype(a0),d0
    andi.w  #$F,d0
    lea (ButtonVine_Trigger).w,a3
    bset    #0,(a3,d0.w)
    move.w  #SndID_Blip,d0
    jsr (PlaySound).l
 
return_29BF8:
    rts
; ===========================================================================
; loc_29BFA:
Obj80_WFZ_Main:
    tst.b   objoff_36(a0)
    beq.s   loc_29C08
    tst.w   objoff_30(a0)
    bne.s   loc_29C1E
    bra.s   loc_29C0E
; ===========================================================================
 
loc_29C08:
    tst.w   objoff_30(a0)
    beq.s   loc_29C1E
 
loc_29C0E:
    move.w  objoff_38(a0),d2
    cmp.w   objoff_2E(a0),d2
    beq.s   loc_29C42
    add.w   objoff_3A(a0),d2
    bra.s   loc_29C28
; ===========================================================================
 
loc_29C1E:
    move.w  objoff_38(a0),d2
    beq.s   loc_29C42
    sub.w   objoff_3A(a0),d2
 
loc_29C28:
    move.w  d2,objoff_38(a0)
    move.w  objoff_3C(a0),d0
    add.w   d2,d0
    move.w  d0,y_pos(a0)
    move.w  d2,d0
    beq.s   +
    lsr.w   #4,d0
    addq.w  #1,d0
+
    move.b  d0,mapping_frame(a0)
 
loc_29C42:
    lea objoff_30(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1).w,d0
    bsr.w   Obj80_Action
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d0
    bsr.w   Obj80_Action
    jmpto   (MarkObjGone).l, JmpTo25_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj80_MapUnc_29C64: BINCLUDE "mappings/sprite/obj80_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj80_MapUnc_29DD0: BINCLUDE "mappings/sprite/obj80_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo25_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo44_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 81 - Drawbridge (MCZ)
; ----------------------------------------------------------------------------
; Sprite_2A000:
Obj81:
    btst    #6,render_flags(a0)
    bne.w   +
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj81_Index(pc,d0.w),d1
    jmp Obj81_Index(pc,d1.w)
; ===========================================================================
+
    move.w  #$280,d0
    jmpto   (DisplaySprite3).l, JmpTo2_DisplaySprite3
; ===========================================================================
; off_2A020:
Obj81_Index:    offsetTable
        offsetTableEntry.w Obj81_Init       ; 0
        offsetTableEntry.w Obj81_BridgeUp   ; 2
        offsetTableEntry.w loc_2A18A        ; 4
; ===========================================================================
; loc_2A026:
Obj81_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj81_MapUnc_2A24E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MCZGateLog,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo45_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #5,priority(a0)
    move.b  #8,width_pixels(a0)
    ori.b   #$80,status(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    subi.w  #$48,y_pos(a0)
    move.b  #-$40,angle(a0)
    moveq   #-$10,d4
    btst    #1,status(a0)
    beq.s   +
    addi.w  #$90,y_pos(a0)
    move.b  #$40,angle(a0)
    neg.w   d4
+
    move.w  #$100,d1
    btst    #0,status(a0)
    beq.s   +
    neg.w   d1
+
    move.w  d1,objoff_34(a0)
    jsrto   (SingleObjLoad2).l, JmpTo18_SingleObjLoad2
    bne.s   Obj81_BridgeUp
    _move.b id(a0),id(a1) ; load obj81
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #$40,mainspr_width(a1)
    move.w  objoff_30(a0),d2
    move.w  objoff_32(a0),d3
    moveq   #8,d1
    move.b  d1,mainspr_childsprites(a1)
    subq.w  #1,d1
    lea sub2_x_pos(a1),a2
 
-   add.w   d4,d3
    move.w  d2,(a2)+    ; sub?_x_pos
    move.w  d3,(a2)+    ; sub?_y_pos
    move.w  #1,(a2)+    ; sub?_mapframe
    dbf d1,-
 
    move.w  sub6_x_pos(a1),x_pos(a1)
    move.w  sub6_y_pos(a1),y_pos(a1)
    move.l  a1,objoff_3C(a0)
    move.b  #$40,mainspr_height(a1)
    bset    #4,render_flags(a1)
; loc_2A0FE:
Obj81_BridgeUp:
    lea (ButtonVine_Trigger).w,a2
    moveq   #0,d0
    move.b  subtype(a0),d0
    btst    #0,(a2,d0.w)
    beq.s   +
    tst.b   objoff_36(a0)
    bne.s   +
    move.b  #1,objoff_36(a0)
    move.w  #SndID_DrawbridgeMove,d0
    jsr (PlaySoundStereo).l
    cmpi.b  #$81,status(a0)
    bne.s   +
    move.w  objoff_30(a0),x_pos(a0)
    subi.w  #$48,x_pos(a0)
+
    tst.b   objoff_36(a0)
    beq.s   loc_2A188
    move.w  #$48,d1
    tst.b   angle(a0)
    beq.s   loc_2A154
    cmpi.b  #$80,angle(a0)
    bne.s   loc_2A180
    neg.w   d1
 
loc_2A154:
    move.w  objoff_32(a0),y_pos(a0)
    move.w  objoff_30(a0),x_pos(a0)
    add.w   d1,x_pos(a0)
    move.b  #$40,width_pixels(a0)
    move.b  #0,objoff_36(a0)
    move.w  #SndID_DrawbridgeDown,d0
    jsr (PlaySound).l
    addq.b  #2,routine(a0)
    bra.s   loc_2A188
; ===========================================================================
 
loc_2A180:
    move.w  objoff_34(a0),d0
    add.w   d0,angle(a0)
 
loc_2A188:
    bsr.s   loc_2A1EA
 
loc_2A18A:
    move.w  #$13,d1
    move.w  #$40,d2
    move.w  #$41,d3
    move.b  angle(a0),d0
    beq.s   loc_2A1A8
    cmpi.b  #$40,d0
    beq.s   loc_2A1B4
    cmpi.b  #-$40,d0
    bhs.s   loc_2A1B4
 
loc_2A1A8:
    move.w  #$4B,d1
    move.w  #8,d2
    move.w  #9,d3
 
loc_2A1B4:
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo22_SolidObject
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite).l, JmpTo26_DisplaySprite
; ---------------------------------------------------------------------------
+
    move.w  objoff_30(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   +
    jmpto   (DisplaySprite).l, JmpTo26_DisplaySprite
; ---------------------------------------------------------------------------
+
    movea.l objoff_3C(a0),a1 ; a1=object
    jsrto   (DeleteObject2).l, JmpTo3_DeleteObject2
    jmpto   (DeleteObject).l, JmpTo41_DeleteObject
; ===========================================================================
 
loc_2A1EA:
    tst.b   objoff_36(a0)
    beq.s   return_2A24C
    moveq   #0,d0
    moveq   #0,d1
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo9_CalcSine
    move.w  objoff_32(a0),d2
    move.w  objoff_30(a0),d3
    moveq   #0,d6
    movea.l objoff_3C(a0),a1 ; a1=object
    move.b  mainspr_childsprites(a1),d6
    subq.w  #1,d6
    bcs.s   return_2A24C
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    move.l  d0,d4
    move.l  d1,d5
    lea sub2_x_pos(a1),a2
 
-   movem.l d4-d5,-(sp)
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,(a2)+    ; sub?_x_pos
    move.w  d4,(a2)+    ; sub?_y_pos
    movem.l (sp)+,d4-d5
    add.l   d0,d4
    add.l   d1,d5
    addq.w  #next_subspr-4,a2
    dbf d6,-
 
    move.w  sub6_x_pos(a1),x_pos(a1)
    move.w  sub6_y_pos(a1),y_pos(a1)
 
return_2A24C:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj81_MapUnc_2A24E: BINCLUDE "mappings/sprite/obj81.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_DisplaySprite3 
    jmp (DisplaySprite3).l
JmpTo26_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo41_DeleteObject 
    jmp (DeleteObject).l
JmpTo3_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo18_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo45_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo9_CalcSine 
    jmp (CalcSine).l
JmpTo22_SolidObject 
    jmp (SolidObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 82 - Platform that is usually swinging, from ARZ
; ----------------------------------------------------------------------------
; Sprite_2A290:
Obj82:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj82_Index(pc,d0.w),d1
    jmp Obj82_Index(pc,d1.w)
; ===========================================================================
; off_2A29E:
Obj82_Index:    offsetTable
        offsetTableEntry.w Obj82_Init   ; 0
        offsetTableEntry.w Obj82_Main   ; 2
; ===========================================================================
; byte_2A2A2:
Obj82_Properties:
    ;    width_pixels
    ;        y_radius
    dc.b $20,  8    ; 0
    dc.b $1C,$30    ; 2
    ; Unused and broken; these don't have an associated frame, so using them crashes the game
    dc.b $10,$10    ; 4
    dc.b $10,$10    ; 6
; ===========================================================================
; loc_2A2AA:
Obj82_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj82_MapUnc_2A476,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo46_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsr.w   #3,d0
    andi.w  #$E,d0
    lea Obj82_Properties(pc,d0.w),a2
    move.b  (a2)+,width_pixels(a0)
    move.b  (a2),y_radius(a0)
    lsr.w   #1,d0
    move.b  d0,mapping_frame(a0)
    move.w  x_pos(a0),objoff_34(a0)
    move.w  y_pos(a0),objoff_30(a0)
    move.b  subtype(a0),d0
    andi.b  #$F,d0
    beq.s   +
    cmpi.b  #7,d0
    beq.s   +
    move.b  #1,objoff_38(a0)
+
    andi.b  #$F,subtype(a0)
; loc_2A312:
Obj82_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  subtype(a0),d0
    add.w   d0,d0
    move.w  Obj82_Types(pc,d0.w),d1
    jsr Obj82_Types(pc,d1.w)
    move.w  (sp)+,d4
    tst.b   render_flags(a0)
    bpl.s   +
 
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    moveq   #0,d2
    move.b  y_radius(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    jsrto   (SolidObject).l, JmpTo23_SolidObject
    swap    d6
    move.b  d6,objoff_3F(a0)
    bsr.w   loc_2A432
+
    move.w  objoff_34(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo7_MarkObjGone2
; ===========================================================================
; off_2A358:
Obj82_Types:    offsetTable
        offsetTableEntry.w return_2A368 ; 0
        offsetTableEntry.w loc_2A36A    ; 1
        offsetTableEntry.w loc_2A392    ; 2
        offsetTableEntry.w loc_2A36A    ; 3
        offsetTableEntry.w loc_2A3B6    ; 4
        offsetTableEntry.w loc_2A3D8    ; 5
        offsetTableEntry.w loc_2A392    ; 6
        offsetTableEntry.w loc_2A3EC    ; 7
; ===========================================================================
 
return_2A368:
    rts
; ===========================================================================
 
loc_2A36A:
    tst.w   objoff_36(a0)
    bne.s   loc_2A382
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   return_2A380
    move.w  #$1E,objoff_36(a0)
 
return_2A380:
    rts
; ===========================================================================
 
loc_2A382:
    subq.w  #1,objoff_36(a0)
    bne.s   return_2A380
    addq.b  #1,subtype(a0)
    clr.b   objoff_38(a0)
    rts
; ===========================================================================
 
loc_2A392:
    jsrto   (ObjectMove).l, JmpTo16_ObjectMove
    addi_.w #8,y_vel(a0)
    jsrto   (ObjCheckFloorDist).l, JmpTo2_ObjCheckFloorDist
    tst.w   d1
    bpl.w   return_2A3B4
    addq.w  #1,d1
    add.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    clr.b   subtype(a0)
 
return_2A3B4:
    rts
; ===========================================================================
 
loc_2A3B6:
    jsrto   (ObjectMove).l, JmpTo16_ObjectMove
    subi_.w #8,y_vel(a0)
    jsrto   (ObjCheckCeilingDist).l, JmpTo_ObjCheckCeilingDist
    tst.w   d1
    bpl.w   return_2A3D6
    sub.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    clr.b   subtype(a0)
 
return_2A3D6:
    rts
; ===========================================================================
 
loc_2A3D8:
    move.b  objoff_3F(a0),d0
    andi.b  #3,d0
    beq.s   return_2A3EA
    addq.b  #1,subtype(a0)
    clr.b   objoff_38(a0)
 
return_2A3EA:
    rts
; ===========================================================================
 
loc_2A3EC:
    move.w  (Water_Level_1).w,d0
    sub.w   y_pos(a0),d0
    beq.s   return_2A430
    bcc.s   loc_2A414
    cmpi.w  #-2,d0
    bge.s   loc_2A400
    moveq   #-2,d0
 
loc_2A400:
    add.w   d0,y_pos(a0)
    jsrto   (ObjCheckCeilingDist).l, JmpTo_ObjCheckCeilingDist
    tst.w   d1
    bpl.w   return_2A412
    sub.w   d1,y_pos(a0)
 
return_2A412:
    rts
; ===========================================================================
 
loc_2A414:
    cmpi.w  #2,d0
    ble.s   loc_2A41C
    moveq   #2,d0
 
loc_2A41C:
    add.w   d0,y_pos(a0)
    jsrto   (ObjCheckFloorDist).l, JmpTo2_ObjCheckFloorDist
    tst.w   d1
    bpl.w   return_2A430
    addq.w  #1,d1
    add.w   d1,y_pos(a0)
 
return_2A430:
    rts
; ===========================================================================
 
loc_2A432:
    tst.b   objoff_38(a0)
    beq.s   return_2A474
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   loc_2A44E
    tst.b   objoff_3E(a0)
    beq.s   return_2A474
    subq.b  #4,objoff_3E(a0)
    bra.s   loc_2A45A
; ===========================================================================
 
loc_2A44E:
    cmpi.b  #$40,objoff_3E(a0)
    beq.s   return_2A474
    addq.b  #4,objoff_3E(a0)
 
loc_2A45A:
    move.b  objoff_3E(a0),d0
    jsr (CalcSine).l
    move.w  #$400,d1
    muls.w  d1,d0
    swap    d0
    add.w   objoff_30(a0),d0
    move.w  d0,y_pos(a0)
 
return_2A474:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj82_MapUnc_2A476: BINCLUDE "mappings/sprite/obj82.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_ObjCheckFloorDist 
    jmp (ObjCheckFloorDist).l
JmpTo46_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_ObjCheckCeilingDist 
    jmp (ObjCheckCeilingDist).l
JmpTo23_SolidObject 
    jmp (SolidObject).l
JmpTo7_MarkObjGone2 
    jmp (MarkObjGone2).l
; loc_2A4F6:
JmpTo16_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 83 - 3 adjoined platforms from ARZ that rotate in a circle
; ----------------------------------------------------------------------------
; OST Variables:
Obj83_last_x_pos    = objoff_2C ; word
Obj83_speed     = objoff_2E ; word
Obj83_initial_x_pos = objoff_30 ; word
Obj83_initial_y_pos = objoff_32 ; word
; Child object RAM pointers
Obj83_childobjptr_chains    = objoff_34 ; longword  ; chain multisprite object
Obj83_childobjptr_platform2 = objoff_38 ; longword  ; 2nd platform object (parent object is 1st platform)
Obj83_childobjptr_platform3 = objoff_3C ; longword  ; 3rd platform object
 
; Sprite_2A4FC:
Obj83:
    btst    #6,render_flags(a0)
    bne.w   .isMultispriteObject
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj83_Index(pc,d0.w),d1
    jmp Obj83_Index(pc,d1.w)
; ===========================================================================
.isMultispriteObject:
    move.w  #$280,d0
    jmpto   (DisplaySprite3).l, JmpTo3_DisplaySprite3
; ===========================================================================
; off_2A51C:
Obj83_Index:    offsetTable
        offsetTableEntry.w Obj83_Init           ; 0
        offsetTableEntry.w Obj83_Main           ; 2
        offsetTableEntry.w Obj83_PlatformSubObject  ; 4
; ===========================================================================
; loc_2A522:
Obj83_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj15_Obj83_MapUnc_1021E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo47_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$20,width_pixels(a0)
    move.w  x_pos(a0),Obj83_initial_x_pos(a0)
    move.w  y_pos(a0),Obj83_initial_y_pos(a0)
 
    ; Setup subtype variables (rotation speed and other unused variable)
    move.b  subtype(a0),d1
    move.b  d1,d0
    andi.w  #$F,d1  ; The lower 4 bits of subtype are unused, making these instructions useless
    andi.b  #$F0,d0
    ext.w   d0
    asl.w   #3,d0
    move.w  d0,Obj83_speed(a0)
 
    ; Set angle according to X-flip and Y-flip
    move.b  status(a0),d0
    ror.b   #2,d0
    andi.b  #$C0,d0
    move.b  d0,angle(a0)
 
    ; Create child object (chain multisprite)
    jsrto   (SingleObjLoad2).l, JmpTo19_SingleObjLoad2
    bne.s   .noRAMforChildObjects
 
    _move.b id(a0),id(a1) ; load obj83
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    bset    #6,render_flags(a1)
    move.b  #$40,mainspr_width(a1)
    moveq   #8,d1
    move.b  d1,mainspr_childsprites(a1)
    subq.w  #1,d1
    lea sub2_x_pos(a1),a2
 
.nextChildSprite:
    addq.w  #next_subspr-2,a2
    move.w  #1,(a2)+    ; sub?_mapframe
    dbf d1,.nextChildSprite
 
    move.b  #1,mainspr_mapframe(a1)
    move.b  #$40,mainspr_height(a1)
    bset    #4,render_flags(a1)
    move.l  a1,Obj83_childobjptr_chains(a0)
 
    ; Create remaining child objects: platform 2 and 3
    bsr.s   Obj83_LoadSubObject
    move.l  a1,Obj83_childobjptr_platform2(a0)
    bsr.s   Obj83_LoadSubObject
    move.l  a1,Obj83_childobjptr_platform3(a0)
 
.noRAMforChildObjects:
    bra.s   Obj83_Main
; ===========================================================================
; loc_2A5DE:
Obj83_LoadSubObject:
    jsrto   (SingleObjLoad2).l, JmpTo19_SingleObjLoad2
    bne.s   .noRAMforChildObject    ; rts
    addq.b  #4,routine(a1)
    _move.b id(a0),id(a1) ; load obj
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #$20,width_pixels(a1)
    move.w  x_pos(a0),Obj83_initial_x_pos(a1)
    move.w  y_pos(a0),Obj83_initial_y_pos(a1)
    move.w  x_pos(a0),Obj83_last_x_pos(a1)
 
.noRAMforChildObject:
    rts
; ===========================================================================
; loc_2A620:
Obj83_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    moveq   #0,d1
    move.w  Obj83_speed(a0),d0
    add.w   d0,angle(a0)
    move.w  Obj83_initial_y_pos(a0),d2
    move.w  Obj83_initial_x_pos(a0),d3
    moveq   #0,d6
    movea.l Obj83_childobjptr_chains(a0),a1 ; a1=object
    lea sub2_x_pos(a1),a2
 
    ; Update first row of chains
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo10_CalcSine
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    move.l  d0,d4
    move.l  d1,d5
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,x_pos(a1)    ; update chainlink mainsprite x_pos
    move.w  d4,y_pos(a1)    ; update chainlink mainsprite y_pos
    move.l  d0,d4
    move.l  d1,d5
    add.l   d0,d4
    add.l   d1,d5
    moveq   #1,d6   ; Update 2 chainlink childsprites (the third chainlink is the mainsprite, which has already been updated)
    bsr.w   Obj83_UpdateChainSpritePosition
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,x_pos(a0)
    move.w  d4,y_pos(a0)
 
    ; Update second row of chains
    move.b  angle(a0),d0
    addi.b  #256/3,d0   ; 360 degrees = 256
    jsrto   (CalcSine).l, JmpTo10_CalcSine
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    move.l  d0,d4
    move.l  d1,d5
    moveq   #2,d6   ; Update 3 chainlink childsprites
    bsr.w   Obj83_UpdateChainSpritePosition
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    movea.l Obj83_childobjptr_platform2(a0),a1 ; a1=object
    move.w  d5,x_pos(a1)
    move.w  d4,y_pos(a1)
 
    ; Update third row of chains
    move.b  angle(a0),d0
    subi.b  #256/3,d0   ; 360 degrees = 256
    jsrto   (CalcSine).l, JmpTo10_CalcSine
    swap    d0
    swap    d1
    asr.l   #4,d0
    asr.l   #4,d1
    move.l  d0,d4
    move.l  d1,d5
    moveq   #2,d6   ; Update 3 chainlink childsprites
    bsr.w   Obj83_UpdateChainSpritePosition
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    movea.l Obj83_childobjptr_platform3(a0),a1 ; a1=object
    move.w  d5,x_pos(a1)
    move.w  d4,y_pos(a1)
 
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  (sp)+,d4
    jsrto   (PlatformObject).l, JmpTo7_PlatformObject
    tst.w   (Two_player_mode).w
    beq.s   .notTwoPlayerMode
    jmpto   (DisplaySprite).l, JmpTo27_DisplaySprite
; ===========================================================================
.notTwoPlayerMode:
    move.w  Obj83_initial_x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   .objectOffscreen
    jmpto   (DisplaySprite).l, JmpTo27_DisplaySprite
; ===========================================================================
.objectOffscreen:
    movea.l Obj83_childobjptr_chains(a0),a1 ; a1=object
    jsrto   (DeleteObject2).l, JmpTo4_DeleteObject2
    jmpto   (DeleteObject).l, JmpTo42_DeleteObject
; ===========================================================================
; loc_2A72E:
Obj83_UpdateChainSpritePosition:
.nextChainSprite:
    movem.l d4-d5,-(sp)
    swap    d4
    swap    d5
    add.w   d2,d4
    add.w   d3,d5
    move.w  d5,(a2)+    ; sub?_x_pos
    move.w  d4,(a2)+    ; sub?_y_pos
    movem.l (sp)+,d4-d5
    add.l   d0,d4
    add.l   d1,d5
    addq.w  #next_subspr-4,a2
    dbf d6,.nextChainSprite
    rts
; ===========================================================================
; loc_2A74E: Obj83_SubObject:
Obj83_PlatformSubObject:
    moveq   #0,d1
    move.b  width_pixels(a0),d1
    addi.w  #$B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  Obj83_last_x_pos(a0),d4
    jsrto   (PlatformObject).l, JmpTo7_PlatformObject
    move.w  x_pos(a0),Obj83_last_x_pos(a0)
    move.w  Obj83_initial_x_pos(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo8_MarkObjGone2
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo3_DisplaySprite3 
    jmp (DisplaySprite3).l
JmpTo27_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo42_DeleteObject 
    jmp (DeleteObject).l
JmpTo4_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo19_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo47_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo10_CalcSine 
    jmp (CalcSine).l
JmpTo7_PlatformObject 
    jmp (PlatformObject).l
JmpTo8_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3F - Fan from OOZ
; ----------------------------------------------------------------------------
; Sprite_2A7B0:
Obj3F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3F_Index(pc,d0.w),d1
    jmp Obj3F_Index(pc,d1.w)
; ===========================================================================
; off_2A7BE:
Obj3F_Index:    offsetTable
        offsetTableEntry.w Obj3F_Init       ; 0
        offsetTableEntry.w Obj3F_Horizontal ; 2 - pushes horizontally
        offsetTableEntry.w Obj3F_Vertical   ; 4 - pushes vertically
; ===========================================================================
; loc_2A7C4:
Obj3F_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj3F_MapUnc_2AA12,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZFanHoriz,3,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo48_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    tst.b   subtype(a0)
    bpl.s   Obj3F_Horizontal
    addq.b  #2,routine(a0)
    move.l  #Obj3F_MapUnc_2AAC4,mappings(a0)
    bra.w   Obj3F_Vertical
; ===========================================================================
; loc_2A802:
Obj3F_Horizontal:
    btst    #1,subtype(a0)
    bne.s   loc_2A82A
    subq.w  #1,objoff_30(a0)
    bpl.s   loc_2A82A
    move.w  #0,objoff_34(a0)
    move.w  #$78,objoff_30(a0)
    bchg    #0,objoff_32(a0)
    beq.s   loc_2A82A
    move.w  #$B4,objoff_30(a0)
 
loc_2A82A:
    tst.b   objoff_32(a0)
    beq.w   loc_2A84E
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo_JmpTo26_MarkObjGone
    cmpi.w  #$400,objoff_34(a0)
    bhs.s   BranchTo_JmpTo26_MarkObjGone
    addi.w  #$2A,objoff_34(a0)
    move.b  objoff_34(a0),anim_frame_duration(a0)
    bra.s   loc_2A86A
; ===========================================================================
 
loc_2A84E:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   loc_2A894
    lea (Sidekick).w,a1 ; a1=character
    bsr.w   loc_2A894
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo_JmpTo26_MarkObjGone
    move.b  #0,anim_frame_duration(a0)
 
loc_2A86A:
    addq.b  #1,anim_frame(a0)
    cmpi.b  #6,anim_frame(a0)
    blo.s   loc_2A87C
    move.b  #0,anim_frame(a0)
 
loc_2A87C:
    moveq   #0,d0
    btst    #0,subtype(a0)
    beq.s   loc_2A888
    moveq   #5,d0
 
loc_2A888:
    add.b   anim_frame(a0),d0
    move.b  d0,mapping_frame(a0)
 
BranchTo_JmpTo26_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo26_MarkObjGone
; ===========================================================================
 
loc_2A894:
    cmpi.b  #4,routine(a1)
    bhs.s   return_2A8FC
    tst.b   obj_control(a1)
    bne.s   return_2A8FC
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    btst    #0,status(a0)
    bne.s   loc_2A8B4
    neg.w   d0
 
loc_2A8B4:
    addi.w  #$50,d0
    cmpi.w  #$F0,d0
    bhs.s   return_2A8FC
    move.w  y_pos(a1),d1
    addi.w  #$60,d1
    sub.w   y_pos(a0),d1
    bcs.s   return_2A8FC
    cmpi.w  #$70,d1
    bhs.s   return_2A8FC
    subi.w  #$50,d0
    bcc.s   loc_2A8DC
    not.w   d0
    add.w   d0,d0
 
loc_2A8DC:
    addi.w  #$60,d0
    btst    #0,status(a0)
    bne.s   loc_2A8EA
    neg.w   d0
 
loc_2A8EA:
    neg.b   d0
    asr.w   #4,d0
    btst    #0,subtype(a0)
    beq.s   loc_2A8F8
    neg.w   d0
 
loc_2A8F8:
    add.w   d0,x_pos(a1)
 
return_2A8FC:
    rts
; ===========================================================================
; loc_2A8FE:
Obj3F_Vertical:
    btst    #1,subtype(a0)
    bne.s   loc_2A926
    subq.w  #1,objoff_30(a0)
    bpl.s   loc_2A926
    move.w  #0,objoff_34(a0)
    move.w  #$78,objoff_30(a0)
    bchg    #0,objoff_32(a0)
    beq.s   loc_2A926
    move.w  #$B4,objoff_30(a0)
 
loc_2A926:
    tst.b   objoff_32(a0)
    beq.w   loc_2A94A
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo2_JmpTo26_MarkObjGone
    cmpi.w  #$400,objoff_34(a0)
    bhs.s   BranchTo2_JmpTo26_MarkObjGone
    addi.w  #$2A,objoff_34(a0)
    move.b  objoff_34(a0),anim_frame_duration(a0)
    bra.s   loc_2A966
; ===========================================================================
 
loc_2A94A:
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   loc_2A990
    lea (Sidekick).w,a1 ; a1=character
    bsr.w   loc_2A990
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo2_JmpTo26_MarkObjGone
    move.b  #0,anim_frame_duration(a0)
 
loc_2A966:
    addq.b  #1,anim_frame(a0)
    cmpi.b  #6,anim_frame(a0)
    blo.s   +
    move.b  #0,anim_frame(a0)
+
    moveq   #0,d0
    btst    #0,subtype(a0)
    beq.s   +
    moveq   #5,d0
+
    add.b   anim_frame(a0),d0
    move.b  d0,mapping_frame(a0)
 
BranchTo2_JmpTo26_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo26_MarkObjGone
; ===========================================================================
 
loc_2A990:
    cmpi.b  #4,routine(a1)
    bhs.s   return_2AA10
    tst.b   obj_control(a1)
    bne.s   return_2AA10
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$40,d0
    cmpi.w  #$80,d0
    bhs.s   return_2AA10
    moveq   #0,d1
    move.b  (Oscillating_Data+$14).w,d1
    add.w   y_pos(a1),d1
    addi.w  #$60,d1
    sub.w   y_pos(a0),d1
    bcs.s   return_2AA10
    cmpi.w  #$90,d1
    bhs.s   return_2AA10
    subi.w  #$60,d1
    bcs.s   +
    not.w   d1
    add.w   d1,d1
+
    addi.w  #$60,d1
    neg.w   d1
    asr.w   #4,d1
    add.w   d1,y_pos(a1)
    bset    #1,status(a1)
    move.w  #0,y_vel(a1)
    move.w  #1,inertia(a1)
    tst.b   flip_angle(a1)
    bne.s   return_2AA10
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Walk,anim(a1)
    move.b  #$7F,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
 
return_2AA10:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
; sidefacing fan
Obj3F_MapUnc_2AA12: BINCLUDE "mappings/sprite/obj3F_a.bin"
; upfacing fan
Obj3F_MapUnc_2AAC4: BINCLUDE "mappings/sprite/obj3F_b.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo26_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo48_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 85 - Spring from CNZ that you hold jump on to pull back further
; ----------------------------------------------------------------------------
; Sprite_2AB84:
Obj85:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj85_Index(pc,d0.w),d1
    jsr Obj85_Index(pc,d1.w)
    move.w  #$200,d0
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite3).l, JmpTo4_DisplaySprite3
; ===========================================================================
+
    move.w  x_pos(a0),d1
    andi.w  #$FF80,d1
    sub.w   (Camera_X_pos_coarse).w,d1
    cmpi.w  #$280,d1
    bhi.w   +
    jmpto   (DisplaySprite3).l, JmpTo4_DisplaySprite3
; ===========================================================================
+
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   BranchTo_JmpTo43_DeleteObject
    bclr    #7,2(a2,d0.w)
 
BranchTo_JmpTo43_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo43_DeleteObject
; ===========================================================================
; off_2ABCE:
Obj85_Index:    offsetTable
        offsetTableEntry.w Obj85_Init       ; 0
        offsetTableEntry.w Obj85_Up     ; 2
        offsetTableEntry.w Obj85_Diagonal   ; 4
; ===========================================================================
; loc_2ABD4:
Obj85_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj85_MapUnc_2B07E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZVertPlunger,0,0),art_tile(a0)
    tst.b   subtype(a0)
    beq.s   +
    move.l  #Obj85_MapUnc_2B0EC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZDiagPlunger,0,0),art_tile(a0)
+
    jsrto   (Adjust2PArtPointer).l, JmpTo49_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    bset    #6,render_flags(a0)
    move.b  #1,mainspr_mapframe(a0)
    tst.b   subtype(a0)
    beq.s   Obj85_Init_Up
    addq.b  #2,routine(a0)
    move.b  #$20,mainspr_width(a0)
    move.b  #$18,width_pixels(a0)
    move.w  x_pos(a0),objoff_2E(a0)
    move.w  y_pos(a0),objoff_34(a0)
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    addi.w  #0,d3
    move.b  #1,mainspr_childsprites(a0)
    lea sub2_x_pos(a0),a2
    move.w  d2,(a2)+    ; sub2_x_pos
    move.w  d3,(a2)+    ; sub2_y_pos
    move.w  #2,(a2)+    ; sub2_mapframe
    bra.w   Obj85_Diagonal
; ===========================================================================
; loc_2AC54:
Obj85_Init_Up:
    move.b  #$18,mainspr_width(a0)
    move.b  #$18,width_pixels(a0)
    move.w  y_pos(a0),objoff_34(a0)
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    addi.w  #$20,d3
    move.b  #1,mainspr_childsprites(a0)
    lea sub2_x_pos(a0),a2
    move.w  d2,(a2)+    ; sub2_x_pos
    move.w  d3,(a2)+    ; sub2_y_pos
    move.w  #2,(a2)+    ; sub2_mapframe
; loc_2AC84:
Obj85_Up:
    move.b  #0,objoff_3A(a0)
    move.w  objoff_34(a0),d0
    add.w   objoff_38(a0),d0
    move.w  d0,y_pos(a0)
    move.b  #2,sub2_mapframe(a0)
    cmpi.w  #$10,objoff_38(a0)
    blo.s   +
    move.b  #3,sub2_mapframe(a0)
+
    move.w  #$23,d1
    move.w  #$20,d2
    move.w  #$1D,d3
    move.w  x_pos(a0),d4
    lea objoff_36(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1_Logical).w,d5
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   loc_2AD26
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d5
    moveq   #p2_standing_bit,d6
    bsr.s   loc_2AD26
    tst.w   objoff_36(a0)
    beq.s   loc_2AD14
    tst.w   objoff_38(a0)
    beq.s   return_2AD24
    moveq   #0,d0
    cmpi.b  #1,objoff_36(a0)
    bne.s   +
    or.w    (Ctrl_1_Logical).w,d0
+
    cmpi.b  #1,objoff_37(a0)
    bne.s   +
    or.w    (Ctrl_2).w,d0
+
    andi.w  #(button_B_mask|button_C_mask|button_A_mask)<<8,d0
    bne.s   return_2AD24
    move.w  #$202,objoff_36(a0)
    rts
; ===========================================================================
 
loc_2AD14:
    move.b  #1,mainspr_mapframe(a0)
    subq.w  #4,objoff_38(a0)
    bcc.s   return_2AD24
    clr.w   objoff_38(a0)
 
return_2AD24:
    rts
; ===========================================================================
 
loc_2AD26:
    move.b  (a2),d0
    bne.s   loc_2AD7A
 
loc_2AD2A:
    tst.w   (Debug_placement_mode).w
    bne.s   return_2AD78
    tst.w   y_vel(a1)
    bmi.s   return_2AD78
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo5_SolidObject_Always_SingleCharacter
    btst    d6,status(a0)
    beq.s   return_2AD78
    move.b  #$81,obj_control(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.w  #0,inertia(a1)
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    addq.b  #1,(a2)
 
return_2AD78:
    rts
; ===========================================================================
 
loc_2AD7A:
    if gameRevision>0
    cmpi.b  #4,routine(a1)
    bhs.s   return_2AD78
    endif
    subq.b  #1,d0
    bne.w   loc_2AE0C
    tst.b   render_flags(a1)
    bmi.s   loc_2ADB0
    bclr    d6,status(a0)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.b  #0,obj_control(a1)
    move.b  #0,(a2)
    rts
; ===========================================================================
 
loc_2ADB0:
    andi.w  #(button_B_mask|button_C_mask|button_A_mask)<<8,d5
    beq.s   loc_2ADFE
    tst.b   objoff_3A(a0)
    bne.s   loc_2ADFE
    move.b  #1,objoff_3A(a0)
    subq.b  #1,objoff_32(a0)
    bpl.s   loc_2ADDA
    move.b  #3,objoff_32(a0)
    cmpi.w  #$20,objoff_38(a0)
    beq.s   loc_2ADDA
    addq.w  #1,objoff_38(a0)
 
loc_2ADDA:
    subq.b  #1,objoff_33(a0)
    bpl.s   loc_2ADF8
    move.w  objoff_38(a0),d0
    subi.w  #$20,d0
    neg.w   d0
    lsr.w   #1,d0
    move.b  d0,objoff_33(a0)
    bchg    #2,mainspr_mapframe(a0)
    bra.s   loc_2ADFE
; ===========================================================================
 
loc_2ADF8:
    move.b  #1,mainspr_mapframe(a0)
 
loc_2ADFE:
    move.w  y_pos(a0),d0
    subi.w  #$2E,d0
    move.w  d0,y_pos(a1)
    rts
; ===========================================================================
 
loc_2AE0C:
    move.b  #0,(a2)
    bclr    d6,status(a0)
    beq.w   loc_2AD2A
    move.w  objoff_38(a0),d0
    addi.w  #$10,d0
    lsl.w   #7,d0
    neg.w   d0
    move.w  d0,y_vel(a1)
    move.w  #0,x_vel(a1)
    move.w  #$800,inertia(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.b  #0,obj_control(a1)
    move.w  #SndID_CNZLaunch,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_2AE56:
Obj85_Diagonal:
    move.b  #0,objoff_3A(a0)
    move.w  objoff_38(a0),d1
    lsr.w   #1,d1
    move.w  objoff_2E(a0),d0
    sub.w   d1,d0
    move.w  d0,x_pos(a0)
    move.w  objoff_34(a0),d0
    add.w   d1,d0
    move.w  d0,y_pos(a0)
    move.b  #2,sub2_mapframe(a0)
    cmpi.w  #$10,objoff_38(a0)
    blo.s   +
    move.b  #3,sub2_mapframe(a0)
+
    move.w  #$23,d1
    move.w  #8,d2
    move.w  #5,d3
    move.w  x_pos(a0),d4
    lea objoff_36(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1_Logical).w,d5
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.s   loc_2AF06
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d5
    moveq   #p2_standing_bit,d6
    bsr.s   loc_2AF06
    tst.w   objoff_36(a0)
    beq.s   loc_2AEF4
    tst.w   objoff_38(a0)
    beq.s   return_2AF04
    moveq   #0,d0
    cmpi.b  #1,objoff_36(a0)
    bne.s   +
    or.w    (Ctrl_1_Logical).w,d0
+
    cmpi.b  #1,objoff_37(a0)
    bne.s   +
    or.w    (Ctrl_2).w,d0
+
    andi.w  #(button_B_mask|button_C_mask|button_A_mask)<<8,d0
    bne.s   return_2AF04
    move.w  #$202,objoff_36(a0)
    rts
; ===========================================================================
 
loc_2AEF4:
    move.b  #1,mainspr_mapframe(a0)
    subq.w  #4,objoff_38(a0)
    bcc.s   return_2AF04
    clr.w   objoff_38(a0)
 
return_2AF04:
    rts
; ===========================================================================
 
loc_2AF06:
    move.b  (a2),d0
    bne.s   loc_2AF7A
    tst.w   (Debug_placement_mode).w
    bne.s   return_2AF78
    tst.w   y_vel(a1)
    bmi.s   return_2AF78
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo5_SolidObject_Always_SingleCharacter
    btst    d6,status(a0)
    bne.s   loc_2AF2E
    move.b  d6,d0
    addq.b  #pushing_bit_delta,d0
    btst    d0,status(a0)
    beq.s   return_2AF78
    bset    d6,status(a0)
 
loc_2AF2E:
    move.b  #$81,obj_control(a1)
    move.w  x_pos(a0),x_pos(a1)
    addi.w  #$13,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    subi.w  #$13,y_pos(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.w  #0,inertia(a1)
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    addq.b  #1,(a2)
 
return_2AF78:
    rts
; ===========================================================================
 
loc_2AF7A:
    if gameRevision>0
    cmpi.b  #4,routine(a1)
    bhs.s   return_2AF78
    endif
    subq.b  #1,d0
    bne.w   loc_2B018
    tst.b   render_flags(a1)
    bmi.s   loc_2AFB0
    bclr    d6,status(a0)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.b  #0,obj_control(a1)
    move.b  #0,(a2)
    rts
; ===========================================================================
 
loc_2AFB0:
    andi.w  #(button_B_mask|button_C_mask|button_A_mask)<<8,d5
    beq.s   loc_2AFFE
    tst.b   objoff_3A(a0)
    bne.s   loc_2AFFE
    move.b  #1,objoff_3A(a0)
    subq.b  #1,objoff_32(a0)
    bpl.s   loc_2AFDA
    move.b  #3,objoff_32(a0)
    cmpi.w  #$1C,objoff_38(a0)
    beq.s   loc_2AFDA
    addq.w  #1,objoff_38(a0)
 
loc_2AFDA:
    subq.b  #1,objoff_33(a0)
    bpl.s   loc_2AFF8
    move.w  objoff_38(a0),d0
    subi.w  #$1C,d0
    neg.w   d0
    lsr.w   #1,d0
    move.b  d0,objoff_33(a0)
    bchg    #2,mainspr_mapframe(a0)
    bra.s   loc_2AFFE
; ===========================================================================
 
loc_2AFF8:
    move.b  #1,mainspr_mapframe(a0)
 
loc_2AFFE:
    move.w  x_pos(a0),d0
    addi.w  #$13,d0
    move.w  d0,x_pos(a1)
    move.w  y_pos(a0),d0
    subi.w  #$13,d0
    move.w  d0,y_pos(a1)
    rts
; ===========================================================================
 
loc_2B018:
    move.b  #0,(a2)
    bclr    d6,status(a0)
    beq.w   return_2AF78
    move.w  objoff_38(a0),d0
    addi_.w #4,d0
    lsl.w   #7,d0
    move.w  d0,x_vel(a1)
    neg.w   d0
    move.w  d0,y_vel(a1)
    move.w  #$800,inertia(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    tst.b   subtype(a0)
    bpl.s   loc_2B068
    neg.w   d0
    move.w  d0,inertia(a1)
    bclr    #0,status(a1)
    bclr    #1,status(a1)
    move.b  #-$20,angle(a1)
 
loc_2B068:
    move.b  #2,routine(a1)
    move.b  #0,obj_control(a1)
    move.w  #SndID_CNZLaunch,d0
    jmp (PlaySound).l
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj85_MapUnc_2B07E: BINCLUDE "mappings/sprite/obj85_a.bin"
Obj85_MapUnc_2B0EC: BINCLUDE "mappings/sprite/obj85_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo4_DisplaySprite3 
    jmp (DisplaySprite3).l
JmpTo43_DeleteObject 
    jmp (DeleteObject).l
JmpTo49_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo5_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 86 - Flipper from CNZ
; ----------------------------------------------------------------------------
; Sprite_2B140:
Obj86:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj86_Index(pc,d0.w),d1
    jsr Obj86_Index(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo27_MarkObjGone
; ===========================================================================
; off_2B152:
Obj86_Index:    offsetTable
        offsetTableEntry.w Obj86_Init       ; 0
        offsetTableEntry.w Obj86_UpwardsType    ; 2 - sends you upwards
        offsetTableEntry.w Obj86_HorizontalType ; 4 - sends you leftward/rightward
; ===========================================================================
; loc_2B158:
Obj86_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj86_MapUnc_2B45A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZFlipper,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo50_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #4,priority(a0)
    tst.b   subtype(a0)
    beq.s   Obj86_UpwardsType
    addq.b  #2,routine(a0)
    move.b  #2,anim(a0)
    bra.w   Obj86_HorizontalType
; ===========================================================================
; loc_2B194:
Obj86_UpwardsType:
    tst.w   (Debug_placement_mode).w
    bne.s   return_2B208
    lea (byte_2B3C6).l,a2
    move.b  mapping_frame(a0),d0
    beq.s   loc_2B1B6
    lea (byte_2B3EA).l,a2
    subq.b  #1,d0
    beq.s   loc_2B1B6
    lea (byte_2B40E).l,a2
 
loc_2B1B6:
    move.w  #$23,d1
    move.w  #6,d2
    move.w  x_pos(a0),d4
    jsrto   (SlopedSolid).l, JmpTo2_SlopedSolid
    lea objoff_36(a0),a3
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1_Logical).w,d5
    moveq   #p1_standing_bit,d6
    bsr.s   loc_2B20A
    addq.w  #1,a3
    lea (Sidekick).w,a1 ; a1=character
    move.w  (Ctrl_2).w,d5
    moveq   #p2_standing_bit,d6
    bsr.s   loc_2B20A
    tst.b   objoff_38(a0)
    beq.s   loc_2B1FE
    clr.b   objoff_38(a0)
    bsr.w   loc_2B290
    subq.w  #1,a3
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    bsr.w   loc_2B290
 
loc_2B1FE:
    lea (Ani_obj86).l,a1
    jmpto   (AnimateSprite).l, JmpTo9_AnimateSprite
; ===========================================================================
 
return_2B208:
    rts
; ===========================================================================
 
loc_2B20A:
    move.b  (a3),d0
    bne.s   loc_2B23C
    btst    d6,status(a0)
    beq.s   return_2B208
    move.b  #1,obj_control(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    bset    #2,status(a1)
    bne.s   loc_2B238
    addq.w  #5,y_pos(a1)
 
loc_2B238:
    addq.b  #1,(a3)
    rts
; ===========================================================================
 
loc_2B23C:
    andi.w  #button_B_mask|button_C_mask|button_A_mask,d5
    bne.s   loc_2B288
    btst    d6,status(a0)
    bne.s   loc_2B254
    move.b  #0,obj_control(a1)
    move.b  #0,(a3)
    rts
; ===========================================================================
 
loc_2B254:
    moveq   #0,d1
    move.b  mapping_frame(a0),d1
    subq.w  #1,d1
    bset    #0,status(a1)
    btst    #0,status(a0)
    bne.s   loc_2B272
    neg.w   d1
    bclr    #0,status(a1)
 
loc_2B272:
    add.w   d1,x_pos(a1)
    lsl.w   #8,d1
    move.w  d1,x_vel(a1)
    move.w  d1,inertia(a1)
    move.w  #0,y_vel(a1)
    rts
; ===========================================================================
 
loc_2B288:
    move.b  #1,objoff_38(a0)
    rts
; ===========================================================================
 
loc_2B290:
    bclr    d6,status(a0)
    beq.w   return_2B208
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    btst    #0,status(a0)
    beq.s   loc_2B2AA
    neg.w   d0
 
loc_2B2AA:
    addi.w  #$23,d0
    move.w  d0,d2
    cmpi.w  #$40,d2
    blo.s   loc_2B2BA
    move.w  #$40,d2
 
loc_2B2BA:
    lsl.w   #5,d2
    addi.w  #$800,d2
    neg.w   d2
    asr.w   #2,d0
    addi.w  #$40,d0
    jsrto   (CalcSine).l, JmpTo11_CalcSine
    muls.w  d2,d0
    muls.w  d2,d1
    asr.l   #8,d0
    asr.l   #8,d1
    move.w  d0,y_vel(a1)
    btst    #0,status(a0)
    beq.s   loc_2B2E2
    neg.w   d1
 
loc_2B2E2:
    move.w  d1,x_vel(a1)
    bset    #1,status(a1)
    bclr    #3,status(a1)
    move.b  #2,routine(a1)
    move.b  #0,obj_control(a1)
    move.b  #1,anim(a0)
    move.b  #0,(a3)
    move.w  #SndID_Flipper,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_2B312:
Obj86_HorizontalType:
    move.w  #$13,d1
    move.w  #$18,d2
    move.w  #$19,d3
    move.w  x_pos(a0),d4
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo6_SolidObject_Always_SingleCharacter
    btst    #p1_pushing_bit,status(a0)
    beq.s   loc_2B33A
    bsr.s   loc_2B35C
 
loc_2B33A:
    movem.l (sp)+,d1-d4
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo6_SolidObject_Always_SingleCharacter
    btst    #p2_pushing_bit,status(a0)
    beq.s   loc_2B352
    bsr.s   loc_2B35C
 
loc_2B352:
    lea (Ani_obj86).l,a1
    jmpto   (AnimateSprite).l, JmpTo9_AnimateSprite
; ===========================================================================
 
loc_2B35C:
    move.w  #$300,anim(a0)
    move.w  #-$1000,x_vel(a1)
    addq.w  #8,x_pos(a1)
    bset    #0,status(a1)
    move.w  x_pos(a0),d0
    sub.w   x_pos(a1),d0
    bcc.s   loc_2B392
    bclr    #0,status(a1)
    subi.w  #$10,x_pos(a1)
    neg.w   x_vel(a1)
    move.w  #$400,anim(a0)
 
loc_2B392:
    move.w  #$F,move_lock(a1)
    move.w  x_vel(a1),inertia(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    bset    #2,status(a1)
    bne.s   loc_2B3BC
    addq.w  #5,y_pos(a1)
 
loc_2B3BC:
    move.w  #SndID_Flipper,d0
    jmp (PlaySound).l
; ===========================================================================
byte_2B3C6:
    dc.b   7,  7,  7,  7,  7,  7,  7,  8,  9, $A, $B, $A,  9,  8,  7,  6
    dc.b   5,  4,  3,  2,  1,  0,$FF,$FE,$FD,$FC,$FB,$FA,$F9,$F8,$F7,$F6; 16
    dc.b $F5,$F4,$F3,$F2    ; 32
byte_2B3EA:
    dc.b   6,  6,  6,  6,  6,  6,  7,  8,  9,  9,  9,  9,  9,  9,  8,  8
    dc.b   8,  8,  8,  8,  7,  7,  7,  7,  6,  6,  6,  6,  5,  5,  4,  4; 16
    dc.b   4,  4,  4,  4    ; 32
byte_2B40E:
    dc.b   5,  5,  5,  5,  5,  6,  7,  8,  9, $A, $B, $B, $C, $C, $D, $D
    dc.b  $E, $E, $F, $F,$10,$10,$11,$11,$12,$12,$11,$11,$10,$10,$10,$10; 16
    dc.b $10,$10,$10,$10    ; 32
 
; animation script
; off_2B432:
Ani_obj86:  offsetTable
        offsetTableEntry.w byte_2B43C   ; 0
        offsetTableEntry.w byte_2B43F   ; 1
        offsetTableEntry.w byte_2B445   ; 2
        offsetTableEntry.w byte_2B448   ; 3
        offsetTableEntry.w byte_2B451   ; 4
byte_2B43C: dc.b  $F,  0,$FF
    rev02even
byte_2B43F: dc.b   3,  1,  2,  1,$FD,  0
    rev02even
byte_2B445: dc.b  $F,  4,$FF
    rev02even
byte_2B448: dc.b   0,  5,  4,  3,  3,  3,  3,$FD,  2
    rev02even
byte_2B451: dc.b   0,  3,  4,  5,  5,  5,  5,$FD,  2
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj86_MapUnc_2B45A: BINCLUDE "mappings/sprite/obj86.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo27_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo9_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo50_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo11_CalcSine 
    jmp (CalcSine).l
JmpTo6_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
JmpTo2_SlopedSolid 
    jmp (SlopedSolid).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D2 - Flashing blocks that appear and disappear in a rectangular shape that you can walk across, from CNZ
; ----------------------------------------------------------------------------
; Sprite_2B528:
ObjD2:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD2_Index(pc,d0.w),d1
    jmp ObjD2_Index(pc,d1.w)
; ===========================================================================
; off_2B536:
ObjD2_Index:    offsetTable
        offsetTableEntry.w ObjD2_Init   ; 0
        offsetTableEntry.w ObjD2_Main   ; 2
; ===========================================================================
; loc_2B53A:
ObjD2_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD2_MapUnc_2B694,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZSnake,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo51_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #8,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #4,d0
    move.w  d0,objoff_38(a0)
    bsr.w   loc_2B60C
; loc_2B57E:
ObjD2_Main:
    tst.w   objoff_38(a0)
    beq.s   +
    subq.w  #1,objoff_38(a0)
    jmpto   (MarkObjGone3).l, JmpTo6_MarkObjGone3
; ===========================================================================
+
    subq.w  #1,objoff_3A(a0)
    bpl.s   loc_2B5EC
    move.w  #$F,objoff_3A(a0)
    addq.b  #1,mapping_frame(a0)
    andi.b  #$F,mapping_frame(a0)
    bne.s   loc_2B5EA
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #4,d0
    move.w  d0,objoff_38(a0)
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   loc_2B5E2
    bclr    #p1_standing_bit,status(a0)
    beq.s   +
    bclr    #3,(MainCharacter+status).w
    bset    #1,(MainCharacter+status).w
+
    bclr    #p2_standing_bit,status(a0)
    beq.s   loc_2B5E2
    bclr    #3,(Sidekick+status).w
    bset    #1,(Sidekick+status).w
 
loc_2B5E2:
    move.w  objoff_30(a0),x_pos(a0)
    bra.s   loc_2B60C
; ===========================================================================
 
loc_2B5EA:
    bsr.s   loc_2B60C
 
loc_2B5EC:
    move.w  objoff_34(a0),d1
    addi.w  #$B,d1
    move.w  objoff_36(a0),d2
    move.w  d2,d3
    addq.w  #1,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo24_SolidObject
    move.w  objoff_30(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo9_MarkObjGone2
; ===========================================================================
 
loc_2B60C:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    add.w   d0,d0
    add.w   d0,d0
    lea byte_2B654(pc,d0.w),a1
    move.b  (a1)+,d0
    ext.w   d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
+
    add.w   objoff_30(a0),d0
    move.w  d0,x_pos(a0)
    move.b  (a1)+,d0
    ext.w   d0
    add.w   objoff_32(a0),d0
    move.w  d0,y_pos(a0)
    moveq   #0,d1
    moveq   #0,d2
    moveq   #0,d3
    move.b  (a1)+,d1
    move.b  (a1)+,d2
    move.w  d1,objoff_34(a0)
    move.b  d1,width_pixels(a0)
    move.w  d2,objoff_36(a0)
    rts
; ===========================================================================
byte_2B654:
    dc.b $D8,$18,  8,  8,$D8,$10,  8,$10,$D8,  8,  8,$18,$D8,  0,  8,$20
    dc.b $E0,  0,$10,$20,$E8,$F8,$18,$18,$F0,$F0,$20,$10,$F8,$E8,$28,  8; 16
    dc.b   8,$E8,$28,  8,$10,$F0,$20,$10,$18,$F8,$18,$18,$20,  0,$10,$20; 32
    dc.b $28,  0,  8,$20,$28,  8,  8,$18,$28,$10,  8,$10,$28,$18,  8,  8; 48
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD2_MapUnc_2B694: BINCLUDE "mappings/sprite/objD2.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo6_MarkObjGone3 
    jmp (MarkObjGone3).l
JmpTo51_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo24_SolidObject 
    jmp (SolidObject).l
JmpTo9_MarkObjGone2 
    jmp (MarkObjGone2).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D3 - Bomb prize from CNZ
; ----------------------------------------------------------------------------
; Note: see object DC (ring prize) for SST entries (casino_prize_*)
 
; Sprite_2B84C:
ObjD3:
    moveq   #0,d1
    move.w  casino_prize_machine_x_pos(a0),d1
    swap    d1
    move.l  casino_prize_x_pos(a0),d0
    sub.l   d1,d0
    asr.l   #4,d0
    sub.l   d0,casino_prize_x_pos(a0)
    move.w  casino_prize_x_pos(a0),x_pos(a0)
    moveq   #0,d1
    move.w  casino_prize_machine_y_pos(a0),d1
    swap    d1
    move.l  casino_prize_y_pos(a0),d0
    sub.l   d1,d0
    asr.l   #4,d0
    sub.l   d0,casino_prize_y_pos(a0)
    move.w  casino_prize_y_pos(a0),y_pos(a0)
    subq.w  #1,casino_prize_display_delay(a0)
    bne.w   JmpTo28_DisplaySprite
    movea.l objoff_2A(a0),a1
    subq.w  #1,(a1)
    cmpi.w  #5,(Bonus_Countdown_3).w
    blo.s   +
    clr.w   (Bonus_Countdown_3).w
    move.w  #SndID_HurtBySpikes,d0
    jsr (PlaySoundStereo).l
+
    tst.b   parent+1(a0)
    beq.s   ++
    tst.w   (Ring_count_2P).w
    beq.s   +
    subq.w  #1,(Ring_count_2P).w
    ori.b   #$81,(Update_HUD_rings_2P).w
+
    tst.w   (Two_player_mode).w
    bne.s   BranchTo_JmpTo44_DeleteObject
+
    tst.w   (Ring_count).w
    beq.s   BranchTo_JmpTo44_DeleteObject
    subq.w  #1,(Ring_count).w
    ori.b   #$81,(Update_HUD_rings).w
 
BranchTo_JmpTo44_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo44_DeleteObject
 
    if removeJmpTos
JmpTo28_DisplaySprite 
    jmp (DisplaySprite).l
    endif
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD3_MapUnc_2B8D4: BINCLUDE "mappings/sprite/objD6_a.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo28_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo44_DeleteObject 
    jmp (DeleteObject).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D4 - Big block from CNZ that moves back and forth
; ----------------------------------------------------------------------------
; Sprite_2B8EC:
ObjD4:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD4_Index(pc,d0.w),d1
    jmp ObjD4_Index(pc,d1.w)
; ===========================================================================
; off_2B8FA:
ObjD4_Index:    offsetTable
        offsetTableEntry.w ObjD4_Init   ; 0
        offsetTableEntry.w ObjD4_Main   ; 2
; ===========================================================================
; loc_2B8FE:
ObjD4_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD4_MapUnc_2B9CA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_BigMovingBlock,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo52_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.w  #$8000,x_sub(a0)
    move.w  #$8000,y_sub(a0)
    tst.b   subtype(a0)
    bne.s   loc_2B95A
    subi.w  #$60,x_pos(a0)
    btst    #0,status(a0)
    beq.s   ObjD4_Main
    addi.w  #$C0,x_pos(a0)
    bra.s   ObjD4_Main
; ===========================================================================
 
loc_2B95A:
    subi.w  #$60,y_pos(a0)
    btst    #1,status(a0)
    beq.s   ObjD4_Main
    addi.w  #$C0,y_pos(a0)
; loc_2B96E:
ObjD4_Main:
    move.w  x_pos(a0),-(sp)
    moveq   #0,d0
    move.b  subtype(a0),d0
    move.w  ObjD4_Types(pc,d0.w),d1
    jsr ObjD4_Types(pc,d1.w)
    jsrto   (ObjectMove).l, JmpTo17_ObjectMove
    move.w  #$2B,d1
    move.w  #$20,d2
    move.w  #$21,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo25_SolidObject
    move.w  objoff_30(a0),d0
    jmpto   (MarkObjGone2).l, JmpTo10_MarkObjGone2
; ===========================================================================
; off_2B99E:
ObjD4_Types:    offsetTable
        offsetTableEntry.w ObjD4_Horizontal ; 0
        offsetTableEntry.w ObjD4_Vertical   ; 2
; ===========================================================================
; loc_2B9A2:
ObjD4_Horizontal:
    moveq   #4,d1
    move.w  objoff_30(a0),d0
    cmp.w   x_pos(a0),d0
    bhi.s   +
    neg.w   d1
+
    add.w   d1,x_vel(a0)
    rts
; ===========================================================================
; loc_2B9B6:
ObjD4_Vertical:
    moveq   #4,d1
    move.w  objoff_32(a0),d0
    cmp.w   y_pos(a0),d0
    bhi.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD4_MapUnc_2B9CA: BINCLUDE "mappings/sprite/objD4.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo52_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo25_SolidObject 
    jmp (SolidObject).l
JmpTo10_MarkObjGone2 
    jmp (MarkObjGone2).l
; loc_2BA02:
JmpTo17_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D5 - Elevator from CNZ
; ----------------------------------------------------------------------------
; Sprite_2BA08:
ObjD5:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD5_Index(pc,d0.w),d1
    jmp ObjD5_Index(pc,d1.w)
; ===========================================================================
; off_2BA16:
ObjD5_Index:    offsetTable
        offsetTableEntry.w ObjD5_Init   ; 0
        offsetTableEntry.w ObjD5_Main   ; 2
; ===========================================================================
; loc_2BA1A:
ObjD5_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD5_MapUnc_2BB40,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZElevator,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo53_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #4,priority(a0)
    move.w  y_pos(a0),objoff_32(a0)
    move.w  #$8000,y_sub(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #2,d0
    sub.w   d0,y_pos(a0)
    btst    #0,status(a0)
    beq.s   ObjD5_Main
    add.w   d0,d0
    add.w   d0,y_pos(a0)
; loc_2BA68:
ObjD5_Main:
    jsrto   (ObjectMove).l, JmpTo18_ObjectMove
    move.w  objoff_34(a0),d0
    move.w  off_2BA94(pc,d0.w),d1
    jsr off_2BA94(pc,d1.w)
    cmpi.w  #6,objoff_34(a0)
    bhs.s   +
    move.w  #$10,d1
    move.w  #9,d3
    move.w  x_pos(a0),d4
    jsrto   (PlatformObjectD5).l, JmpTo_PlatformObjectD5
+
    jmpto   (MarkObjGone).l, JmpTo28_MarkObjGone
; ===========================================================================
off_2BA94:  offsetTable
        offsetTableEntry.w loc_2BA9C    ; 0
        offsetTableEntry.w loc_2BAB6    ; 2
        offsetTableEntry.w loc_2BAEE    ; 4
        offsetTableEntry.w loc_2BB08    ; 6
; ===========================================================================
 
loc_2BA9C:
    move.b  status(a0),d0
    andi.w  #standing_mask,d0
    beq.s   +   ; rts
    move.w  #SndID_CNZElevator,d0
    jsr (PlaySound).l
    addq.w  #2,objoff_34(a0)
+
    rts
; ===========================================================================
 
loc_2BAB6:
    moveq   #8,d1
    move.w  objoff_32(a0),d0
    cmp.w   y_pos(a0),d0
    bhs.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    bne.s   +   ; rts
    addq.w  #2,objoff_34(a0)
    move.w  d0,y_pos(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #2,d0
    sub.w   d0,y_pos(a0)
    btst    #0,status(a0)
    bne.s   +   ; rts
    add.w   d0,d0
    add.w   d0,y_pos(a0)
+
    rts
; ===========================================================================
 
loc_2BAEE:
    move.b  status(a0),d0
    andi.w  #standing_mask,d0
    bne.s   +   ; rts
    move.w  #SndID_CNZElevator,d0
    jsr (PlaySound).l
    addq.w  #2,objoff_34(a0)
+
    rts
; ===========================================================================
 
loc_2BB08:
    moveq   #8,d1
    move.w  objoff_32(a0),d0
    cmp.w   y_pos(a0),d0
    bhs.s   +
    neg.w   d1
+
    add.w   d1,y_vel(a0)
    bne.s   +   ; rts
    clr.w   objoff_34(a0)
    move.w  d0,y_pos(a0)
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #2,d0
    sub.w   d0,y_pos(a0)
    btst    #0,status(a0)
    beq.s   +   ; rts
    add.w   d0,d0
    add.w   d0,y_pos(a0)
+
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD5_MapUnc_2BB40: BINCLUDE "mappings/sprite/objD5.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo28_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo53_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_PlatformObjectD5 
    jmp (PlatformObjectD5).l
; loc_2BB66:
JmpTo18_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D6 - Pokey that gives out points from CNZ
; ----------------------------------------------------------------------------
; Sprite_2BB6C:
ObjD6:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD6_Index(pc,d0.w),d1
    jmp ObjD6_Index(pc,d1.w)
; ===========================================================================
; off_2BB7A:
ObjD6_Index:    offsetTable
        offsetTableEntry.w ObjD6_Init   ; 0
        offsetTableEntry.w ObjD6_Main   ; 2
; ===========================================================================
; loc_2BB7E:
ObjD6_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD6_MapUnc_2BEBC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZCage,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo54_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #1,priority(a0)
; loc_2BBA6:
ObjD6_Main:
    move.w  #$23,d1
    move.w  #$10,d2
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    lea objoff_30(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    moveq   #p1_standing_bit,d6
    movem.l d1-d4,-(sp)
    bsr.w   loc_2BBE8
    movem.l (sp)+,d1-d4
    lea objoff_34(a0),a2 ; a2=object
    lea (Sidekick).w,a1 ; a1=character
    moveq   #p2_standing_bit,d6
    bsr.w   loc_2BBE8
    lea (Ani_objD6).l,a1
    jsrto   (AnimateSprite).l, JmpTo10_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo29_MarkObjGone
; ===========================================================================
 
loc_2BBE8:
    move.w  (a2),d0
    move.w  off_2BBF2(pc,d0.w),d0
    jmp off_2BBF2(pc,d0.w)
; ===========================================================================
off_2BBF2:  offsetTable
        offsetTableEntry.w loc_2BBF8    ; 0
        offsetTableEntry.w loc_2BDF8    ; 2
        offsetTableEntry.w loc_2BE9C    ; 4
; ===========================================================================
 
loc_2BBF8:
    tst.b   obj_control(a1)
    bne.w   return_2BC84
    tst.b   subtype(a0)
    beq.s   loc_2BC0C
    tst.w   (SlotMachineInUse).w
    bne.s   return_2BC84
 
loc_2BC0C:
    jsrto   (SolidObject_Always_SingleCharacter).l, JmpTo7_SolidObject_Always_SingleCharacter
    tst.w   d4
    bpl.s   return_2BC84
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  #0,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.w  #0,inertia(a1)
    move.b  #$81,obj_control(a1)
    bset    #2,status(a1)
    move.b  #$E,y_radius(a1)
    move.b  #7,x_radius(a1)
    move.b  #AniIDSonAni_Roll,anim(a1)
    move.b  #1,anim(a0)
    addq.w  #2,(a2)+
    move.w  #$78,(a2)
    move.w  a1,parent(a0)
    tst.b   subtype(a0)
    beq.s   return_2BC84
    cmpi.b  #$18,(SlotMachine_Routine).w    ; Is it the null routine?
    bne.s   return_2BC84                    ; Branch if not
    move.b  #8,(SlotMachine_Routine).w      ; => SlotMachine_Routine3
    clr.w   objoff_2E(a0)
    move.w  #-1,(SlotMachineInUse).w
    move.w  #-1,objoff_2A(a0)
 
return_2BC84:
    rts
; ===========================================================================
 
loc_2BC86:
    move.w  (SlotMachine_Reward).w,d0
    bpl.w   loc_2BD4E
    tst.w   objoff_2A(a0)
    bpl.s   +
    move.w  #$64,objoff_2A(a0)
+
    tst.w   objoff_2A(a0)
    beq.w   +
    btst    #0,(Timer_frames+1).w
    beq.w   loc_2BD48
    cmpi.w  #$10,objoff_2C(a0)
    bhs.w   loc_2BD48
    jsrto   (SingleObjLoad).l, JmpTo10_SingleObjLoad
    bne.w   loc_2BD48
    _move.b #ObjID_BombPrize,id(a1) ; load objD3
    move.l  #ObjD3_MapUnc_2B8D4,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZBonusSpike,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo6_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #4,priority(a1)
    move.w  #$1E,casino_prize_display_delay(a1)
    move.w  objoff_2E(a0),objoff_2E(a1)
    addi.w  #$90,objoff_2E(a0)
    move.w  x_pos(a0),casino_prize_machine_x_pos(a1)
    move.w  y_pos(a0),casino_prize_machine_y_pos(a1)
    move.w  objoff_2E(a1),d0
    jsrto   (CalcSine).l, JmpTo12_CalcSine
    asr.w   #1,d1
    add.w   casino_prize_machine_x_pos(a1),d1
    move.w  d1,casino_prize_x_pos(a1)
    move.w  d1,x_pos(a1)
    asr.w   #1,d0
    add.w   casino_prize_machine_y_pos(a1),d0
    move.w  d0,casino_prize_y_pos(a1)
    move.w  d0,y_pos(a1)
    lea objoff_2C(a0),a2
    move.l  a2,objoff_2A(a1)
    move.w  parent(a0),parent(a1)
    addq.w  #1,objoff_2C(a0)
    subq.w  #1,objoff_2A(a0)
+
    tst.w   objoff_2C(a0)
    beq.w   loc_2BE2E
 
loc_2BD48:
    addq.w  #1,(Bonus_Countdown_3).w
    rts
; ===========================================================================
 
loc_2BD4E:
    beq.w   +
    btst    #0,(Timer_frames+1).w
    beq.w   return_2BDF6
    cmpi.w  #$10,objoff_2C(a0)
    bhs.w   return_2BDF6
    jsrto   (SingleObjLoad).l, JmpTo10_SingleObjLoad
    bne.w   return_2BDF6
    _move.b #ObjID_RingPrize,id(a1) ; load objDC
    move.l  #Obj25_MapUnc_12382,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo6_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #8,width_pixels(a1)
    move.w  #$1A,casino_prize_display_delay(a1)
    move.w  objoff_2E(a0),objoff_2E(a1)
    addi.w  #$89,objoff_2E(a0)
    move.w  x_pos(a0),casino_prize_machine_x_pos(a1)
    move.w  y_pos(a0),casino_prize_machine_y_pos(a1)
    move.w  objoff_2E(a1),d0
    jsrto   (CalcSine).l, JmpTo12_CalcSine
    asr.w   #1,d1
    add.w   casino_prize_machine_x_pos(a1),d1
    move.w  d1,casino_prize_x_pos(a1)
    move.w  d1,x_pos(a1)
    asr.w   #1,d0
    add.w   casino_prize_machine_y_pos(a1),d0
    move.w  d0,casino_prize_y_pos(a1)
    move.w  d0,y_pos(a1)
    lea objoff_2C(a0),a2
    move.l  a2,objoff_2A(a1)
    move.w  parent(a0),parent(a1)
    addq.w  #1,objoff_2C(a0)
    subq.w  #1,(SlotMachine_Reward).w
+
    tst.w   objoff_2C(a0)
    beq.s   loc_2BE2E
 
return_2BDF6:
    rts
; ===========================================================================
 
loc_2BDF8:
    tst.b   render_flags(a0)
    bpl.s   loc_2BE2E
    tst.b   subtype(a0)
    beq.s   loc_2BE28
    move.w  a1,objoff_3E(a0)
    cmpi.b  #$18,(SlotMachine_Routine).w    ; Is it the null routine?
    beq.w   loc_2BC86                       ; Branch if yes
    move.b  (Vint_runcount+3).w,d0
    andi.w  #$F,d0
    bne.s   +   ; rts
    move.w  #SndID_CasinoBonus,d0
    jsr (PlaySound).l
+
    rts
; ===========================================================================
 
loc_2BE28:
    subq.w  #1,2(a2)
    bpl.s   loc_2BE5E
 
loc_2BE2E:
    move.w  #0,objoff_2C(a0)
    move.b  #0,anim(a0)
    move.b  #0,objoff_2A(a1)
    bclr    d6,status(a0)
    bclr    #3,status(a1)
    bset    #1,status(a1)
    move.w  #$400,y_vel(a1)
    addq.w  #2,(a2)+
    move.w  #$1E,(a2)
    rts
; ===========================================================================
 
loc_2BE5E:
    move.w  2(a2),d0
    andi.w  #$F,d0
    bne.s   +   ; rts
    move.w  #SndID_CasinoBonus,d0
    jsr (PlaySound).l
    moveq   #10,d0
    movea.w a1,a3
    jsr (AddPoints2).l
    jsrto   (SingleObjLoad).l, JmpTo10_SingleObjLoad
    bne.s   +   ; rts
    _move.b #ObjID_Points,id(a1) ; load obj29
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #0,mapping_frame(a1)
+
    rts
; ===========================================================================
 
loc_2BE9C:
    subq.w  #1,2(a2)
    bpl.s   +   ; rts
    clr.w   (a2)
    tst.b   subtype(a0)
    beq.s   +   ; rts
    clr.w   (SlotMachineInUse).w
+
    rts
; ===========================================================================
; animation script
; off_2BEB0:
Ani_objD6:  offsetTable
        offsetTableEntry.w byte_2BEB4   ; 0
        offsetTableEntry.w byte_2BEB7   ; 1
byte_2BEB4: dc.b  $F,  0,$FF
    rev02even
byte_2BEB7: dc.b   1,  1,  0,$FF
    even
; ------------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------------
ObjD6_MapUnc_2BEBC: BINCLUDE "mappings/sprite/objD6_b.bin"
; ===========================================================================
 
 
; ------------------------------------------------------------------------------
; runs the slot machines in CNZ
; ------------------------------------------------------------------------------
 
slot_rout = 0
slot_timer = 1
slot_index = 3
slots_targ = 4
slot1_targ = 4
slot23_targ = 5
slots_data = 6
slot1_index = slots_data
slot1_offset = slots_data+1
slot1_speed = slots_data+2
slot1_rout = slots_data+3
slot2_index = slots_data+4
slot2_offset = slots_data+5
slot2_speed = slots_data+6
slot2_rout = slots_data+7
slot3_index = slots_data+8
slot3_offset = slots_data+9
slot3_speed = slots_data+10
slot3_rout = slots_data+11
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_2BF24:
SlotMachine:
    lea (SlotMachineVariables).w,a4
    moveq   #0,d0
    _move.b slot_rout(a4),d0
    jmp SlotMachine_JmpTable(pc,d0.w)
; ===========================================================================
; loc_2BF32:
SlotMachine_JmpTable: ;;
    bra.w   SlotMachine_Routine1        ; $00
    bra.w   SlotMachine_Routine2        ; $04
    bra.w   SlotMachine_Routine3        ; $08
    bra.w   SlotMachine_Routine4        ; $0C
    bra.w   SlotMachine_Routine5        ; $10
    bra.w   SlotMachine_Routine6        ; $14
    rts                                 ; $18
; ===========================================================================
; loc_2BF4C:
SlotMachine_Routine1:
    movea.l a4,a1                       ; Copy destination
 
    moveq   #8,d0                       ; 18 bytes, in words
-   clr.w   (a1)+
    dbf d0,-
 
    move.b  (Vint_runcount+3).w,d0      ; 'Random' seed
    move.b  d0,slot1_index(a4)          ; Only last 3 bits matter
    ror.b   #3,d0                       ; Remove last 3 bits
    move.b  d0,slot2_index(a4)          ; Again, only last 3 bits matter
    ror.b   #3,d0                       ; Remove 3 more bits (only have 2 bits now!)
    move.b  d0,slot3_index(a4)          ; Only 3 bits matter, but we only have 2 anyway
    move.b  #8,slot1_offset(a4)         ; This will set a draw from start of tile
    move.b  #8,slot2_offset(a4)         ; This will set a draw from start of tile
    move.b  #8,slot3_offset(a4)         ; This will set a draw from start of tile
    move.b  #8,slot1_speed(a4)          ; Initial rolling speed
    move.b  #8,slot2_speed(a4)          ; Initial rolling speed
    move.b  #8,slot3_speed(a4)          ; Initial rolling speed
    move.b  #1,slot_timer(a4)           ; Roll each slot once
    _addq.b #4,slot_rout(a4)            ; => SlotMachine_Routine2
    rts
; ===========================================================================
; loc_2BF9A:
SlotMachine_Routine2:
    bsr.w   SlotMachine_DrawSlot        ; Draw the slots
    tst.b   slot_timer(a4)              ; Are we still rolling?
    beq.s   +                           ; Branch if not
    rts
; ===========================================================================
+
    _move.b #$18,slot_rout(a4)          ; => null routine (rts)
    clr.w   slot1_speed(a4)             ; Stop slot 1
    clr.w   slot2_speed(a4)             ; Stop slot 2
    clr.w   slot3_speed(a4)             ; Stop slot 3
    rts
; ===========================================================================
; loc_2BFBA:
SlotMachine_Routine3:
    move.b  (Vint_runcount+3).w,d0      ; 'Random' seed
    andi.b  #7,d0                       ; Only want last 3 bits
    subq.b  #4,d0                       ; Subtract 4...
    addi.b  #$30,d0                     ; ... then add $30 (why not just add $2C?)
    move.b  d0,slot1_speed(a4)          ; This is our starting speed for slot 1
    move.b  (Vint_runcount+3).w,d0      ; 'Random' seed
    rol.b   #4,d0                       ; Get top nibble...
    andi.b  #7,d0                       ; ... but discard what was the sign bit
    subq.b  #4,d0                       ; Subtract 4...
    addi.b  #$30,d0                     ; ... then add $30 (why not just add $2C?)
    move.b  d0,slot2_speed(a4)          ; This is our starting speed for slot 2
    move.b  (Vint_runcount+2).w,d0      ; 'Random' seed
    andi.b  #7,d0                       ; Only want last 3 bits
    subq.b  #4,d0                       ; Subtract 4...
    addi.b  #$30,d0                     ; ... then add $30 (why not just add $2C?)
    move.b  d0,slot3_speed(a4)          ; This is our starting speed for slot 3
    move.b  #2,slot_timer(a4)           ; Roll each slot twice under these conditions
    clr.b   slot_index(a4)              ; => SlotMachine_Subroutine1
    clr.b   slot1_rout(a4)              ; => SlotMachine_Routine5_1
    clr.b   slot2_rout(a4)              ; => SlotMachine_Routine5_1
    clr.b   slot3_rout(a4)              ; => SlotMachine_Routine5_1
    _addq.b #4,slot_rout(a4)            ; => SlotMachine_Routine4
    move.b  (Vint_runcount+3).w,d0      ; 'Random' seed
    ror.b   #3,d0                       ; Mess it around
    lea (SlotTargetValues).l,a2
 
-   sub.b   (a2),d0                     ; Subtract from random seed
    bcs.s   +                           ; Branch if result is less than zero
    addq.w  #3,a2                       ; Advance 3 bytes
    bra.s   -                           ; Keep looping
; ===========================================================================
+
    cmpi.b  #-1,(a2)                    ; Is the previous value -1?
    beq.s   +                           ; Branch if yes (end of array)
    move.b  1(a2),slot1_targ(a4)        ; Target value for slot 1
    move.b  2(a2),slot23_targ(a4)       ; Target values for slots 2 and 3
    rts
; ===========================================================================
+
    move.b  d0,d1                       ; Copy our 'random' value
    andi.w  #7,d1                       ; Want only last 3 bits
    lea (SlotSequence1).l,a1            ; Slot sequence array for slot 1
    move.b  (a1,d0.w),slot1_targ(a4)    ; Uhhh... use d0 as array index? This should have been d1! Anyway, set slot 1 target
    ror.b   #3,d0                       ; Rotate it
    move.b  d0,d1                       ; Copy it
    andi.w  #7,d1                       ; Want only last 3 bits
    lea (SlotSequence2).l,a1            ; Slot sequence array for slot 2
    move.b  (a1,d1.w),d2                ; Use as array index
    lsl.b   #4,d2                       ; Move to high nibble
    ror.b   #3,d0                       ; Rotate it again
    andi.w  #7,d0                       ; Want only last 3 bits
    lea (SlotSequence3).l,a1            ; Slot sequence array for slot 3
    or.b    (a1,d0.w),d2                ; Combine with earlier value
    move.b  d2,slot23_targ(a4)          ; Target values for slots 2 and 3
    rts
; ===========================================================================
; loc_2C070:
SlotMachine_Routine4:
    bsr.w   SlotMachine_DrawSlot
    tst.b   slot_timer(a4)              ; Are slots still going?
    beq.s   +                           ; Branch if not
    rts
; ===========================================================================
+
    addi.b  #$30,slot1_speed(a4)        ; Increase slot 1 speed
    addi.b  #$30,slot2_speed(a4)        ; Increase slot 2 speed
    addi.b  #$30,slot3_speed(a4)        ; Increase slot 3 speed
    move.b  (Vint_runcount+3).w,d0      ; 'Random' seed
    andi.b  #$F,d0                      ; Want only low nibble
    addi.b  #$C,d0                      ; Increase by $C
    move.b  d0,slot_timer(a4)           ; New value for slot timer
    clr.b   2(a4)                       ; Clear otherwise unused variable
    _addq.b #4,slot_rout(a4)            ; => SlotMachine_Routine5
    rts
; ===========================================================================
; loc_2C0A8:
SlotMachine_Routine5:
    bsr.w   SlotMachine_DrawSlot
    cmpi.b  #$C,slot1_rout(a4)          ; Is slot done?
    bne.s   +                           ; Branch if not
    cmpi.b  #$C,slot2_rout(a4)          ; Is slot done?
    bne.s   +                           ; Branch if not
    cmpi.b  #$C,slot3_rout(a4)          ; Is slot done?
    beq.w   SlotMachine_Routine6        ; Branch if yes
+
    moveq   #0,d0                       ; Clear d0
    move.b  slot_index(a4),d0           ; Get current slot index
    lea slots_data(a4),a1               ; a1 = pointer to slots data
    adda.w  d0,a1                       ; a1 = pointer to current slot data
    lea (SlotSequence1).l,a3            ; Get pointer to slot sequences
    add.w   d0,d0                       ; Turn into index
    adda.w  d0,a3                       ; Get sequence for this slot
    moveq   #0,d0                       ; Clear d0 again
    move.b  slot1_rout-slot1_index(a1),d0   ; Slot routine
    jmp SlotMachine_Routine5_JmpTable(pc,d0.w)
; ===========================================================================
; loc_2C0E6
SlotMachine_Routine5_JmpTable: ;;
    bra.w   SlotMachine_Routine5_1      ; $00
    bra.w   SlotMachine_Routine5_2      ; $04
    bra.w   SlotMachine_Routine5_3      ; $08
    bra.w   SlotMachine_Routine5_4      ; $0C
; ===========================================================================
;loc_2C0F6
SlotMachine_GetTargetForSlot:
    move.w  slots_targ(a4),d1           ; Get target slot faces
    move.b  slot_index(a4),d0           ; Get current slot index
    beq.s   +                           ; Branch if zero
    lsr.w   d0,d1                       ; Shift slot face into position
+
    andi.w  #7,d1                       ; Only 8 slot faces
    cmpi.b  #5,d1                       ; Is this above bar?
    bgt.s   +                           ; Branch if yes
    rts
; ===========================================================================
+
    subq.b  #2,d1                       ; Wrap back to ring/bar
    rts
; ===========================================================================
;loc_2C112
SlotMachine_ChangeTarget:
    move.w  #$FFF0,d2                   ; Kept faces mask
    andi.w  #$F,d1                      ; New slot target
    move.b  slot_index(a4),d0           ; Get current slot
    beq.s   +                           ; Branch if it is slot 0
    lsl.w   d0,d1                       ; Shift new slot target into position
    rol.w   d0,d2                       ; Shift kept faces mask into position
+
    and.w   d2,slots_targ(a4)           ; Mask off current slot
    or.w    d1,slots_targ(a4)           ; Put in new value for it
    andi.w  #$777,slots_targ(a4)        ; Slots are only 0-7
    rts
; ===========================================================================
; loc_2C134:
SlotMachine_Routine5_1:
    tst.b   slot_index(a4)              ; Is this slot 1?
    bne.s   +                           ; Branch if not
    tst.b   slot_timer(a4)              ; Is timer positive or zero?
    bmi.s   ++                          ; Branch if not
    rts
; ===========================================================================
+
    cmpi.b  #8,slot1_rout-slot2_index(a1)   ; Is previous slot in state SlotMachine_Routine5_3 or SlotMachine_Routine5_4?
    bge.s   +                           ; Branch if yes
    rts
; ===========================================================================
+
    bsr.s   SlotMachine_GetTargetForSlot
    move.w  (a1),d0                     ; Get current slot index/offset
    subi.w  #$A0,d0                     ; Subtract 20 lines (2.5 tiles) from it
    lsr.w   #8,d0                       ; Get effective slot index
    andi.w  #7,d0                       ; Only want 3 bits
    move.b  (a3,d0.w),d0                ; Get face from sequence
    cmp.b   d1,d0                       ; Are we close to target?
    beq.s   +                           ; Branch if yes
    rts
; ===========================================================================
+
    addq.b  #4,slot1_rout-slot1_index(a1)   ; => SlotMachine_Routine5_2
    move.b  #$60,slot1_speed-slot1_index(a1)    ; Decrease slot speed
    rts
; ===========================================================================
; loc_2C170:
SlotMachine_Routine5_2:
    bsr.s   SlotMachine_GetTargetForSlot
    move.w  (a1),d0                     ; Get current slot index/offset
    addi.w  #$F0,d0                     ; Add 30 lines (3.75 tiles) to it
    andi.w  #$700,d0                    ; Limit to 8 faces
    lsr.w   #8,d0                       ; Get effective slot index
    move.b  (a3,d0.w),d0                ; Get face from sequence
    cmp.b   d0,d1                       ; Are we this close to target?
    beq.s   loc_2C1AE                   ; Branch if yes
    cmpi.b  #$20,slot1_speed-slot1_index(a1)    ; Is slot speed more than $20?
    bls.s   +                           ; Branch if not
    subi.b  #$C,slot1_speed-slot1_index(a1)     ; Reduce slot speed
+
    cmpi.b  #$18,slot1_speed-slot1_index(a1)    ; Is slot speed $18 or less?
    bgt.s   +                           ; Branch if not
    rts
; ===========================================================================
+
    cmpi.b  #$80,slot1_offset-slot1_index(a1)   ; Is offset $80 or less?
    bls.s   +                           ; Branch if yes
    rts
; ===========================================================================
+
    subq.b  #2,slot1_speed-slot1_index(a1)      ; Reduce slot speed
    rts
; ===========================================================================
 
loc_2C1AE:
    move.w  (a1),d0                     ; Get current slot index/offset
    addi.w  #$80,d0                     ; Subtract 16 lines (2 tiles) to it
    move.w  d0,d1                       ; Copy to d1
    andi.w  #$700,d1                    ; Limit to 8 faces
    subi.w  #$10,d1                     ; Subtract 2 lines (1/4 tile) from it
    move.w  d1,(a1)                     ; Store new value for index/offset
    lsr.w   #8,d0                       ; Convert to index
    andi.w  #7,d0                       ; Limit to 8 faces
    move.b  (a3,d0.w),d1                ; Get face from sequence
    bsr.w   SlotMachine_ChangeTarget    ; Set slot index to face number, indtead of sequence index
    move.b  #-8,slot1_speed-slot1_index(a1) ; Rotate slowly on the other direction
    addq.b  #4,slot1_rout-slot1_index(a1)   ; => SlotMachine_Routine5_3
    rts
; ===========================================================================
; loc_2C1DA:
SlotMachine_Routine5_3:
    tst.b   slot1_offset-slot1_index(a1)    ; Is offset zero?
    beq.s   +                           ; Branch if yes
    rts
; ===========================================================================
+
    clr.b   slot1_speed-slot1_index(a1) ; Stop slot
    addq.b  #4,slot1_rout-slot1_index(a1)   ; => SlotMachine_Routine5_4
    rts
; ===========================================================================
; return_2C1EC:
SlotMachine_Routine5_4:
    rts
; ===========================================================================
; loc_2C1EE:
SlotMachine_Routine6:
    clr.w   slot1_speed(a4)         ; Stop slot 1
    clr.w   slot2_speed(a4)         ; Stop slot 2
    clr.w   slot3_speed(a4)         ; Stop slot 3
    clr.b   slot_timer(a4)          ; Stop drawing the slots
    bsr.w   SlotMachine_ChooseReward
    _move.b #$18,slot_rout(a4)      ; => null routine (rts)
    rts
; ===========================================================================
; loc_2C20A
SlotMachine_DrawSlot:
    moveq   #0,d0                   ; Clear d0
    move.b  slot_index(a4),d0       ; d0 = index of slot to draw
    lea slots_data(a4),a1           ; a1 = pointer to slots data
    adda.w  d0,a1                   ; a1 = pointer to current slot data
    lea (SlotSequence1).l,a3        ; Get slot sequence
    adda.w  d0,a3                   ; Add offset...
    adda.w  d0,a3                   ; ... twice
    jmp BranchTo_SlotMachine_Subroutine(pc,d0.w)
; ===========================================================================
 
BranchTo_SlotMachine_Subroutine 
    bra.w   SlotMachine_Subroutine1     ; $00
    bra.w   SlotMachine_Subroutine2     ; $04
;   bra.w   SlotMachine_Subroutine3     ; $08
;SlotMachine_Subroutine3:
    clr.b   slot_index(a4)          ; => SlotMachine_Subroutine1
    subq.b  #1,slot_timer(a4)       ; Decrease timer
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_CNZSlotPics_3),d2    ; DMA destination
    bra.s   +
; ===========================================================================
; loc_2C23A:
SlotMachine_Subroutine1:
    addq.b  #4,slot_index(a4)       ; => SlotMachine_Subroutine2
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_CNZSlotPics_1),d2    ; DMA destination
    bra.w   +
; ===========================================================================
; loc_2C246:
SlotMachine_Subroutine2:
    addq.b  #4,slot_index(a4)       ; => SlotMachine_Subroutine3
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_CNZSlotPics_2),d2    ; DMA destination
+
    move.w  (a1),d0                 ; Get last pixel offset
    move.b  2(a1),d1                ; Get slot rotation speed
    ext.w   d1                      ; Extend to word
    sub.w   d1,(a1)                 ; Modify pixel offset
    move.w  (a1),d3                 ; Get current pixel offset
    andi.w  #$7F8,d0                ; Get only desired bits of last pixel offset
    andi.w  #$7F8,d3                ; Get only desired bits of current pixel offset
    cmp.w   d0,d3                   ; Are those equal?
    bne.s   +                       ; Branch if not (need new picture)
    rts
; ---------------------------------------------------------------------------
+
    bsr.w   SlotMachine_GetPixelRow ; Get pointer to pixel row
    lea (Block_Table+$1000).w,a1    ; Destination for pixel rows
 
    move.w  #4*8-1,d1               ; Slot picture is 4 tiles
-   move.l  $80(a2),$80(a1)         ; Copy pixel row for second column
    move.l  $100(a2),$100(a1)       ; Copy pixel row for third column
    move.l  $180(a2),$180(a1)       ; Copy pixel row for fourth column
    move.l  (a2)+,(a1)+             ; Copy pixel row for first column, advance destination to next line
    addq.b  #8,d3                   ; Increase offset by 8 (byte operation)
    bne.s   +                       ; If the result is not zero, branch
    addi.w  #$100,d3                ; Advance to next slot picture
    andi.w  #$700,d3                ; Limit the sequence to 8 pictures
    bsr.w   SlotMachine_GetPixelRow ; Need pointer to next pixel row
+
    dbf d1,-                        ; Loop for aoo pixel rows
 
    move.l  #(Block_Table+$1000)&$FFFFFF,d1 ; Source
    tst.w   (Two_player_mode).w
    beq.s   +
    addi.w  #tiles_to_bytes(ArtTile_ArtUnc_CNZSlotPics_1_2p-ArtTile_ArtUnc_CNZSlotPics_1),d2
+
    move.w  #$100,d3                        ; Number of bytes
    jsr (QueueDMATransfer).l
    rts
; ===========================================================================
; loc_2C2B8
SlotMachine_GetPixelRow:
    move.w  d3,d0                   ; d0 = pixel offset into slot picture
    lsr.w   #8,d0                   ; Convert offset into index
    andi.w  #7,d0                   ; Limit each sequence to 8 pictures
    move.b  (a3,d0.w),d0            ; Get slot pic id
    andi.w  #7,d0                   ; Get only lower 3 bits; leaves space for 2 more images
    ror.w   #7,d0                   ; Equal to shifting left 9 places, or multiplying by 4*4 tiles, in bytes
    lea (ArtUnc_CNZSlotPics).l,a2   ; Load slot pictures
    adda.w  d0,a2                   ; a2 = pointer to first tile of slot picture
    move.w  d3,d0                   ; d0 = d3
    andi.w  #$F8,d0                 ; Strip high word (picture index)
    lsr.w   #1,d0                   ; Convert into bytes
    adda.w  d0,a2                   ; a2 = pointer to desired pixel row
    rts
; ==========================================================================
; loc_2C2DE:
SlotMachine_ChooseReward:
    move.b  slot23_targ(a4),d2      ; Get slots 2 and 3
    move.b  d2,d3                   ; Copy to d3
    andi.w  #$F0,d2                 ; Strip off slot 3 nibble
    lsr.w   #4,d2                   ; Shift slot 2 to position
    andi.w  #$F,d3                  ; Strip off slot 2 nibble
    moveq   #0,d0                   ; Clear d0
    cmp.b   slot1_targ(a4),d2       ; Are slots 1 and 2 equal?
    bne.s   +                       ; Branch if not
    addq.w  #4,d0
+
    cmp.b   slot1_targ(a4),d3       ; Are slots 1 and 3 equal?
    bne.s   +                       ; Branch if not
    addq.w  #8,d0
+
    jmp SlotMachine_ChooseReward_JmpTable(pc,d0.w)
; ==========================================================================
; loc_2C304:
SlotMachine_ChooseReward_JmpTable: ;;
    bra.w   SlotMachine_Unmatched1  ; $00
    bra.w   SlotMachine_Match12     ; $04
    bra.w   SlotMachine_Match13     ; $08
; ==========================================================================
; SlotMachine_TripleMatch:
    move.w  d2,d0                   ; d0 = reward index
    bsr.w   SlotMachine_GetReward
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
;loc_2C31C
SlotMachine_Match13:
    cmpi.b  #3,d3                   ; is slot 3 a jackpot?
    bne.s   +                       ; Branch if not
    move.w  d2,d0                   ; Slot 2 is reward index
    bsr.w   SlotMachine_GetReward
    bsr.w   SlotMachine_QuadrupleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
+
    cmpi.b  #3,d2                   ; Is slot 2 a jackpot?
    bne.w   SlotMachine_Unmatched1  ; Branch if not
    move.w  d3,d0                   ; Slot 3 is reward index
    bsr.w   SlotMachine_GetReward
    bsr.w   SlotMachine_DoubleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
;loc_2C34A
SlotMachine_Match12:
    cmpi.b  #3,d2                   ; Is slot 2 a jackpot?
    bne.s   +                       ; Branch if not
    move.w  d3,d0                   ; Slot 3 is reward index
    bsr.s   SlotMachine_GetReward
    bsr.w   SlotMachine_QuadrupleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
+
    cmpi.b  #3,d3                   ; Is slot 3 a jackpot?
    bne.w   SlotMachine_Unmatched1  ; Branch if not
    move.w  d2,d0                   ; Slot 2 is reward index
    bsr.s   SlotMachine_GetReward
    bsr.w   SlotMachine_DoubleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
;loc_2C374
SlotMachine_Unmatched1:
    cmp.b   d2,d3                   ; Are slots 2 and 3 equal?
    bne.s   SlotMachine_CheckBars   ; Branch if not
    cmpi.b  #3,slot1_targ(a4)       ; Is slot 1 a jackpot?
    bne.s   +                       ; Branch if not
    move.w  d2,d0                   ; Use slot 2 as reward index
    bsr.s   SlotMachine_GetReward
    bsr.w   SlotMachine_DoubleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
+
    cmpi.b  #3,d2                   ; Is slot 2 a jackpot?
    bne.s   SlotMachine_CheckBars   ; Branch if not
    move.b  slot1_targ(a4),d0       ; Get slot 1 face
    andi.w  #$F,d0                  ; Strip high nibble
    bsr.s   SlotMachine_GetReward
    bsr.w   SlotMachine_QuadrupleUp
    move.w  d0,slots_targ(a4)       ; Store reward
    rts
; ===========================================================================
;loc_2C3A8
SlotMachine_CheckBars:
    moveq   #2,d1                   ; Number of rings per bar
    moveq   #0,d0                   ; Start with zero
    cmpi.b  #5,slot1_targ(a4)       ; Is slot 1 a bar?
    bne.s   +                       ; Branch if not
    add.w   d1,d0                   ; Gain 2 rings
+
    cmpi.b  #5,d2                   ; Is slot 2 a bar?
    bne.s   +                       ; Branch if not
    add.w   d1,d0                   ; Gain 2 rings
+
    cmpi.b  #5,d3                   ; Is slot 3 a bar?
    bne.s   +                       ; Branch if not
    add.w   d1,d0                   ; Gain 2 rings
+
    move.w  d0,slots_targ(a4)       ; Store reward
    ; For bars, the code past this line is useless. There should be an rts here.
 
;loc_2C3CA
SlotMachine_GetReward:
    add.w   d0,d0                   ; Convert to index
    lea (SlotRingRewards).l,a2      ; Ring reward array
    move.w  (a2,d0.w),d0            ; Get ring reward
    rts
; ===========================================================================
;loc_2C3D8
SlotMachine_QuadrupleUp:
    asl.w   #2,d0                   ; Quadruple reward
    rts
; ===========================================================================
;loc_2C3DC
SlotMachine_DoubleUp:
    add.w   d0,d0                   ; Double reward
    rts
 
; ===========================================================================
; data for the slot machines
;byte_2C3E0
SlotRingRewards:    dc.w   30,  25,  -1, 150,  10,  20
    rev02even
;byte_2C3EC
SlotTargetValues:   dc.b   8, 3,$33,  $12, 0,$00,  $12, 1,$11  ,$24, 2,$22
                    dc.b $1E, 4,$44,  $1E, 5,$55,  $FF,$F,$FF
    rev02even
;byte_2C401
SlotSequence1:  dc.b   3,  0,  1,  4,  2,  5,  4,  1
    rev02even
;byte_2C409
SlotSequence2:  dc.b   3,  0,  1,  4,  2,  5,  0,  2
    rev02even
;byte_2C411
SlotSequence3:  dc.b   3,  0,  1,  4,  2,  5,  4,  1
    even
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo10_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo29_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo10_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo6_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo54_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo12_CalcSine 
    jmp (CalcSine).l
JmpTo7_SolidObject_Always_SingleCharacter 
    jmp (SolidObject_Always_SingleCharacter).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D7 - Bumper from Casino Night Zone
; ----------------------------------------------------------------------------
; Sprite_2C448:
ObjD7:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD7_Index(pc,d0.w),d1
    jmp ObjD7_Index(pc,d1.w)
; ===========================================================================
; off_2C456:
ObjD7_Index:    offsetTable
        offsetTableEntry.w ObjD7_Init   ; 0
        offsetTableEntry.w ObjD7_Main   ; 2
; ===========================================================================
; loc_2C45A:
ObjD7_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD7_MapUnc_2C626,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZHexBumper,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo55_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  #$CA,collision_flags(a0)
    btst    #0,status(a0)
    beq.s   +
    move.b  #1,objoff_34(a0)
+
    move.w  x_pos(a0),d0
    move.w  d0,d1
    subi.w  #$60,d0
    move.w  d0,objoff_30(a0)
    addi.w  #$60,d1
    move.w  d1,objoff_32(a0)
; loc_2C4AC:
ObjD7_Main:
    move.b  collision_property(a0),d0
    beq.w   ObjD7_MainContinued
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #0,collision_property(a0)
    beq.s   +
    bsr.s   ObjD7_BouncePlayerOff
+
    lea (Sidekick).w,a1 ; a1=character
    bclr    #1,collision_property(a0)
    beq.s   +
    bsr.s   ObjD7_BouncePlayerOff
+
    clr.b   collision_property(a0)
    bra.w   ObjD7_MainContinued
; ===========================================================================
; loc_2C4D8:
ObjD7_BouncePlayerOff:
    move.w  x_pos(a0),d1
    move.w  y_pos(a0),d2
    sub.w   x_pos(a1),d1
    sub.w   y_pos(a1),d2
    jsr (CalcAngle).l
    addi.b  #$20,d0
    andi.w  #$C0,d0
    cmpi.w  #$40,d0
    beq.s   ObjD7_BounceDown
    cmpi.w  #$80,d0
    beq.s   ObjD7_BounceRight
    cmpi.w  #$C0,d0
    beq.s   ObjD7_BounceUp
    move.w  #-$800,x_vel(a1)
    move.b  #2,anim(a0)
    bra.s   ObjD7_BounceEnd
; ===========================================================================
; loc_2C516:
ObjD7_BounceDown:
    subi.w  #$200,x_vel(a1)
    tst.w   d1
    bpl.s   +
    addi.w  #$400,x_vel(a1)
+
    move.w  #-$800,y_vel(a1)
    move.b  #1,anim(a0)
    bra.s   ObjD7_BounceEnd
; ===========================================================================
; loc_2C534:
ObjD7_BounceRight:
    move.w  #$800,x_vel(a1)
    move.b  #2,anim(a0)
    bra.s   ObjD7_BounceEnd
; ===========================================================================
; loc_2C542:
ObjD7_BounceUp:
    subi.w  #$200,x_vel(a1)
    tst.w   d1
    bpl.s   +
    addi.w  #$400,x_vel(a1)
+
    move.w  #$800,y_vel(a1)
    move.b  #1,anim(a0)
; loc_2C55E:
ObjD7_BounceEnd:
    bset    #1,status(a1)
    bclr    #4,status(a1)
    bclr    #5,status(a1)
    clr.b   jumping(a1)
    move.w  #SndID_Bumper,d0
    jmp (PlaySound).l
; ===========================================================================
; loc_2C57E:
ObjD7_MainContinued:
    lea (Ani_objD7).l,a1
    jsrto   (AnimateSprite).l, JmpTo11_AnimateSprite
    tst.b   subtype(a0)
    beq.w   JmpTo30_MarkObjGone
    tst.b   objoff_34(a0)
    beq.s   loc_2C5AE
    move.w  x_pos(a0),d0
    subq.w  #1,d0
    cmp.w   objoff_30(a0),d0
    bne.s   +
    move.b  #0,objoff_34(a0)
+
    move.w  d0,x_pos(a0)
    bra.s   loc_2C5C4
; ===========================================================================
 
loc_2C5AE:
    move.w  x_pos(a0),d0
    addq.w  #1,d0
    cmp.w   objoff_32(a0),d0
    bne.s   +
    move.b  #1,objoff_34(a0)
+
    move.w  d0,x_pos(a0)
 
loc_2C5C4:
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite).l, JmpTo30_DisplaySprite
; ---------------------------------------------------------------------------
+
    move.w  objoff_30(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bls.s   +
    move.w  objoff_32(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.s   loc_2C5F8
+
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_2C5F8:
    lea (Object_Respawn_Table).w,a2
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a2,d0.w)
+
    jmp (DeleteObject).l
 
    if removeJmpTos
JmpTo30_MarkObjGone 
    jmp (MarkObjGone).l
    endif
; ===========================================================================
; animation script
; off_2C610:
Ani_objD7:  offsetTable
        offsetTableEntry.w byte_2C616   ; 0
        offsetTableEntry.w byte_2C619   ; 1
        offsetTableEntry.w byte_2C61F   ; 2
byte_2C616: dc.b  $F,  0,$FF
    rev02even
byte_2C619: dc.b   3,  1,  0,  1,$FD,  0
    rev02even
byte_2C61F: dc.b   3,  2,  0,  2,$FD,  0
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD7_MapUnc_2C626: BINCLUDE "mappings/sprite/objD7.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo30_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo30_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo11_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo55_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D8 - Block thingy from CNZ that disappears after 3 hits (UFO saucer-shaped)
; ----------------------------------------------------------------------------
; Sprite_2C6AC:
ObjD8:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD8_Index(pc,d0.w),d1
    jmp ObjD8_Index(pc,d1.w)
; ===========================================================================
; off_2C6BA:
ObjD8_Index:    offsetTable
        offsetTableEntry.w ObjD8_Init   ; 0
        offsetTableEntry.w loc_2C6FC    ; 2
        offsetTableEntry.w loc_2C884    ; 4
; ===========================================================================
; loc_2C6C0:
ObjD8_Init:
    addq.b  #2,routine(a0)
    move.l  #ObjD8_MapUnc_2C8C4,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZMiniBumper,2,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo56_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #1,priority(a0)
    move.b  #$D7,collision_flags(a0)
    move.b  subtype(a0),d0
    rol.b   #2,d0
    andi.b  #3,d0
    move.b  d0,anim(a0)
 
loc_2C6FC:
    move.b  collision_property(a0),d0
    bne.w   loc_2C70A
    tst.w   objoff_30(a0)
    beq.s   loc_2C740
 
loc_2C70A:
    lea objoff_30(a0),a4
    tst.b   (a4)
    beq.s   loc_2C716
    subq.b  #1,(a4)
    bra.s   loc_2C724
; ===========================================================================
 
loc_2C716:
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #0,collision_property(a0)
    beq.s   loc_2C724
    bsr.s   loc_2C74E
 
loc_2C724:
    addq.w  #1,a4
    tst.b   (a4)
    beq.s   loc_2C72E
    subq.b  #1,(a4)
    bra.s   loc_2C73C
; ===========================================================================
 
loc_2C72E:
    lea (Sidekick).w,a1 ; a1=character
    bclr    #1,collision_property(a0)
    beq.s   loc_2C73C
    bsr.s   loc_2C74E
 
loc_2C73C:
    clr.b   collision_property(a0)
 
loc_2C740:
    lea (Ani_objD8).l,a1
    jsrto   (AnimateSprite).l, JmpTo12_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo31_MarkObjGone
; ===========================================================================
 
loc_2C74E:
    move.b  mapping_frame(a0),d0
    subq.b  #3,d0
    beq.s   loc_2C75C
    bcc.s   loc_2C77A
    addq.b  #3,d0
    bne.s   loc_2C77A
 
loc_2C75C:
    move.b  #3,anim(a0)
    move.w  #-$700,y_vel(a1)
    move.w  y_pos(a0),d2
    sub.w   y_pos(a1),d2
    bpl.s   BranchTo_loc_2C806
    neg.w   y_vel(a1)
 
BranchTo_loc_2C806 
    bra.w   loc_2C806
; ===========================================================================
 
loc_2C77A:
    subq.b  #1,d0
    bne.s   loc_2C7EC
    move.b  #4,anim(a0)
    move.w  #$20,d3
    btst    #0,status(a0)
    bne.s   loc_2C794
    move.w  #$60,d3
 
loc_2C794:
    move.w  x_vel(a1),d1
    move.w  y_vel(a1),d2
    jsr (CalcAngle).l
    sub.w   d3,d0
    mvabs.w d0,d1
    neg.w   d0
    add.w   d3,d0
    cmpi.b  #$40,d1
    bhs.s   loc_2C7BE
    cmpi.b  #$38,d1
    blo.s   loc_2C7D0
    move.w  d3,d0
    bra.s   loc_2C7D0
; ===========================================================================
 
loc_2C7BE:
    subi.w  #$80,d1
    neg.w   d1
    cmpi.b  #$38,d1
    blo.s   loc_2C7D0
    move.w  d3,d0
    addi.w  #$80,d0
 
loc_2C7D0:
    jsr (CalcSine).l
    muls.w  #-$700,d1
    asr.l   #8,d1
    move.w  d1,x_vel(a1)
    muls.w  #-$700,d0
    asr.l   #8,d0
    move.w  d0,y_vel(a1)
    bra.s   loc_2C806
; ===========================================================================
 
loc_2C7EC:
    move.b  #5,anim(a0)
    move.w  #-$700,x_vel(a1)
    move.w  x_pos(a0),d2
    sub.w   x_pos(a1),d2
    bpl.s   loc_2C806
    neg.w   x_vel(a1)
 
loc_2C806:
    bset    #1,status(a1)
    bclr    #4,status(a1)
    bclr    #5,status(a1)
    clr.b   jumping(a1)
    move.w  #SndID_BonusBumper,d0
    jsr (PlaySound).l
    movea.w a1,a3
    moveq   #4,d3
    moveq   #1,d0
    subi.w  #palette_line_1,art_tile(a0)
    bcc.s   loc_2C85C
    addi.w  #palette_line_1,art_tile(a0)
    move.b  #4,routine(a0)
    lea (CNZ_saucer_data).w,a1
    move.b  subtype(a0),d1
    andi.w  #$3F,d1     ; This means CNZ_saucer_data is only $40 bytes large
    lea (a1,d1.w),a1
    addq.b  #1,(a1)
    cmpi.b  #3,(a1)
    blo.s   loc_2C85C
    moveq   #2,d3
    moveq   #50,d0
 
loc_2C85C:
    jsr (AddPoints2).l
    jsrto   (SingleObjLoad).l, JmpTo11_SingleObjLoad
    bne.s   loc_2C87E
    _move.b #ObjID_Points,id(a1) ; load obj29
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  d3,mapping_frame(a1)
 
loc_2C87E:
    move.b  #4,(a4)
    rts
; ===========================================================================
 
loc_2C884:
    lea (Ani_objD8).l,a1
    jsrto   (AnimateSprite).l, JmpTo12_AnimateSprite
    cmpi.b  #3,anim(a0)
    blo.w   JmpTo46_DeleteObject
    jmpto   (MarkObjGone).l, JmpTo31_MarkObjGone
 
    if removeJmpTos
JmpTo46_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; animation script
; off_2C89C:
Ani_objD8:  offsetTable
        offsetTableEntry.w byte_2C8A8   ; 0
        offsetTableEntry.w byte_2C8AB   ; 1
        offsetTableEntry.w byte_2C8AE   ; 2
        offsetTableEntry.w byte_2C8B1   ; 3
        offsetTableEntry.w byte_2C8B7   ; 4
        offsetTableEntry.w byte_2C8BD   ; 5
byte_2C8A8: dc.b  $F,  0,$FF
    rev02even
byte_2C8AB: dc.b  $F,  1,$FF
    rev02even
byte_2C8AE: dc.b  $F,  2,$FF
    rev02even
byte_2C8B1: dc.b   3,  3,  0,  3,$FD,  0
    rev02even
byte_2C8B7: dc.b   3,  4,  1,  4,$FD,  1
    rev02even
byte_2C8BD: dc.b   3,  5,  2,  5,$FD,  2
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjD8_MapUnc_2C8C4: BINCLUDE "mappings/sprite/objD8.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo46_DeleteObject 
    jmp (DeleteObject).l
JmpTo11_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo31_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo12_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo56_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object D9 - Invisible sprite that you can hang on to, like the blocks in WFZ
; ----------------------------------------------------------------------------
; Sprite_2C92C:
ObjD9:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjD9_Index(pc,d0.w),d1
    jmp ObjD9_Index(pc,d1.w)
; ===========================================================================
; off_2C93A:
ObjD9_Index:    offsetTable
        offsetTableEntry.w ObjD9_Init   ; 0
        offsetTableEntry.w ObjD9_Main   ; 2
; ===========================================================================
; loc_2C93E:
ObjD9_Init:
    addq.b  #2,routine(a0)
    move.b  #4,render_flags(a0)
    move.b  #$18,width_pixels(a0)
    move.b  #4,priority(a0)
; loc_2C954:
ObjD9_Main:
    lea objoff_30(a0),a2
    lea (MainCharacter).w,a1 ; a1=character
    move.w  (Ctrl_1).w,d0
    bsr.s   ObjD9_CheckCharacter
    lea (Sidekick).w,a1 ; a1=character
    addq.w  #1,a2
    move.w  (Ctrl_2).w,d0
    bsr.s   ObjD9_CheckCharacter
    jmpto   (MarkObjGone3).l, JmpTo7_MarkObjGone3
; ===========================================================================
; loc_2C972:
ObjD9_CheckCharacter:
    tst.b   (a2)
    beq.s   loc_2C9A0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   ObjD9_CheckCharacter_End
    clr.b   obj_control(a1)
    clr.b   (a2)
    move.b  #$12,2(a2)
    andi.w  #(button_up_mask|button_down_mask|button_left_mask|button_right_mask)<<8,d0
    beq.s   +
    move.b  #$3C,2(a2)
+
    move.w  #-$300,y_vel(a1)
    bra.w   ObjD9_CheckCharacter_End
; ===========================================================================
 
loc_2C9A0:
    tst.b   2(a2)
    beq.s   +
    subq.b  #1,2(a2)
    bne.w   ObjD9_CheckCharacter_End
+
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$18,d0
    cmpi.w  #$30,d0
    bhs.w   ObjD9_CheckCharacter_End
    move.w  y_pos(a1),d1
    sub.w   y_pos(a0),d1
    cmpi.w  #$10,d1
    bhs.w   ObjD9_CheckCharacter_End
    tst.b   obj_control(a1)
    bmi.s   ObjD9_CheckCharacter_End
    cmpi.b  #6,routine(a1)
    bhs.s   ObjD9_CheckCharacter_End
    tst.w   (Debug_placement_mode).w
    bne.s   ObjD9_CheckCharacter_End
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #AniIDSonAni_Hang2,anim(a1)
    move.b  #1,obj_control(a1)
    move.b  #1,(a2)
; return_2CA08:
ObjD9_CheckCharacter_End:
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo7_MarkObjGone3 
    jmp (MarkObjGone3).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 4A - Octus (octopus badnik) from OOZ
; ----------------------------------------------------------------------------
octus_start_position = objoff_2A
; Sprite_2CA14:
Obj4A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj4A_Index(pc,d0.w),d1
    jmp Obj4A_Index(pc,d1.w)
; ===========================================================================
; off_2CA22:
Obj4A_Index:    offsetTable
        offsetTableEntry.w Obj4A_Init   ; 0
        offsetTableEntry.w Obj4A_Main   ; 2
        offsetTableEntry.w Obj4A_Angry  ; 4 - unused
        offsetTableEntry.w Obj4A_Bullet ; 6
; ===========================================================================
; loc_2CA2A:
Obj4A_Bullet:
    subi_.w #1,objoff_2C(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    jsrto   (ObjectMove).l, JmpTo19_ObjectMove
    lea (Ani_obj4A).l,a1
    jsrto   (AnimateSprite).l, JmpTo13_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo32_MarkObjGone
; ===========================================================================
; loc_2CA46:
Obj4A_Angry:    ; Used by removed sub-object
    subq.w  #1,objoff_2C(a0)
    beq.w   JmpTo47_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo31_DisplaySprite
 
    if removeJmpTos
JmpTo47_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; loc_2CA52:
Obj4A_Init:
    move.l  #Obj4A_MapUnc_2CBFE,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Octus,1,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$A,collision_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #$B,y_radius(a0)
    move.b  #8,x_radius(a0)
    jsrto   (ObjectMoveAndFall).l, JmpTo2_ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    add.w   d1,y_pos(a0)
    move.w  #0,y_vel(a0)
    addq.b  #2,routine(a0)
    move.w  x_pos(a0),d0
    sub.w   (MainCharacter+x_pos).w,d0
    bpl.s   +
    bchg    #0,status(a0)
+
    move.w  y_pos(a0),octus_start_position(a0)
    rts
; ===========================================================================
; loc_2CAB8:
Obj4A_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj4A_Main_Index(pc,d0.w),d1
    jsr Obj4A_Main_Index(pc,d1.w)
    lea (Ani_obj4A).l,a1
    jsrto   (AnimateSprite).l, JmpTo13_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo32_MarkObjGone
; ===========================================================================
; off_2CAD4:
Obj4A_Main_Index: offsetTable
    offsetTableEntry.w Obj4A_WaitForCharacter   ; 0
    offsetTableEntry.w Obj4A_DelayBeforeMoveUp  ; 2
    offsetTableEntry.w Obj4A_MoveUp         ; 4
    offsetTableEntry.w Obj4A_Hover          ; 6
    offsetTableEntry.w Obj4A_MoveDown       ; 8
; ===========================================================================
; loc_2CADE:
Obj4A_WaitForCharacter:
    move.w  x_pos(a0),d0
    sub.w   (MainCharacter+x_pos).w,d0
    cmpi.w  #$80,d0
    bgt.s   +   ; rts
    cmpi.w  #-$80,d0
    blt.s   +   ; rts
    addq.b  #2,routine_secondary(a0)
    move.b  #3,anim(a0)
    move.w  #$20,objoff_2C(a0)
+
    rts
; ===========================================================================
; loc_2CB04:
Obj4A_DelayBeforeMoveUp:
    subq.w  #1,objoff_2C(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.b  #4,anim(a0)
    move.w  #-$200,y_vel(a0)
    jmpto   (ObjectMove).l, JmpTo19_ObjectMove
; ===========================================================================
; loc_2CB20:
Obj4A_MoveUp:
    addi.w  #$10,y_vel(a0)
    bpl.s   +
    jmpto   (ObjectMove).l, JmpTo19_ObjectMove
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$3C,objoff_2C(a0)
    bra.w   Obj4A_FireBullet
; ===========================================================================
; loc_2CB3A:
Obj4A_Hover:
    subq.w  #1,objoff_2C(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    rts
; ===========================================================================
; loc_2CB48:
Obj4A_MoveDown:
    addi.w  #$10,y_vel(a0)
    move.w  y_pos(a0),d0
    cmp.w   octus_start_position(a0),d0
    bhs.s   +
    jmpto   (ObjectMove).l, JmpTo19_ObjectMove
; ===========================================================================
+
    clr.b   routine_secondary(a0)
    clr.b   anim(a0)
    clr.w   y_vel(a0)
    move.b  #1,mapping_frame(a0)
    rts
; ===========================================================================
; loc_2CB70:
Obj4A_FireBullet:
    ; In the Simon Wai beta, the object loads another object
    ; here, which makes it look angry as it fires.
    ; This object would have used Obj4A_Angry.
    jsr (SingleObjLoad).l
    bne.s   +   ; rts
    _move.b #ObjID_Octus,id(a1) ; load obj4A
    move.b  #6,routine(a1)
    move.l  #Obj4A_MapUnc_2CBFE,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Octus,1,0),art_tile(a1)
    move.b  #4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  #$F,objoff_2C(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  status(a0),status(a1)
    move.b  #2,anim(a1)
    move.b  #$98,collision_flags(a1)
    move.w  #-$200,x_vel(a1)
    btst    #0,render_flags(a1)
    beq.s   +   ; rts
    neg.w   x_vel(a1)
+
    rts
; ===========================================================================
; animation script
; off_2CBDC:
Ani_obj4A:  offsetTable
        offsetTableEntry.w byte_2CBE6   ; 0
        offsetTableEntry.w byte_2CBEA   ; 1
        offsetTableEntry.w byte_2CBEF   ; 2
        offsetTableEntry.w byte_2CBF4   ; 3
        offsetTableEntry.w byte_2CBF8   ; 4
byte_2CBE6: dc.b  $F,  1,  0,$FF
    rev02even
byte_2CBEA: dc.b   3,  1,  2,  3,$FF
    rev02even
byte_2CBEF: dc.b   2,  5,  6,$FF
    even
byte_2CBF4: dc.b  $F,  4,$FF
    even
byte_2CBF8: dc.b   7,  0,  1,$FD,  1
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj4A_MapUnc_2CBFE: BINCLUDE "mappings/sprite/obj4A.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo31_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo47_DeleteObject 
    jmp (DeleteObject).l
JmpTo32_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo13_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo2_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
; loc_2CCC2:
JmpTo19_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 50 - Aquis (seahorse badnik) from OOZ
; ----------------------------------------------------------------------------
; OST Variables:
Obj50_unkown1       = objoff_2A ; word
Obj50_shooting_flag = objoff_2D ; byte  ; if set, shooting is disabled
Obj50_shots_remaining   = objoff_2E ; word  ; number of shots before retreating
Obj50_unkown2       = objoff_30 ; word
Obj50_unkown3       = objoff_32 ; word
Obj50_unkown4       = objoff_34 ; word
Obj50_child     = objoff_36 ; long  ; pointer to wing object (main)
Obj50_parent        = objoff_36 ; long  ; pointer to main object (wing)
Obj50_unkown5       = objoff_3A ; word
Obj50_timer     = objoff_3C ; byte  ; time spent following the player before shooting and time to wait before actually shooting
 
; Sprite_2CCC8:
Obj50:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj50_Index(pc,d0.w),d1
    jmp Obj50_Index(pc,d1.w)
; ===========================================================================
; off_2CCD6:
Obj50_Index:    offsetTable
        offsetTableEntry.w Obj50_Init   ; 0
        offsetTableEntry.w Obj50_Main   ; 2
        offsetTableEntry.w Obj50_Wing   ; 4
        offsetTableEntry.w Obj50_Bullet ; 6
; ===========================================================================
; loc_2CCDE:
Obj50_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj50_MapUnc_2CF94,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Aquis,1,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$A,collision_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.w  #-$100,x_vel(a0)
    move.b  subtype(a0),d0
    move.b  d0,d1
    andi.w  #$F0,d1
    lsl.w   #4,d1
    move.w  d1,Obj50_shots_remaining(a0)    ; looks like the number of shots could be set via subtype at one point
    move.w  d1,Obj50_unkown2(a0)    ; unused
    andi.w  #$F,d0
    lsl.w   #4,d0
    subq.w  #1,d0
    move.w  d0,Obj50_unkown3(a0)    ; unused
    move.w  d0,Obj50_unkown4(a0)    ; unused
    move.w  y_pos(a0),Obj50_unkown1(a0) ; unused
    move.w  (Water_Level_1).w,Obj50_unkown5(a0)
    move.b  #3,Obj50_shots_remaining(a0)    ; hardcoded to three shots
 
    ; creat wing child object
    jsrto   (SingleObjLoad).l, JmpTo12_SingleObjLoad
    bne.s   Obj50_Main
 
    _move.b #ObjID_Aquis,id(a1) ; load obj50
    move.b  #4,routine(a1)  ; => Obj50_Wing
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$A,x_pos(a1)
    addi.w  #-6,y_pos(a1)
    move.l  #Obj50_MapUnc_2CF94,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Aquis,1,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  status(a0),status(a1)
    move.b  #3,anim(a1)
    move.l  a1,Obj50_child(a0)
    move.l  a0,Obj50_parent(a1)
    bset    #6,status(a0)   ; set compund sprite flag. This is useless, as the object doesn't define any child spites, nor does it set its child sprite count
; loc_2CDA2:
Obj50_Main:
    lea (Ani_obj50).l,a1
    jsrto   (AnimateSprite).l, JmpTo14_AnimateSprite
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj50_Main_Index(pc,d0.w),d1
    jsr Obj50_Main_Index(pc,d1.w)
    bsr.w   Obj50_ControlWing
    jmpto   (MarkObjGone).l, JmpTo33_MarkObjGone
; ===========================================================================
; off_2CDC2:
Obj50_Main_Index: offsetTable
    offsetTableEntry.w Obj50_CheckIfOnScreen    ; 0
    offsetTableEntry.w Obj50_Chase          ; 2
    offsetTableEntry.w Obj50_Shooting       ; 4
    offsetTableEntry.w BranchTo_JmpTo20_ObjectMove  ; 6
; ===========================================================================
; loc_2CDCA:
Obj50_Wing:
    movea.l Obj50_parent(a0),a1 ; a1=object
    tst.b   id(a1)      ; is parent object's slot empty?
    beq.w   JmpTo48_DeleteObject    ; if yes, branch
    cmpi.b  #ObjID_Aquis,(a1)   ; is parent object ObjID_Aquis?
    bne.w   JmpTo48_DeleteObject    ; if not, branch
    btst    #7,status(a1)       ; is parent object marked as destroyed?
    bne.w   JmpTo48_DeleteObject    ; if yes, branch
    lea (Ani_obj50).l,a1
    jsrto   (AnimateSprite).l, JmpTo14_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo32_DisplaySprite
; ===========================================================================
; loc_2CDF4:
Obj50_Bullet:
    jsrto   (ObjectMove).l, JmpTo20_ObjectMove
    lea (Ani_obj50).l,a1
    jsrto   (AnimateSprite).l, JmpTo14_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo33_MarkObjGone
; ===========================================================================
; wait and do nothing until on screen
; loc_2CE06:
Obj50_CheckIfOnScreen:
    tst.b   render_flags(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)    ; => Obj50_Chase
    rts
; ===========================================================================
; loc_2CE14:
Obj50_Chase:
    bsr.w   Obj50_FollowPlayer
    rts
; ===========================================================================
; loc_2CE1A:
Obj50_Shooting:
    bsr.w   Obj50_WaitForNextShot
    bsr.w   Obj50_ChkIfShoot
    rts
; ===========================================================================
; loc_2CE24:
Obj50_ChkIfShoot:
    tst.b   Obj50_shooting_flag(a0) ; is object allowed to shoot?
    bne.w   return_2CEAC        ; if not, branch
    st  Obj50_shooting_flag(a0) ; else, disallow shooting after this
    jsrto   (Obj_GetOrientationToPlayer).l, JmpTo_Obj_GetOrientationToPlayer
    tst.w   d1      ; is player above object?
    beq.s   return_2CEAC    ; if yes, don't shoot
    cmpi.w  #$FFF0,d1   ; ? d1 should only be 0 or 2 here...
    bhs.s   return_2CEAC
 
    ; shoot bullet
    jsrto   (SingleObjLoad).l, JmpTo12_SingleObjLoad
    bne.s   return_2CEAC
    _move.b #ObjID_Aquis,id(a1) ; load obj50
    move.b  #6,routine(a1)  ; => Obj50_Bullet
    move.w  x_pos(a0),x_pos(a1) ; align with parent object
    move.w  y_pos(a0),y_pos(a1)
    move.l  #Obj50_MapUnc_2CF94,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Aquis,1,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #$98,collision_flags(a1)
    move.b  #2,anim(a1)
    move.w  #$A,d0      ; set y offset
    move.w  #$10,d1     ; set x offset
    move.w  #-$300,d2   ; set x velocity
    btst    #0,status(a0)   ; is object facing right?
    beq.s   +       ; if yes, branch
    neg.w   d1  ; else, align bullet with other side of object...
    neg.w   d2  ; ... and move in the opposite direction
+
    sub.w   d0,y_pos(a1)
    sub.w   d1,x_pos(a1)
    move.w  d2,x_vel(a1)
    move.w  #$200,y_vel(a1)
 
return_2CEAC:
    rts
; ===========================================================================
; follow player for a while; target is whichever character is the closest
; loc_2CEAE:
Obj50_FollowPlayer:
    subq.b  #1,Obj50_timer(a0)
    bmi.s   Obj50_DoneFollowing ; branch, if counter has expired
    jsrto   (Obj_GetOrientationToPlayer).l, JmpTo_Obj_GetOrientationToPlayer
    bclr    #0,status(a0)   ; face right
    tst.w   d0
    beq.s   +       ; branch, if player is right from object
    bset    #0,status(a0)   ; otherwise, face left
+
    ; make object move towards player; d0 and d1 were set by the GetOrientationToPlayer routine
    move.w  Obj50_Speeds(pc,d0.w),d2
    add.w   d2,x_vel(a0)
    move.w  Obj50_Speeds(pc,d1.w),d2
    add.w   d2,y_vel(a0)
    move.w  #$100,d0    ; $100 is object's max x...
    move.w  d0,d1       ; ... and y velocity
    jsrto   (Obj_CapSpeed).l, JmpTo_Obj_CapSpeed
    jmpto   (ObjectMove).l, JmpTo20_ObjectMove
; ===========================================================================
; word_2CEE6:
Obj50_Speeds:
    dc.w   -$10 ; 0 - left/up
    dc.w    $10 ; 2 - right/down
; ===========================================================================
; loc_2CEEA:
Obj50_DoneFollowing:
    addq.b  #2,routine_secondary(a0)    ; => Obj50_Shooting
    move.b  #$20,Obj50_timer(a0)
    jmpto   (Obj_MoveStop).l, JmpTo_Obj_MoveStop
; ===========================================================================
; loc_2CEF8:
Obj50_WaitForNextShot:
    subq.b  #1,Obj50_timer(a0)  ; wait for a while
    bmi.s   +       ; branch, if counter has expired
    rts
; ===========================================================================
+   ; check if object is out of shots and flee if it is
    subq.b  #1,Obj50_shots_remaining(a0)
    bmi.s   Obj50_GoAway    ; branch, if object is out of atttacks
    ; otherwise, shoot and return to chasing the player
    subq.b  #2,routine_secondary(a0)    ; => Obj50_Chase
    move.w  #-$100,y_vel(a0)
    move.b  #$80,Obj50_timer(a0)    ; reset timer
    clr.b   Obj50_shooting_flag(a0) ; reenbale shooting
    rts
; ===========================================================================
; loc_2CF1C:
Obj50_GoAway:
    move.b  #6,routine_secondary(a0)    ; => BranchTo_JmpTo20_ObjectMove
    move.w  #-$200,x_vel(a0)    ; fly off to the left
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
BranchTo_JmpTo20_ObjectMove 
    jmpto   (ObjectMove).l, JmpTo20_ObjectMove
; ===========================================================================
; loc_2CF32:
Obj50_ControlWing:
    moveq   #$A,d0  ; x offset
    moveq   #-6,d1  ; y offset
    movea.l Obj50_child(a0),a1 ; a1=object
    move.w  x_pos(a0),x_pos(a1) ; align child with parent object
    move.w  y_pos(a0),y_pos(a1)
    move.b  status(a0),status(a1)
    move.b  respawn_index(a0),respawn_index(a1)
    move.b  render_flags(a0),render_flags(a1)
    btst    #0,status(a1)   ; is object facing right?
    beq.s   +       ; if yes, branch
    neg.w   d0  ; else, align wing with other side of object
+
    add.w   d0,x_pos(a1)
    add.w   d1,y_pos(a1)
    rts
; ===========================================================================
; animation script
; off_2CF6C:
Ani_obj50:  offsetTable
        offsetTableEntry.w Ani_obj50_Normal ; 0
        offsetTableEntry.w byte_2CF7B       ; 1
        offsetTableEntry.w Ani_obj50_Bullet ; 2
        offsetTableEntry.w Ani_obj50_Wing   ; 3
        offsetTableEntry.w byte_2CF8D       ; 4
        offsetTableEntry.w byte_2CF90       ; 5
Ani_obj50_Normal:   dc.b  $E,  0,$FF            ; byte_2CF78
    rev02even
byte_2CF7B:     dc.b   5,  3,  4,  3,  4,  3,  4,$FF
    rev02even
Ani_obj50_Bullet:   dc.b   3,  5,  6,  7,  6,$FF        ; byte_2CF83
    rev02even
Ani_obj50_Wing:     dc.b   3,  1,  2,$FF            ; byte_2CF89
    rev02even
byte_2CF8D:     dc.b   1,  5,$FF
    rev02even
byte_2CF90:     dc.b  $E,  8,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj50_MapUnc_2CF94: BINCLUDE "mappings/sprite/obj50.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo32_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo48_DeleteObject 
    jmp (DeleteObject).l
JmpTo12_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo33_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo14_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo_Obj_GetOrientationToPlayer 
    jmp (Obj_GetOrientationToPlayer).l
JmpTo_Obj_CapSpeed 
    jmp (Obj_CapSpeed).l
JmpTo_Obj_MoveStop 
    jmp (Obj_MoveStop).l
; loc_2D060:
JmpTo20_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo48_DeleteObject 
    jmp (DeleteObject).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 4B - Buzzer (Buzz bomber) from EHZ
; ----------------------------------------------------------------------------
; OST Variables:
Obj4B_parent        = objoff_2A ; long
Obj4B_move_timer    = objoff_2E ; word
Obj4B_turn_delay    = objoff_30 ; word
Obj4B_shooting_flag = objoff_32 ; byte
Obj4B_shot_timer    = objoff_34 ; word
 
; Sprite_2D068: ; Obj_Buzzer:
Obj4B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj4B_Index(pc,d0.w),d1
    jmp Obj4B_Index(pc,d1.w)
; ===========================================================================
; off_2D076:
Obj4B_Index:    offsetTable
        offsetTableEntry.w Obj4B_Init   ; 0
        offsetTableEntry.w Obj4B_Main   ; 2
        offsetTableEntry.w Obj4B_Flame  ; 4
        offsetTableEntry.w Obj4B_Projectile ; 6
; ===========================================================================
; loc_2D07E:
Obj4B_Projectile:
    jsrto   (ObjectMove).l, JmpTo21_ObjectMove
    lea (Ani_obj4B).l,a1
    jsrto   (AnimateSprite).l, JmpTo15_AnimateSprite
    jmpto   (MarkObjGone_P1).l, JmpTo_MarkObjGone_P1
; ===========================================================================
; loc_2D090:
Obj4B_Flame:
    movea.l Obj4B_parent(a0),a1 ; a1=object
    tst.b   id(a1)
    beq.w   JmpTo49_DeleteObject    ; branch, if object slot is empty. This check is incomplete and very unreliable; check Obj50_Wing to see how it should be done
    tst.w   Obj4B_turn_delay(a1)
    bmi.s   +       ; branch, if parent isn't currently turning around
    rts
; ---------------------------------------------------------------------------
+   ; follow parent object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    lea (Ani_obj4B).l,a1
    jsrto   (AnimateSprite).l, JmpTo15_AnimateSprite
    jmpto   (MarkObjGone_P1).l, JmpTo_MarkObjGone_P1
; ===========================================================================
; loc_2D0C8:
Obj4B_Init:
    move.l  #Obj4B_MapUnc_2D2EA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Buzzer,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo57_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #$A,collision_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$10,width_pixels(a0)
    move.b  #$10,y_radius(a0)
    move.b  #$18,x_radius(a0)
    move.b  #3,priority(a0)
    addq.b  #2,routine(a0)  ; => Obj4B_Main
 
    ; load exhaust flame object
    jsrto   (SingleObjLoad2).l, JmpTo20_SingleObjLoad2
    bne.s   +   ; rts
 
    _move.b #ObjID_Buzzer,id(a1) ; load obj4B
    move.b  #4,routine(a1)  ; => Obj4B_Flame
    move.l  #Obj4B_MapUnc_2D2EA,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Buzzer,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo7_Adjust2PArtPointer2
    move.b  #4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.b  status(a0),status(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #1,anim(a1)
    move.l  a0,Obj4B_parent(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  #$100,Obj4B_move_timer(a0)
    move.w  #-$100,x_vel(a0)
    btst    #0,render_flags(a0)
    beq.s   +   ; rts
    neg.w   x_vel(a0)
+
    rts
; ===========================================================================
; loc_2D174:
Obj4B_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj4B_Buzzer_States(pc,d0.w),d1
    jsr Obj4B_Buzzer_States(pc,d1.w)
    lea (Ani_obj4B).l,a1
    jsrto   (AnimateSprite).l, JmpTo15_AnimateSprite
    jmpto   (MarkObjGone_P1).l, JmpTo_MarkObjGone_P1
; ===========================================================================
; off_2D190:
Obj4B_Buzzer_States:    offsetTable
        offsetTableEntry.w Obj4B_Roaming    ; 0
        offsetTableEntry.w Obj4B_Shooting   ; 2
; ===========================================================================
; loc_2D194:
Obj4B_Roaming:
    bsr.w   Obj4B_ChkPlayers
    subq.w  #1,Obj4B_turn_delay(a0)
    move.w  Obj4B_turn_delay(a0),d0
    cmpi.w  #$F,d0
    beq.s   Obj4B_TurnAround
    tst.w   d0
    bpl.s   return_2D1B8
    subq.w  #1,Obj4B_move_timer(a0)
    bgt.w   JmpTo21_ObjectMove
    move.w  #$1E,Obj4B_turn_delay(a0)
 
return_2D1B8:
    rts
; ---------------------------------------------------------------------------
; loc_2D1BA:
Obj4B_TurnAround:
    sf  Obj4B_shooting_flag(a0) ; reenable shooting
    neg.w   x_vel(a0)       ; reverse movement direction
    bchg    #0,render_flags(a0)
    bchg    #0,status(a0)
    move.w  #$100,Obj4B_move_timer(a0)
    rts
; ===========================================================================
; Start of subroutine Obj4B_ChkPlayers
; sub_2D1D6:
Obj4B_ChkPlayers:
    tst.b   Obj4B_shooting_flag(a0)
    bne.w   return_2D232    ; branch, if shooting is disabled
    move.w  x_pos(a0),d0
    lea (MainCharacter).w,a1 ; a1=character
    btst    #0,(Vint_runcount+3).w
    beq.s   +       ; target Sidekick on uneven frames
    lea (Sidekick).w,a1 ; a1=character
+
    sub.w   x_pos(a1),d0    ; get object's distance to player
    move.w  d0,d1       ; save value for later
    bpl.s   +       ; branch, if it was positive
    neg.w   d0      ; get absolute value
+
    ; test if player is inside an 8 pixel wide strip
    cmpi.w  #$28,d0
    blt.s   return_2D232
    cmpi.w  #$30,d0
    bgt.s   return_2D232
 
    tst.w   d1          ; test sign of distance
    bpl.s   Obj4B_PlayerIsLeft  ; branch, if player is left from object
    btst    #0,render_flags(a0)
    beq.s   return_2D232        ; branch, if object is facing right
    bra.s   Obj4B_ReadyToShoot
; ---------------------------------------------------------------------------
; loc_2D216:
Obj4B_PlayerIsLeft:
    btst    #0,render_flags(a0)
    bne.s   return_2D232    ; branch, if object is facing left
 
; loc_2D21E:
Obj4B_ReadyToShoot:
    st  Obj4B_shooting_flag(a0)     ; disable shooting
    addq.b  #2,routine_secondary(a0)    ; => Obj4B_Shooting
    move.b  #3,anim(a0)     ; play shooting animation
    move.w  #$32,Obj4B_shot_timer(a0)
 
return_2D232:
    rts
; End of subroutine Obj4B_ChkPlayers
; ===========================================================================
; loc_2D234:
Obj4B_Shooting:
    move.w  Obj4B_shot_timer(a0),d0 ; get timer value
    subq.w  #1,d0           ; decrement
    blt.s   Obj4B_DoneShooting  ; branch, if timer has expired
    move.w  d0,Obj4B_shot_timer(a0) ; update timer value
    cmpi.w  #$14,d0         ; has timer reached a certain value?
    beq.s   Obj4B_ShootProjectile   ; if yes, branch
    rts
; ---------------------------------------------------------------------------
; loc_2D248:
Obj4B_DoneShooting:
    subq.b  #2,routine_secondary(a0)    ; => Obj4B_Roaming
    rts
; ---------------------------------------------------------------------------
; loc_2D24E
Obj4B_ShootProjectile:
    jsr (SingleObjLoad2).l  ; Find next open object space
    bne.s   +
 
    _move.b #ObjID_Buzzer,id(a1) ; load obj4B
    move.b  #6,routine(a1)  ; => Obj4B_Projectile
    move.l  #Obj4B_MapUnc_2D2EA,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Buzzer,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo7_Adjust2PArtPointer2
    move.b  #4,priority(a1)
    move.b  #$98,collision_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  status(a0),status(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #2,anim(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$18,y_pos(a1)  ; align vertically with stinger
    move.w  #$D,d0      ; absolute horizontal offset for stinger
    move.w  #$180,y_vel(a1)
    move.w  #-$180,x_vel(a1)
    btst    #0,render_flags(a1) ; is object facing left?
    beq.s   +           ; if not, branch
    neg.w   x_vel(a1)   ; move in other direction
    neg.w   d0      ; make offset negative
+
    add.w   d0,x_pos(a1)    ; align horizontally with stinger
    rts
; ===========================================================================
; animation script
; off_2D2CE:
Ani_obj4B:  offsetTable
        offsetTableEntry.w byte_2D2D6   ; 0
        offsetTableEntry.w byte_2D2D9   ; 1
        offsetTableEntry.w byte_2D2DD   ; 2
        offsetTableEntry.w byte_2D2E1   ; 3
byte_2D2D6: dc.b    $0F, $00, $FF
    rev02even
byte_2D2D9: dc.b    $02, $03, $04, $FF
    rev02even
byte_2D2DD: dc.b    $03, $05, $06, $FF
    rev02even
byte_2D2E1: dc.b    $09, $01, $01, $01, $01, $01, $FD, $00
    even
; ----------------------------------------------------------------------------
; sprite mappings -- Buzz Bomber Sprite Table
; ----------------------------------------------------------------------------
; MapUnc_2D2EA: SprTbl_Buzzer:
Obj4B_MapUnc_2D2EA: BINCLUDE "mappings/sprite/obj4B.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
 
    if ~~removeJmpTos
; loc_2D368:
JmpTo49_DeleteObject 
    jmp (DeleteObject).l
JmpTo20_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo15_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo7_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo_MarkObjGone_P1 
    jmp (MarkObjGone_P1).l
JmpTo57_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
; loc_2D38C:
JmpTo21_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    else
JmpTo49_DeleteObject 
    jmp (DeleteObject).l
; loc_2D38C:
JmpTo21_ObjectMove 
    jmp (ObjectMove).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5C - Masher (jumping piranha fish badnik) from EHZ
; ----------------------------------------------------------------------------
; OST Variables:
Obj5C_initial_y_pos = objoff_30 ; word
 
; Sprite_2D394:
Obj5C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj5C_Index(pc,d0.w),d1
    jsr Obj5C_Index(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo34_MarkObjGone
; ===========================================================================
; off_2D3A6:
Obj5C_Index:    offsetTable
        offsetTableEntry.w Obj5C_Init   ; 0
        offsetTableEntry.w Obj5C_Main   ; 2
; ===========================================================================
; loc_2D3AA:
Obj5C_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj5C_MapUnc_2D442,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Masher,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo58_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #9,collision_flags(a0)
    move.b  #$10,width_pixels(a0)
    move.w  #-$400,y_vel(a0)
    move.w  y_pos(a0),Obj5C_initial_y_pos(a0)   ; set initial (and lowest) y position
; loc_2D3E4:
Obj5C_Main:
    lea (Ani_obj5C).l,a1
    jsrto   (AnimateSprite).l, JmpTo16_AnimateSprite
    jsrto   (ObjectMove).l, JmpTo22_ObjectMove
    addi.w  #$18,y_vel(a0)  ; apply gravity
    move.w  Obj5C_initial_y_pos(a0),d0
    cmp.w   y_pos(a0),d0    ; has object reached its initial y position?
    bhs.s   +       ; if not, branch
    move.w  d0,y_pos(a0)
    move.w  #-$500,y_vel(a0)    ; jump
+
    move.b  #1,anim(a0)
    subi.w  #$C0,d0
    cmp.w   y_pos(a0),d0
    bhs.s   +   ; rts
    move.b  #0,anim(a0)
    tst.w   y_vel(a0)   ; is object falling?
    bmi.s   +   ; rts   ; if not, branch
    move.b  #2,anim(a0) ; use closed mouth animation
+
    rts
; ===========================================================================
; animation script
; off_2D430:
Ani_obj5C:  offsetTable
        offsetTableEntry.w byte_2D436   ; 0
        offsetTableEntry.w byte_2D43A   ; 1
        offsetTableEntry.w byte_2D43E   ; 2
byte_2D436: dc.b   7,  0,  1,$FF
byte_2D43A: dc.b   3,  0,  1,$FF
byte_2D43E: dc.b   7,  0,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj5C_MapUnc_2D442: BINCLUDE "mappings/sprite/obj5C.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo34_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo16_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo58_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
; loc_2D48E:
JmpTo22_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 58 - Boss explosion
; ----------------------------------------------------------------------------
; Sprite_2D494:
Obj58:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj58_Index(pc,d0.w),d1
    jmp Obj58_Index(pc,d1.w)
; ===========================================================================
; off_2D4A2:
Obj58_Index:    offsetTable
        offsetTableEntry.w Obj58_Init   ; 0
        offsetTableEntry.w Obj58_Main   ; 2
; ===========================================================================
; loc_2D4A6:
Obj58_Init:
    addq.b  #2,routine(a0)
    move.l  #Obj58_MapUnc_2D50A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_FieryExplosion,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo59_Adjust2PArtPointer
    move.b  #4,render_flags(a0)
    move.b  #0,priority(a0)
    move.b  #0,collision_flags(a0)
    move.b  #$C,width_pixels(a0)
    move.b  #7,anim_frame_duration(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #SndID_BossExplosion,d0
    jmp (PlaySound).l
; ===========================================================================
    rts
; ===========================================================================
; loc_2D4EC:
Obj58_Main:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #7,mapping_frame(a0)
    beq.w   JmpTo50_DeleteObject
+
    jmpto   (DisplaySprite).l, JmpTo33_DisplaySprite
 
    if removeJmpTos
JmpTo50_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj58_MapUnc_2D50A: BINCLUDE "mappings/sprite/obj58.bin"
; ===========================================================================
 
    ; Unused - a little dead code here (until the next label)
;Boss_HoverPos:
    move.b  boss_sine_count(a0),d0 ; a0=object
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    addq.b  #2,boss_sine_count(a0)
 
;loc_2D57C
Boss_HandleHits:
    cmpi.b  #8,boss_routine(a0) ; is boss exploding or retreating?
    bhs.s   return_2D5C2        ; if yes, branch
    tst.b   boss_hitcount2(a0)  ; has boss run out of hits?
    beq.s   Boss_Defeat     ; if yes, branch
    tst.b   collision_flags(a0) ; are boss' collisions enabled?
    bne.s   return_2D5C2        ; if yes, branch
    tst.b   boss_invulnerable_time(a0)  ; is boss invulnerable?
    bne.s   +               ; if yes, branch
    move.b  #$20,boss_invulnerable_time(a0) ; make boss invulnerable
    move.w  #SndID_BossHit,d0   ; play "boss hit" sound
    jsr (PlaySound).l
+
    ; do palette flashing effect
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0       ; 0000 = black
    tst.w   (a1)        ; is current color black?
    bne.s   +       ; if not, branch
    move.w  #$EEE,d0    ; 0EEE = white
+
    move.w  d0,(a1)     ; set color to white or black
    subq.b  #1,boss_invulnerable_time(a0)   ; decrease boss' invulnerable time
    bne.s   return_2D5C2            ; branch, if it hasn't run out
    move.b  #$F,collision_flags(a0)     ; else, restore collisions
 
return_2D5C2:
    rts
; ===========================================================================
; loc_2D5C4:
Boss_Defeat:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo_AddPoints
    move.w  #$B3,(Boss_Countdown).w
    move.b  #8,boss_routine(a0)
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo4_LoadPLC
    rts
; ===========================================================================
 
;loc_2D5DE:
Boss_MoveObject:
    move.l  (Boss_X_pos).w,d2
    move.l  (Boss_Y_pos).w,d3
    move.w  (Boss_X_vel).w,d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  (Boss_Y_vel).w,d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,(Boss_X_pos).w
    move.l  d3,(Boss_Y_pos).w
    rts
; ===========================================================================
; a1 = animation script pointer
;AnimationArray: up to 8 2-byte entries:
    ; 4-bit: anim_ID (1)
    ; 4-bit: anim_ID (2) - the relevant one
    ; 4-bit: anim_frame
    ; 4-bit: anim_timer until next anim_frame
; if anim_ID (1) & (2) are not equal, new animation data is loaded
 
;loc_2D604:
AnimateBoss:
    moveq   #0,d6
    movea.l a1,a4       ; address of animation script
    lea (Boss_AnimationArray).w,a2
    lea mainspr_mapframe(a0),a3 ; mapframe 1 (main object)
    tst.b   (a3)
    bne.s   +
    addq.w  #2,a2
    bra.s   ++
; ----------------------------------------------------------------------------
+
    bsr.w   AnimateBoss_Loop
 
+
    moveq   #0,d6
    move.b  mainspr_childsprites(a0),d6 ; number of child sprites
    subq.w  #1,d6       ; = amount of iterations to run the code from AnimateBoss_Loop
    bmi.s   return_2D690    ; if was 0, don't run
    lea sub2_mapframe(a0),a3    ; mapframe 2
; ----------------------------------------------------------------------------
;loc_2D62A:
AnimateBoss_Loop:   ; increases a2 (AnimationArray) by 2 each iteration
    movea.l a4,a1
    moveq   #0,d0
    moveq   #0,d1
    moveq   #0,d2
    moveq   #0,d4
    move.b  (a2)+,d0
    move.b  d0,d1
    lsr.b   #4,d1       ; anim_ID (1)
    andi.b  #$F,d0      ; anim_ID (2)
    move.b  d0,d2
    cmp.b   d0,d1
    beq.s   +
    st  d4      ; anim_IDs not equal
+
    move.b  d0,d5
    lsl.b   #4,d5
    or.b    d0,d5       ; anim_ID (2) in both nybbles
    move.b  (a2)+,d0
    move.b  d0,d1
    lsr.b   #4,d1       ; anim_frame
    tst.b   d4      ; are the anim_IDs equal?
    beq.s   +
    moveq   #0,d0
    moveq   #0,d1       ; reset d0,d1 if anim_IDs not equal
+
    andi.b  #$F,d0      ; timer until next anim_frame
    subi_.b #1,d0
    bpl.s   loc_2D67C   ; timer not yet at 0, and anim_IDs are equal
 
    add.w   d2,d2       ; anim_ID (2)
    adda.w  (a1,d2.w),a1    ; address of animation data with this ID
    move.b  (a1),d0     ; animation speed
    move.b  1(a1,d1.w),d2   ; mapping_frame of first/next anim_frame
    bmi.s   AnimateBoss_CmdParam    ; if animation command parameter, branch
 
loc_2D672:
    andi.b  #$7F,d2
    move.b  d2,(a3)     ; store mapping_frame to OST of object
    addi_.b #1,d1       ; anim_frame
 
loc_2D67C:
    lsl.b   #4,d1
    or.b    d1,d0
    move.b  d0,-1(a2)   ; (2nd byte) anim_frame and anim_timer
    move.b  d5,-2(a2)   ; (1st byte) anim_ID (both nybbles)
    adda_.w #6,a3       ; mapping_frame of next subobject
    dbf d6,AnimateBoss_Loop
 
return_2D690:
    rts
; ----------------------------------------------------------------------------
;loc_2D692:
AnimateBoss_CmdParam:   ; parameter $FF - reset animation to first frame
    addq.b  #1,d2
    bne.s   +
    move.b  #0,d1
    move.b  1(a1),d2
    bra.s   loc_2D672
; ----------------------------------------------------------------------------
+       ; parameter $FE - increase boss routine
    addq.b  #1,d2
    bne.s   +
    addi_.b #2,angle(a0)    ; boss routine
    rts
; ----------------------------------------------------------------------------
+       ; parameter $FD - change anim_ID to byte after parameter
    addq.b  #1,d2
    bne.s   +
    andi.b  #$F0,d5     ; keep anim_ID (1)
    or.b    2(a1,d1.w),d5   ; set anim_ID (2)
    bra.s   loc_2D67C
; ----------------------------------------------------------------------------
+       ; parameter $FC - jump back to anim_frame d1
    addq.b  #1,d2
    bne.s   +   ; rts
    moveq   #0,d3
    move.b  2(a1,d1.w),d1   ; anim_frame
    move.b  1(a1,d1.w),d2   ; mapping_frame
    bra.s   loc_2D672
; ----------------------------------------------------------------------------
+       ; parameter $80-$FB
    rts
; ===========================================================================
 
;loc_2D6CC:
Boss_LoadExplosion:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    bne.s   +   ; rts
    jsr (SingleObjLoad).l
    bne.s   +   ; rts
    _move.b #ObjID_BossExplosion,id(a1) ; load obj58
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    jsr (RandomNumber).l
    move.w  d0,d1
    moveq   #0,d1
    move.b  d0,d1
    lsr.b   #2,d1
    subi.w  #$20,d1
    add.w   d1,x_pos(a1)
    lsr.w   #8,d0
    lsr.b   #2,d0
    subi.w  #$20,d0
    add.w   d0,y_pos(a1)
+
    rts
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo33_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo50_DeleteObject 
    jmp (DeleteObject).l
JmpTo4_LoadPLC 
    jmp (LoadPLC).l
JmpTo_AddPoints 
    jmp (AddPoints).l
JmpTo59_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5D - CPZ boss
; ----------------------------------------------------------------------------
; OST Variables:
Obj5D_timer2        = objoff_2A
Obj5D_pipe_segments = objoff_2C
Obj5D_status        = objoff_2D
Obj5D_status2       = objoff_2E
Obj5D_x_vel     = objoff_2E ; and $2F
Obj5D_x_pos_next    = objoff_30
Obj5D_timer     = objoff_30
Obj5D_y_offset      = objoff_31
Obj5D_timer3        = objoff_32
Obj5D_parent        = objoff_34
Obj5D_y_pos_next    = objoff_38
Obj5D_defeat_timer  = objoff_3C
Obj5D_flag      = objoff_3C
Obj5D_timer4        = objoff_3C
Obj5D_invulnerable_time = objoff_3E
Obj5D_hover_counter = objoff_3F
 
; Sprite_2D734:
Obj5D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj5D_Index(pc,d0.w),d1
    jmp Obj5D_Index(pc,d1.w)
; ===========================================================================
; off_2D742:
Obj5D_Index:    offsetTable
        offsetTableEntry.w Obj5D_Init       ;   0
        offsetTableEntry.w Obj5D_Main       ;   2
        offsetTableEntry.w Obj5D_Pipe       ;   4
        offsetTableEntry.w Obj5D_Pipe_Pump  ;   6
        offsetTableEntry.w Obj5D_Pipe_Retract   ;   8
        offsetTableEntry.w Obj5D_Dripper    ;  $A
        offsetTableEntry.w Obj5D_Gunk       ;  $C
        offsetTableEntry.w Obj5D_PipeSegment    ;  $E
        offsetTableEntry.w Obj5D_Container  ; $10
        offsetTableEntry.w Obj5D_Pump       ; $12
        offsetTableEntry.w Obj5D_FallingParts   ; $14
        offsetTableEntry.w Obj5D_Robotnik   ; $16
        offsetTableEntry.w Obj5D_Flame      ; $18
        offsetTableEntry.w Obj5D_1A     ; $1A
; ===========================================================================
; loc_2D75E:
Obj5D_Init:
    ; main vehicle
    move.l  #Obj5D_MapUnc_2ED8C,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Eggpod_3,1,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.w  #$2B80,x_pos(a0)
    move.w  #$4B0,y_pos(a0)
    move.b  #3,priority(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,collision_property(a0)
    addq.b  #2,routine(a0)  ; => Obj5D_Main
    move.w  x_pos(a0),Obj5D_x_pos_next(a0)
    move.w  y_pos(a0),Obj5D_y_pos_next(a0)
    bclr    #3,Obj5D_status(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo60_Adjust2PArtPointer
 
    ; robotnik sitting in his eggmobile
    jsr (SingleObjLoad2).l
    bne.w   loc_2D8AC
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  a1,Obj5D_parent(a0)
    move.l  #Obj5D_MapUnc_2ED8C,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Eggpod_3,0,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #3,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$16,routine(a1)    ; => Obj5D_Robotnik
    move.b  #1,anim(a1)
    move.b  render_flags(a0),render_flags(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo8_Adjust2PArtPointer2
    tst.b   subtype(a0)
    bmi.w   loc_2D8AC
 
    ; eggmobile's exhaust flame
    jsr (SingleObjLoad2).l
    bne.w   loc_2D8AC
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EE88,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EggpodJets_1,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo8_Adjust2PArtPointer2
    move.b  #1,anim_frame_duration(a0)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #3,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$18,routine(a1)    ; => Obj5D_Flame
    move.b  render_flags(a0),render_flags(a1)
 
    ; large pump mechanism on top of eggmobile
    jsr (SingleObjLoad2).l
    bne.s   loc_2D8AC
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #2,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$12,routine(a1)    ; => Obj5D_Pump
 
loc_2D8AC:
    ; glass container that dumps mega mack on player
    jsr (SingleObjLoad2).l
    bne.s   loc_2D908
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    subi.w  #$38,y_pos(a1)
    subi.w  #$10,x_pos(a1)
    move.w  #-$10,Obj5D_x_vel(a1)
    addi.b  #$10,routine(a1)    ; => Obj5D_Container
    move.b  #6,anim(a1)
 
loc_2D908:
    ; pipe used to suck mega mack from tube below
    jsr (SingleObjLoad2).l
    bne.s   return_2D94C
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #4,routine(a1)      ; => Obj5D_Pipe
 
return_2D94C:
    rts
; ===========================================================================
 
Obj5D_Main:
    bsr.w   Obj5D_LookAtChar
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Main_Index(pc,d0.w),d1
    jsr Obj5D_Main_Index(pc,d1.w)
    lea (Ani_obj5D_b).l,a1
    jsr (AnimateSprite).l
    move.b  status(a0),d0
    andi.b  #3,d0
    andi.b  #$FC,render_flags(a0)
    or.b    d0,render_flags(a0)
    jmp (DisplaySprite).l
; ===========================================================================
Obj5D_Main_Index:   offsetTable
        offsetTableEntry.w Obj5D_Main_0 ;  0
        offsetTableEntry.w Obj5D_Main_2 ;  2
        offsetTableEntry.w Obj5D_Main_4 ;  4
        offsetTableEntry.w Obj5D_Main_6 ;  6
        offsetTableEntry.w Obj5D_Main_8 ;  8
        offsetTableEntry.w Obj5D_Main_A ; $A
        offsetTableEntry.w Obj5D_Main_C ; $C
; ===========================================================================
; Makes the boss look in Sonic's direction under certain circumstances.
 
Obj5D_LookAtChar:
    cmpi.b  #8,routine_secondary(a0)
    bge.s   +
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    bgt.s   ++
    bclr    #0,status(a0)
+
    rts
; ---------------------------------------------------------------------------
+
    bset    #0,status(a0)
    rts
; ===========================================================================
 
Obj5D_Main_8:
    subq.w  #1,Obj5D_defeat_timer(a0)
    bpl.w   Obj5D_Main_Explode
    bset    #0,status(a0)
    bclr    #7,status(a0)
    clr.w   x_vel(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Main_A
    move.w  #-$26,Obj5D_defeat_timer(a0)
    rts
; ===========================================================================
 
Obj5D_Main_A:
    addq.w  #1,Obj5D_defeat_timer(a0)
    beq.s   +
    bpl.s   ++
    addi.w  #$18,y_vel(a0)
    bra.s   Obj5D_Main_A_End
; ---------------------------------------------------------------------------
+
    clr.w   y_vel(a0)
    bra.s   Obj5D_Main_A_End
; ---------------------------------------------------------------------------
+
    cmpi.w  #$30,Obj5D_defeat_timer(a0)
    blo.s   +
    beq.s   ++
    cmpi.w  #$38,Obj5D_defeat_timer(a0)
    blo.s   Obj5D_Main_A_End
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Main_C
    bra.s   Obj5D_Main_A_End
; ---------------------------------------------------------------------------
+
    subi_.w #8,y_vel(a0)
    bra.s   Obj5D_Main_A_End
; ---------------------------------------------------------------------------
+
    clr.w   y_vel(a0)
    jsrto   (PlayLevelMusic).l, JmpTo_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo_LoadPLC_AnimalExplosion
 
Obj5D_Main_A_End:
    bsr.w   Obj5D_Main_Move
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
 
Obj5D_Main_C:
    bset    #6,Obj5D_status2(a0)
    move.w  #$400,x_vel(a0)
    move.w  #-$40,y_vel(a0)
    cmpi.w  #$2C30,(Camera_Max_X_pos).w
    bhs.s   +
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   Obj5D_Main_C_End
; ===========================================================================
+
    tst.b   render_flags(a0)
    bpl.s   Obj5D_Main_Delete
 
Obj5D_Main_C_End:
    bsr.w   Obj5D_Main_Move
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
 
Obj5D_Main_Delete:
    addq.l  #4,sp
    movea.l Obj5D_parent(a0),a1 ; a1=object
    jsr (DeleteObject2).l
 
    if removeJmpTos
JmpTo51_DeleteObject 
    endif
 
    jmp (DeleteObject).l
; ===========================================================================
 
Obj5D_Main_0:
    move.w  #$100,y_vel(a0)
    bsr.w   Obj5D_Main_Move
    cmpi.w  #$4C0,Obj5D_y_pos_next(a0)
    bne.s   Obj5D_Main_Pos_and_Collision
    move.w  #0,y_vel(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Main_2
 
Obj5D_Main_Pos_and_Collision:
    ; do hovering motion using sine wave
    move.b  Obj5D_hover_counter(a0),d0
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   Obj5D_y_pos_next(a0),d0     ; get y position for next frame, add sine value
    move.w  d0,y_pos(a0)            ; set y and x positions
    move.w  Obj5D_x_pos_next(a0),x_pos(a0)
    addq.b  #2,Obj5D_hover_counter(a0)
 
    cmpi.b  #8,routine_secondary(a0)    ; exploding or retreating?
    bhs.s   return_2DAE8            ; if yes, branch
    tst.b   status(a0)
    bmi.s   Obj5D_Defeated      ; branch, if boss is defeated
    tst.b   collision_flags(a0)
    bne.s   return_2DAE8        ; branch, if collisions are not turned off
 
    ; if collisions are turned off, it means the boss was hit
    tst.b   Obj5D_invulnerable_time(a0)
    bne.s   +           ; branch, if still invulnerable
    move.b  #$20,Obj5D_invulnerable_time(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
+
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0       ; color black
    tst.w   (a1)    ; test palette entry
    bne.s   +   ; branch, if it's not black
    move.w  #$EEE,d0    ; color white
+
    move.w  d0,(a1)     ; set color for flashing effect
    subq.b  #1,Obj5D_invulnerable_time(a0)
    bne.s   return_2DAE8
    move.b  #$F,collision_flags(a0) ; restore collisions
    bclr    #1,Obj5D_status(a0)
 
return_2DAE8:
    rts
; ===========================================================================
; called when status bit 7 is set (check Touch_Enemy_Part2)
 
Obj5D_Defeated:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo2_AddPoints
    move.b  #8,routine_secondary(a0)    ; => Obj5D_Main_8
    move.w  #$B3,Obj5D_defeat_timer(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.b  #4,anim(a1)
    moveq   #PLCID_Capsule,d0
    jmpto   (LoadPLC).l, JmpTo5_LoadPLC
; ===========================================================================
    rts
; ===========================================================================
 
Obj5D_Main_Move:
    move.l  Obj5D_x_pos_next(a0),d2
    move.l  Obj5D_y_pos_next(a0),d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,Obj5D_x_pos_next(a0)
    move.l  d3,Obj5D_y_pos_next(a0)
    rts
; ===========================================================================
; Creates an explosion every 8 frames at a random position relative to boss.
 
Obj5D_Main_Explode:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    bne.s   +   ; rts
    jsr (SingleObjLoad).l
    bne.s   +   ; rts
    _move.b #ObjID_BossExplosion,id(a1) ; load obj58
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    jsr (RandomNumber).l
    move.w  d0,d1
    moveq   #0,d1
    move.b  d0,d1
    lsr.b   #2,d1
    subi.w  #$20,d1
    add.w   d1,x_pos(a1)
    lsr.w   #8,d0
    lsr.b   #2,d0
    subi.w  #$20,d0
    add.w   d0,y_pos(a1)
+
    rts
; ===========================================================================
; Creates an explosion.
 
Obj5D_Main_Explode2:
    jsr (SingleObjLoad).l
    bne.s   +   ; rts
    _move.b #ObjID_BossExplosion,id(a1) ; load obj58
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
+
    rts
; ===========================================================================
 
Obj5D_Main_2:
    btst    #3,Obj5D_status(a0) ; is boss on the left side of the arena?
    bne.s   +           ; if yes, branch
    move.w  #$2B30,d0   ; right side of arena
    bra.s   ++
; ---------------------------------------------------------------------------
+
    move.w  #$2A50,d0   ; left side of arena
+
    move.w  d0,d1
    sub.w   Obj5D_x_pos_next(a0),d0
    bpl.s   +
    neg.w   d0  ; get absolute value
+
    cmpi.w  #3,d0
    ble.s   Obj5D_Main_2_Stop   ; branch, if boss is within 3 pixels to his target
    cmp.w   Obj5D_x_pos_next(a0),d1
    bgt.s   Obj5D_Main_2_MoveRight
 
;Obj5D_Main_2_MoveLeft:
    move.w  #-$300,x_vel(a0)
    bra.s   Obj5D_Main_2_End
; ---------------------------------------------------------------------------
 
Obj5D_Main_2_MoveRight:
    move.w  #$300,x_vel(a0)
 
Obj5D_Main_2_End:
    bsr.w   Obj5D_Main_Move
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
 
Obj5D_Main_2_Stop:
    cmpi.w  #$4C0,Obj5D_y_pos_next(a0)
    bne.w   Obj5D_Main_Pos_and_Collision
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Main_4
    bchg    #3,Obj5D_status(a0) ; indicate boss is now at the other side
    bset    #0,Obj5D_status2(a0)    ; action 0
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
; when status2 bit 0 set, wait for something
 
Obj5D_Main_4:
    btst    #0,Obj5D_status2(a0)    ; action 0?
    beq.s   +           ; if not, branch
    bra.w   Obj5D_Main_Pos_and_Collision
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Main_6
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
 
Obj5D_Main_6:
    move.w  (MainCharacter+x_pos).w,d0
    addi.w  #$4C,d0
    cmp.w   Obj5D_x_pos_next(a0),d0
    bgt.s   Obj5D_Main_6_MoveRight
    beq.w   Obj5D_Main_Pos_and_Collision
 
;Obj5D_Main_6_MoveLeft:
    subi.l  #$10000,Obj5D_x_pos_next(a0)    ; move left one pixel
    ; stop at left boundary
    cmpi.w  #$2A28,Obj5D_x_pos_next(a0)
    bgt.w   Obj5D_Main_Pos_and_Collision
    move.w  #$2A28,Obj5D_x_pos_next(a0)
    bra.w   Obj5D_Main_Pos_and_Collision
; ---------------------------------------------------------------------------
 
Obj5D_Main_6_MoveRight:
    addi.l  #$10000,Obj5D_x_pos_next(a0)    ; move right one pixel
    ; stop at right boundary
    cmpi.w  #$2B70,Obj5D_x_pos_next(a0)
    blt.w   Obj5D_Main_Pos_and_Collision
    move.w  #$2B70,Obj5D_x_pos_next(a0)
    bra.w   Obj5D_Main_Pos_and_Collision
; ===========================================================================
 
Obj5D_FallingParts:
    cmpi.b  #-7,Obj5D_timer(a0)
    beq.s   +
    subi_.b #1,Obj5D_timer(a0)
    bgt.w   JmpTo34_DisplaySprite
    bsr.w   Obj5D_Main_Explode2
    move.b  #-7,Obj5D_timer(a0)
    move.w  #$1E,Obj5D_timer2(a0)
+
    subq.w  #1,Obj5D_timer2(a0)
    bpl.w   JmpTo34_DisplaySprite
    move.w  x_vel(a0),d0
    add.w   d0,x_pos(a0)
    move.l  y_pos(a0),d3
    move.w  y_vel(a0),d0
    addi.w  #$38,y_vel(a0)
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d3,y_pos(a0)
    cmpi.l  #$5800000,d3
    bhs.w   JmpTo51_DeleteObject
    jmpto   (MarkObjGone).l, JmpTo35_MarkObjGone
; ===========================================================================
 
Obj5D_Pump:
    btst    #7,status(a0)
    bne.s   +
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    move.b  render_flags(a1),render_flags(a0)
    move.b  status(a1),status(a0)
    movea.l #Ani_Obj5D_Dripper,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ---------------------------------------------------------------------------
+
    moveq   #$22,d3
    move.b  #$78,Obj5D_timer(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  d3,mapping_frame(a0)
    move.b  #$14,routine(a0)    ; => Obj5D_FallingParts
    jsr (RandomNumber).l
    asr.w   #8,d0
    asr.w   #6,d0
    move.w  d0,x_vel(a0)
    move.w  #-$380,y_vel(a0)
    moveq   #1,d2
    addq.w  #1,d3
 
-
    jsr (SingleObjLoad).l
    bne.w   JmpTo51_DeleteObject
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.b  d3,mapping_frame(a1)
    move.b  #$14,routine(a1)    ; => Obj5D_FallingParts
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #2,priority(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  status(a0),status(a1)
    move.b  render_flags(a0),render_flags(a1)
    jsr (RandomNumber).l
    asr.w   #8,d0
    asr.w   #6,d0
    move.w  d0,x_vel(a1)
    move.w  #-$380,y_vel(a1)
    swap    d0
    addi.b  #$1E,d0
    andi.w  #$7F,d0
    move.b  d0,Obj5D_timer(a1)
    addq.w  #1,d3
    dbf d2,-
    rts
; ===========================================================================
; Object to control the pipe's actions before pumping starts.
 
Obj5D_Pipe:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Pipe_Index(pc,d0.w),d1
    jmp Obj5D_Pipe_Index(pc,d1.w)
; ===========================================================================
Obj5D_Pipe_Index:   offsetTable
        offsetTableEntry.w Obj5D_Pipe_0 ; 0
        offsetTableEntry.w Obj5D_Pipe_2_Load    ; 2
; ===========================================================================
; wait for main vehicle's action 0
 
Obj5D_Pipe_0:
    movea.l Obj5D_parent(a0),a1 ; parent = main vehicle ; a1=object
    btst    #0,Obj5D_status2(a1)    ; parent's action 0?
    bne.s   +           ; if yes, branch
    ; else, do nothing
    rts
; ---------------------------------------------------------------------------
+
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi.w  #$18,y_pos(a0)
    move.w  #$C,Obj5D_pipe_segments(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Pipe_2_Load
    movea.l a0,a1
    bra.s   Obj5D_Pipe_2_Load_Part2     ; skip initial loading setup
; ===========================================================================
; load pipe segments, first object controls rest of pipe
; objects not loaded in a loop => one segment loaded per frame
; pipe extends gradually
 
Obj5D_Pipe_2_Load:
    jsr (SingleObjLoad2).l
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    move.l  a0,Obj5D_parent(a1)
 
Obj5D_Pipe_2_Load_Part2:
    subq.w  #1,Obj5D_pipe_segments(a0)  ; is pipe fully extended?
    blt.s   Obj5D_Pipe_2_Load_End       ; if yes, branch
 
    _move.b #ObjID_CPZBoss,id(a1)   ; load obj5D
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #5,priority(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
 
    ; calculate y position for current pipe segment
    move.w  Obj5D_pipe_segments(a0),d0
    subi.w  #$B,d0  ; $B = maximum number of pipe segments -1, result is always negative or zero
    neg.w   d0  ; positive value needed
    lsl.w   #3,d0   ; multiply with 8
    move.w  d0,Obj5D_y_pos_next(a1)
    add.w   d0,y_pos(a1)
    move.b  #1,anim(a1)
    cmpi.b  #2,routine_secondary(a1)
    beq.w   Obj5D_PipeSegment   ; only true for the first object
    move.b  #$E,routine(a1) ; => Obj5D_PipeSegment
    bra.w   Obj5D_PipeSegment
; ===========================================================================
; once all pipe segments have been loaded, switch to pumping routine
 
Obj5D_Pipe_2_Load_End:
    move.b  #0,routine_secondary(a0)
    move.b  #6,routine(a0)  ; => Obj5D_Pipe_Pump_0
    bra.w   Obj5D_PipeSegment
; ===========================================================================
; Object to control the pipe's actions while pumping.
 
Obj5D_Pipe_Pump:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Pipe_Pump_Index(pc,d0.w),d1
    jmp Obj5D_Pipe_Pump_Index(pc,d1.w)
; ===========================================================================
Obj5D_Pipe_Pump_Index:  offsetTable
        offsetTableEntry.w Obj5D_Pipe_Pump_0    ; 0
        offsetTableEntry.w Obj5D_Pipe_Pump_2    ; 2
        offsetTableEntry.w Obj5D_Pipe_Pump_4    ; 4
; ===========================================================================
; prepares for pumping animation
 
Obj5D_Pipe_Pump_0:
    jsr (SingleObjLoad2).l
    bne.w   Obj5D_PipeSegment
    move.b  #$E,routine(a0) ; => Obj5D_PipeSegment  ; temporarily turn control object into a pipe segment
    move.b  #6,routine(a1)
    move.b  #2,routine_secondary(a1)    ; => Obj5D_Pipe_Pump_2
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.b  #2,Obj5D_timer3(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
 
    ; starting position for pumping animation
    move.w  #$B*8,d0
    move.b  d0,Obj5D_y_offset(a1)
    add.w   d0,y_pos(a1)
    move.b  #2,anim(a1)
    move.l  a0,Obj5D_parent(a1) ; address of control object
    move.b  #$12,Obj5D_timer(a1)
    jsr (SingleObjLoad2).l
    bne.s   BranchTo_Obj5D_PipeSegment
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.b  #$A,routine(a1) ; => Obj5D_Dripper
    move.l  Obj5D_parent(a0),Obj5D_parent(a1)
 
BranchTo_Obj5D_PipeSegment 
    bra.w   Obj5D_PipeSegment
; ===========================================================================
; do pumping animation
 
Obj5D_Pipe_Pump_2:
    movea.l Obj5D_parent(a0),a1 ; parent = pipe segment (control object) ; a1=object
    movea.l Obj5D_parent(a1),a2 ; parent = main vehicle ; a2=object
    btst    #7,status(a2)       ; has boss been defeated?
    bne.w   JmpTo51_DeleteObject    ; if yes, branch
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
 
    subi_.b #1,Obj5D_timer(a0)  ; animation timer
    bne.s   Obj5D_Pipe_Pump_2_End
    ; when timer reaches zero
    move.b  #$12,Obj5D_timer(a0)    ; reset animation timer
    subi_.b #8,Obj5D_y_offset(a0)   ; move one segment up
    bgt.s   Obj5D_Pipe_Pump_2_End
    bmi.s   +   ; pumping sequence is over when y offset becomes negative
 
    ; one final delay when last segment is reached
    move.b  #3,anim(a0)
    move.b  #$C,Obj5D_timer(a0)
    bra.s   Obj5D_Pipe_Pump_2_End
; ---------------------------------------------------------------------------
+   ; when pumping sequence is over
    move.b  #6,Obj5D_timer(a0)
    move.b  #4,routine_secondary(a0)    ; => Obj5D_Pipe_Pump_4
    rts
; ---------------------------------------------------------------------------
 
Obj5D_Pipe_Pump_2_End:
    ; set y position based on y offset
    moveq   #0,d0
    move.b  Obj5D_y_offset(a0),d0
    add.w   d0,y_pos(a0)
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Pipe_Pump_4:
    subi_.b #1,Obj5D_timer(a0)  ; wait a few frames
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    subq.b  #1,Obj5D_timer3(a0)
    beq.s   +
    move.b  #2,anim(a0)
    move.b  #$12,Obj5D_timer(a0)
    move.b  #2,routine_secondary(a0)    ; => Obj5D_Pipe_Pump_2
    move.b  #$B*8,Obj5D_y_offset(a0)
+
    ; set control object's routine
    movea.l Obj5D_parent(a0),a1 ; parent = pipe segment (control object) ; a1=object
    move.b  #8,routine(a1)      ; => Obj5D_Pipe_Retract
    move.b  #$B*8,Obj5D_y_offset(a1)
    bra.w   JmpTo51_DeleteObject
; ===========================================================================
; Object to control the pipe's actions after pumping is finished.
 
Obj5D_Pipe_Retract:
    tst.b   Obj5D_flag(a0)  ; is flag set?
    bne.s   loc_2DFEE   ; if yes, branch
 
    moveq   #0,d0
    move.b  Obj5D_y_offset(a0),d0
    add.w   y_pos(a0),d0    ; get y pos of current pipe segment
    lea (MainCharacter).w,a1 ; a1=object
    moveq   #(Dynamic_Object_RAM_End-Object_RAM)/object_size-1,d1
 
Obj5D_Pipe_Retract_Loop:
    cmp.w   y_pos(a1),d0            ; compare object's y position with current y offset
    beq.s   Obj5D_Pipe_Retract_ChkID    ; if they match, branch
    lea next_object(a1),a1 ; a1=object
    dbf d1,Obj5D_Pipe_Retract_Loop  ; continue as long as there are object slots left
    bra.s   Obj5D_PipeSegment
; ===========================================================================
 
loc_2DFD8:
    st  Obj5D_flag(a0)
    bra.s   Obj5D_PipeSegment
; ===========================================================================
 
Obj5D_Pipe_Retract_ChkID:
    moveq   #0,d7
    move.b  #ObjID_CPZBoss,d7
    cmp.b   id(a1),d7   ; is object a subtype of the CPZ Boss?
    beq.s   loc_2DFF0   ; if yes, branch
    dbf d1,Obj5D_Pipe_Retract_Loop
    bra.s   Obj5D_PipeSegment
; ===========================================================================
 
loc_2DFEE:
    movea.l a0,a1
 
loc_2DFF0:
    bset    #7,status(a1)   ; mark segment for deletion
    subi_.b #8,Obj5D_y_offset(a0)   ; position of next segment up
    beq.s   loc_2DFD8
 
Obj5D_PipeSegment:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a2 ; a2=object
    btst    #7,status(a2)       ; has boss been defeated?
    bne.s   Obj5D_PipeSegment_End   ; if yes, branch
 
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    cmpi.b  #4,routine_secondary(a0)
    bne.s   +
    addi.w  #$18,y_pos(a0)
+
    btst    #7,status(a0)           ; is object marked for deletion?
    bne.s   BranchTo_JmpTo51_DeleteObject   ; if yes, branch
    move.w  Obj5D_y_pos_next(a0),d0
    add.w   d0,y_pos(a0)
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
BranchTo_JmpTo51_DeleteObject 
    bra.w   JmpTo51_DeleteObject
; ===========================================================================
 
Obj5D_PipeSegment_End:
    move.b  #$14,routine(a0)
    jsr (RandomNumber).l
    asr.w   #8,d0
    asr.w   #6,d0
    move.w  d0,x_vel(a0)
    move.w  #-$380,y_vel(a0)
    swap    d0
    addi.b  #$1E,d0
    andi.w  #$7F,d0
    move.b  d0,Obj5D_timer(a0)
    jmpto   (DisplaySprite).l, JmpTo34_DisplaySprite
; ===========================================================================
 
Obj5D_Dripper:
    btst    #7,status(a0)
    bne.w   JmpTo51_DeleteObject
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Dripper_States(pc,d0.w),d1
    jmp Obj5D_Dripper_States(pc,d1.w)
; ===========================================================================
Obj5D_Dripper_States:   offsetTable
        offsetTableEntry.w Obj5D_Dripper_0  ; 0
        offsetTableEntry.w Obj5D_Dripper_2  ; 2
        offsetTableEntry.w Obj5D_Dripper_4  ; 4
; ===========================================================================
 
Obj5D_Dripper_0:
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Dripper_2
    _move.b #ObjID_CPZBoss,id(a0) ; load 0bj5D
    move.l  #Obj5D_MapUnc_2EADC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,3,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #4,priority(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  #$F,Obj5D_timer(a0)
    move.b  #4,anim(a0)
 
Obj5D_Dripper_2:
    subq.b  #1,Obj5D_timer(a0)
    bne.s   +
    move.b  #5,anim(a0)
    move.b  #4,Obj5D_timer(a0)
    addq.b  #2,routine_secondary(a0)
    subi.w  #$24,y_pos(a0)
    subi_.w #2,x_pos(a0)
    rts
; ---------------------------------------------------------------------------
+
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Dripper_4:
    subq.b  #1,Obj5D_timer(a0)
    bne.s   +
    move.b  #0,routine_secondary(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    bset    #1,Obj5D_status2(a1)
    addq.b  #1,Obj5D_timer4(a0)
    cmpi.b  #$C,Obj5D_timer4(a0)
    bge.w   JmpTo51_DeleteObject
    rts
; ---------------------------------------------------------------------------
+
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    subi.w  #$24,y_pos(a0)
    subi_.w #2,x_pos(a0)
    btst    #0,render_flags(a0)
    beq.s   +
    addi_.w #4,x_pos(a0)
+
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Container:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Container_States(pc,d0.w),d1
    jmp Obj5D_Container_States(pc,d1.w)
; ===========================================================================
Obj5D_Container_States: offsetTable
        offsetTableEntry.w Obj5D_Container_Init ; 0
        offsetTableEntry.w Obj5D_Container_Main ; 2
        offsetTableEntry.w Obj5D_Container_Floor    ; 4
        offsetTableEntry.w Obj5D_Container_Extend   ; 6
        offsetTableEntry.w Obj5D_Container_Floor2   ; 8
        offsetTableEntry.w Obj5D_Container_FallOff  ; A
; ===========================================================================
 
Obj5D_Container_Init:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    btst    #7,Obj5D_status2(a1)
    bne.s   +
    bset    #7,Obj5D_status2(a1)
    jsr (SingleObjLoad2).l
    bne.s   +
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$10,routine(a1)
    move.b  #4,routine_secondary(a1)    ; => Obj5D_Container_Floor
    move.b  #9,anim(a1)
+
    jsr (SingleObjLoad2).l
    bne.s   +
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.b  #$10,routine(a1)
    move.b  #6,routine_secondary(a1)    ; => Obj5D_Container_Extend
+
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Container_Main
 
Obj5D_Container_Main:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    subi.w  #$38,y_pos(a0)
    btst    #7,status(a0)
    bne.s   loc_2E2E0
    btst    #2,Obj5D_status2(a1)
    beq.s   +
    bsr.w   loc_2E4CE
    bsr.w   loc_2E3F2
    bra.s   loc_2E2AC
; ---------------------------------------------------------------------------
+
    btst    #5,Obj5D_status2(a1)
    beq.s   loc_2E2AC
    subq.w  #1,Obj5D_timer2(a0)
    bne.s   loc_2E2AC
    bclr    #5,Obj5D_status2(a1)
    bset    #3,Obj5D_status2(a1)
    bset    #4,Obj5D_status2(a1)
 
loc_2E2AC:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    move.w  Obj5D_x_vel(a0),d0
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
+
    add.w   d0,x_pos(a0)
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_2E2E0:
    move.b  #$A,routine_secondary(a0)
    bra.s   loc_2E2AC
; ===========================================================================
 
Obj5D_Container_FallOff:
    move.l  d7,-(sp)
    move.b  #$1E,Obj5D_timer(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    subi.w  #$38,y_pos(a0)
    move.w  Obj5D_x_vel(a0),d0
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
+
    add.w   d0,x_pos(a0)
    move.b  #$20,mapping_frame(a0)
    move.b  #$14,routine(a0)
    jsr (RandomNumber).l
    asr.w   #8,d0
    asr.w   #6,d0
    move.w  d0,x_vel(a0)
    move.w  #-$380,y_vel(a0)
    moveq   #0,d7
    move.w  Obj5D_x_vel(a0),d0
    addi.w  #$18,d0
    bge.s   loc_2E356
    addi.w  #$18,d0
    bge.s   loc_2E354
    addi.w  #$18,d0
    bge.s   loc_2E352
    addq.w  #1,d7
 
loc_2E352:
    addq.w  #1,d7
 
loc_2E354:
    addq.w  #1,d7
 
loc_2E356:
    subq.w  #1,d7
    bmi.w   loc_2E3E6
 
loc_2E35C:
    jsr (SingleObjLoad).l
    bne.w   JmpTo51_DeleteObject
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.b  #$21,mapping_frame(a1)
    move.b  #$14,routine(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #2,priority(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi_.w #8,y_pos(a1)
    move.w  d7,d2
    add.w   d2,d2
    move.w  word_2E3EC(pc,d2.w),d3
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d3
+
    add.w   d3,x_pos(a1)
    jsr (RandomNumber).l
    asr.w   #8,d0
    asr.w   #6,d0
    move.w  d0,x_vel(a1)
    move.w  #-$380,y_vel(a1)
    swap    d0
    addi.b  #$1E,d0
    andi.w  #$7F,d0
    move.b  d0,Obj5D_timer(a1)
    dbf d7,loc_2E35C
 
loc_2E3E6:
    move.l  (sp)+,d7
 
    if removeJmpTos
JmpTo34_DisplaySprite 
    endif
 
    jmpto   (DisplaySprite).l, JmpTo34_DisplaySprite
; ===========================================================================
word_2E3EC:
    dc.w   $18
    dc.w   $30  ; 1
    dc.w   $48  ; 2
; ===========================================================================
 
loc_2E3F2:
    btst    #3,Obj5D_status2(a1)
    bne.w   return_2E4CC
    btst    #4,Obj5D_status2(a1)
    bne.w   return_2E4CC
    cmpi.w  #-$14,Obj5D_x_vel(a0)
    blt.s   +
    btst    #1,Obj5D_status(a1)
    beq.w   return_2E4CC
    bclr    #1,Obj5D_status(a1)
    bset    #2,Obj5D_status(a1)
    bra.s   loc_2E464
; ---------------------------------------------------------------------------
+
    cmpi.w  #-$40,Obj5D_x_vel(a0)
    bge.w   return_2E4CC
    move.w  (MainCharacter+x_pos).w,d1
    subi_.w #8,d1
    btst    #0,render_flags(a0)
    beq.s   +
    add.w   Obj5D_x_vel(a0),d1
    sub.w   x_pos(a0),d1
    bgt.w   return_2E4CC
    cmpi.w  #-$18,d1
    bge.s   loc_2E464
    rts
; ---------------------------------------------------------------------------
+
    sub.w   Obj5D_x_vel(a0),d1
    sub.w   x_pos(a0),d1
    blt.s   return_2E4CC
    cmpi.w  #$18,d1
    bgt.s   return_2E4CC
 
loc_2E464:
    bset    #5,Obj5D_status2(a1)
    bclr    #2,Obj5D_status2(a1)
    move.w  #$12,Obj5D_timer2(a0)
    jsr (SingleObjLoad2).l
    bne.s   return_2E4CC
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.b  #$10,routine(a1)
    move.b  #8,routine_secondary(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #5,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$B,anim(a1)
    move.w  #$24,Obj5D_timer2(a1)
 
return_2E4CC:
    rts
; ===========================================================================
 
loc_2E4CE:
    moveq   #1,d0
    btst    #4,Obj5D_status2(a1)
    bne.s   +
    moveq   #-1,d0
+
    cmpi.w  #-$10,Obj5D_x_vel(a0)
    bne.s   loc_2E552
    bclr    #4,Obj5D_status2(a1)
    beq.s   loc_2E552
    bclr    #2,Obj5D_status2(a1)
    clr.b   routine_secondary(a0)
    movea.l a1,a2
    jsr (SingleObjLoad2).l
    bne.s   return_2E550
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  Obj5D_parent(a0),Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #4,routine(a1)
    move.b  #0,routine_secondary(a0)
    bra.s   return_2E550
; ===========================================================================
    move.b  #$A,routine(a1)
    move.l  Obj5D_parent(a0),Obj5D_parent(a1)
 
return_2E550:
    rts
; ===========================================================================
 
loc_2E552:
    move.w  Obj5D_x_vel(a0),d1
    cmpi.w  #-$28,d1
    bge.s   loc_2E59C
    cmpi.w  #-$40,d1
    bge.s   loc_2E594
    move.b  #8,anim(a0)
    cmpi.w  #-$58,d1
    blt.s   loc_2E57E
    bgt.s   loc_2E578
    btst    #4,Obj5D_status2(a1)
    beq.s   return_2E57C
 
loc_2E578:
    add.w   d0,Obj5D_x_vel(a0)
 
return_2E57C:
    rts
; ===========================================================================
 
loc_2E57E:
    move.w  #-$58,Obj5D_x_vel(a0)
    btst    #0,render_flags(a0)
    beq.s   loc_2E578
    move.w  #$58,Obj5D_x_vel(a0)
    bra.s   loc_2E578
; ===========================================================================
 
loc_2E594:
    move.b  #7,anim(a0)
    bra.s   loc_2E578
; ===========================================================================
 
loc_2E59C:
    move.b  #6,anim(a0)
    bra.s   loc_2E578
; ===========================================================================
 
Obj5D_Container_Extend:
    btst    #7,status(a0)
    bne.w   JmpTo51_DeleteObject
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.l  Obj5D_parent(a1),d0
    beq.w   JmpTo51_DeleteObject
    movea.l d0,a1 ; a1=object
    bclr    #3,Obj5D_status2(a1)
    beq.s   +
    move.b  #$C,routine(a0)
    move.b  #0,routine_secondary(a0)
    move.b  #$87,collision_flags(a0)
    bra.s   Obj5D_Container_Floor_End
; ----------------------------------------------------------------------------
+
    bclr    #1,Obj5D_status2(a1)
    bne.s   +
    tst.b   anim(a0)
    bne.s   Obj5D_Container_Floor_End
    rts
; ---------------------------------------------------------------------------
+
    tst.b   anim(a0)
    bne.s   +
    move.b  #$B,anim(a0)
+
    addi_.b #1,anim(a0)
    cmpi.b  #$17,anim(a0)
    blt.s   Obj5D_Container_Floor_End
    bclr    #0,Obj5D_status2(a1)
    bset    #2,Obj5D_status2(a1)
    bra.s   Obj5D_Container_Floor_End
; ===========================================================================
 
Obj5D_Container_Floor:
    btst    #7,status(a0)
    bne.w   JmpTo51_DeleteObject
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1
    btst    #5,Obj5D_status2(a1)
    beq.s   Obj5D_Container_Floor_End
    cmpi.b  #9,anim(a0)
    bne.s   Obj5D_Container_Floor_End
    move.b  #$A,anim(a0)
 
Obj5D_Container_Floor_End:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  render_flags(a1),render_flags(a0)
    move.b  status(a1),status(a0)
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Container_Floor2:
    btst    #7,status(a0)
    bne.w   JmpTo51_DeleteObject
    subq.w  #1,Obj5D_timer2(a0)
    beq.w   JmpTo51_DeleteObject
    bra.s   Obj5D_Container_Floor_End
; ===========================================================================
 
Obj5D_Gunk:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj5D_Gunk_States(pc,d0.w),d1
    jmp Obj5D_Gunk_States(pc,d1.w)
; ===========================================================================
Obj5D_Gunk_States:  offsetTable
        offsetTableEntry.w Obj5D_Gunk_Init  ; 0
        offsetTableEntry.w Obj5D_Gunk_Main  ; 2
        offsetTableEntry.w Obj5D_Gunk_Droplets  ; 4
        offsetTableEntry.w Obj5D_Gunk_6 ; 6
        offsetTableEntry.w Obj5D_Gunk_8 ; 8
; ===========================================================================
 
Obj5D_Gunk_Init:
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Gunk_Main
    move.b  #$20,y_radius(a0)
    move.b  #$19,anim(a0)
    move.w  #0,y_vel(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1
    btst    #2,Obj5D_status(a1)
    beq.s   Obj5D_Gunk_Main
    bclr    #2,Obj5D_status(a1)
    move.b  #6,routine_secondary(a0)    ; => Obj5D_Gunk_6
    move.w  #9,Obj5D_timer2(a0)
 
Obj5D_Gunk_Main:
    jsrto   (ObjectMoveAndFall).l, JmpTo3_ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bmi.s   +   ; branch, if hit the floor
    cmpi.w  #$518,y_pos(a0)
    bge.s   Obj5D_Gunk_OffScreen    ; branch, if fallen off screen
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
+
    add.w   d1,y_pos(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1
    bset    #2,Obj5D_status2(a1)
    bset    #4,Obj5D_status2(a1)
    move.b  #2,routine_secondary(a1)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Gunk_Droplets
    move.b  #0,subtype(a0)
    move.w  #SndID_MegaMackDrop,d0
    jsrto   (PlaySound).l, JmpTo5_PlaySound
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Gunk_OffScreen:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1
    bset    #2,Obj5D_status2(a1)
    bset    #4,Obj5D_status2(a1)
    move.b  #2,routine_secondary(a1)
    bra.w   JmpTo51_DeleteObject
; ===========================================================================
 
Obj5D_Gunk_6:
    subi_.w #1,Obj5D_timer2(a0)
    bpl.s   +
    move.b  #2,priority(a0)
    move.b  #$25,mapping_frame(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj5D_Gunk_8
    move.b  #8,anim_frame_duration(a0)
    bra.s   Obj5D_Gunk_8
; ===========================================================================
+
    jsrto   (ObjectMove).l, JmpTo23_ObjectMove
    lea (Ani_Obj5D_Dripper).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Gunk_8:
    subi_.b #1,anim_frame_duration(a0)
    bpl.s   +
    addi_.b #1,mapping_frame(a0)
    move.b  #8,anim_frame_duration(a0)
    cmpi.b  #$27,mapping_frame(a0)
    bgt.w   Obj5D_Gunk_OffScreen
    blt.s   +
    addi.b  #$C,anim_frame_duration(a0)
+
    movea.l Obj5D_parent(a0),a1 ; a1=object
    movea.l Obj5D_parent(a1),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    jmp (DisplaySprite).l
; ===========================================================================
 
Obj5D_Gunk_Droplets:
    moveq   #0,d0
    move.b  subtype(a0),d0
    bne.w   Obj5D_Gunk_Droplets_Move
    addi.w  #$18,y_pos(a0)
    addi.w  #$C,x_pos(a0)
    btst    #0,render_flags(a0)
    beq.s   +
    subi.w  #$18,x_pos(a0)
+
    move.b  #4,y_radius(a0)
    move.b  #4,x_radius(a0)
    addq.b  #1,subtype(a0)
    move.b  #9,mapping_frame(a0)
    move.w  y_vel(a0),d0
    lsr.w   #1,d0
    neg.w   d0
    move.w  d0,y_vel(a0)
    jsr (RandomNumber).l
    asr.w   #6,d0
    bmi.s   +
    addi.w  #$200,d0
+
    addi.w  #-$100,d0
    move.w  d0,x_vel(a0)
    move.b  #0,collision_flags(a0)
    moveq   #3,d3
 
Obj5D_Gunk_Droplets_Loop:
    jsr (SingleObjLoad2).l
    bne.w   BranchTo_JmpTo34_DisplaySprite
    _move.b #ObjID_CPZBoss,id(a1) ; load obj5D
    move.l  a0,Obj5D_parent(a1)
    move.l  #Obj5D_MapUnc_2EADC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_CPZBoss,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #2,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #4,y_radius(a1)
    move.b  #4,x_radius(a1)
    move.b  #9,mapping_frame(a1)
    move.b  #$C,routine(a1)
    move.b  #4,routine_secondary(a1)
    move.b  #1,subtype(a1) 
    move.w  y_vel(a0),y_vel(a1)
    move.b  collision_flags(a0),collision_flags(a1)
    jsr (RandomNumber).l
    asr.w   #6,d0
    bmi.s   +
    addi.w  #$80,d0
+
    addi.w  #-$80,d0
    move.w  d0,x_vel(a1)
    swap    d0
    andi.w  #$3FF,d0
    sub.w   d0,y_vel(a1)
    dbf d3,Obj5D_Gunk_Droplets_Loop
 
BranchTo_JmpTo34_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo34_DisplaySprite
; ===========================================================================
 
Obj5D_Gunk_Droplets_Move:
    jsrto   (ObjectMoveAndFall).l, JmpTo3_ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bmi.s   +
    jmpto   (MarkObjGone).l, JmpTo35_MarkObjGone
; ---------------------------------------------------------------------------
+
    bra.w   JmpTo51_DeleteObject
; ===========================================================================
 
    ; a bit of unused/dead code here
    add.w   d1,y_pos(a0) ; a0=object
    move.w  y_vel(a0),d0
    lsr.w   #1,d0
    neg.w   d0
    move.w  d0,y_vel(a0)
    jmpto   (DisplaySprite).l, JmpTo34_DisplaySprite
 
; ===========================================================================
 
Obj5D_Robotnik:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    move.b  Obj5D_invulnerable_time(a1),d0
    cmpi.b  #$1F,d0
    bne.s   +
    move.b  #2,anim(a0)
+
    cmpi.b  #4,(MainCharacter+routine).w
    beq.s   +
    cmpi.b  #4,(Sidekick+routine).w
    bne.s   Obj5D_Robotnik_End
+
    move.b  #3,anim(a0)
 
Obj5D_Robotnik_End:
    lea (Ani_obj5D_b).l,a1
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
byte_2E94A:
    dc.b   0
    dc.b $FF    ; 1
    dc.b   1    ; 2
    dc.b   0    ; 3
; ===========================================================================
 
Obj5D_Flame:
    btst    #7,status(a0)
    bne.s   loc_2E9A8
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_2E996
    move.b  #1,anim_frame_duration(a0)
    move.b  Obj5D_timer2(a0),d0
    addq.b  #1,d0
    cmpi.b  #2,d0
    ble.s   +
    moveq   #0,d0
+
    move.b  byte_2E94A(pc,d0.w),mapping_frame(a0)
    move.b  d0,Obj5D_timer2(a0)
 
loc_2E996:
    cmpi.b  #-1,mapping_frame(a0)
    bne.w   JmpTo34_DisplaySprite
    move.b  #0,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_2E9A8:
    movea.l Obj5D_parent(a0),a1 ; a1=object
    btst    #6,Obj5D_status2(a1)
    bne.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.l  #Obj5D_MapUnc_2EEA0,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_EggpodJets_1,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo60_Adjust2PArtPointer
    move.b  #0,mapping_frame(a0)
    move.b  #5,anim_frame_duration(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi_.w #4,y_pos(a0)
    subi.w  #$28,x_pos(a0)
    rts
; ===========================================================================
 
Obj5D_1A:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   BranchTo2_JmpTo34_DisplaySprite
    move.b  #5,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #4,mapping_frame(a0)
    bne.w   BranchTo2_JmpTo34_DisplaySprite
    move.b  #0,mapping_frame(a0)
    movea.l Obj5D_parent(a0),a1 ; a1=object
    move.b  id(a1),d0
    beq.w   JmpTo51_DeleteObject    ; branch, if parent object is gone
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi_.w #4,y_pos(a0)
    subi.w  #$28,x_pos(a0)
 
BranchTo2_JmpTo34_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo34_DisplaySprite
; ===========================================================================
; animation script
; off_2EA3C:
Ani_Obj5D_Dripper:  offsetTable
        offsetTableEntry.w byte_2EA72   ;   0
        offsetTableEntry.w byte_2EA75   ;   1
        offsetTableEntry.w byte_2EA78   ;   2
        offsetTableEntry.w byte_2EA7D   ;   3
        offsetTableEntry.w byte_2EA81   ;   4
        offsetTableEntry.w byte_2EA88   ;   5
        offsetTableEntry.w byte_2EA8B   ;   6
        offsetTableEntry.w byte_2EA8E   ;   7
        offsetTableEntry.w byte_2EA91   ;   8
        offsetTableEntry.w byte_2EA94   ;   9
        offsetTableEntry.w byte_2EA97   ;  $A
        offsetTableEntry.w byte_2EAA3   ;  $B
        offsetTableEntry.w byte_2EAAE   ;  $C
        offsetTableEntry.w byte_2EAB1   ;  $D
        offsetTableEntry.w byte_2EAB4   ;  $E
        offsetTableEntry.w byte_2EAB7   ;  $F
        offsetTableEntry.w byte_2EABA   ; $10
        offsetTableEntry.w byte_2EABD   ; $11
        offsetTableEntry.w byte_2EAC0   ; $12
        offsetTableEntry.w byte_2EAC3   ; $13
        offsetTableEntry.w byte_2EAC6   ; $14
        offsetTableEntry.w byte_2EAC9   ; $15
        offsetTableEntry.w byte_2EACC   ; $16
        offsetTableEntry.w byte_2EACF   ; $17
        offsetTableEntry.w byte_2EAD2   ; $18
        offsetTableEntry.w byte_2EAD5   ; $19
        offsetTableEntry.w byte_2EAD9   ; $1A
byte_2EA72: dc.b  $F,  0,$FF 
    rev02even
byte_2EA75: dc.b  $F,  1,$FF
    rev02even
byte_2EA78: dc.b   5,  2,  3,  2,$FF
    rev02even
byte_2EA7D: dc.b   5,  2,  3,$FF
    rev02even
byte_2EA81: dc.b   2,  4,  5,  6,  7,  8,$FF
    rev02even
byte_2EA88: dc.b   3,  9,$FF
    rev02even
byte_2EA8B: dc.b  $F, $A,$FF
    rev02even
byte_2EA8E: dc.b  $F,$1C,$FF
    rev02even
byte_2EA91: dc.b  $F,$1E,$FF
    rev02even
byte_2EA94: dc.b  $F, $B,$FF
    rev02even
byte_2EA97: dc.b   3, $C, $C, $D, $D, $D, $D, $D, $C, $C,$FD,  9
    rev02even
byte_2EAA3: dc.b   3, $E, $E, $F, $F, $F, $F, $F, $E, $E,$FF
    rev02even
byte_2EAAE: dc.b  $F,$10,$FF
    rev02even
byte_2EAB1: dc.b  $F,$11,$FF
    rev02even
byte_2EAB4: dc.b  $F,$12,$FF
    rev02even
byte_2EAB7: dc.b  $F,$13,$FF
    rev02even
byte_2EABA: dc.b  $F,$14,$FF
    rev02even
byte_2EABD: dc.b  $F,$15,$FF
    rev02even
byte_2EAC0: dc.b  $F,$16,$FF
    rev02even
byte_2EAC3: dc.b  $F,$17,$FF
    rev02even
byte_2EAC6: dc.b  $F,$18,$FF
    rev02even
byte_2EAC9: dc.b  $F,$19,$FF
    rev02even
byte_2EACC: dc.b  $F,$1A,$FF
    rev02even
byte_2EACF: dc.b  $F,$1B,$FF
    rev02even
byte_2EAD2: dc.b  $F,$1C,$FF
    rev02even
byte_2EAD5: dc.b   1,$1D,$1F,$FF
    rev02even
byte_2EAD9: dc.b  $F,$1E,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_CPZBoss
; ----------------------------------------------------------------------------
Obj5D_MapUnc_2EADC: BINCLUDE "mappings/sprite/obj5D_a.bin"
 
; animation script
; off_2ED5C:
Ani_obj5D_b:    offsetTable
        offsetTableEntry.w byte_2ED66   ; 0
        offsetTableEntry.w byte_2ED69   ; 1
        offsetTableEntry.w byte_2ED6D   ; 2
        offsetTableEntry.w byte_2ED76   ; 3
        offsetTableEntry.w byte_2ED7F   ; 4
byte_2ED66: dc.b  $F,  0,$FF
    rev02even
byte_2ED69: dc.b   7,  1,  2,$FF
    rev02even
byte_2ED6D: dc.b   7,  5,  5,  5,  5,  5,  5,$FD,  1
    rev02even
byte_2ED76: dc.b   7,  3,  4,  3,  4,  3,  4,$FD,  1
    rev02even
byte_2ED7F: dc.b  $F,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,$FD,  1
    even
 
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_Eggpod
; ----------------------------------------------------------------------------
Obj5D_MapUnc_2ED8C: BINCLUDE "mappings/sprite/obj5D_b.bin"
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_EggpodJets
; ----------------------------------------------------------------------------
Obj5D_MapUnc_2EE88: BINCLUDE "mappings/sprite/obj5D_c.bin"
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_BossSmoke
; ----------------------------------------------------------------------------
Obj5D_MapUnc_2EEA0: BINCLUDE "mappings/sprite/obj5D_d.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo34_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo51_DeleteObject 
    jmp (DeleteObject).l
JmpTo35_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo5_PlaySound 
    jmp (PlaySound).l
JmpTo8_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo5_LoadPLC 
    jmp (LoadPLC).l
JmpTo2_AddPoints 
    jmp (AddPoints).l
JmpTo60_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
JmpTo3_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
; loc_2EF12:
JmpTo23_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 56 - EHZ boss
; the bottom part of the vehicle with the ability to fly is the parent object
; ----------------------------------------------------------------------------
; Sprite_2EF18:
Obj56:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj56_Index(pc,d0.w),d1
    jmp Obj56_Index(pc,d1.w)
; ===========================================================================
; off_2EF26:
Obj56_Index:    offsetTable
        offsetTableEntry.w Obj56_Init   ; 0 - Init
        offsetTableEntry.w loc_2F262    ; 2 - Flying vehicle, bottom = main object
        offsetTableEntry.w loc_2F54E    ; 4 - Propeller normal
        offsetTableEntry.w loc_2F5F6    ; 6 - Vehicle on ground
        offsetTableEntry.w loc_2F664    ; 8 - Wheels
        offsetTableEntry.w loc_2F7F4    ; A - Spike
        offsetTableEntry.w loc_2F52A    ; C - Propeller after defeat
        offsetTableEntry.w loc_2F8DA    ; E - Flying vehicle, top
; ===========================================================================
 
; #7,status(ax) set via collision response routine (Touch_Enemy_Part2)
;   when after a hit collision_property(ax) = hitcount has reached zero
; objoff_2A(ax) used as timer (countdown)
; objoff_2C(ax) tertiary rountine counter
; #0,objoff_2D(ax) set when robotnik is on ground
; #1,objoff_2D(ax) set when robotnik is active (moving back & forth)
; #2,objoff_2D(ax) set when robotnik is flying off after being defeated
;   #3,objoff_2D(ax) flag to separate spike from vehicle
; objoff_2E(ax) y_position of wheels
;   objoff_34(ax) parent object
; objoff_3C(ax) timer after defeat
 
; loc_2EF36:
Obj56_Init:
    move.l  #Obj56_MapUnc_2FAF8,mappings(a0)    ; main object
    move.w  #make_art_tile(ArtTile_ArtNem_Eggpod_1,1,0),art_tile(a0) ; vehicle with ability to fly, bottom part
    ori.b   #4,render_flags(a0)
    move.b  #$81,subtype(a0) 
    move.w  #$29D0,x_pos(a0)
    move.w  #$426,y_pos(a0)
    move.b  #$20,width_pixels(a0)
    move.b  #$14,y_radius(a0)
    move.b  #4,priority(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,collision_property(a0)   ; hitcount
    addq.b  #2,routine(a0)
    move.w  x_pos(a0),objoff_30(a0)
    move.w  y_pos(a0),objoff_38(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo61_Adjust2PArtPointer
    jsr (SingleObjLoad2).l  ; vehicle with ability to fly, top part
    bne.w   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; link top and bottom to each other
    move.l  a1,objoff_34(a0)    ; i.e. addresses for cross references
    move.l  #Obj56_MapUnc_2FAF8,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Eggpod_1,0,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #4,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #$E,routine(a1)
    move.b  #1,anim(a1) ; normal animation
    move.b  render_flags(a0),render_flags(a1)
+
    jsr (SingleObjLoad2).l  ; Vehicle on ground
    bne.s   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2FA58,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZBoss,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$30,width_pixels(a1)
    move.b  #$10,y_radius(a1)
    move.b  #3,priority(a1)
    move.w  #$2AF0,x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.b  #6,routine(a1)
+
    bsr.w   loc_2F098
    subi_.w #8,objoff_38(a0)
    move.w  #$2AF0,x_pos(a0)
    move.w  #$2F8,y_pos(a0)
    jsr (SingleObjLoad2).l  ; propeller normal
    bne.s   +   ; rts
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2F970,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EggChoppers,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$40,width_pixels(a1)
    move.b  #3,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    move.w  #$1E,objoff_2A(a1)
    move.b  #4,routine(a1)
+
    rts
; ---------------------------------------------------------------------------
 
loc_2F098:
    jsr (SingleObjLoad2).l  ; first foreground wheel
    bne.s   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2FA58,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZBoss,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #2,priority(a1)
    move.b  #$10,y_radius(a1)
    move.b  #$10,x_radius(a1)
    move.w  #$2AF0,x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.w  #$1C,x_pos(a1)
    addi.w  #$C,y_pos(a1)
    move.b  #8,routine(a1)
    move.b  #4,mapping_frame(a1)
    move.b  #1,anim(a1)
    move.w  #$A,objoff_2A(a1)
    move.b  #0,subtype(a1) 
+
    jsr (SingleObjLoad2).l  ; second foreground wheel
    bne.s   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2FA58,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZBoss,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #2,priority(a1)
    move.b  #$10,y_radius(a1)
    move.b  #$10,x_radius(a1)
    move.w  #$2AF0,x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.w  #-$C,x_pos(a1)
    addi.w  #$C,y_pos(a1)
    move.b  #8,routine(a1)
    move.b  #4,mapping_frame(a1)
    move.b  #1,anim(a1)
    move.w  #$A,objoff_2A(a1)
    move.b  #1,subtype(a1) 
+
    jsr (SingleObjLoad2).l  ; background wheel
    bne.s   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2FA58,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZBoss,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #3,priority(a1)
    move.b  #$10,y_radius(a1)
    move.b  #$10,x_radius(a1)
    move.w  #$2AF0,x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.w  #-$2C,x_pos(a1)
    addi.w  #$C,y_pos(a1)
    move.b  #8,routine(a1)
    move.b  #6,mapping_frame(a1)
    move.b  #2,anim(a1)
    move.w  #$A,objoff_2A(a1)
    move.b  #2,subtype(a1) 
+
    jsr (SingleObjLoad2).l  ; Spike
    bne.s   +
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2FA58,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EHZBoss,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #2,priority(a1)
    move.w  #$2AF0,x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.w  #-$36,x_pos(a1)
    addi_.w #8,y_pos(a1)
    move.b  #$A,routine(a1)
    move.b  #1,mapping_frame(a1)
    move.b  #0,anim(a1)
+
    rts
; ===========================================================================
 
loc_2F262:  ; Obj56_VehicleMain:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_2F270(pc,d0.w),d1
    jmp off_2F270(pc,d1.w)
; ---------------------------------------------------------------------------
off_2F270:  offsetTable
        offsetTableEntry.w loc_2F27C    ; 0 - approaching diagonally
        offsetTableEntry.w loc_2F2A8    ; 2 - final approaching stage (vertically/waiting)
        offsetTableEntry.w loc_2F304    ; 4 - moving back and forth
        offsetTableEntry.w loc_2F336    ; 6 - boss defeated, falling/lying on ground
        offsetTableEntry.w loc_2F374    ; 8 - boss idle for $C frames
        offsetTableEntry.w loc_2F38A    ; A - flying off, moving camera
; ===========================================================================
 
loc_2F27C:  ; Obj56_VehicleMain_Sub0:
    move.b  #0,collision_flags(a0)
    cmpi.w  #$29D0,x_pos(a0)    ; reached the point to unite with bottom vehicle?
    ble.s   loc_2F29A
    subi_.w #1,x_pos(a0)
    addi_.w #1,y_pos(a0)    ; move diagonally down
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F29A:
    move.w  #$29D0,x_pos(a0)
    addq.b  #2,routine_secondary(a0)    ; next routine
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F2A8:  ; Obj56_VehicleMain_Sub2:
    moveq   #0,d0
    move.b  objoff_2C(a0),d0    ; tertiary routine
    move.w  off_2F2B6(pc,d0.w),d1
    jmp off_2F2B6(pc,d1.w)
; ---------------------------------------------------------------------------
off_2F2B6:  offsetTable
        offsetTableEntry.w loc_2F2BA    ; 0 - moving down to ground vehicle vertically
        offsetTableEntry.w loc_2F2E0    ; 2 - not moving, delay until activation
; ---------------------------------------------------------------------------
 
loc_2F2BA:  ; Obj56_VehicleMain_Sub2_0:
    cmpi.w  #$41E,y_pos(a0)
    bge.s   loc_2F2CC
    addi_.w #1,y_pos(a0)    ; move vertically (down)
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F2CC:
    addq.b  #2,objoff_2C(a0)    ; tertiary routine
    bset    #0,objoff_2D(a0)    ; robotnik on ground (relevant for propeller)
    move.w  #$3C,objoff_2A(a0)  ; timer for standing still
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F2E0:  ; Obj56_VehicleMain_Sub2_2:
    subi_.w #1,objoff_2A(a0)    ; timer
    bpl.w   JmpTo35_DisplaySprite
    move.w  #-$200,x_vel(a0)
    addq.b  #2,routine_secondary(a0)
    move.b  #$F,collision_flags(a0)
    bset    #1,objoff_2D(a0)    ; boss now active and moving
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F304:  ; Obj56_VehicleMain_Sub4:
    bsr.w   loc_2F4A6   ; routine to handle hits
    bsr.w   loc_2F484   ; position check, sets direction
    move.w  objoff_2E(a0),d0    ; y_position of wheels
    lsr.w   #1,d0
    subi.w  #$14,d0
    move.w  d0,y_pos(a0)    ; set y_pos depending on wheels
    move.w  #0,objoff_2E(a0)
    move.l  x_pos(a0),d2
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.l  d2,x_pos(a0)    ; set x_pos depening on velocity
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F336:  ; Obj56_VehicleMain_Sub6:
    subq.w  #1,objoff_3C(a0)    ; timer set after defeat
    bmi.s   loc_2F35C   ; if countdown finished
    bsr.w   Boss_LoadExplosion
    jsrto   (ObjectMoveAndFall).l, JmpTo4_ObjectMoveAndFall
    jsrto   (ObjCheckFloorDist).l, JmpTo3_ObjCheckFloorDist
    tst.w   d1
    bpl.w   JmpTo35_DisplaySprite
    add.w   d1,y_pos(a0)
    move.w  #0,y_vel(a0)    ; set to ground and stand still
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F35C:
    clr.w   x_vel(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #-$26,objoff_3C(a0)
    move.w  #$C,objoff_2A(a0)
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F374:  ; Obj56_VehicleMain_Sub8:
    subq.w  #1,objoff_2A(a0)    ; timer
    bpl.w   JmpTo35_DisplaySprite
    addq.b  #2,routine_secondary(a0)
    move.b  #0,objoff_2C(a0)    ; tertiary routine
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F38A:  ; Obj56_VehicleMain_SubA:
    moveq   #0,d0
    move.b  objoff_2C(a0),d0    ; tertiary routine
    move.w  off_2F39C(pc,d0.w),d1
    jsr off_2F39C(pc,d1.w)
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
off_2F39C:  offsetTable
        offsetTableEntry.w loc_2F3A2    ; 0 - initialize propellor
        offsetTableEntry.w loc_2F424    ; 2 - waiting
        offsetTableEntry.w loc_2F442    ; 4 - flying off
; ===========================================================================
 
loc_2F3A2:  ; Obj56_VehicleMain_SubA_0:
    bclr    #0,objoff_2D(a0)    ; robotnik off ground
    jsrto   (SingleObjLoad2).l, JmpTo21_SingleObjLoad2  ; reload propeller after defeat
    bne.w   +   ; rts
 
    _move.b #ObjID_EHZBoss,id(a1) ; load obj56
    move.l  a0,objoff_34(a1)    ; linked to main object
    move.l  #Obj56_MapUnc_2F970,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_EggChoppers,1,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer2).l, JmpTo9_Adjust2PArtPointer2
    move.b  #4,render_flags(a1)
    move.b  #$20,width_pixels(a1)
    move.b  #3,priority(a1)
    move.l  x_pos(a0),x_pos(a1)
    move.l  y_pos(a0),y_pos(a1)
    addi.w  #$C,y_pos(a1)
    move.b  status(a0),status(a1)
    move.b  render_flags(a0),render_flags(a1)
    move.b  #$C,routine(a1) 
    move.b  #2,anim(a1)
    move.w  #$10,objoff_2A(a1)  ; timer
    move.w  #$32,objoff_2A(a0)  ; timer
    addq.b  #2,objoff_2C(a0)    ; tertiary routine - increase
    jsrto   (PlayLevelMusic).l, JmpTo2_PlayLevelMusic ; play level Music
    move.b  #1,(Boss_defeated_flag).w
+
    rts
; ===========================================================================
 
loc_2F424:  ; Obj56_VehicleMain_SubA_2:
    subi_.w #1,objoff_2A(a0)    ; timer
    bpl.s   +   ; rts
    bset    #2,objoff_2D(a0)    ; robotnik flying off
    move.w  #$60,objoff_2A(a0)  ; timer
    addq.b  #2,objoff_2C(a0)    ; tertiary routine
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo2_LoadPLC_AnimalExplosion ; PLC_Explosion
+
    rts
; ===========================================================================
 
loc_2F442:  ; Obj56_VehicleMain_SubA_4:
    subi_.w #1,objoff_2A(a0)    ; timer
    bpl.s   loc_2F45C
    bset    #0,status(a0)
    bset    #0,render_flags(a0)
    addq.w  #6,x_pos(a0)
    bra.s   loc_2F460
; ===========================================================================
 
loc_2F45C:
    subq.w  #1,y_pos(a0)
 
loc_2F460:
    cmpi.w  #$2AB0,(Camera_Max_X_pos).w
    bhs.s   loc_2F46E
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   return_2F482
; ===========================================================================
 
loc_2F46E:
    tst.b   render_flags(a0)
    bmi.s   return_2F482
    addq.w  #4,sp
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    jsrto   (DeleteObject2).l, JmpTo5_DeleteObject2
    jmpto   (DeleteObject).l, JmpTo52_DeleteObject
; ===========================================================================
 
return_2F482:
    rts
; ===========================================================================
 
loc_2F484:  ; shared routine, checks positions and sets direction
    move.w  x_pos(a0),d0
    cmpi.w  #$28A0,d0   ; beyond left boundary?
    ble.s   loc_2F494
    cmpi.w  #$2B08,d0
    blt.s   return_2F4A4    ; beyond right boundary?
 
loc_2F494:  ; beyond boundary
    bchg    #0,status(a0)   ; change direction
    bchg    #0,render_flags(a0) ; mirror sprite
    neg.w   x_vel(a0)   ; change direction of velocity
 
return_2F4A4:
    rts
; ===========================================================================
 
loc_2F4A6:  ; routine to handle hits
    cmpi.b  #6,routine_secondary(a0)    ; is only called when value is 4?
    bhs.s   return_2F4EC    ; thus unnecessary? (return if greater or equal than 6)
    tst.b   status(a0)
    bmi.s   loc_2F4EE   ; sonic has just defeated the boss (i.e. bit 7 set)
    tst.b   collision_flags(a0) ; set to 0 when boss was hit by Touch_Enemy_Part2
    bne.s   return_2F4EC    ; not 0, i.e. boss not hit
    tst.b   objoff_3E(a0)
    bne.s   loc_2F4D0   ; boss already invincibile
    move.b  #$20,objoff_3E(a0)  ; boss invincibility timer
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l   ; play boss hit sound
 
loc_2F4D0:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0   ; black
    tst.w   (a1)
    bne.s   loc_2F4DE   ; already not black (i.e. white)?
    move.w  #$EEE,d0    ; white
 
loc_2F4DE:
    move.w  d0,(a1) ; set respective color
    subq.b  #1,objoff_3E(a0)    ; decrease boss invincibility timer
    bne.s   return_2F4EC
    move.b  #$F,collision_flags(a0) ; if invincibility ended, allow collision again
 
return_2F4EC:
    rts
; ===========================================================================
 
loc_2F4EE:  ;   boss defeated
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo3_AddPoints ; add 1000 points, reward for defeating boss
    move.b  #6,routine_secondary(a0)
    move.w  #0,x_vel(a0)
    move.w  #-$180,y_vel(a0)
    move.w  #$B3,objoff_3C(a0)  ; timer
    bset    #3,objoff_2D(a0)    ; flag to separate spike from vehicle
    movea.l objoff_34(a0),a1 ; address top part
    move.b  #4,anim(a1) ; flying off animation
    move.b  #6,mapping_frame(a1)
    moveq   #PLCID_Capsule,d0
    jmpto   (LoadPLC).l, JmpTo6_LoadPLC ; load egg prison
; ===========================================================================
    rts
; ===========================================================================
 
loc_2F52A:  ; Obj56_PropellerReloaded:  ; Propeller after defeat
    subi_.w #1,y_pos(a0)    ; move up
    subi_.w #1,objoff_2A(a0)    ; decrease timer
    bpl.w   JmpTo35_DisplaySprite
    move.b  #4,routine(a0)  ; Propeller normal
    lea (Ani_obj56_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F54E:  ; Obj56_Propeller:  ; Propeller normal
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_2F55C(pc,d0.w),d1
    jmp off_2F55C(pc,d1.w)
; ---------------------------------------------------------------------------
off_2F55C:  offsetTable
        offsetTableEntry.w loc_2F560    ; 0 - robotnik in air
        offsetTableEntry.w loc_2F5C6    ; 2 - robotnik on ground
; ---------------------------------------------------------------------------
 
loc_2F560:  ; Obj56_Propeller_Sub0
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    cmpi.b  #ObjID_EHZBoss,id(a1)
    bne.w   JmpTo52_DeleteObject    ; if boss non-existant
    btst    #0,objoff_2D(a1)    ; is robotnik on ground?
    beq.s   loc_2F58E   ; if not, branch
    move.b  #1,anim(a0)
    move.w  #$18,objoff_2A(a0)  ; timer until deletion
    addq.b  #2,routine_secondary(a0)
    move.b  #MusID_StopSFX,d0
    jsrto   (PlaySound).l, JmpTo6_PlaySound
    bra.s   loc_2F5A0
; ---------------------------------------------------------------------------
 
loc_2F58E:  ; not on ground
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   loc_2F5A0
    move.b  #SndID_Helicopter,d0
    jsrto   (PlaySound).l, JmpTo6_PlaySound
 
loc_2F5A0:
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    lea (Ani_obj56_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F5C6:  ; Obj56_Propeller_Sub2
    subi_.w #1,objoff_2A(a0)    ; timer
    bpl.s   loc_2F5E8
    cmpi.w  #-$10,objoff_2A(a0)
    ble.w   JmpTo52_DeleteObject
    move.b  #4,priority(a0)
    addi_.w #1,y_pos(a0)    ; move down
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F5E8:
    lea (Ani_obj56_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F5F6:  ; Obj56_GroundVehicle:
    tst.b   routine_secondary(a0)
    bne.s   loc_2F626
; Obj56_GroundVehicle_Sub0:
    cmpi.w  #$28F0,(Camera_Min_X_pos).w
    blo.w   JmpTo35_DisplaySprite
    cmpi.w  #$29D0,x_pos(a0)
    ble.s   loc_2F618
    subi_.w #1,x_pos(a0)
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F618:
    move.w  #$29D0,x_pos(a0)
    addq.b  #2,routine_secondary(a0)
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F626:  ; Obj56_GroundVehicle_Sub2:
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    btst    #1,objoff_2D(a1)
    beq.w   JmpTo35_DisplaySprite   ; boss not moving yet (inactive)
    btst    #2,objoff_2D(a1)    ; robotnik flying off flag
    bne.w   JmpTo35_DisplaySprite
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi_.w #8,y_pos(a0)
    move.b  status(a1),status(a0)
    bmi.w   JmpTo35_DisplaySprite
    move.b  render_flags(a1),render_flags(a0)
    bra.w   JmpTo35_DisplaySprite
; ===========================================================================
 
loc_2F664:  ; Obj56_Wheel:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_2F672(pc,d0.w),d1
    jmp off_2F672(pc,d1.w)
; ---------------------------------------------------------------------------
off_2F672:  offsetTable
        offsetTableEntry.w loc_2F67C    ; 0 - wheels moving towards start position
        offsetTableEntry.w loc_2F714    ; 2 - standing still (boss inactive)
        offsetTableEntry.w loc_2F746    ; 4 - normal mode (boss active)
        offsetTableEntry.w loc_2F7A6    ; 6 - inactive while defeat
        offsetTableEntry.w loc_2F7D2    ; 8 - wheels bouncing away after defeat
; ---------------------------------------------------------------------------
 
loc_2F67C:  ; Obj56_Wheel_Sub0:
    cmpi.w  #$28F0,(Camera_Min_X_pos).w
    blo.w   JmpTo35_DisplaySprite
    move.w  #$100,y_vel(a0)
    cmpi.b  #1,subtype(a0)  ; wheel number (0-2)
    bgt.s   loc_2F6B6   ; background wheel
    beq.s   loc_2F6A6   ; second foreground wheel
; ---------------------------------------------------------------------------
    cmpi.w  #$29EC,x_pos(a0)    ; first foreground wheel
    ble.s   loc_2F6C6
    subi_.w #1,x_pos(a0)
    bra.s   loc_2F6E8
 
loc_2F6A6:  ; second foreground wheel
    cmpi.w  #$29C4,x_pos(a0)
    ble.s   loc_2F6D2
    subi_.w #1,x_pos(a0)
    bra.s   loc_2F6E8
 
loc_2F6B6:  ; background wheel
    cmpi.w  #$29A4,x_pos(a0)
    ble.s   loc_2F6DE
    subi_.w #1,x_pos(a0)
    bra.s   loc_2F6E8
; ---------------------------------------------------------------------------
 
loc_2F6C6:  ; first foreground wheel
    move.w  #$29EC,x_pos(a0)
    addq.b  #2,routine_secondary(a0)
    bra.s   loc_2F6E8
 
loc_2F6D2:  ; second foreground wheel
    move.w  #$29C4,x_pos(a0)
    addq.b  #2,routine_secondary(a0)
    bra.s   loc_2F6E8
 
loc_2F6DE:  ; background wheel
    move.w  #$29A4,x_pos(a0)
    addq.b  #2,routine_secondary(a0)
; ---------------------------------------------------------------------------
 
loc_2F6E8:  ; routine for all wheels
    jsrto   (ObjectMoveAndFall).l, JmpTo4_ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   loc_2F6FA
    add.w   d1,y_pos(a0)    ; reset on floor
 
loc_2F6FA:
    tst.b   routine_secondary(a0)
    beq.s   loc_2F706
    move.w  #-$200,x_vel(a0)    ; if reached position, set velocity
 
loc_2F706:
    lea (Ani_obj56_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F714:  ; Obj56_Wheel_Sub2:
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    cmpi.b  #ObjID_EHZBoss,id(a1)
    bne.w   JmpTo52_DeleteObject    ; if boss non-existant
    btst    #1,objoff_2D(a1)
    beq.w   JmpTo35_DisplaySprite   ; boss not moving yet (inactive)
    addq.b  #2,routine_secondary(a0)
    cmpi.b  #2,priority(a0)
    bne.s   BranchTo_JmpTo35_DisplaySprite
    move.w  y_pos(a0),d0
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    add.w   d0,objoff_2E(a1)
 
BranchTo_JmpTo35_DisplaySprite 
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F746:  ; Obj56_Wheel_Sub4:
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    cmpi.b  #ObjID_EHZBoss,id(a1)
    bne.w   JmpTo52_DeleteObject    ; if boss non-existant
    move.b  status(a1),status(a0)
    move.b  render_flags(a1),render_flags(a0)
    tst.b   status(a0)
    bpl.s   loc_2F768   ; has sonic just defeated the boss (i.e. bit7 set)?
    addq.b  #2,routine_secondary(a0)    ; if yes, Sub6
 
loc_2F768:
    bsr.w   loc_2F484   ; position check, sets direction
    jsrto   (ObjectMoveAndFall).l, JmpTo4_ObjectMoveAndFall
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   loc_2F77E
    add.w   d1,y_pos(a0)    ; reset on floor
 
loc_2F77E:
    move.w  #$100,y_vel(a0)
    cmpi.b  #2,priority(a0)
    bne.s   loc_2F798
    move.w  y_pos(a0),d0
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    add.w   d0,objoff_2E(a1)
 
loc_2F798:
    lea (Ani_obj56_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F7A6:  ; Obj56_Wheel_Sub6:
    subi_.w #1,objoff_2A(a0)    ; timer, initially set to $A (first delay until wheels rolling off)
    bpl.w   JmpTo35_DisplaySprite
    addq.b  #2,routine_secondary(a0)    ; Sub8
    move.w  #$A,objoff_2A(a0)
    move.w  #-$300,y_vel(a0)    ; first bounce higher
    cmpi.b  #2,priority(a0)
    beq.w   JmpTo35_DisplaySprite
    neg.w   x_vel(a0)   ; into other direction
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F7D2:  ; Obj56_Wheel_Sub8:
    subq.w  #1,objoff_2A(a0)    ; timer, initially set to $A (second delay until wheels rolling off)
    bpl.w   JmpTo35_DisplaySprite
    jsrto   (ObjectMoveAndFall).l, JmpTo4_ObjectMoveAndFall
    jsrto   (ObjCheckFloorDist).l, JmpTo3_ObjCheckFloorDist
    tst.w   d1
    bpl.s   BranchTo_JmpTo36_MarkObjGone
    move.w  #-$200,y_vel(a0)    ; negative velocity to have bouncing effect
    add.w   d1,y_pos(a0)    ; reset on floor
 
BranchTo_JmpTo36_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo36_MarkObjGone
; ===========================================================================
 
loc_2F7F4:  ; Obj56_Spike:
    tst.b   routine_secondary(a0)
    bne.s   loc_2F824
; Obj56_Spike_Sub0:
    cmpi.w  #$28F0,(Camera_Min_X_pos).w
    blo.w   JmpTo35_DisplaySprite
    cmpi.w  #$299A,x_pos(a0)
    ble.s   loc_2F816
    subi_.w #1,x_pos(a0)
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F816:
    move.w  #$299A,x_pos(a0)
    addq.b  #2,routine_secondary(a0)
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F824:  ; Obj56_Spike_Sub2:
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    cmpi.b  #ObjID_EHZBoss,id(a1)
    bne.w   JmpTo52_DeleteObject    ; if boss non-existant
    btst    #3,objoff_2D(a1)
    bne.s   loc_2F88A   ; spike separated from vehicle
    bsr.w   loc_2F8AA
    btst    #1,objoff_2D(a1)
    beq.w   JmpTo35_DisplaySprite   ; boss not moving yet (inactive)
    move.b  #$8B,collision_flags(a0)    ; spike still linked to vehicle
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)   ; transfer positions
    move.b  render_flags(a1),render_flags(a0)
    addi.w  #$10,y_pos(a0)  ; vertical offset
    move.w  #-$36,d0
    btst    #0,status(a0)
    beq.s   loc_2F878
    neg.w   d0
 
loc_2F878:
    add.w   d0,x_pos(a0)    ; horizontal offset
    lea (Ani_obj56_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F88A:  ; spike separated from vehicle
    move.w  #-3,d0  ; velocity of spike in pixels/frame
    btst    #0,status(a0)   ; check direction
    beq.s   loc_2F898
    neg.w   d0
 
loc_2F898:
    add.w   d0,x_pos(a0)
    lea (Ani_obj56_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo17_AnimateSprite
    bra.w   JmpTo35_DisplaySprite
; ---------------------------------------------------------------------------
 
loc_2F8AA:
    cmpi.b  #1,collision_property(a1)   ; hit counter, only 1 life left?
    beq.s   loc_2F8B4
    rts
; ---------------------------------------------------------------------------
 
loc_2F8B4:
    move.w  x_pos(a0),d0
    sub.w   (MainCharacter+x_pos).w,d0
    bpl.s   loc_2F8C8
    btst    #0,status(a1)   ; sonic right from spike
    bne.s   loc_2F8D2   ; spike facing right
    rts
; ---------------------------------------------------------------------------
 
loc_2F8C8:
    btst    #0,status(a1)   ; sonic left from spike
    beq.s   loc_2F8D2   ; spike facing left
    rts
; ---------------------------------------------------------------------------
 
loc_2F8D2:
    bset    #3,objoff_2D(a1)    ; flag to separate spike from vehicle
    rts
; ===========================================================================
 
loc_2F8DA:  ; Obj56_VehicleTop:
    movea.l objoff_34(a0),a1 ; parent address (vehicle)
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    move.b  status(a1),status(a0)   ; update position and status
    move.b  render_flags(a1),render_flags(a0)
    move.b  objoff_3E(a1),d0    ; boss invincibility timer
    cmpi.b  #$1F,d0 ; boss just got hit?
    bne.s   loc_2F906
    move.b  #2,anim(a0) ; robotnik animation when hit
 
loc_2F906:
    cmpi.b  #4,(MainCharacter+routine).w    ; Sonic = ball
    beq.s   loc_2F916
    cmpi.b  #4,(Sidekick+routine).w ; Tails = ball
    bne.s   loc_2F924
 
loc_2F916:
    cmpi.b  #2,anim(a0) ; check eggman animation (when hit)
    beq.s   loc_2F924
    move.b  #3,anim(a0) ; eggman animation when hurting sonic
 
loc_2F924:
    lea (Ani_obj56_c).l,a1  ; animation script
    jsr (AnimateSprite).l
    jmp (DisplaySprite).l
; ===========================================================================
; animation script
; off_2F936:
Ani_obj56_a:    offsetTable
        offsetTableEntry.w byte_2F93C   ; 0
        offsetTableEntry.w byte_2F940   ; 1
        offsetTableEntry.w byte_2F956   ; 2
byte_2F93C:
    dc.b   1,  5,  6,$FF
byte_2F940:
    dc.b   1,  1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  0,  0,  0
    dc.b   0,  0,  0,  0,  0,$FF; 16
byte_2F956:
    dc.b   1,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  4,  3,  3,  3,  2
    dc.b   2,  2,  1,  1,  1,  5,  6,$FE,  2
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj56_MapUnc_2F970: BINCLUDE "mappings/sprite/obj56_a.bin"
    ; propeller
    ; 7 frames
    
; animation script
; off_2FA44:
Ani_obj56_b:    offsetTable
        offsetTableEntry.w byte_2FA4A   ; 0
        offsetTableEntry.w byte_2FA4F   ; 1
        offsetTableEntry.w byte_2FA53   ; 2
byte_2FA4A:
    dc.b   5,  1,  2,  3,$FF    ; spike
    rev02even
byte_2FA4F:
    dc.b   1,  4,  5,$FF    ; foreground wheel
    rev02even
byte_2FA53:
    dc.b   1,  6,  7,$FF    ; background wheel
    even
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj56_MapUnc_2FA58: BINCLUDE "mappings/sprite/obj56_b.bin"
    ; ground vehicle
    ; frame 0 = vehicle itself
    ; frame 1-3 = spike
    ;   frame 4-5 = foreground wheel
    ; frame 6-7 = background wheel
 
; animation script
; off_2FAC8:
Ani_obj56_c:    offsetTable
        offsetTableEntry.w byte_2FAD2   ; 0
        offsetTableEntry.w byte_2FAD5   ; 1
        offsetTableEntry.w byte_2FAD9   ; 2
        offsetTableEntry.w byte_2FAE2   ; 3
        offsetTableEntry.w byte_2FAEB   ; 4
byte_2FAD2: dc.b  $F,  0,$FF    ; bottom
    rev02even
byte_2FAD5: dc.b   7,  1,  2,$FF    ; top, normal
    rev02even
byte_2FAD9: dc.b   7,  5,  5,  5,  5,  5,  5,$FD,  1    ;   top, when hit
    rev02even
byte_2FAE2: dc.b   7,  3,  4,  3,  4,  3,  4,$FD,  1    ; top, laughter (when hurting sonic)
    rev02even
byte_2FAEB: dc.b  $F,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,$FD,  1    ; top, when flying off
    even    ; for top part, after end of special animations always return to normal one ($FD->1)
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj56_MapUnc_2FAF8: BINCLUDE "mappings/sprite/obj56_c.bin"
    ; flying vehicle
    ; frame 0 = bottom
    ; frame 1-2 = top, normal
    ; frame 3-4 = top, laughter
    ; frame 5 = top, when hit
    ; frame 6 = top, when flying off
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo35_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo52_DeleteObject 
    jmp (DeleteObject).l
JmpTo36_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo5_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo6_PlaySound 
    jmp (PlaySound).l
JmpTo21_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo17_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo9_Adjust2PArtPointer2 
    jmp (Adjust2PArtPointer2).l
JmpTo3_ObjCheckFloorDist 
    jmp (ObjCheckFloorDist).l
JmpTo6_LoadPLC 
    jmp (LoadPLC).l
JmpTo3_AddPoints 
    jmp (AddPoints).l
JmpTo61_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo2_PlayLevelMusic ; play level Music
    jmp (PlayLevelMusic).l
JmpTo2_LoadPLC_AnimalExplosion ; PLC_Explosion
    jmp (LoadPLC_AnimalExplosion).l
JmpTo4_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
 
    align 4
    else
JmpTo52_DeleteObject 
    jmp (DeleteObject).l
JmpTo35_DisplaySprite 
    jmp (DisplaySprite).l
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 52 - HTZ boss
; ----------------------------------------------------------------------------
; Sprite_2FC50:
Obj52:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj52_Index(pc,d0.w),d1
    jmp Obj52_Index(pc,d1.w)
; ===========================================================================
; off_2FC5E:
Obj52_Index:    offsetTable
        offsetTableEntry.w Obj52_Init           ; 0
        offsetTableEntry.w Obj52_Mobile         ; 2
        offsetTableEntry.w Obj52_FlameThrower   ; 4
        offsetTableEntry.w Obj52_LavaBall       ; 6
        offsetTableEntry.w loc_30210            ; 8
; ===========================================================================
; loc_2FC68:
Obj52_Init:
    move.l  #Obj52_MapUnc_302BC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Eggpod_2,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #-$70,mainspr_width(a0)
    move.b  #-$70,mainspr_height(a0)
    move.b  #4,priority(a0)
    move.w  #$3040,x_pos(a0)
    move.w  #$580,y_pos(a0)
    move.b  #1,objoff_2C(a0)
    move.b  #1,mainspr_mapframe(a0)
    addq.b  #2,boss_subtype(a0)
    bset    #6,render_flags(a0)
    move.b  #$32,collision_flags(a0)
    move.b  #8,objoff_32(a0)
    move.w  #-$E0,(Boss_Y_vel).w
    move.w  x_pos(a0),(Boss_X_pos).w
    move.w  y_pos(a0),(Boss_Y_pos).w
    clr.b   objoff_14(a0)
    move.w  x_pos(a0),sub2_x_pos(a0)
    move.w  y_pos(a0),sub2_y_pos(a0)
    move.b  #2,sub2_mapframe(a0)
    bsr.w   loc_2FCEA
    rts
; ===========================================================================
 
loc_2FCEA:
    lea (Boss_AnimationArray).w,a2
    move.b  #6,(a2)+
    move.b  #0,(a2)+
    move.b  #$10,(a2)+
    move.b  #0,(a2)+
    rts
; ===========================================================================
 
; loc_2FD00:
Obj52_Mobile:
    moveq   #0,d0
    move.b  angle(a0),d0
    move.w  off_2FD0E(pc,d0.w),d1
    jmp off_2FD0E(pc,d1.w)
; ===========================================================================
off_2FD0E:  offsetTable
        offsetTableEntry.w Obj52_Mobile_Raise           ; 0
        offsetTableEntry.w Obj52_Mobile_Flamethrower    ; 2
        offsetTableEntry.w Obj52_Mobile_BeginLower      ; 4
        offsetTableEntry.w Obj52_Mobile_Lower           ; 6
        offsetTableEntry.w Obj52_Mobile_Defeated                ; 8
; ===========================================================================
 
; loc_2FD18:
Obj52_Mobile_Raise:
    move.b  #0,(Boss_CollisionRoutine).w
    bsr.w   Boss_MoveObject
    tst.b   objoff_2C(a0)
    bne.s   loc_2FD32
    cmpi.w  #$518,(Boss_Y_pos).w
    bgt.s   loc_2FD50
    bra.s   loc_2FD3A
; ===========================================================================
 
loc_2FD32:
    cmpi.w  #$4FC,(Boss_Y_pos).w
    bgt.s   loc_2FD50
 
loc_2FD3A:
    move.w  #0,(Boss_Y_vel).w
    move.b  #4,mapping_frame(a0)
    addq.b  #2,angle(a0)
    move.b  #$3C,objoff_3E(a0)
 
loc_2FD50:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    bsr.w   loc_300A4
 
    if removeJmpTos
JmpTo36_DisplaySprite 
    endif
 
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
; loc_2FD5E:
Obj52_Mobile_Flamethrower:
    subi_.b #1,objoff_3E(a0)
    bpl.s   Obj52_Mobile_Hover
    move.b  #1,(Boss_CollisionRoutine).w
    move.b  #1,mainspr_childsprites(a0)
    cmpi.b  #-$18,objoff_3E(a0)
    bne.s   Obj52_Mobile_Hover
    jsrto   (SingleObjLoad).l, JmpTo13_SingleObjLoad
    bne.s   loc_2FDAA
    _move.b #ObjID_HTZBoss,id(a1) ; load obj52
    move.b  #4,boss_subtype(a1)
    move.b  render_flags(a0),render_flags(a1)
    andi.b  #1,render_flags(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #$2F,objoff_3E(a0)
 
loc_2FDAA:
    bsr.w   loc_300A4
    bsr.w   loc_2FEDE
    lea (Ani_obj52).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
; loc_2FDC0:
Obj52_Mobile_Hover:
    move.b  mapping_frame(a0),d0
    jsr (CalcSine).l
    asr.w   #7,d1
    add.w   (Boss_Y_pos).w,d1
    move.w  d1,y_pos(a0)
    addq.b  #4,mapping_frame(a0)
    bra.s   loc_2FDAA
; ===========================================================================
 
; loc_2FDDA:
Obj52_Mobile_BeginLower:
    move.b  #0,(Boss_CollisionRoutine).w
    move.b  #0,mainspr_childsprites(a0)
    move.b  #$10,(Boss_AnimationArray+2).w
    move.b  #0,(Boss_AnimationArray+3).w
    subi_.b #1,objoff_3E(a0)
    bne.w   Obj52_Mobile_Hover
    move.w  #$E0,(Boss_Y_vel).w
    addq.b  #2,angle(a0)
    bsr.w   loc_2FEDE
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
; loc_2FE0E:
Obj52_Mobile_Lower:
    bsr.w   Boss_MoveObject
    tst.b   objoff_2C(a0)
    bne.s   loc_2FE22
    cmpi.w  #$538,(Boss_Y_pos).w
    blt.s   loc_2FE58
    bra.s   Obj52_CreateLavaBall
; ===========================================================================
 
loc_2FE22:
    cmpi.w  #$548,(Boss_Y_pos).w
    blt.s   loc_2FE58
 
; loc_2FE2A
Obj52_CreateLavaBall:
    tst.b   objoff_38(a0)
    bne.s   loc_2FE58
    st  objoff_38(a0)
    jsrto   (SingleObjLoad).l, JmpTo13_SingleObjLoad
    bne.s   loc_2FE58
    move.b  #ObjID_HTZBoss,id(a1) ; load obj52
    move.b  #6,boss_subtype(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #SndID_LavaBall,d0
    jsrto   (PlaySound).l, JmpTo7_PlaySound
 
loc_2FE58:
    tst.b   objoff_2C(a0)
    bne.s   loc_2FE6E
    cmpi.w  #$5A0,(Boss_Y_pos).w
    blt.s   loc_2FED0
    move.w  #$5A0,(Boss_Y_pos).w
    bra.s   loc_2FE7C
; ===========================================================================
 
loc_2FE6E:
    cmpi.w  #$580,(Boss_Y_pos).w
    blt.s   loc_2FED0
    move.w  #$580,(Boss_Y_pos).w
 
loc_2FE7C:
    move.w  #-$E0,(Boss_Y_vel).w
    move.b  #0,angle(a0)
    sf  objoff_38(a0)
    move.w  (MainCharacter+x_pos).w,d0
    subi.w  #$2FC0,d0
    bmi.s   loc_2FEA8
    move.w  #$580,(Boss_Y_pos).w
    move.w  #$3040,x_pos(a0)
    st  objoff_2C(a0)
    bra.s   loc_2FEB8
; ===========================================================================
 
loc_2FEA8:
    move.w  #$2F40,x_pos(a0)
    move.w  #$5A0,(Boss_Y_pos).w
    sf  objoff_2C(a0)
 
loc_2FEB8:
    move.w  x_pos(a0),d0
    cmp.w   (MainCharacter+x_pos).w,d0
    bgt.s   loc_2FECA
    bset    #0,render_flags(a0)
    bra.s   loc_2FED0
; ===========================================================================
 
loc_2FECA:
    bclr    #0,render_flags(a0)
 
loc_2FED0:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    bsr.w   loc_300A4
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
loc_2FEDE:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    rts
; ===========================================================================
 
; loc_2FEF0:
Obj52_FlameThrower:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_2FEFE(pc,d0.w),d1
    jmp off_2FEFE(pc,d1.w)
; ===========================================================================
off_2FEFE:  offsetTable
        offsetTableEntry.w loc_2FF02    ; 0
        offsetTableEntry.w loc_2FF50    ; 2
; ===========================================================================
 
loc_2FF02:
    move.l  #Obj52_MapUnc_302BC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_HTZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    addq.b  #2,routine_secondary(a0)
    move.b  #5,anim(a0)
    move.b  #$98,collision_flags(a0)
    subi.w  #$1C,y_pos(a0)
    move.w  #-$70,d0
    move.w  #-4,d1
    btst    #0,render_flags(a0)
    beq.s   loc_2FF46
    neg.w   d0
    neg.w   d1
 
loc_2FF46:
    add.w   d0,x_pos(a0)
    move.w  d1,x_vel(a0)
    rts
; ===========================================================================
 
loc_2FF50:
    move.w  x_vel(a0),d1
    add.w   d1,x_pos(a0)
    lea (Ani_obj52).l,a1
    jsrto   (AnimateSprite).l, JmpTo18_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo37_MarkObjGone
; ===========================================================================
 
; loc_2FF66:
Obj52_LavaBall:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_2FF74(pc,d0.w),d1
    jmp off_2FF74(pc,d1.w)
; ===========================================================================
off_2FF74:  offsetTable
        offsetTableEntry.w loc_2FF78    ; 0
        offsetTableEntry.w loc_30008    ; 2
; ===========================================================================
 
loc_2FF78:
    movea.l a0,a1
    moveq   #0,d2
    moveq   #1,d1
    bra.s   loc_2FF94
; ===========================================================================
 
loc_2FF80:
    jsrto   (SingleObjLoad).l, JmpTo13_SingleObjLoad
    bne.w   return_30006
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
 
loc_2FF94:
    move.b  #ObjID_HTZBoss,id(a1) ; load obj52
    move.b  #6,boss_subtype(a1)
    move.l  #Obj52_MapUnc_302BC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_HTZBoss,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    addq.b  #2,routine_secondary(a1)
    move.b  #7,anim(a1)
    move.b  #$8B,collision_flags(a1)
    move.b  d2,objoff_2E(a1)
    move.b  #8,y_radius(a1)
    move.b  #8,x_radius(a1)
    move.w  x_pos(a1),objoff_2A(a1)
    move.w  #$1C00,d0
    tst.w   d2
    bne.s   loc_2FFE8
    neg.w   d0
 
loc_2FFE8:
    move.w  d0,x_vel(a1)
    move.w  #-$5400,y_vel(a1)
    cmpi.w  #$2F40,x_pos(a1)
    beq.s   loc_30000
    move.w  #-$6400,y_vel(a1)
 
loc_30000:
    addq.w  #1,d2
    dbf d1,loc_2FF80
 
return_30006:
    rts
; ===========================================================================
 
loc_30008:
    bsr.w   Obj52_LavaBall_Move
    jsrto   (ObjCheckFloorDist).l, JmpTo4_ObjCheckFloorDist
    tst.w   d1
    bpl.s   loc_30064
    add.w   d1,y_pos(a0)
    move.b  #ObjID_LavaBubble,id(a0) ; load 0bj20
    move.b  #$A,routine(a0)
    move.b  #2,anim(a0)
    move.b  #4,mapping_frame(a0)
    move.w  #0,y_vel(a0)
    move.l  #Obj20_MapUnc_23294,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_Buzzer_Fireball_1,0,1),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo62_Adjust2PArtPointer
    move.b  #0,mapping_frame(a0)
    move.w  #9,objoff_32(a0)
    move.b  #3,objoff_36(a0)
    move.b  #SndID_FireBurn,d0
    jsrto   (PlaySound).l, JmpTo7_PlaySound
    jmpto   (Obj20).l, JmpTo_Obj20
; ===========================================================================
 
loc_30064:
    lea (Ani_obj52).l,a1
    jsrto   (AnimateSprite).l, JmpTo18_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo37_MarkObjGone
; ===========================================================================
 
; loc_30072:
Obj52_LavaBall_Move:
    move.l  objoff_2A(a0),d2
    move.l  y_pos(a0),d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #4,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    addi.w  #$380,y_vel(a0)
    ext.l   d0
    asl.l   #4,d0
    add.l   d0,d3
    move.l  d2,objoff_2A(a0)
    move.l  d3,y_pos(a0)
    move.w  objoff_2A(a0),x_pos(a0)
    rts
; ===========================================================================
 
loc_300A4:
    cmpi.b  #8,angle(a0)
    bhs.s   return_300EA
    tst.b   objoff_32(a0)
    beq.s   Obj52_Defeat
    tst.b   collision_flags(a0)
    bne.s   return_300EA
    tst.b   objoff_14(a0)
    bne.s   loc_300CE
    move.b  #$20,objoff_14(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
 
loc_300CE:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   loc_300DC
    move.w  #$EEE,d0
 
loc_300DC:
    move.w  d0,(a1)
    subq.b  #1,objoff_14(a0)
    bne.s   return_300EA
    move.b  #$32,collision_flags(a0)
 
return_300EA:
    rts
; ===========================================================================
 
; loc_300EC:
Obj52_Defeat:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo4_AddPoints
    move.w  #$B3,(Boss_Countdown).w
    move.b  #8,angle(a0)
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo7_LoadPLC
    rts
; ===========================================================================
 
; loc_30106:
Obj52_Mobile_Defeated:
    move.b  #0,mainspr_childsprites(a0)
    subi_.w #1,(Boss_Countdown).w
    bmi.s   loc_30142
    cmpi.w  #$1E,(Boss_Countdown).w
    bgt.s   Obj52_Mobile_UpdateExplosion
    move.b  #$10,mainspr_mapframe(a0)
    bsr.w   Boss_LoadExplosion
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.w   JmpTo36_DisplaySprite
    bsr.w   Obj52_CreateSmoke
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
; loc_3013A:
Obj52_Mobile_UpdateExplosion:
    bsr.w   Boss_LoadExplosion
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
loc_30142:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.w   Obj52_Mobile_Flee
    bsr.w   Obj52_CreateSmoke
 
; loc_30152:
Obj52_Mobile_Flee:
    cmpi.w  #-$3C,(Boss_Countdown).w
    bgt.w   JmpTo36_DisplaySprite
    tst.b   (Boss_defeated_flag).w
    bne.s   loc_30170
    jsrto   (PlayLevelMusic).l, JmpTo3_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo3_LoadPLC_AnimalExplosion
    move.b  #1,(Boss_defeated_flag).w
 
loc_30170:
    addq.w  #2,y_pos(a0)
    cmpi.w  #$3160,(Camera_Max_X_pos).w
    bhs.s   loc_30182
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   BranchTo_JmpTo36_DisplaySprite
; ===========================================================================
 
loc_30182:
    tst.b   render_flags(a0)
    bpl.s   loc_301AA
    tst.b   objoff_2C(a0)
    bne.s   loc_3019C
    cmpi.w  #$578,y_pos(a0)
    bgt.w   loc_301AA
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
loc_3019C:
    cmpi.w  #$588,y_pos(a0)
    bgt.w   loc_301AA
 
BranchTo_JmpTo36_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
 
loc_301AA:
    move.w  #$3160,(Camera_Max_X_pos).w
 
    if removeJmpTos
JmpTo53_DeleteObject 
    endif
 
    jmpto   (DeleteObject).l, JmpTo53_DeleteObject
; ===========================================================================
 
; loc_301B4:
Obj52_CreateSmoke
    jsrto   (SingleObjLoad).l, JmpTo13_SingleObjLoad
    bne.s   return_3020E
    move.b  #ObjID_HTZBoss,id(a1) ; load obj52
    move.b  #8,boss_subtype(a1)
    move.l  #Obj52_MapUnc_30258,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_BossSmoke_2,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #1,priority(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  x_pos(a0),objoff_2A(a1)
    subi.w  #$28,y_pos(a1)
    move.w  #-$60,x_vel(a1)
    move.w  #-$C0,y_vel(a1)
    move.b  #0,mapping_frame(a1)
    move.b  #$11,anim_frame_duration(a1)
 
return_3020E:
    rts
; ===========================================================================
 
loc_30210:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   loc_3022A
    move.b  #$11,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #4,mapping_frame(a0)
    beq.w   JmpTo53_DeleteObject
 
loc_3022A:
    move.l  objoff_2A(a0),d2
    move.l  y_pos(a0),d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,objoff_2A(a0)
    move.w  objoff_2A(a0),x_pos(a0)
    move.l  d3,y_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo36_DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_BossSmoke
; ----------------------------------------------------------------------------
Obj52_MapUnc_30258: BINCLUDE "mappings/sprite/obj52_a.bin"
 
; animation script
; off_30288:
Ani_obj52:  offsetTable
        offsetTableEntry.w byte_30298   ; 0
        offsetTableEntry.w byte_3029D   ; 1
        offsetTableEntry.w byte_302A2   ; 2
        offsetTableEntry.w byte_302A7   ; 3
        offsetTableEntry.w byte_302AC   ; 4
        offsetTableEntry.w byte_302B0   ; 5
        offsetTableEntry.w byte_302B4   ; 6
        offsetTableEntry.w byte_302B7   ; 7
byte_30298: dc.b   1,  2,  3,$FD,  1
    rev02even
byte_3029D: dc.b   2,  4,  5,$FD,  2
    rev02even
byte_302A2: dc.b   3,  6,  7,$FD,  3
    rev02even
byte_302A7: dc.b   4,  8,  9,$FD,  4
    rev02even
byte_302AC: dc.b   5, $A, $B,$FE
    rev02even
byte_302B0: dc.b   3, $C, $D,$FF
    rev02even
byte_302B4: dc.b  $F,  1,$FF
    rev02even
byte_302B7: dc.b   3, $E, $F,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_Eggpod + ?
; ----------------------------------------------------------------------------
Obj52_MapUnc_302BC: BINCLUDE "mappings/sprite/obj52_b.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo36_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo53_DeleteObject 
    jmp (DeleteObject).l
JmpTo13_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo37_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo7_PlaySound 
    jmp (PlaySound).l
JmpTo18_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo4_ObjCheckFloorDist 
    jmp (ObjCheckFloorDist).l
JmpTo7_LoadPLC 
    jmp (LoadPLC).l
JmpTo_Obj20 
    jmp (Obj20).l
JmpTo4_AddPoints 
    jmp (AddPoints).l
JmpTo62_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo3_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo3_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 89 - ARZ boss
; ----------------------------------------------------------------------------
; OST Variables:
; Main Vehicle
obj89_hammer_y_vel  = objoff_2E     ; falling hammer's y velocity
obj89_target        = objoff_38
obj89_hammer_y_pos  = objoff_3A     ; falling hammer's y position
obj89_hammer_flags  = objoff_3E
 
; Pillars & Arrows
obj89_pillar_parent     = objoff_2A ; address of main vehicle
obj89_pillar_shake_time     = objoff_30
obj89_pillar_shaking        = objoff_38
obj89_eyes_timer        = objoff_30
obj89_arrow_routine     = objoff_2A
obj89_arrow_timer       = objoff_30
obj89_arrow_parent2     = objoff_34
obj89_arrow_parent      = objoff_38 ; address of main vehicle
 
; Sprite_30480:
Obj89:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj89_Index(pc,d0.w),d1
    jmp Obj89_Index(pc,d1.w)
; ===========================================================================
; off_3048E:
Obj89_Index:    offsetTable
        offsetTableEntry.w Obj89_Init   ; 0 - Init
        offsetTableEntry.w Obj89_Main   ; 2 - Main Vehicle
        offsetTableEntry.w Obj89_Pillar ; 4 - Pillars & Arrows
; ===========================================================================
; loc_30494:
Obj89_Init:
    tst.l   (Plc_Buffer).w          ; is art finished loading?
    beq.s   +               ; if yes, branch
    rts
; ---------------------------------------------------------------------------
+
    tst.w   (Player_mode).w         ; is player mode anything other than Sonic & Tails?
    bne.s   Obj89_Init_RaisePillars     ; if yes, branch
    move.w  (MainCharacter+x_pos).w,d0
    cmpi.w  #$2A60,d0           ; is Sonic too close to the left edge?
    blt.w   Obj89_Init_Standard     ; if yes, branch
    cmpi.w  #$2B60,d0           ; is Sonic too close to the right edge?
    bgt.w   Obj89_Init_Standard     ; if yes, branch
    cmpi.b  #$81,(Sidekick+obj_control).w
    beq.w   Obj89_Init_RaisePillars     ; branch, if Tails is flying
    move.w  (Sidekick+x_pos).w,d0
    cmpi.w  #$2A60,d0           ; is Tails too close to the left edge?
    blt.w   Obj89_Init_Standard     ; if yes, branch
    cmpi.w  #$2B60,d0           ; is Tails too close to the right edge?
    bgt.w   Obj89_Init_Standard     ; if yes, branch
 
; loc_304D4:
Obj89_Init_RaisePillars:
    move.b  #1,(Screen_Shaking_Flag).w  ; make screen shake
    move.w  #make_art_tile(ArtTile_ArtNem_ARZBoss,0,0),art_tile(a0)
    move.l  #Obj89_MapUnc_30E04,mappings(a0)
    ori.b   #4,render_flags(a0)
    move.b  #$20,mainspr_width(a0)
    move.b  #2,priority(a0)
    move.b  #2,boss_subtype(a0) ; => Obj89_Main
    move.w  #$2AE0,x_pos(a0)
    move.w  #$388,y_pos(a0)
    move.w  #$2AE0,(Boss_X_pos).w
    move.w  #$388,(Boss_Y_pos).w
    bset    #6,render_flags(a0)
    move.b  #3,mainspr_childsprites(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,boss_hitcount2(a0)
    move.b  #8,mainspr_mapframe(a0)
    move.w  #-$380,obj89_hammer_y_vel(a0)
    clr.b   (Boss_CollisionRoutine).w   ; disable special collisions
    move.w  #$2AE0,sub2_x_pos(a0)       ;
    move.w  #$488,sub2_y_pos(a0)
    move.b  #0,sub2_mapframe(a0)
    move.w  #$2AE0,sub3_x_pos(a0)       ;
    move.w  #$488,sub3_y_pos(a0)
    move.b  #9,sub3_mapframe(a0)
    move.w  #$2AE0,sub4_x_pos(a0)       ;
    move.w  #$488,sub4_y_pos(a0)
    move.b  #6,sub4_mapframe(a0)
    move.w  #$100,(Boss_Y_vel).w
 
    ; load first pillar object
    jsrto   (SingleObjLoad).l, JmpTo14_SingleObjLoad
    bne.w   Obj89_Init_Standard
    move.b  #ObjID_ARZBoss,id(a1) ; load obj89
    move.l  #Obj89_MapUnc_30D68,mappings(a1)
    ori.b   #4,render_flags(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_ARZBoss,0,0),art_tile(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #4,priority(a1)
    move.w  #$2A50,x_pos(a1)
    move.w  #$510,y_pos(a1)
    addq.b  #4,boss_subtype(a1) ; => Obj89_Pillar
    move.l  a0,obj89_pillar_parent(a1)
    move.b  #0,mapping_frame(a1)
    move.b  #2,priority(a1)
    move.b  #$20,y_radius(a1)
    movea.l a1,a2               ; save first pillar's address
    jsrto   (SingleObjLoad2).l, JmpTo22_SingleObjLoad2
    bne.s   Obj89_Init_Standard
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
 
; loc_305DC:
Obj89_Init_DuplicatePillar:
    move.l  (a2,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,Obj89_Init_DuplicatePillar
    if object_size&3
    move.w  (a2,d0.w),(a1,d0.w)
    endif
 
    bset    #0,render_flags(a1)
    move.w  #$2B70,x_pos(a1)        ; move pillar to other side of boss area
 
; loc_305F4:
Obj89_Init_Standard:
    bsr.w   Obj89_Init_AnimationArray
    rts
; ===========================================================================
; loc_305FA:
Obj89_Init_AnimationArray:
    lea (Boss_AnimationArray).w,a2
    move.b  #4,(a2)+    ; main vehicle
    move.b  #0,(a2)+
    move.b  #0,(a2)+    ; face
    move.b  #0,(a2)+
    move.b  #2,(a2)+    ; hammer
    move.b  #0,(a2)+
    move.b  #1,(a2)+    ; flames
    move.b  #0,(a2)+
    rts
; ===========================================================================
; loc_30620:
Obj89_Main:
    moveq   #0,d0
    move.b  boss_routine(a0),d0
    move.w  Obj89_Main_Index(pc,d0.w),d1
    jmp Obj89_Main_Index(pc,d1.w)
; ===========================================================================
; off_3062E:
Obj89_Main_Index:   offsetTable         ; main boss object
        offsetTableEntry.w Obj89_Main_Sub0  ; 0 - moving down into arena
        offsetTableEntry.w Obj89_Main_Sub2  ; 2 - moving left/right
        offsetTableEntry.w Obj89_Main_Sub4  ; 4 - having reached pillar
        offsetTableEntry.w Obj89_Main_Sub6  ; 6 - hit with hammer
        offsetTableEntry.w Obj89_Main_Sub8  ; 8 - boss exploding
        offsetTableEntry.w Obj89_Main_SubA  ; A - move boss down and alter a little up again
        offsetTableEntry.w Obj89_Main_SubC  ; C - beaten boss moving away
; ===========================================================================
; loc_3063C:
Obj89_Main_Sub0:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleFace
    bsr.w   Obj89_Main_AlignParts
    cmpi.w  #$430,(Boss_Y_pos).w        ; has boss reached its target?
    blt.s   Obj89_Main_Sub0_Standard    ; if not, branch
    move.w  #$430,(Boss_Y_pos).w
    addi_.b #2,boss_routine(a0) ; => Obj89_Main_Sub2
    move.w  #0,(Boss_Y_vel).w       ; stop y movement
    move.w  #-$C8,(Boss_X_vel).w        ; move leftward
    st  obj89_target(a0)
 
; loc_3066C:
Obj89_Main_Sub0_Standard:
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_3067A:
Obj89_Main_Sub2:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleFace
    bsr.w   Obj89_Main_AlignParts
    tst.b   obj89_target(a0)        ; is boss going left?
    bne.s   Obj89_Main_Sub2_GoingLeft   ; if yes, branch
    cmpi.w  #$2B10,(Boss_X_pos).w       ; is boss right in front of the right pillar?
    blt.s   Obj89_Main_Sub2_Standard    ; branch, if still too far away
    bra.s   Obj89_Main_Sub2_AtTarget
; ===========================================================================
; loc_30696:
Obj89_Main_Sub2_GoingLeft:
    cmpi.w  #$2AB0,(Boss_X_pos).w       ; is boss right in front of the left pillar?
    bgt.s   Obj89_Main_Sub2_Standard    ; branch, if still too far away
 
; loc_3069E:
Obj89_Main_Sub2_AtTarget:
    addi_.b #2,boss_routine(a0) ; => Obj89_Main_Sub4
    move.w  #0,(Boss_X_vel).w
 
; loc_306AA:
Obj89_Main_Sub2_Standard:
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_306B8:
Obj89_Main_Sub4:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleFace
    bsr.w   Obj89_Main_AlignParts
    cmpi.b  #-$40,boss_sine_count(a0)   ; has boss reached the right height in its hovering animation?
    bne.s   Obj89_Main_Sub4_Standard    ; if not, branch
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,2*2(a1)            ; reset hammer animation
    ori.b   #3,2*2(a1)          ; reset hammer animation timer
    addq.b  #2,boss_routine(a0) ; => Obj89_Main_Sub6
    btst    #0,render_flags(a0)
    sne obj89_target(a0)        ; target opposite side
    move.w  #$1E,(Boss_Countdown).w
    move.b  #SndID_Hammer,d0
    jsrto   (PlaySound).l, JmpTo8_PlaySound
 
; loc_306F8:
Obj89_Main_Sub4_Standard:
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30706:
Obj89_Main_Sub6:
    cmpi.w  #$14,(Boss_Countdown).w     ; has counter reached a specific value?
    bne.s   +               ; if not, branch
    bset    #0,obj89_hammer_flags(a0)   ; hammer just hit a pillar
    move.b  #1,(Boss_CollisionRoutine).w    ; enable hammer collision
+
    subi_.w #1,(Boss_Countdown).w       ; decrement counter
    bpl.s   Obj89_Main_Sub6_Standard    ; branch, if counter > 0
    clr.b   (Boss_CollisionRoutine).w   ; disable hammer collision
    move.b  #2,boss_routine(a0) ; => Obj89_Main_Sub2
    bchg    #0,render_flags(a0)     ; face opposite direction
    beq.s   Obj89_Main_Sub6_MoveRight   ; branch, if new direction is right
    move.w  #-$C8,(Boss_X_vel).w        ; move left
    bra.s   Obj89_Main_Sub6_Standard
; ===========================================================================
; loc_3073C:
Obj89_Main_Sub6_MoveRight:
    move.w  #$C8,(Boss_X_vel).w     ; move right
 
; loc_30742:
Obj89_Main_Sub6_Standard:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleFace
    bsr.w   Obj89_Main_AlignParts
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_3075C:
Obj89_Main_HandleFace:
    bsr.w   Obj89_Main_HandleHoveringAndHits
    cmpi.b  #4,(MainCharacter+routine).w    ; is Sonic hurt?
    beq.s   Obj89_Main_Laugh        ; if yes, branch
    cmpi.b  #4,(Sidekick+routine).w     ; is Tails hurt?
    bne.s   Obj89_Main_ChkHurt      ; if not, branch
 
; loc_30770:
Obj89_Main_Laugh:
    lea (Boss_AnimationArray).w,a1
    move.b  #$31,1*2+1(a1)          ; use laughing animation
 
; loc_3077A:
Obj89_Main_ChkHurt:
    cmpi.b  #$3F,boss_invulnerable_time(a0) ; was boss hurt?
    bne.s   return_3078C            ; if not, branch
    lea (Boss_AnimationArray).w,a1
    move.b  #-$40,1*2+1(a1)         ; use hurt animation
 
return_3078C:
    rts
; ===========================================================================
; loc_3078E:
Obj89_Main_HandleHoveringAndHits:
    move.b  boss_sine_count(a0),d0
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    addq.b  #2,boss_sine_count(a0)
    cmpi.b  #8,boss_routine(a0)     ; has boss been defeated?
    bhs.s   return_307F2            ; if yes, branch
    tst.b   boss_hitcount2(a0)      ; has boss run out of hits?
    beq.s   Obj89_Main_KillBoss     ; if yes, branch
    tst.b   collision_flags(a0)     ; are boss's collisions enabled?
    bne.s   return_307F2            ; if yes, branch
    tst.b   boss_invulnerable_time(a0)  ; is boss invulnerable?
    bne.s   Obj89_Main_Flash        ; if yes, branch
    move.b  #$40,boss_invulnerable_time(a0) ; make boss invulnerable
    move.w  #SndID_BossHit,d0       ; play "boss hit" sound
    jsr (PlaySound).l
 
; loc_307D6:
Obj89_Main_Flash:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0               ; 0000 = black
    tst.w   (a1)                ; is current color black?
    bne.s   +               ; if not, branch
    move.w  #$EEE,d0            ; 0EEE = white
+
    move.w  d0,(a1)             ; set color
    subq.b  #1,boss_invulnerable_time(a0)
    bne.s   return_307F2            ; branch, if invulnerability hasn't run out
    move.b  #$F,collision_flags(a0)     ; restore collisions
 
return_307F2:
    rts
; ===========================================================================
; loc_307F4:
Obj89_Main_KillBoss:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo5_AddPoints
    move.w  #$B3,(Boss_Countdown).w     ; set timer
    move.b  #8,boss_routine(a0) ; => Obj89_Main_Sub8
    lea (Boss_AnimationArray).w,a1
    move.b  #5,1*2(a1)          ; use defeated animation
    move.b  #0,1*2+1(a1)            ; reset animation
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo8_LoadPLC
    move.b  #5,sub2_mapframe(a0)
    rts
; ===========================================================================
; loc_30824:
Obj89_Main_AlignParts:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    move.w  d0,sub4_x_pos(a0)
    move.w  d1,sub4_y_pos(a0)
    tst.b   boss_defeated(a0)
    bne.s   Obj89_Main_DropHammer       ; branch, if boss was defeated
    move.w  d0,sub3_x_pos(a0)
    move.w  d1,sub3_y_pos(a0)
    move.w  d1,obj89_hammer_y_pos(a0)
    rts
; ===========================================================================
; loc_30850:
Obj89_Main_DropHammer:
    cmpi.w  #$78,(Boss_Countdown).w
    bgt.s   return_3088A            ; wait until timer is below $78
    subi_.w #1,sub3_x_pos(a0)       ; make hammer move left
    move.l  obj89_hammer_y_pos(a0),d0
    move.w  obj89_hammer_y_vel(a0),d1
    addi.w  #$38,obj89_hammer_y_vel(a0) ; add gravity
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d0
    move.l  d0,obj89_hammer_y_pos(a0)   ; update position
    move.w  obj89_hammer_y_pos(a0),sub3_y_pos(a0)
    cmpi.w  #$540,sub3_y_pos(a0)        ; has the hammer reached the bottom?
    blt.s   return_3088A            ; if not, branch
    move.w  #0,obj89_hammer_y_vel(a0)   ; else, make hammer invisible
 
return_3088A:
    rts
; ===========================================================================
; loc_3088C:
Obj89_Main_Sub8:
    st  boss_defeated(a0)
    subq.w  #1,(Boss_Countdown).w
    bmi.s   Obj89_Main_SetupEscapeAnim
    bsr.w   Boss_LoadExplosion
    bra.s   Obj89_Main_Sub8_Standard
; ===========================================================================
; loc_3089C:
Obj89_Main_SetupEscapeAnim:
    move.b  #3,mainspr_childsprites(a0)
    lea (Boss_AnimationArray).w,a2
    move.b  #1,2*2(a2)          ; hammer
    move.b  #0,2*2+1(a2)
    move.b  #0,1*2(a2)          ; face
    move.b  #0,1*2+1(a2)
    bset    #0,render_flags(a0)
    clr.w   (Boss_X_vel).w          ; stop movement
    clr.w   (Boss_Y_vel).w
    addq.b  #2,boss_routine(a0) ; => Obj89_Main_SubA
    move.w  #-$12,(Boss_Countdown).w
 
; loc_308D6:
Obj89_Main_Sub8_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj89_Main_AlignParts
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_308F4:
Obj89_Main_SubA:
    addq.w  #1,(Boss_Countdown).w       ; note: countdown starts out as -$12
    beq.s   Obj89_Main_SubA_StopFall    ; branch, if countdown reached 0
    bpl.s   Obj89_Main_SubA_Phase2      ; branch, if falling phase is over
    addi.w  #$18,(Boss_Y_vel).w     ; else, make boss fall
    bra.s   Obj89_Main_SubA_Standard
; ===========================================================================
; loc_30904:
Obj89_Main_SubA_StopFall:
    clr.w   (Boss_Y_vel).w          ; stop fall
    bra.s   Obj89_Main_SubA_Standard
; ===========================================================================
; loc_3090A:
Obj89_Main_SubA_Phase2:
    cmpi.w  #$18,(Boss_Countdown).w
    blo.s   Obj89_Main_SubA_Ascend
    beq.s   Obj89_Main_SubA_StopAscent
    cmpi.w  #$20,(Boss_Countdown).w
    blo.s   Obj89_Main_SubA_Standard
    addq.b  #2,boss_routine(a0) ; => Obj89_Main_SubC
    bra.s   Obj89_Main_SubA_Standard
; ===========================================================================
; loc_30922:
Obj89_Main_SubA_Ascend:
    subi_.w #8,(Boss_Y_vel).w       ; ascend slowly
    bra.s   Obj89_Main_SubA_Standard
; ===========================================================================
; loc_3092A:
Obj89_Main_SubA_StopAscent:
    clr.w   (Boss_Y_vel).w          ; stop ascent
    jsrto   (PlayLevelMusic).l, JmpTo4_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo4_LoadPLC_AnimalExplosion
 
; loc_30936:
Obj89_Main_SubA_Standard:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleHoveringAndHits
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj89_Main_AlignParts
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_3095C:
Obj89_Main_SubC:
    move.w  #$400,(Boss_X_vel).w
    move.w  #-$40,(Boss_Y_vel).w
    cmpi.w  #$2C00,(Camera_Max_X_pos).w ; has camera reached its target position?
    bhs.s   Obj89_Main_SubC_ChkDelete   ; if yes, branch
    addq.w  #2,(Camera_Max_X_pos).w     ; else, move camera
    bra.s   Obj89_Main_SubC_Standard
; ===========================================================================
; loc_30976:
Obj89_Main_SubC_ChkDelete:
    tst.b   render_flags(a0)        ; is boss still visible?
    bpl.s   JmpTo54_DeleteObject        ; if not, branch
 
; loc_3097C:
Obj89_Main_SubC_Standard:
    bsr.w   Boss_MoveObject
    bsr.w   Obj89_Main_HandleHoveringAndHits
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj89_b).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj89_Main_AlignParts
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
 
JmpTo54_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
; loc_309A8:
Obj89_Pillar:
    moveq   #0,d0
    movea.l obj89_pillar_parent(a0),a1 ; a1=object
    cmpi.b  #8,boss_routine(a1)     ; has boss been defeated?
    blt.s   Obj89_Pillar_Normal     ; if not, branch
    move.b  #4,routine_secondary(a0)
 
; loc_309BC:
Obj89_Pillar_Normal:
    move.b  routine_secondary(a0),d0
    move.w  Obj89_Pillar_Index(pc,d0.w),d1
    jmp Obj89_Pillar_Index(pc,d1.w)
; ===========================================================================
; off_309C8:
Obj89_Pillar_Index: offsetTable             ; pillar/arrow object
        offsetTableEntry.w Obj89_Pillar_Sub0        ; 0 - raise pillars
        offsetTableEntry.w Obj89_Pillar_Sub2        ; 2 - pillars shaking(?)
        offsetTableEntry.w Obj89_Pillar_Sub4        ; 4 - move pillars down
        offsetTableEntry.w Obj89_Arrow          ; 6 - arrow
        offsetTableEntry.w Obj89_Pillar_BulgingEyes ; 8 - pillar normal (standing)
; ===========================================================================
; loc_309D2:
Obj89_Pillar_Sub0:
    bsr.w   Obj89_Pillar_SolidObject
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +
    move.w  #SndID_Rumbling2,d0     ; play rumbling sound every 32 frames
    jsrto   (PlaySound).l, JmpTo8_PlaySound
+
    subi_.w #1,y_pos(a0)            ; raise pillar
    cmpi.w  #$488,y_pos(a0)         ; has pillar reached its target height?
    bgt.s   BranchTo_JmpTo37_DisplaySprite  ; if not, branch
    addq.b  #2,routine_secondary(a0)    ; => Obj89_Pillar_Sub2
    move.b  #0,(Screen_Shaking_Flag).w  ; stop screen shaking
 
BranchTo_JmpTo37_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30A04:
Obj89_Pillar_Sub2:
    ; note: the boss switches targets before bit 0 of obj89_hammer_flags is set.  In other
    ; words, it's always the pillar facing the new target that fires.
    bsr.w   Obj89_Pillar_SolidObject
    movea.l obj89_pillar_parent(a0),a3 ; a3=object
    btst    #0,obj89_hammer_flags(a3)
    beq.s   Obj89_Pillar_Sub2_Standard  ; branch, if hammer hasn't hit a pillar
    tst.b   obj89_target(a3)        ; is boss targeting the right?
    beq.s   Obj89_Pillar_Sub2_RightPillar   ; if yes, branch
    btst    #0,render_flags(a0)     ; is pillar facing left?
    beq.s   Obj89_Pillar_Sub2_Standard  ; if not, branch
    bra.s   loc_30A2C
; ===========================================================================
; loc_30A24:
Obj89_Pillar_Sub2_RightPillar:
    btst    #0,render_flags(a0)     ; is pillar facing right?
    bne.s   Obj89_Pillar_Sub2_Standard  ; if not, branch
 
loc_30A2C:
    bclr    #0,obj89_hammer_flags(a3)   ; clear "hitting-pillar" flag
    bsr.w   Obj89_Pillar_Shoot      ; shoot an arrow
    st  obj89_pillar_shaking(a0)    ; make pillar shake
 
; loc_30A3A:
Obj89_Pillar_Sub2_Standard:
    bsr.w   Obj89_Pillar_ChkShake
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30A42:
Obj89_Pillar_ChkShake:
    tst.b   obj89_pillar_shaking(a0)    ; is pillar shaking?
    beq.s   return_30AAE            ; if not, branch
    tst.w   obj89_pillar_shake_time(a0) ; has timer been set?
    bgt.s   +               ; if yes, branch
    move.w  #$1F,obj89_pillar_shake_time(a0); else, initialize timer
+
    subi_.w #1,obj89_pillar_shake_time(a0)
    bgt.s   Obj89_Pillar_Shake      ; branch, if timer hasn't expired
    sf  obj89_pillar_shaking(a0)    ; stop shaking
    move.w  #0,obj89_pillar_shake_time(a0)  ; clear timer
    tst.b   obj89_target(a3)        ; is boss targeting the left?
    bne.s   +               ; if yes, branch
    move.w  #$2A50,x_pos(a0)        ; reset x position of left pillar
    bra.s   Obj89_Pillar_Sub2_End
; ===========================================================================
+
    move.w  #$2B70,x_pos(a0)        ; reset x position of right pillar
 
; loc_30A7A:
Obj89_Pillar_Sub2_End:
    move.w  #$488,y_pos(a0)         ; reset y position
    bra.s   return_30AAE
; ===========================================================================
; loc_30A82:
Obj89_Pillar_Shake:
    move.w  #$2A50,d1           ; load left pillar's default x position
    tst.b   obj89_target(a3)        ; is boss targeting the left
    beq.s   +               ; if not, branch
    move.w  #$2B70,d1           ; load right pillar's default x position
+
    move.b  (Vint_runcount+3).w,d0
    andi.w  #1,d0
    add.w   d0,d0
    add.w   Obj89_Pillar_ShakeOffsets(pc,d0.w),d1
    move.w  d1,x_pos(a0)            ; add offset to x position
    move.w  #$488,d1            ; load  pillar's default y position
    add.w   Obj89_Pillar_ShakeOffsets(pc,d0.w),d1
    move.w  d1,y_pos(a0)            ; add offset to y position
 
return_30AAE:
    rts
; ===========================================================================
; word_30AB0:
Obj89_Pillar_ShakeOffsets:
    dc.w     1  ; 0
    dc.w    -1  ; 1
; ===========================================================================
; loc_30AB4:
Obj89_Pillar_Shoot:
    jsrto   (SingleObjLoad).l, JmpTo14_SingleObjLoad
    bne.w   return_30B40
    _move.b #ObjID_ARZBoss,id(a1) ; load obj89
    move.b  #4,boss_subtype(a1)
    move.b  #8,routine_secondary(a1)    ; => Obj89_Pillar_BulgingEyes
    move.l  #Obj89_MapUnc_30D68,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_ARZBoss,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    moveq   #0,d6
    move.b  #2,mapping_frame(a1)
    move.w  #$2A6A,x_pos(a1)        ; align with left pillar
    tst.b   obj89_target(a3)        ; is boss targeting the right?
    beq.s   +               ; if yes, branch
    st  d6
    move.w  #$2B56,x_pos(a1)        ; align with right pillar
    bset    #0,render_flags(a1)
+
    move.w  #$28,obj89_eyes_timer(a1)
    jsrto   (RandomNumber).l, JmpTo3_RandomNumber
    andi.w  #3,d0
    add.w   d0,d0
    move.w  Obj89_Arrow_Offsets(pc,d0.w),y_pos(a1)
    movea.l a1,a2
    jsrto   (SingleObjLoad).l, JmpTo14_SingleObjLoad
    bne.s   return_30B40
    _move.b #ObjID_ARZBoss,id(a1) ; load obj89
    move.b  #4,boss_subtype(a1)
    move.b  #6,routine_secondary(a1)    ; => Obj89_Arrow
    move.l  a2,obj89_arrow_parent2(a1)
    move.b  d6,subtype(a1)
    move.l  a3,obj89_arrow_parent(a1)
 
return_30B40:
    rts
; ===========================================================================
; word_30B42:
Obj89_Arrow_Offsets:
    dc.w  $458
    dc.w  $478  ; 1
    dc.w  $498  ; 2
    dc.w  $4B8  ; 3
; ===========================================================================
; loc_30B4A:
Obj89_Pillar_Sub4:
    move.b  #1,(Screen_Shaking_Flag).w  ; make screen shake
    addi_.w #1,y_pos(a0)            ; lower pillar
    cmpi.w  #$510,y_pos(a0)         ; has pillar lowered into the ground?
    blt.s   BranchTo2_JmpTo37_DisplaySprite ; if not, branch
    move.b  #0,(Screen_Shaking_Flag).w  ; else, stop shaking the screen
    jmpto   (DeleteObject).l, JmpTo55_DeleteObject
; ===========================================================================
 
BranchTo2_JmpTo37_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30B6C:
Obj89_Pillar_BulgingEyes:
    subi_.w #1,obj89_eyes_timer(a0)
    beq.w   JmpTo55_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30B7A:
Obj89_Pillar_SolidObject:
    move.w  #$23,d1
    move.w  #$44,d2
    move.w  #$45,d3
    move.w  x_pos(a0),d4
    move.w  y_pos(a0),-(sp)
    addi_.w #4,y_pos(a0)            ; assume a slightly lower y position
    jsrto   (SolidObject).l, JmpTo26_SolidObject
    move.w  (sp)+,y_pos(a0)         ; restore y position
    rts
; ===========================================================================
;loc_30B9E:
Obj89_Arrow:
    moveq   #0,d0
    movea.l obj89_arrow_parent(a0),a1 ; a1=object
    cmpi.b  #8,boss_routine(a1)     ; has boss been defeated?
    blt.s   Obj89_Arrow_Normal      ; if not, branch
    move.b  #6,obj89_arrow_routine(a0)  ; => Obj89_Arrow_Sub6
 
; loc_30BB2:
Obj89_Arrow_Normal:
    move.b  obj89_arrow_routine(a0),d0
    move.w  Obj89_Arrow_Index(pc,d0.w),d1
    jmp Obj89_Arrow_Index(pc,d1.w)
; ===========================================================================
; off_30BBE:
Obj89_Arrow_Index:  offsetTable
        offsetTableEntry.w Obj89_Arrow_Init         ; 0 - launch arrow (init)
        offsetTableEntry.w Obj89_Arrow_Sub2         ; 2 - arrow in air
        offsetTableEntry.w Obj89_Arrow_Sub4         ; 4 - arrow stuck
        offsetTableEntry.w Obj89_Arrow_Sub6         ; 6 - falling down
        offsetTableEntry.w BranchTo_JmpTo55_DeleteObject    ; 8 - delete arrow
; ===========================================================================
; loc_30BC8:
Obj89_Arrow_Init:
    move.l  #Obj89_MapUnc_30D68,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_ARZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #-$70,mainspr_width(a0)
    move.b  #4,priority(a0)
    addq.b  #2,obj89_arrow_routine(a0)  ; => Obj89_Arrow_Sub2
    movea.l obj89_arrow_parent2(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)     ; align with parent object
    move.w  y_pos(a1),y_pos(a0)
    move.w  #4,y_vel(a0)
    move.b  #4,mapping_frame(a0)
    addi.w  #9,y_pos(a0)
    tst.b   subtype(a0)         ; was arrow fired from right pillar?
    beq.s   +               ; if not, branch
    bset    #0,status(a0)           ; make arrow face left
    bset    #0,render_flags(a0)
    move.w  #-3,x_vel(a0)           ; move left
    bra.s   Obj89_Arrow_Init_End
; ===========================================================================
+
    move.w  #3,x_vel(a0)            ; move right
 
; loc_30C2E:
Obj89_Arrow_Init_End:
    move.b  #$B0,collision_flags(a0)
    rts
; ===========================================================================
; loc_30C36:
Obj89_Arrow_Sub2:
    btst    #7,status(a0)
    beq.s   +
    move.b  #8,obj89_arrow_routine(a0)  ; => BranchTo_JmpTo55_DeleteObject
+
    move.w  x_pos(a0),d0            ; load x position...
    add.w   x_vel(a0),d0            ; ... and add x velocity
    tst.w   x_vel(a0)           ; is arrow moving right?
    bpl.s   Obj89_Arrow_Sub2_GoingRight ; if yes, branch
    cmpi.w  #$2A77,d0
    bgt.s   Obj89_Arrow_Sub2_Move       ; branch, if arrow hasn't reached left pillar
    move.w  #$2A77,d0           ; else, make arrow stick to left pillar
    bra.s   Obj89_Arrow_Sub2_Stop
; ===========================================================================
; loc_30C5E:
Obj89_Arrow_Sub2_GoingRight:
    cmpi.w  #$2B49,d0
    blt.s   Obj89_Arrow_Sub2_Move       ; branch, if arrow hasn't reached right pillar
    move.w  #$2B49,d0           ; else, make arrow stick to right pillar
 
; loc_30C68:
Obj89_Arrow_Sub2_Stop:
    addi_.b #2,obj89_arrow_routine(a0)  ; => Obj89_Arrow_Sub4
    move.w  d0,x_pos(a0)            ; update position
    move.b  #SndID_ArrowStick,d0
    jsrto   (PlaySound).l, JmpTo8_PlaySound
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30C7E:
Obj89_Arrow_Sub2_Move:
    move.w  d0,x_pos(a0)            ; update position
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30C86:
Obj89_Arrow_Sub4:
    move.b  #0,collision_flags(a0)      ; make arrow harmless
    btst    #7,status(a0)
    beq.s   +
    addi_.b #2,obj89_arrow_routine(a0)  ; => Obj89_Arrow_Sub6
+
    bsr.w   Obj89_Arrow_Platform
    lea (Ani_obj89_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo19_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
; loc_30CAC:
Obj89_Arrow_Sub6:
    bsr.w   Obj89_Arrow_ChkDropPlayers
    move.w  y_pos(a0),d0            ; load y position...
    add.w   y_vel(a0),d0            ; ... and add y velocity
    cmpi.w  #$4F0,d0            ; has arrow dropped to the ground?
    bgt.w   JmpTo55_DeleteObject        ; if yes, branch
    move.w  d0,y_pos(a0)            ; update y position
    jmpto   (DisplaySprite).l, JmpTo37_DisplaySprite
; ===========================================================================
 
    if removeJmpTos
JmpTo55_DeleteObject 
    endif
 
BranchTo_JmpTo55_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo55_DeleteObject
; ===========================================================================
; loc_30CCC:
Obj89_Arrow_Platform:
    tst.w   obj89_arrow_timer(a0)       ; is timer set?
    bne.s   Obj89_Arrow_Platform_Decay  ; if yes, branch
    move.w  #$1B,d1
    move.w  #1,d2
    move.w  #2,d3
    move.w  x_pos(a0),d4
    jsrto   (PlatformObject).l, JmpTo8_PlatformObject
    btst    #3,status(a0)           ; is Sonic standing on the arrow?
    beq.s   return_30D02            ; if not, branch
    move.w  #$1F,obj89_arrow_timer(a0)  ; else, set timer
 
; loc_30CF4:
Obj89_Arrow_Platform_Decay:
    subi_.w #1,obj89_arrow_timer(a0)    ; decrement timer
    bne.s   return_30D02            ; branch, if timer hasn't expired
    move.b  #6,obj89_arrow_routine(a0)  ; => Obj89_Arrow_Sub6
 
return_30D02:
    rts
; ===========================================================================
; loc_30D04:
Obj89_Arrow_ChkDropPlayers:
    bclr    #p1_standing_bit,status(a0)
    beq.s   +               ; branch, if Sonic wasn't standing on the arrow
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   Obj89_Arrow_DropPlayer
+
    bclr    #p2_standing_bit,status(a0)
    beq.s   return_30D2A            ; branch, if Tails wasn't standing on the arrow
    lea (Sidekick).w,a1 ; a1=character
 
; loc_30D1E:
Obj89_Arrow_DropPlayer:
    bset    #1,status(a1)
    bclr    #3,status(a1)
 
return_30D2A:
    rts
; ===========================================================================
; animation script
; off_30D2C:
Ani_obj89_a:    offsetTable
        offsetTableEntry.w byte_30D30   ; 0
        offsetTableEntry.w byte_30D47   ; 1
byte_30D30: dc.b   1,  4,  6,  5,  4,  6,  4,  5,  4,  6,  4,  4,  6,  5,  4,  6
        dc.b   4,  5,  4,  6,  4,$FD,  1; 16
    rev02even
        
byte_30D47: dc.b  $F,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4
        dc.b   4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,$F9; 16
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj89_MapUnc_30D68: BINCLUDE "mappings/sprite/obj89_a.bin"
 
; animation script
; off_30DC8:
Ani_obj89_b:    offsetTable
        offsetTableEntry.w byte_30DD4   ;  0
        offsetTableEntry.w byte_30DEA   ;  2
        offsetTableEntry.w byte_30DEE   ;  4
        offsetTableEntry.w byte_30DF1   ;  6
        offsetTableEntry.w byte_30DFD   ;  8
        offsetTableEntry.w byte_30E00   ; $A
byte_30DD4: dc.b   7,  0,  1,$FF,  2,  3,  2,  3,  2,  3,  2,  3,$FF,  4,  4,  4
        dc.b   4,  4,  4,  4,  4,$FF; 16
    rev02even
byte_30DEA: dc.b   1,  6,  7,$FF
    rev02even
byte_30DEE: dc.b  $F,  9,$FF
    rev02even
byte_30DF1: dc.b   2, $A, $A, $B, $B, $B, $B, $B, $A, $A,$FD,  2
    rev02even
byte_30DFD: dc.b  $F,  8,$FF
    rev02even
byte_30E00: dc.b   7,  5,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj89_MapUnc_30E04: BINCLUDE "mappings/sprite/obj89_b.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo37_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo55_DeleteObject 
    jmp (DeleteObject).l
JmpTo14_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo8_PlaySound 
    jmp (PlaySound).l
JmpTo22_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo19_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo3_RandomNumber 
    jmp (RandomNumber).l
JmpTo8_LoadPLC 
    jmp (LoadPLC).l
JmpTo5_AddPoints 
    jmp (AddPoints).l
JmpTo4_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo4_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
JmpTo8_PlatformObject 
    jmp (PlatformObject).l
JmpTo26_SolidObject 
    jmp (SolidObject).l
    
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 57 - MCZ boss
; ----------------------------------------------------------------------------
; OST: first $10 bytes for main sprite, 6 bytes for childsprites (5th byte unused)
obj57_sub5_y_vel    = $2E   ; word - y_vel of second digger when falling down
obj57_sub2_y_vel    = $30   ; word - y_vel of first digger when falling down
obj57_sub2_y_pos2   = $34   ; longword - y_pos of first digger when falling down
obj57_sub5_y_pos2   = $3A   ; longword - y_pos of second digger when falling down
; ----------------------------------------------------------------------------
; Sprite_30FA4:
Obj57:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj57_Index(pc,d0.w),d1
    jmp Obj57_Index(pc,d1.w)
; ===========================================================================
;off_30FB2:
Obj57_Index:    offsetTable
        offsetTableEntry.w Obj57_Init       ; 0 - Init
        offsetTableEntry.w Obj57_Main       ; 2 - Main Vehicle
        offsetTableEntry.w Obj57_FallingStuff   ; 4 - Spikes & Stones
; ===========================================================================
;loc_30FB8:
Obj57_Init:
    move.l  #Obj57_MapUnc_316EC,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MCZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0) ; gets overwritten
    move.w  #$21A0,x_pos(a0)
    move.w  #$560,y_pos(a0)
    move.b  #5,mainspr_mapframe(a0)
    addq.b  #2,boss_subtype(a0)
    move.b  #2,boss_routine(a0)
    bset    #6,render_flags(a0) ; use subobjects for rendering
    move.b  #4,mainspr_childsprites(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,boss_hitcount2(a0)
    move.w  x_pos(a0),(Boss_X_pos).w
    move.w  y_pos(a0),(Boss_Y_pos).w
    move.w  #$C0,(Boss_Y_vel).w ; move down
    move.b  #0,(Boss_CollisionRoutine).w
    move.b  #1,(Screen_Shaking_Flag).w
    move.b  #$40,mainspr_width(a0)
    move.w  x_pos(a0),sub2_x_pos(a0)
    move.w  y_pos(a0),sub2_y_pos(a0)
    move.b  #2,sub2_mapframe(a0)
    move.w  x_pos(a0),sub3_x_pos(a0)
    move.w  y_pos(a0),sub3_y_pos(a0)
    move.b  #1,sub3_mapframe(a0)
    move.w  x_pos(a0),sub4_x_pos(a0)
    move.w  y_pos(a0),sub4_y_pos(a0)
    move.b  #$E,sub4_mapframe(a0)
    move.w  x_pos(a0),sub5_x_pos(a0)
    move.w  y_pos(a0),sub5_y_pos(a0)
    move.b  #2,sub5_mapframe(a0)
    subi.w  #$28,sub5_x_pos(a0)
    move.w  #$28,(Boss_Countdown).w
    move.w  #-$380,obj57_sub5_y_vel(a0)
    move.w  #-$380,obj57_sub2_y_vel(a0)
 
    bsr.w   Obj57_InitAnimationData
    rts
; ===========================================================================
;loc_31090:
Obj57_InitAnimationData:
    lea (Boss_AnimationArray).w,a2
    move.b  #2,(a2)+    ; hover thingies (fire on)
    move.b  #0,(a2)+
    move.b  #3,(a2)+    ; digger 1 (vertical)
    move.b  #0,(a2)+
    move.b  #$10,(a2)+  ; main vehicle
    move.b  #0,(a2)+
    move.b  #$D,(a2)+   ; main vehicle center (including robotnik's face)
    move.b  #0,(a2)+
    move.b  #3,(a2)+    ; digger 2 (vertical)
    move.b  #0,(a2)+
    rts
; ===========================================================================
;loc_310BE:
Obj57_Main: ; Main Vehicle
    moveq   #0,d0
    move.b  boss_routine(a0),d0
    move.w  Obj57_Main_Index(pc,d0.w),d1
    jmp Obj57_Main_Index(pc,d1.w)
; ===========================================================================
;off_310CC:
Obj57_Main_Index: offsetTable
    offsetTableEntry.w Obj57_Main_Sub0  ;  0 - boss just moving up
    offsetTableEntry.w Obj57_Main_Sub2  ;  2 - boss moving down, stuff falling down
    offsetTableEntry.w Obj57_Main_Sub4  ;  4 - moving down, stop stuff falling down
    offsetTableEntry.w Obj57_Main_Sub6  ;  6 - digger transition (rotation), moving back and forth
    offsetTableEntry.w Obj57_Main_Sub8  ;  8 - boss defeated, standing still, exploding
    offsetTableEntry.w Obj57_Main_SubA  ; $A - slowly hovering down, no explosions
    offsetTableEntry.w Obj57_Main_SubC  ; $C - moving away fast
; ===========================================================================
;loc_310DA:
Obj57_Main_Sub0: ; boss just moving up
    subi_.w #1,(Boss_Countdown).w       ; countdown
    bpl.s   Obj57_Main_Sub0_Continue
    move.b  #0,(Boss_AnimationArray+5).w    ; reset anim main vehicle
    bsr.w   Boss_MoveObject
    cmpi.w  #$560,(Boss_Y_pos).w        ; a little above top screen boundary
    bgt.s   Obj57_Main_Sub0_Continue    ; if below that, branch
    move.w  #$100,(Boss_Y_vel).w
    move.w  (MainCharacter+x_pos).w,d3
    cmpi.w  #$2190,d3
    bhs.s   +
    move.w  #$2200,d3
    bra.s   ++
; ===========================================================================
+
    move.w  #$2120,d3
+
    move.w  d3,(Boss_X_pos).w
    addq.b  #2,boss_routine(a0) ; stuff falling down
    bclr    #0,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   (Boss_X_pos).w,d0
    bmi.s   Obj57_Main_Sub0_Continue
    bset    #0,render_flags(a0)
;loc_3112C:
Obj57_Main_Sub0_Continue:   ; if countdown finished or boss below $560
    cmpi.w  #$28,(Boss_Countdown).w
    bne.s   +
    move.b  #0,(Boss_CollisionRoutine).w
+
    cmpi.w  #$620,(Boss_Y_pos).w    ; if above, screenshaking & stones
    bge.s   Obj57_Main_Sub0_Standard
    move.b  #1,(Screen_Shaking_Flag).w
    bsr.w   Obj57_SpawnStoneSpike
 
Obj57_Main_Sub0_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_HandleHits
    lea (Ani_obj57).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_3116E:
Obj57_Main_Sub2: ; boss moving down, stuff falling down
    bsr.w   Boss_MoveObject
    bsr.w   Obj57_SpawnStoneSpike
    cmpi.w  #$620,(Boss_Y_pos).w    ; if below...
    blt.s   Obj57_Main_Sub2_Standard
    addq.b  #2,boss_routine(a0) ; ...next routine
    move.b  #0,(Screen_Shaking_Flag).w  ; no screen shaking
    
Obj57_Main_Sub2_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_HandleHits
    lea (Ani_obj57).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_311AA:
Obj57_Main_Sub4: ; moving down, stop stuff falling down
    bsr.w   Boss_MoveObject
    cmpi.w  #$660,(Boss_Y_pos).w
    blt.s   Obj57_Main_Sub4_Standard    ; if above, keep moving down
    move.w  #$660,(Boss_Y_pos).w    ; if below, routine 6 + new anim
    addq.b  #2,boss_routine(a0)
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,2(a1)
    ori.b   #6,2(a1)    ; (6) prepare for digger rotation to diag/hztl
    andi.b  #$F0,8(a1)
    ori.b   #6,8(a1)    ; (6) prepare for digger rotation to diag/hztl
    andi.b  #$F0,6(a1)
    ori.b   #$D,6(a1)   ; (D) robotnik face normal
    move.b  #$20,5(a1)  ; main vehicle light on
    move.w  #$64,(Boss_Countdown).w
    move.b  #$30,1(a1)  ; hover thingies fire off
    bclr    #0,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   (Boss_X_pos).w,d0
    bmi.s   +
    bset    #0,render_flags(a0)
+
    move.w  #-$200,(Boss_X_vel).w   ; boss moving horizontally
    move.w  #0,(Boss_Y_vel).w
    btst    #0,render_flags(a0)
    beq.s   Obj57_Main_Sub4_Standard
    neg.w   (Boss_X_vel).w
 
Obj57_Main_Sub4_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_HandleHits
    lea (Ani_obj57).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_3124A:
Obj57_Main_Sub6: ; digger transition (rotation), moving back and forth
    subi_.w #1,(Boss_Countdown).w
    cmpi.w  #$28,(Boss_Countdown).w
    bgt.w   Obj57_Main_Sub6_Standard
    move.b  #1,(Boss_CollisionRoutine).w
    tst.w   (Boss_Countdown).w
    bpl.w   Obj57_Main_Sub6_Standard
    tst.b   boss_hurt_sonic(a0) ; has sonic just been hurt?
    beq.s   +
    sf  boss_hurt_sonic(a0) ; if yes, clear this flag
    bra.s   Obj57_Main_Sub6_ReAscend1
; ===========================================================================
+
    bsr.w   Boss_MoveObject
    cmpi.w  #$2120,(Boss_X_pos).w
    bgt.s   +
    move.w  #$2120,(Boss_X_pos).w
    bra.s   Obj57_Main_Sub6_ReAscend2
; ===========================================================================
+
    cmpi.w  #$2200,(Boss_X_pos).w
    blt.s   Obj57_Main_Sub6_Standard
    move.w  #$2200,(Boss_X_pos).w
    bra.s   Obj57_Main_Sub6_ReAscend2
; ===========================================================================
;loc_31298:
Obj57_Main_Sub6_ReAscend1:  ; that's a dumb name for a label
    lea (Boss_AnimationArray).w,a1
    move.b  #$30,7(a1)  ; face grin after hurting sonic
;loc_312A2:
Obj57_Main_Sub6_ReAscend2:  ; set to routine 0 and make boss move up again
    move.w  #0,(Boss_X_vel).w
    move.b  #0,boss_routine(a0)
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,2(a1)
    ori.b   #$B,2(a1)   ; (B) prepare for digger rotation to diag/vert
    andi.b  #$F0,8(a1)
    ori.b   #$B,8(a1)   ; (B) prepare for digger rotation to diag/vert
    move.b  #0,1(a1)    ; hover thingies fire on
    andi.b  #$F0,6(a1)
    ori.b   #$D,6(a1)   ; (D) robotnik face normal
    move.w  #$64,(Boss_Countdown).w
    move.w  #-$C0,(Boss_Y_vel).w    ; move up
 
Obj57_Main_Sub6_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_HandleHits
    lea (Ani_obj57).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_3130A:
Obj57_TransferPositions:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub3_x_pos(a0)
    move.w  d1,sub3_y_pos(a0)
    move.w  d0,sub4_x_pos(a0)
    move.w  d1,sub4_y_pos(a0)
    tst.b   boss_defeated(a0)
    bne.s   Obj57_FallApart ; if boss defeated
    move.w  d0,sub5_x_pos(a0)
    move.w  d1,sub5_y_pos(a0)
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    move.w  d1,obj57_sub5_y_pos2(a0)
    move.w  d1,obj57_sub2_y_pos2(a0)
    btst    #0,render_flags(a0)
    beq.s   +
    addi.w  #$28,sub5_x_pos(a0)
    rts
; ===========================================================================
+
    subi.w  #$28,sub5_x_pos(a0)
    rts
; ===========================================================================
;loc_31358:
Obj57_FallApart:    ; make the digger thingies fall down
    cmpi.w  #$78,(Boss_Countdown).w
    bgt.s   return_313C4
    subi_.w #1,sub5_x_pos(a0)
    move.l  obj57_sub5_y_pos2(a0),d0
    move.w  obj57_sub5_y_vel(a0),d1
    addi.w  #$38,obj57_sub5_y_vel(a0)
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d0
    move.l  d0,obj57_sub5_y_pos2(a0)
    move.w  obj57_sub5_y_pos2(a0),sub5_y_pos(a0)
    cmpi.w  #$6F0,sub5_y_pos(a0)
    blt.s   +
    move.w  #0,obj57_sub5_y_vel(a0)
+           ; second one
    addi_.w #1,sub2_x_pos(a0)
    move.l  obj57_sub2_y_pos2(a0),d0
    move.w  obj57_sub2_y_vel(a0),d1
    addi.w  #$38,obj57_sub2_y_vel(a0)
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d0
    move.l  d0,obj57_sub2_y_pos2(a0)
    move.w  obj57_sub2_y_pos2(a0),sub2_y_pos(a0)
    cmpi.w  #$6F0,sub2_y_pos(a0)
    blt.s   return_313C4
    move.w  #0,obj57_sub2_y_vel(a0)
 
return_313C4:
    rts
; ===========================================================================
;loc_313C6:
Obj57_SpawnStoneSpike:  ; decide whether stone or spike
    move.b  (Vint_runcount+3).w,d1  ; not so random number?
    sf  d2
    andi.b  #$1F,d1
    beq.s   Obj57_LoadStoneSpike
    andi.b  #7,d1
    bne.s   return_31438
    st  d2
 ;loc_313DA:
Obj57_LoadStoneSpike:
    jsrto   (RandomNumber).l, JmpTo4_RandomNumber
    swap    d1
    andi.w  #$1FF,d1
    addi.w  #$20F0,d1
    cmpi.w  #$2230,d1
    bgt.s   Obj57_LoadStoneSpike
    jsrto   (SingleObjLoad).l, JmpTo15_SingleObjLoad
    bne.s   return_31438
    move.b  #ObjID_MCZBoss,id(a1)   ; load obj57
    move.b  #4,boss_subtype(a1)
    move.w  d1,x_pos(a1)
    move.w  #$5F0,y_pos(a1)
    move.l  #Obj57_MapUnc_316EC,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtUnc_FallingRocks,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    move.b  #$D,mapping_frame(a1)
    tst.b   d2
    bne.s   return_31438    ; stone
    move.b  #$14,mapping_frame(a1)  ; spike
    move.b  #$B1,collision_flags(a1)
 
return_31438:
    rts
; ===========================================================================
;loc_3143A:
Obj57_HandleHits:
    bsr.w   Obj57_HandleHits_Main
    cmpi.b  #$1F,boss_invulnerable_time(a0)
    bne.s   +   ; rts
    lea (Boss_AnimationArray).w,a1
    move.b  #$C0,7(a1)  ; face grin when hit
+
    rts
; ===========================================================================
;loc_31452:
Obj57_AddSinusOffset:   ; called from routine $A and $C
    move.b  boss_sine_count(a0),d0  ; sinus offset something
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    addq.b  #2,boss_sine_count(a0)  ; increment frame counter for sinus offset
;loc_31470:
Obj57_HandleHits_Main:
    cmpi.b  #8,boss_routine(a0)
    bhs.s   return_314B6        ; skip if boss already defeated
    tst.b   boss_hitcount2(a0)
    beq.s   Obj57_FinalDefeat
    tst.b   collision_flags(a0)
    bne.s   return_314B6
    tst.b   boss_invulnerable_time(a0)
    bne.s   +
    move.b  #$20,boss_invulnerable_time(a0) ; set invincibility timer
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
+
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   +
    move.w  #$EEE,d0
+
    move.w  d0,(a1)
    subq.b  #1,boss_invulnerable_time(a0)
    bne.s   return_314B6
    move.b  #$F,collision_flags(a0)
 
return_314B6:
    rts
; ===========================================================================
;loc_314B8:
Obj57_FinalDefeat:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo6_AddPoints
    move.w  #$B3,(Boss_Countdown).w
    move.b  #8,boss_routine(a0) ; routine boss defeated
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo9_LoadPLC
    rts
; ===========================================================================
;loc_314D2:
Obj57_Main_Sub8: ; boss defeated, standing still, exploding
    st  boss_defeated(a0)
    move.b  #0,(Screen_Shaking_Flag).w
    subq.w  #1,(Boss_Countdown).w   ; countdown initially $B3
    bmi.s   +           ; branch if countdown finished
    move.b  #$13,sub4_mapframe(a0)  ; burnt face
    move.b  #7,mainspr_mapframe(a0)
    bsr.w   Boss_LoadExplosion
    bra.s   Obj57_Main_Sub8_Standard
; ===========================================================================
+
    bset    #0,render_flags(a0)
    clr.w   (Boss_X_vel).w
    clr.w   (Boss_Y_vel).w
    addq.b  #2,boss_routine(a0) ; next routine
    move.b  #$12,sub4_mapframe(a0)  ; face grin when hit
    move.w  #-$12,(Boss_Countdown).w
    
Obj57_Main_Sub8_Standard:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_31526:
Obj57_Main_SubA: ; slowly hovering down, no explosions
    addq.w  #1,(Boss_Countdown).w   ; countdown initially -$12
    beq.s   ++          ; reset y_vel
    bpl.s   +++
    cmpi.w  #$620,(Boss_Y_pos).w
    bhs.s   +
    subq.w  #1,(Boss_Countdown).w
+
    addi.w  #$10,(Boss_Y_vel).w ; add gravity
    bra.s   Obj57_Main_SubA_Standard
; ===========================================================================
+
    clr.w   (Boss_Y_vel).w
    bra.s   Obj57_Main_SubA_Standard
; ===========================================================================
+
    cmpi.w  #$18,(Boss_Countdown).w
    blo.s   +       ; accelerate boss upwards
    beq.s   ++      ; reset y_vel, PlayLevelMusic
    cmpi.w  #$20,(Boss_Countdown).w
    blo.s   Obj57_Main_SubA_Standard
    lea (Boss_AnimationArray).w,a1
    move.b  #$D,7(a1)   ; face grin when hit
    _move.b #2,0(a2)    ; There is a bug here. This should be a1 instead of a2. A random part of RAM gets written to instead.
    move.b  #0,1(a1)    ; hover thingies fire off
    addq.b  #2,boss_routine(a0)
    bra.s   Obj57_Main_SubA_Standard
; ===========================================================================
+
    subi_.w #8,(Boss_Y_vel).w
    bra.s   Obj57_Main_SubA_Standard
; ===========================================================================
+
    clr.w   (Boss_Y_vel).w
    jsrto   (PlayLevelMusic).l, JmpTo5_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo5_LoadPLC_AnimalExplosion
;loc_3158A:
Obj57_Main_SubA_Standard:
    bsr.w   Boss_MoveObject
    bsr.w   Obj57_AddSinusOffset
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
;loc_315A6:
Obj57_Main_SubC: ; moving away fast
    move.w  #$400,(Boss_X_vel).w
    move.w  #-$40,(Boss_Y_vel).w    ; escape to the right
    cmpi.w  #$2240,(Camera_Max_X_pos).w
    beq.s   +
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   Obj57_Main_SubC_Standard
; ===========================================================================
+
    tst.b   render_flags(a0)
    bpl.s   JmpTo56_DeleteObject    ; if off screen
;loc_315C6:
Obj57_Main_SubC_Standard:
    bsr.w   Boss_MoveObject
    bsr.w   Obj57_AddSinusOffset
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj57).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj57_TransferPositions
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
 
JmpTo56_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
;loc_315F2:
Obj57_FallingStuff: ; Spikes & Stones
    jsrto   (ObjectMoveAndFall).l, JmpTo5_ObjectMoveAndFall
    subi.w  #$28,sub2_y_pos(a0) ; decrease gravity
    cmpi.w  #$6F0,y_pos(a0) ; if below boundary, delete
    if ~~removeJmpTos
    bgt.w   JmpTo57_DeleteObject
    else
    bgt.s   JmpTo56_DeleteObject
    endif
    jmpto   (DisplaySprite).l, JmpTo38_DisplaySprite
; ===========================================================================
; off_3160A: Obj57_AnimIndex:
Ani_obj57:  offsetTable
        offsetTableEntry.w byte_31628 ; 0 - main vehicle
        offsetTableEntry.w byte_3162E ; 1 - digger diagonal
        offsetTableEntry.w byte_31631 ; 2 - hover fire thingies to keep boss in air
        offsetTableEntry.w byte_31638 ; 3 - digger vertical animated 1 -> (4)
        offsetTableEntry.w byte_31649 ; 4 - digger vertical animated 2 -> (5)
        offsetTableEntry.w byte_3165A ; 5 - digger vertical animated 3 (loop)
        offsetTableEntry.w byte_31661 ; 6 - digger vertical animated 4 -> (7)
        offsetTableEntry.w byte_31673 ; 7 - digger vertical + diagonal transition -> (8)
        offsetTableEntry.w byte_31684 ; 8 - digger horizontal animated 1 -> (9)
        offsetTableEntry.w byte_31695 ; 9 - digger horizontal animated 2 -> (A)
        offsetTableEntry.w byte_316A6 ; A - digger horizontal animated 3 (loop)
        offsetTableEntry.w byte_316AD ; B - digger horizontal animated 4 -> (C)
        offsetTableEntry.w byte_316BF ; C - digger horizontal + diagonal transition -> (3)
        offsetTableEntry.w byte_316D1 ; D - center vehicle, robotnik's face normal
        offsetTableEntry.w byte_316E8 ; E - center vehicle, robotnik's face when hit
byte_31628: dc.b  $F,  1,$FF    ; light off
        dc.b       0,$FC,  2    ; light on; (3) subanimation
    rev02even
byte_3162E: dc.b   5,  8,$FF
    rev02even
byte_31631: dc.b   1,  5,  6,$FF    ; fire on
        dc.b       7,$FC,  3    ; fire off; (4) subanimation
    rev02even
byte_31638: dc.b   1,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  4,  4,  4,  4,$FD,  4
    rev02even
byte_31649: dc.b   1,  2,  2,  2,  2,  3,  3,  3,  4,  4,  4,  2,  2,  3,  3,$FD,  5
    rev02even
byte_3165A: dc.b   1,  4,  2,  3,  4,$FC,  1
    rev02even
byte_31661: dc.b   1,  2,  3,  4,  4,  2,  2,  3,  3,  3,  4,  4,  4,  2,  2,  2,$FD,  7
    rev02even
byte_31673: dc.b   1,  2,  3,  3,  3,  3,  4,  4,  4,  4,  4,  2,  8,  8,  8,$FD,  8
    rev02even
byte_31684: dc.b   1,  9,  9,  9,  9,  9, $A, $A, $A, $A, $A, $B, $B, $B, $B,$FD,  9
    rev02even
byte_31695: dc.b   1,  9,  9,  9,  9, $A, $A, $A, $B, $B, $B,  9,  9, $A, $A,$FD, $A
    rev02even
byte_316A6: dc.b   1, $B,  9, $A, $B,$FC,  1
    rev02even
byte_316AD: dc.b   1,  9, $A, $B, $B,  9,  9, $A, $A, $A, $B, $B, $B,  9,  9,  9,$FD, $C
    rev02even
byte_316BF: dc.b   1,  9, $A, $A, $A, $A, $B, $B, $B, $B, $B,  9,  8,  8,  8,  8,$FD,  3
    rev02even
byte_316D1: dc.b   7, $E, $F,$FF
        dc.b     $10,$11,$10,$11,$10,$11,$10,$11,$FF        ; (4) subanimation (grin after hurting sonic)
        dc.b     $12,$12,$12,$12,$12,$12,$12,$12,$12,$FF    ; (D) subanimation (grin when hit)
    rev02even
byte_316E8: dc.b   7,$12,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj57_MapUnc_316EC: BINCLUDE "mappings/sprite/obj57.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo38_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo57_DeleteObject 
    jmp (DeleteObject).l
JmpTo15_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo4_RandomNumber 
    jmp (RandomNumber).l
JmpTo9_LoadPLC 
    jmp (LoadPLC).l
JmpTo6_AddPoints 
    jmp (AddPoints).l
JmpTo5_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo5_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
JmpTo5_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 51 - CNZ boss
; ----------------------------------------------------------------------------
; Sprite_318F0:
Obj51:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj51_Index(pc,d0.w),d1
    jmp Obj51_Index(pc,d1.w)
; ===========================================================================
; off_318FE:
Obj51_Index:    offsetTable
        offsetTableEntry.w Obj51_Init   ; 0
        offsetTableEntry.w loc_31A04    ; 2
        offsetTableEntry.w loc_31F24    ; 4
; ===========================================================================
; loc_31904:
Obj51_Init:
    move.l  #Obj51_MapUnc_320EA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZBoss_Fudge,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.w  #$2A46,x_pos(a0)
    move.w  #$654,y_pos(a0)
    move.b  #0,mainspr_mapframe(a0)
    move.b  #$20,mainspr_width(a0)
    move.b  #$80,mainspr_height(a0)
    addq.b  #2,boss_subtype(a0)
    move.b  #0,angle(a0)
    bset    #6,render_flags(a0)
    move.b  #4,mainspr_childsprites(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,objoff_32(a0)
    move.w  x_pos(a0),(Boss_X_pos).w
    move.w  y_pos(a0),(Boss_Y_pos).w
    move.w  x_pos(a0),sub2_x_pos(a0)
    move.w  y_pos(a0),sub2_y_pos(a0)
    move.b  #5,sub2_mapframe(a0)
    move.w  x_pos(a0),sub3_x_pos(a0)
    move.w  y_pos(a0),sub3_y_pos(a0)
    move.b  #1,sub3_mapframe(a0)
    move.w  x_pos(a0),sub4_x_pos(a0)
    move.w  y_pos(a0),sub4_y_pos(a0)
    move.b  #6,sub4_mapframe(a0)
    move.w  x_pos(a0),sub5_x_pos(a0)
    move.w  y_pos(a0),sub5_y_pos(a0)
    move.b  #2,sub5_mapframe(a0)
    move.b  #0,objoff_38(a0)
    move.w  #0,(Boss_Y_vel).w
    move.w  #-$180,(Boss_X_vel).w
    move.b  #0,objoff_2D(a0)
    move.w  #1,(Boss_Countdown).w
    bsr.w   loc_319D6
    rts
; ===========================================================================
 
loc_319D6:
    lea (Boss_AnimationArray).w,a2
    move.b  #8,(a2)+
    move.b  #0,(a2)+
    move.b  #1,(a2)+
    move.b  #0,(a2)+
    move.b  #$10,(a2)+
    move.b  #0,(a2)+
    move.b  #3,(a2)+
    move.b  #0,(a2)+
    move.b  #2,(a2)+
    move.b  #0,(a2)+
    rts
; ===========================================================================
 
loc_31A04:
    tst.b   (Boss_CollisionRoutine).w
    beq.s   loc_31A1C
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   loc_31A1C
    move.b  #SndID_CNZBossZap,d0
    jsrto   (PlaySound).l, JmpTo9_PlaySound
 
loc_31A1C:
    moveq   #0,d0
    move.b  angle(a0),d0
    move.w  off_31A2A(pc,d0.w),d1
    jmp off_31A2A(pc,d1.w)
; ===========================================================================
off_31A2A:  offsetTable
        offsetTableEntry.w loc_31A36    ;  0
        offsetTableEntry.w loc_31BA8    ;  2
        offsetTableEntry.w loc_31C22    ;  4
        offsetTableEntry.w loc_31D5C    ;  6
        offsetTableEntry.w loc_31DCC    ;  8
        offsetTableEntry.w loc_31E2A    ; $A
; ===========================================================================
 
loc_31A36:
    moveq   #0,d0
    move.b  objoff_38(a0),d0
    move.w  off_31A44(pc,d0.w),d0
    jmp off_31A44(pc,d0.w)
; ===========================================================================
off_31A44:  offsetTable
        offsetTableEntry.w loc_31A48    ; 0
        offsetTableEntry.w loc_31A78    ; 2
; ===========================================================================
 
loc_31A48:
    cmpi.w  #$28C0,(Boss_X_pos).w
    bgt.s   BranchTo_loc_31AA4
    move.w  #$28C0,(Boss_X_pos).w
    move.w  #0,(Boss_Y_vel).w
    move.w  #$180,(Boss_X_vel).w
    move.b  #2,objoff_38(a0)
    bset    #0,render_flags(a0)
    move.b  #0,objoff_2D(a0)
 
BranchTo_loc_31AA4 
    bra.w   loc_31AA4
; ===========================================================================
 
loc_31A78:
    cmpi.w  #$29C0,(Boss_X_pos).w
    blt.s   loc_31AA4
    move.w  #$29C0,(Boss_X_pos).w
    move.w  #0,(Boss_Y_vel).w
    move.w  #-$180,(Boss_X_vel).w
    move.b  #0,objoff_38(a0)
    bclr    #0,render_flags(a0)
    move.b  #0,objoff_2D(a0)
 
loc_31AA4:
    bsr.w   Boss_MoveObject
    tst.b   objoff_3F(a0)
    beq.s   loc_31AB6
    subq.b  #1,objoff_3F(a0)
    bra.w   loc_31B46
; ===========================================================================
 
loc_31AB6:
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    addi.w  #$10,d0
    cmpi.w  #$20,d0
    bhs.s   loc_31B46
    cmpi.w  #$6B0,(MainCharacter+y_pos).w
    blo.s   loc_31B06
    cmpi.b  #3,objoff_2D(a0)
    bhs.s   loc_31B46
    addq.b  #1,objoff_2D(a0)
    addq.b  #2,angle(a0)
    move.b  #8,(Boss_AnimationArray).w
    move.b  #0,(Boss_AnimationArray+3).w
    move.b  #0,(Boss_AnimationArray+9).w
    move.b  #0,(Boss_CollisionRoutine).w
    bsr.w   loc_31BF2
    move.w  #$50,(Boss_Countdown).w
    bra.w   loc_31C08
; ===========================================================================
 
loc_31B06:
    cmpi.w  #$67C,(MainCharacter+y_pos).w
    blo.s   loc_31B46
    move.b  #$F,mainspr_mapframe(a0)
    move.b  #2,(Boss_CollisionRoutine).w
    move.b  #$20,(Boss_AnimationArray+3).w
    move.b  #$20,(Boss_AnimationArray+9).w
    move.b  #9,(Boss_AnimationArray).w
    addq.b  #4,angle(a0)
    move.w  #0,(Boss_X_vel).w
    move.w  #$180,(Boss_Y_vel).w
    move.b  #0,objoff_3E(a0)
    bra.w   loc_31C08
; ===========================================================================
 
loc_31B46:
    bra.w   +
+   addi_.w #1,(Boss_Countdown).w
    move.w  (Boss_Countdown).w,d0
    andi.w  #$3F,d0
    bne.w   loc_31C08
    btst    #6,(Boss_Countdown+1).w
    beq.s   loc_31B86
    move.b  #$F,mainspr_mapframe(a0)
    move.b  #2,(Boss_CollisionRoutine).w
    move.b  #$20,(Boss_AnimationArray+3).w
    move.b  #$20,(Boss_AnimationArray+9).w
    move.b  #9,(Boss_AnimationArray).w
    bra.w   loc_31C08
; ===========================================================================
 
loc_31B86:
    move.b  #$C,mainspr_mapframe(a0)
    move.b  #1,(Boss_CollisionRoutine).w
    move.b  #0,(Boss_AnimationArray+3).w
    move.b  #0,(Boss_AnimationArray+9).w
    move.b  #4,(Boss_AnimationArray).w
    bra.w   loc_31C08
; ===========================================================================
 
loc_31BA8:
    move.b  #0,(Boss_CollisionRoutine).w
    subi_.w #1,(Boss_Countdown).w
    bne.s   loc_31BC6
    move.b  #$20,(Boss_AnimationArray+3).w
    move.b  #$20,(Boss_AnimationArray+9).w
    bra.w   loc_31C08
; ===========================================================================
 
loc_31BC6:
    cmpi.w  #-$14,(Boss_Countdown).w
    bgt.w   loc_31C08
    move.b  #0,(Boss_AnimationArray+3).w
    move.b  #0,(Boss_AnimationArray+9).w
    move.b  #0,angle(a0)
    move.w  #-1,(Boss_Countdown).w
    move.b  #$40,objoff_3F(a0)
    bra.w   loc_31C08
; ===========================================================================
 
loc_31BF2:
    jsrto   (SingleObjLoad).l, JmpTo16_SingleObjLoad
    bne.s   return_31C06
    move.b  #ObjID_CNZBoss,id(a1) ; load obj51
    move.b  #4,boss_subtype(a1)
    move.l  a0,objoff_34(a1)
 
return_31C06:
    rts
; ===========================================================================
 
loc_31C08:
    bsr.w   loc_31CDC
    bsr.w   loc_31E76
    bsr.w   loc_31C92
    lea (Ani_obj51).l,a1
    bsr.w   AnimateBoss
 
    if removeJmpTos
JmpTo39_DisplaySprite 
    endif
 
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
loc_31C22:
    bsr.w   Boss_MoveObject
    tst.b   objoff_3E(a0)
    bne.s   loc_31C60
    cmpi.w  #$680,y_pos(a0)
    blo.s   loc_31C08
    move.w  #0,(Boss_X_vel).w
    move.w  #-$180,(Boss_Y_vel).w
    move.b  #-1,objoff_3E(a0)
    move.b  #1,(Boss_CollisionRoutine).w
    move.b  #0,(Boss_AnimationArray+3).w
    move.b  #0,(Boss_AnimationArray+9).w
    move.b  #4,(Boss_AnimationArray).w
    bra.s   loc_31C08
; ===========================================================================
 
loc_31C60:
    cmpi.w  #$654,y_pos(a0)
    bhs.s   loc_31C08
    move.b  #0,angle(a0)
    move.w  #0,(Boss_Y_vel).w
    move.w  #-$180,(Boss_X_vel).w
    btst    #0,render_flags(a0)
    beq.s   BranchTo_loc_31C08
    move.w  #$180,(Boss_X_vel).w
    move.b  #$C,mainspr_mapframe(a0)
 
BranchTo_loc_31C08 
    bra.w   loc_31C08
; ===========================================================================
 
loc_31C92:
    cmpi.b  #$2F,mainspr_height(a0)
    bne.s   loc_31CAC
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,6(a1)
    ori.b   #6,6(a1)
    rts
; ===========================================================================
 
loc_31CAC:
    cmpi.b  #4,(MainCharacter+routine).w
    beq.s   loc_31CBC
    cmpi.b  #4,(Sidekick+routine).w
    bne.s   return_31CDA
 
loc_31CBC:
    lea (Boss_AnimationArray).w,a1
    move.b  6(a1),d0
    andi.b  #$F,d0
    cmpi.b  #6,d0
    beq.s   return_31CDA
    andi.b  #$F0,6(a1)
    ori.b   #5,6(a1)
 
return_31CDA:
    rts
; ===========================================================================
 
loc_31CDC:
    move.b  mapping_frame(a0),d0
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    addq.b  #2,mapping_frame(a0)
    cmpi.b  #6,angle(a0)
    bhs.s   return_31D40
    tst.b   objoff_32(a0)
    beq.s   loc_31D42
    tst.b   collision_flags(a0)
    bne.s   return_31D40
    tst.b   mainspr_height(a0)
    bne.s   loc_31D24
    move.b  #$30,mainspr_height(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
 
loc_31D24:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   loc_31D32
    move.w  #$EEE,d0
 
loc_31D32:
    move.w  d0,(a1)
    subq.b  #1,mainspr_height(a0)
    bne.s   return_31D40
    move.b  #$F,collision_flags(a0)
 
return_31D40:
    rts
; ===========================================================================
 
loc_31D42:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo7_AddPoints
    move.w  #$B3,(Boss_Countdown).w
    move.b  #6,angle(a0)
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo10_LoadPLC
    rts
; ===========================================================================
 
loc_31D5C:
    st  objoff_2C(a0)
    subq.w  #1,(Boss_Countdown).w
    bmi.s   loc_31D7E
    move.b  #0,(Boss_CollisionRoutine).w
    move.b  #0,mainspr_mapframe(a0)
    move.b  #$B,collision_property(a0)
    bsr.w   Boss_LoadExplosion
    bra.s   loc_31DB8
; ===========================================================================
 
loc_31D7E:
    bset    #0,render_flags(a0)
    clr.w   (Boss_X_vel).w
    clr.w   (Boss_Y_vel).w
    addq.b  #2,angle(a0)
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,6(a1)
    ori.b   #3,6(a1)
    _move.b #8,0(a1)
    move.b  #$DD,(Level_Layout+$C54).w
    move.b  #1,(Screen_redraw_flag).w
    move.w  #-$12,(Boss_Countdown).w
 
loc_31DB8:
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   loc_31E76
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
loc_31DCC:
    addq.w  #1,(Boss_Countdown).w
    beq.s   loc_31DDC
    bpl.s   loc_31DE2
    addi.w  #$18,(Boss_Y_vel).w
    bra.s   loc_31E0E
; ===========================================================================
 
loc_31DDC:
    clr.w   (Boss_Y_vel).w
    bra.s   loc_31E0E
; ===========================================================================
 
loc_31DE2:
    cmpi.w  #$18,(Boss_Countdown).w
    blo.s   loc_31DFA
    beq.s   loc_31E02
    cmpi.w  #$20,(Boss_Countdown).w
    blo.s   loc_31E0E
    addq.b  #2,angle(a0)
    bra.s   loc_31E0E
; ===========================================================================
 
loc_31DFA:
    subi_.w #8,(Boss_Y_vel).w
    bra.s   loc_31E0E
; ===========================================================================
 
loc_31E02:
    clr.w   (Boss_Y_vel).w
    jsrto   (PlayLevelMusic).l, JmpTo6_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo6_LoadPLC_AnimalExplosion
 
loc_31E0E:
    bsr.w   Boss_MoveObject
    bsr.w   loc_31CDC
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   loc_31E76
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
loc_31E2A:
    move.w  #$400,(Boss_X_vel).w
    move.w  #-$40,(Boss_Y_vel).w
    cmpi.w  #$2B20,(Camera_Max_X_pos).w
    beq.s   loc_31E44
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   loc_31E4A
; ===========================================================================
 
loc_31E44:
    tst.b   render_flags(a0)
    bpl.s   JmpTo58_DeleteObject
 
loc_31E4A:
    bsr.w   Boss_MoveObject
    bsr.w   loc_31CDC
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   loc_31E76
    lea (Ani_obj51).l,a1
    bsr.w   AnimateBoss
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
    if removeJmpTos
JmpTo59_DeleteObject 
    endif
 
JmpTo58_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
loc_31E76:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub3_x_pos(a0)
    move.w  d1,sub3_y_pos(a0)
    move.w  d0,sub4_x_pos(a0)
    move.w  d1,sub4_y_pos(a0)
    tst.b   objoff_2C(a0)
    bne.s   loc_31EAE
    move.w  d0,sub5_x_pos(a0)
    move.w  d1,sub5_y_pos(a0)
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    move.w  d1,objoff_3A(a0)
    move.w  d1,objoff_34(a0)
    rts
; ===========================================================================
 
loc_31EAE:
    cmpi.w  #$78,(Boss_Countdown).w
    bgt.s   return_31F22
    subi_.w #1,sub5_x_pos(a0)
    move.l  objoff_3A(a0),d0
    move.w  objoff_2E(a0),d1
    addi.w  #$38,objoff_2E(a0)
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d0
    move.l  d0,objoff_3A(a0)
    move.w  objoff_3A(a0),sub5_y_pos(a0)
    cmpi.w  #$6F0,sub5_y_pos(a0)
    blt.s   loc_31EE8
    move.w  #0,objoff_2E(a0)
 
loc_31EE8:
    cmpi.w  #$3C,(Boss_Countdown).w
    bgt.s   return_31F22
    addi_.w #1,sub2_x_pos(a0)
    move.l  objoff_34(a0),d0
    move.w  objoff_30(a0),d1
    addi.w  #$38,objoff_30(a0)
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d0
    move.l  d0,objoff_34(a0)
    move.w  objoff_34(a0),sub2_y_pos(a0)
    cmpi.w  #$6F0,sub2_y_pos(a0)
    blt.s   return_31F22
    move.w  #0,objoff_30(a0)
 
return_31F22:
    rts
; ===========================================================================
 
loc_31F24:
    movea.l objoff_34(a0),a1 ; a1=object
    cmpi.b  #6,angle(a1)
    bhs.w   JmpTo59_DeleteObject
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_31F40(pc,d0.w),d1
    jmp off_31F40(pc,d1.w)
; ===========================================================================
off_31F40:  offsetTable
        offsetTableEntry.w loc_31F48    ; 0
        offsetTableEntry.w loc_31F96    ; 2
        offsetTableEntry.w loc_31FDC    ; 4
        offsetTableEntry.w loc_32080    ; 6
; ===========================================================================
 
loc_31F48:
    move.l  #Obj51_MapUnc_320EA,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_CNZBoss_Fudge,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #7,priority(a0)
    addq.b  #2,routine_secondary(a0)
    movea.l objoff_34(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi.w  #$30,y_pos(a0)
    move.b  #8,y_radius(a0)
    move.b  #8,x_radius(a0)
    move.b  #$12,mapping_frame(a0)
    move.b  #$98,collision_flags(a0)
    rts
; ===========================================================================
 
loc_31F96:
    movea.l objoff_34(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.w  objoff_28(a0),d0
    add.w   d0,y_pos(a0)
    addi_.w #1,d0
    cmpi.w  #$2E,d0
    blt.s   +
    move.w  #$2E,d0
+
    move.w  d0,objoff_28(a0)
    tst.w   (Boss_Countdown).w
    bne.w   JmpTo39_DisplaySprite
    addq.b  #2,routine_secondary(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,y_vel(a0)
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
loc_31FDC:
    bsr.w   loc_31FF8
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.w   JmpTo39_DisplaySprite
    add.w   d1,y_pos(a0)
    bsr.w   loc_32030
    jmpto   (DisplaySprite).l, JmpTo39_DisplaySprite
; ===========================================================================
 
loc_31FF8:
    moveq   #0,d2
    move.w  x_pos(a0),d2
    swap    d2
    moveq   #0,d3
    move.w  y_pos(a0),d3
    swap    d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    addi.w  #$38,y_vel(a0)
    swap    d2
    move.w  d2,x_pos(a0)
    swap    d3
    move.w  d3,y_pos(a0)
    rts
; ===========================================================================
 
loc_32030:
    move.b  #SndID_BossExplosion,d0
    jsrto   (PlaySound).l, JmpTo9_PlaySound
    move.w  #make_art_tile(ArtTile_ArtNem_CNZBoss_Fudge,0,0),art_tile(a0)
    move.b  #7,anim(a0)
    move.w  #-$300,y_vel(a0)
    move.w  #-$100,x_vel(a0)
    move.b  #4,boss_subtype(a0)
    move.b  #6,routine_secondary(a0)
    move.b  #$98,collision_flags(a0)
    jsrto   (SingleObjLoad2).l, JmpTo23_SingleObjLoad2
    bne.s   return_3207E
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
 
loc_3206E:
    move.l  (a0,d0.w),(a1,d0.w)
    addq.w  #4,d0
    dbf d1,loc_3206E
    if object_size&3
    move.w  (a0,d0.w),(a1,d0.w)
    endif
 
    neg.w   x_vel(a1)
 
return_3207E:
    rts
; ===========================================================================
 
loc_32080:
    bsr.w   loc_31FF8
    lea (Ani_obj51).l,a1
    jsrto   (AnimateSprite).l, JmpTo20_AnimateSprite
    cmpi.w  #$705,y_pos(a0)
    blo.w   JmpTo39_DisplaySprite
    jmpto   JmpTo59_DeleteObject, JmpTo59_DeleteObject
; ===========================================================================
; animation script
; off_3209C:
Ani_obj51:  offsetTable
        offsetTableEntry.w byte_320B0   ; 0
        offsetTableEntry.w byte_320B3   ; 1
        offsetTableEntry.w byte_320B9   ; 2
        offsetTableEntry.w byte_320BF   ; 3
        offsetTableEntry.w byte_320C3   ; 4
        offsetTableEntry.w byte_320C8   ; 5
        offsetTableEntry.w byte_320D3   ; 6
        offsetTableEntry.w byte_320DD   ; 7
        offsetTableEntry.w byte_320E1   ; 8
        offsetTableEntry.w byte_320E4   ; 9
byte_320B0: dc.b  $F,  1,$FF
    rev02even
byte_320B3: dc.b  $F,  4,$FF,  5,$FC,  2
    rev02even
byte_320B9: dc.b  $F,  2,$FF,  3,$FC,  2
    rev02even
byte_320BF: dc.b   7,  6,  7,$FF
    rev02even
byte_320C3: dc.b   1, $C, $D, $E,$FF
    rev02even
byte_320C8: dc.b   7,  8,  9,  8,  9,  8,  9,  8,  9,$FD,  3
    rev02even
byte_320D3: dc.b   7, $A, $A, $A, $A, $A, $A, $A,$FD,  3
    rev02even
byte_320DD: dc.b   3,$13,$14,$FF
    rev02even
byte_320E1: dc.b   1,  0,$FF
    rev02even
byte_320E4: dc.b   1, $F,$10,$11,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj51_MapUnc_320EA: BINCLUDE "mappings/sprite/obj51.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo39_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo59_DeleteObject 
    jmp (DeleteObject).l
JmpTo16_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo9_PlaySound 
    jmp (PlaySound).l
JmpTo23_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo20_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo10_LoadPLC 
    jmp (LoadPLC).l
JmpTo7_AddPoints 
    jmp (AddPoints).l
JmpTo6_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo6_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 54 - MTZ boss
; ----------------------------------------------------------------------------
; Sprite_32288:
Obj54:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj54_Index(pc,d0.w),d1
    jmp Obj54_Index(pc,d1.w)
; ===========================================================================
; off_32296:
Obj54_Index:    offsetTable
        offsetTableEntry.w Obj54_Init           ; 0
        offsetTableEntry.w Obj54_Main           ; 2
        offsetTableEntry.w Obj54_Laser          ; 4
        offsetTableEntry.w Obj54_LaserShooter   ; 6
; ===========================================================================
; loc_3229E:
Obj54_Init:
    move.l  #Obj54_MapUnc_32DC6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MTZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.w  #$2B50,x_pos(a0)
    move.w  #$380,y_pos(a0)
    move.b  #2,mainspr_mapframe(a0)
    addq.b  #2,boss_subtype(a0)     ; => Obj54_Main
    bset    #6,render_flags(a0)
    move.b  #2,mainspr_childsprites(a0)
    move.b  #$F,collision_flags(a0)
    move.b  #8,boss_hitcount2(a0)
    move.b  #7,objoff_3E(a0)
    move.w  x_pos(a0),(Boss_X_pos).w
    move.w  y_pos(a0),(Boss_Y_pos).w
    move.w  #0,(Boss_X_vel).w
    move.w  #$100,(Boss_Y_vel).w
    move.b  #$20,mainspr_width(a0)
    clr.b   objoff_2B(a0)
    clr.b   objoff_2C(a0)
    move.b  #$40,mapping_frame(a0)
    move.b  #$27,objoff_33(a0)
    move.b  #$27,objoff_39(a0)
    move.w  x_pos(a0),sub2_x_pos(a0)
    move.w  y_pos(a0),sub2_y_pos(a0)
    move.b  #$C,sub2_mapframe(a0)
    move.w  x_pos(a0),sub3_x_pos(a0)
    move.w  y_pos(a0),sub3_y_pos(a0)
    move.b  #0,sub3_mapframe(a0)
    jsrto   (SingleObjLoad).l, JmpTo17_SingleObjLoad
    bne.s   +
    move.b  #ObjID_MTZBoss,id(a1) ; load obj54
    move.b  #6,boss_subtype(a1)     ; => Obj54_LaserShooter
    move.b  #$13,mapping_frame(a1)
    move.l  #Obj54_MapUnc_32DC6,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MTZBoss,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #6,priority(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  a0,objoff_34(a1)
    move.b  #$20,width_pixels(a1)
    jsrto   (SingleObjLoad).l, JmpTo17_SingleObjLoad
    bne.s   +
    move.b  #ObjID_MTZBossOrb,id(a1) ; load obj53
    move.l  a0,objoff_34(a1)
+
    lea (Boss_AnimationArray).w,a2
    move.b  #$10,(a2)+
    move.b  #0,(a2)+
    move.b  #3,(a2)+
    move.b  #0,(a2)+
    move.b  #1,(a2)+
    move.b  #0,(a2)+
    rts
; ===========================================================================
;loc_323BA
Obj54_Main:
    moveq   #0,d0
    move.b  angle(a0),d0
    move.w  Obj54_MainSubStates(pc,d0.w),d1
    jmp Obj54_MainSubStates(pc,d1.w)
; ===========================================================================
Obj54_MainSubStates:    offsetTable
        offsetTableEntry.w Obj54_MainSub0   ;   0
        offsetTableEntry.w Obj54_MainSub2   ;   2
        offsetTableEntry.w Obj54_MainSub4   ;   4
        offsetTableEntry.w Obj54_MainSub6   ;   6
        offsetTableEntry.w Obj54_MainSub8   ;   8
        offsetTableEntry.w Obj54_MainSubA   ;  $A
        offsetTableEntry.w Obj54_MainSubC   ;  $C
        offsetTableEntry.w Obj54_MainSubE   ;  $E
        offsetTableEntry.w Obj54_MainSub10  ; $10
        offsetTableEntry.w Obj54_MainSub12  ; $12
; ===========================================================================
;loc_323DC
Obj54_MainSub0:
    bsr.w   Boss_MoveObject
    move.w  (Boss_Y_pos).w,y_pos(a0)
    cmpi.w  #$4A0,(Boss_Y_pos).w
    blo.s   +
    addq.b  #2,angle(a0)        ; => Obj54_MainSub2
    move.w  #0,(Boss_Y_vel).w
    move.w  #-$100,(Boss_X_vel).w
    bclr    #7,objoff_2B(a0)
    bclr    #0,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d0
    cmp.w   (Boss_X_pos).w,d0
    blo.s   +
    move.w  #$100,(Boss_X_vel).w
    bset    #7,objoff_2B(a0)
    bset    #0,render_flags(a0)
+
    bsr.w   Obj54_AnimateFace
    lea (Ani_obj53).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj54_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_3243C
Obj54_Float:
    move.b  mapping_frame(a0),d0
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    addq.b  #4,mapping_frame(a0)
    rts
; ===========================================================================
;loc_32456
Obj54_MainSub2:
    bsr.w   Boss_MoveObject
    btst    #7,objoff_2B(a0)
    bne.s   +
    cmpi.w  #$2AD0,(Boss_X_pos).w
    bhs.s   Obj54_MoveAndShow
    bchg    #7,objoff_2B(a0)
    move.w  #$100,(Boss_X_vel).w
    bset    #0,render_flags(a0)
    bset    #6,objoff_2B(a0)
    beq.s   Obj54_MoveAndShow
    addq.b  #2,angle(a0)        ; => Obj54_MainSub4
    move.w  #-$100,(Boss_Y_vel).w
    bra.s   Obj54_MoveAndShow
; ===========================================================================
+
    cmpi.w  #$2BD0,(Boss_X_pos).w
    blo.s   Obj54_MoveAndShow
    bchg    #7,objoff_2B(a0)
    move.w  #-$100,(Boss_X_vel).w
    bclr    #0,render_flags(a0)
    bset    #6,objoff_2B(a0)
    beq.s   Obj54_MoveAndShow
    addq.b  #2,angle(a0)        ; => Obj54_MainSub4
    move.w  #-$100,(Boss_Y_vel).w
;loc_324BC
Obj54_MoveAndShow:
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj54_Float
;loc_324C6
Obj54_Display:
    bsr.w   Obj54_AnimateFace
    lea (Ani_obj53).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj54_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_324DC
Obj54_MainSub4:
    bsr.w   Boss_MoveObject
    cmpi.w  #$470,(Boss_Y_pos).w
    bhs.s   +
    move.w  #0,(Boss_Y_vel).w
+
    btst    #7,objoff_2B(a0)
    bne.s   +
    cmpi.w  #$2B50,(Boss_X_pos).w
    bhs.s   ++
    move.w  #0,(Boss_X_vel).w
    bra.s   ++
; ===========================================================================
+
    cmpi.w  #$2B50,(Boss_X_pos).w
    blo.s   +
    move.w  #0,(Boss_X_vel).w
+
    move.w  (Boss_X_vel).w,d0
    or.w    (Boss_Y_vel).w,d0
    bne.s   BranchTo_Obj54_MoveAndShow
    addq.b  #2,angle(a0)        ; => Obj54_MainSub6
 
BranchTo_Obj54_MoveAndShow 
    bra.s   Obj54_MoveAndShow
; ===========================================================================
;loc_32524
Obj54_MainSub6:
    cmpi.b  #$68,objoff_33(a0)
    bhs.s   +
    addq.b  #1,objoff_33(a0)
    addq.b  #1,objoff_39(a0)
    bra.s   BranchTo2_Obj54_MoveAndShow
; ===========================================================================
+
    subq.b  #1,objoff_39(a0)
    bne.s   BranchTo2_Obj54_MoveAndShow
    addq.b  #2,angle(a0)        ; => Obj54_MainSub8
 
BranchTo2_Obj54_MoveAndShow 
    bra.w   Obj54_MoveAndShow
; ===========================================================================
;loc_32544
Obj54_MainSub8:
    cmpi.b  #$27,objoff_33(a0)
    blo.s   +
    subq.b  #1,objoff_33(a0)
    bra.s   BranchTo3_Obj54_MoveAndShow
; ===========================================================================
+
    addq.b  #1,objoff_39(a0)
    cmpi.b  #$27,objoff_39(a0)
    blo.s   BranchTo3_Obj54_MoveAndShow
    move.w  #$100,(Boss_Y_vel).w
    move.b  #0,angle(a0)        ; => Obj54_MainSub0
    bclr    #6,objoff_2B(a0)
 
BranchTo3_Obj54_MoveAndShow 
    bra.w   Obj54_MoveAndShow
; ===========================================================================
;loc_32574
Obj54_MainSubA:
    tst.b   objoff_39(a0)
    beq.s   +
    subq.b  #1,objoff_39(a0)
    bra.s   ++
; ===========================================================================
+
    move.b  #-1,objoff_3A(a0)
+
    cmpi.b  #$27,objoff_33(a0)
    blo.s   +
    subq.b  #1,objoff_33(a0)
+
    bsr.w   Boss_MoveObject
    cmpi.w  #$420,(Boss_Y_pos).w
    bhs.s   +
    move.w  #0,(Boss_Y_vel).w
+
    tst.b   objoff_2C(a0)
    bne.s   BranchTo4_Obj54_MoveAndShow
    tst.b   objoff_3A(a0)
    beq.s   +
    move.b  #$80,objoff_3A(a0)
+
    addq.b  #2,angle(a0)        ; => Obj54_MainSubC
 
BranchTo4_Obj54_MoveAndShow 
    bra.w   Obj54_MoveAndShow
; ===========================================================================
;loc_325BE
Obj54_MainSubC:
    tst.b   objoff_3E(a0)
    beq.s   ++
    tst.b   objoff_3A(a0)
    bne.s   BranchTo5_Obj54_MoveAndShow
    cmpi.b  #$27,objoff_39(a0)
    bhs.s   +
    addq.b  #1,objoff_39(a0)
    bra.s   BranchTo5_Obj54_MoveAndShow
; ===========================================================================
+
    move.w  #$100,(Boss_Y_vel).w
    move.b  #0,angle(a0)        ; => Obj54_MainSub0
    bclr    #6,objoff_2B(a0)
    bra.s   BranchTo5_Obj54_MoveAndShow
; ===========================================================================
+
    move.w  #-$180,(Boss_Y_vel).w
    move.w  #-$100,(Boss_X_vel).w
    bclr    #0,render_flags(a0)
    btst    #7,objoff_2B(a0)
    beq.s   +
    move.w  #$100,(Boss_X_vel).w
    bset    #0,render_flags(a0)
+
    move.b  #$E,angle(a0)       ; => Obj54_MainSubE
    move.b  #0,objoff_2E(a0)
    bclr    #6,objoff_2B(a0)
    move.b  #0,objoff_2F(a0)
 
BranchTo5_Obj54_MoveAndShow 
    bra.w   Obj54_MoveAndShow
; ===========================================================================
;loc_3262E
Obj54_MainSubE:
    tst.b   objoff_2F(a0)
    beq.s   +
    subq.b  #1,objoff_2F(a0)
    bra.w   Obj54_Display
; ===========================================================================
+
    moveq   #0,d0
    move.b  objoff_2E(a0),d0
    move.w  off_3264A(pc,d0.w),d1
    jmp off_3264A(pc,d1.w)
; ===========================================================================
off_3264A:  offsetTable
        offsetTableEntry.w loc_32650    ; 0
        offsetTableEntry.w loc_326B8    ; 2
        offsetTableEntry.w loc_32704    ; 4
; ===========================================================================
 
loc_32650:
    bsr.w   Boss_MoveObject
    cmpi.w  #$420,(Boss_Y_pos).w
    bhs.s   +
    move.w  #0,(Boss_Y_vel).w
+
    btst    #7,objoff_2B(a0)
    bne.s   +
    cmpi.w  #$2AF0,(Boss_X_pos).w
    bhs.s   BranchTo6_Obj54_MoveAndShow
    addq.b  #2,objoff_2E(a0)
    move.w  #$180,(Boss_Y_vel).w
    move.b  #3,objoff_2D(a0)
    move.w  #$1E,(Boss_Countdown).w
    bset    #0,render_flags(a0)
    bra.s   BranchTo6_Obj54_MoveAndShow
; ===========================================================================
+
    cmpi.w  #$2BB0,(Boss_X_pos).w
    blo.s   BranchTo6_Obj54_MoveAndShow
    addq.b  #2,objoff_2E(a0)
    move.w  #$180,(Boss_Y_vel).w
    move.b  #3,objoff_2D(a0)
    move.w  #$1E,(Boss_Countdown).w
    bclr    #0,render_flags(a0)
 
BranchTo6_Obj54_MoveAndShow 
    bra.w   Obj54_MoveAndShow
; ===========================================================================
 
loc_326B8:
    bsr.w   Boss_MoveObject
    cmpi.w  #$4A0,(Boss_Y_pos).w
    blo.s   +
    move.w  #-$180,(Boss_Y_vel).w
    addq.b  #2,objoff_2E(a0)
    bchg    #7,objoff_2B(a0)
    bra.s   +++
; ===========================================================================
+
    btst    #7,objoff_2B(a0)
    bne.s   +
    cmpi.w  #$2AD0,(Boss_X_pos).w
    bhs.s   ++
    move.w  #0,(Boss_X_vel).w
    bra.s   ++
; ===========================================================================
+
    cmpi.w  #$2BD0,(Boss_X_pos).w
    blo.s   +
    move.w  #0,(Boss_X_vel).w
+
    bsr.w   Obj54_FireLaser
    bra.w   Obj54_MoveAndShow
; ===========================================================================
 
loc_32704:
    bsr.w   Boss_MoveObject
    cmpi.w  #$470,(Boss_Y_pos).w
    bhs.s   +
    move.w  #$100,(Boss_X_vel).w
    btst    #7,objoff_2B(a0)
    bne.s   +
    move.w  #-$100,(Boss_X_vel).w
+
    cmpi.w  #$420,(Boss_Y_pos).w
    bhs.s   +
    move.w  #0,(Boss_Y_vel).w
    move.b  #0,objoff_2E(a0)
+
    bsr.w   Obj54_FireLaser
    bra.w   Obj54_MoveAndShow
; ===========================================================================
;loc_32740
Obj54_FireLaser:
    subi_.w #1,(Boss_Countdown).w
    bne.s   +       ; rts
    tst.b   objoff_2D(a0)
    beq.s   +       ; rts
    subq.b  #1,objoff_2D(a0)
    jsrto   (SingleObjLoad).l, JmpTo17_SingleObjLoad
    bne.s   +       ; rts
    move.b  #ObjID_MTZBoss,id(a1) ; load obj54
    move.b  #4,boss_subtype(a1)     ; => Obj54_Laser
    move.l  a0,objoff_34(a1)
    move.w  #$1E,(Boss_Countdown).w
    move.b  #$10,objoff_2F(a0)
+
    rts
; ===========================================================================
;loc_32774
Obj54_AlignSprites:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    move.w  d0,sub3_x_pos(a0)
    move.w  d1,sub3_y_pos(a0)
    rts
; ===========================================================================
;loc_3278E
Obj54_AnimateFace:
    bsr.w   Obj54_CheckHit
    cmpi.b  #$3F,boss_invulnerable_time(a0)
    bne.s   ++
    st.b    objoff_38(a0)
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,2(a1)
    ori.b   #5,2(a1)
    tst.b   objoff_3E(a0)
    beq.s   +
    move.b  #$A,angle(a0)       ; => Obj54_MainSubA
    move.w  #-$180,(Boss_Y_vel).w
    subq.b  #1,objoff_3E(a0)
    move.w  #0,(Boss_X_vel).w
+
    move.w  #0,(Boss_X_vel).w
    rts
; ===========================================================================
+
    cmpi.b  #4,(MainCharacter+routine).w
    beq.s   +
    cmpi.b  #4,(Sidekick+routine).w
    bne.s   ++      ; rts
+
    lea (Boss_AnimationArray).w,a1
    move.b  2(a1),d0
    andi.b  #$F,d0
    cmpi.b  #4,d0
    beq.s   +       ; rts
    andi.b  #$F0,2(a1)
    ori.b   #4,2(a1)
+
    rts
; ===========================================================================
;loc_32802
Obj54_MainSub10:
    subq.w  #1,(Boss_Countdown).w
    cmpi.w  #$3C,(Boss_Countdown).w
    blo.s   ++
    bmi.s   +
    bsr.w   Boss_LoadExplosion
    lea (Boss_AnimationArray).w,a1
    move.b  #7,2(a1)
    bra.s   ++
; ===========================================================================
+
    bset    #0,render_flags(a0)
    clr.w   (Boss_X_vel).w
    clr.w   (Boss_Y_vel).w
    addq.b  #2,angle(a0)        ; => Obj54_MainSub12
    move.w  #-$12,(Boss_Countdown).w
    lea (Boss_AnimationArray).w,a1
    move.b  #3,2(a1)
    jsrto   (PlayLevelMusic).l, JmpTo7_PlayLevelMusic
+
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj53).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj54_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_32864
Obj54_MainSub12:
    move.w  #$400,(Boss_X_vel).w
    move.w  #-$40,(Boss_Y_vel).w
    cmpi.w  #$2BF0,(Camera_Max_X_pos).w
    bhs.s   +
    addq.w  #2,(Camera_Max_X_pos).w
    bra.s   ++
; ===========================================================================
+
    tst.b   render_flags(a0)
    bpl.s   JmpTo60_DeleteObject
+
    tst.b   (Boss_defeated_flag).w
    bne.s   +
    move.b  #1,(Boss_defeated_flag).w
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo7_LoadPLC_AnimalExplosion
+
    bsr.w   Boss_MoveObject
    bsr.w   loc_328C0
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    lea (Ani_obj53).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj54_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
 
JmpTo60_DeleteObject 
    jmp (DeleteObject).l
; ===========================================================================
 
loc_328C0:
    move.b  mapping_frame(a0),d0
    jsr (CalcSine).l
    asr.w   #6,d0
    add.w   (Boss_Y_pos).w,d0
    move.w  d0,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    addq.b  #2,mapping_frame(a0)
;loc_328DE
Obj54_CheckHit:
    cmpi.b  #$10,angle(a0)
    bhs.s   return_32924
    tst.b   boss_hitcount2(a0)
    beq.s   Obj54_Defeated
    tst.b   collision_flags(a0)
    bne.s   return_32924
    tst.b   boss_invulnerable_time(a0)
    bne.s   +
    move.b  #$40,boss_invulnerable_time(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
+
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   +
    move.w  #$EEE,d0
+
    move.w  d0,(a1)
    subq.b  #1,boss_invulnerable_time(a0)
    bne.s   return_32924
    move.b  #$F,collision_flags(a0)
 
return_32924:
    rts
; ===========================================================================
;loc_32926
Obj54_Defeated:
    moveq   #100,d0
    jsrto   (AddPoints).l, JmpTo8_AddPoints
    move.w  #$EF,(Boss_Countdown).w
    move.b  #$10,angle(a0)      ; => Obj54_MainSub10
    moveq   #PLCID_Capsule,d0
    jsrto   (LoadPLC).l, JmpTo11_LoadPLC
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 53 - Shield orbs that surround MTZ boss
; ----------------------------------------------------------------------------
; Sprite_32940:
Obj53:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj53_Index(pc,d0.w),d1
    jmp Obj53_Index(pc,d1.w)
; ===========================================================================
; off_3294E:
Obj53_Index:    offsetTable
        offsetTableEntry.w Obj53_Init   ; 0
        offsetTableEntry.w Obj53_Main   ; 2
        offsetTableEntry.w Obj53_BreakAway  ; 4
        offsetTableEntry.w Obj53_BounceAround   ; 6
        offsetTableEntry.w Obj53_Burst  ; 8
; ===========================================================================
; loc_32958:
Obj53_Init:
    movea.l a0,a1
    moveq   #6,d3
    moveq   #0,d2
    bra.s   +
; ===========================================================================
-   jsrto   (SingleObjLoad).l, JmpTo17_SingleObjLoad
    bne.s   ++
+
    move.b  #$20,width_pixels(a1)
    move.l  objoff_34(a0),objoff_34(a1)
    move.b  #ObjID_MTZBossOrb,id(a1) ; load obj53
    move.l  #Obj54_MapUnc_32DC6,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_MTZBoss,0,0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #3,priority(a1)
    addq.b  #2,routine(a1)      ; => Obj53_Main
    move.b  #5,mapping_frame(a1)
    move.b  byte_329CC(pc,d2.w),objoff_28(a1)
    move.b  byte_329CC(pc,d2.w),objoff_3B(a1)
    move.b  byte_329D3(pc,d2.w),objoff_3A(a1)
    move.b  #$40,objoff_29(a1)
    move.b  #$87,collision_flags(a1)
    move.b  #2,collision_property(a1)
    move.b  #0,objoff_3C(a1)
    addq.w  #1,d2
    dbf d3,-
+
    rts
; ===========================================================================
byte_329CC:
    dc.b $24
    dc.b $6C    ; 1
    dc.b $B4    ; 2
    dc.b $FC    ; 3
    dc.b $48    ; 4
    dc.b $90    ; 5
    dc.b $D8    ; 6
    rev02even
byte_329D3:
    dc.b   0
    dc.b   1    ; 1
    dc.b   1    ; 2
    dc.b   0    ; 3
    dc.b   1    ; 4
    dc.b   1    ; 5
    dc.b   0    ; 6
    even
; ===========================================================================
;loc_329DA
Obj53_Main:
    movea.l objoff_34(a0),a1 ; a1=object
    move.w  y_pos(a1),objoff_2A(a0)
    subi_.w #4,objoff_2A(a0)
    move.w  x_pos(a1),objoff_38(a0)
    tst.b   objoff_38(a1)
    beq.s   Obj53_ClearBossCollision
    move.b  #0,objoff_38(a1)
    addi_.b #1,objoff_2C(a1)
    addq.b  #2,routine(a0)      ; => Obj53_BreakAway
    move.b  #$3C,objoff_32(a0)
    move.b  #2,anim(a0)
    move.w  #-$400,y_vel(a0)
    move.w  #-$80,d1
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    bpl.s   +
    neg.w   d1
+
    cmpi.w  #$2AF0,x_pos(a0)
    bhs.s   +
    move.w  #$80,d1
+
    cmpi.w  #$2BB0,x_pos(a0)
    blo.s   +
    move.w  #-$80,d1
+
    bclr    #0,render_flags(a0)
    tst.w   d1
    bmi.s   +
    bset    #0,render_flags(a0)
+
    move.w  d1,x_vel(a0)
    bra.s   +
; ===========================================================================
;loc_32A56
Obj53_ClearBossCollision:
    cmpi.b  #2,collision_property(a0)
    beq.s   +
    move.b  #0,collision_flags(a1)
+
    bsr.w   Obj53_OrbitBoss
    bsr.w   Obj53_SetAnimPriority
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_32A70
Obj53_OrbitBoss:
    move.b  objoff_29(a0),d0
    jsr (CalcSine).l
    move.w  d0,d3
    moveq   #0,d1
    move.b  objoff_33(a1),d1
    muls.w  d1,d0
    move.w  d0,d5
    move.w  d0,d4
    move.b  objoff_39(a1),d2
    tst.b   objoff_3A(a1)
    beq.s   +
    move.w  #$10,d2
+
    muls.w  d3,d2
    move.w  objoff_38(a0),d6
    move.b  objoff_28(a0),d0
    jsr (CalcSine).l
    muls.w  d0,d5
    swap    d5
    add.w   d6,d5
    move.w  d5,x_pos(a0)
    muls.w  d1,d4
    swap    d4
    move.w  d4,objoff_30(a0)
    move.w  objoff_2A(a0),d6
    move.b  objoff_3B(a0),d0
    tst.b   objoff_3A(a1)
    beq.s   +
    move.b  objoff_3C(a0),d0
+
    jsr (CalcSine).l
    muls.w  d0,d2
    swap    d2
    add.w   d6,d2
    move.w  d2,y_pos(a0)
    addq.b  #4,objoff_28(a0)
    tst.b   objoff_3A(a1)
    bne.s   +
    addq.b  #8,objoff_3B(a0)
    rts
; ===========================================================================
+
    cmpi.b  #-1,objoff_3A(a1)
    beq.s   ++
    cmpi.b  #$80,objoff_3A(a1)
    bne.s   +
    subq.b  #2,objoff_3C(a0)
    bpl.s   return_32B18
    clr.b   objoff_3C(a0)
+
    move.b  #0,objoff_3A(a1)
    rts
; ===========================================================================
+
    cmpi.b  #$40,objoff_3C(a0)
    bhs.s   return_32B18
    addq.b  #2,objoff_3C(a0)
 
return_32B18:
    rts
; ===========================================================================
;loc_32B1A
Obj53_SetAnimPriority:
    move.w  objoff_30(a0),d0
    bmi.s   ++
    cmpi.w  #$C,d0
    blt.s   +
    move.b  #3,mapping_frame(a0)
    move.b  #1,priority(a0)
    rts
; ===========================================================================
+
    move.b  #4,mapping_frame(a0)
    move.b  #2,priority(a0)
    rts
; ===========================================================================
+
    cmpi.w  #-$C,d0
    blt.s   +
    move.b  #4,mapping_frame(a0)
    move.b  #6,priority(a0)
    rts
; ===========================================================================
+
    move.b  #5,mapping_frame(a0)
    move.b  #7,priority(a0)
    rts
; ===========================================================================
;loc_32B64
Obj53_BreakAway:
    tst.b   objoff_32(a0)
    bmi.s   +
    subq.b  #1,objoff_32(a0)
    bpl.s   +
    move.b  #$DA,collision_flags(a0)
+
    jsrto   (ObjectMoveAndFall).l, JmpTo6_ObjectMoveAndFall
    subi.w  #$20,y_vel(a0)
    cmpi.w  #$180,y_vel(a0)
    blt.s   +
    move.w  #$180,y_vel(a0)
+
    cmpi.w  #$4AC,y_pos(a0)
    blo.s   Obj53_Animate
    move.w  #$4AC,y_pos(a0)
    move.w  #$4AC,objoff_2E(a0)
    move.b  #1,objoff_2C(a0)
    addq.b  #2,routine(a0)
    bsr.w   Obj53_FaceLeader
;loc_32BB0
Obj53_Animate:
    bsr.w   +
    lea (Ani_obj53).l,a1
    jsrto   (AnimateSprite).l, JmpTo21_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
+
    cmpi.b  #-2,collision_property(a0)
    bgt.s   +       ; rts
    move.b  #$14,mapping_frame(a0)
    move.b  #6,anim(a0)
    addq.b  #2,routine(a0)
+
    rts
; ===========================================================================
;loc_32BDC
Obj53_BounceAround:
    tst.b   objoff_32(a0)
    bmi.s   +
    subq.b  #1,objoff_32(a0)
    bpl.s   +
    move.b  #$DA,collision_flags(a0)
+
    bsr.w   Obj53_CheckPlayerHit
    cmpi.b  #$B,mapping_frame(a0)
    bne.s   Obj53_Animate
    move.b  objoff_2C(a0),d0
    jsr (CalcSine).l
    neg.w   d0
    asr.w   #2,d0
    add.w   objoff_2E(a0),d0
    cmpi.w  #$4AC,d0
    bhs.s   ++
    move.w  d0,y_pos(a0)
    addq.b  #1,objoff_2C(a0)
    btst    #0,objoff_2C(a0)
    beq.w   JmpTo40_DisplaySprite
    moveq   #-1,d0
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
+
    add.w   d0,x_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
+
    move.w  #$4AC,y_pos(a0)
    bsr.w   Obj53_FaceLeader
    move.b  #1,objoff_2C(a0)
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_32C4C
Obj53_FaceLeader:
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    bpl.s   +
    bclr    #0,render_flags(a0)
    rts
; ===========================================================================
+
    bset    #0,render_flags(a0)
    rts
; ===========================================================================
;loc_32C66
Obj53_CheckPlayerHit:
    cmpi.b  #4,(MainCharacter+routine).w
    beq.s   +
    cmpi.b  #4,(Sidekick+routine).w
    bne.s   ++
+
    move.b  #$14,mapping_frame(a0)
    move.b  #6,anim(a0)
+
    cmpi.b  #-2,collision_property(a0)
    bgt.s   +
    move.b  #$14,mapping_frame(a0)
    move.b  #6,anim(a0)
+
    rts
; ===========================================================================
;loc_32C98
Obj53_Burst:
    move.b  #SndID_BossExplosion,d0
    jsrto   (PlaySound).l, JmpTo10_PlaySound
    movea.l objoff_34(a0),a1 ; a1=object
    subi_.b #1,objoff_2C(a1)
 
    if removeJmpTos
JmpTo61_DeleteObject 
    endif
 
    jmpto   (DeleteObject).l, JmpTo61_DeleteObject
; ===========================================================================
;loc_32CAE
Obj54_Laser:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_32CBC(pc,d0.w),d0
    jmp off_32CBC(pc,d0.w)
; ===========================================================================
off_32CBC:  offsetTable
        offsetTableEntry.w Obj54_Laser_Init ; 0
        offsetTableEntry.w Obj54_Laser_Main ; 2
; ===========================================================================
;loc_32CC0
Obj54_Laser_Init:
    move.l  #Obj54_MapUnc_32DC6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_MTZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #5,priority(a0)
    move.b  #$12,mapping_frame(a0)
    addq.b  #2,routine_secondary(a0)    ; => Obj54_Laser_Main
    movea.l objoff_34(a0),a1 ; a1=object
    move.b  #$50,width_pixels(a0)
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    addi_.w #7,y_pos(a0)
    subi_.w #4,x_pos(a0)
    move.w  #-$400,d0
    btst    #0,render_flags(a1)
    beq.s   +
    neg.w   d0
    addi_.w #8,x_pos(a0)
+
    move.w  d0,x_vel(a0)
    move.b  #$99,collision_flags(a0)
    move.b  #SndID_LaserBurst,d0
    jsrto   (PlaySound).l, JmpTo10_PlaySound
;loc_32D2C
Obj54_Laser_Main:
    jsrto   (ObjectMove).l, JmpTo24_ObjectMove
    cmpi.w  #$2AB0,x_pos(a0)
    blo.w   JmpTo61_DeleteObject
    cmpi.w  #$2BF0,x_pos(a0)
    bhs.w   JmpTo61_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
;loc_32D48
Obj54_LaserShooter:
    movea.l objoff_34(a0),a1 ; a1=object
    cmpi.b  #ObjID_MTZBoss,id(a1)
    bne.w   JmpTo61_DeleteObject
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    bclr    #0,render_flags(a0)
    btst    #0,render_flags(a1)
    beq.w   JmpTo40_DisplaySprite
    bset    #0,render_flags(a0)
 
    if removeJmpTos
JmpTo40_DisplaySprite 
    endif
 
    jmpto   (DisplaySprite).l, JmpTo40_DisplaySprite
; ===========================================================================
; animation script
; off_32D7A:
Ani_obj53:  offsetTable
        offsetTableEntry.w byte_32D8A   ; 0
        offsetTableEntry.w byte_32D8D   ; 1
        offsetTableEntry.w byte_32D91   ; 2
        offsetTableEntry.w byte_32DA6   ; 3
        offsetTableEntry.w byte_32DAA   ; 4
        offsetTableEntry.w byte_32DB5   ; 5
        offsetTableEntry.w byte_32DC0   ; 6
        offsetTableEntry.w byte_32DC3   ; 7
byte_32D8A: dc.b  $F,  2,$FF
    rev02even
byte_32D8D: dc.b   1,  0,  1,$FF
    rev02even
byte_32D91: dc.b   3,  5,  5,  5,  5,  5,  5,  5,  5,  6,  7,  6,  7,  6,  7,  8
        dc.b   9, $A, $B,$FE,  1; 16
    rev02even
byte_32DA6: dc.b   7, $C, $D,$FF
    rev02even
byte_32DAA: dc.b   7, $E, $F, $E, $F, $E, $F, $E, $F,$FD,  3
    rev02even
byte_32DB5: dc.b   7,$10,$10,$10,$10,$10,$10,$10,$10,$FD,  3
    rev02even
byte_32DC0: dc.b   1,$14,$FC
    rev02even
byte_32DC3: dc.b   7,$11,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj54_MapUnc_32DC6: BINCLUDE "mappings/sprite/obj54.bin"
 
    if ~~removeJmpTos
    align 4
    endif
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo40_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo61_DeleteObject 
    jmp (DeleteObject).l
JmpTo17_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo10_PlaySound 
    jmp (PlaySound).l
JmpTo21_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo11_LoadPLC 
    jmp (LoadPLC).l
JmpTo8_AddPoints 
    jmp (AddPoints).l
JmpTo7_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo7_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
JmpTo6_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
; loc_32F88:
JmpTo24_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 55 - OOZ boss
; ----------------------------------------------------------------------------
; OST Variables:
Obj55_status            = objoff_2A ; bitfield
Obj55_anim_frame_duration   = objoff_2C ; number of frames the laser shooter displays its shooting frame
Obj55_shot_count        = objoff_38 ; number of lasers the shooter fires during its attack phase
Obj55_laser_pos         = objoff_3E ; bitfield, each of the first four bits stands for one of the possible y positions a laser can be fired from
 
Obj55_Wave_delay    = objoff_32 ; time before the next part of the wave is created
Obj55_Wave_parent   = objoff_34 ; pointer to main vehicle
Obj55_Wave_count    = objoff_36 ; number of waves to make
 
; Sprite_32F90:
Obj55:
    moveq   #0,d0
    move.b  boss_subtype(a0),d0
    move.w  Obj55_Index(pc,d0.w),d1
    jmp Obj55_Index(pc,d1.w)
; ===========================================================================
; off_32F9E:
Obj55_Index:    offsetTable
        offsetTableEntry.w Obj55_Init       ; 0 - Init
        offsetTableEntry.w Obj55_Main       ; 2 - Main Vehicle
        offsetTableEntry.w Obj55_LaserShooter   ; 4 - Laser Shooter
        offsetTableEntry.w Obj55_SpikeChain ; 6 - Spiked Chain
        offsetTableEntry.w Obj55_Laser      ; 8 - Laser
; ===========================================================================
; loc_32FA8:
Obj55_Init:
    move.l  #Obj55_MapUnc_33756,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #3,priority(a0)
    bset    #6,render_flags(a0) ; object consists of multiple sprites
    move.b  #0,mainspr_childsprites(a0)
    addq.b  #2,boss_subtype(a0) ; => Obj55_Main
    move.b  #$F,collision_flags(a0)
    move.b  #8,boss_hitcount2(a0)
    move.b  #$40,mainspr_width(a0)
    rts
; ===========================================================================
; loc_32FE6:
Obj55_Main:
    moveq   #0,d0
    move.b  boss_routine(a0),d0
    move.w  Obj55_Main_Index(pc,d0.w),d1
    jmp Obj55_Main_Index(pc,d1.w)
; ===========================================================================
; off_32FF4:
Obj55_Main_Index:   offsetTable
        offsetTableEntry.w Obj55_Main_Init  ; 0 - boss' initial state
        offsetTableEntry.w Obj55_Main_Surface   ; 2 - moving up
        offsetTableEntry.w Obj55_Main_Wait  ; 4 - stay in place for a while
        offsetTableEntry.w Obj55_Main_Dive  ; 6 - moving down
        offsetTableEntry.w Obj55_Main_Defeated  ; 8 - boss defeated and escaping
; ===========================================================================
; loc_32FFE:
Obj55_Main_Init:
    move.w  #$2940,(Boss_X_pos).w
    bclr    #0,render_flags(a0) ; face right
    move.w  (MainCharacter+x_pos).w,d1
    cmpi.w  #$293A,d1   ; is player on the left side of the arena?
    bhs.s   +       ; if not, branch
    bchg    #0,render_flags(a0) ; face left
+
    move.w  #$2D0,y_pos(a0)
    move.w  #$2D0,(Boss_Y_pos).w
    move.b  #8,mainspr_mapframe(a0)
    move.b  #1,mainspr_childsprites(a0)
    addq.b  #2,boss_routine(a0) ; => Obj55_Main_Surface
    move.w  #-$80,(Boss_Y_vel).w
    move.b  #$F,collision_flags(a0)
    move.w  x_pos(a0),sub2_x_pos(a0)
    move.w  y_pos(a0),sub2_y_pos(a0)
    clr.b   boss_sine_count(a0)
    clr.b   Obj55_status(a0)
    move.b  #8,sub2_mapframe(a0)
    lea (Boss_AnimationArray).w,a2
    move.b  #5,(a2)+
    move.b  #0,(a2)+
    move.b  #1,(a2)+
    move.b  #0,(a2)
    move.b  #0,(Boss_CollisionRoutine).w
    rts
; ===========================================================================
; loc_33078:
Obj55_Main_Surface:
    bsr.w   Boss_MoveObject
    move.w  (Boss_X_pos).w,x_pos(a0)
    bsr.w   Obj55_HoverPos
    cmpi.w  #$290,(Boss_Y_pos).w    ; has boss reached its target position?
    bhs.w   Obj55_Main_End      ; if not, branch
    move.w  #$290,(Boss_Y_pos).w
    addq.b  #2,boss_routine(a0) ; => Obj55_Main_Wait
    move.w  #$A8,(Boss_Countdown).w
    btst    #7,Obj55_status(a0) ; was boss hit?
    bne.w   Obj55_Main_End      ; if yes, branch
    lea (Boss_AnimationArray).w,a2
    move.b  #$10,(a2)+
    move.b  #0,(a2)
    bra.w   Obj55_Main_End
; ===========================================================================
; loc_330BA:
Obj55_Main_Wait:
    btst    #7,Obj55_status(a0) ; was boss hit?
    bne.s   +           ; if yes, branch
    bsr.w   Obj55_HoverPos
    subi_.w #1,(Boss_Countdown).w   ; hover in place for a while
    bpl.w   Obj55_Main_End
    lea (Boss_AnimationArray).w,a2
    move.b  #5,(a2)+
    move.b  #0,(a2)
+
    addq.b  #2,boss_routine(a0) ; => Obj55_Main_Dive
    move.w  #-$40,(Boss_Y_vel).w    ; bob up a little before diving
    bra.w   Obj55_Main_End
; ===========================================================================
; does the hovering effect
; loc_330EA:
Obj55_HoverPos:
    move.b  boss_sine_count(a0),d0
    jsr (CalcSine).l
    asr.w   #7,d1
    add.w   (Boss_Y_pos).w,d1
    move.w  d1,y_pos(a0)
    addq.b  #4,boss_sine_count(a0)
    rts
; ===========================================================================
; loc_33104:
Obj55_Main_Dive:
    bsr.w   Boss_MoveObject
    move.w  (Boss_Y_pos).w,y_pos(a0)
    move.w  (Boss_X_pos).w,x_pos(a0)
    btst    #6,Obj55_status(a0) ; is boss done rising?
    bne.s   Obj55_Main_Dive_Part2   ; if yes, branch
    cmpi.w  #$28C,(Boss_Y_pos).w    ; has boss reached initial destination (rising before diving)?
    bhs.w   Obj55_Main_End      ; if not, branch
    move.w  #$28C,(Boss_Y_pos).w
    move.w  #$80,(Boss_Y_vel).w
    ori.b   #$40,Obj55_status(a0)   ; set diving bit
    bra.w   Obj55_Main_End
; ===========================================================================
; loc_3313C:
Obj55_Main_Dive_Part2:
    cmpi.w  #$2D0,(Boss_Y_pos).w    ; has boss reached its target position?
    blo.s   Obj55_Main_End      ; if yes, branch
    move.w  #$2D0,(Boss_Y_pos).w
    clr.b   boss_routine(a0)
    addq.b  #2,boss_subtype(a0) ; => Obj55_LaserShooter
    btst    #7,Obj55_status(a0) ; was boss hit?
    beq.s   Obj55_Main_End      ; if not, branch
    addq.b  #2,boss_subtype(a0) ; => Obj55_SpikeChain
 
; loc_3315E:
Obj55_Main_End:
    bsr.w   Obj55_HandleHits
    lea (Ani_obj55).l,a1
    bsr.w   AnimateBoss
    bsr.w   Obj55_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; loc_33174:
Obj55_HandleHits:
    bsr.w   Boss_HandleHits
    cmpi.b  #$1F,boss_invulnerable_time(a0)
    bne.s   return_33192
    lea (Boss_AnimationArray).w,a1
    andi.b  #$F0,(a1)
    ori.b   #3,(a1)
    ori.b   #$80,Obj55_status(a0)   ; set boss hit bit
 
return_33192:
    rts
; ===========================================================================
; loc_33194:
Obj55_AlignSprites:
    move.w  x_pos(a0),d0
    move.w  y_pos(a0),d1
    move.w  d0,sub2_x_pos(a0)
    move.w  d1,sub2_y_pos(a0)
    rts
; ===========================================================================
; loc_331A6:
Obj55_Main_Defeated:
    clr.w   (Normal_palette_line2+2).w  ; set color to black
    subq.w  #1,(Boss_Countdown).w       ; wait for a while
    bmi.s   Obj55_Main_Defeated_Part2   ; branch, if wait is over
    cmpi.w  #$1E,(Boss_Countdown).w     ; has boss waited for a certain ammount of time?
    bhs.s   Obj55_Explode           ; if not, branch
    move.b  #$B,mainspr_mapframe(a0)    ; use defeated animation
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; loc_331C2:
Obj55_Explode:
    bsr.w   Boss_LoadExplosion
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; loc_331CA:
Obj55_Main_Defeated_Part2:
    tst.b   (Boss_defeated_flag).w  ; has boss been defeated?
    bne.s   Obj55_ReleaseCamera ; if yes, branch
    jsrto   (PlayLevelMusic).l, JmpTo8_PlayLevelMusic
    jsrto   (LoadPLC_AnimalExplosion).l, JmpTo8_LoadPLC_AnimalExplosion
    move.b  #1,(Boss_defeated_flag).w
 
; loc_331DE:
Obj55_ReleaseCamera:
    cmpi.w  #$2A20,(Camera_Max_X_pos).w ; has camera reached its destination?
    bhs.s   Obj55_ChkDelete         ; if yes, branch
    addq.w  #2,(Camera_Max_X_pos).w     ; else, move camera some more
    bra.s   Obj55_Defeated_Sink
; ===========================================================================
; loc_331EC:
Obj55_ChkDelete:
    move.w  #$2A20,(Camera_Max_X_pos).w
    cmpi.w  #$2D0,y_pos(a0)         ; has boss reached its target position?
    bhs.s   BranchTo_JmpTo62_DeleteObject   ; if yes, branch
 
; loc_331FA:
Obj55_Defeated_Sink:
    addi_.w #1,y_pos(a0)
    bsr.s   Obj55_AlignSprites
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
    if removeJmpTos
JmpTo62_DeleteObject 
    endif
 
BranchTo_JmpTo62_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo62_DeleteObject
; ===========================================================================
; loc_3320A:
Obj55_LaserShooter:
    moveq   #0,d0
    move.b  boss_routine(a0),d0
    move.w  Obj55_LaserShooter_Index(pc,d0.w),d1
    jmp Obj55_LaserShooter_Index(pc,d1.w)
; ===========================================================================
; off_33218:
Obj55_LaserShooter_Index:   offsetTable
        offsetTableEntry.w Obj55_LaserShooter_Init      ; 0 - laser shooter's initial state
        offsetTableEntry.w Obj55_LaserShooter_Rise      ; 2 - moving up
        offsetTableEntry.w Obj55_LaserShooter_ChooseTarget  ; 4 - stay in place for a while
        offsetTableEntry.w Obj55_LaserShooter_Aim       ; 6 - move towards target and shoot
        offsetTableEntry.w Obj55_LaserShooter_Lower     ; 8 - moving down
; ===========================================================================
; loc_33222:
Obj55_LaserShooter_Init:
    clr.w   (Normal_palette_line2+2).w  ; reset palette flash
    move.w  #$2940,(Boss_X_pos).w
    bclr    #0,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d1
    cmpi.w  #$293A,d1       ; is player left from center?
    blo.s   +           ; if yes, branch
    bchg    #0,render_flags(a0)
+
    move.w  #$2B0,(Boss_Y_pos).w
    move.w  #$2B0,y_pos(a0)
    move.b  #2,boss_routine(a0) ; => Obj55_LaserShooter_Rise
    move.b  #$8A,collision_flags(a0)
    move.b  #5,mainspr_mapframe(a0)
    moveq   #7,d0
    moveq   #7,d2
    moveq   #0,d4
    move.w  (Boss_Y_pos).w,d5
 
-   ; initialize chain
    addi.w  #$F,d5
    move.b  d0,sub2_mapframe(a0,d4.w)
    move.w  d5,sub2_y_pos(a0,d4.w)
    addq.w  #next_subspr,d4
    dbf d2,-
 
    move.b  #8,mainspr_childsprites(a0)
    move.w  #-$80,(Boss_Y_vel).w
    move.b  #0,Obj55_laser_pos(a0)
    move.b  #1,(Boss_CollisionRoutine).w
    rts
; ===========================================================================
; loc_33296:
Obj55_LaserShooter_Rise:
    bsr.w   Boss_MoveObject
    cmpi.w  #$240,(Boss_Y_pos).w    ; has laser shooter reached its destination?
    bhs.w   Obj55_LaserShooter_End  ; if not, branch
    move.w  #$240,(Boss_Y_pos).w
    move.w  #0,(Boss_Y_vel).w
    addi_.b #2,boss_routine(a0) ; => Obj55_LaserShooter_ChooseTarget
    move.w  #$80,(Boss_Countdown).w
    move.b  #3,Obj55_shot_count(a0) ; prepare to shoot 3 lasers
    bra.w   Obj55_LaserShooter_End
; ===========================================================================
; loc_332C6:
Obj55_LaserShooter_ChooseTarget:
    subq.b  #1,Obj55_anim_frame_duration(a0)    ; is firing animation finished?
    bne.s   +                   ; if not, branch
    move.b  #5,mainspr_mapframe(a0) ; reset animation frame to not firing
+
    subi_.w #1,(Boss_Countdown).w   ; wait for a while
    bne.w   Obj55_LaserShooter_End  ; branch, as long as wait isn't over
    subi_.b #1,Obj55_shot_count(a0)     ; decrement number of shots left
    bmi.s   Obj55_LaserShooter_DoneShooting ; branch, if no shots left
    jsrto   (RandomNumber).l, JmpTo5_RandomNumber
 
-   ; find first valid firing position
    addq.b  #1,d0           ; next position
    andi.w  #3,d0           ; limit to 4 possible values
    btst    d0,Obj55_laser_pos(a0)  ; was a laser already shot in this position?
    bne.s   -           ; if yes, branch
 
    bset    d0,Obj55_laser_pos(a0)  ; set posion as used
    add.w   d0,d0
    move.w  Obj55_LaserTargets(pc,d0.w),(Boss_Countdown).w  ; set target positon
    addq.b  #2,boss_routine(a0) ; => Obj55_LaserShooter_Aim
    bsr.w   Obj55_MoveTowardTarget
    bra.w   Obj55_LaserShooter_End
; ===========================================================================
; loc_3330C:
Obj55_LaserShooter_DoneShooting:
    move.w  #$80,(Boss_Y_vel).w
    move.b  #8,boss_routine(a0) ; => Obj55_LaserShooter_Lower
    bra.w   Obj55_LaserShooter_End
; ===========================================================================
; word_3331C:
Obj55_LaserTargets:
    dc.w  $238  ; 0
    dc.w  $230  ; 2
    dc.w  $240  ; 4
    dc.w  $25F  ; 6
; ===========================================================================
; loc_33324:
Obj55_LaserShooter_Aim:
    bsr.w   Boss_MoveObject
    move.w  (Boss_Countdown).w,d0
    tst.w   (Boss_Y_vel).w          ; is laser shooter moving up?
    bmi.s   Obj55_LaserShooter_Aim_MovingUp ; if yes, branch
    cmp.w   (Boss_Y_pos).w,d0   ; has laser shooter reached its destination?
    blo.s   Obj55_LaserShooter_Fire ; if yes, branch
    bra.w   Obj55_LaserShooter_End
; ===========================================================================
; loc_3333C:
Obj55_LaserShooter_Aim_MovingUp:
    cmp.w   (Boss_Y_pos).w,d0   ; has laser shooter reached its destination?
    blo.s   Obj55_LaserShooter_End  ; if not, branch
 
; loc_33342:
Obj55_LaserShooter_Fire:
    move.w  #0,(Boss_Y_vel).w
    move.b  #8,Obj55_anim_frame_duration(a0)
    move.b  #6,mainspr_mapframe(a0) ; use firing frame
    jsrto   (SingleObjLoad).l, JmpTo18_SingleObjLoad
    bne.w   Obj55_LaserShooter_End
    move.b  #ObjID_OOZBoss,id(a1) ; load obj55
    move.b  #8,boss_subtype(a1) ; => Obj55_Laser
    move.l  a0,Obj55_Wave_parent(a1)
    move.b  #SndID_LaserBurst,d0
    jsrto   (PlaySound).l, JmpTo11_PlaySound
    move.b  #4,boss_routine(a0) ; => Obj55_LaserShooter_ChooseTarget
    move.w  #$28,(Boss_Countdown).w
    move.w  #-$80,(Boss_Y_vel).w
    bra.w   Obj55_LaserShooter_End
; ===========================================================================
; loc_33388:
Obj55_LaserShooter_Lower:
    subq.b  #1,Obj55_anim_frame_duration(a0)    ; is firing animation finished?
    bne.s   +                   ; if not, branch
    move.b  #5,mainspr_mapframe(a0) ; reset animation frame to not firing
+
    bsr.w   Boss_MoveObject
    cmpi.w  #$2B0,(Boss_Y_pos).w    ; has laser shooter reached its destination?
    blo.s   Obj55_LaserShooter_End  ; if not, branch
    move.w  #$2B0,(Boss_Y_pos).w
    move.w  #0,(Boss_Y_vel).w
    move.b  #0,boss_routine(a0)
    move.b  #2,boss_subtype(a0) ; => Obj55_Main_Init
    rts
; ===========================================================================
; loc_333BA:
Obj55_LaserShooter_End:
    bsr.w   Obj55_LaserShooter_FacePlayer
    bsr.w   Obj55_LaserShooter_Wind
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; sets the laser shooter's y velocity so that it moves toward its target
; loc_333C6:
Obj55_MoveTowardTarget:
    move.w  (Boss_Countdown).w,d0
    sub.w   (Boss_Y_pos).w,d0
    bpl.s   Obj55_LaserShooter_MoveUp   ; branch, if laser shooter is below target
    move.w  #-$80,(Boss_Y_vel).w
    rts
; ===========================================================================
; loc_333D8:
Obj55_LaserShooter_MoveUp:
    move.w  #$80,(Boss_Y_vel).w
    rts
; ===========================================================================
; loc_333E0:
Obj55_LaserShooter_FacePlayer:
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    blt.s   Obj55_LaserShooter_FaceLeft ; branch, if player is to the left
    subi_.w #8,d0       ; allow an 8 pixel margin
    blt.s   return_333F6
    bset    #0,render_flags(a0)
 
return_333F6:
    rts
; ===========================================================================
; loc_333F8:
Obj55_LaserShooter_FaceLeft:
    addi_.w #8,d0       ; allow an 8 pixel margin
    bgt.s   return_333F6
    bclr    #0,render_flags(a0)
    rts
; ===========================================================================
; creates the twisting effect
; loc_33406:
Obj55_LaserShooter_Wind:
    move.w  (Boss_X_pos).w,d5
    move.w  (Boss_Y_pos).w,d6
    move.b  boss_sine_count(a0),d3
    move.b  d3,d0
    bsr.w   Obj55_LaserShooter_CalcSineRelative
    move.w  d1,x_pos(a0)
    move.w  d0,y_pos(a0)
    addi_.b #2,boss_sine_count(a0)
    moveq   #7,d2
    moveq   #0,d4
 
-   addi.w  #$F,d6
    subi.b  #$10,d3
    bsr.w   Obj55_LaserShooter_CalcSineRelative
    move.w  d1,sub2_x_pos(a0,d4.w)
    move.w  d0,sub2_y_pos(a0,d4.w)
    addq.w  #next_subspr,d4
    dbf d2,-
    rts
; ===========================================================================
; loc_33446:
Obj55_LaserShooter_CalcSineRelative:
    move.b  d3,d0
    jsrto   (CalcSine).l, JmpTo13_CalcSine
    asr.w   #4,d1
    add.w   d5,d1
    asr.w   #6,d0
    add.w   d6,d0
    rts
; ===========================================================================
; loc_33456:
Obj55_SpikeChain:
    moveq   #0,d0
    move.b  boss_routine(a0),d0
    move.w  Obj55_SpikeChain_Index(pc,d0.w),d1
    jmp Obj55_SpikeChain_Index(pc,d1.w)
; ===========================================================================
; off_33464:
Obj55_SpikeChain_Index: offsetTable
        offsetTableEntry.w Obj55_SpikeChain_Init    ; 0 - spiked chain's initial state
        offsetTableEntry.w Obj55_SpikeChain_Main    ; 2 - spiked chain moving at an arc
; ===========================================================================
; loc_33468:
Obj55_SpikeChain_Init:
    clr.w   (Normal_palette_line2+2).w  ; reset palette flash
    move.w  #$28C0,(Boss_X_pos).w
    bclr    #0,render_flags(a0)
    move.w  (MainCharacter+x_pos).w,d1
    cmpi.w  #$293A,d1   ; is player on the left side of the arena?
    blo.s   +       ; if yes, branch
    move.w  #$29C0,(Boss_X_pos).w
    bset    #0,render_flags(a0)
+
    move.w  #$2A0,(Boss_Y_pos).w
    move.b  #2,mainspr_mapframe(a0)
    move.b  #$8A,collision_flags(a0)
    addq.b  #2,boss_routine(a0) ; => Obj55_SpikeChain_Main
    move.b  #$80,mainspr_width(a0)
    clr.b   boss_sine_count(a0)
    moveq   #7,d0
    moveq   #7,d1
    moveq   #0,d2
 
-   move.b  d1,sub2_mapframe(a0,d2.w)
    addq.w  #next_subspr,d2
    dbf d0,-
 
    move.b  #8,mainspr_childsprites(a0)
    move.b  #2,(Boss_CollisionRoutine).w
    rts
; ===========================================================================
; loc_334CC:
Obj55_SpikeChain_Main:
    bsr.w   Obj55_SpikeChain_Move
    cmpi.b  #$FE,boss_sine_count(a0)    ; has chain reached a certain angle?
    blo.s   Obj55_SpikeChain_End        ; if not, branch
    move.b  #0,boss_routine(a0)
    move.b  #4,boss_subtype(a0) ; => Obj55_LaserShooter_Init
    rts
; ===========================================================================
; loc_334E6:
Obj55_SpikeChain_End:
    bsr.w   Obj55_SpikeChain_SetAnimFrame
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; loc_334EE:
Obj55_SpikeChain_Move:
    move.b  boss_sine_count(a0),d0
    addi.b  #$40,d0
    move.b  d0,d3
    bsr.w   Obj55_SpikeChain_Rotate
    move.w  d1,x_pos(a0)
    move.w  d0,y_pos(a0)
    addi_.b #1,boss_sine_count(a0)
    moveq   #7,d2
    moveq   #0,d4
 
-   subi_.b #6,d3
    bsr.w   Obj55_SpikeChain_Rotate
    move.w  d1,sub2_x_pos(a0,d4.w)
    move.w  d0,sub2_y_pos(a0,d4.w)
    addq.w  #next_subspr,d4
    dbf d2,-
    rts
; ===========================================================================
; loc_33526:
Obj55_SpikeChain_Rotate:
    move.b  d3,d0
    jsrto   (CalcSine).l, JmpTo13_CalcSine
    muls.w  #$68,d1
    asr.l   #8,d1
    btst    #0,render_flags(a0)
    bne.s   +
    neg.w   d1
+
    add.w   (Boss_X_pos).w,d1
    muls.w  #$68,d0
    asr.l   #8,d0
    add.w   (Boss_Y_pos).w,d0
    rts
; ===========================================================================
; loc_3354C:
Obj55_SpikeChain_SetAnimFrame:
    move.b  boss_sine_count(a0),d0
    moveq   #$15,d1
    cmpi.b  #$52,d0
    blo.s   +
    moveq   #3,d1
    cmpi.b  #$6B,d0
    blo.s   +
    moveq   #2,d1
    cmpi.b  #-$6E,d0
    blo.s   +
    moveq   #4,d1
+
    move.b  d1,mainspr_mapframe(a0)
    rts
; ===========================================================================
; loc_33570:
Obj55_Laser:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj55_Laser_Index(pc,d0.w),d0
    jmp Obj55_Laser_Index(pc,d0.w)
; ===========================================================================
; off_3357E:
Obj55_Laser_Index:  offsetTable
        offsetTableEntry.w Obj55_Laser_Init         ; 0 - Init
        offsetTableEntry.w Obj55_Laser_Main         ; 2 - Laser moving horizontally
        offsetTableEntry.w Obj55_Wave               ; 4 - Energy wave that moves along the ground
        offsetTableEntry.w BranchTo2_JmpTo62_DeleteObject   ; 6 - Delete (triggered by an animation)
; ===========================================================================
; loc_33586:
Obj55_Laser_Init:
    addq.b  #2,routine_secondary(a0)    ; => Obj55_Laser_Main
    move.l  #Obj55_MapUnc_33756,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZBoss,0,0),art_tile(a0)
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    movea.l Obj55_Wave_parent(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  #$C,mapping_frame(a0)
    move.w  #-$20,d0
    move.w  #-$400,x_vel(a0)
    btst    #0,render_flags(a1)
    beq.s   +
    neg.w   d0
    neg.w   x_vel(a0)
+
    add.w   d0,x_pos(a0)
    move.b  #$AF,collision_flags(a0)
    rts
; ===========================================================================
; loc_335DE:
Obj55_Laser_Main:
    bsr.w   Obj55_Laser_ChkGround
    jsrto   (ObjectMove).l, JmpTo25_ObjectMove
    cmpi.w  #$2870,x_pos(a0)    ; has laser moved off screen going left?
    blo.w   JmpTo62_DeleteObject    ; if yes, branch
    cmpi.w  #$2A10,x_pos(a0)    ; has laser moved off screen going right?
    bhs.w   JmpTo62_DeleteObject    ; if yes, branch
    jmpto   (DisplaySprite).l, JmpTo41_DisplaySprite
; ===========================================================================
; checks if laser hit the ground
; loc_335FE:
Obj55_Laser_ChkGround:
    cmpi.w  #$250,y_pos(a0)     ; is laser on ground level?
    blo.s   return_33626        ; if not, branch
    tst.w   x_vel(a0)           ; is laser moving left?
    bmi.w   Obj55_Laser_ChkGroundLeft   ; if yes, branch
    move.w  x_pos(a0),d0
    cmpi.w  #$2980,d0
    bhs.s   return_33626
    cmpi.w  #$297C,d0
    blo.w   return_33626
    move.w  #$2988,d1       ; wave's start position
    bra.s   Obj55_Laser_CreateWave
; ===========================================================================
 
return_33626:
    rts
; ===========================================================================
; loc_33628:
Obj55_Laser_ChkGroundLeft:
    move.w  x_pos(a0),d0
    cmpi.w  #$2900,d0
    blo.s   return_3363E
    cmpi.w  #$2904,d0
    bhs.s   return_3363E
    move.w  #$28F8,d1       ; wave's start position
    bra.s   Obj55_Laser_CreateWave
; ===========================================================================
 
return_3363E:
    rts
; ===========================================================================
; loc_33640:
Obj55_Laser_CreateWave:
    jsrto   (SingleObjLoad).l, JmpTo18_SingleObjLoad
    bne.s   return_336B0
    move.b  #ObjID_OOZBoss,id(a1) ; load obj55
    move.b  #8,boss_subtype(a1)
    move.b  #4,routine_secondary(a1)    ; => Obj55_Wave
    move.b  #$8B,collision_flags(a1)
    move.b  #2,anim(a1)
    move.b  #$D,mapping_frame(a1)
    move.w  #0,y_vel(a1)
    move.l  #Obj55_MapUnc_33756,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_OOZBoss,0,0),art_tile(a1)
    jsrto   (Adjust2PArtPointer).l, JmpTo63_Adjust2PArtPointer
    ori.b   #4,render_flags(a1)
    move.b  #2,priority(a1)
    move.w  #5,Obj55_Wave_delay(a1)
    move.b  #7,Obj55_Wave_count(a1)
    move.w  x_vel(a0),x_vel(a1)
    move.w  d1,x_pos(a1)
    move.w  #$250,y_pos(a1)
    move.b  #SndID_LaserFloor,d0
    jsrto   (PlaySound).l, JmpTo11_PlaySound
 
return_336B0:
    rts
; ===========================================================================
; loc_336B2:
Obj55_Wave:
    subq.w  #1,Obj55_Wave_delay(a0)
    bpl.s   Obj55_Wave_End
    move.w  #$C7,Obj55_Wave_delay(a0)
    subq.b  #1,Obj55_Wave_count(a0)
    bmi.s   Obj55_Wave_End
    jsrto   (SingleObjLoad2).l, JmpTo24_SingleObjLoad2
    bne.s   Obj55_Wave_End
    moveq   #0,d0
 
    move.w  #bytesToLcnt(object_size),d1
 
-   move.l  (a0,d0.w),(a1,d0.w) ; make new object a copy of this one
    addq.w  #4,d0
    dbf d1,-
    if object_size&3
    move.w  (a0,d0.w),(a1,d0.w) ; make new object a copy of this one
    endif
 
    move.w  #5,Obj55_Wave_delay(a1)
    move.w  #$200,anim(a1)
    move.w  #$10,d0     ; place new wave object 16 pixels next to current one
    tst.w   x_vel(a1)   ; is object going left?
    bpl.s   +       ; if not, branch
    neg.w   d0      ; flip offset
+
    add.w   d0,x_pos(a1)    ; set position
    move.b  #SndID_LaserFloor,d0
    jsrto   (PlaySound).l, JmpTo11_PlaySound
 
Obj55_Wave_End:
    lea (Ani_obj55).l,a1
    jsrto   (AnimateSprite).l, JmpTo22_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo38_MarkObjGone
; ===========================================================================
 
BranchTo2_JmpTo62_DeleteObject 
    bra.w   JmpTo62_DeleteObject
; ===========================================================================
; animation script
; off_33712:
Ani_obj55:  offsetTable
        offsetTableEntry.w byte_3371E
        offsetTableEntry.w byte_33738
        offsetTableEntry.w byte_3373B
        offsetTableEntry.w byte_3374D
        offsetTableEntry.w byte_33750
        offsetTableEntry.w byte_33753
byte_3371E:
    dc.b   9,  8,  8,  8,  8,  9,  9,  9,  9,  8,  8,  8,  8,  9,  9,  9
    dc.b   9,  8,  8,  8,  8,  9,  9,  9,  9,$FF; 16
    rev02even
byte_33738:
    dc.b  $F,  1,$FF
    rev02even
byte_3373B:
    dc.b   1, $D,$11, $E,$12, $F,$13,$10,$14,$14,$10,$13, $F,$12, $E,$11
    dc.b  $D,$FA    ; 16
    rev02even
byte_3374D:
    dc.b  $F, $A,$FF
    rev02even
byte_33750:
    dc.b  $F, $B,$FF
    rev02even
byte_33753:
    dc.b  $F,  8,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj55_MapUnc_33756: BINCLUDE "mappings/sprite/obj55.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo41_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo62_DeleteObject 
    jmp (DeleteObject).l
JmpTo18_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo38_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo11_PlaySound 
    jmp (PlaySound).l
JmpTo24_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo22_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo5_RandomNumber 
    jmp (RandomNumber).l
JmpTo63_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo13_CalcSine 
    jmp (CalcSine).l
JmpTo8_PlayLevelMusic 
    jmp (PlayLevelMusic).l
JmpTo8_LoadPLC_AnimalExplosion 
    jmp (LoadPLC_AnimalExplosion).l
; loc_338E4:
JmpTo25_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 09 - Sonic in Special Stage
; ----------------------------------------------------------------------------
; Sprite_338EC:
Obj09:
    bsr.w   loc_33908
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj09_Index(pc,d0.w),d1
    jmp Obj09_Index(pc,d1.w)
; ===========================================================================
; off_338FE:
Obj09_Index:    offsetTable
        offsetTableEntry.w Obj09_Init   ; 0
        offsetTableEntry.w Obj09_MdNormal   ; 2
        offsetTableEntry.w Obj09_MdJump ; 4
        offsetTableEntry.w Obj09_Index  ; 6 - invalid
        offsetTableEntry.w Obj09_MdAir  ; 8
; ===========================================================================
 
loc_33908:
    lea (SS_Ctrl_Record_Buf_End).w,a1
 
    moveq   #(SS_Ctrl_Record_Buf_End-SS_Ctrl_Record_Buf)/2-2,d0
-   move.w  -4(a1),-(a1)
    dbf d0,-
 
    move.w  (Ctrl_1_Logical).w,-(a1)
    rts
; ===========================================================================
; loc_3391C:
Obj09_Init:
    move.b  #2,routine(a0)
    moveq   #0,d0
    move.l  d0,ss_x_pos(a0)
    move.w  #$80,d1
    move.w  d1,ss_y_pos(a0)
    move.w  d0,ss_y_sub(a0)
    add.w   (SS_Offset_X).w,d0
    move.w  d0,x_pos(a0)
    add.w   (SS_Offset_Y).w,d1
    move.w  d1,y_pos(a0)
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.l  #Obj09_MapUnc_34212,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialSonic,1,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.w  #$6E,ss_z_pos(a0)
    clr.b   (SS_Swap_Positions_Flag).w
    move.w  #$400,ss_init_flip_timer(a0)
    move.b  #$40,angle(a0)
    move.b  #1,(Sonic_LastLoadedDPLC).w
    clr.b   ss_slide_timer(a0)
    bclr    #6,status(a0)
    clr.b   collision_property(a0)
    clr.b   ss_dplc_timer(a0)
    movea.l #SpecialStageShadow_Sonic,a1
    move.b  #ObjID_SSShadow,id(a1) ; load obj63 (shadow) at $FFFFB140
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$18,y_pos(a1)
    move.l  #Obj63_MapUnc_34492,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.l  a0,ss_parent(a1)
    bra.w   LoadSSSonicDynPLC
; ===========================================================================
 
Obj09_MdNormal:
    tst.b   routine_secondary(a0)
    bne.s   Obj09_Hurt
    lea (Ctrl_1_Held_Logical).w,a2
    bsr.w   SSPlayer_Move
    bsr.w   SSPlayer_Traction
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSObjectMove
    bsr.w   SSAnglePos
    bsr.w   SSSonic_Jump
    bsr.w   SSPlayer_SetAnimation
    lea (off_341E4).l,a1
    bsr.w   SSPlayer_Animate
    bsr.w   SSPlayer_Collision
    bra.w   LoadSSSonicDynPLC
; ===========================================================================
 
Obj09_Hurt:
    bsr.w   SSHurt_Animation
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSObjectMove
    bsr.w   SSAnglePos
    bra.w   LoadSSSonicDynPLC
; ===========================================================================
 
SSHurt_Animation:
    moveq   #0,d0
    move.b  ss_hurt_timer(a0),d0
    addi_.b #8,d0
    move.b  d0,ss_hurt_timer(a0)
    bne.s   +
    move.b  #0,routine_secondary(a0)
    move.b  #$1E,ss_dplc_timer(a0)
+
    add.b   angle(a0),d0
    andi.b  #$FC,render_flags(a0)
    subi.b  #$10,d0
    lsr.b   #5,d0
    add.w   d0,d0
    move.b  byte_33A92(pc,d0.w),mapping_frame(a0)
    move.b  byte_33A92+1(pc,d0.w),d0
    or.b    d0,render_flags(a0)
    move.b  ss_hurt_timer(a0),d0
    subi_.b #8,d0
    bne.s   return_33A90
    move.b  d0,collision_property(a0)
    cmpa.l  #MainCharacter,a0
    bne.s   +
    tst.w   (Ring_count).w
    beq.s   return_33A90
    bra.s   ++
; ===========================================================================
+
    tst.w   (Ring_count_2P).w
    beq.s   return_33A90
+
    jsrto   (SSSingleObjLoad).l, JmpTo_SSSingleObjLoad
    bne.s   return_33A90
    move.l  a0,ss_parent(a1)
    move.b  #ObjID_SSRingSpill,id(a1) ; load obj5B
 
return_33A90:
    rts
; ===========================================================================
byte_33A92:
    dc.b   4,  1
    dc.b   0,  0    ; 2
    dc.b   4,  0    ; 4
    dc.b  $C,  0    ; 6
    dc.b   4,  2    ; 8
    dc.b   0,  2    ; 10
    dc.b   4,  3    ; 12
    dc.b  $C,  1    ; 14
dword_33AA2:
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($000)     ; Sonic in upright position, $58 tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($058)     ; Sonic in diagonal position, $CC tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($124)     ; Sonic in horizontal position, $4D tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($171)     ; Sonic in ball form, $12 tiles
; ===========================================================================
 
LoadSSSonicDynPLC:
    move.b  ss_dplc_timer(a0),d0
    beq.s   +
    subq.b  #1,d0
    move.b  d0,ss_dplc_timer(a0)
    andi.b  #1,d0
    beq.s   +
    rts
; ===========================================================================
+
    jsrto   (DisplaySprite).l, JmpTo42_DisplaySprite
    lea dword_33AA2(pc),a3
    lea (Sonic_LastLoadedDPLC).w,a4
    move.w  #tiles_to_bytes(ArtTile_ArtNem_SpecialSonic),d4
    moveq   #0,d1
 
LoadSSPlayerDynPLC:
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    cmp.b   (a4),d0
    beq.s   return_33B3E
    move.b  d0,(a4)
    moveq   #0,d6
    cmpi.b  #4,d0
    blt.s   loc_33AFE
    addq.w  #4,d6
    cmpi.b  #$C,d0
    blt.s   loc_33AFE
    addq.w  #4,d6
    cmpi.b  #$10,d0
    blt.s   loc_33AFE
    addq.b  #4,d6
 
loc_33AFE:
    move.l  (a3,d6.w),d6
    add.w   d1,d0
    add.w   d0,d0
    lea (Obj09_MapRUnc_345FA).l,a2
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d5
    subq.w  #1,d5
    bmi.s   return_33B3E
 
SSPLC_ReadEntry:
    moveq   #0,d1
    move.w  (a2)+,d1
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.w   #1,d1
    add.l   d6,d1
    move.w  d4,d2
    add.w   d3,d4
    add.w   d3,d4
    jsr (QueueDMATransfer).l
    dbf d5,SSPLC_ReadEntry
 
return_33B3E:
    rts
; ===========================================================================
 
SSSonic_Jump:
    lea (Ctrl_1_Press_Logical).w,a2
 
SSPlayer_Jump:
    move.b  (a2),d0
    andi.b  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.w   return_33BAC
    move.w  #$780,d2
    moveq   #0,d0
    move.b  angle(a0),d0
    addi.b  #$80,d0
    jsr (CalcSine).l
    muls.w  d2,d1
    asr.l   #8,d1
    add.w   d1,x_vel(a0)
    muls.w  d2,d0
    asr.l   #7,d0
    add.w   d0,y_vel(a0)
    bset    #2,status(a0)
    move.b  #4,routine(a0)
    move.b  #3,anim(a0)
    moveq   #0,d0
    move.b  d0,anim_frame_duration(a0)
    move.b  d0,anim_frame(a0)
    move.b  d0,collision_property(a0)
    tst.b   (SS_2p_Flag).w
    bne.s   loc_33B9E
    tst.w   (Player_mode).w
    bne.s   loc_33BA2
 
loc_33B9E:
    not.b   (SS_Swap_Positions_Flag).w
 
loc_33BA2:
    move.w  #SndID_Jump,d0
    jsr (PlaySound).l
 
return_33BAC:
    rts
; ===========================================================================
 
Obj09_MdJump:
    lea (Ctrl_1_Held_Logical).w,a2
    bsr.w   SSPlayer_ChgJumpDir
    bsr.w   SSObjectMoveAndFall
    bsr.w   SSPlayer_JumpAngle
    bsr.w   SSPlayer_DoLevelCollision
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSAnglePos
    lea (off_341E4).l,a1
    bsr.w   SSPlayer_Animate
    bra.w   LoadSSSonicDynPLC
; ===========================================================================
 
Obj09_MdAir:
    lea (Ctrl_1_Held_Logical).w,a2
    bsr.w   SSPlayer_ChgJumpDir
    bsr.w   SSObjectMoveAndFall
    bsr.w   SSPlayer_JumpAngle
    bsr.w   SSPlayer_DoLevelCollision
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSAnglePos
    bsr.w   SSPlayer_SetAnimation
    lea (off_341E4).l,a1
    bsr.w   SSPlayer_Animate
    bra.w   LoadSSSonicDynPLC
; ===========================================================================
 
SSObjectMoveAndFall:
    move.l  ss_x_pos(a0),d2
    move.l  ss_y_pos(a0),d3
    move.w  x_vel(a0),d0
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d2
    move.w  y_vel(a0),d0
    addi.w  #$A8,y_vel(a0)  ; Apply gravity
    ext.l   d0
    asl.l   #8,d0
    add.l   d0,d3
    move.l  d2,ss_x_pos(a0)
    move.l  d3,ss_y_pos(a0)
    rts
; ===========================================================================
 
SSPlayer_ChgJumpDir:
    move.b  (a2),d0
    btst    #button_left,d0
    bne.s   +
    btst    #button_right,d0
    bne.w   ++
    rts
; ===========================================================================
+
    subi.w  #$40,x_vel(a0)
    rts
; ===========================================================================
+
    addi.w  #$40,x_vel(a0)
    rts
; ===========================================================================
 
SSPlayer_JumpAngle:
    moveq   #0,d2
    moveq   #0,d3
    move.w  ss_y_pos(a0),d2
    bmi.s   SSPlayer_JumpAngle_above_screen
    move.w  ss_x_pos(a0),d3
    bmi.s   +++
    cmp.w   d2,d3
    blo.s   ++
    bne.s   +
    tst.w   d3
    bne.s   +
    move.b  #$40,angle(a0)
    rts
; ===========================================================================
+
    lsl.l   #5,d2
    divu.w  d3,d2
    move.b  d2,angle(a0)
    rts
; ===========================================================================
+
    lsl.l   #5,d3
    divu.w  d2,d3
    subi.w  #$40,d3
    neg.w   d3
    move.b  d3,angle(a0)
    rts
; ===========================================================================
+
    neg.w   d3
    cmp.w   d2,d3
    bhs.s   +
    lsl.l   #5,d3
    divu.w  d2,d3
    addi.w  #$40,d3
    move.b  d3,angle(a0)
    rts
; ===========================================================================
+
    lsl.l   #5,d2
    divu.w  d3,d2
    subi.w  #$80,d2
    neg.w   d2
    move.b  d2,angle(a0)
    rts
; ===========================================================================
 
SSPlayer_JumpAngle_above_screen:
    neg.w   d2
    move.w  ss_x_pos(a0),d3
    bpl.s   ++
    neg.w   d3
    cmp.w   d2,d3
    blo.s   +
    lsl.l   #5,d2
    divu.w  d3,d2
    addi.w  #$80,d2
    move.b  d2,angle(a0)
    rts
; ===========================================================================
+
    lsl.l   #5,d3
    divu.w  d2,d3
    subi.w  #$C0,d3
    neg.w   d3
    move.b  d3,angle(a0)
    rts
; ===========================================================================
+
    cmp.w   d2,d3
    bhs.s   +
    lsl.l   #5,d3
    divu.w  d2,d3
    addi.w  #$C0,d3
    move.b  d3,angle(a0)
    rts
; ===========================================================================
+
    lsl.l   #5,d2
    divu.w  d3,d2
    subi.w  #$100,d2
    neg.w   d2
    move.b  d2,angle(a0)
    rts
; ===========================================================================
 
loc_33D02:
    moveq   #0,d6
    moveq   #0,d0
    move.w  ss_x_pos(a1),d0
    bpl.s   loc_33D10
    st  d6
    neg.w   d0
 
loc_33D10:
    lsl.l   #7,d0
    divu.w  ss_z_pos(a1),d0
    move.b  byte_33D32(pc,d0.w),d0
    tst.b   d6
    bne.s   loc_33D24
    subi.b  #$80,d0
    neg.b   d0
 
loc_33D24:
    tst.w   ss_y_pos(a1)
    bpl.s   loc_33D2C
    neg.b   d0
 
loc_33D2C:
    move.b  d0,angle(a0)
    rts
; ===========================================================================
byte_33D32:
    dc.b $40,$40,$40,$40,$41,$41,$41,$42,$42,$42,$43,$43,$43,$44,$44,$44
    dc.b $45,$45,$45,$46,$46,$46,$47,$47,$47,$48,$48,$48,$48,$49,$49,$49; 16
    dc.b $4A,$4A,$4A,$4B,$4B,$4B,$4C,$4C,$4C,$4D,$4D,$4D,$4E,$4E,$4E,$4F; 32
    dc.b $4F,$50,$50,$50,$51,$51,$51,$52,$52,$52,$53,$53,$53,$54,$54,$54; 48
    dc.b $55,$55,$56,$56,$56,$57,$57,$57,$58,$58,$59,$59,$59,$5A,$5A,$5B; 64
    dc.b $5B,$5B,$5C,$5C,$5D,$5D,$5E,$5E,$5E,$5F,$5F,$60,$60,$61,$61,$62; 80
    dc.b $62,$63,$63,$64,$64,$65,$65,$66,$66,$67,$67,$68,$68,$69,$6A,$6A; 96
    dc.b $6B,$6C,$6C,$6D,$6E,$6E,$6F,$70,$71,$72,$73,$74,$75,$77,$78,$7A; 112
    dc.b $80,  0    ; 128
; ===========================================================================
 
SSPlayer_DoLevelCollision:
    move.w  ss_y_pos(a0),d0
    ble.s   +
    muls.w  d0,d0
    move.w  ss_x_pos(a0),d1
    muls.w  d1,d1
    add.w   d1,d0
    move.w  ss_z_pos(a0),d1
    mulu.w  d1,d1
    cmp.l   d1,d0
    blo.s   +
    move.b  #2,routine(a0)
    bclr    #2,status(a0)
    moveq   #0,d0
    move.w  d0,x_vel(a0)
    move.w  d0,y_vel(a0)
    move.w  d0,inertia(a0)      ; This makes player stop on ground
    move.b  d0,ss_slide_timer(a0)
    bset    #6,status(a0)
    bsr.w   SSObjectMove
    bsr.w   SSAnglePos
+
    rts
; ===========================================================================
 
SSPlayer_Collision:
    tst.b   collision_property(a0)
    beq.s   return_33E42
    clr.b   collision_property(a0)
    tst.b   ss_dplc_timer(a0)
    bne.s   return_33E42
    clr.b   inertia(a0)     ; clears only high byte, leaving a bit of speed
    cmpa.l  #MainCharacter,a0
    bne.s   +
    st.b    (SS_Swap_Positions_Flag).w
    tst.w   (Ring_count).w
    beq.s   loc_33E38
    bra.s   ++
; ===========================================================================
+
    clr.b   (SS_Swap_Positions_Flag).w
    tst.w   (Ring_count_2P).w
    beq.s   loc_33E38
+
    move.w  #SndID_RingSpill,d0
    jsr (PlaySound).l
 
loc_33E38:
    move.b  #2,routine_secondary(a0)        ; hurt state
    clr.b   ss_hurt_timer(a0)
 
return_33E42:
    rts
; ===========================================================================
 
SSPlayerSwapPositions:
    tst.w   (Player_mode).w
    bne.s   return_33E8E
    move.w  ss_z_pos(a0),d0
    cmpa.l  #MainCharacter,a0
    bne.s   loc_33E5E
    tst.b   (SS_Swap_Positions_Flag).w
    beq.s   loc_33E6E
    bra.s   loc_33E64
; ===========================================================================
 
loc_33E5E:
    tst.b   (SS_Swap_Positions_Flag).w
    bne.s   loc_33E6E
 
loc_33E64:
    cmpi.w  #$80,d0
    beq.s   return_33E8E
    addq.w  #1,d0
    bra.s   loc_33E76
; ===========================================================================
 
loc_33E6E:
    cmpi.w  #$6E,d0
    beq.s   return_33E8E
    subq.w  #1,d0
 
loc_33E76:
    move.w  d0,ss_z_pos(a0)
    cmpi.w  #$77,d0
    bhs.s   loc_33E88
    move.b  #3,priority(a0)
    rts
; ===========================================================================
 
loc_33E88:
    move.b  #2,priority(a0)
 
return_33E8E:
    rts
; ===========================================================================
byte_33E90:
    dc.b   1,  1
    dc.b   0,  0    ; 2
    dc.b   1,  0    ; 4
    dc.b   2,  0    ; 6
    dc.b   1,  2    ; 8
    dc.b   0,  2    ; 10
    dc.b   1,  3    ; 12
    dc.b   2,  1    ; 14
; ===========================================================================
 
SSPlayer_SetAnimation:
    btst    #2,status(a0)
    beq.s   +
    move.b  #3,anim(a0)
    andi.b  #$FC,status(a0)
    rts
; ===========================================================================
+
    moveq   #0,d0
    move.b  angle(a0),d0
    subi.b  #$10,d0
    lsr.b   #5,d0
    move.b  d0,d1
    add.w   d0,d0
    move.b  byte_33E90(pc,d0.w),d2
    cmp.b   anim(a0),d2
    bne.s   +
    cmp.b   ss_last_angle_index(a0),d1
    beq.s   return_33EFE
+
    move.b  d1,ss_last_angle_index(a0)
    move.b  d2,anim(a0)
    move.b  byte_33E90+1(pc,d0.w),d0
    andi.b  #$FC,status(a0)
    or.b    d0,status(a0)
    cmpi.b  #1,d1
    beq.s   loc_33EF8
    cmpi.b  #5,d1
    bne.s   return_33EFE
 
loc_33EF8:
    move.w  #$400,ss_init_flip_timer(a0)
 
return_33EFE:
    rts
; ===========================================================================
 
SSPlayer_Animate:
    moveq   #0,d0
    move.b  anim(a0),d0
    cmp.b   next_anim(a0),d0
    beq.s   SSAnim_Do
    move.b  #0,anim_frame(a0)
    move.b  d0,next_anim(a0)
    move.b  #0,anim_frame_duration(a0)
 
SSAnim_Do:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   SSAnim_Delay
    add.w   d0,d0
    adda.w  (a1,d0.w),a1
    move.b  (SS_player_anim_frame_timer).w,d0
    lsr.b   #1,d0
    move.b  d0,anim_frame_duration(a0)
    cmpi.b  #0,anim(a0)
    bne.s   +
    subi_.b #1,ss_flip_timer(a0)
    bgt.s   +
    bchg    #0,status(a0)
    bchg    #0,render_flags(a0)
    move.b  ss_init_flip_timer(a0),ss_flip_timer(a0)
+
    moveq   #0,d1
    move.b  anim_frame(a0),d1
    move.b  1(a1,d1.w),d0
    bpl.s   +
    move.b  #0,anim_frame(a0)
    move.b  1(a1),d0
+
    andi.b  #$7F,d0
    move.b  d0,mapping_frame(a0)
    move.b  status(a0),d1
    andi.b  #3,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    addq.b  #1,anim_frame(a0)
 
SSAnim_Delay:
    rts
; ===========================================================================
 
SSPlayer_Move:
    move.w  inertia(a0),d2
    move.b  (a2),d0
    btst    #button_left,d0
    bne.s   SSPlayer_MoveLeft
    btst    #button_right,d0
    bne.w   SSPlayer_MoveRight
    bset    #6,status(a0)
    bne.s   +
    move.b  #$1E,ss_slide_timer(a0)
+
    move.b  angle(a0),d0
    bmi.s   +
    subi.b  #$38,d0
    cmpi.b  #$10,d0
    bhs.s   +
    move.w  d2,d1
    asr.w   #3,d1
    sub.w   d1,d2
    bra.s   ++
; ===========================================================================
+
    move.w  d2,d1
    asr.w   #3,d1
    sub.w   d1,d2
+
    move.w  d2,inertia(a0)
    move.b  ss_slide_timer(a0),d0
    beq.s   +
    subq.b  #1,d0
    move.b  d0,ss_slide_timer(a0)
+
    rts
; ===========================================================================
 
SSPlayer_MoveLeft:
    addi.w  #$60,d2
    cmpi.w  #$600,d2
    ble.s   +
    move.w  #$600,d2
    bra.s   +
; ===========================================================================
 
SSPlayer_MoveRight:
    subi.w  #$60,d2
    cmpi.w  #-$600,d2
    bge.s   +
    move.w  #-$600,d2
+
    move.w  d2,inertia(a0)
    bclr    #6,status(a0)
    clr.b   ss_slide_timer(a0)
    rts
; ===========================================================================
 
SSPlayer_Traction:
    tst.b   ss_slide_timer(a0)
    bne.s   +
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  #$50,d1
    asr.l   #8,d1
    add.w   d1,inertia(a0)
+
    move.b  angle(a0),d0
    bpl.s   return_34048
    addi_.b #4,d0
    cmpi.b  #-$78,d0
    blo.s   return_34048
    mvabs.w inertia(a0),d0
    cmpi.w  #$100,d0
    bhs.s   return_34048
    move.b  #8,routine(a0)
 
return_34048:
    rts
; ===========================================================================
 
SSObjectMove:
    moveq   #0,d0
    moveq   #0,d1
    move.w  inertia(a0),d2
    bpl.s   +
    neg.w   d2
    lsr.w   #8,d2
    sub.b   d2,angle(a0)
    bra.s   ++
; ===========================================================================
+
    lsr.w   #8,d2
    add.b   d2,angle(a0)
+
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  ss_z_pos(a0),d1
    asr.l   #8,d1
    move.w  d1,ss_x_pos(a0)
    muls.w  ss_z_pos(a0),d0
    asr.l   #8,d0
    move.w  d0,ss_y_pos(a0)
    rts
; ===========================================================================
 
SSAnglePos:
    move.w  ss_x_pos(a0),d0
    muls.w  #$CC,d0
    asr.l   #8,d0
    add.w   (SS_Offset_X).w,d0
    move.w  d0,x_pos(a0)
    move.w  ss_y_pos(a0),d0
    add.w   (SS_Offset_Y).w,d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 63 - Character shadow from Special Stage
; ----------------------------------------------------------------------------
; Sprite_340A4:
Obj63:
    movea.l ss_parent(a0),a1 ; a1=object
    cmpa.l  #MainCharacter,a1
    bne.s   loc_340BC
    movea.l #MainCharacter,a1 ; a1=character
    bsr.s   loc_340CC
    jmpto   (DisplaySprite).l, JmpTo42_DisplaySprite
; ===========================================================================
 
loc_340BC:
    movea.l #Sidekick,a1 ; a1=object
    bsr.s   loc_340CC
    bsr.w   loc_341BA
    jmpto   (DisplaySprite).l, JmpTo42_DisplaySprite
; ===========================================================================
 
loc_340CC:
    cmpi.b  #2,routine(a1)
    beq.w   loc_34108
    bsr.w   loc_33D02
    move.b  angle(a0),d0
    jsr (CalcSine).l
    muls.w  ss_z_pos(a1),d1
    muls.w  #$CC,d1
    swap    d1
    add.w   (SS_Offset_X).w,d1
    move.w  d1,x_pos(a0)
    muls.w  ss_z_pos(a1),d0
    asr.l   #8,d0
    add.w   (SS_Offset_Y).w,d0
    move.w  d0,y_pos(a0)
    bra.w   loc_3411A
; ===========================================================================
 
loc_34108:
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  angle(a1),angle(a0)
 
loc_3411A:
    moveq   #0,d0
    move.b  angle(a0),d0
    subi.b  #$10,d0
    lsr.b   #5,d0
    move.b  d0,d1
    lsl.w   #3,d0
    lea word_3417A(pc),a2
    adda.w  d0,a2
    move.w  (a2)+,art_tile(a0)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a0)
    move.w  (a2)+,d0
    add.w   d0,y_pos(a0)
    move.b  (a2)+,mapping_frame(a0)
    move.b  render_flags(a0),d0
    andi.b  #$FC,d0
    or.b    (a2)+,d0
    move.b  d0,render_flags(a0)
    tst.b   angle(a0)
    bpl.s   return_34178
    cmpi.b  #3,d1
    beq.s   loc_34164
    cmpi.b  #7,d1
    bne.s   loc_3416A
 
loc_34164:
    addi_.b #3,mapping_frame(a0)
 
loc_3416A:
    move.w  (SS_Offset_Y).w,d1
    sub.w   y_pos(a0),d1
    add.w   d1,d1
    add.w   d1,y_pos(a0)
 
return_34178:
    rts
; ===========================================================================
word_3417A:
    dc.w make_art_tile(ArtTile_ArtNem_SpecialDiagShadow,3,0),  $14,  $14,   $101
    dc.w make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),    0,  $18,      0; 4
    dc.w make_art_tile(ArtTile_ArtNem_SpecialDiagShadow,3,0),$FFEC,  $14,   $100; 8
    dc.w make_art_tile(ArtTile_ArtNem_SpecialSideShadow,3,0),$FFEC,    0,   $200; 12
    dc.w make_art_tile(ArtTile_ArtNem_SpecialDiagShadow,3,0),$FFEC,$FFEC,   $700; 16
    dc.w make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),    0,$FFE8,   $900; 20
    dc.w make_art_tile(ArtTile_ArtNem_SpecialDiagShadow,3,0),  $14,$FFEC,   $701; 24
    dc.w make_art_tile(ArtTile_ArtNem_SpecialSideShadow,3,0),  $14,    0,   $201; 28
; ===========================================================================
 
loc_341BA:
    cmpi.b  #1,anim(a1)
    bne.s   return_341E0
    move.b  status(a1),d1
    andi.w  #3,d1
    cmpi.b  #2,d1
    bhs.s   return_341E0
    move.b  byte_341E2(pc,d1.w),d0
    ext.w   d0
    add.w   d0,x_pos(a0)
    subi_.w #4,y_pos(a0)
 
return_341E0:
    rts
; ===========================================================================
; animation script
byte_341E2: dc.b  4, -4
off_341E4:  offsetTable
        offsetTableEntry.w byte_341EE   ; 0
        offsetTableEntry.w byte_341F4   ; 1
        offsetTableEntry.w byte_341FE   ; 2
        offsetTableEntry.w byte_34204   ; 3
        offsetTableEntry.w byte_34208   ; 4
byte_341EE:
    dc.b   3,  0,  1,  2,  3,$FF
byte_341F4:
    dc.b   3,  4,  5,  6,  7,  8,  9, $A, $B,$FF
byte_341FE:
    dc.b   3, $C, $D, $E, $F,$FF
byte_34204:
    dc.b   1,$10,$11,$FF
byte_34208:
    dc.b   3,  0,  4, $C,  4,  0,  4, $C,  4,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings - uses ArtNem_SpecialSonicAndTails
; ----------------------------------------------------------------------------
Obj09_MapUnc_34212: BINCLUDE "mappings/sprite/obj09.bin"
; ----------------------------------------------------------------------------
; sprite mappings for special stage shadows
; ----------------------------------------------------------------------------
Obj63_MapUnc_34492: BINCLUDE "mappings/sprite/obj63.bin"
; ----------------------------------------------------------------------------
; custom dynamic pattern loading cues for special stage Sonic, Tails and
; Tails' tails
; The first $12 frames are for Sonic, and the next $12 frames are for Tails.
; The last $15 frames are for Tails' tails.
; The first $24 frames are almost normal dplcs -- the only difference being
; that the art tile to load is pre-shifted left by 4 bits.
; The same applies to the last $15 frames, but they have yet another difference:
; a small space optimization. These frames only have one dplc per frame ever,
; hence the two-byte dplc count is removed from each frame.
; ----------------------------------------------------------------------------
Obj09_MapRUnc_345FA:    BINCLUDE "mappings/spriteDPLC/obj09.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo42_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo_SSSingleObjLoad 
    jmp (SSSingleObjLoad).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 10 - Tails in Special Stage
; ----------------------------------------------------------------------------
; Sprite_347EC:
Obj10:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj10_Index(pc,d0.w),d1
    jmp Obj10_Index(pc,d1.w)
; ===========================================================================
; off_347FA:
Obj10_Index:    offsetTable
        offsetTableEntry.w Obj10_Init   ; 0
        offsetTableEntry.w Obj10_MdNormal   ; 1
        offsetTableEntry.w Obj10_MdJump ; 2
        offsetTableEntry.w Obj10_Index  ; 3 - invalid
        offsetTableEntry.w Obj10_MdAir  ; 4
; ===========================================================================
; loc_34804:
Obj10_Init:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.w  d0,ss_x_pos(a0)
    move.w  #$80,d1
    move.w  d1,ss_y_pos(a0)
    add.w   (SS_Offset_X).w,d0
    move.w  d0,x_pos(a0)
    add.w   (SS_Offset_Y).w,d1
    move.w  d1,y_pos(a0)
    move.b  #$E,y_radius(a0)
    move.b  #7,x_radius(a0)
    move.l  #Obj10_MapUnc_34B3E,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialTails,2,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #2,priority(a0)
    move.w  #$80,ss_z_pos(a0)
    tst.w   (Player_mode).w
    beq.s   loc_34864
    move.b  #3,priority(a0)
    move.w  #$6E,ss_z_pos(a0)
 
loc_34864:
    move.w  #$400,ss_init_flip_timer(a0)
    move.b  #$40,angle(a0)
    move.b  #1,(Tails_LastLoadedDPLC).w
    clr.b   collision_property(a0)
    clr.b   ss_dplc_timer(a0)
    bsr.w   LoadSSTailsDynPLC
    movea.l #SpecialStageShadow_Tails,a1
    move.b  #ObjID_SSShadow,id(a1) ; load obj63 (shadow) at $FFFFB180
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$18,y_pos(a1)
    move.l  #Obj63_MapUnc_34492,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.l  a0,ss_parent(a1)
    movea.l #SpecialStageTails_Tails,a1
    move.b  #ObjID_SSTailsTails,id(a1) ; load obj88
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  #Obj88_MapUnc_34DA8,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialTails_Tails,2,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  priority(a0),priority(a1)
    subi_.b #1,priority(a1)
    move.l  a0,ss_parent(a1)
    movea.l a1,a0
    move.b  #1,(TailsTails_LastLoadedDPLC).w
    clr.b   ss_dplc_timer(a0)
    movea.l ss_parent(a0),a0 ; load 0bj address
    rts
; ===========================================================================
 
Obj10_MdNormal:
    tst.b   routine_secondary(a0)
    bne.s   Obj10_Hurt
    bsr.w   SSTailsCPU_Control
    lea (Ctrl_2_Held_Logical).w,a2
    tst.w   (Player_mode).w
    beq.s   +
    lea (Ctrl_1_Held_Logical).w,a2
+
    bsr.w   SSPlayer_Move
    bsr.w   SSPlayer_Traction
    moveq   #1,d0
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSObjectMove
    bsr.w   SSAnglePos
    lea (Ctrl_2_Press_Logical).w,a2
    tst.w   (Player_mode).w
    beq.s   +
    lea (Ctrl_1_Press_Logical).w,a2
+
    bsr.w   SSPlayer_Jump
    bsr.w   SSPlayer_SetAnimation
    lea (off_34B1C).l,a1
    bsr.w   SSPlayer_Animate
    bsr.w   SSPlayer_Collision
    bra.w   LoadSSTailsDynPLC
; ===========================================================================
 
Obj10_Hurt:
    bsr.w   SSHurt_Animation
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSObjectMove
    bsr.w   SSAnglePos
    bra.w   LoadSSTailsDynPLC
; ===========================================================================
 
SSTailsCPU_Control:
    tst.b   (SS_2p_Flag).w
    bne.s   +
    tst.w   (Player_mode).w
    beq.s   ++
+
    rts
; ===========================================================================
+
    move.b  (Ctrl_2_Held_Logical).w,d0
    andi.b  #button_up_mask|button_down_mask|button_left_mask|button_right_mask|button_B_mask|button_C_mask|button_A_mask,d0
    beq.s   +
    moveq   #0,d0
    moveq   #3,d1
    lea (SS_Ctrl_Record_Buf).w,a1
-
    move.l  d0,(a1)
    move.l  d0,(a1)
    dbf d1,-
    move.w  #$B4,(Tails_control_counter).w
    rts
; ===========================================================================
+
    tst.w   (Tails_control_counter).w
    beq.s   +
    subq.w  #1,(Tails_control_counter).w
    rts
; ===========================================================================
+
    lea (SS_Last_Ctrl_Record).w,a1
    move.w  (a1),(Ctrl_2_Logical).w
    rts
; ===========================================================================
dword_349B8:
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($183)     ; Tails in upright position, $3D tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($1C0)     ; Tails in diagonal position, $A4 tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($264)     ; Tails in horizontal position, $3A tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($29E)     ; Tails in ball form, $10 tiles
; ===========================================================================
 
LoadSSTailsDynPLC:
    move.b  ss_dplc_timer(a0),d0
    beq.s   +
    subq.b  #1,d0
    move.b  d0,ss_dplc_timer(a0)
    andi.b  #1,d0
    beq.s   +
    rts
; ===========================================================================
+
    jsrto   (DisplaySprite).l, JmpTo43_DisplaySprite
    lea dword_349B8(pc),a3
    lea (Tails_LastLoadedDPLC).w,a4
    move.w  #tiles_to_bytes(ArtTile_ArtNem_SpecialTails),d4
    moveq   #$12,d1
    bra.w   LoadSSPlayerDynPLC
; ===========================================================================
 
Obj10_MdJump:
    lea (Ctrl_2_Held_Logical).w,a2
    tst.w   (Player_mode).w
    beq.s   +
    lea (Ctrl_1_Held_Logical).w,a2
+
    bsr.w   SSPlayer_ChgJumpDir
    bsr.w   SSObjectMoveAndFall
    bsr.w   SSPlayer_DoLevelCollision
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSAnglePos
    bsr.w   SSPlayer_JumpAngle
    lea (off_34B1C).l,a1
    bsr.w   SSPlayer_Animate
    bra.s   LoadSSTailsDynPLC
; ===========================================================================
 
Obj10_MdAir:
    lea (Ctrl_2_Held_Logical).w,a2
    tst.w   (Player_mode).w
    beq.s   +
    lea (Ctrl_1_Held_Logical).w,a2
+
    bsr.w   SSPlayer_ChgJumpDir
    bsr.w   SSObjectMoveAndFall
    bsr.w   SSPlayer_JumpAngle
    bsr.w   SSPlayer_DoLevelCollision
    bsr.w   SSPlayerSwapPositions
    bsr.w   SSAnglePos
    bsr.w   SSPlayer_SetAnimation
    lea (off_34B1C).l,a1
    bsr.w   SSPlayer_Animate
    bra.w   LoadSSTailsDynPLC
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 88 - Tails' tails in Special Stage
; ----------------------------------------------------------------------------
; Sprite_34A5C:
Obj88:
    movea.l ss_parent(a0),a1 ; load obj address of Tails
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.b  render_flags(a1),render_flags(a0)
    move.b  status(a1),status(a0)
    move.b  anim(a1),anim(a0)
    move.b  priority(a1),d0
    subq.b  #1,d0
    move.b  d0,priority(a0)
    cmpi.b  #3,anim(a0)
    bhs.s   return_34A9E
    lea (Ani_obj88).l,a1
    jsrto   (AnimateSprite).l, JmpTo23_AnimateSprite
    bra.w   LoadSSTailsTailsDynPLC
; ===========================================================================
 
return_34A9E:
    rts
; ===========================================================================
dword_34AA0:
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($2AE)     ; Tails' tails when he is in upright position, $35 tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($2E3)     ; Tails' tails when he is in diagonal position, $3B tiles
    dc.l   (SSRAM_ArtNem_SpecialSonicAndTails & $FFFFFF) + tiles_to_bytes($31E)     ; Tails' tails when he is in horizontal position, $35 tiles
; ===========================================================================
 
LoadSSTailsTailsDynPLC:
    movea.l ss_parent(a0),a1 ; load obj address of Tails
    move.b  ss_dplc_timer(a1),d0
    beq.s   +
    andi.b  #1,d0
    beq.s   +
    rts
; ===========================================================================
+
    jsrto   (DisplaySprite).l, JmpTo43_DisplaySprite
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    cmp.b   (TailsTails_LastLoadedDPLC).w,d0
    beq.s   return_34B1A
    move.b  d0,(TailsTails_LastLoadedDPLC).w
    moveq   #0,d6
    cmpi.b  #7,d0
    blt.s   loc_34AE4
    addq.w  #4,d6
    cmpi.b  #$E,d0
    blt.s   loc_34AE4
    addq.w  #4,d6
 
loc_34AE4:
    move.l  dword_34AA0(pc,d6.w),d6
    addi.w  #$24,d0
    add.w   d0,d0
    lea (Obj09_MapRUnc_345FA).l,a2
    adda.w  (a2,d0.w),a2
    move.w  #tiles_to_bytes(ArtTile_ArtNem_SpecialTails_Tails),d2
    moveq   #0,d1
    move.w  (a2)+,d1
    move.w  d1,d3
    lsr.w   #8,d3
    andi.w  #$F0,d3
    addi.w  #$10,d3
    andi.w  #$FFF,d1
    lsl.w   #1,d1
    add.l   d6,d1
    jsr (QueueDMATransfer).l
 
return_34B1A:
    rts
; ===========================================================================
off_34B1C:  offsetTable
        offsetTableEntry.w byte_34B24   ; 0
        offsetTableEntry.w byte_34B2A   ; 1
        offsetTableEntry.w byte_34B34   ; 2
        offsetTableEntry.w byte_34B3A   ; 3
byte_34B24:
    dc.b   3,  0,  1,  2,  3,$FF
byte_34B2A:
    dc.b   3,  4,  5,  6,  7,  8,  9, $A, $B,$FF
byte_34B34:
    dc.b   3, $C, $D, $E, $F,$FF
byte_34B3A:
    dc.b   1,$10,$11,$FF
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj10_MapUnc_34B3E: BINCLUDE "mappings/sprite/obj10.bin"
 
; animation script
; off_34D86:
Ani_obj88:  offsetTable
        offsetTableEntry.w byte_34D8C   ; 0
        offsetTableEntry.w byte_34D95   ; 1
        offsetTableEntry.w byte_34D9E   ; 2
byte_34D8C: dc.b   3,  0,  1,  2,  3,  4,  5,  6,$FF
    rev02even
byte_34D95: dc.b   3,  7,  8,  9, $A, $B, $C, $D,$FF
    rev02even
byte_34D9E: dc.b   3, $E, $F,$10,$11,$12,$13,$14,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings for Tails' tails in special stage
; ----------------------------------------------------------------------------
Obj88_MapUnc_34DA8: BINCLUDE "mappings/sprite/obj88.bin"
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo43_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo23_AnimateSprite 
    jmp (AnimateSprite).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 61 - Bombs from Special Stage
; ----------------------------------------------------------------------------
; Sprite_34EB0:
Obj61:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj61_Index(pc,d0.w),d1
    jmp Obj61_Index(pc,d1.w)
; ===========================================================================
; off_34EBE:
Obj61_Index:    offsetTable
        offsetTableEntry.w Obj61_Init   ; 0
        offsetTableEntry.w loc_34F06    ; 2
        offsetTableEntry.w loc_3533A    ; 4
        offsetTableEntry.w loc_34F6A    ; 6
; ===========================================================================
; loc_34EC6:
Obj61_Init:
    addq.b  #2,routine(a0)
    move.w  #$7F,x_pos(a0)
    move.w  #$58,y_pos(a0)
    move.l  #Obj61_MapUnc_36508,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialBomb,1,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #2,collision_flags(a0)
    move.b  #-1,(SS_unk_DB4D).w
    tst.b   angle(a0)
    bmi.s   loc_34F06
    bsr.w   loc_3529C
 
loc_34F06:
    bsr.w   loc_3512A
    bsr.w   loc_351A0
    lea (Ani_obj61).l,a1
    bsr.w   loc_3539E
    tst.b   render_flags(a0)
    bpl.s   return_34F26
    bsr.w   loc_34F28
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
return_34F26:
    rts
; ===========================================================================
 
loc_34F28:
    move.w  #8,d6
    bsr.w   loc_350A0
    bcc.s   return_34F68
    move.b  #1,collision_property(a1)
    move.w  #SndID_SlowSmash,d0
    jsr (PlaySoundStereo).l
    move.b  #6,routine(a0)
    move.b  #0,anim_frame(a0)
    move.b  #0,anim_frame_duration(a0)
    move.l  objoff_34(a0),d0
    beq.s   return_34F68
    move.l  #0,objoff_34(a0)
    movea.l d0,a1 ; a1=object
    st  objoff_2A(a1)
 
return_34F68:
    rts
; ===========================================================================
 
loc_34F6A:
    move.b  #$A,anim(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialExplosion,2,0),art_tile(a0)
    bsr.w   loc_34F90
    bsr.w   loc_3512A
    bsr.w   loc_351A0
    lea (Ani_obj61).l,a1
    jsrto   (AnimateSprite).l, JmpTo24_AnimateSprite
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
loc_34F90:
    cmpi.w  #4,objoff_30(a0)
    bhs.s   return_34F9E
    move.b  #1,priority(a0)
 
return_34F9E:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 60 - Rings from Special Stage
; ----------------------------------------------------------------------------
; Sprite_34FA0:
Obj60:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj60_Index(pc,d0.w),d1
    jmp Obj60_Index(pc,d1.w)
; ===========================================================================
; off_34FAE:
Obj60_Index:    offsetTable
        offsetTableEntry.w Obj60_Init   ; 0
        offsetTableEntry.w loc_34FF0    ; 1
        offsetTableEntry.w loc_3533A    ; 2
        offsetTableEntry.w loc_35010    ; 3
; ===========================================================================
; loc_34FB6:
Obj60_Init:
    addq.b  #2,routine(a0)
    move.w  #$7F,x_pos(a0)
    move.w  #$58,y_pos(a0)
    move.l  #Obj5A_Obj5B_Obj60_MapUnc_3632A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialRings,3,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #3,priority(a0)
    move.b  #1,collision_flags(a0)
    tst.b   angle(a0)
    bmi.s   loc_34FF0
    bsr.w   loc_3529C
 
loc_34FF0:
 
    bsr.w   loc_3512A
    bsr.w   loc_351A0
    bsr.w   loc_35036
    lea (Ani_obj5B_obj60).l,a1
    bsr.w   loc_3539E
    tst.b   render_flags(a0)
    bmi.w   JmpTo44_DisplaySprite
    rts
; ===========================================================================
 
loc_35010:
    move.b  #$A,anim(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialStars,2,0),art_tile(a0)
    bsr.w   loc_34F90
    bsr.w   loc_3512A
    bsr.w   loc_351A0
    lea (Ani_obj5B_obj60).l,a1
    jsrto   (AnimateSprite).l, JmpTo24_AnimateSprite
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
loc_35036:
    move.w  #$A,d6
    bsr.w   loc_350A0
    bcc.s   return_3509E
    cmpa.l  #MainCharacter,a1
    bne.s   loc_3504E
    addq.w  #1,(Ring_count).w
    bra.s   loc_35052
; ===========================================================================
 
loc_3504E:
    addq.w  #1,(Ring_count_2P).w
 
loc_35052:
    addq.b  #1,ss_rings_units(a1)
    cmpi.b  #$A,ss_rings_units(a1)
    blt.s   loc_3507A
    addq.b  #1,ss_rings_tens(a1)
    move.b  #0,ss_rings_units(a1)
    cmpi.b  #$A,ss_rings_tens(a1)
    blt.s   loc_3507A
    addq.b  #1,ss_rings_hundreds(a1)
    move.b  #0,ss_rings_tens(a1)
 
loc_3507A:
    move.b  #6,routine(a0)
    move.l  objoff_34(a0),d0
    beq.s   loc_35094
    move.l  #0,objoff_34(a0)
    movea.l d0,a1 ; a1=object
    st  objoff_2A(a1)
 
loc_35094:
    move.w  #SndID_Ring,d0
    jsr (PlaySoundStereo).l
 
return_3509E:
    rts
; ===========================================================================
 
loc_350A0:
    cmpi.b  #8,anim(a0)
    bne.s   loc_350DC
    tst.b   collision_flags(a0)
    beq.s   loc_350DC
    lea (MainCharacter).w,a2 ; a2=object (special stage sonic)
    lea (Sidekick).w,a3 ; a3=object (special stage tails)
    move.w  objoff_34(a2),d0
    cmp.w   objoff_34(a3),d0
    blo.s   loc_350CE
    movea.l a3,a1
    bsr.w   loc_350E2
    bcs.s   return_350E0
    movea.l a2,a1
    bra.w   loc_350E2
; ===========================================================================
 
loc_350CE:
    movea.l a2,a1
    bsr.w   loc_350E2
    bcs.s   return_350E0
    movea.l a3,a1
    bra.w   loc_350E2
; ===========================================================================
 
loc_350DC:
    move    #0,ccr
 
return_350E0:
    rts
; ===========================================================================
 
loc_350E2:
    tst.b   (a1)
    beq.s   loc_3511A
    cmpi.b  #2,routine(a1)
    bne.s   loc_3511A
    tst.b   routine_secondary(a1)
    bne.s   loc_3511A
    move.b  angle(a1),d0
    move.b  angle(a0),d1
    move.b  d1,d2
    add.b   d6,d1
    bcs.s   loc_35110
    sub.b   d6,d2
    bcs.s   loc_35112
    cmp.b   d1,d0
    bhs.s   loc_3511A
    cmp.b   d2,d0
    bhs.s   loc_35120
    bra.s   loc_3511A
; ===========================================================================
 
loc_35110:
    sub.b   d6,d2
 
loc_35112:
    cmp.b   d1,d0
    blo.s   loc_35120
    cmp.b   d2,d0
    bhs.s   loc_35120
 
loc_3511A:
    move    #0,ccr
    rts
; ===========================================================================
 
loc_35120:
    clr.b   collision_flags(a0)
    move    #1,ccr
    rts
; ===========================================================================
 
loc_3512A:
    btst    #7,status(a0)
    bne.s   loc_3516C
    cmpi.b  #4,(SSTrack_drawing_index).w
    bne.s   loc_35146
    subi.l  #$CCCC,objoff_30(a0)
    ble.s   loc_3516C
    bra.s   loc_35150
; ===========================================================================
 
loc_35146:
    subi.l  #$CCCD,objoff_30(a0)
    ble.s   loc_3516C
 
loc_35150:
    cmpi.b  #$A,anim(a0)
    beq.s   return_3516A
    move.w  objoff_30(a0),d0
    cmpi.w  #$1D,d0
    ble.s   loc_35164
    moveq   #$1E,d0
 
loc_35164:
    move.b  byte_35180(pc,d0.w),anim(a0)
 
return_3516A:
    rts
; ===========================================================================
 
loc_3516C:
    move.l  (sp)+,d0
    move.l  objoff_34(a0),d0
    beq.w   JmpTo63_DeleteObject
    movea.l d0,a1 ; a1=object
    st  objoff_2A(a1)
 
    if removeJmpTos
JmpTo63_DeleteObject 
    endif
 
    jmpto   (DeleteObject).l, JmpTo63_DeleteObject
; ===========================================================================
byte_35180:
    dc.b   9,  9,  9,  8,  8,  7,  7,  6,  6,  5,  5,  4,  4,  3,  3,  3
    dc.b   2,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0; 16
; ===========================================================================
 
loc_351A0:
    move.w  d7,-(sp)
    moveq   #0,d2
    moveq   #0,d3
    moveq   #0,d4
    moveq   #0,d5
    moveq   #0,d6
    moveq   #0,d7
    movea.l (SS_CurrentPerspective).w,a1
    move.w  objoff_30(a0),d0
    beq.w   loc_35258
    cmp.w   (a1)+,d0
    bgt.w   loc_35258
    subq.w  #1,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    tst.b   (SSTrack_Orientation).w
    bne.w   loc_35260
    move.b  4(a1,d0.w),d6
    move.b  5(a1,d0.w),d7
    beq.s   loc_351E8
    move.b  angle(a0),d1
    cmp.b   d6,d1
    blo.s   loc_351E8
    cmp.b   d7,d1
    blo.s   loc_35258
 
loc_351E8:
    move.b  (a1,d0.w),d2
    move.b  2(a1,d0.w),d4
    move.b  3(a1,d0.w),d5
    move.b  1(a1,d0.w),d3
 
loc_351F8:
    bpl.s   loc_35202
    cmpi.b  #$48,d3
    blo.s   loc_35202
    ext.w   d3
 
loc_35202:
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo14_CalcSine
    muls.w  d4,d1
    muls.w  d5,d0
    asr.l   #8,d0
    asr.l   #8,d1
    add.w   d2,d1
    add.w   d3,d0
    move.w  d1,x_pos(a0)
    move.w  d0,y_pos(a0)
    move.l  objoff_34(a0),d0
    beq.s   loc_3524E
    movea.l d0,a1 ; a1=object
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo14_CalcSine
    move.w  d4,d7
    lsr.w   #2,d7
    add.w   d7,d4
    muls.w  d4,d1
    move.w  d5,d7
    asr.w   #2,d7
    add.w   d7,d5
    muls.w  d5,d0
    asr.l   #8,d0
    asr.l   #8,d1
    add.w   d2,d1
    add.w   d3,d0
    move.w  d1,x_pos(a1)
    move.w  d0,y_pos(a1)
 
loc_3524E:
    ori.b   #$80,render_flags(a0)
 
loc_35254:
    move.w  (sp)+,d7
    rts
; ===========================================================================
 
loc_35258:
    andi.b  #$7F,render_flags(a0)
    bra.s   loc_35254
; ===========================================================================
 
loc_35260:
    move.b  #$80,d1
    move.b  4(a1,d0.w),d6
    move.b  5(a1,d0.w),d7
    beq.s   loc_35282
    sub.w   d1,d6
    sub.w   d1,d7
    neg.w   d6
    neg.w   d7
    move.b  angle(a0),d1
    cmp.b   d7,d1
    blo.s   loc_35282
    cmp.b   d6,d1
    blo.s   loc_35258
 
loc_35282:
    move.b  (a1,d0.w),d2
    move.b  2(a1,d0.w),d4
    move.b  3(a1,d0.w),d5
    subi.w  #$100,d2
    neg.w   d2
    move.b  1(a1,d0.w),d3
    bra.w   loc_351F8
; ===========================================================================
 
loc_3529C:
    jsrto   (SSSingleObjLoad2).l, JmpTo_SSSingleObjLoad2
    bne.w   return_3532C
    move.l  a0,objoff_34(a1)
    move.b  (a0),(a1)
    move.b  #4,routine(a1)
    move.l  #Obj63_MapUnc_34492,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #5,priority(a1)
    move.b  angle(a0),d0
    cmpi.b  #$10,d0
    bgt.s   loc_352E6
    bset    #0,render_flags(a1)
    move.b  #2,objoff_2B(a1)
    move.l  a1,objoff_34(a0)
    rts
; ===========================================================================
 
loc_352E6:
    cmpi.b  #$30,d0
    bgt.s   loc_352FE
    bset    #0,render_flags(a1)
    move.b  #1,objoff_2B(a1)
    move.l  a1,objoff_34(a0)
    rts
; ===========================================================================
 
loc_352FE:
    cmpi.b  #$50,d0
    bgt.s   loc_35310
    move.b  #0,objoff_2B(a1)
    move.l  a1,objoff_34(a0)
    rts
; ===========================================================================
 
loc_35310:
    cmpi.b  #$70,d0
    bgt.s   loc_35322
    move.b  #1,objoff_2B(a1)
    move.l  a1,objoff_34(a0)
    rts
; ===========================================================================
 
loc_35322:
    move.b  #2,objoff_2B(a1)
    move.l  a1,objoff_34(a0)
 
return_3532C:
    rts
; ===========================================================================
    dc.b   0
    dc.b   0    ; 1
    dc.b   0    ; 2
    dc.b $18    ; 3
    dc.b   0    ; 4
    dc.b $14    ; 5
    dc.b   0    ; 6
    dc.b $14    ; 7
    dc.b   0    ; 8
    dc.b $14    ; 9
    dc.b   0    ; 10
    dc.b   0    ; 11
; ===========================================================================
 
loc_3533A:
    tst.b   objoff_2A(a0)
    bne.w   BranchTo_JmpTo63_DeleteObject
    movea.l objoff_34(a0),a1 ; a1=object
    tst.b   render_flags(a1)
    bmi.s   loc_3534E
    rts
; ===========================================================================
 
loc_3534E:
    moveq   #9,d0
    sub.b   anim(a1),d0
    addi_.b #1,d0
    cmpi.b  #$A,d0
    bne.s   loc_35362
    move.w  #9,d0
 
loc_35362:
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    moveq   #0,d1
    move.b  objoff_2B(a0),d1
    beq.s   loc_3538A
    cmpi.b  #1,d1
    beq.s   loc_35380
    add.w   d1,d0
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialSideShadow,3,0),art_tile(a0)
    bra.s   loc_35392
; ===========================================================================
 
loc_35380:
    add.w   d1,d0
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialDiagShadow,3,0),art_tile(a0)
    bra.s   loc_35392
; ===========================================================================
 
loc_3538A:
    add.w   d1,d0
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialFlatShadow,3,0),art_tile(a0)
 
loc_35392:
    move.b  d0,mapping_frame(a0)
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
BranchTo_JmpTo63_DeleteObject 
    jmpto   (DeleteObject).l, JmpTo63_DeleteObject
; ===========================================================================
 
loc_3539E:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   return_353E8
    moveq   #0,d0
    move.b  anim(a0),d0
    add.w   d0,d0
    adda.w  (a1,d0.w),a1
    move.b  (a1),anim_frame_duration(a0)
    moveq   #0,d1
    move.b  anim_frame(a0),d1
    move.b  1(a1,d1.w),d0
    bpl.s   loc_353CA
    move.b  #0,anim_frame(a0)
    move.b  1(a1),d0
 
loc_353CA:
    andi.b  #$7F,d0
    move.b  d0,mapping_frame(a0)
    move.b  status(a0),d1
    andi.b  #3,d1
    andi.b  #$FC,render_flags(a0)
    or.b    d1,render_flags(a0)
    addq.b  #1,anim_frame(a0)
 
return_353E8:
    rts
; ===========================================================================
byte_353EA:
    dc.b $38
    dc.b $48    ; 1
    dc.b $2A    ; 2
    dc.b $56    ; 3
    dc.b $1C    ; 4
    dc.b $64    ; 5
    dc.b  $E    ; 6
    dc.b $72    ; 7
    dc.b   0    ; 8
    dc.b $80    ; 9
byte_353F4:
    dc.b $40
    dc.b $30    ; 1
    dc.b $50    ; 2
    dc.b $20    ; 3
    dc.b $60    ; 4
    dc.b $10    ; 5
    dc.b $70    ; 6
    dc.b   0    ; 7
    dc.b $80    ; 8
    dc.b   0    ; 9
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5B - Ring spray/spill in Special Stage
; ----------------------------------------------------------------------------
; Sprite_353FE:
Obj5B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj5B_Index(pc,d0.w),d1
    jmp Obj5B_Index(pc,d1.w)
; ===========================================================================
; off_3540C:
Obj5B_Index:    offsetTable
        offsetTableEntry.w Obj5B_Init   ; 0
        offsetTableEntry.w Obj5B_Main   ; 2
; ===========================================================================
; loc_35410:
Obj5B_Init:
    movea.l ss_parent(a0),a3
    moveq   #0,d1
    move.b  ss_rings_tens(a3),d1
    beq.s   loc_35428
    subi_.b #1,ss_rings_tens(a3)
    move.w  #$A,d1
    bra.s   loc_35458
; ===========================================================================
 
loc_35428:
    move.b  ss_rings_hundreds(a3),d1
    beq.s   loc_35440
    subi_.b #1,ss_rings_hundreds(a3)
    move.b  #9,ss_rings_tens(a3)
    move.w  #$A,d1
    bra.s   loc_35458
; ===========================================================================
 
loc_35440:
    move.b  ss_rings_units(a3),d1
    beq.s   loc_3545C
    move.b  #0,ss_rings_units(a3)
    btst    #0,d1
    beq.s   loc_35458
    lea_    byte_353F4,a2
    bra.s   loc_3545C
; ===========================================================================
 
loc_35458:
    lea_    byte_353EA,a2
loc_3545C:
    cmpi.b  #ObjID_SonicSS,(a3)
    bne.s   loc_35468
    sub.w   d1,(Ring_count).w
    bra.s   loc_3546C
; ===========================================================================
 
loc_35468:
    sub.w   d1,(Ring_count_2P).w
 
loc_3546C:
    move.w  d1,d2
    subq.w  #1,d2
    bmi.w   JmpTo63_DeleteObject
    movea.l a0,a1
    bra.s   loc_3547E
; ===========================================================================
 
loc_35478:
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   loc_354DE
 
loc_3547E:
    move.b  #ObjID_SSRingSpill,id(a1) ; load obj5B
    move.b  #2,routine(a1)
    move.l  #Obj5A_Obj5B_Obj60_MapUnc_3632A,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialRings,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #5,priority(a1)
    move.b  #0,collision_flags(a1)
    move.b  #8,anim(a1)
    move.w  x_pos(a3),x_pos(a1)
    move.w  y_pos(a3),y_pos(a1)
    move.b  angle(a3),d0
    addi.b  #$40,d0
    add.b   (a2)+,d0
    jsr (CalcSine).l
    muls.w  #$400,d1
    asr.l   #8,d1
    move.w  d1,x_vel(a1)
    muls.w  #$1000,d0
    asr.l   #8,d0
    move.w  d0,y_vel(a1)
 
loc_354DE:
    dbf d2,loc_35478
    rts
; ===========================================================================
; loc_354E4:
Obj5B_Main:
    jsrto   (ObjectMoveAndFall).l, JmpTo7_ObjectMoveAndFall
    addi.w  #$80,y_vel(a0)
    bsr.w   loc_3551C
    tst.w   x_pos(a0)
    bmi.w   JmpTo63_DeleteObject
    cmpi.w  #$100,x_pos(a0)
    bhs.w   JmpTo63_DeleteObject
    cmpi.w  #$E0,y_pos(a0)
    bgt.w   JmpTo63_DeleteObject
    lea (Ani_obj5B_obj60).l,a1
    jsrto   (AnimateSprite).l, JmpTo24_AnimateSprite
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
loc_3551C:
    tst.w   y_vel(a0)
    bmi.w   +
    move.b  #0,priority(a0)
    move.b  #9,anim(a0)
+
    rts
; ===========================================================================
    rts
; ===========================================================================
 
SSRainbowPaletteColors:
    move.w  word_35548(pc,d0.w),(Normal_palette_line4+$16).w
    move.w  word_35548+2(pc,d0.w),(Normal_palette_line4+$18).w
    move.w  word_35548+4(pc,d0.w),(Normal_palette_line4+$1A).w
    rts
; ===========================================================================
word_35548:
    dc.w   $EE,  $88,  $44
    dc.w   $EE,  $CC,  $88  ; 3
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 5A - Messages/checkpoint from Special Stage
; ----------------------------------------------------------------------------
; Sprite_35554:
Obj5A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj5A_Index(pc,d0.w),d1
    jmp Obj5A_Index(pc,d1.w)
; ===========================================================================
; off_35562:
Obj5A_Index:    offsetTable
        offsetTableEntry.w Obj5A_Init               ;   0
        offsetTableEntry.w Obj5A_CheckpointRainbow  ;   2
        offsetTableEntry.w Obj5A_TextFlyoutInit     ;   4
        offsetTableEntry.w Obj5A_Handshake          ;   6
        offsetTableEntry.w Obj5A_TextFlyout         ;   8
        offsetTableEntry.w Obj5A_MostRingsWin       ;  $A
        offsetTableEntry.w Obj5A_RingCheckTrigger   ;  $C
        offsetTableEntry.w Obj5A_RingsNeeded        ;  $E
        offsetTableEntry.w Obj5A_FlashMessage       ; $10
        offsetTableEntry.w Obj5A_MoveAndFlash       ; $12
        offsetTableEntry.w Obj5A_FlashOnly          ; $14
; ===========================================================================
; loc_35578:
Obj5A_Init:
    tst.b   (SS_NoCheckpoint_flag).w
    bne.s   Obj5A_RingsMessageInit
    movea.l (SSTrack_last_mappings_copy).w,a1
    cmpa.l  #MapSpec_Straight4,a1
    blt.s   ++      ; rts
    cmpa.l  #MapSpec_Drop1,a1
    bge.s   ++      ; rts
    moveq   #6,d0
    bsr.s   SSRainbowPaletteColors
    st.b    (SS_Checkpoint_Rainbow_flag).w
    moveq   #6,d0
-
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   +
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #2,routine(a1)  ; => Obj5A_CheckpointRainbow
    move.l  #Obj5A_Obj5B_Obj60_MapUnc_3632A,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialRings,3,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #5,priority(a1)
    move.b  d0,objoff_2A(a1)
    move.w  #0,objoff_30(a1)
    move.b  #-1,mapping_frame(a1)
+   dbf d0,-
 
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
+
    rts
; ===========================================================================
;loc_355E0
Obj5A_RingsMessageInit:
    sf.b    (SS_NoCheckpoint_flag).w
    tst.b   (SS_2p_Flag).w
    bne.w   JmpTo63_DeleteObject
    sf.b    (SS_HideRingsToGo).w
    sf.b    (SS_TriggerRingsToGo).w
    move.w  #0,(SS_NoRingsTogoLifetime).w
    move.b  #0,objoff_3A(a0)
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
 ; temporarily remap characters to title card letter format
 ; Characters are encoded as Aa, Bb, Cc, etc. through a macro
 charset 'a','z','A'    ; Convert to uppercase
 charset 'A',"\xD\x11\7\x11\1\x11"
 charset 'G',0  ; can't have an embedded 0 in a string
 charset 'H',"\xB\4\x11\x11\9\xF\5\8\xC\x11\3\6\2\xA\x11\x10\x11\xE\x11"
 charset '!',"\x11"
 charset '.',"\x12"
 
specialText macro letters
    dc.b letters
    dc.b $FF    ; output string terminator
    endm
 
Obj5A_RingsToGoText:
    specialText "RING"
    specialText "!OGOT"
    specialText "S"
    even
 
Obj5A_ToGoOffsets:
    dc.w   $C0  ; 0
    dc.w   $B8  ; 1
    dc.w   $B0  ; 2
    dc.w   $A0  ; 3
    dc.w   $98  ; 4
    dc.w   $88  ; 5
 
 charset ; revert character set
 
; ===========================================================================
;loc_3561E
Obj5A_CreateRingsToGoText:
    st.b    (SS_TriggerRingsToGo).w
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.w   return_356E4
    move.l  #Obj5F_MapUnc_72D2,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,2,0),art_tile(a1)
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #4,render_flags(a1)
    move.b  #1,priority(a1)
    bset    #6,render_flags(a1)
    move.b  #0,mainspr_childsprites(a1)
    move.b  #$E,routine(a1) ; => Obj5A_RingsNeeded
    lea sub2_x_pos(a1),a2
    move.w  #$5A,d1
    move.w  #$38,d2
    moveq   #0,d0
    moveq   #2,d3
 
-   move.w  d1,(a2)+    ; sub?_x_pos
    move.w  d2,(a2)+    ; sub?_y_pos
    move.w  d0,(a2)+    ; sub?_mapframe
    subq.w  #8,d1
    dbf d3,-
    lea Obj5A_RingsToGoText(pc),a3
    move.w  #$68,d1
    move.w  #$38,d2
 
-   move.b  (a3)+,d0
    bmi.s   +
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   return_356E4
    bsr.s   Init_Obj5A
    move.b  #$10,routine(a1)
    move.w  d1,x_pos(a1)
    move.w  d2,y_pos(a1)
    move.b  d0,mapping_frame(a1)
    addq.w  #8,d1
    bra.s   -
; ===========================================================================
+
    lea Obj5A_ToGoOffsets(pc),a2
 
-   move.b  (a3)+,d0
    bmi.s   +
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   return_356E4
    bsr.s   Init_Obj5A
    move.b  #$12,routine(a1)    ; => Obj5A_MoveAndFlash
    move.w  (a2)+,objoff_2A(a1)
    move.w  d2,y_pos(a1)
    move.b  d0,mapping_frame(a1)
    bra.s   -
; ===========================================================================
+
    move.b  (a3)+,d0
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   return_356E4
    bsr.s   Init_Obj5A
    move.b  #$14,routine(a1)    ; => Obj5A_FlashOnly
    move.w  (a2)+,x_pos(a1)
    move.w  d2,y_pos(a1)
    move.b  d0,mapping_frame(a1)
 
return_356E4:
    rts
; ===========================================================================
;loc_356E6
Init_Obj5A:
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.l  #Obj5A_MapUnc_35E1E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialMessages,2,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #1,priority(a1)
    rts
; ===========================================================================
;loc_35706
Obj5A_RingsNeeded:
    move.b  (SS_TriggerRingsToGo).w,(SS_HideRingsToGo).w
    bne.s   +
    bsr.s   ++
    bra.w   Obj5A_FlashMessage
; ===========================================================================
+
    rts
; ===========================================================================
+
    move.w  (Ring_count).w,d0
    cmpi.w  #1,(Player_mode).w
    blt.s   +
    beq.s   ++
    move.w  (Ring_count_2P).w,d0
    bra.s   ++
; ===========================================================================
+
    add.w   (Ring_count_2P).w,d0
+
    sub.w   (SS_Ring_Requirement).w,d0
    neg.w   d0
    bgt.s   +
    moveq   #0,d0
    moveq   #1,d2
    addi_.w #1,(SS_NoRingsTogoLifetime).w
    cmpi.w  #$C,(SS_NoRingsTogoLifetime).w
    blo.s   loc_3577A
    st.b    (SS_HideRingsToGo).w
    bra.s   loc_3577A
; ===========================================================================
+
    ; This code converts the remaining rings into binary coded decimal format.
    moveq   #0,d1
    move.w  d0,d1
    moveq   #0,d0
    cmpi.w  #100,d1
    blt.s   +
 
-   addi.w  #$100,d0
    subi.w  #100,d1
    bgt.s   -
+
    divu.w  #$A,d1
    lsl.w   #4,d1
    or.b    d1,d0
    swap    d1
    or.b    d1,d0
    move.w  #0,(SS_NoRingsTogoLifetime).w
    sf.b    (SS_HideRingsToGo).w
 
loc_3577A:
    moveq   #1,d2
    lea sub2_x_pos(a0),a1
    move.w  d0,(SS_RingsToGoBCD).w
    move.w  d0,d1
    andi.w  #$F,d1
    move.b  d1,sub2_mapframe-sub2_x_pos(a1)
    lsr.w   #4,d0
    beq.s   +
    addq.w  #1,d2
    move.w  d0,d1
    andi.w  #$F,d1
    move.b  d1,sub3_mapframe-sub2_x_pos(a1)
    lsr.w   #4,d0
    beq.s   +
    addq.w  #1,d2
    andi.w  #$F,d0
    move.b  d0,sub4_mapframe-sub2_x_pos(a1)
+
    move.b  d2,mainspr_childsprites(a0)
    rts
; ===========================================================================
;loc_357B2
Obj5A_FlashMessage:
    tst.b   (SS_NoCheckpointMsg_flag).w
    bne.w   +       ; rts
    tst.b   (SS_HideRingsToGo).w
    bne.s   +       ; rts
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    cmpi.b  #6,d0
    blo.w   JmpTo44_DisplaySprite
+
    rts
; ===========================================================================
;loc_357D2
Obj5A_MoveAndFlash:
    moveq   #0,d0
    cmpi.w  #2,(SS_RingsToGoBCD).w
    bhs.s   +
    moveq   #-8,d0
+
    add.w   objoff_2A(a0),d0
    move.w  d0,x_pos(a0)
    bra.s   Obj5A_FlashMessage
; ===========================================================================
;loc_357E8
Obj5A_FlashOnly:
    moveq   #0,d0
    cmpi.w  #2,(SS_RingsToGoBCD).w
    bhs.s   Obj5A_FlashMessage
    rts
; ===========================================================================
Obj5A_Rainbow_Frames:
    dc.b   0
    dc.b   1    ; 1
    dc.b   1    ; 2
    dc.b   1    ; 3
    dc.b   2    ; 4
    dc.b   4    ; 5
    dc.b   6    ; 6
    dc.b   8    ; 7
    dc.b   9    ; 8
    dc.b $FF    ; 9
; ===========================================================================
;loc_357FE
Obj5A_CheckpointRainbow:
    cmpi.b  #4,(SSTrack_drawing_index).w
    bne.s   +
    move.w  objoff_2C(a0),d0
    move.b  Obj5A_Rainbow_Frames(pc,d0.w),mapping_frame(a0)
    bmi.w   ++
    addi_.w #1,objoff_2C(a0)
    moveq   #0,d0
    move.b  objoff_2A(a0),d0
    add.w   d0,d0
    add.w   objoff_30(a0),d0
    move.b  Obj5A_Rainbow_Positions(pc,d0.w),1+x_pos(a0)
    move.b  Obj5A_Rainbow_Positions+1(pc,d0.w),1+y_pos(a0)
    addi.w  #$E,objoff_30(a0)
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
+
    tst.b   mapping_frame(a0)
    bpl.w   JmpTo44_DisplaySprite
    rts
; ===========================================================================
Obj5A_Rainbow_Positions:
    ;      x,  y
    dc.b $F6,$F6
    dc.b $70,$5E    ; 2
    dc.b $76,$58    ; 4
    dc.b $7E,$56    ; 6
    dc.b $88,$58    ; 8
    dc.b $8E,$5E    ; 10
    dc.b $F6,$F6    ; 12
    dc.b $F6,$F6    ; 14
    dc.b $6D,$5A    ; 16
    dc.b $74,$54    ; 18
    dc.b $7E,$50    ; 20
    dc.b $8A,$54    ; 22
    dc.b $92,$5A    ; 24
    dc.b $F6,$F6    ; 26
    dc.b $F6,$F6    ; 28
    dc.b $6A,$58    ; 30
    dc.b $72,$50    ; 32
    dc.b $7E,$4C    ; 34
    dc.b $8C,$50    ; 36
    dc.b $94,$58    ; 38
    dc.b $F6,$F6    ; 40
    dc.b $F6,$F6    ; 42
    dc.b $68,$56    ; 44
    dc.b $70,$4C    ; 46
    dc.b $7E,$48    ; 48
    dc.b $8E,$4C    ; 50
    dc.b $96,$56    ; 52
    dc.b $F6,$F6    ; 54
    dc.b $62,$5E    ; 56
    dc.b $66,$50    ; 58
    dc.b $70,$46    ; 60
    dc.b $7E,$42    ; 62
    dc.b $8E,$46    ; 64
    dc.b $98,$50    ; 66
    dc.b $9C,$5E    ; 68
    dc.b $5C,$5A    ; 70
    dc.b $62,$4A    ; 72
    dc.b $70,$3E    ; 74
    dc.b $7E,$38    ; 76
    dc.b $8E,$3E    ; 78
    dc.b $9C,$4A    ; 80
    dc.b $A2,$5A    ; 82
    dc.b $54,$54    ; 84
    dc.b $5A,$3E    ; 86
    dc.b $6A,$30    ; 88
    dc.b $7E,$2A    ; 90
    dc.b $94,$30    ; 92
    dc.b $A4,$3E    ; 94
    dc.b $AA,$54    ; 96
    dc.b $42,$4A    ; 98
    dc.b $4C,$28    ; 100
    dc.b $62,$12    ; 102
    dc.b $7E, $A    ; 104
    dc.b $9C,$12    ; 106
    dc.b $B2,$28    ; 108
    dc.b $BC,$4A    ; 110
    dc.b $16,$26    ; 112
    dc.b $28,$FC    ; 114
    dc.b $EC,$EC    ; 116
    dc.b $EC,$EC    ; 118
    dc.b $EC,$EC    ; 120
    dc.b $D6,$FC    ; 122
    dc.b $E8,$26    ; 124
; ===========================================================================
+
    cmpi.w  #$E8,x_pos(a0)
    bne.w   JmpTo63_DeleteObject
    moveq   #0,d0
    bsr.w   SSRainbowPaletteColors
    sf.b    (SS_Checkpoint_Rainbow_flag).w
    st.b    (SS_NoCheckpointMsg_flag).w
    tst.b   (SS_2p_Flag).w          ; Is it VS mode?
    beq.w   loc_35978                   ; Branch if not
    move.w  #SndID_Checkpoint,d0
    jsr (PlaySound).l
    addi.b  #$10,(SS_2P_BCD_Score).w
    moveq   #0,d6
    addi_.b #1,(Current_Special_Act).w
    move.w  #$C,d0
    move.w  (Ring_count).w,d2
    cmp.w   (Ring_count_2P).w,d2
    bgt.s   ++
    beq.s   +++
    subi.b  #$10,(SS_2P_BCD_Score).w
    addi_.b #1,(SS_2P_BCD_Score).w
    move.w  #$E,d0
    tst.b   (Graphics_Flags).w
    bpl.s   +
    move.w  #$14,d0
+
    move.w  #palette_line_1,d6
+
    move.w  #$80,d3
    bsr.w   Obj5A_CreateCheckpointWingedHand
    add.w   d6,art_tile(a1)
    add.w   d6,2(a2)
    bsr.w   Obj5A_PrintPhrase
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
+
    subi.b  #$10,(SS_2P_BCD_Score).w
    move.w  #$10,d0
    bsr.w   Obj5A_PrintPhrase
    cmpi.b  #3,(Current_Special_Act).w
    beq.s   +
    move.w  #$46,objoff_2A(a0)
    move.b  #$A,routine(a0)
    rts
; ===========================================================================
+
    bsr.w   Obj5A_VSReset
    move.w  #$46,objoff_2A(a0)
    move.b  #$C,routine(a0)
    rts
; ===========================================================================
 
loc_35978:
    move.w  #6,d1
    move.w  #SndID_Error,d0
    move.w  (Ring_count).w,d2
    add.w   (Ring_count_2P).w,d2
    cmp.w   (SS_Ring_Requirement).w,d2
    blt.s   +
    move.w  #4,d1
    move.w  #SndID_Checkpoint,d0
+
    jsr (PlaySound).l
    move.w  d1,d0
    bsr.w   Obj5A_PrintCheckpointMessage
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
;loc_359A6
Obj5A_MostRingsWin:
    subi_.w #1,objoff_2A(a0)
    beq.s   +
    rts
; ===========================================================================
+
    move.w  #$A,d0          ; MOST RINGS WINS
    bsr.w   Obj5A_PrintPhrase
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
;loc_359BC
Obj5A_RingCheckTrigger:
    subi_.w #1,objoff_2A(a0)
    beq.s   +
    rts
; ===========================================================================
+
    st.b    (SS_Check_Rings_flag).w
    bra.w   SSClearObjs
; ===========================================================================
;loc_359CE
Obj5A_Handshake:
    cmpi.b  #$15,mapping_frame(a0)      ; Is this the hand?
    bne.s   ++                          ; if not, branch
    move.w  objoff_30(a0),d0            ; Target y position for handshake
    tst.b   objoff_2E(a0)
    bne.s   +
    subi_.w #1,y_pos(a0)
    subi_.w #4,d0
    cmp.w   y_pos(a0),d0
    blt.s   ++
    addi_.w #1,d0
    move.w  d0,y_pos(a0)
    st.b    objoff_2E(a0)
    bra.s   ++
; ===========================================================================
+
    addi_.w #1,y_pos(a0)
    addi_.w #4,d0
    cmp.w   y_pos(a0),d0
    bgt.s   +
    subi_.w #1,d0
    move.w  d0,y_pos(a0)
    sf.b    objoff_2E(a0)
+
    subi_.w #1,objoff_2A(a0)
    bne.w   JmpTo44_DisplaySprite
    tst.b   objoff_2F(a0)
    beq.s   +
-
    move.w  #MusID_FadeOut,d0
    jsr (PlayMusic).l
    move.w  #$30,objoff_2A(a0)
    move.b  #$C,routine(a0) ; => Obj5A_RingCheckTrigger
    rts
; ===========================================================================
+
    cmpi.b  #$15,mapping_frame(a0)      ; Is this the hand?
    bne.w   JmpTo63_DeleteObject        ; Branch if not
    tst.w   objoff_30(a0)
    beq.w   JmpTo63_DeleteObject
    tst.b   (SS_2p_Flag).w          ; Is this VS mode?
    beq.s   +                           ; Branch if not
    bsr.w   Obj5A_VSReset
    cmpi.b  #3,(Current_Special_Act).w
    beq.s   -
    move.w  #$A,d0
    bsr.w   Obj5A_PrintPhrase
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
+
    bsr.w   Obj5A_CreateRingReqMessage
    bra.w   JmpTo63_DeleteObject
; ===========================================================================
;loc_35A7A
Obj5A_VSReset:
    lea (SS2p_RingBuffer).w,a3
    moveq   #0,d0
    move.b  (Current_Special_Act).w,d0
    subq.w  #1,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  (Ring_count).w,(a3,d0.w)
    move.w  (Ring_count_2P).w,2(a3,d0.w)
    move.w  #0,(Ring_count).w
    move.w  #0,(Ring_count_2P).w
    moveq   #0,d0
    move.w  d0,(MainCharacter+ss_rings_base).w
    move.b  d0,(MainCharacter+ss_rings_units).w
    move.w  d0,(Sidekick+ss_rings_base).w
    move.b  d0,(Sidekick+ss_rings_units).w
    rts
; ===========================================================================
;loc_35AB6
Obj5A_CreateCheckpointWingedHand:
    move.w  #$48,d4
    tst.b   (SS_2p_Flag).w      ; Is this VS mode?
    beq.s   +                       ; Branch if not
    move.w  #$1C,d4
+
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.w   +       ; rts
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #6,routine(a1)  ; => Obj5A_Handshake
    move.l  #Obj5A_MapUnc_35E1E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialMessages,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #1,priority(a1)
    move.w  d3,x_pos(a1)
    move.w  d4,y_pos(a1)
    move.w  #$46,objoff_2A(a1)
    move.b  #$14,mapping_frame(a1)      ; Checkpoint wings
    movea.l a1,a2
    jsrto   (SSSingleObjLoad).l, JmpTo2_SSSingleObjLoad
    bne.s   +       ; rts
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #6,routine(a1)  ; => Obj5A_Handshake
    move.l  #Obj5A_MapUnc_35E1E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialMessages,1,0),art_tile(a1)
    move.b  #4,render_flags(a1)
    move.b  #0,priority(a1)
    move.w  d3,x_pos(a1)
    move.w  d4,y_pos(a1)
    move.w  d4,objoff_30(a1)            ; Target y position for handshake
    move.w  #$46,objoff_2A(a1)
    move.b  #$15,mapping_frame(a1)      ; Checkpoint hand
    cmpi.w  #6,d0                       ; Does player have enough rings?
    bne.s   +                           ; If yes, return
    st.b    objoff_2F(a1)               ; Flag for failed checkpoint
    bset    #1,render_flags(a1)         ; Point thumb down
+
    rts
; ===========================================================================
;loc_35B5A
Obj5A_TextFlyoutInit:
    subi_.w #1,objoff_2A(a0)
    bne.w   JmpTo44_DisplaySprite
    cmpi.b  #$13,mapping_frame(a0)      ; Is this the hand or wings?
    bgt.w   JmpTo63_DeleteObject        ; If yes, branch
    move.b  #8,routine(a0)          ; Obj5A_TextFlyout
    move.w  #8,objoff_14(a0)
    move.w  x_pos(a0),d1
    subi.w  #$80,d1
    move.w  y_pos(a0),d2
    subi.w  #$70,d2
    jsrto   (CalcAngle).l, JmpTo_CalcAngle
    move.b  d0,angle(a0)
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
; this makes special stage messages like "most rings wins!" fly off the screen 
;loc_35B96
Obj5A_TextFlyout:
    moveq   #0,d0
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo14_CalcSine
    muls.w  objoff_14(a0),d0
    muls.w  objoff_14(a0),d1
    asr.w   #8,d0
    asr.w   #8,d1
    add.w   d1,x_pos(a0)
    add.w   d0,y_pos(a0)
    cmpi.w  #0,x_pos(a0)
    blt.w   JmpTo63_DeleteObject
    cmpi.w  #$100,x_pos(a0)
    bgt.w   JmpTo63_DeleteObject
    cmpi.w  #0,y_pos(a0)
    blt.w   JmpTo63_DeleteObject
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
;loc_35BD6
Obj5A_PrintNumber:
    jsrto   (SSSingleObjLoad2).l, JmpTo_SSSingleObjLoad2
    bne.s   +       ; rts
    move.b  d0,mapping_frame(a1)
    move.l  #Obj5F_MapUnc_72D2,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialHUD,2,0),art_tile(a1)
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #4,routine(a1)          ; Obj5A_TextFlyoutInit
    move.b  #4,render_flags(a1)
    move.b  #1,priority(a1)
    move.w  d1,x_pos(a1)
    move.w  d2,y_pos(a1)
    move.w  #$46,objoff_2A(a1)
+
    rts
; ===========================================================================
; Subroutine to draw checkpoint or message text
; d0 = text ID
; d1 = x position of first letter
; d2 = y position
;loc_35C14
Obj5A_PrintWord:
    lea SSMessage_TextFrames(pc),a3
    adda.w  (a3,d0.w),a3
 
-   move.b  (a3)+,d0
    bmi.s   +       ; rts
    jsrto   (SSSingleObjLoad2).l, JmpTo_SSSingleObjLoad2
    bne.s   +       ; rts
    move.b  d0,mapping_frame(a1)
    move.l  #Obj5A_MapUnc_35E1E,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialMessages,2,0),art_tile(a1)
    move.b  #ObjID_SSMessage,id(a1) ; load obj5A
    move.b  #4,routine(a1)          ; Obj5A_TextFlyoutInit
    move.b  #4,render_flags(a1)
    move.b  #1,priority(a1)
    move.w  d1,x_pos(a1)
    move.w  d2,y_pos(a1)
    move.w  #$46,objoff_2A(a1)
    addq.w  #8,d1
    bra.s   -
; ===========================================================================
+
    rts
; ===========================================================================
 ; temporarily remap characters to title card letter format
 ; Characters are encoded as Aa, Bb, Cc, etc. through a macro
 charset 'a','z','A'    ; Convert to uppercase
 charset 'A',"\xD\x11\7\x11\1\x11"
 charset 'G',0  ; can't have an embedded 0 in a string
 charset 'H',"\xB\4\x11\x11\9\xF\5\8\xC\x11\3\6\2\xA\x11\x10\x11\xE\x11"
 charset '!',"\x11"
 charset '.',"\x12"
 
; Text words
;off_35C62
SSMessage_TextFrames:   offsetTable
        offsetTableEntry.w byte_35C86   ;  0
        offsetTableEntry.w byte_35C8A   ;  2
        offsetTableEntry.w byte_35C90   ;  4
        offsetTableEntry.w byte_35C96   ;  6
        offsetTableEntry.w byte_35C9A   ;  8
        offsetTableEntry.w byte_35CA1   ; $A
        offsetTableEntry.w byte_35CA8   ; $C
        offsetTableEntry.w byte_35CAD   ; $E
        offsetTableEntry.w byte_35CB3   ;$10
        offsetTableEntry.w byte_35CB9   ;$12
        offsetTableEntry.w byte_35CBF   ;$14
        offsetTableEntry.w byte_35CC4   ;$16
        offsetTableEntry.w byte_35CC8   ;$18
        offsetTableEntry.w byte_35CCE   ;$1A
        offsetTableEntry.w byte_35CD3   ;$1C
        offsetTableEntry.w byte_35CD5   ;$1E
        offsetTableEntry.w byte_35CD9   ;$20
        offsetTableEntry.w byte_35CDB   ;$22
byte_35C86: specialText "GET"
    rev02even
byte_35C8A: specialText "RINGS"
    rev02even
byte_35C90: specialText "COOL!"
    rev02even
byte_35C96: specialText "NOT"
    rev02even
byte_35C9A: specialText "ENOUGH"
    rev02even
byte_35CA1: specialText "PLAYER"
    rev02even
byte_35CA8: specialText "MOST"
    rev02even
byte_35CAD: specialText "WINS!"
    rev02even
byte_35CB3: specialText "SONIC"
    rev02even
byte_35CB9: specialText "MILES"
    rev02even
byte_35CBF: specialText "TIE!"
    rev02even
byte_35CC4: specialText "WIN"
    rev02even
byte_35CC8: specialText "TWICE"
    rev02even
byte_35CCE: specialText "ALL!"
    rev02even
byte_35CD3: specialText "!"
    rev02even
byte_35CD5: specialText "..."
    rev02even
byte_35CD9: dc.b $13,$FF                        ; VS
    rev02even
byte_35CDB: specialText "TAILS"
    even
 
 charset ; revert character set
 
; ===========================================================================
;loc_35CE2
Obj5A_CreateRingReqMessage:
    moveq   #0,d0               ; GET
    move.w  #$54,d1             ; x
    move.w  #$6C,d2             ; y
    bsr.w   Obj5A_PrintWord
    jsrto   (SSStartNewAct).l, JmpTo_SSStartNewAct
    move.w  d1,d4               ; Binary coded decimal ring requirements
    move.w  d2,d5               ; Digit count - 1 (minumum 2 digits)
    movea.w d2,a3               ; Copy of above, but in a3.
    move.w  #$80,d1             ; x position of least digit
    cmpi.w  #2,d2               ; Do we need hundreds digit?
    beq.s   +                   ; if yes, branch
    subi_.w #8,d1               ; Otherwise, move digits to the left
 
+   move.w  #$6C,d2             ; y position of digits
 
-   move.w  d4,d6               ; Copy BCD reuirements
    lsr.w   #4,d4               ; Next BCD digit
    andi.w  #$F,d6              ; Extract least digit
    move.b  d6,d0
    swap    d5
    bsr.w   Obj5A_PrintNumber
    subi_.w #8,d1               ; Set position for next digit
    swap    d5
    dbf d5,-
    
    moveq   #2,d0               ; RINGS!
    lea (SSMessage_TextPhrases).l,a2
    adda.w  (a2,d0.w),a2
    move.w  #$6C,d2             ; y
    move.w  #$84,d1             ; x
    cmpa.w  #2,a3               ; Do we need space for hundreds digit?
    bne.s   +                   ; Branch if not
    addi_.w #8,d1               ; Move digits to right
 
/   moveq   #0,d0
    move.b  (a2)+,d0
    bmi.s   +
    bsr.w   Obj5A_PrintWord
    bra.s   -
; ===========================================================================
+
    rts
; ===========================================================================
;loc_35D52
Obj5A_PrintCheckpointMessage:
    move.w  #$80,d3             ; x
    bsr.w   Obj5A_CreateCheckpointWingedHand
    cmpi.w  #1,(Player_mode).w
    ble.s   loc_35D6E
    addi.w  #palette_line_1,art_tile(a1)
    addi.w  #palette_line_1,art_tile(a2)
 
loc_35D6E:
    move.w  #$74,d1             ; x
    move.w  #$68,d2             ; y
    lea (SSMessage_TextPhrases).l,a2
    adda.w  (a2,d0.w),a2        ; Fetch phrase
    cmpi.b  #4,d0               ; Is it 'COOL!'?
    beq.s   +                   ; Branch if yes
    move.w  #$5E,d1             ; Move text otherwise
 
/   moveq   #0,d0
    move.b  (a2)+,d0
    bmi.s   ++          ; rts
    cmpi.b  #2,d0
    bne.s   +
    move.w  #$5E,d1             ; x
    move.w  #$7E,d2             ; y
+
    bsr.w   Obj5A_PrintWord
    addi_.w #8,d1
    bra.s   -
; ===========================================================================
+
    rts
; ===========================================================================
;loc_35DAA
Obj5A_PrintPhrase:
    move.w  d0,d3
    subq.w  #8,d3
    lsr.w   #1,d3
    moveq   #0,d1
    move.b  byte_35DD6(pc,d3.w),d1
    move.w  #$48,d2
    lea (SSMessage_TextPhrases).l,a2
    adda.w  (a2,d0.w),a2
 
-   moveq   #0,d0
    move.b  (a2)+,d0
    bmi.s   +           ; rts
    bsr.w   Obj5A_PrintWord
    addi_.w #8,d1
    bra.s   -
; ===========================================================================
+
    rts
; ===========================================================================
byte_35DD6:
    dc.b $48
    dc.b $44    ; 1
    dc.b $58    ; 2
    dc.b $58    ; 3
    dc.b $74    ; 4
    dc.b $3C    ; 5
    dc.b $58    ; 6
    dc.b   0    ; 7
 
; Text phrases
;off_35DDE
SSMessage_TextPhrases:  offsetTable
        offsetTableEntry.w byte_35DF6   ;  0
        offsetTableEntry.w byte_35DF7   ;  2
        offsetTableEntry.w byte_35DFA   ;  4
        offsetTableEntry.w byte_35DFC   ;  6
        offsetTableEntry.w byte_35E01   ;  8
        offsetTableEntry.w byte_35E05   ; $A
        offsetTableEntry.w byte_35E09   ; $C
        offsetTableEntry.w byte_35E0C   ; $E
        offsetTableEntry.w byte_35E0F   ;$10
        offsetTableEntry.w byte_35E11   ;$12
        offsetTableEntry.w byte_35E16   ;$14 
        offsetTableEntry.w byte_35E19   ;$16
byte_35DF6: dc.b $FF                    ; (empty)
byte_35DF7: dc.b   2,$1C,$FF            ; RINGS!
byte_35DFA: dc.b   4,$FF                ; COOL!
byte_35DFC: dc.b   6,  8,  2,$1E,$FF    ; NOT ENOUGH RINGS...
byte_35E01: dc.b  $A,$20, $A,$FF        ; PLAYER VS PLAYER
byte_35E05: dc.b  $C,  2, $E,$FF        ; MOST RINGS WINS
byte_35E09: dc.b $10, $E,$FF            ; SONIC WINS
byte_35E0C: dc.b $12, $E,$FF            ; MILES WINS
byte_35E0F: dc.b $14,$FF                ; TIE!
byte_35E11: dc.b $16,$18,$16,$1A,$FF    ; WIN TWICE WIN ALL!
byte_35E16: dc.b $22, $E,$FF            ; TAILS WINS
byte_35E19: dc.b   2,$24,$26,$1C,$FF    ; RINGS ?? ?? !
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj5A_MapUnc_35E1E: BINCLUDE "mappings/sprite/obj5A.bin"
; ===========================================================================
 
loc_35F76:
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    move.w  word_35F92(pc,d0.w),(Normal_palette_line4+$16).w
    move.w  word_35F92+2(pc,d0.w),(Normal_palette_line4+$18).w
    move.w  word_35F92+4(pc,d0.w),(Normal_palette_line4+$1A).w
    rts
; ===========================================================================
; Special Stage Chaos Emerald palette
word_35F92: BINCLUDE    "art/palettes/SS Emerald.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 59 - Emerald from Special Stage
; ----------------------------------------------------------------------------
; Sprite_35FBC:
Obj59:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj59_Index(pc,d0.w),d1
    jmp Obj59_Index(pc,d1.w)
; ===========================================================================
; off_35FCA:
Obj59_Index:    offsetTable
        offsetTableEntry.w Obj59_Init   ; 0
        offsetTableEntry.w loc_36022    ; 2
        offsetTableEntry.w loc_3533A    ; 4
        offsetTableEntry.w loc_36160    ; 6
        offsetTableEntry.w loc_36172    ; 8
; ===========================================================================
; loc_35FD4:
Obj59_Init:
    st.b    (SS_NoCheckpointMsg_flag).w
    st.b    (SS_Pause_Only_flag).w
    subi_.w #1,objoff_2A(a0)
    cmpi.w  #-$3C,objoff_2A(a0)
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    moveq   #0,d0
    move.b  (Current_Special_Stage).w,d0
    bsr.s   loc_35F76
    addq.b  #2,routine(a0)
    move.l  #Obj59_MapUnc_3625A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_SpecialEmerald,3,0),art_tile(a0)
    move.b  #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.w  #$36,objoff_30(a0)
    move.b  #$40,angle(a0)
    bsr.w   loc_3529C
 
loc_36022:
    bsr.w   loc_360F0
    bsr.w   loc_3512A
    bsr.w   loc_3603C
    lea (off_36228).l,a1
    bsr.w   loc_3539E
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
 
loc_3603C:
    move.w  d7,-(sp)
    moveq   #0,d2
    moveq   #0,d3
    moveq   #0,d4
    moveq   #0,d5
    moveq   #0,d6
    moveq   #0,d7
    movea.l (SS_CurrentPerspective).w,a1
    adda_.l #2,a1
    move.w  objoff_30(a0),d0
    subq.w  #1,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    move.b  (a1,d0.w),d2
    move.b  1(a1,d0.w),d3
    move.b  2(a1,d0.w),d4
    move.b  3(a1,d0.w),d5
    move.w  d5,d6
    swap    d5
    move.w  d6,d5
    move.w  d4,d6
    swap    d4
    move.w  d6,d4
    bpl.s   loc_36088
    cmpi.b  #$48,d3
    blo.s   loc_36088
    ext.w   d3
 
loc_36088:
    move.w  d4,d6
    add.w   d4,d4
    add.w   d6,d4
    lsr.w   #2,d4
    move.w  d5,d6
    add.w   d5,d5
    add.w   d6,d5
    lsr.w   #2,d5
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo14_CalcSine
    muls.w  d4,d1
    muls.w  d5,d0
    asr.l   #8,d0
    asr.l   #8,d1
    add.w   d2,d1
    add.w   d3,d0
    move.w  d1,x_pos(a0)
    move.w  d0,y_pos(a0)
    move.b  d1,objoff_3A(a0)
    move.b  d0,objoff_3B(a0)
    swap    d4
    swap    d5
    movea.l objoff_34(a0),a1 ; a1=object
    move.b  angle(a0),d0
    jsrto   (CalcSine).l, JmpTo14_CalcSine
    move.w  d4,d6
    lsr.w   #2,d6
    add.w   d6,d4
    muls.w  d4,d1
    move.w  d5,d6
    asr.w   #2,d6
    add.w   d6,d5
    muls.w  d5,d0
    asr.l   #8,d0
    asr.l   #8,d1
    add.w   d2,d1
    add.w   d3,d0
    move.w  d1,x_pos(a1)
    move.w  d0,y_pos(a1)
    move.w  (sp)+,d7
    rts
; ===========================================================================
 
loc_360F0:
    cmpi.b  #3,anim(a0)
    blo.s   return_36140
    tst.b   objoff_3E(a0)
    bne.s   loc_3610C
    move.w  #MusID_FadeOut,d0
    jsr (PlayMusic).l
    st  objoff_3E(a0)
 
loc_3610C:
    cmpi.b  #6,anim(a0)
    blo.s   return_36140
    move.w  (Ring_count).w,d2
    add.w   (Ring_count_2P).w,d2
    cmp.w   (SS_Ring_Requirement).w,d2
    blt.s   loc_36142
    cmpi.b  #9,anim(a0)
    blo.s   return_36140
    move.w  #$63,objoff_2A(a0)
    move.b  #8,routine(a0)
    move.w  #MusID_Emerald,d0
    jsr (PlayMusic).l
 
return_36140:
    rts
; ===========================================================================
 
loc_36142:
    move.l  #0,(SS_New_Speed_Factor).w
    move.b  #6,routine(a0)
    move.w  #$4F,objoff_2A(a0)
    move.w  #6,d0
    bsr.w   loc_35D6E
    rts
; ===========================================================================
 
loc_36160:
    subi_.w #1,objoff_2A(a0)
    bpl.w   JmpTo44_DisplaySprite
    st.b    (SS_Check_Rings_flag).w
    bra.w   SSClearObjs
; ===========================================================================
 
loc_36172:
    subi_.w #1,objoff_2A(a0)
    bpl.s   loc_361A4
    moveq   #0,d0
    move.b  (Current_Special_Stage).w,d0
    lea (Got_Emeralds_array).w,a0
    st  (a0,d0.w)
    st  (Got_Emerald).w
    addi_.b #1,(Current_Special_Stage).w
    addi_.b #1,(Emerald_count).w
    st.b    (SS_Check_Rings_flag).w
    bsr.w   SSClearObjs
    move.l  (sp)+,d0
    rts
; ===========================================================================
 
loc_361A4:
    addi_.b #1,objoff_3C(a0)
    moveq   #0,d0
    moveq   #0,d2
    move.b  objoff_3B(a0),d2
    move.b  objoff_3C(a0),d0
    lsr.w   #2,d0
    andi.w  #3,d0
    add.b   byte_361C8(pc,d0.w),d2
    move.w  d2,y_pos(a0)
    bra.w   JmpTo44_DisplaySprite
; ===========================================================================
byte_361C8:
    dc.b $FF
    dc.b   0    ; 1
    dc.b   1    ; 2
    dc.b   0    ; 3
; ===========================================================================
;loc_361CC
SSClearObjs:
    movea.l #(SS_Object_RAM&$FFFFFF),a1
 
    move.w  #(SS_Object_RAM_End-SS_Object_RAM)/$10-1,d0
    moveq   #0,d1
 
loc_361D8:
    rept $10/4
    move.l  d1,(a1)+
    endm
    dbf d0,loc_361D8
.c := ((SS_Object_RAM_End-SS_Object_RAM)#$10)/4
    if .c
    rept .c
    move.l  d1,(a1)+
    endm
    endif
.c := ((SS_Object_RAM_End-SS_Object_RAM)#$10)&2
    if .c
    rept .c
    move.w  d1,(a1)+
    endm
    endif
 
    ; Bug: The '+4' shouldn't be here; clearRAM accidentally clears an additional 4 bytes
    clearRAM SS_Sprite_Table,SS_Sprite_Table_End+4
 
    rts
; ===========================================================================
    ; unused/dead code ; a0=object
    cmpi.b  #$B,(SSTrack_drawing_index).w
    blo.s   loc_36208
    subi.l  #$4445,objoff_30(a0)
    bra.s   loc_36210
; ---------------------------------------------------------------------------
loc_36208:
    subi.l  #$4444,objoff_30(a0)
loc_36210:
    move.w  objoff_30(a0),d0
    cmpi.w  #$1D,d0
    ble.s   +
    moveq   #$1E,d0
+
    lea_    byte_35180,a1
    move.b  (a1,d0.w),anim(a0)
    rts
    ; end of unused code
 
; ===========================================================================
; animation script for object 59
off_36228:  offsetTable
        offsetTableEntry.w byte_3623C   ; 0
        offsetTableEntry.w byte_3623F   ; 1
        offsetTableEntry.w byte_36242   ; 2
        offsetTableEntry.w byte_36245   ; 3
        offsetTableEntry.w byte_36248   ; 4
        offsetTableEntry.w byte_3624B   ; 5
        offsetTableEntry.w byte_3624E   ; 6
        offsetTableEntry.w byte_36251   ; 7
        offsetTableEntry.w byte_36254   ; 8
        offsetTableEntry.w byte_36257   ; 9
byte_3623C:
    dc.b  $B,  0,$FF
    rev02even
byte_3623F:
    dc.b  $B,  1,$FF
    rev02even
byte_36242:
    dc.b  $B,  2,$FF
    rev02even
byte_36245:
    dc.b  $B,  3,$FF
    rev02even
byte_36248:
    dc.b  $B,  4,$FF
    rev02even
byte_3624B:
    dc.b  $B,  5,$FF
    rev02even
byte_3624E:
    dc.b  $B,  6,$FF
    rev02even
byte_36251:
    dc.b  $B,  7,$FF
    rev02even
byte_36254:
    dc.b  $B,  8,$FF
    rev02even
byte_36257:
    dc.b  $B,  9,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj59_MapUnc_3625A: BINCLUDE "mappings/sprite/obj59.bin"
 
; animation script:
; off_362D2:
Ani_obj5B_obj60:offsetTable
        offsetTableEntry.w byte_362E8   ;  0
        offsetTableEntry.w byte_362EE   ;  1
        offsetTableEntry.w byte_362F4   ;  2
        offsetTableEntry.w byte_362FA   ;  3
        offsetTableEntry.w byte_36300   ;  4
        offsetTableEntry.w byte_36306   ;  5
        offsetTableEntry.w byte_3630C   ;  6
        offsetTableEntry.w byte_36312   ;  7
        offsetTableEntry.w byte_36318   ;  8
        offsetTableEntry.w byte_3631E   ;  9
        offsetTableEntry.w byte_36324   ; $A
byte_362E8: dc.b   5,  0, $A,$14, $A,$FF
    rev02even
byte_362EE: dc.b   5,  1, $B,$15, $B,$FF
    rev02even
byte_362F4: dc.b   5,  2, $C,$16, $C,$FF
    rev02even
byte_362FA: dc.b   5,  3, $D,$17, $D,$FF
    rev02even
byte_36300: dc.b   5,  4, $E,$18, $E,$FF
    rev02even
byte_36306: dc.b   5,  5, $F,$19, $F,$FF
    rev02even
byte_3630C: dc.b   5,  6,$10,$1A,$10,$FF
    rev02even
byte_36312: dc.b   5,  7,$11,$1B,$11,$FF
    rev02even
byte_36318: dc.b   5,  8,$12,$1C,$12,$FF
    rev02even
byte_3631E: dc.b   5,  9,$13,$1D,$13,$FF
    rev02even
byte_36324: dc.b   1,$1E,$1F,$20,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj5A_Obj5B_Obj60_MapUnc_3632A: BINCLUDE "mappings/sprite/obj5A_5B_60.bin"
 
; animation script:
; off_364CE:
Ani_obj61:  offsetTable
        offsetTableEntry.w byte_364E4   ;  0
        offsetTableEntry.w byte_364E7   ;  1
        offsetTableEntry.w byte_364EA   ;  2
        offsetTableEntry.w byte_364ED   ;  3
        offsetTableEntry.w byte_364F0   ;  4
        offsetTableEntry.w byte_364F3   ;  5
        offsetTableEntry.w byte_364F6   ;  6
        offsetTableEntry.w byte_364F9   ;  7
        offsetTableEntry.w byte_364FC   ;  8
        offsetTableEntry.w byte_364FF   ;  9
        offsetTableEntry.w byte_36502   ; $A
byte_364E4: dc.b  $B,  0,$FF
    rev02even
byte_364E7: dc.b  $B,  1,$FF
    rev02even
byte_364EA: dc.b  $B,  2,$FF
    rev02even
byte_364ED: dc.b  $B,  3,$FF
    rev02even
byte_364F0: dc.b  $B,  4,$FF
    rev02even
byte_364F3: dc.b  $B,  5,$FF
    rev02even
byte_364F6: dc.b  $B,  6,$FF
    rev02even
byte_364F9: dc.b  $B,  7,$FF
    rev02even
byte_364FC: dc.b  $B,  8,$FF
    rev02even
byte_364FF: dc.b  $B,  9,$FF
    rev02even
byte_36502: dc.b   2, $A, $B, $C,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj61_MapUnc_36508: BINCLUDE "mappings/sprite/obj61.bin"
; ===========================================================================
 
JmpTo44_DisplaySprite 
    jmp (DisplaySprite).l
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo63_DeleteObject 
    jmp (DeleteObject).l
JmpTo24_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo_SSStartNewAct 
    jmp (SSStartNewAct).l
JmpTo_CalcAngle 
    jmp (CalcAngle).l
JmpTo14_CalcSine 
    jmp (CalcSine).l
JmpTo7_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
JmpTo_SSSingleObjLoad2 
    jmp (SSSingleObjLoad2).l
JmpTo2_SSSingleObjLoad 
    jmp (SSSingleObjLoad).l
 
    align 4
    endif
; ===========================================================================
 
 
 
 
; ---------------------------------------------------------------------------
; LoadSubObject
; loads information from a sub-object into this object a0
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_365F4:
LoadSubObject:
    moveq   #0,d0
    move.b  subtype(a0),d0
; loc_365FA:
LoadSubObject_Part2:
    move.w  SubObjData_Index(pc,d0.w),d0
    lea SubObjData_Index(pc,d0.w),a1
; loc_36602:
LoadSubObject_Part3:
    move.l  (a1)+,mappings(a0)
    move.w  (a1)+,art_tile(a0)
    jsr (Adjust2PArtPointer).l
    move.b  (a1)+,d0
    or.b    d0,render_flags(a0)
    move.b  (a1)+,priority(a0)
    move.b  (a1)+,width_pixels(a0)
    move.b  (a1),collision_flags(a0)
    addq.b  #2,routine(a0)
    rts
 
; ===========================================================================
; table that maps from the subtype ID to which address to load the data from
; the format of the data there is
;   dc.l Pointer_To_Sprite_Mappings
;   dc.w VRAM_Location
;   dc.b render_flags, priority, width_pixels, collision_flags
; 
; for whatever reason, only Obj8C and later have entries in this table
 
; off_36628:
SubObjData_Index: offsetTable
    offsetTableEntry.w Obj8C_SubObjData ; $0
    offsetTableEntry.w Obj8D_SubObjData ; $2
    offsetTableEntry.w Obj90_SubObjData ; $4
    offsetTableEntry.w Obj90_SubObjData2    ; $6
    offsetTableEntry.w Obj91_SubObjData ; $8
    offsetTableEntry.w Obj92_SubObjData ; $A
    offsetTableEntry.w Invalid_SubObjData   ; $C
    offsetTableEntry.w Obj94_SubObjData ; $E
    offsetTableEntry.w Obj94_SubObjData2    ; $10
    offsetTableEntry.w Obj99_SubObjData2    ; $12
    offsetTableEntry.w Obj99_SubObjData ; $14
    offsetTableEntry.w Obj9A_SubObjData ; $16
    offsetTableEntry.w Obj9B_SubObjData ; $18
    offsetTableEntry.w Obj9C_SubObjData ; $1A
    offsetTableEntry.w Obj9A_SubObjData2    ; $1C
    offsetTableEntry.w Obj9D_SubObjData ; $1E
    offsetTableEntry.w Obj9D_SubObjData2    ; $20
    offsetTableEntry.w Obj9E_SubObjData ; $22
    offsetTableEntry.w Obj9F_SubObjData ; $24
    offsetTableEntry.w ObjA0_SubObjData ; $26
    offsetTableEntry.w ObjA1_SubObjData ; $28
    offsetTableEntry.w ObjA2_SubObjData ; $2A
    offsetTableEntry.w ObjA3_SubObjData ; $2C
    offsetTableEntry.w ObjA4_SubObjData ; $2E
    offsetTableEntry.w ObjA4_SubObjData2    ; $30
    offsetTableEntry.w ObjA5_SubObjData ; $32
    offsetTableEntry.w ObjA6_SubObjData ; $34
    offsetTableEntry.w ObjA7_SubObjData ; $36
    offsetTableEntry.w ObjA7_SubObjData2    ; $38
    offsetTableEntry.w ObjA8_SubObjData ; $3A
    offsetTableEntry.w ObjA8_SubObjData2    ; $3C
    offsetTableEntry.w ObjA7_SubObjData3    ; $3E
    offsetTableEntry.w ObjAC_SubObjData ; $40
    offsetTableEntry.w ObjAD_SubObjData ; $42
    offsetTableEntry.w ObjAD_SubObjData2    ; $44
    offsetTableEntry.w ObjAD_SubObjData3    ; $46
    offsetTableEntry.w ObjAF_SubObjData2    ; $48
    offsetTableEntry.w ObjAF_SubObjData ; $4A
    offsetTableEntry.w ObjB0_SubObjData ; $4C
    offsetTableEntry.w ObjB1_SubObjData ; $4E
    offsetTableEntry.w ObjB2_SubObjData ; $50
    offsetTableEntry.w ObjB2_SubObjData ; $52
    offsetTableEntry.w ObjB2_SubObjData ; $54
    offsetTableEntry.w ObjBC_SubObjData2    ; $56
    offsetTableEntry.w ObjBC_SubObjData2    ; $58
    offsetTableEntry.w ObjB3_SubObjData ; $5A
    offsetTableEntry.w ObjB2_SubObjData2    ; $5C
    offsetTableEntry.w ObjB3_SubObjData ; $5E
    offsetTableEntry.w ObjB3_SubObjData ; $60
    offsetTableEntry.w ObjB3_SubObjData ; $62
    offsetTableEntry.w ObjB4_SubObjData ; $64
    offsetTableEntry.w ObjB5_SubObjData ; $66
    offsetTableEntry.w ObjB5_SubObjData ; $68
    offsetTableEntry.w ObjB6_SubObjData ; $6A
    offsetTableEntry.w ObjB6_SubObjData ; $6C
    offsetTableEntry.w ObjB6_SubObjData ; $6E
    offsetTableEntry.w ObjB6_SubObjData ; $70
    offsetTableEntry.w ObjB7_SubObjData ; $72
    offsetTableEntry.w ObjB8_SubObjData ; $74
    offsetTableEntry.w ObjB9_SubObjData ; $76
    offsetTableEntry.w ObjBA_SubObjData ; $78
    offsetTableEntry.w ObjBB_SubObjData ; $7A
    offsetTableEntry.w ObjBC_SubObjData2    ; $7C
    offsetTableEntry.w ObjBD_SubObjData ; $7E
    offsetTableEntry.w ObjBD_SubObjData ; $80
    offsetTableEntry.w ObjBE_SubObjData ; $82
    offsetTableEntry.w ObjBE_SubObjData2    ; $84
    offsetTableEntry.w ObjC0_SubObjData ; $86
    offsetTableEntry.w ObjC1_SubObjData ; $88
    offsetTableEntry.w ObjC2_SubObjData ; $8A
    offsetTableEntry.w Invalid_SubObjData2  ; $8C
    offsetTableEntry.w ObjB8_SubObjData2    ; $8E
    offsetTableEntry.w ObjC3_SubObjData ; $90
    offsetTableEntry.w ObjC5_SubObjData ; $92
    offsetTableEntry.w ObjC5_SubObjData2    ; $94
    offsetTableEntry.w ObjC5_SubObjData3    ; $96
    offsetTableEntry.w ObjC5_SubObjData3    ; $98
    offsetTableEntry.w ObjC5_SubObjData3    ; $9A
    offsetTableEntry.w ObjC5_SubObjData3    ; $9C
    offsetTableEntry.w ObjC5_SubObjData3    ; $9E
    offsetTableEntry.w ObjC6_SubObjData2    ; $A0
    offsetTableEntry.w ObjC5_SubObjData4    ; $A2
    offsetTableEntry.w ObjAF_SubObjData3    ; $A4
    offsetTableEntry.w ObjC6_SubObjData3    ; $A6
    offsetTableEntry.w ObjC6_SubObjData4    ; $A8
    offsetTableEntry.w ObjC6_SubObjData ; $AA
    offsetTableEntry.w ObjC8_SubObjData ; $AC
; ===========================================================================
; ---------------------------------------------------------------------------
; Get Orientation To Player
; Returns the horizontal and vertical distances of the closest player object.
;
; input variables:
;  a0 = object
;
; returns:
;  a1 = address of closest player character
;  d0 = 0 if player is left from object, 2 if right
;  d1 = 0 if player is above object, 2 if below
;  d2 = closest character's horizontal distance to object
;  d3 = closest character's vertical distance to object
;
; writes:
;  d0, d1, d2, d3, d4, d5
;  a1
;  a2 = sidekick
; ---------------------------------------------------------------------------
;loc_366D6:
Obj_GetOrientationToPlayer:
    moveq   #0,d0
    moveq   #0,d1
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a0),d2
    sub.w   x_pos(a1),d2
    mvabs.w d2,d4   ; absolute horizontal distance to main character
    lea (Sidekick).w,a2 ; a2=character
    move.w  x_pos(a0),d3
    sub.w   x_pos(a2),d3
    mvabs.w d3,d5   ; absolute horizontal distance to sidekick
    cmp.w   d5,d4   ; get shorter distance
    bls.s   +   ; branch, if main character is closer
    ; if sidekick is closer
    movea.l a2,a1
    move.w  d3,d2
+
    tst.w   d2  ; is player to enemy's left?
    bpl.s   +   ; if not, branch
    addq.w  #2,d0
+
    move.w  y_pos(a0),d3
    sub.w   y_pos(a1),d3    ; vertical distance to closest character
    bhs.s   +   ; branch, if enemy is under
    addq.w  #2,d1
+
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Cap Object Speed
; Prevents an object from going over a specified speed value.
;
; input variables:
;  d0 = max x velocity
;  d1 = max y velocity
;
;  a0 = object
;
; writes:
;  d0, d1, d2, d3
; ---------------------------------------------------------------------------
; loc_3671A:
Obj_CapSpeed:
    move.w  x_vel(a0),d2
    bpl.s   +   ; branch, if object is moving right
    ; going left
    neg.w   d0  ; set opposite direction
    cmp.w   d0,d2   ; is object's current x velocity lower than max?
    bhs.s   ++  ; if yes, branch
    move.w  d0,d2   ; else, cap speed
    bra.w   ++
; ===========================================================================
+   ; going right
    cmp.w   d0,d2   ; is object's current x velocity lower than max?
    bls.s   +   ; if yes, branch
    move.w  d0,d2   ; else, cap speed
+
    move.w  y_vel(a0),d3
    bpl.s   +   ; branch, if object is moving down
    ; going up
    neg.w   d1  ; set opposite direction
    cmp.w   d1,d3   ; is object's current y velocity lower than max?
    bhs.s   ++  ; if yes, branch
    move.w  d1,d3   ; else, cap speed
    bra.w   ++
; ===========================================================================
+   ; going down
    cmp.w   d1,d3   ; is object's current y velocity lower than max?
    bls.s   +   ; if yes, branch
    move.w  d1,d3   ; else, cap speed
+   ; update speed
    move.w  d2,x_vel(a0)
    move.w  d3,y_vel(a0)
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Movement Stop
; Stops an object's movement.
;
; input variables:
;  a0 = object
;
; writes:
;  d0 = 0
; ---------------------------------------------------------------------------
;loc_36754:
Obj_MoveStop:
    moveq   #0,d0
    move.w  d0,x_vel(a0)
    move.w  d0,y_vel(a0)
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Align Child XY
; Moves a referenced object to the position of the current object with
; variable x and y offset.
;
; input variables:
;  d0 = x offset
;  d1 = y offset
;
;  a0 = parent object
;  a1 = child object
;
; writes:
;  d2 = new x position
;  d3 = new y position
; ---------------------------------------------------------------------------
;loc_36760:
Obj_AlignChildXY:
    move.w  x_pos(a0),d2
    add.w   d0,d2
    move.w  d2,x_pos(a1)
    move.w  y_pos(a0),d3
    add.w   d1,d3
    move.w  d3,y_pos(a1)
    rts
; ===========================================================================
 
loc_36776:
    move.w  (Tornado_Velocity_X).w,d0
    add.w   d0,x_pos(a0)
    move.w  (Tornado_Velocity_Y).w,d0
    add.w   d0,y_pos(a0)
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Delete If Behind Screen
; deletes an object if it scrolls off the left side of the screen
;
; input variables:
;  a0 = object
;
; writes:
;  d0
; ---------------------------------------------------------------------------
;loc_36788:
Obj_DeleteBehindScreen:
    tst.w   (Two_player_mode).w
    beq.s   +
    jmp (DisplaySprite).l
+
    ; when not in two player mode
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    bmi.w   JmpTo64_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
loc_367AA:
    move.b  render_flags(a0),d0
    if gameRevision<2
    andi.b  #$FC,d0
    move.b  status(a0),d2
    andi.b  #$FC,d2
    move.b  render_flags(a1),d1
    andi.b  #3,d1
    else
    ; now causes a bug where some sprites are displayed backwards (Silver Sonic's sparks and Grabber's legs)
    andi.b  #$FD,d0
    move.b  status(a0),d2
    andi.b  #$FD,d2
    move.b  render_flags(a1),d1
    andi.b  #2,d1
    endif
    or.b    d1,d0
    or.b    d1,d2
    move.b  d0,render_flags(a0)
    move.b  d2,status(a0)
    rts
; ===========================================================================
 
;loc_367D0:
LoadChildObject:
    jsr (SingleObjLoad2).l
    bne.s   +   ; rts
    move.w  (a2)+,d0
    move.w  a1,(a0,d0.w) ; store pointer to child in parent's SST
    _move.b (a2)+,id(a1) ; load obj
    move.b  (a2)+,subtype(a1)
    move.w  a0,objoff_2C(a1) ; store pointer to parent in child's SST
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
+
    rts
; ===========================================================================
    ; unused/dead code ; a0=object
    bsr.w   Obj_GetOrientationToPlayer
    bclr    #0,render_flags(a0)
    bclr    #0,status(a0)
    tst.w   d0
    beq.s   return_36818
    bset    #0,render_flags(a0)
    bset    #0,status(a0)
 
return_36818:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Create Projectiles
; Creates a specified number of generic moving projectiles.
; 
; input variables:
;  d2 = subtype, used for object initialization (refer to LoadSubObject)
;  d6 = number of projectiles to create -1
;
;  a2 = projectile stat list
;   format:
;   dc.b x_offset, y_offset, x_vel, y_vel, mapping_frame, render_flags
;
; writes:
;  d0
;  d1 = index in list
;  d6 = num objects
;
;  a1 = addres of new projectile
;  a3 = movement type (ObjectMove)
; ---------------------------------------------------------------------------
;loc_3681A:
Obj_CreateProjectiles:
    moveq   #0,d1
    ; loop creates d6+1 projectiles
-
    jsr (SingleObjLoad2).l
    bne.s   return_3686E
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  d2,subtype(a1)  ; used for object initialization
    move.w  x_pos(a0),x_pos(a1) ; align objects
    move.w  y_pos(a0),y_pos(a1)
    lea (ObjectMove).l,a3   ; set movement type
    move.l  a3,objoff_2A(a1)
    lea (a2,d1.w),a3    ; get address in list
    move.b  (a3)+,d0    ; get x offset
    ext.w   d0
    add.w   d0,x_pos(a1)
    move.b  (a3)+,d0    ; get y offset
    ext.w   d0
    add.w   d0,y_pos(a1)
    move.b  (a3)+,x_vel(a1) ; set movement values
    move.b  (a3)+,y_vel(a1)
    move.b  (a3)+,mapping_frame(a1) ; set map frame
    move.b  (a3)+,render_flags(a1)  ; set render flags
    addq.w  #6,d1
    dbf d6,-
 
return_3686E:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Subroutine to animate a sprite using an animation script
; Works like AnimateSprite, except for:
; * this function does not change render flags to match orientation given by
;   the status byte;
; * the function returns 0 on d0 if it changed the mapping frame, or 1 if an
;   end-of-animation flag was found ($FC to $FF);
; * it is only used by Mecha Sonic;
; * some of the end-of-animation flags work differently.
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_36870:
AnimateSprite_Checked:
    moveq   #0,d0
    move.b  anim(a0),d0     ; move animation number to d0
    cmp.b   next_anim(a0),d0    ; is animation set to change?
    beq.s   AnimChk_Run     ; if not, branch
    move.b  d0,next_anim(a0)    ; set next anim to current current
    move.b  #0,anim_frame(a0)   ; reset animation
    move.b  #0,anim_frame_duration(a0)  ; reset frame duration
 
AnimChk_Run:
    subq.b  #1,anim_frame_duration(a0)  ; subtract 1 from frame duration
    bpl.s   AnimChk_Wait    ; if time remains, branch
    add.w   d0,d0
    adda.w  (a1,d0.w),a1    ; calculate address of appropriate animation script
    move.b  (a1),anim_frame_duration(a0)    ; load frame duration
    moveq   #0,d1
    move.b  anim_frame(a0),d1   ; load current frame number
    move.b  1(a1,d1.w),d0       ; read sprite number from script
    bmi.s   AnimChk_End_FF      ; if animation is complete, branch
;loc_368A8
AnimChk_Next:
    move.b  d0,mapping_frame(a0)    ; load sprite number
    addq.b  #1,anim_frame(a0)   ; next frame number
;loc_368B0
AnimChk_Wait:
    moveq   #0,d0   ; Return 0
    rts
; ---------------------------------------------------------------------------
;loc_368B4
AnimChk_End_FF:
    addq.b  #1,d0       ; is the end flag = $FF ?
    bne.s   AnimChk_End_FE  ; if not, branch
    move.b  #0,anim_frame(a0)   ; restart the animation
    move.b  1(a1),d0    ; read sprite number
    bsr.s   AnimChk_Next
    moveq   #1,d0   ; Return 1
    rts
; ---------------------------------------------------------------------------
;loc_368C8
AnimChk_End_FE:
    addq.b  #1,d0       ; is the end flag = $FE ?
    bne.s   AnimChk_End_FD  ; if not, branch
    addq.b  #2,routine(a0)  ; jump to next routine
    move.b  #0,anim_frame_duration(a0)
    addq.b  #1,anim_frame(a0)
    moveq   #1,d0   ; Return 1
    rts
; ---------------------------------------------------------------------------
;loc_368DE
AnimChk_End_FD:
    addq.b  #1,d0       ; is the end flag = $FD ?
    bne.s   AnimChk_End_FC  ; if not, branch
    addq.b  #2,routine_secondary(a0)    ; jump to next routine
    moveq   #1,d0   ; Return 1
    rts
; ---------------------------------------------------------------------------
;loc_368EA
AnimChk_End_FC:
    addq.b  #1,d0       ; is the end flag = $FC ?
    bne.s   AnimChk_End ; if not, branch
    move.b  #1,anim_frame_duration(a0)  ; Force frame duration to 1
    moveq   #1,d0   ; Return 1
 
AnimChk_End:
    rts
; ===========================================================================
; ---------------------------------------------------------------------------
; Delete If Off-Screen
; deletes an object if it is too far away from the screen
;
; input variables:
;  a0 = object
;
; writes:
;  d0
; ---------------------------------------------------------------------------
;loc_368F8:
Obj_DeleteOffScreen:
    tst.w   (Two_player_mode).w
    beq.s   +
    jmp (DisplaySprite).l
+
    ; when not in two player mode
    move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   JmpTo64_DeleteObject
    jmp (DisplaySprite).l
; ===========================================================================
 
    if removeJmpTos
JmpTo65_DeleteObject 
    endif
 
JmpTo64_DeleteObject 
    jmp (DeleteObject).l
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 8C - Whisp (blowfly badnik) from ARZ
; ----------------------------------------------------------------------------
; Sprite_36924:
Obj8C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj8C_Index(pc,d0.w),d1
    jmp Obj8C_Index(pc,d1.w)
; ===========================================================================
; off_36932: Obj8C_States:
Obj8C_Index:    offsetTable
        offsetTableEntry.w Obj8C_Init   ; 0
        offsetTableEntry.w loc_3694E    ; 1
        offsetTableEntry.w loc_369A8    ; 2
        offsetTableEntry.w loc_36958    ; 3
        offsetTableEntry.w loc_36A26    ; 4
; ===========================================================================
; loc_3693C:
Obj8C_Init:
    bsr.w   LoadSubObject
    move.b  #$10,objoff_2A(a0)
    move.b  #4,objoff_2B(a0)
    rts
; ===========================================================================
 
loc_3694E:
    tst.b   render_flags(a0)
    bmi.s   loc_36970
    bra.w   Obj8C_Animate
; ===========================================================================
 
loc_36958:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_36970
; loc_3695E:
Obj8C_Animate:
    lea (Ani_obj8C).l,a1
    jsr (AnimateSprite).l
    jmp (MarkObjGone).l
; ===========================================================================
 
loc_36970:
    subq.b  #1,objoff_2B(a0)
    bpl.s   loc_36996
    move.b  #8,routine(a0)
    bclr    #0,status(a0)
    clr.w   y_vel(a0)
    move.w  #-$200,x_vel(a0)
    move.w  #-$200,y_vel(a0)
    bra.w   loc_36A26
; ===========================================================================
 
loc_36996:
    move.b  #4,routine(a0)
    move.w  #-$100,y_vel(a0)
    move.b  #$60,objoff_2A(a0)
 
loc_369A8:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_369F8
    bsr.w   Obj_GetOrientationToPlayer
    bclr    #0,status(a0)
    tst.w   d0
    beq.s   loc_369C2
    bset    #0,status(a0)
 
loc_369C2:
    move.w  word_369F4(pc,d0.w),d2
    add.w   d2,x_vel(a0)
    move.w  word_369F4(pc,d1.w),d2
    add.w   d2,y_vel(a0)
    move.w  #$200,d0
    move.w  d0,d1
    bsr.w   Obj_CapSpeed
    jsr (ObjectMove).l
    lea (Ani_obj8C).l,a1
    jsr (AnimateSprite).l
    jmp (MarkObjGone).l
; ===========================================================================
word_369F4:
    dc.w -$10
    dc.w  $10
; ===========================================================================
 
loc_369F8:
    move.b  #6,routine(a0)
    jsr (RandomNumber).l
    move.l  (RNG_seed).w,d0
    andi.b  #$1F,d0
    move.b  d0,objoff_2A(a0)
    bsr.w   Obj_MoveStop
    lea (Ani_obj8C).l,a1
    jsr (AnimateSprite).l
    jmp (MarkObjGone).l
; ===========================================================================
 
loc_36A26:
    jsr (ObjectMove).l
    lea (Ani_obj8C).l,a1
    jsr (AnimateSprite).l
    jmp (MarkObjGone).l
; ===========================================================================
; off_36A3E:
Obj8C_SubObjData:
    subObjData Obj8C_MapUnc_36A4E,make_art_tile(ArtTile_ArtNem_Whisp,1,1),4,4,$C,$B
; animation script
; off_36A48:
Ani_obj8C:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,$FF
        even
; ------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------
Obj8C_MapUnc_36A4E: BINCLUDE "mappings/sprite/obj8C.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 8D - Grounder in wall, from ARZ
; ----------------------------------------------------------------------------
; Sprite_36A76:
Obj8D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj8D_Index(pc,d0.w),d1
    jmp Obj8D_Index(pc,d1.w)
; ===========================================================================
; off_36A84:
Obj8D_Index:    offsetTable
        offsetTableEntry.w Obj8D_Init       ;  0
        offsetTableEntry.w loc_36ADC        ;  2
        offsetTableEntry.w Obj8D_Animate    ;  4
        offsetTableEntry.w loc_36B0E        ;  6
        offsetTableEntry.w loc_36B34        ;  8
        offsetTableEntry.w loc_36B6A        ; $A
; ===========================================================================
; loc_36A90:
Obj8D_Init:
    bsr.w   LoadSubObject
    bclr    #1,render_flags(a0)
    beq.s   +
    bclr    #1,status(a0)
    andi.w  #drawing_mask,art_tile(a0)
+
    move.b  #$14,y_radius(a0)
    move.b  #$10,x_radius(a0)
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   +
    add.w   d1,y_pos(a0)
    move.w  #0,y_vel(a0)
+
    _move.b id(a0),d0
    subi.b  #ObjID_GrounderInWall,d0
    beq.w   loc_36C64
    move.b  #6,routine(a0)
    rts
; ===========================================================================
 
loc_36ADC:
    bsr.w   Obj_GetOrientationToPlayer
    abs.w   d2
    cmpi.w  #$60,d2
    bls.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    st  objoff_2B(a0)
    bsr.w   loc_36C2C
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_36B00:
Obj8D_Animate:
    lea (Ani_obj8D_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36B0E:
    addq.b  #2,routine(a0)
    bsr.w   Obj_GetOrientationToPlayer
    move.w  Obj8D_Directions(pc,d0.w),x_vel(a0)
    bclr    #0,status(a0)
    tst.w   d0
    beq.s   +
    bset    #0,status(a0)
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; word_36B30:
Obj8D_Directions:
    dc.w -$100
    dc.w  $100  ; 1
; ===========================================================================
 
loc_36B34:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jsr (ObjCheckFloorDist).l
    cmpi.w  #-1,d1
    blt.s   loc_36B5C
    cmpi.w  #$C,d1
    bge.s   loc_36B5C
    add.w   d1,y_pos(a0)
    lea (Ani_obj8D_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36B5C:
    addq.b  #2,routine(a0)
    move.b  #$3B,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36B6A:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_36B74
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36B74:
    move.b  #8,routine(a0)
    neg.w   x_vel(a0)
    bchg    #0,status(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 8F - Wall behind which Grounder hides, from ARZ
; ----------------------------------------------------------------------------
; Sprite_36B88:
Obj8F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj8F_Index(pc,d0.w),d1
    jmp Obj8F_Index(pc,d1.w)
; ===========================================================================
; off_36B96:
Obj8F_Index:    offsetTable
        offsetTableEntry.w Obj8F_Init   ; 0
        offsetTableEntry.w loc_36BA6    ; 2
        offsetTableEntry.w Obj8F_Move   ; 4
; ===========================================================================
; loc_36B9C:
Obj8F_Init:
    bsr.w   LoadSubObject
    clr.w   art_tile(a0)
    rts
; ===========================================================================
 
loc_36BA6:
    movea.w objoff_2C(a0),a1 ; a1=object
    tst.b   objoff_2B(a1)
    bne.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  objoff_2E(a0),d0
    move.b  Obj8F_Directions(pc,d0.w),x_vel(a0)
    move.b  Obj8F_Directions+1(pc,d0.w),y_vel(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; byte_36BCC:
Obj8F_Directions:
    dc.b  1,-2  ; 0
    dc.b  1,-1  ; 2
    dc.b -1,-2  ; 4
    dc.b -1,-1  ; 6
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 90 - Rocks thrown by Grounder behind wall, from ARZ
; ----------------------------------------------------------------------------
; Sprite_36BD4:
Obj90:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj90_Index(pc,d0.w),d1
    jmp Obj90_Index(pc,d1.w)
; ===========================================================================
; off_36BE2:
Obj90_Index:    offsetTable
        offsetTableEntry.w Obj90_Init   ; 0
        offsetTableEntry.w Obj90_Move   ; 2
; ===========================================================================
; loc_36BE6:
Obj90_Init:
    bsr.w   LoadSubObject
    move.w  #make_art_tile(ArtTile_ArtNem_Grounder,2,0),art_tile(a0)
    move.w  objoff_2E(a0),d0
    move.b  Obj90_Directions(pc,d0.w),x_vel(a0)
    move.b  Obj90_Directions+1(pc,d0.w),y_vel(a0)
    lsr.w   #1,d0
    move.b  Obj90_Frames(pc,d0.w),mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; byte_36C0C:
Obj90_Frames:
    dc.b   0
    dc.b   2    ; 1
    dc.b   0    ; 2
    dc.b   1    ; 3
    dc.b   0    ; 4
    dc.b   0    ; 5
; ===========================================================================
; byte_36C12:
Obj90_Directions:
    dc.b  -1, -4
    dc.b   4, -3    ; 2
    dc.b   2,  0    ; 4
    dc.b  -3, -1    ; 6
    dc.b  -3, -3    ; 8
; ===========================================================================
; loc_36C1C:
Obj8F_Move:
Obj90_Move:
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36C2C:
    moveq   #0,d1
 
    moveq   #4,d6
-   jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   +   ; rts
    bsr.w   loc_36C40
    dbf d6,-
+
    rts
; ===========================================================================
 
loc_36C40:
    _move.b #ObjID_GrounderRocks,id(a1) ; load obj90
    move.b  #6,subtype(a1) ; <== Obj90_SubObjData2
    move.w  a0,objoff_2C(a1)
    move.w  d1,objoff_2E(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addq.w  #2,d1
    rts
; ===========================================================================
 
loc_36C64:
    moveq   #0,d1
 
    moveq   #3,d6
-   jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   +   ; rts
    bsr.w   loc_36C78
    dbf d6,-
+
    rts
; ===========================================================================
 
loc_36C78:
    _move.b #ObjID_GrounderWall,id(a1) ; load obj8F
    move.b  #4,subtype(a1) ; <== Obj90_SubObjData
    move.w  a0,objoff_2C(a1)
    move.w  d1,objoff_2E(a1)
    move.l  x_pos(a0),d0
    swap    d0
    moveq   #0,d2
    move.b  byte_36CBC(pc,d1.w),d2
    ext.w   d2
    add.w   d2,d0
    swap    d0
    move.l  d0,x_pos(a1)
    move.l  y_pos(a0),d0
    swap    d0
    moveq   #0,d2
    move.b  byte_36CBC+1(pc,d1.w),d2
    ext.w   d2
    add.w   d2,d0
    swap    d0
    move.l  d0,y_pos(a1)
    addq.w  #2,d1
    rts
; ===========================================================================
byte_36CBC:
    dc.b    0,-$14
    dc.b  $10,  -4  ; 2
    dc.b    0,  $C  ; 4
    dc.b -$10,  -4  ; 6
; off_36CC4:
Obj8D_SubObjData:
    subObjData Obj8D_MapUnc_36CF0,make_art_tile(ArtTile_ArtNem_Grounder,1,1),4,5,$10,2
; off_36CCE:
Obj90_SubObjData:
    subObjData Obj90_MapUnc_36D00,make_art_tile(ArtTile_ArtKos_LevelArt,0,0),$84,4,$10,0
; off_36CD8:
Obj90_SubObjData2:
    subObjData Obj90_MapUnc_36CFA,make_art_tile(ArtTile_ArtNem_Grounder,1,1),$84,4,8,0
 
; animation script
Ani_obj8D_a:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  2,  3,  4,$FF
        even
; animation script
; off_36CEA:
Ani_obj8D_b:    offsetTable
        offsetTableEntry.w +
+       dc.b   7,  0,  1,$FC
        even
; -----------------------------------------------------------------------------
; sprite mappings (obj8D)
; -----------------------------------------------------------------------------
Obj8D_MapUnc_36CF0: offsetTable
    offsetTableEntry.w word_36D02   ; 0
    offsetTableEntry.w word_36D24   ; 2
    offsetTableEntry.w word_36D46   ; 4
    offsetTableEntry.w word_36D58   ; 6
    offsetTableEntry.w word_36D6A   ; 8
; -----------------------------------------------------------------------------
; sprite mappings (obj90)
; -----------------------------------------------------------------------------
Obj90_MapUnc_36CFA: offsetTable
    offsetTableEntry.w word_36D7C   ; 0
    offsetTableEntry.w word_36D86   ; 2
    offsetTableEntry.w word_36D90   ; 4
; -----------------------------------------------------------------------------
; sprite mappings (obj90)
; -----------------------------------------------------------------------------
Obj90_MapUnc_36D00: offsetTable
    offsetTableEntry.w word_36D9A   ; 0
word_36D02:
    dc.w 4
    dc.w $F400,    0,    0,$FFF8
    dc.w $FC06,    1,    0,$FFF0 ; 4
    dc.w $F400, $800, $800,    0 ; 8
    dc.w $FC06, $801, $800,    0 ; 12
word_36D24:
    dc.w 4
    dc.w $EC00,    7,    3,$FFF8
    dc.w $F407,    8,    4,$FFF0 ; 4
    dc.w $EC00, $807, $803,    0 ; 8
    dc.w $F407, $808, $804,    0 ; 12
word_36D46:
    dc.w 2
    dc.w $EC0F,  $10,    8,$FFF0
    dc.w  $C0C,  $20,  $10,$FFF0 ; 4
word_36D58:
    dc.w 2
    dc.w $EC0F,  $10,    8,$FFF0
    dc.w  $C0C,  $24,  $12,$FFF0 ; 4
word_36D6A:
    dc.w 2
    dc.w $EC0F,  $10,    8,$FFF0
    dc.w  $C0C,  $28,  $14,$FFF0 ; 4
word_36D7C:
    dc.w 1
    dc.w $F805,  $2C,  $16,$FFF8
word_36D86:
    dc.w 1
    dc.w $FC00,  $30,  $18,$FFFC
word_36D90:
    dc.w 1
    dc.w $FC00,  $31,  $18,$FFFC
word_36D9A:
    dc.w 2
    dc.w $F805,$4093,$4049,$FFF0
    dc.w $F805,$4097,$404B,    0 ; 4
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 91 - Chop Chop (piranha/shark badnik) from ARZ
; ----------------------------------------------------------------------------
; OST Variables:
Obj91_move_timer    = objoff_2A ; time to wait before turning around
Obj91_bubble_timer  = objoff_2C ; time to wait before producing a bubble
; Sprite_36DAC:
Obj91:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj91_Index(pc,d0.w),d1
    jmp Obj91_Index(pc,d1.w)
; ===========================================================================
; off_36DBA:
Obj91_Index:    offsetTable
        offsetTableEntry.w Obj91_Init       ; 0 - Initialize object variables
        offsetTableEntry.w Obj91_Main       ; 2 - Moving back and forth until Sonic or Tails approach
        offsetTableEntry.w Obj91_Waiting    ; 4 - Stopped, opening and closing mouth
        offsetTableEntry.w Obj91_Charge     ; 6 - Charging at Sonic or Tails
; ===========================================================================
; loc_36DC2:
Obj91_Init:
    bsr.w   LoadSubObject
    move.w  #$200,Obj91_move_timer(a0)
    move.w  #$50,Obj91_bubble_timer(a0)
    moveq   #$40,d0     ; enemy speed
    btst    #0,status(a0)   ; is enemy facing left?
    bne.s   +       ; if not, branch
    neg.w   d0      ; else reverse movement direction
+
    move.w  d0,x_vel(a0)    ; set speed
    rts
; ===========================================================================
; loc_36DE4:
Obj91_Main:
    subq.b  #1,Obj91_bubble_timer(a0)
    bne.s   +           ; branch, if timer isn't done counting down
    bsr.w   Obj91_MakeBubble
+
    subq.w  #1,Obj91_move_timer(a0)
    bpl.s   +           ; branch, if timer isn't done counting down
    move.w  #$200,Obj91_move_timer(a0)  ; else, reset timer...
    bchg    #0,status(a0)       ; ... change direction...
    bchg    #0,render_flags(a0)
    neg.w   x_vel(a0)       ; ... and reverse movement
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   Obj_GetOrientationToPlayer
    move.w  d2,d4
    move.w  d3,d5
    bsr.w   Obj91_TestCharacterPos  ; are Sonic or Tails close enough to attack?
    bne.s   Obj91_PrepareCharge ; if yes, prepare to charge at them
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_36E20
Obj91_PrepareCharge:
    addq.b  #2,routine(a0)  ; => Obj91_Waiting
    move.b  #$10,Obj91_move_timer(a0)   ; time to wait before charging at the player
    clr.w   x_vel(a0)       ; stop movement
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_36E32:
Obj91_Waiting:
    subq.b  #1,Obj91_move_timer(a0) 
    bmi.s   Obj91_MoveTowardsPlayer     ; branch, if wait time is over
    bra.w   Obj91_Animate
; ===========================================================================
; loc_36E3C:
Obj91_MoveTowardsPlayer:
    addq.b  #2,routine(a0)  ; => Obj91_Charge
    bsr.w   Obj_GetOrientationToPlayer
    lsr.w   #1,d0       ; set speed based on closest character
    move.b  Obj91_HorizontalSpeeds(pc,d0.w),x_vel(a0)   ; horizontal
    addi.w  #$10,d3
    cmpi.w  #$20,d3     ; is closest character withing $10 pixels above or $F pixels below?
    blo.s   +       ; if not, branch
    lsr.w   #1,d1       ; set speed based on closest character
    move.b  Obj91_VerticalSpeeds(pc,d1.w),1+y_vel(a0)   ; vertical
+
    bra.w   Obj91_Animate
; ===========================================================================
; byte_36E62:
Obj91_HorizontalSpeeds:
    dc.b  -2    ; 0 - player is left from object -> move left
    dc.b   2    ; 1 - player is right from object -> move right
; byte_36E64:
Obj91_VerticalSpeeds:
    dc.b $80    ; 0 - player is above object -> ... move down?
    dc.b $80    ; 1 - player is below object -> move down
; ===========================================================================
; loc_36E66:
Obj91_Charge:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
; loc_36E6A:
Obj91_Animate:
    lea (Ani_obj91).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_36E78:
Obj91_MakeBubble:
    move.w  #$50,Obj91_bubble_timer(a0) ; reset timer
    jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   return_36EB0
    _move.b #ObjID_SmallBubbles,id(a1) ; load obj
    move.b  #6,subtype(a1) ; <== Obj90_SubObjData2
    move.w  x_pos(a0),x_pos(a1) ; align objects horizontally
    moveq   #$14,d0         ; load x-offset
    btst    #0,render_flags(a0) ; is object facing left?
    beq.s   +           ; if not, branch
    neg.w   d0          ; else mirror offset
+
    add.w   d0,x_pos(a1)        ; add horizontal offset
    move.w  y_pos(a0),y_pos(a1) ; align objects vertically
    addq.w  #6,y_pos(a1)        ; move object 6 pixels down
 
return_36EB0:
    rts
; ===========================================================================
; loc_36EB2:
Obj91_TestCharacterPos:
    addi.w  #$20,d3
    cmpi.w  #$40,d3         ; is character too low?
    bhs.s   Obj91_DoNotCharge   ; if yes, branch
    tst.w   d2          ; is character to the left?
    bmi.s   Obj91_TestPosLeft   ; if yes, branch
    tst.w   x_vel(a0)       ; is object moving left, towards character?
    bpl.s   Obj91_DoNotCharge   ; if not, branch
    bra.w   Obj91_TestHorizontalDist
; ===========================================================================
; loc_36ECA:
Obj91_TestPosLeft:
    tst.w   x_vel(a0)       ; is object moving right, towards character?
    bmi.s   Obj91_DoNotCharge   ; if not, branch
    neg.w   d2          ; get absolute value
 
; loc_36ED2:
Obj91_TestHorizontalDist:
    cmpi.w  #$20,d2         ; is distance less than $20?
    blo.s   Obj91_DoNotCharge   ; if yes, don't attack
    cmpi.w  #$A0,d2         ; is distance less than $A0?
    blo.s   Obj91_PlayerInRange ; if yes, attack
 
; loc_36EDE:
Obj91_DoNotCharge:
    moveq   #0,d2           ; -> don't charge at player
    rts
; ===========================================================================
; loc_36EE2:
Obj91_PlayerInRange:
    moveq   #1,d2           ; -> charge at player
    rts
; ===========================================================================
; off_36EE6:
Obj91_SubObjData:
    subObjData Obj91_MapUnc_36EF6,make_art_tile(ArtTile_ArtNem_ChopChop,1,0),4,4,$10,2
 
; animation script
; off_36EF0:
Ani_obj91:  offsetTable
        offsetTableEntry.w +
+       dc.b   4,  0,  1,$FF    ; 0
        even
; --------------------------------------------------------------------------
; sprite mappings
; --------------------------------------------------------------------------
Obj91_MapUnc_36EF6: BINCLUDE "mappings/sprite/obj91.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 92 - Spiker (drill badnik) from HTZ
; ----------------------------------------------------------------------------
; Sprite_36F0E:
Obj92:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj92_Index(pc,d0.w),d1
    jmp Obj92_Index(pc,d1.w)
; ===========================================================================
; off_36F1C:
Obj92_Index:    offsetTable
        offsetTableEntry.w Obj92_Init   ; 0
        offsetTableEntry.w loc_36F3C    ; 2
        offsetTableEntry.w loc_36F68    ; 4
        offsetTableEntry.w loc_36F90    ; 6
; ===========================================================================
; loc_36F24:
Obj92_Init:
    bsr.w   LoadSubObject
    move.b  #$40,objoff_2A(a0)
    move.w  #$80,x_vel(a0)
    bchg    #0,status(a0)
    rts
; ===========================================================================
 
loc_36F3C:
    bsr.w   loc_3703E
    bne.s   loc_36F48
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_36F5A
 
loc_36F48:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_obj92).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36F5A:
    addq.b  #2,routine(a0)
    move.b  #$10,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36F68:
    bsr.w   loc_3703E
    bne.s   +
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_36F78
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36F78:
    subq.b  #2,routine(a0)
    move.b  #$40,objoff_2A(a0)
    neg.w   x_vel(a0)
    bchg    #0,status(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36F90:
    move.b  objoff_2E(a0),d0
    cmpi.b  #8,d0
    beq.s   loc_36FA4
    subq.b  #1,d0
    move.b  d0,objoff_2E(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_36FA4:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   loc_36FDC
    st  objoff_2B(a0)
    _move.b #ObjID_SpikerDrill,id(a1) ; load obj93
    move.b  subtype(a0),subtype(a1)
    move.w  a0,objoff_2C(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #4,mapping_frame(a1)
    move.b  #2,mapping_frame(a0)
    move.b  #1,anim(a0)
 
loc_36FDC:
    move.b  objoff_2F(a0),routine(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 93 - Drill thrown by Spiker from HTZ
; ----------------------------------------------------------------------------
; Sprite_36FE6:
Obj93:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj93_Index(pc,d0.w),d1
    jmp Obj93_Index(pc,d1.w)
; ===========================================================================
; off_36FF4:
Obj93_Index:    offsetTable
        offsetTableEntry.w Obj93_Init   ; 0
        offsetTableEntry.w loc_37028    ; 2
; ===========================================================================
; loc_36FF8:
Obj93_Init:
    bsr.w   LoadSubObject
    ori.b   #$80,render_flags(a0)
    ori.b   #$80,collision_flags(a0)
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  render_flags(a1),d0
    andi.b  #3,d0
    or.b    d0,render_flags(a0)
    moveq   #2,d1
    btst    #1,d0
    bne.s   +
    neg.w   d1
+
    move.b  d1,y_vel(a0)
    rts
; ===========================================================================
 
loc_37028:
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    bchg    #0,render_flags(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3703E:
    tst.b   objoff_2B(a0)
    bne.s   loc_37062
    tst.b   render_flags(a0)
    bpl.s   loc_37062
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$20,d2
    cmpi.w  #$40,d2
    bhs.s   loc_37062
    addi.w  #$80,d3
    cmpi.w  #$100,d3
    blo.s   loc_37066
 
loc_37062:
    moveq   #0,d0
    rts
; ===========================================================================
 
loc_37066:
    move.b  routine(a0),objoff_2F(a0)
    move.b  #6,routine(a0)
    move.b  #$10,objoff_2E(a0)
    moveq   #1,d0
    rts
; ===========================================================================
; off_3707C:
Obj92_SubObjData:
    subObjData Obj92_Obj93_MapUnc_37092,make_art_tile(ArtTile_ArtKos_LevelArt,0,0),4,4,$10,$12
; animation script
; off_37086:
Ani_obj92:  offsetTable
        offsetTableEntry.w byte_3708A   ; 0
        offsetTableEntry.w byte_3708E   ; 2
byte_3708A: dc.b   9,  0,  1,$FF
byte_3708E: dc.b   9,  2,  3,$FF
        even
; ---------------------------------------------------------------------------
; sprite mappings
; ---------------------------------------------------------------------------
Obj92_Obj93_MapUnc_37092:   BINCLUDE "mappings/sprite/obj93.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 95 - Sol (fireball-throwing orbit badnik) from HTZ
; ----------------------------------------------------------------------------
; Sprite_370FE:
Obj95:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj95_Index(pc,d0.w),d1
    jmp Obj95_Index(pc,d1.w)
; ===========================================================================
; off_3710C:
Obj95_Index:    offsetTable
        offsetTableEntry.w Obj95_Init   ; 0
        offsetTableEntry.w Obj95_WaitForPlayer  ; 2
        offsetTableEntry.w loc_37224    ; 4
        offsetTableEntry.w Obj95_FireballUpdate ; 6
        offsetTableEntry.w loc_372B8    ; 8
; ===========================================================================
; loc_37116:
Obj95_Init:
    move.l  #Obj95_MapUnc_372E6,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtKos_LevelArt,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo64_Adjust2PArtPointer
    ori.b   #4,render_flags(a0)
    move.b  #4,priority(a0)
    move.b  #$B,collision_flags(a0)
    move.b  #$C,width_pixels(a0)
    move.w  #-$40,x_vel(a0)
    moveq   #0,d2
    lea objoff_37(a0),a2
    movea.l a2,a3
    addq.w  #1,a2
    moveq   #3,d1
 
; loc_37152:
Obj95_NextFireball:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   loc_371AE
    addq.b  #1,(a3)
    move.w  a1,d5
    subi.w  #MainCharacter,d5
    if object_size=$40
    lsr.w   #6,d5
    else
    divu.w  #object_size,d5
    endif
    andi.w  #$7F,d5
    move.b  d5,(a2)+
    _move.b id(a0),id(a1) ; load obj95
    move.b  #6,routine(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    ori.b   #4,render_flags(a1)
    move.b  #4,priority(a1)
    move.b  #8,width_pixels(a1)
    move.b  #3,mapping_frame(a1)
    move.b  #$98,collision_flags(a1)
    move.b  d2,angle(a1)
    addi.b  #$40,d2
    move.l  a0,objoff_3C(a1)
    dbf d1,Obj95_NextFireball
 
loc_371AE:
    moveq   #1,d0
    btst    #0,status(a0)
    beq.s   loc_371BA
    neg.w   d0
 
loc_371BA:
    move.b  d0,objoff_36(a0)
    move.b  subtype(a0),routine(a0)
    addq.b  #2,routine(a0)
    move.w  #-$40,x_vel(a0)
    btst    #0,status(a0)
    beq.s   return_371DA
    neg.w   x_vel(a0)
 
return_371DA:
    rts
; ===========================================================================
 
; loc_371DC:
Obj95_WaitForPlayer:
    move.w  (MainCharacter+x_pos).w,d0
    sub.w   x_pos(a0),d0
    bcc.s   loc_371E8
    neg.w   d0
 
loc_371E8:
    cmpi.w  #$A0,d0
    bhs.s   loc_3720C
    move.w  (MainCharacter+y_pos).w,d0
    sub.w   y_pos(a0),d0
    bcc.s   loc_371FA
    neg.w   d0
 
loc_371FA:
    cmpi.w  #$50,d0
    bhs.s   loc_3720C
    tst.w   (Debug_placement_mode).w
    bne.s   loc_3720C
    move.b  #1,anim(a0)
 
loc_3720C:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_obj95_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    andi.b  #3,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37224:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_obj95_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    andi.b  #3,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_3723C:
Obj95_FireballUpdate:
    lea (Ani_obj95_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    movea.l objoff_3C(a0),a1 ; a1=object
    _cmpi.b #ObjID_Sol,id(a1) ; check if parent object is still alive
    bne.w   JmpTo65_DeleteObject
    cmpi.b  #2,mapping_frame(a1)
    bne.s   Obj95_FireballOrbit
    cmpi.b  #$40,angle(a0)
    bne.s   Obj95_FireballOrbit
    addq.b  #2,routine(a0)
    move.b  #0,anim(a0)
    subq.b  #1,objoff_37(a1)
    bne.s   loc_37278
    addq.b  #2,routine(a1)
 
loc_37278:
    move.w  #-$200,x_vel(a0)
    btst    #0,status(a1)
    beq.s   +
    neg.w   x_vel(a0)
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
; loc_3728E:
Obj95_FireballOrbit:
    move.b  angle(a0),d0
    jsr (CalcSine).l
    asr.w   #4,d1
    add.w   x_pos(a1),d1
    move.w  d1,x_pos(a0)
    asr.w   #4,d0
    add.w   y_pos(a1),d0
    move.w  d0,y_pos(a0)
    move.b  objoff_36(a1),d0
    add.b   d0,angle(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_372B8:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    lea (Ani_obj95_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; animation script
; off_372D2:
Ani_obj95_a:    offsetTable
        offsetTableEntry.w byte_372D6   ; 0
        offsetTableEntry.w byte_372DA   ; 1
byte_372D6: dc.b  $F,  0,$FF,  0
byte_372DA: dc.b  $F,  1,  2,$FE,  1
        even
; animation script
; off_372E0:
Ani_obj95_b:    offsetTable
        offsetTableEntry.w +
+       dc.b   5,  3,  4,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj95_MapUnc_372E6: BINCLUDE "mappings/sprite/obj95.bin"
 
Invalid_SubObjData:
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 94,96 - Rexon (lava snake badnik), from HTZ
; ----------------------------------------------------------------------------
; Sprite_37322:
Obj94:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj94_Index(pc,d0.w),d1
    jmp Obj94_Index(pc,d1.w)
; ===========================================================================
; off_37330:
Obj94_Index:    offsetTable
        offsetTableEntry.w Obj94_Init   ; 0
        offsetTableEntry.w Obj94_WaitForPlayer  ; 2
        offsetTableEntry.w Obj94_ReadyToCreateHead  ; 4
        offsetTableEntry.w Obj94_PostCreateHead ; 6
; ===========================================================================
; loc_37338:
Obj94_Init:
    bsr.w   LoadSubObject
    move.b  #2,mapping_frame(a0)
    move.w  #-$20,x_vel(a0)
    move.b  #$80,objoff_2A(a0)
    rts
; ===========================================================================
 
; loc_37350:
Obj94_WaitForPlayer:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$60,d2
    cmpi.w  #$100,d2
    bhs.s   loc_37362
    bsr.w   Obj94_CreateHead
 
loc_37362:
    move.w  x_pos(a0),-(sp)
    bsr.w   Obj94_CheckTurnAround
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #$11,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo27_SolidObject
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_37380:
Obj94_CheckTurnAround:
    subq.b  #1,objoff_2A(a0)
    bpl.s   loc_37396
    move.b  #$80,objoff_2A(a0)
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
 
loc_37396:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    rts
; ===========================================================================
 
; loc_3739C:
Obj94_ReadyToCreateHead:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$60,d2
    cmpi.w  #$100,d2
    bhs.s   loc_373AE
    bsr.w   Obj94_CreateHead
 
loc_373AE:
    bsr.w   Obj94_SolidCollision
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_373B6:
Obj94_SolidCollision:
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #8,d3
    move.w  x_pos(a0),d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
 
; loc_373CA:
Obj94_PostCreateHead:
    bsr.s   Obj94_SolidCollision
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 97 - Rexon's head, from HTZ
; ----------------------------------------------------------------------------
; Sprite_373D0:
Obj97:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj97_Index(pc,d0.w),d1
    jmp Obj97_Index(pc,d1.w)
; ===========================================================================
; off_373DE:
Obj97_Index:    offsetTable
        offsetTableEntry.w Obj97_Init   ; 0
        offsetTableEntry.w Obj97_InitialWait    ; 2
        offsetTableEntry.w Obj97_RaiseHead  ; 4
        offsetTableEntry.w Obj97_Normal ; 6
        offsetTableEntry.w Obj97_DeathDrop  ; 8
; ===========================================================================
; loc_373E8:
Obj97_Init:
    bsr.w   LoadSubObject
    move.b  #8,width_pixels(a0)
    moveq   #$28,d0
    btst    #0,render_flags(a0)
    bne.s   +
    moveq   #-$18,d0
+
    add.w   d0,x_pos(a0)
    addi.w  #$10,y_pos(a0)
    move.b  #1,objoff_38(a0)
    movea.w objoff_2C(a0),a1 ; a1=object
    lea objoff_2E(a1),a1
    move.b  #$B,collision_flags(a0)
    moveq   #0,d0
    move.w  objoff_2E(a0),d0
    cmpi.w  #8,d0
    beq.s   +
    move.b  #1,mapping_frame(a0)
    move.b  #$8B,collision_flags(a0)
    move.w  (a1,d0.w),objoff_30(a0)
+
    move.w  6(a1),objoff_32(a0)
    lsr.w   #1,d0
    move.b  byte_3744E(pc,d0.w),objoff_2A(a0)
    move.b  d0,objoff_39(a0)
    rts
; ===========================================================================
byte_3744E:
    dc.b $1E
    dc.b $18    ; 1
    dc.b $12    ; 2
    dc.b  $C    ; 3
    dc.b   6    ; 4
    dc.b   0    ; 5
; ===========================================================================
 
; loc_37454:
Obj97_InitialWait:
    if gameRevision<2
    bsr.w   Obj97_CheckHeadIsAlive
    subq.b  #1,objoff_2A(a0)
    bmi.s   Obj97_StartRaise
    else
    ; fixes an occational crash when defeated
    subq.b  #1,objoff_2A(a0)
    bmi.s   Obj97_StartRaise
    bsr.w   Obj97_CheckHeadIsAlive
    endif
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_37462:
Obj97_StartRaise:
    addq.b  #2,routine(a0)
    move.w  #-$120,x_vel(a0)
    move.w  #-$200,y_vel(a0)
    move.w  objoff_2E(a0),d0
    subi_.w #8,d0
    neg.w   d0
    lsr.w   #1,d0
    move.b  byte_3744E(pc,d0.w),objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_37488:
Obj97_RaiseHead:
    if gameRevision<2
    bsr.w   Obj97_CheckHeadIsAlive
    moveq   #$10,d0
    add.w   d0,x_vel(a0)
    subq.b  #1,objoff_2A(a0)
    bmi.s   Obj97_StartNormalState
    else
    ; fixes an occational crash when defeated
    moveq   #$10,d0
    add.w   d0,x_vel(a0)
    subq.b  #1,objoff_2A(a0)
    bmi.s   Obj97_StartNormalState
    bsr.w   Obj97_CheckHeadIsAlive
    endif
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_374A0:
Obj97_StartNormalState:
    addq.b  #2,routine(a0)
    bsr.w   Obj_MoveStop
    move.b  #$20,objoff_2A(a0)
    move.w  objoff_2E(a0),d0
    lsr.w   #1,d0
    move.b  byte_374BE(pc,d0.w),objoff_2B(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
byte_374BE:
    dc.b $24
    dc.b $20    ; 1
    dc.b $1C    ; 2
    dc.b $1A    ; 3
; ===========================================================================
 
; loc_374C2:
Obj97_Normal:
    bsr.w   Obj97_CheckHeadIsAlive
    cmpi.w  #8,objoff_2E(a0)
    bne.s   loc_374D8
    subq.b  #1,objoff_2A(a0)
    bpl.s   loc_374D8
    bsr.w   Obj97_FireProjectile
 
loc_374D8:
    move.b  objoff_39(a0),d0
    addq.b  #1,d0
    move.b  d0,objoff_39(a0)
    andi.b  #3,d0
    bne.s   +
    bsr.w   loc_3758A
    bsr.w   Obj97_Oscillate
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_374F4:
Obj97_DeathDrop:
    move.w  (Camera_Max_Y_pos_now).w,d0
    addi.w  #$E0,d0
    cmp.w   y_pos(a0),d0
    blo.w   JmpTo65_DeleteObject
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
; loc_3750C:
Obj97_CheckHeadIsAlive:
    movea.w objoff_32(a0),a1 ; a1=object
    cmpi.b  #ObjID_RexonHead,(a1)
    beq.s   +   ; rts
    move.b  #8,routine(a0)
    move.w  objoff_2E(a0),d0
    move.w  word_37528(pc,d0.w),x_vel(a0)
+
    rts
; ===========================================================================
word_37528:
    dc.w   $80
    dc.w -$100  ; 1
    dc.w  $100  ; 2
    dc.w  -$80  ; 3
    dc.w   $80  ; 4
; ===========================================================================
 
; loc_37532:
Obj97_FireProjectile:
    move.b  #$7F,objoff_2A(a0)
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   ++  ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #3,mapping_frame(a1)
    move.b  #$10,subtype(a1) ; <== Obj94_SubObjData2
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    lea (ObjectMove).l,a2
    move.l  a2,objoff_2A(a1)
    moveq   #1,d0
    moveq   #$10,d1
    btst    #0,render_flags(a0)
    bne.s   +
    neg.w   d0
    neg.w   d1
+
    move.b  d0,x_vel(a1)
    add.w   d1,x_pos(a1)
    addq.w  #4,y_pos(a1)
    move.b  #$80,1+y_vel(a1)
+
    rts
; ===========================================================================
 
loc_3758A:
    move.b  objoff_2B(a0),d0
    move.b  objoff_38(a0),d1
    add.b   d1,d0
    move.b  d0,objoff_2B(a0)
    subi.b  #$18,d0
    beq.s   +
    bcs.s   +
    cmpi.b  #$10,d0
    blo.s   ++  ; rts
+
    neg.b   objoff_38(a0)
+
    rts
; ===========================================================================
 
; loc_375AC:
Obj94_CreateHead:
    move.b  #6,routine(a0)
    bclr    #0,render_flags(a0)
    tst.w   d0
    beq.s   +
    bset    #0,render_flags(a0)
+
    bsr.w   Obj_MoveStop
    lea objoff_2C(a0),a2
    moveq   #0,d1
    moveq   #4,d6
 
loc_375CE:
    jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   +   ; rts
    _move.b #ObjID_RexonHead,id(a1) ; load obj97
    move.b  render_flags(a0),render_flags(a1)
    move.b  subtype(a0),subtype(a1)
    move.w  a0,objoff_2C(a1)
    move.w  a1,(a2)+
    move.w  d1,objoff_2E(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addq.w  #2,d1
    dbf d6,loc_375CE
+
    rts
; ===========================================================================
 
; loc_37604:
Obj97_Oscillate:
    move.w  objoff_30(a0),d0
    beq.s   +   ; rts
    movea.w d0,a1 ; a1=object
    lea byte_376A8(pc),a2
    moveq   #0,d0
    move.b  objoff_2B(a0),d0
    andi.b  #$7F,d0
    move.w  d0,d1
    andi.w  #$1F,d0
    add.w   d0,d0
    move.b  (a2,d0.w),d2
    ext.w   d2
    move.b  1(a2,d0.w),d3
    ext.w   d3
    lsr.w   #4,d1
    andi.w  #6,d1
    move.w  off_37652(pc,d1.w),d1
    jsr off_37652(pc,d1.w)
    move.w  x_pos(a0),d4
    add.w   d2,d4
    move.w  d4,x_pos(a1)
    move.b  1+y_pos(a0),d5
    add.b   d3,d5
    move.b  d5,1+y_pos(a1)
+
    rts
; ===========================================================================
off_37652:  offsetTable
        offsetTableEntry.w return_3765A ;   0
        offsetTableEntry.w loc_3765C    ; $20
        offsetTableEntry.w loc_37662    ; $40
        offsetTableEntry.w loc_37668    ; $60
; ===========================================================================
 
return_3765A:
    rts
; ===========================================================================
 
loc_3765C:
    exg d2,d3
    neg.w   d3
    rts
; ===========================================================================
 
loc_37662:
    neg.w   d2
    neg.w   d3
    rts
; ===========================================================================
 
loc_37668:
    exg d2,d3
    neg.w   d2
    rts
; ===========================================================================
; off_3766E:
Obj94_SubObjData:
    subObjData Obj94_Obj98_MapUnc_37678,make_art_tile(ArtTile_ArtNem_Rexon,3,0),4,4,$10,0
; ------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------
Obj94_Obj98_MapUnc_37678:   BINCLUDE "mappings/sprite/obj97.bin"
 
; seems to be a lookup table for oscillating horizontal position offset
byte_376A8:
    dc.b $F,  0
    dc.b $F,$FF ; 1
    dc.b $F,$FF ; 2
    dc.b $F,$FE ; 3
    dc.b $F,$FD ; 4
    dc.b $F,$FC ; 5
    dc.b $E,$FC ; 6
    dc.b $E,$FB ; 7
    dc.b $E,$FA ; 8
    dc.b $E,$FA ; 9
    dc.b $D,$F9 ; 10
    dc.b $D,$F8 ; 11
    dc.b $C,$F8 ; 12
    dc.b $C,$F7 ; 13
    dc.b $C,$F6 ; 14
    dc.b $B,$F6 ; 15
    dc.b $B,$F5 ; 16
    dc.b $A,$F5 ; 17
    dc.b $A,$F4 ; 18
    dc.b  9,$F4 ; 19
    dc.b  8,$F4 ; 20
    dc.b  8,$F3 ; 21
    dc.b  7,$F3 ; 22
    dc.b  6,$F2 ; 23
    dc.b  6,$F2 ; 24
    dc.b  5,$F2 ; 25
    dc.b  4,$F2 ; 26
    dc.b  4,$F1 ; 27
    dc.b  3,$F1 ; 28
    dc.b  2,$F1 ; 29
    dc.b  1,$F1 ; 30
    dc.b  1,$F1 ; 31
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 98 - Projectile with optional gravity (EHZ coconut, CPZ spiny, etc.)
; ----------------------------------------------------------------------------
; Sprite_376E8:
Obj98:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj98_Index(pc,d0.w),d1
    jmp Obj98_Index(pc,d1.w)
; ===========================================================================
; off_376F6: Obj98_States:
Obj98_Index:    offsetTable
        offsetTableEntry.w Obj98_Init   ; 0
        offsetTableEntry.w Obj98_Main   ; 2
; ===========================================================================
; loc_376FA:
Obj98_Init: ;;
    bra.w   LoadSubObject
; ===========================================================================
; loc_376FE:
Obj98_Main:
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    movea.l objoff_2A(a0),a1
    jsr (a1)    ; dynamic call! to Obj98_NebulaBombFall, Obj98_TurtloidShotMove, Obj98_CoconutFall, Obj98_CluckerShotMove, Obj98_SpinyShotFall, or Obj98_WallTurretShotMove, assuming the code hasn't been changed
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
 
; ===========================================================================
; for obj99
; loc_37710:
Obj98_NebulaBombFall:
    bchg    #palette_bit_0,art_tile(a0) ; bypass the animation system and make it blink
    jmpto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
 
; ===========================================================================
; for obj9A
; loc_3771A:
Obj98_TurtloidShotMove:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_TurtloidShot).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
 
; ===========================================================================
; for obj9D
; loc_37728:
Obj98_CoconutFall:
    addi.w  #$20,y_vel(a0) ; apply gravity (less than normal)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    rts
 
; ===========================================================================
; for objAE
; loc_37734:
Obj98_CluckerShotMove:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_CluckerShot).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
 
; ===========================================================================
; for objA6
; loc_37742:
Obj98_SpinyShotFall:
    addi.w  #$20,y_vel(a0) ; apply gravity (less than normal)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_SpinyShot).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
 
; ===========================================================================
; for objB8
; loc_37756:
Obj98_WallTurretShotMove:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_WallTurretShot).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
 
; ===========================================================================
; off_37764:
Obj94_SubObjData2:
    subObjData Obj94_Obj98_MapUnc_37678,make_art_tile(ArtTile_ArtNem_Rexon,1,0),$84,4,4,$98
; off_3776E:
Obj99_SubObjData:
    subObjData Obj99_Obj98_MapUnc_3789A,make_art_tile(ArtTile_ArtNem_Nebula,1,1),$84,4,8,$8B
; off_37778:
Obj9A_SubObjData2:
    subObjData Obj9A_Obj98_MapUnc_37B62,make_art_tile(ArtTile_ArtNem_Turtloid,0,0),$84,4,4,$98
; off_37782:
Obj9D_SubObjData2:
    subObjData Obj9D_Obj98_MapUnc_37D96,make_art_tile(ArtTile_ArtNem_Coconuts,0,0),$84,4,8,$8B
; off_3778C:
ObjA4_SubObjData2:
    subObjData ObjA4_Obj98_MapUnc_38A96,make_art_tile(ArtTile_ArtNem_MtzSupernova,0,1),$84,5,4,$98
; off_37796:
ObjA6_SubObjData:
    subObjData ObjA5_ObjA6_Obj98_MapUnc_38CCA,make_art_tile(ArtTile_ArtNem_Spiny,1,0),$84,5,4,$98
; off_377A0:
ObjA7_SubObjData3:
    subObjData ObjA7_ObjA8_ObjA9_Obj98_MapUnc_3921A,make_art_tile(ArtTile_ArtNem_Grabber,1,1),$84,4,4,$98
; off_377AA:
ObjAD_SubObjData3:
    subObjData ObjAD_Obj98_MapUnc_395B4,make_art_tile(ArtTile_ArtNem_WfzScratch,0,0),$84,5,4,$98
; off_377B4:
ObjAF_SubObjData:
    subObjData ObjAF_Obj98_MapUnc_39E68,make_art_tile(ArtTile_ArtNem_CNZBonusSpike,1,0),$84,5,4,$98
; off_377BE:
ObjB8_SubObjData2:
    subObjData ObjB8_Obj98_MapUnc_3BA46,make_art_tile(ArtTile_ArtNem_WfzWallTurret,0,0),$84,3,4,$98
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 99 - Nebula (bomber badnik) from SCZ
; ----------------------------------------------------------------------------
; Sprite_377C8:
Obj99:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj99_Index(pc,d0.w),d1
    jmp Obj99_Index(pc,d1.w)
; ===========================================================================
; off_377D6:
Obj99_Index:    offsetTable
        offsetTableEntry.w Obj99_Init
        offsetTableEntry.w loc_377E8
        offsetTableEntry.w loc_3781C
; ===========================================================================
; loc_377DC:
Obj99_Init:
    bsr.w   LoadSubObject
    move.w  #-$C0,x_vel(a0)
    rts
; ===========================================================================
 
loc_377E8:
    bsr.w   Obj_GetOrientationToPlayer
    tst.w   d0
    bne.s   loc_377FA
    cmpi.w  #$80,d2
    bhs.s   loc_377FA
    bsr.w   loc_37810
 
loc_377FA:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    lea (Ani_obj99).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
 
loc_37810:
    addq.b  #2,routine(a0)
    move.w  #-$A0,y_vel(a0)
    rts
; ===========================================================================
 
loc_3781C:
    tst.b   objoff_2A(a0)
    bne.s   loc_37834
    bsr.w   Obj_GetOrientationToPlayer
    addi_.w #8,d2
    cmpi.w  #$10,d2
    bhs.s   loc_37834
    bsr.w   loc_37850
 
loc_37834:
    addi_.w #1,y_vel(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    lea (Ani_obj99).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
 
loc_37850:
    st  objoff_2A(a0)
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   return_37886
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #4,mapping_frame(a1)
    move.b  #$14,subtype(a1) ; <== Obj99_SubObjData
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$18,y_pos(a1)
    lea_    Obj98_NebulaBombFall,a2
    move.l  a2,objoff_2A(a1)
 
return_37886:
    rts
; ===========================================================================
; off_37888:
Obj99_SubObjData2:
    subObjData Obj99_Obj98_MapUnc_3789A,make_art_tile(ArtTile_ArtNem_Nebula,1,1),4,4,$10,6
; animation script
; off_37892:
Ani_obj99:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  0,  1,  2,  3,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj99_Obj98_MapUnc_3789A:   BINCLUDE "mappings/sprite/obj99.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9A - Turtloid (turtle badnik) from Sky Chase Zone
; ----------------------------------------------------------------------------
; Sprite_37936:
Obj9A:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj9A_Index(pc,d0.w),d1
    jmp Obj9A_Index(pc,d1.w)
; ===========================================================================
; off_37944:
Obj9A_Index:    offsetTable
        offsetTableEntry.w Obj9A_Init   ; 0
        offsetTableEntry.w Obj9A_Main   ; 2
; ===========================================================================
; loc_37948:
Obj9A_Init:
    bsr.w   LoadSubObject
    move.w  #-$80,x_vel(a0)
    bsr.w   loc_37A4A
    lea (Ani_obj9A).l,a1
    move.l  a1,objoff_2E(a0)
    bra.w   loc_37ABE
; ===========================================================================
; loc_37964:
Obj9A_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3797A(pc,d0.w),d1
    jsr off_3797A(pc,d1.w)
    bsr.w   loc_37982
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
off_3797A:  offsetTable
        offsetTableEntry.w loc_379A0    ; 0
        offsetTableEntry.w loc_379CA    ; 2
        offsetTableEntry.w loc_379EA    ; 4
        offsetTableEntry.w return_37A04 ; 6
; ===========================================================================
 
loc_37982:
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    move.w  #$18,d1
    move.w  #8,d2
    move.w  #$E,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo9_PlatformObject
; ===========================================================================
 
loc_379A0:
    bsr.w   Obj_GetOrientationToPlayer
    tst.w   d0
    bmi.w   return_37A48
    cmpi.w  #$80,d2
    bhs.w   return_37A48
    addq.b  #2,routine_secondary(a0)
    move.w  #0,x_vel(a0)
    move.b  #4,objoff_2A(a0)
    move.b  #1,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_379CA:
    subq.b  #1,objoff_2A(a0)
    bpl.w   return_37A48
    addq.b  #2,routine_secondary(a0)
    move.b  #8,objoff_2A(a0)
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  #3,mapping_frame(a1)
    bra.w   loc_37AF2
; ===========================================================================
 
loc_379EA:
    subq.b  #1,objoff_2A(a0)
    bpl.s   return_37A02
    addq.b  #2,routine_secondary(a0)
    move.w  #-$80,x_vel(a0)
    clr.b   mapping_frame(a0)
    movea.w objoff_2C(a0),a1 ; a1=object
 
return_37A02:
    rts
; ===========================================================================
 
return_37A04:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9B - Turtloid rider from Sky Chase Zone
; ----------------------------------------------------------------------------
; Sprite_37A06:
Obj9B:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj9B_Index(pc,d0.w),d1
    jmp Obj9B_Index(pc,d1.w)
; ===========================================================================
; off_37A14:
Obj9B_Index:    offsetTable
        offsetTableEntry.w Obj9B_Init   ; 0
        offsetTableEntry.w Obj9B_Main   ; 2
; ===========================================================================
; BranchTo_LoadSubObject 
Obj9B_Init:
    bra.w   LoadSubObject
; ===========================================================================
; loc_37A1C:
Obj9B_Main:
    movea.w objoff_2C(a0),a1 ; a1=object
    lea word_37A2C(pc),a2
    bsr.w   loc_37A30
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
word_37A2C:
    dc.w     4  ; 0
    dc.w  -$18  ; 1
; ===========================================================================
 
loc_37A30:
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    move.w  (a2)+,d0
    add.w   d0,x_pos(a0)
    move.w  (a2)+,d0
    add.w   d0,y_pos(a0)
 
return_37A48:
    rts
; ===========================================================================
 
loc_37A4A:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   return_37A80
    _move.b #ObjID_TurtloidRider,id(a1) ; load obj9B
    move.b  #2,mapping_frame(a1)
    move.b  #$18,subtype(a1) ; <== Obj9B_SubObjData
    move.w  a0,objoff_2C(a1)
    move.w  a1,objoff_2C(a0)
    move.w  x_pos(a0),x_pos(a1)
    addq.w  #4,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    subi.w  #$18,y_pos(a1)
 
return_37A80:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9C - Balkiry's jet from Sky Chase Zone
; ----------------------------------------------------------------------------
; Sprite_37A82:
Obj9C:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj9C_Index(pc,d0.w),d1
    jmp Obj9C_Index(pc,d1.w)
; ===========================================================================
; off_37A90:
Obj9C_Index:    offsetTable
        offsetTableEntry.w Obj9C_Init
        offsetTableEntry.w Obj9C_Main
; ===========================================================================
; BranchTo2_LoadSubObject 
Obj9C_Init:
    bra.w   LoadSubObject
; ===========================================================================
; loc_37A98:
Obj9C_Main:
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  objoff_32(a0),d0
    cmp.b   (a1),d0
    bne.w   JmpTo65_DeleteObject
    move.l  x_pos(a1),x_pos(a0)
    move.l  y_pos(a1),y_pos(a0)
    movea.l objoff_2E(a0),a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
 
loc_37ABE:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   +   ; rts
    _move.b #ObjID_BalkiryJet,id(a1) ; load obj9C
    move.b  #6,mapping_frame(a1)
    move.b  #$1A,subtype(a1) ; <== Obj9C_SubObjData
    move.w  a0,objoff_2C(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.l  objoff_2E(a0),objoff_2E(a1)
    move.b  (a0),objoff_32(a1)
+
    rts
 
; ===========================================================================
; this code is for Obj9A
 
loc_37AF2:
    jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   +   ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #6,mapping_frame(a1)
    move.b  #$1C,subtype(a1) ; <== Obj9A_SubObjData2
    move.w  x_pos(a0),x_pos(a1)
    subi.w  #$14,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$A,y_pos(a1)
    move.w  #-$100,x_vel(a1)
    lea_    Obj98_TurtloidShotMove,a2
    move.l  a2,objoff_2A(a1)
+
    rts
; ===========================================================================
; off_37B32:
Obj9A_SubObjData:
    subObjData Obj9A_Obj98_MapUnc_37B62,make_art_tile(ArtTile_ArtNem_Turtloid,0,0),4,5,$18,0
; off_37B3C:
Obj9B_SubObjData:
    subObjData Obj9A_Obj98_MapUnc_37B62,make_art_tile(ArtTile_ArtNem_Turtloid,0,0),4,4,$C,$1A
; off_37B46:
Obj9C_SubObjData:
    subObjData Obj9A_Obj98_MapUnc_37B62,make_art_tile(ArtTile_ArtNem_Turtloid,0,0),4,5,8,0
 
; animation script
; off_37B50: TurtloidShotAniData:
Ani_TurtloidShot: offsetTable
        offsetTableEntry.w +
+       dc.b   1,  4,  5,$FF
        even
 
; animation script
; off_37B56:
Ani_obj9A:  offsetTable
        offsetTableEntry.w +
+       dc.b   1,  6,  7,$FF
        even
 
; animation script
; off_37B5C:
Ani_obj9C:  offsetTable
        offsetTableEntry.w +
+       dc.b   1,  8,  9,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj9A_Obj98_MapUnc_37B62:   BINCLUDE "mappings/sprite/obj9C.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9D - Coconuts (monkey badnik) from EHZ
; ----------------------------------------------------------------------------
; OST Variables:
Obj9D_timer     = objoff_2A ; byte
Obj9D_climb_table_index = objoff_2C ; word
Obj9D_attack_timer  = objoff_2E ; byte  ; time player needs to spend close to object before it attacks
; Sprite_37BFA:
Obj9D:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj9D_Index(pc,d0.w),d1
    jmp Obj9D_Index(pc,d1.w)
; ===========================================================================
; off_37C08:
Obj9D_Index:    offsetTable
        offsetTableEntry.w Obj9D_Init       ; 0
        offsetTableEntry.w Obj9D_Idle       ; 2
        offsetTableEntry.w Obj9D_Climbing   ; 4
        offsetTableEntry.w Obj9D_Throwing   ; 6
; ===========================================================================
; loc_37C10:
Obj9D_Init:
    bsr.w   LoadSubObject
    move.b  #$10,Obj9D_timer(a0)
    rts
; ===========================================================================
; loc_37C1C: Obj9D_Main:
Obj9D_Idle:
    bsr.w   Obj_GetOrientationToPlayer
    bclr    #0,render_flags(a0) ; face right
    bclr    #0,status(a0)
    tst.w   d0      ; is player to object's left?
    beq.s   +       ; if not, branch
    bset    #0,render_flags(a0) ; face left
    bset    #0,status(a0)
+
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    bcc.s   +   ; branch, if distance to player is greater than 60 in either direction
    tst.b   Obj9D_attack_timer(a0)  ; wait for a bit before attacking
    beq.s   Obj9D_StartThrowing ; branch, when done waiting
    subq.b  #1,Obj9D_attack_timer(a0)
+
    subq.b  #1,Obj9D_timer(a0)  ; wait for a bit...
    bmi.s   Obj9D_StartClimbing ; branch, when done waiting
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
 
Obj9D_StartClimbing:
    addq.b  #2,routine(a0)  ; => Obj9D_Climbing
    bsr.w   Obj9D_SetClimbingDirection
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
; loc_37C66:
Obj9D_StartThrowing:
    move.b  #6,routine(a0)  ; => Obj9D_Throwing
    move.b  #1,mapping_frame(a0)    ; display first throwing frame
    move.b  #8,Obj9D_timer(a0)  ; set time to display frame
    move.b  #$20,Obj9D_attack_timer(a0) ; reset timer
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
; loc_37C82:
Obj9D_SetClimbingDirection:
    move.w  Obj9D_climb_table_index(a0),d0
    cmpi.w  #$C,d0
    blo.s   +   ; branch, if index is less than $C
    moveq   #0,d0   ; otherwise, reset to 0
+
    lea Obj9D_ClimbData(pc,d0.w),a1
    addq.w  #2,d0
    move.w  d0,Obj9D_climb_table_index(a0)
    move.b  (a1)+,y_vel(a0) ; climbing speed
    move.b  (a1)+,Obj9D_timer(a0) ; time to spend moving at this speed
    rts
; ===========================================================================
; byte_37CA2:
Obj9D_ClimbData:
    dc.b  -1,$20
    dc.b   1,$18    ; 2
    dc.b  -1,$10    ; 4
    dc.b   1,$28    ; 6
    dc.b  -1,$20    ; 8
    dc.b   1,$10    ; 10
; ===========================================================================
; loc_37CAE: Obj09_Climbing:
Obj9D_Climbing:
    subq.b  #1,Obj9D_timer(a0)
    beq.s   Obj9D_StopClimbing  ; branch, if done moving
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove  ; else, keep moving
    lea (Ani_obj09).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_37CC6:
Obj9D_StopClimbing:
    subq.b  #2,routine(a0)  ; => Obj9D_Idle
    move.b  #$10,Obj9D_timer(a0)    ; time to remain idle
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_37CD4: Obj09_Throwing:
Obj9D_Throwing:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  Obj9D_ThrowingStates(pc,d0.w),d1
    jsr Obj9D_ThrowingStates(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_37CE6:
Obj9D_ThrowingStates:   offsetTable
        offsetTableEntry.w Obj9D_ThrowingHandRaised ; 0
        offsetTableEntry.w Obj9D_ThrowingHandLowered    ; 2
; ===========================================================================
; loc_37CEA:
Obj9D_ThrowingHandRaised:
    subq.b  #1,Obj9D_timer(a0)  ; wait for a bit...
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+   addq.b  #2,routine_secondary(a0)    ; => Obj9D_ThrowingHandLowered
    move.b  #8,Obj9D_timer(a0)
    move.b  #2,mapping_frame(a0)    ; display second throwing frame
    bra.w   Obj9D_CreateCoconut
; ===========================================================================
; loc_37D06:
Obj9D_ThrowingHandLowered:
    subq.b  #1,Obj9D_timer(a0)  ; wait for a bit...
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+   clr.b   routine_secondary(a0)   ; reset routine counter for next time
    move.b  #4,routine(a0) ; => Obj9D_Climbing
    move.b  #8,Obj9D_timer(a0)  ; this gets overwrittten by the next subroutine...
    bra.w   Obj9D_SetClimbingDirection
; ===========================================================================
; loc_37D22:
Obj9D_CreateCoconut:
    jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   return_37D74        ; branch, if no free slots
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #3,mapping_frame(a1)
    move.b  #$20,subtype(a1) ; <== Obj9D_SubObjData2
    move.w  x_pos(a0),x_pos(a1) ; align with parent object
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #-$D,y_pos(a1)      ; offset slightly upward
    moveq   #0,d0       ; use rightfacing data
    btst    #0,render_flags(a0) ; is object facing left?
    bne.s   +       ; if yes, branch
    moveq   #4,d0       ; use leftfacing data
+
    lea Obj9D_ThrowData(pc,d0.w),a2
    move.w  (a2)+,d0
    add.w   d0,x_pos(a1)    ; offset slightly left or right depending on object's direction
    move.w  (a2)+,x_vel(a1) ; set projectile speed
    move.w  #-$100,y_vel(a1)
    lea_    Obj98_CoconutFall,a2 ; set the routine used to move the projectile
    move.l  a2,objoff_2A(a1)
 
return_37D74:
    rts
; ===========================================================================
; word_37D76:
Obj9D_ThrowData:
    dc.w   -$B,  $100   ; 0
    dc.w    $B, -$100   ; 4
; off_37D7E:
Obj9D_SubObjData:
    subObjData Obj9D_Obj98_MapUnc_37D96,make_art_tile(ArtTile_ArtNem_Coconuts,0,0),4,5,$C,9
 
; animation script
; off_37D88:
Ani_obj09:  offsetTable
        offsetTableEntry.w byte_37D8C   ; 0
        offsetTableEntry.w byte_37D90   ; 1
byte_37D8C: dc.b   5,  0,  1,$FF
byte_37D90: dc.b   9,  1,  2,  1,$FF
        even
; ------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------
Obj9D_Obj98_MapUnc_37D96:   BINCLUDE "mappings/sprite/obj9D.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9E - Crawlton (snake badnik) from MCZ
; ----------------------------------------------------------------------------
; Sprite_37E16:
Obj9E:
    moveq   #0,d0
    move.b  objoff_3B(a0),d0
    move.w  Obj9E_Index(pc,d0.w),d1
    jmp Obj9E_Index(pc,d1.w)
; ===========================================================================
; off_37E24:
Obj9E_Index:    offsetTable
        offsetTableEntry.w Obj9E_Init   ;  0
        offsetTableEntry.w loc_37E42    ;  2
        offsetTableEntry.w loc_37E98    ;  4
        offsetTableEntry.w loc_37EB6    ;  6
        offsetTableEntry.w loc_37ED4    ;  8
        offsetTableEntry.w loc_37EFC    ; $A
; ===========================================================================
; loc_37E30:
Obj9E_Init:
    bsr.w   LoadSubObject
    move.b  #$80,y_radius(a0)
    addq.b  #2,objoff_3B(a0)
    bra.w   loc_37F74
; ===========================================================================
 
loc_37E42:
    bsr.w   Obj_GetOrientationToPlayer
    move.w  d2,d4
    move.w  d3,d5
    addi.w  #$80,d2
    cmpi.w  #$100,d2
    bhs.s   +
    addi.w  #$80,d3
    cmpi.w  #$100,d3
    blo.s   loc_37E62
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37E62:
    addq.b  #2,objoff_3B(a0)
    move.b  #$10,objoff_3A(a0)
    bclr    #0,render_flags(a0)
    tst.w   d0
    beq.s   +
    bset    #0,render_flags(a0)
+
    neg.w   d4
    lsl.w   #3,d4
    andi.w  #$FF00,d4
    move.w  d4,x_vel(a0)
    neg.w   d5
    lsl.w   #3,d5
    andi.w  #$FF00,d5
    move.w  d5,y_vel(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37E98:
    subq.b  #1,objoff_3A(a0)
    bmi.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
+
    addq.b  #2,objoff_3B(a0)
    move.b  #8,objoff_39(a0)
    move.b  #$1C,objoff_3A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37EB6:
    subq.b  #1,objoff_3A(a0)
    beq.s   +
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
+
    move.b  objoff_39(a0),objoff_3B(a0)
    move.b  #$20,objoff_3A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37ED4:
    subq.b  #1,objoff_3A(a0)
    beq.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
+
    move.b  #6,objoff_3B(a0)
    move.b  #2,objoff_39(a0)
    move.b  #$1C,objoff_3A(a0)
    neg.w   x_vel(a0)
    neg.w   y_vel(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_37EFC:
    movea.w parent(a0),a1 ; a1=object
    cmpi.b  #ObjID_Crawlton,id(a1)
    bne.w   JmpTo65_DeleteObject
    bclr    #0,render_flags(a0)
    btst    #0,render_flags(a1)
    beq.s   +
    bset    #0,render_flags(a0)
+
    move.b  #$80,objoff_14(a0)
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    cmpi.b  #6,objoff_3B(a1)
    bne.s   loc_37F6C
    move.w  x_vel(a1),d2
    asr.w   #8,d2
    move.w  y_vel(a1),d3
    asr.w   #8,d3
    lea sub2_x_pos(a0),a2
    move.b  objoff_3A(a1),d0
    moveq   #$18,d1
 
    moveq   #6,d6
-   move.w  (a2),d4     ; sub?_x_pos
    move.w  2(a2),d5    ; sub?_y_pos
    cmp.b   d1,d0
    bhs.s   +
    add.w   d2,d4
    add.w   d3,d5
+
    move.w  d4,(a2)+    ; sub?_x_pos
    move.w  d5,(a2)+    ; sub?_y_pos
    subi_.b #4,d1
    bcs.s   loc_37F6C
    addq.w  #next_subspr-4,a2
    dbf d6,-
 
loc_37F6C:
    move.w  #$280,d0
    jmpto   (DisplaySprite3).l, JmpTo5_DisplaySprite3
; ===========================================================================
 
loc_37F74:
    jsrto   (SingleObjLoad).l, JmpTo19_SingleObjLoad
    bne.s   +   ; rts
    _move.b #ObjID_Crawlton,id(a1) ; load obj9E
    move.b  render_flags(a0),render_flags(a1)
    bset    #6,render_flags(a1)
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #$A,objoff_3B(a1)
    move.b  #0,mainspr_mapframe(a1)
    move.b  #$80,mainspr_width(a1)
    move.b  #7,mainspr_childsprites(a1)
    move.w  a0,parent(a1)
    move.w  x_pos(a0),d2
    move.w  d2,x_pos(a1)
    move.w  y_pos(a0),d3
    move.w  d3,y_pos(a1)
    move.b  #$80,objoff_14(a1)
    bset    #4,render_flags(a1)
    lea sub2_x_pos(a1),a2
 
    moveq   #6,d6
-   move.w  d2,(a2)+    ; sub?_x_pos
    move.w  d3,(a2)+    ; sub?_y_pos
    move.w  #2,(a2)+    ; sub?_mapframe
    addi.w  #$10,d1
    dbf d6,-
+
    rts
; ===========================================================================
; off_37FE8:
Obj9E_SubObjData:
    subObjData Obj9E_MapUnc_37FF2,make_art_tile(ArtTile_ArtNem_Crawlton,1,0),4,4,$80,$B
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
Obj9E_MapUnc_37FF2: BINCLUDE "mappings/sprite/obj9E.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 9F - Shellcraker (crab badnik) from MTZ
; ----------------------------------------------------------------------------
; Sprite_3800C:
Obj9F:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj9F_Index(pc,d0.w),d1
    jmp Obj9F_Index(pc,d1.w)
; ===========================================================================
; off_3801A:
Obj9F_Index:    offsetTable
        offsetTableEntry.w Obj9F_Init   ; 0
        offsetTableEntry.w loc_3804E    ; 2
        offsetTableEntry.w loc_380C4    ; 4
        offsetTableEntry.w loc_380FC    ; 6
; ===========================================================================
; loc_38022:
Obj9F_Init:
    bsr.w   LoadSubObject
    btst    #0,render_flags(a0)
    beq.s   +
    bset    #0,status(a0)
+
    move.w  #-$40,x_vel(a0)
    move.b  #$C,y_radius(a0)
    move.b  #$18,x_radius(a0)
    move.w  #$140,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3804E:
    bsr.w   Obj_GetOrientationToPlayer
    tst.w   d0
    beq.s   loc_3805E
    btst    #0,render_flags(a0)
    beq.s   loc_38068
 
loc_3805E:
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    blo.s   loc_380AE
 
loc_38068:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jsr (ObjCheckFloorDist).l
    cmpi.w  #-8,d1
    blt.s   loc_38096
    cmpi.w  #$C,d1
    bge.s   loc_38096
    add.w   d1,y_pos(a0)
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3809A
    lea (Ani_obj9F).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38096:
    neg.w   x_vel(a0)
 
loc_3809A:
    addq.b  #2,routine(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #$3B,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_380AE:
    move.b  #6,routine(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #8,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_380C4:
    tst.b   render_flags(a0)
    bpl.s   loc_380E4
    bsr.w   Obj_GetOrientationToPlayer
    tst.w   d0
    beq.s   loc_380DA
    btst    #0,render_flags(a0)
    beq.s   loc_380E4
 
loc_380DA:
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    blo.s   loc_380AE
 
loc_380E4:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_380EE
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_380EE:
    subq.b  #2,routine(a0)
    move.w  #$140,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_380FC:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3810E(pc,d0.w),d1
    jsr off_3810E(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3810E:  offsetTable
        offsetTableEntry.w loc_38114    ; 0
        offsetTableEntry.w loc_3812A    ; 2
        offsetTableEntry.w loc_3813E    ; 4
; ===========================================================================
 
loc_38114:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3811C
    rts
; ===========================================================================
 
loc_3811C:
    addq.b  #2,routine_secondary(a0)
    move.b  #3,mapping_frame(a0)
    bra.w   loc_38292
; ===========================================================================
 
loc_3812A:
    tst.b   objoff_2C(a0)
    bne.s   loc_38132
    rts
; ===========================================================================
 
loc_38132:
    addq.b  #2,routine_secondary(a0)
    move.w  #$20,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3813E:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_38146
    rts
; ===========================================================================
 
loc_38146:
    clr.b   routine_secondary(a0)
    clr.b   objoff_2C(a0)
    move.b  #2,routine(a0)
    move.w  #$140,objoff_2A(a0)
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A0 - Shellcracker's claw from MTZ
; ----------------------------------------------------------------------------
; Sprite_3815C:
ObjA0:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA0_Index(pc,d0.w),d1
    jmp ObjA0_Index(pc,d1.w)
; ===========================================================================
; off_3816A:
ObjA0_Index:    offsetTable
        offsetTableEntry.w ObjA0_Init   ; 0
        offsetTableEntry.w loc_381AC    ; 2
        offsetTableEntry.w loc_38280    ; 4
; ===========================================================================
; loc_38170:
ObjA0_Init:
    bsr.w   LoadSubObject
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  render_flags(a1),d0
    andi.b  #1,d0
    or.b    d0,render_flags(a0)
    move.w  objoff_2E(a0),d0
    beq.s   loc_38198
    move.b  #4,mapping_frame(a0)
    addq.w  #6,x_pos(a0)
    addq.w  #6,y_pos(a0)
 
loc_38198:
    lsr.w   #1,d0
    move.b  byte_381A4(pc,d0.w),objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
byte_381A4:
    dc.b   0    ; 0
    dc.b   3    ; 1
    dc.b   5    ; 2
    dc.b   7    ; 3
    dc.b   9    ; 4
    dc.b  $B    ; 5
    dc.b  $D    ; 6
    dc.b  $F    ; 7
; ===========================================================================
 
loc_381AC:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Shellcracker,id(a1)
    bne.s   loc_381D0
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_381C8(pc,d0.w),d1
    jsr off_381C8(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_381C8:  offsetTable
        offsetTableEntry.w loc_381E0    ; 0
        offsetTableEntry.w loc_3822A    ; 2
        offsetTableEntry.w loc_38244    ; 4
        offsetTableEntry.w loc_38258    ; 6
; ===========================================================================
 
loc_381D0:
    move.b  #4,routine(a0)
    move.w  #$40,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_381E0:
    subq.b  #1,objoff_2A(a0)
    beq.s   loc_381EA
    bmi.s   loc_381EA
    rts
; ===========================================================================
 
loc_381EA:
    addq.b  #2,routine_secondary(a0)
    move.w  objoff_2E(a0),d0
    cmpi.w  #$E,d0
    bhs.s   loc_3821A
    move.w  #-$400,d2
    btst    #0,render_flags(a0)
    beq.s   loc_38206
    neg.w   d2
 
loc_38206:
    move.w  d2,x_vel(a0)
    lsr.w   #1,d0
    move.b  byte_38222(pc,d0.w),d1
    move.b  d1,objoff_2A(a0)
    move.b  d1,objoff_2B(a0)
    rts
; ===========================================================================
 
loc_3821A:
    move.w  #$B,objoff_2A(a0)
    rts
; ===========================================================================
byte_38222:
    dc.b  $D    ; 0
    dc.b  $C    ; 1
    dc.b  $A    ; 2
    dc.b   8    ; 3
    dc.b   6    ; 4
    dc.b   4    ; 5
    dc.b   2    ; 6
    dc.b   0    ; 7
; ===========================================================================
 
loc_3822A:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    subq.b  #1,objoff_2A(a0)
    beq.s   loc_38238
    bmi.s   loc_38238
    rts
; ===========================================================================
 
loc_38238:
    addq.b  #2,routine_secondary(a0)
    move.b  #8,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_38244:
    subq.b  #1,objoff_2A(a0)
    beq.s   loc_3824E
    bmi.s   loc_3824E
    rts
; ===========================================================================
 
loc_3824E:
    addq.b  #2,routine_secondary(a0)
    neg.w   x_vel(a0)
    rts
; ===========================================================================
 
loc_38258:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    subq.b  #1,objoff_2B(a0)
    beq.s   loc_38266
    bmi.s   loc_38266
    rts
; ===========================================================================
 
loc_38266:
    tst.w   objoff_2E(a0)
    bne.s   loc_3827A
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  #0,mapping_frame(a1)
    st  objoff_2C(a1)
 
loc_3827A:
    addq.w  #4,sp
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
loc_38280:
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    subi_.w #1,objoff_2A(a0)
    bmi.w   JmpTo65_DeleteObject
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38292:
    moveq   #0,d1
    moveq   #7,d6
 
loc_38296:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   return_382EE
    _move.b #ObjID_ShellcrackerClaw,id(a1) ; load objA0
    move.b  #$26,subtype(a1) ; <== ObjA0_SubObjData
    move.b  #5,mapping_frame(a1)
    move.b  #4,priority(a1)
    move.w  a0,objoff_2C(a1)
    move.w  d1,objoff_2E(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  #-$14,d2
    btst    #0,render_flags(a0)
    beq.s   loc_382D8
    neg.w   d2
    tst.w   d1
    beq.s   loc_382D8
    subi.w  #$C,d2
 
loc_382D8:
    add.w   d2,x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    subi_.w #8,y_pos(a1)
    addq.w  #2,d1
    dbf d6,loc_38296
 
return_382EE:
    rts
; ===========================================================================
; off_382F0:
Obj9F_SubObjData:
    subObjData Obj9F_MapUnc_38314,make_art_tile(ArtTile_ArtNem_Crabmeat,0,0),4,5,$18,$A
; off_382FA:
ObjA0_SubObjData:
    subObjData Obj9F_MapUnc_38314,make_art_tile(ArtTile_ArtNem_Crabmeat,0,0),4,4,$C,$9A
; animation script
; off_38304:
Ani_obj9F:  offsetTable
        offsetTableEntry.w byte_38308   ; 0
        offsetTableEntry.w byte_3830E   ; 1
byte_38308: dc.b  $E,  0,  1,  2,$FF,  0
byte_3830E: dc.b  $E,  0,  2,  1,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj9F_MapUnc_38314: BINCLUDE "mappings/sprite/objA0.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A1 - Slicer (praying mantis dude) from MTZ
; ----------------------------------------------------------------------------
; Sprite_383B4:
ObjA1:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA1_Index(pc,d0.w),d1
    jmp ObjA1_Index(pc,d1.w)
; ===========================================================================
; off_383C2:
ObjA1_Index:    offsetTable
        offsetTableEntry.w ObjA1_Init   ; 0
        offsetTableEntry.w ObjA1_Main   ; 2
        offsetTableEntry.w loc_38466    ; 4
        offsetTableEntry.w loc_38482    ; 6
        offsetTableEntry.w BranchTo5_JmpTo39_MarkObjGone    ; 8
; ===========================================================================
; loc_383CC:
ObjA1_Init:
    bsr.w   LoadSubObject
    move.w  #-$40,d0
    btst    #0,render_flags(a0)
    beq.s   loc_383DE
    neg.w   d0
 
loc_383DE:
    move.w  d0,x_vel(a0)
    move.b  #$10,y_radius(a0)
    move.b  #$10,x_radius(a0)
    rts
; ===========================================================================
 
ObjA1_Main:
    tst.b   render_flags(a0)
    bpl.s   loc_3841C
    bsr.w   Obj_GetOrientationToPlayer
    btst    #0,render_flags(a0)
    beq.s   loc_38404
    subq.w  #2,d0
 
loc_38404:
    tst.w   d0
    bne.s   loc_3841C
    addi.w  #$80,d2
    cmpi.w  #$100,d2
    bhs.s   loc_3841C
    addi.w  #$40,d3
    cmpi.w  #$80,d3
    blo.s   loc_38452
 
loc_3841C:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jsr (ObjCheckFloorDist).l
    cmpi.w  #-8,d1
    blt.s   loc_38444
    cmpi.w  #$C,d1
    bge.s   loc_38444
    add.w   d1,y_pos(a0)
    lea (Ani_objA1).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38444:
    addq.b  #2,routine(a0)
    move.b  #$3B,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38452:
    addq.b  #4,routine(a0)
    move.b  #3,mapping_frame(a0)
    move.b  #8,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38466:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_38470
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38470:
    subq.b  #2,routine(a0)
    neg.w   x_vel(a0)
    bchg    #0,status(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38482:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_3848C
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3848C:
    addq.b  #2,routine(a0)
    move.b  #4,mapping_frame(a0)
    bsr.w   ObjA1_LoadPincers
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
BranchTo5_JmpTo39_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A2 - Slicer's pincers from MTZ
; ----------------------------------------------------------------------------
; Sprite_384A2:
ObjA2:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA2_Index(pc,d0.w),d1
    jmp ObjA2_Index(pc,d1.w)
; ===========================================================================
; off_384B0:
ObjA2_Index:    offsetTable
        offsetTableEntry.w ObjA2_Init   ; 0
        offsetTableEntry.w ObjA2_Main   ; 2
        offsetTableEntry.w ObjA2_Main2  ; 4
; ===========================================================================
; loc_384B6:
ObjA2_Init:
    bsr.w   LoadSubObject
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
ObjA2_Main:
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3851A
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Slicer,(a1)
    bne.s   loc_3851A
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_384F6(pc,d0.w),d1
    jsr off_384F6(pc,d1.w)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objA2).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_384F6:  offsetTable
        offsetTableEntry.w +
; ===========================================================================
+
    bsr.w   Obj_GetOrientationToPlayer
    move.w  ObjA2_acceleration(pc,d0.w),d2
    add.w   d2,x_vel(a0)
    move.w  ObjA2_acceleration(pc,d1.w),d2
    add.w   d2,y_vel(a0)
    move.w  #$200,d0
    move.w  d0,d1
    bra.w   Obj_CapSpeed
; ===========================================================================
ObjA2_acceleration: dc.w -$10, $10
; ===========================================================================
 
loc_3851A:
    addq.b  #2,routine(a0)
    move.w  #$60,objoff_2A(a0)
 
ObjA2_Main2:
    subq.w  #1,objoff_2A(a0)
    bmi.w   JmpTo65_DeleteObject
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    lea (Ani_objA2).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
ObjA1_LoadPincers:
    lea objoff_3C(a0),a2 ; a2=object
    moveq   #0,d1
    moveq   #1,d6
 
loc_38546:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   return_385BA
    _move.b #ObjID_SlicerPincers,id(a1) ; load objA2
    move.b  #$2A,subtype(a1) ; <== ObjA2_SubObjData
    move.b  render_flags(a0),render_flags(a1)
    move.b  #5,mapping_frame(a1)
    move.b  #4,priority(a1)
    move.w  #$78,objoff_2A(a1)
    move.w  a0,objoff_2C(a1)
    move.w  a1,(a2)+
    move.w  #-$200,d0
    btst    #0,render_flags(a1)
    beq.s   loc_3858A
    neg.w   d0
    bset    #0,status(a1)
 
loc_3858A:
    move.w  d0,x_vel(a1)
    lea ObjA1_Pincer_Offsets(pc,d1.w),a3
    move.b  (a3)+,d0
    ext.w   d0
    btst    #0,render_flags(a1)
    beq.s   loc_385A0
    neg.w   d0
 
loc_385A0:
    add.w   x_pos(a0),d0
    move.w  d0,x_pos(a1)
    move.b  (a3)+,d0
    ext.w   d0
    add.w   y_pos(a0),d0
    move.w  d0,y_pos(a1)
    addq.w  #2,d1
    dbf d6,loc_38546
 
return_385BA:
    rts
; ===========================================================================
ObjA1_Pincer_Offsets:
    dc.b    6,    0 ; 0
    dc.b -$10,    0 ; 3
; off_385C0
ObjA1_SubObjData:
    subObjData ObjA1_MapUnc_385E2,make_art_tile(ArtTile_ArtNem_MtzMantis,1,0),4,5,$10,6
; off_385CA:
ObjA2_SubObjData:
    subObjData ObjA1_MapUnc_385E2,make_art_tile(ArtTile_ArtNem_MtzMantis,1,0),4,4,$10,$9A
; animation script
; off_385D4:
Ani_objA1:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b $13,  0,  2,$FF
        even
; animation script
; off_385DA:
Ani_objA2:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  5,  6,  7,  8,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjA1_MapUnc_385E2: BINCLUDE "mappings/sprite/objA2.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A3 - Flasher (firefly/glowbug badnik) from MCZ
; ----------------------------------------------------------------------------
; Sprite_3873E:
ObjA3:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA3_Index(pc,d0.w),d1
    jmp ObjA3_Index(pc,d1.w)
; ===========================================================================
; off_3874C:
ObjA3_Index:    offsetTable
        offsetTableEntry.w loc_3875A    ;  0
        offsetTableEntry.w loc_38766    ;  2
        offsetTableEntry.w loc_38794    ;  4
        offsetTableEntry.w loc_38832    ;  6
        offsetTableEntry.w loc_3885C    ;  8
        offsetTableEntry.w loc_38880    ; $A
        offsetTableEntry.w loc_3888E    ; $C
; ===========================================================================
 
loc_3875A:
    bsr.w   LoadSubObject
    move.w  #$40,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_38766:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_38770
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_38770:
    addq.b  #2,routine(a0)
    move.w  #-$100,x_vel(a0)
    move.w  #$40,y_vel(a0)
    move.w  #2,objoff_2E(a0)
    clr.w   objoff_2A(a0)
    move.w  #$80,objoff_30(a0)
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_38794:
    subq.w  #1,objoff_30(a0)
    bmi.s   loc_387FC
    move.w  objoff_2A(a0),d0
    bmi.w   JmpTo65_DeleteObject
    bclr    #0,render_flags(a0)
    bclr    #0,status(a0)
    tst.w   x_vel(a0)
    bmi.s   loc_387C0
    bset    #0,render_flags(a0)
    bset    #0,status(a0)
 
loc_387C0:
    addq.w  #1,d0
    move.w  d0,objoff_2A(a0)
    move.w  objoff_2C(a0),d1
    move.w  word_38810(pc,d1.w),d2
    cmp.w   d2,d0
    blo.s   loc_387EC
    addq.w  #2,d1
    move.w  d1,objoff_2C(a0)
    lea byte_38820(pc,d1.w),a1
    tst.b   (a1)+
    beq.s   loc_387E4
    neg.w   objoff_2E(a0)
 
loc_387E4:
    tst.b   (a1)+
    beq.s   loc_387EC
    neg.w   y_vel(a0)
 
loc_387EC:
    move.w  objoff_2E(a0),d0
    add.w   d0,x_vel(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_387FC:
    addq.b  #2,routine(a0)
    move.w  #$80,objoff_30(a0)
    ori.b   #$80,collision_flags(a0)
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
word_38810:
    dc.w  $100
    dc.w  $1A0  ; 1
    dc.w  $208  ; 2
    dc.w  $285  ; 3
    dc.w  $300  ; 4
    dc.w  $340  ; 5
    dc.w  $390  ; 6
    dc.w  $440  ; 7
byte_38820:
    dc.b $F0
    dc.b   0    ; 1
    dc.b   1    ; 2
    dc.b   1    ; 3
    dc.b   0    ; 4
    dc.b   1    ; 5
    dc.b   1    ; 6
    dc.b   1    ; 7
    dc.b   0    ; 8
    dc.b   1    ; 9
    dc.b   0    ; 10
    dc.b   1    ; 11
    dc.b   1    ; 12
    dc.b   0    ; 13
    dc.b   0    ; 14
    dc.b   1    ; 15
    dc.b   0    ; 16
    dc.b   1    ; 17
; ===========================================================================
 
loc_38832:
    move.b  routine(a0),d2
    lea (Ani_objA3_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    cmp.b   routine(a0),d2
    bne.s   loc_3884A
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_3884A:
    clr.l   mapping_frame(a0)
    clr.w   anim_frame_duration(a0)
    move.b  #3,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3885C:
    subq.w  #1,objoff_30(a0)
    bmi.s   loc_38870
    lea (Ani_objA3_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_38870:
    addq.b  #2,routine(a0)
    clr.l   mapping_frame(a0)
    clr.w   anim_frame_duration(a0)
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_38880:
    lea (Ani_objA3_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
 
loc_3888E:
    move.b  #4,routine(a0)
    move.w  #$80,objoff_30(a0)
    andi.b  #$7F,collision_flags(a0)
    clr.l   mapping_frame(a0)
    clr.w   anim_frame_duration(a0)
    jmpto   (MarkObjGone_P1).l, JmpTo2_MarkObjGone_P1
; ===========================================================================
; off_388AC:
ObjA3_SubObjData:
    subObjData ObjA3_MapUnc_388F0,make_art_tile(ArtTile_ArtNem_Flasher,0,1),4,4,$10,6
 
; animation script
; off_388B6:
Ani_objA3_a:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   0,  0,  1,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  0,  1
        dc.b   0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  2,  3,  4, $FC
        even
; animation script
; off_388DA:
Ani_objA3_b:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   0,  2,  0,  3,  0,  4,  0,  3,  0,$FF
        even
; animation script
; off_388E6:
Ani_objA3_c:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  4,  3,  2,  1,  0,$FC
        even
; -------------------------------------------------------------------------------
; sprite mappings
; -------------------------------------------------------------------------------
ObjA3_MapUnc_388F0: BINCLUDE "mappings/sprite/objA3.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A4 - Asteron (exploding starfish badnik) from MTZ
; ----------------------------------------------------------------------------
; Sprite_3899C:
ObjA4:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA4_Index(pc,d0.w),d1
    jmp ObjA4_Index(pc,d1.w)
; ===========================================================================
; off_389AA:
ObjA4_Index:    offsetTable
        offsetTableEntry.w ObjA4_Init   ; 0
        offsetTableEntry.w loc_389B6    ; 2
        offsetTableEntry.w loc_389DA    ; 4
        offsetTableEntry.w loc_38A2C    ; 6
; ===========================================================================
; BranchTo3_LoadSubObject 
ObjA4_Init:
    bra.w   LoadSubObject
; ===========================================================================
 
loc_389B6:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    bhs.s   BranchTo6_JmpTo39_MarkObjGone
    addi.w  #$40,d3
    cmpi.w  #$80,d3
    blo.s   loc_389D2
 
BranchTo6_JmpTo39_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_389D2:
    addq.b  #2,routine(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_389DA:
    bsr.w   Obj_GetOrientationToPlayer
    abs.w   d2
    cmpi.w  #$10,d2
    blo.s   loc_389FA
    cmpi.w  #$60,d2
    bhs.s   loc_389FA
    move.w  word_38A1A(pc,d0.w),x_vel(a0)
    bsr.w   loc_38A1E
 
loc_389FA:
    abs.w   d3
    cmpi.w  #$10,d3
    blo.s   BranchTo7_JmpTo39_MarkObjGone
    cmpi.w  #$60,d3
    bhs.s   BranchTo7_JmpTo39_MarkObjGone
    move.w  word_38A1A(pc,d1.w),y_vel(a0)
    bsr.w   loc_38A1E
 
BranchTo7_JmpTo39_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
word_38A1A:
    dc.w  -$40  ; 0
    dc.w   $40  ; 1
; ===========================================================================
 
loc_38A1E:
    move.b  #6,routine(a0)
    move.b  #$40,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_38A2C:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_38A44
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objA4).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38A44:
    _move.b #ObjID_Explosion,id(a0) ; load 0bj27
    move.b  #2,routine(a0)
    bsr.w   loc_38A58
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38A58:
    move.b  #$30,d2
    moveq   #4,d6
    lea (word_38A68).l,a2
    bra.w   Obj_CreateProjectiles
; ===========================================================================
word_38A68:
    dc.w $F8
    dc.w $FC
    dc.w $200
    dc.w $8FC
    dc.w $3FF
    dc.w $301
    dc.w $808
    dc.w $303
    dc.w $401
    dc.w $F808
    dc.w $FD03
    dc.w $400
    dc.w $F8FC
    dc.w $FDFF
    dc.w $300
; off_38A86:
ObjA4_SubObjData:
    subObjData ObjA4_Obj98_MapUnc_38A96,make_art_tile(ArtTile_ArtNem_MtzSupernova,0,1),4,4,$10,$B
; animation script
; off_38A90:
Ani_objA4:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjA4_Obj98_MapUnc_38A96:   BINCLUDE "mappings/sprite/objA4.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A5 - Spiny (crawling badnik) from CPZ
; ----------------------------------------------------------------------------
; Sprite_38AEA:
ObjA5:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA5_Index(pc,d0.w),d1
    jmp ObjA5_Index(pc,d1.w)
; ===========================================================================
; off_38AF8:
ObjA5_Index:    offsetTable
        offsetTableEntry.w ObjA5_Init   ; 0
        offsetTableEntry.w loc_38B10    ; 2
        offsetTableEntry.w loc_38B62    ; 4
; ===========================================================================
; loc_38AFE:
ObjA5_Init:
    bsr.w   LoadSubObject
    move.w  #-$40,x_vel(a0)
    move.w  #$80,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_38B10:
    tst.b   objoff_2B(a0)
    beq.s   loc_38B1E
    subq.b  #1,objoff_2B(a0)
    bra.w   loc_38B2C
; ===========================================================================
 
loc_38B1E:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    blo.s   loc_38B4E
 
loc_38B2C:
    subq.b  #1,objoff_2A(a0)
    bne.s   loc_38B3C
    move.w  #$80,objoff_2A(a0)
    neg.w   x_vel(a0)
 
loc_38B3C:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objA5).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38B4E:
    addq.b  #2,routine(a0)
    move.b  #$28,objoff_2B(a0)
    move.b  #2,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38B62:
    subq.b  #1,objoff_2B(a0)
    bmi.s   loc_38B78
    cmpi.b  #$14,objoff_2B(a0)
    bne.s   +
    bsr.w   loc_38C22
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38B78:
    subq.b  #2,routine(a0)
    move.b  #$40,objoff_2B(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A6 - Spiny (on wall) from CPZ
; ----------------------------------------------------------------------------
; Sprite_38B86:
ObjA6:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA6_Index(pc,d0.w),d1
    jmp ObjA6_Index(pc,d1.w)
; ===========================================================================
; off_38B94:
ObjA6_Index:    offsetTable
        offsetTableEntry.w ObjA6_Init   ; 0
        offsetTableEntry.w loc_38BAC    ; 2
        offsetTableEntry.w loc_38BFE    ; 4
; ===========================================================================
; loc_38B9A:
ObjA6_Init:
    bsr.w   LoadSubObject
    move.w  #-$40,y_vel(a0)
    move.w  #$80,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_38BAC:
    tst.b   objoff_2B(a0)
    beq.s   loc_38BBA
    subq.b  #1,objoff_2B(a0)
    bra.w   loc_38BC8
; ===========================================================================
 
loc_38BBA:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    blo.s   loc_38BEA
 
loc_38BC8:
    subq.b  #1,objoff_2A(a0)
    bne.s   +
    move.w  #$80,objoff_2A(a0)
    neg.w   y_vel(a0)
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objA6).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38BEA:
    addq.b  #2,routine(a0)
    move.b  #$28,objoff_2B(a0)
    move.b  #5,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38BFE:
    subq.b  #1,objoff_2B(a0)
    bmi.s   loc_38C14
    cmpi.b  #$14,objoff_2B(a0)
    bne.s   +
    bsr.w   loc_38C6E
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38C14:
    subq.b  #2,routine(a0)
    move.b  #$40,objoff_2B(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_38C22:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   ++  ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #6,mapping_frame(a1)
    move.b  #$34,subtype(a1) ; <== ObjA6_SubObjData
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  #-$300,y_vel(a1)
    move.w  #$100,d1
    lea (MainCharacter).w,a2 ; a2=character
    move.w  x_pos(a0),d0
    cmp.w   x_pos(a2),d0
    blo.s   +
    neg.w   d1
+
    move.w  d1,x_vel(a1)
    lea_    Obj98_SpinyShotFall,a2
    move.l  a2,objoff_2A(a1)
+
    rts
; ===========================================================================
 
loc_38C6E:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   ++  ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #6,mapping_frame(a1)
    move.b  #$34,subtype(a1) ; <== ObjA6_SubObjData
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  #$300,d1
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d1
+
    move.w  d1,x_vel(a1)
    lea_    Obj98_SpinyShotFall,a2
    move.l  a2,objoff_2A(a1)
+
    rts
; ===========================================================================
; off_38CAE:
ObjA5_SubObjData:
    subObjData ObjA5_ObjA6_Obj98_MapUnc_38CCA,make_art_tile(ArtTile_ArtNem_Spiny,1,0),4,4,8,$B
; animation scripts
; off_38CB8
Ani_objA5:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   9,  0,  1,$FF
        even
; off_38CBE
Ani_objA6:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   9,  3,  4,$FF
        even
; off_38CC4
Ani_SpinyShot:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  6,  7,$FF
        even
; ------------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------------
ObjA5_ObjA6_Obj98_MapUnc_38CCA: BINCLUDE "mappings/sprite/objA6.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A7 - Grabber (spider badnik) from CPZ
; ----------------------------------------------------------------------------
; Sprite_38DBA:
ObjA7:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA7_Index(pc,d0.w),d1
    jmp ObjA7_Index(pc,d1.w)
; ===========================================================================
; off_38DC8:
ObjA7_Index:    offsetTable
        offsetTableEntry.w ObjA7_Init   ; 0
        offsetTableEntry.w ObjA7_Main   ; 2
; ===========================================================================
; loc_38DCC:
ObjA7_Init:
    bsr.w   LoadSubObject
    move.w  #-$40,d0
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
+
    move.w  d0,x_vel(a0)
    move.w  #$FF,objoff_2A(a0)
    move.b  #2,objoff_2D(a0)
    lea (word_391E0).l,a2
    bsr.w   LoadChildObject
    lea (word_391E4).l,a2
    bsr.w   LoadChildObject
    lea (word_391E8).l,a2
    bra.w   LoadChildObject
; ===========================================================================
; loc_38E0C:
ObjA7_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_38E46(pc,d0.w),d1
    jsr off_38E46(pc,d1.w)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    moveq   #0,d0
    moveq   #$10,d1
    movea.w objoff_3C(a0),a1 ; a1=object
    bsr.w   Obj_AlignChildXY
    movea.w parent(a0),a1 ; a1=object
    move.w  x_pos(a0),x_pos(a1)
    movea.w objoff_3A(a0),a1 ; a1=object
    move.w  x_pos(a0),x_pos(a1)
    lea objoff_3A(a0),a2 ; a2=object
    bra.w   loc_39182
; ===========================================================================
off_38E46:  offsetTable
        offsetTableEntry.w loc_38E52    ;  0
        offsetTableEntry.w loc_38E9A    ;  2
        offsetTableEntry.w loc_38EB4    ;  4
        offsetTableEntry.w loc_38F3E    ;  6
        offsetTableEntry.w loc_38F58    ;  8
        offsetTableEntry.w BranchTo_ObjA7_CheckExplode  ; $A
; ===========================================================================
 
loc_38E52:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$40,d2
    cmpi.w  #$80,d2
    bhs.s   loc_38E66
    cmpi.w  #-$80,d3
    bhi.s   loc_38E84
 
loc_38E66:
    subq.w  #1,objoff_2A(a0)
    bpl.s   return_38E82
    move.w  #$FF,objoff_2A(a0)
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
    bchg    #0,status(a0)
 
return_38E82:
    rts
; ===========================================================================
 
loc_38E84:
    addq.b  #2,routine_secondary(a0)
    move.w  x_vel(a0),objoff_2E(a0)
    clr.w   x_vel(a0)
    move.b  #$10,objoff_2C(a0)
    rts
; ===========================================================================
 
loc_38E9A:
    subq.b  #1,objoff_2C(a0)
    bmi.s   loc_38EA2
    rts
; ===========================================================================
 
loc_38EA2:
    addq.b  #2,routine_secondary(a0)
    move.w  #$200,y_vel(a0)
    move.b  #$40,objoff_2C(a0)
    rts
; ===========================================================================
 
loc_38EB4:
    tst.b   objoff_30(a0)
    bne.s   ObjA7_GrabCharacter
    subq.b  #1,objoff_2C(a0)
    beq.s   loc_38ED6
    cmpi.b  #$20,objoff_2C(a0)
    bne.s   loc_38ECC
    neg.w   y_vel(a0)
 
loc_38ECC:
    lea (Ani_objA7).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
 
loc_38ED6:
    move.b  #0,routine_secondary(a0)
    clr.w   y_vel(a0)
    move.w  objoff_2E(a0),x_vel(a0)
    move.b  #0,mapping_frame(a0)
    rts
; ===========================================================================
 
;loc_38EEE:
ObjA7_GrabCharacter:
    addq.b  #2,routine_secondary(a0)
    movea.w objoff_32(a0),a1
    move.b  #$81,obj_control(a1)
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    move.b  #AniIDSonAni_Float,anim(a1)
    move.b  #1,mapping_frame(a0)
    tst.w   y_vel(a0)
    bmi.s   loc_38F2A
    neg.w   y_vel(a0)
    move.b  objoff_2C(a0),d0
    subi.b  #$40,d0
    neg.w   d0
    addq.b  #1,d0
    move.b  d0,objoff_2C(a0)
 
loc_38F2A:
    move.b  #1,objoff_2A(a0)
    move.b  #$10,objoff_2B(a0)
    move.b  #$20,objoff_37(a0)
    rts
; ===========================================================================
 
loc_38F3E:
    bsr.w   ObjA7_CheckExplode
    bsr.w   loc_390BC
    subq.b  #1,objoff_2C(a0)
    beq.s   loc_38F4E
    rts
; ===========================================================================
 
loc_38F4E:
    addq.b  #2,routine_secondary(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_38F58:
    bsr.w   ObjA7_CheckExplode
    bra.w   loc_390BC
; ===========================================================================
    rts
; ===========================================================================
 
BranchTo_ObjA7_CheckExplode 
    bra.w   ObjA7_CheckExplode
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A8 - Grabber's legs from CPZ
; ----------------------------------------------------------------------------
; Sprite_38F66:
ObjA8:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA8_Index(pc,d0.w),d1
    jmp ObjA8_Index(pc,d1.w)
; ===========================================================================
; off_38F74:
ObjA8_Index:    offsetTable
        offsetTableEntry.w ObjA8_Init   ; 0
        offsetTableEntry.w loc_38F88    ; 2
        offsetTableEntry.w loc_38FE8    ; 4
        offsetTableEntry.w loc_39022    ; 6
; ===========================================================================
; loc_38F7C:
ObjA8_Init:
    bsr.w   LoadSubObject
    move.b  #3,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_38F88:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Grabber,id(a1)
    bne.w   JmpTo65_DeleteObject
    bsr.w   loc_367AA
    movea.w objoff_2C(a0),a1 ; a1=object
    move.b  mapping_frame(a1),d0
    addq.b  #3,d0
    move.b  d0,mapping_frame(a0)
    move.b  collision_property(a0),d0
    beq.s   BranchTo2_JmpTo45_DisplaySprite
    clr.b   collision_property(a0)
    cmpi.b  #4,routine_secondary(a1)
    bne.s   BranchTo2_JmpTo45_DisplaySprite
    andi.b  #3,d0
    beq.s   BranchTo2_JmpTo45_DisplaySprite
    clr.b   collision_flags(a0)
    addq.b  #2,routine(a0)
    add.w   d0,d0
    st  objoff_30(a1)
    move.w  word_38FE0-6(pc,d0.w),objoff_32(a1)
    move.w  word_38FE0(pc,d0.w),objoff_34(a1)
 
BranchTo2_JmpTo45_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
        dc.w MainCharacter  ; -2
        dc.w Sidekick   ; -1
word_38FE0: dc.w MainCharacter  ; 0
        dc.w Ctrl_1_Held    ; 1
        dc.w Ctrl_2_Held    ; 2
        dc.w Ctrl_1_Held    ; 3
; ===========================================================================
 
loc_38FE8:
    movea.w objoff_2C(a0),a1 ; a1=object
    move.w  objoff_32(a1),d0
    beq.s   loc_3901A
    movea.w d0,a2 ; a2=object
    cmpi.b  #ObjID_Grabber,id(a1)
    bne.s   loc_3900A
    move.w  x_pos(a0),x_pos(a2)
    move.w  y_pos(a0),y_pos(a2)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3900A:
    move.b  #0,obj_control(a2)
    bset    #1,status(a2)
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
loc_3901A:
    addq.b  #2,routine(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39022:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Grabber,id(a1) ; compare to objA7
    bne.w   JmpTo65_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object A9 - The little hanger box thing a Grabber's string comes out of
; ----------------------------------------------------------------------------
; Sprite_39032:
ObjA9:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjA9_Index(pc,d0.w),d1
    jmp ObjA9_Index(pc,d1.w)
; ===========================================================================
; off_39040:
ObjA9_Index:    offsetTable
        offsetTableEntry.w ObjA9_Init   ; 0
        offsetTableEntry.w ObjA9_Main   ; 2
; ===========================================================================
; loc_39044:
ObjA9_Init:
    bsr.w   LoadSubObject
    move.b  #2,mapping_frame(a0)
    subi.w  #$C,y_pos(a0)
    rts
; ===========================================================================
; loc_39056:
ObjA9_Main:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Grabber,id(a1) ; compare to objA7 (grabber badnik)
    bne.w   JmpTo65_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AA - The thin white string a Grabber hangs from
; ----------------------------------------------------------------------------
; Sprite_39066:
ObjAA:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAA_Index(pc,d0.w),d1
    jmp ObjAA_Index(pc,d1.w)
; ===========================================================================
; off_39074:
ObjAA_Index:    offsetTable
        offsetTableEntry.w ObjAA_Init   ; 0
        offsetTableEntry.w ObjAA_Main   ; 2
; ===========================================================================
; loc_39078:
ObjAA_Init:
    bsr.w   LoadSubObject
    subq.w  #8,y_pos(a0)
    rts
; ===========================================================================
; loc_39082:
ObjAA_Main:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_Grabber,id(a1) ; compare to objA7 (grabber badnik)
    bne.w   JmpTo65_DeleteObject
    move.w  y_pos(a1),d0
    sub.w   y_pos(a0),d0
    bmi.s   +
    lsr.w   #4,d0
    move.b  d0,mapping_frame(a0)
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AB - Removed object (unknown, unused)
; ----------------------------------------------------------------------------
; Sprite_390A2:
ObjAB:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAB_Index(pc,d0.w),d1
    jmp ObjAB_Index(pc,d1.w)
; ===========================================================================
; off_390B0:
ObjAB_Index:    offsetTable
        offsetTableEntry.w ObjAB_Init
        offsetTableEntry.w ObjAB_Main
; ===========================================================================
; BranchTo4_LoadSubObject 
ObjAB_Init:
    bra.w   LoadSubObject
; ===========================================================================
; BranchTo10_JmpTo39_MarkObjGone 
ObjAB_Main:
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; END OF OBJECT AB
 
 
; ---------------------------------------------------------------------------
; Some subroutine for the Grabber badnik
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
loc_390BC:
    movea.w objoff_34(a0),a1 ; a1=object
    move.w  (a1),d0
    tst.b   objoff_31(a0)
    beq.s   loc_390E6
    subq.b  #1,objoff_37(a0)
    beq.s   loc_390FA
    move.b  objoff_36(a0),d1
    andi.b  #$C,d0
    beq.s   return_390E4
    cmp.b   d1,d0
    beq.s   return_390E4
    move.b  d0,objoff_36(a0)
    addq.b  #1,objoff_38(a0)
 
return_390E4:
    rts
; ---------------------------------------------------------------------------
loc_390E6:
    andi.b  #$C,d0
    beq.s   return_390E4
    nop
    st  objoff_31(a0)
    move.b  d0,objoff_36(a0)
    nop
    rts
; ---------------------------------------------------------------------------
loc_390FA:
    cmpi.b  #4,objoff_38(a0)
    blo.s   +
    move.b  #$A,routine_secondary(a0)
    clr.w   y_vel(a0)
    clr.b   collision_flags(a0)
    movea.w objoff_32(a0),a2 ; a2=object
    move.b  #0,obj_control(a2)
    bset    #1,status(a2)
    move.b  #AniIDSonAni_Walk,anim(a2)
    clr.w   objoff_32(a0)
+
    move.b  #$20,objoff_37(a0)
    clr.b   objoff_31(a0)
    clr.b   objoff_38(a0)
    rts
; End of subroutine loc_390BC
 
; ---------------------------------------------------------------------------
; Grabber death check subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_3913A:
ObjA7_CheckExplode:
    subq.b  #1,objoff_2A(a0)
    bne.s   +
    move.b  objoff_2B(a0),objoff_2A(a0)
    subq.b  #1,objoff_2B(a0)
    beq.s   ObjA7_Poof
    bchg    #palette_bit_0,art_tile(a0)
+
    rts
; ---------------------------------------------------------------------------
; loc_39154:
ObjA7_Poof:
    _move.b #ObjID_Explosion,id(a0) ; load 0bj27 (transform into explosion)
    move.b  #2,routine(a0)
    bset    #palette_bit_0,art_tile(a0)
    move.w  objoff_32(a0),d0
    beq.s   +
    movea.w d0,a2 ; a2=object
    move.b  #0,objoff_2A(a2)
    bset    #1,status(a2)
    move.b  #$B,collision_flags(a0)
+
    rts
; End of subroutine ObjA7_CheckExplode
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Yet another subroutine for the Grabber badnik
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
loc_39182:
    tst.w   (Two_player_mode).w
    beq.s   +
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
+   move.w  x_pos(a0),d0
    andi.w  #$FF80,d0
    sub.w   (Camera_X_pos_coarse).w,d0
    cmpi.w  #$280,d0
    bhi.w   +
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
+   lea (Object_Respawn_Table).w,a3
    moveq   #0,d0
    move.b  respawn_index(a0),d0
    beq.s   +
    bclr    #7,2(a3,d0.w)
+
    tst.b   objoff_30(a0)
    beq.s   +
    movea.w objoff_32(a0),a3
    move.b  #0,$2A(a3)
    bset    #1,$22(a3)
+
    moveq   #0,d6
    move.b  objoff_2D(a0),d6
 
-   movea.w (a2)+,a1
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2
    dbf d6,-
 
    bra.w   JmpTo65_DeleteObject
; End of subroutine loc_39182
 
; ===========================================================================
word_391E0:
    dc.w objoff_3E
    dc.b ObjID_GrabberBox
    dc.b $3A
word_391E4:
    dc.w objoff_3C
    dc.b ObjID_GrabberLegs
    dc.b $38
word_391E8:
    dc.w objoff_3A
    dc.b ObjID_GrabberString
    dc.b $3C
; off_391EC:
ObjA7_SubObjData:
    subObjData ObjA7_ObjA8_ObjA9_Obj98_MapUnc_3921A,make_art_tile(ArtTile_ArtNem_Grabber,1,1),4,4,$10,$B
; off_391F6:
ObjA7_SubObjData2:
    subObjData ObjA7_ObjA8_ObjA9_Obj98_MapUnc_3921A,make_art_tile(ArtTile_ArtNem_Grabber,1,1),4,1,$10,$D7
; off_39200:
ObjA8_SubObjData:
    subObjData ObjA7_ObjA8_ObjA9_Obj98_MapUnc_3921A,make_art_tile(ArtTile_ArtNem_Grabber,1,1),4,4,4,0
; off_3920A:
ObjA8_SubObjData2:
    subObjData ObjAA_MapUnc_39228,make_art_tile(ArtTile_ArtNem_Grabber,1,1),4,5,4,0
; animation script
; off_39214:
Ani_objA7:  offsetTable
        offsetTableEntry.w byte_39216   ; 0
byte_39216:
    dc.b   7,  0,  1,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings - objA7,objA8,objA9
; ----------------------------------------------------------------------------
ObjA7_ObjA8_ObjA9_Obj98_MapUnc_3921A: offsetTable
    offsetTableEntry.w word_3923A   ; 0
    offsetTableEntry.w word_39254   ; 1
    offsetTableEntry.w word_3926E   ; 2
    offsetTableEntry.w word_39278   ; 3
    offsetTableEntry.w word_39282   ; 4
    offsetTableEntry.w word_3928C   ; 5
    offsetTableEntry.w word_39296   ; 6
; -------------------------------------------------------------------------------
; sprite mappings - objAA (string of various lengths)
; -------------------------------------------------------------------------------
ObjAA_MapUnc_39228: offsetTable
    offsetTableEntry.w word_392A0   ; 0
    offsetTableEntry.w word_392AA   ; 1
    offsetTableEntry.w word_392B4   ; 2
    offsetTableEntry.w word_392C6   ; 3
    offsetTableEntry.w word_392D8   ; 4
    ; Unused - The spider badnik never goes down enough for these to appear
    offsetTableEntry.w word_3930C   ; 5 ; This is in the wrong place - this should be frame 6
    offsetTableEntry.w word_392F2   ; 6 ; This is in the wrong place - this should be frame 5
    offsetTableEntry.w word_3932E   ; 7
    offsetTableEntry.w word_3932E   ; 8 ; This should point to word_39350
word_3923A:
    dc.w 3
    dc.w $F801,    0,    0,$FFE5
    dc.w $F80D,    2,    1,$FFED; 4
    dc.w  $809,  $1D,   $E,$FFF1; 8
word_39254:
    dc.w 3
    dc.w $F801,    0,    0,$FFE5
    dc.w $F80D,    2,    1,$FFED; 4
    dc.w  $80D,  $23,  $11,$FFF1; 8
word_3926E:
    dc.w 1
    dc.w $FC00,   $A,    5,$FFFC
word_39278:
    dc.w 1
    dc.w $F809,   $F,    7,$FFF9
word_39282:
    dc.w 1
    dc.w $F80D,  $15,   $A,$FFF9
word_3928C:
    dc.w 1
    dc.w $FC00,  $2B,  $15,$FFFC
word_39296:
    dc.w 1
    dc.w $FC00,  $2C,  $16,$FFFC
word_392A0:
    dc.w 1
    dc.w     1,   $B,    5,$FFFC
word_392AA:
    dc.w 1
    dc.w     3,   $B,    5,$FFFC
word_392B4:
    dc.w 2
    dc.w     1,   $B,    5,$FFFC
    dc.w $1003,   $B,    5,$FFFC; 4
word_392C6:
    dc.w 2
    dc.w     3,   $B,    5,$FFFC
    dc.w $2003,   $B,    5,$FFFC; 4
word_392D8:
    dc.w 3
    dc.w     1,   $B,    5,$FFFC
    dc.w $1003,   $B,    5,$FFFC; 4
    dc.w $3003,   $B,    5,$FFFC; 8
word_392F2:
    dc.w 3
    dc.w     3,   $B,    5,$FFFC
    dc.w $2003,   $B,    5,$FFFC; 4
    dc.w $4003,   $B,    5,$FFFC; 8
word_3930C:
    dc.w 4
    dc.w     1,   $B,    5,$FFFC
    dc.w $1003,   $B,    5,$FFFC; 4
    dc.w $3003,   $B,    5,$FFFC; 8
    dc.w $5003,   $B,    5,$FFFC; 12
word_3932E:
    dc.w 4
    dc.w     3,   $B,    5,$FFFC
    dc.w $2003,   $B,    5,$FFFC; 4
    dc.w $4003,   $B,    5,$FFFC; 8
    dc.w $6003,   $B,    5,$FFFC; 12
; Unused frame
;word_39350:
    dc.w 5
    dc.w     1,   $B,    5,$FFFC
    dc.w $1003,   $B,    5,$FFFC; 4
    dc.w $3003,   $B,    5,$FFFC; 8
    dc.w $5003,   $B,    5,$FFFC; 12
    dc.w $7003,   $B,    5,$FFFC; 16
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AC - Balkiry (jet badnik) from SCZ
; ----------------------------------------------------------------------------
; Sprite_3937A:
ObjAC:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAC_Index(pc,d0.w),d1
    jmp ObjAC_Index(pc,d1.w)
; ===========================================================================
; off_39388:
ObjAC_Index:    offsetTable
        offsetTableEntry.w ObjAC_Init   ; 0
        offsetTableEntry.w ObjAC_Main   ; 2
; ===========================================================================
; loc_3938C:
ObjAC_Init:
    bsr.w   LoadSubObject
    move.b  #1,mapping_frame(a0)
    move.w  #-$300,x_vel(a0)
    bclr    #1,render_flags(a0)
    beq.s   +
    move.w  #-$500,x_vel(a0)
+
    lea_    Ani_obj9C,a1
    move.l  a1,objoff_2E(a0)
    bra.w   loc_37ABE
; ===========================================================================
; loc_393B6:
ObjAC_Main:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
; off_393C2:
ObjAC_SubObjData:
    subObjData ObjAC_MapUnc_393CC,make_art_tile(ArtTile_ArtNem_Balkrie,0,0),4,4,$20,8
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjAC_MapUnc_393CC: BINCLUDE "mappings/sprite/objAC.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AD - Clucker's base from WFZ
; ----------------------------------------------------------------------------
; Sprite_3941C:
ObjAD:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAD_Index(pc,d0.w),d1
    jmp ObjAD_Index(pc,d1.w)
; ===========================================================================
; off_3942A:
ObjAD_Index:    offsetTable
        offsetTableEntry.w ObjAD_Init   ; 0
        offsetTableEntry.w ObjAD_Main   ; 2
; ===========================================================================
; loc_3942E:
ObjAD_Init:
    bsr.w   LoadSubObject
    move.b  #$C,mapping_frame(a0)
    rts
; ===========================================================================
; loc_3943A:
ObjAD_Main:
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #8,d3
    move.w  x_pos(a0),d4
    jsrto   (SolidObject).l, JmpTo27_SolidObject
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AE - Clucker (chicken badnik) from WFZ
; ----------------------------------------------------------------------------
; Sprite_39452:
ObjAE:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAE_Index(pc,d0.w),d1
    jmp ObjAE_Index(pc,d1.w)
; ===========================================================================
; off_39460:
ObjAE_Index:    offsetTable
        offsetTableEntry.w ObjAE_Init   ;  0
        offsetTableEntry.w loc_39488    ;  2
        offsetTableEntry.w loc_394A2    ;  4
        offsetTableEntry.w loc_394D2    ;  6
        offsetTableEntry.w loc_394E0    ;  8
        offsetTableEntry.w loc_39508    ; $A
        offsetTableEntry.w loc_39516    ; $C
; ===========================================================================
; loc_3946E:
ObjAE_Init:
    bsr.w   LoadSubObject
    move.b  #$15,mapping_frame(a0)
    btst    #0,render_flags(a0)
    beq.s   +
    bset    #0,status(a0)
+
    rts
; ===========================================================================
 
loc_39488:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$80,d2
    cmpi.w  #$100,d2
    blo.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_394A2:
    move.b  routine(a0),d2
    lea (Ani_objAE_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    cmp.b   routine(a0),d2
    bne.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    lea mapping_frame(a0),a1
    clr.l   (a1)
    clr.w   anim_frame_duration-mapping_frame(a1)
    move.b  #8,(a1)
    move.b  #6,collision_flags(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_394D2:
    lea (Ani_objAE_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_394E0:
    tst.b   objoff_2A(a0)
    beq.s   +
    subq.b  #1,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    lea mapping_frame(a0),a1
    clr.l   (a1)
    clr.w   anim_frame_duration-mapping_frame(a1)
    move.b  #$B,(a1)
    bsr.w   loc_39526
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_39508:
    lea (Ani_objAE_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_39516:
    move.b  #8,routine(a0)
    move.b  #$40,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_39526:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   ++  ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #$D,mapping_frame(a1)
    move.b  #$46,subtype(a1) ; <==  ObjAD_SubObjData3
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    addi.w  #$B,y_pos(a1)
    move.w  #-$200,d0
    move.w  #-8,d1
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
    neg.w   d1
+
    move.w  d0,x_vel(a1)
    add.w   d1,x_pos(a1)
    lea_    Obj98_CluckerShotMove,a2
    move.l  a2,objoff_2A(a1)
+
    rts
; ===========================================================================
ObjAD_SubObjData:
    subObjData ObjAD_Obj98_MapUnc_395B4,make_art_tile(ArtTile_ArtNem_WfzScratch,0,0),4,4,$18,0
ObjAD_SubObjData2:
    subObjData ObjAD_Obj98_MapUnc_395B4,make_art_tile(ArtTile_ArtNem_WfzScratch,0,0),4,5,$10,0
 
; animation script
; off_3958A
Ani_objAE_a:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,  2,  3,  4,  5,  6,  7,$FC
        even
 
; animation script
; off_39596
Ani_objAE_b:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  8,  9, $A, $B, $B, $B, $B,$FC
        even
 
; animation script
; off_395A2
Ani_objAE_c:    offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3, $A, $B,$FC
        even
 
; animation script
; off_395A8
Ani_CluckerShot:offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3, $D, $E, $F,$10,$11,$12,$13,$14,$FF
        even
 
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjAD_Obj98_MapUnc_395B4:   BINCLUDE "mappings/sprite/objAE.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object AF - Mecha Sonic / Silver Sonic from DEZ
; (also handles Eggman's remote-control window)
; ----------------------------------------------------------------------------
; Sprite_3972C:
ObjAF:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjAF_Index(pc,d0.w),d1
    jmp ObjAF_Index(pc,d1.w)
; ===========================================================================
; off_3973A:
ObjAF_Index:    offsetTable
        offsetTableEntry.w ObjAF_Init   ;   0
        offsetTableEntry.w loc_397AC    ;   2
        offsetTableEntry.w loc_397E6    ;   4
        offsetTableEntry.w loc_397FE    ;   6
        offsetTableEntry.w loc_3984A    ;   8
        offsetTableEntry.w loc_398C0    ;  $A
        offsetTableEntry.w loc_39B92    ;  $C
        offsetTableEntry.w loc_39BBA    ;  $E
        offsetTableEntry.w loc_39BCC    ; $10
        offsetTableEntry.w loc_39BE2    ; $12
        offsetTableEntry.w loc_39BEA    ; $14
        offsetTableEntry.w loc_39C02    ; $16
        offsetTableEntry.w loc_39C0A    ; $18
        offsetTableEntry.w loc_39C12    ; $1A
        offsetTableEntry.w loc_39C2A    ; $1C
        offsetTableEntry.w loc_39C42    ; $1E
        offsetTableEntry.w loc_39C50    ; $20
        offsetTableEntry.w loc_39CA0    ; $22
; ===========================================================================
; loc_3975E:
ObjAF_Init:
    bsr.w   LoadSubObject
    move.b  #$1B,y_radius(a0)
    move.b  #$10,x_radius(a0)
    move.b  #0,collision_flags(a0)
    move.b  #8,collision_property(a0)
    lea (word_39DC2).l,a2
    bsr.w   LoadChildObject
    move.b  #$E,routine(a1)
    lea (word_39DC6).l,a2
    bsr.w   LoadChildObject
    move.b  #$14,routine(a1)
    lea (word_39DCA).l,a2
    bsr.w   LoadChildObject
    move.b  #$1A,routine(a1)
    rts
; ===========================================================================
 
loc_397AC:
    move.w  (Camera_X_pos).w,d0
    cmpi.w  #$224,d0
    bhs.s   loc_397BA
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_397BA:
    addq.b  #2,routine(a0)
    move.w  #$3C,objoff_2A(a0)
    move.w  #$100,y_vel(a0)
    move.w  #$224,d0
    move.w  d0,(Camera_Min_X_pos).w
    move.w  d0,(Camera_Max_X_pos).w
    move.b  #9,(Current_Boss_ID).w
    moveq   #MusID_FadeOut,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_397E6:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_397F0
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_397F0:
    addq.b  #2,routine(a0)
    moveq   #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo5_PlayMusic
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_397FE:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   loc_3980E
    moveq   #SndID_Fire,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
 
loc_3980E:
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bmi.s   loc_39830
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    moveq   #0,d0
    moveq   #0,d1
    movea.w parent(a0),a1 ; a1=object
    bsr.w   Obj_AlignChildXY
    bsr.w   loc_39D4A
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39830:
    add.w   d1,y_pos(a0)
    move.w  #0,y_vel(a0)
    move.b  #$1A,collision_flags(a0)
    bset    #1,status(a0)
    bra.w   loc_399D6
; ===========================================================================
 
loc_3984A:
    bsr.w   loc_39CAE
    bsr.w   loc_39D1C
    subq.b  #1,objoff_2A(a0)
    beq.s   loc_39886
    cmpi.b  #$32,objoff_2A(a0)
    bne.s   loc_3986A
    moveq   #SndID_MechaSonicBuzz,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jsrto   (DisplaySprite).l, JmpTo45_DisplaySprite
 
loc_3986A:
    jsr (ObjCheckFloorDist).l
    add.w   d1,y_pos(a0)
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    bsr.w   loc_39D4A
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39886:
    addq.b  #2,routine(a0)
    moveq   #0,d0
    move.b  objoff_2F(a0),d0
    andi.b  #$F,d0
    move.b  byte_398B0(pc,d0.w),routine_secondary(a0)
    addq.b  #1,objoff_2F(a0)
    clr.b   objoff_2E(a0)
    movea.w objoff_3C(a0),a1 ; a1=object
    move.b  #$16,routine(a1)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
byte_398B0:
    dc.b   6
    dc.b   0    ; 1
    dc.b $10    ; 2
    dc.b   6    ; 3
    dc.b   6    ; 4
    dc.b $1E    ; 5
    dc.b   0    ; 6
    dc.b $10    ; 7
    dc.b   6    ; 8
    dc.b   6    ; 9
    dc.b $10    ; 10
    dc.b   6    ; 11
    dc.b   0    ; 12
    dc.b   6    ; 13
    dc.b $10    ; 14
    dc.b $1E    ; 15
; ===========================================================================
 
loc_398C0:
    bsr.w   loc_39CAE
    bsr.w   loc_39D1C
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_398F2(pc,d0.w),d1
    jsr off_398F2(pc,d1.w)
    moveq   #0,d0
    moveq   #0,d1
    movea.w parent(a0),a1 ; a1=object
    bsr.w   Obj_AlignChildXY
    bsr.w   loc_39D4A
    bsr.w   Obj_AlignChildXY
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_398F2:  offsetTable
        offsetTableEntry.w loc_3991E    ;   0
        offsetTableEntry.w loc_39946    ;   2
        offsetTableEntry.w loc_39976    ;   4
        offsetTableEntry.w loc_39A0A    ;   6
        offsetTableEntry.w loc_39A1C    ;   8
        offsetTableEntry.w loc_39A44    ;  $A
        offsetTableEntry.w loc_39A68    ;  $C
        offsetTableEntry.w loc_39A96    ;  $E
        offsetTableEntry.w loc_39A0A    ; $10
        offsetTableEntry.w loc_39A1C    ; $12
        offsetTableEntry.w loc_39AAA    ; $14
        offsetTableEntry.w loc_39ACE    ; $16
        offsetTableEntry.w loc_39AF4    ; $18
        offsetTableEntry.w loc_39B28    ; $1A
        offsetTableEntry.w loc_39A96    ; $1C
        offsetTableEntry.w loc_39A0A    ; $1E
        offsetTableEntry.w loc_39A1C    ; $20
        offsetTableEntry.w loc_39AAA    ; $22
        offsetTableEntry.w loc_39ACE    ; $24
        offsetTableEntry.w loc_39B44    ; $26
        offsetTableEntry.w loc_39B28    ; $28
        offsetTableEntry.w loc_39A96    ; $2A
; ===========================================================================
 
loc_3991E:
    addq.b  #2,routine_secondary(a0)
    move.b  #3,mapping_frame(a0)
    move.b  #2,objoff_2C(a0)
 
loc_3992E:
    move.b  #$20,objoff_2A(a0)
    movea.w parent(a0),a1 ; a1=object
    move.b  #$10,routine(a1)
    move.b  #1,anim(a1)
    rts
; ===========================================================================
 
loc_39946:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_3994E
    rts
; ===========================================================================
 
loc_3994E:
    addq.b  #2,routine_secondary(a0)
    move.b  #$40,objoff_2A(a0)
    move.b  #1,anim(a0)
    move.w  #$800,d0
    bsr.w   loc_39D60
    movea.w parent(a0),a1 ; a1=object
    move.b  #2,anim(a1)
    moveq   #SndID_SpindashRelease,d0
    jmpto   (PlaySound).l, JmpTo12_PlaySound
; ===========================================================================
 
loc_39976:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_399C2
    cmpi.b  #$20,objoff_2A(a0)
    bne.s   loc_39994
    move.b  #2,anim(a0)
    movea.w parent(a0),a1 ; a1=object
    move.b  #$12,routine(a1)
 
loc_39994:
    bsr.w   loc_39D72
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    cmpi.b  #2,anim(a0)
    bne.s   return_399C0
    cmpi.b  #2,anim_frame(a0)
    bne.s   return_399C0
    cmpi.b  #3,anim_frame_duration(a0)
    bne.s   return_399C0
    bchg    #0,render_flags(a0)
 
return_399C0:
    rts
; ===========================================================================
 
loc_399C2:
    subq.b  #1,objoff_2C(a0)
    beq.s   loc_399D6
    move.b  #2,routine_secondary(a0)
    clr.w   x_vel(a0)
    bra.w   loc_3992E
; ===========================================================================
 
loc_399D6:
    move.b  #8,routine(a0)
    move.b  #0,anim(a0)
    move.b  #$64,objoff_2A(a0)
    clr.w   x_vel(a0)
    movea.w parent(a0),a1 ; a1=object
    move.b  #$12,routine(a1)
    movea.w objoff_3C(a0),a1 ; a1=object
    move.b  #$18,routine(a1)
    moveq   #SndID_MechaSonicBuzz,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39A0A:
    addq.b  #2,routine_secondary(a0)
    move.b  #3,mapping_frame(a0)
    move.b  #3,anim(a0)
    rts
; ===========================================================================
 
loc_39A1C:
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    bne.s   loc_39A2A
    rts
; ===========================================================================
 
loc_39A2A:
    addq.b  #2,routine_secondary(a0)
    move.b  #$20,objoff_2A(a0)
    move.b  #4,anim(a0)
    moveq   #SndID_LaserBeam,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39A44:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_39A56
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    rts
; ===========================================================================
 
loc_39A56:
    addq.b  #2,routine_secondary(a0)
    move.b  #$40,objoff_2A(a0)
    move.w  #$800,d0
    bra.w   loc_39D60
; ===========================================================================
 
loc_39A68:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_39A7C
    bsr.w   loc_39D72
    lea (off_39DE2).l,a1
    bra.w   AnimateSprite_Checked
; ===========================================================================
 
loc_39A7C:
    addq.b  #2,routine_secondary(a0)
    move.b  #5,anim(a0)
    bchg    #0,render_flags(a0)
    clr.w   x_vel(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_39A96:
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    bne.w   BranchTo_loc_399D6
    rts
; ===========================================================================
 
BranchTo_loc_399D6 
    bra.w   loc_399D6
; ===========================================================================
 
loc_39AAA:
    subq.b  #1,objoff_2A(a0)
    bmi.s   loc_39ABC
    lea (off_39DE2).l,a1
    bsr.w   AnimateSprite_Checked
    rts
; ===========================================================================
 
loc_39ABC:
    addq.b  #2,routine_secondary(a0)
    move.b  #$40,objoff_2A(a0)
    move.w  #$400,d0
    bra.w   loc_39D60
; ===========================================================================
 
loc_39ACE:
    subq.b  #1,objoff_2A(a0)
    cmpi.b  #$3C,objoff_2A(a0)
    bne.s   loc_39ADE
    bsr.w   loc_39AE8
 
loc_39ADE:
    lea (off_39DE2).l,a1
    bra.w   AnimateSprite_Checked
; ===========================================================================
 
loc_39AE8:
    addq.b  #2,routine_secondary(a0)
    move.w  #-$600,y_vel(a0)
    rts
; ===========================================================================
 
loc_39AF4:
    subq.b  #1,objoff_2A(a0)
    bmi.w   loc_39A7C
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   loc_39B0A
    bsr.w   loc_39B1A
 
loc_39B0A:
    addi.w  #$38,y_vel(a0)
    lea (off_39DE2).l,a1
    bra.w   AnimateSprite_Checked
; ===========================================================================
 
loc_39B1A:
    addq.b  #2,routine_secondary(a0)
    add.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_39B28:
    subq.b  #1,objoff_2A(a0)
    bmi.w   loc_39A7C
    jsr (ObjCheckFloorDist).l
    add.w   d1,y_pos(a0)
    lea (off_39DE2).l,a1
    bra.w   AnimateSprite_Checked
; ===========================================================================
 
loc_39B44:
    subq.b  #1,objoff_2A(a0)
    bmi.w   loc_39A7C
    tst.b   objoff_2E(a0)
    bne.s   loc_39B66
    tst.w   y_vel(a0)
    bmi.s   loc_39B66
    st  objoff_2E(a0)
    bsr.w   loc_39D82
    moveq   #SndID_SpikeSwitch,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
 
loc_39B66:
    jsr (ObjCheckFloorDist).l
    tst.w   d1
    bpl.s   loc_39B74
    bsr.w   loc_39B84
 
loc_39B74:
    addi.w  #$38,y_vel(a0)
    lea (off_39DE2).l,a1
    bra.w   AnimateSprite_Checked
; ===========================================================================
 
loc_39B84:
    addq.b  #2,routine_secondary(a0)
    add.w   d1,y_pos(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_39B92:
    clr.b   collision_flags(a0)
    subq.w  #1,objoff_32(a0)
    bmi.s   loc_39BA4
    jsrto   (Boss_LoadExplosion).l, JmpTo_Boss_LoadExplosion
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39BA4:
    move.w  #$1000,(Camera_Max_X_pos).w
    addq.b  #2,(Dynamic_Resize_Routine).w
    move.b  (Level_Music).w,d0
    jsrto   (PlayMusic).l, JmpTo5_PlayMusic
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
loc_39BBA:
    bsr.w   LoadSubObject
    move.b  #8,width_pixels(a0)
    move.b  #0,collision_flags(a0)
    rts
; ===========================================================================
 
loc_39BCC:
    movea.w objoff_2C(a0),a1 ; a1=object
    bsr.w   loc_367AA
    lea (off_39E30).l,a1
    bsr.w   AnimateSprite_Checked
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39BE2:
    andi.b  #$7F,render_flags(a0)
    rts
; ===========================================================================
 
loc_39BEA:
    bsr.w   LoadSubObject
    move.b  #8,width_pixels(a0)
    move.b  #$B,mapping_frame(a0)
    move.b  #3,priority(a0)
    rts
; ===========================================================================
 
loc_39C02:
    move.b  #0,collision_flags(a0)
    rts
; ===========================================================================
 
loc_39C0A:
    move.b  #$98,collision_flags(a0)
    rts
; ===========================================================================
 
loc_39C12:
    bsr.w   LoadSubObject
    move.b  #4,mapping_frame(a0)
    move.w  #$2C0,x_pos(a0)
    move.w  #$139,y_pos(a0)
    rts
; ===========================================================================
 
loc_39C2A:
    movea.w objoff_2C(a0),a1 ; a1=object
    bclr    #1,status(a1)
    bne.s   loc_39C3A
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39C3A:
    addq.b  #2,routine(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39C42:
    lea (Ani_objAF_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39C50:
    movea.w objoff_2C(a0),a1 ; a1=object
    lea (MainCharacter).w,a2 ; a2=character
    btst    #2,status(a1)
    bne.s   loc_39C92
    move.b  #2,anim(a0)
    cmpi.b  #4,routine(a2)
    bne.s   loc_39C78
    move.b  #3,anim(a0)
    bra.w   loc_39C84
; ===========================================================================
 
loc_39C78:
    tst.b   collision_flags(a1)
    bne.s   loc_39C84
    move.b  #4,anim(a0)
 
loc_39C84:
    lea (Ani_objAF_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39C92:
    addq.b  #2,routine(a0)
    move.b  #1,anim(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_39CA0:
    lea (Ani_objAF_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_39CAE:
    tst.b   collision_property(a0)
    beq.s   loc_39CF0
    tst.b   collision_flags(a0)
    bne.s   return_39CEE
    tst.b   objoff_30(a0)
    bne.s   loc_39CD0
    move.b  #$20,objoff_30(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
 
loc_39CD0:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   loc_39CDE
    move.w  #$EEE,d0
 
loc_39CDE:
    move.w  d0,(a1)
    subq.b  #1,objoff_30(a0)
    bne.s   return_39CEE
    clr.w   (Normal_palette_line2+2).w
    bsr.w   loc_39D24
 
return_39CEE:
    rts
; ===========================================================================
 
loc_39CF0:
    moveq   #100,d0
    bsr.w   AddPoints
    move.w  #$FF,objoff_32(a0)
    move.b  #$C,routine(a0)
    clr.b   collision_flags(a0)
    bset    #2,status(a0)
    movea.w objoff_3C(a0),a1 ; a1=object
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2
    movea.w parent(a0),a1 ; a1=object
    jmpto   (DeleteObject2).l, JmpTo6_DeleteObject2
; ===========================================================================
 
loc_39D1C:
    tst.b   collision_flags(a0)
    beq.w   return_37A48
 
loc_39D24:
    move.b  mapping_frame(a0),d0
    cmpi.b  #6,d0
    beq.s   loc_39D42
    cmpi.b  #7,d0
    beq.s   loc_39D42
    cmpi.b  #8,d0
    beq.s   loc_39D42
    move.b  #$1A,collision_flags(a0)
    rts
; ===========================================================================
 
loc_39D42:
    move.b  #$9A,collision_flags(a0)
    rts
; ===========================================================================
 
loc_39D4A:
    moveq   #$C,d0
    moveq   #-$C,d1
    btst    #0,render_flags(a0)
    beq.s   loc_39D58
    neg.w   d0
 
loc_39D58:
    movea.w objoff_3C(a0),a1 ; a1=object
    bra.w   Obj_AlignChildXY
; ===========================================================================
 
loc_39D60:
    tst.b   objoff_2D(a0)
    bne.s   loc_39D68
    neg.w   d0
 
loc_39D68:
    not.b   objoff_2D(a0)
    move.w  d0,x_vel(a0)
    rts
; ===========================================================================
 
loc_39D72:
    moveq   #$20,d0
    tst.w   x_vel(a0)
    bmi.s   loc_39D7C
    neg.w   d0
 
loc_39D7C:
    add.w   d0,x_vel(a0)
    rts
; ===========================================================================
 
loc_39D82:
    move.b  #$4A,d2
    moveq   #7,d6
    lea (byte_39D92).l,a2
    bra.w   Obj_CreateProjectiles
; ===========================================================================
byte_39D92:
    dc.b   0,$E8,  0,$FD, $F,  0,$F0,$F0,$FE,$FE,$10,  0,$E8,  0,$FD,  0
    dc.b $11,  0,$F0,$10,$FE,  2,$12,  0,  0,$18,  0,  3,$13,  0,$10,$10; 16
    dc.b   2,  2,$14,  0,$18,  0,  3,  0,$15,  0,$10,$F0,  2,$FE,$16,  0; 32
word_39DC2:
    dc.w objoff_3E
    dc.b ObjID_MechaSonic
    dc.b $48
word_39DC6:
    dc.w objoff_3C
    dc.b ObjID_MechaSonic
    dc.b $48
word_39DCA:
    dc.w objoff_3A
    dc.b ObjID_MechaSonic
    dc.b $A4
; off_39DCE:
ObjAF_SubObjData2:
    subObjData ObjAF_Obj98_MapUnc_39E68,make_art_tile(ArtTile_ArtNem_SilverSonic,1,0),4,4,$10,$1A
; off_39DD8:
ObjAF_SubObjData3:
    subObjData ObjAF_MapUnc_3A08C,make_art_tile(ArtTile_ArtNem_DEZWindow,0,0),4,6,$10,0
 
; animation script
off_39DE2:  offsetTable
        offsetTableEntry.w byte_39DEE   ; 0
        offsetTableEntry.w byte_39DF4   ; 1
        offsetTableEntry.w byte_39DF8   ; 2
        offsetTableEntry.w byte_39DFE   ; 3
        offsetTableEntry.w byte_39E14   ; 4
        offsetTableEntry.w byte_39E1A   ; 5
byte_39DEE:
    dc.b   2,  0,  1,  2,$FF,  0
byte_39DF4:
    dc.b $45,  3,$FD,  0
byte_39DF8:
    dc.b   3,  4,  5,  4,  3,$FC
byte_39DFE:
    dc.b   3,  3,  3,  6,  6,  6,  7,  7,  7,  8,  8,  8,  6,  6,  7,  7
    dc.b   8,  8,  6,  7,  8,$FC; 16
byte_39E14:
    dc.b   2,  6,  7,  8,$FF,  0
byte_39E1A:
    dc.b   3,  8,  7,  6,  8,  8,  7,  7,  6,  6,  8,  8,  8,  7,  7,  7
    dc.b   6,  6,  6,  3,  3,$FC; 16
    even
 
; animation script
off_39E30:  offsetTable
        offsetTableEntry.w byte_39E36   ; 0
        offsetTableEntry.w byte_39E3A   ; 1
        offsetTableEntry.w byte_39E3E   ; 2
byte_39E36:
    dc.b   1, $B, $C,$FF
byte_39E3A:
    dc.b   1, $D, $E,$FF
byte_39E3E:
    dc.b   1,  9, $A,$FF
    even
 
; animation script
; off_39E42:
Ani_objAF_c:    offsetTable
        offsetTableEntry.w byte_39E4C   ; 0
        offsetTableEntry.w byte_39E54   ; 1
        offsetTableEntry.w byte_39E5C   ; 2
        offsetTableEntry.w byte_39E60   ; 3
        offsetTableEntry.w byte_39E64   ; 4
byte_39E4C: dc.b   3,  4,  3,  2,  1,  0,$FC,  0
byte_39E54: dc.b   3,  0,  1,  2,  3,  4,$FA,  0
byte_39E5C: dc.b   3,  5,  5,$FF
byte_39E60: dc.b   3,  5,  6,$FF
byte_39E64: dc.b   3,  7,  7,$FF
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjAF_Obj98_MapUnc_39E68:   BINCLUDE "mappings/sprite/objAF_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjAF_MapUnc_3A08C: BINCLUDE "mappings/sprite/objAF_b.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B0 - Sonic on the Sega screen
; ----------------------------------------------------------------------------
; Sprite_3A1DC:
ObjB0:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB0_Index(pc,d0.w),d1
    jmp ObjB0_Index(pc,d1.w)
; ===========================================================================
; off_3A1EA:
ObjB0_Index:    offsetTable
        offsetTableEntry.w ObjB0_Init       ;  0
        offsetTableEntry.w ObjB0_RunLeft    ;  2
        offsetTableEntry.w ObjB0_MidWipe    ;  4
        offsetTableEntry.w ObjB0_RunRight   ;  6
        offsetTableEntry.w ObjB0_EndWipe    ;  8
        offsetTableEntry.w return_3A3F6     ; $A
; ===========================================================================
 
ObjB0_Init:
    bsr.w   LoadSubObject
    move.w  #$1E8,x_pixel(a0)
    move.w  #$F0,y_pixel(a0)
    move.w  #$B,objoff_2A(a0)
    move.w  #2,(SegaScr_VInt_Subrout).w
    bset    #0,render_flags(a0)
    bset    #0,status(a0)
 
    ; Initialize streak horizontal offsets for Sonic going left.
    ; 9 full lines (8 pixels) + 6 pixels, 2-byte interleaved entries for PNT A and PNT B
    lea (Horiz_Scroll_Buf + 2 * 2 * (9 * 8 + 6)).w,a1
    lea Streak_Horizontal_offsets(pc),a2
    moveq   #0,d0
    moveq   #$22,d6 ; Number of streaks-1
-   move.b  (a2)+,d0
    add.w   d0,(a1)
    addq.w  #2 * 2 * 2,a1   ; Advance to next streak 2 pixels down
    dbf d6,-
    
    lea off_3A294(pc),a1 ; pointers to mapping DPLC data
    lea (ArtUnc_Sonic).l,a3
    lea (Chunk_Table).l,a5
    moveq   #4-1,d5 ; there are 4 mapping frames to loop over
 
    ; this copies the tiles that we want to scale up from ROM to RAM
;loc_3A246:
;CopySpriteTilesToRAMForSegaScreen:
-   movea.l (a1)+,a2
    move.w  (a2)+,d6 ; get the number of pieces in this mapping frame
    subq.w  #1,d6
-   move.w  (a2)+,d0
    move.w  d0,d1
    ; Depending on the exact location (and size) of the art being used,
    ; you may encounter an overflow in the original code which garbles
    ; the enlarged Sonic. The following code fixes this:
    if 1==0
    andi.l  #$FFF,d0
    lsl.l   #5,d0
    lea (a3,d0.l),a4 ; source ROM address of tiles to copy
    else
    andi.w  #$FFF,d0
    lsl.w   #5,d0
    lea (a3,d0.w),a4 ; source ROM address of tiles to copy
    endif
    andi.w  #$F000,d1 ; abcd000000000000
    rol.w   #4,d1     ; (this calculation can be done smaller and faster
    addq.w  #1,d1     ; by doing rol.w #7,d1 addq.w #7,d1
    lsl.w   #3,d1     ; instead of these 4 lines)
    subq.w  #1,d1     ; 000000000abcd111 ; number of dwords to copy minus 1
-   move.l  (a4)+,(a5)+
    dbf d1,- ; copy all of the pixels in this piece into the temp buffer
    dbf d6,-- ; loop per piece in the frame
    dbf d5,--- ; loop per mapping frame
 
    ; this scales up the tiles by 2
;ScaleUpSpriteTiles:
    move.w  d7,-(sp)
    moveq   #0,d0
    moveq   #0,d1
    lea SonicRunningSpriteScaleData(pc),a6
    moveq   #4*2-1,d7 ; there are 4 sprite mapping frames with 2 pieces each
-   movea.l (a6)+,a1 ; source in RAM of tile graphics to enlarge
    movea.l (a6)+,a2 ; destination in RAM of enlarged graphics
    move.b  (a6)+,d0 ; width of the sprite piece to enlarge (minus 1)
    move.b  (a6)+,d1 ; height of the sprite piece to enlarge (minus 1)
    bsr.w   Scale_2x
    dbf d7,- ; loop over each piece
    move.w  (sp)+,d7
 
    rts
; ===========================================================================
    ; These next four things are pointers to Sonic's dereferenced
    ; DPLC entries of his "running animation" frames for the SEGA screen.
    ; I want that DPLC data split into a binary file for use with editors,
    ; but unfortunately there's no way to refer to BINCLUDE'd bytes
    ; from within AS, so I put an educated guess (default) here and
    ; run an external program (fixpointer.exe) to fix it later.
; WARNING: the build script needs editing if you rename this label
off_3A294:
    dc.l (MapRUnc_Sonic+$33A)   ;dc.l word_7181A
    dc.l (MapRUnc_Sonic+$340)   ;dc.l word_71820
    dc.l (MapRUnc_Sonic+$346)   ;dc.l word_71826
    dc.l (MapRUnc_Sonic+$34C)   ;dc.l word_7182C
 
map_piece macro width,height
    dc.l copysrc,copydst
    dc.b width-1,height-1
copysrc := copysrc + tiles_to_bytes(width * height)
copydst := copydst + tiles_to_bytes(width * height) * 2 * 2
    endm
;word_3A2A4:
SonicRunningSpriteScaleData:
copysrc := Chunk_Table
copydst := Chunk_Table + $B00
SegaScreenScaledSpriteDataStart = copydst
    rept 4 ; repeat 4 times since there are 4 frames to scale up
    ; piece 1 of each frame (the smaller top piece):
    map_piece 3,2
    ; piece 2 of each frame (the larger bottom piece):
    map_piece 4,4
    endm
SegaScreenScaledSpriteDataEnd = copydst
    if copysrc > SegaScreenScaledSpriteDataStart
    fatal "Scale copy source overran allocated size. Try changing the initial value of copydst to Chunk_Table+$\{copysrc-Chunk_Table}"
    endif
; ===========================================================================
 
ObjB0_RunLeft:
    subi.w  #$20,x_pos(a0)
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3A312
    bsr.w   ObjB0_Move_Streaks_Left
    lea (Ani_objB0).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3A312:
    addq.b  #2,routine(a0)
    move.w  #$C,objoff_2A(a0)
    move.b  #1,objoff_2C(a0)
    move.b  #-1,objoff_2D(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjB0_MidWipe:
    tst.w   objoff_2A(a0)
    beq.s   loc_3A33A
    subq.w  #1,objoff_2A(a0)
    bsr.w   ObjB0_Move_Streaks_Left
 
loc_3A33A:
    lea word_3A49E(pc),a1
    bsr.w   loc_3A44E
    bne.s   loc_3A346
    rts
; ===========================================================================
 
loc_3A346:
    addq.b  #2,routine(a0)
    bchg    #0,render_flags(a0)
    move.w  #$B,objoff_2A(a0)
    move.w  #4,(SegaScr_VInt_Subrout).w
    subi.w  #$28,x_pos(a0)
    bchg    #0,render_flags(a0)
    bchg    #0,status(a0)
 
    ; This clears a lot more than the horizontal scroll buffer, which is $400 bytes.
    ; This is because the loop counter is erroneously set to $400, instead of ($400/4)-1.
    clearRAM Horiz_Scroll_Buf,Horiz_Scroll_Buf_End+$C04 ; Bug: That '+$C04' shouldn't be there; accidentally clears an additional $C04 bytes
 
    ; Initialize streak horizontal offsets for Sonic going right.
    ; 9 full lines (8 pixels) + 7 pixels, 2-byte interleaved entries for PNT A and PNT B
    lea (Horiz_Scroll_Buf + 2 * 2 * (9 * 8 + 7)).w,a1
    lea Streak_Horizontal_offsets(pc),a2
    moveq   #0,d0
    moveq   #$22,d6 ; Number of streaks-1
 
loc_3A38A:
    move.b  (a2)+,d0
    sub.w   d0,(a1)
    addq.w  #2 * 2 * 2,a1   ; Advance to next streak 2 pixels down
    dbf d6,loc_3A38A
    rts
; ===========================================================================
 
ObjB0_RunRight:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3A3B4
    addi.w  #$20,x_pos(a0)
    bsr.w   ObjB0_Move_Streaks_Right
    lea (Ani_objB0).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3A3B4:
    addq.b  #2,routine(a0)
    move.w  #$C,objoff_2A(a0)
    move.b  #1,objoff_2C(a0)
    move.b  #-1,objoff_2D(a0)
    rts
; ===========================================================================
 
ObjB0_EndWipe:
    tst.w   objoff_2A(a0)
    beq.s   loc_3A3DA
    subq.w  #1,objoff_2A(a0)
    bsr.w   ObjB0_Move_Streaks_Right
 
loc_3A3DA:
    lea word_3A514(pc),a1
    bsr.w   loc_3A44E
    bne.s   loc_3A3E6
    rts
; ===========================================================================
 
loc_3A3E6:
    addq.b  #2,routine(a0)
    st  (SegaScr_PalDone_Flag).w
    move.b  #SndID_SegaSound,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
 
return_3A3F6:
    rts
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B1 - Object that hides TM symbol on JP region
; ----------------------------------------------------------------------------
; Sprite_3A3F8:
ObjB1:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB1_Index(pc,d0.w),d1
    jmp ObjB1_Index(pc,d1.w)
; ===========================================================================
; off_3A406:
ObjB1_Index:    offsetTable
        offsetTableEntry.w ObjB1_Init   ; 0
        offsetTableEntry.w ObjB1_Main   ; 2
; ===========================================================================
; loc_3A40A:
ObjB1_Init:
    bsr.w   LoadSubObject
    move.b  #4,mapping_frame(a0)
    move.w  #$174,x_pixel(a0)
    move.w  #$D8,y_pixel(a0)
    rts
; ===========================================================================
; BranchTo4_JmpTo45_DisplaySprite 
ObjB1_Main:
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjB0_Move_Streaks_Left:
    ; 9 full lines (8 pixels) + 6 pixels, 2-byte interleaved entries for PNT A and PNT B
    lea (Horiz_Scroll_Buf + 2 * 2 * (9 * 8 + 6)).w,a1
 
    move.w  #$22,d6 ; Number of streaks-1
-   subi.w  #$20,(a1)
    addq.w  #2 * 2 * 2,a1   ; Advance to next streak 2 pixels down
    dbf d6,-
    rts
; ===========================================================================
 
ObjB0_Move_Streaks_Right:
    ; 9 full lines (8 pixels) + 7 pixels, 2-byte interleaved entries for PNT A and PNT B
    lea (Horiz_Scroll_Buf + 2 * 2 * (9 * 8 + 7)).w,a1
 
    move.w  #$22,d6 ; Number of streaks-1
-   addi.w  #$20,(a1)
    addq.w  #2 * 2 * 2,a1   ; Advance to next streak 2 pixels down
    dbf d6,-
    rts
; ===========================================================================
 
loc_3A44E:
    subq.b  #1,objoff_2C(a0)
    bne.s   loc_3A496
    moveq   #0,d0
    move.b  objoff_2D(a0),d0
    addq.b  #1,d0
    cmp.b   1(a1),d0
    blo.s   loc_3A468
    tst.b   3(a1)
    bne.s   loc_3A49A
 
loc_3A468:
    move.b  d0,objoff_2D(a0)
    _move.b 0(a1),objoff_2C(a0)
    lea 6(a1),a2        ; This loads a palette: Sega Screen 2.bin or Sega Screen 3.bin
    moveq   #0,d1
    move.b  2(a1),d1
    move.w  d1,d2
    tst.w   d0
    beq.s   loc_3A48C
 
loc_3A482:
    subq.b  #1,d0
    beq.s   loc_3A48A
    add.w   d2,d1
    bra.s   loc_3A482
; ===========================================================================
 
loc_3A48A:
    adda.w  d1,a2
 
loc_3A48C:
    movea.w 4(a1),a3
 
loc_3A490:
    move.w  (a2)+,(a3)+
    subq.w  #2,d2
    bne.s   loc_3A490
 
loc_3A496:
    moveq   #0,d0
    rts
; ===========================================================================
 
loc_3A49A:
    moveq   #1,d0
    rts
; ===========================================================================
 
; probably some sort of description of how to use the following palette
word_3A49E:
    dc.b   4    ; 0 ; How many frames before each iteration
    dc.b   7    ; 1 ; How many iterations
    dc.b $10    ; 2 ; Number of colors * 2 to skip each iteration
    dc.b $FF    ; 3 ; Some sort of flag
    dc.w Normal_palette+$10 ; 4 ; First target palette entry
 
; Palette for the SEGA screen (background and pre-wipe foreground) (7 frames)
;pal_3A4A4:
    BINCLUDE    "art/palettes/Sega Screen 2.bin"
 
 
; probably some sort of description of how to use the following palette
word_3A514:
    dc.b   4    ; 0 ; How many frames before each iteration
    dc.b   7    ; 1 ; How many iterations
    dc.b $10    ; 2 ; Number of colors * 2 to skip each iteration
    dc.b $FF    ; 3 ; Some sort of flag
    dc.w Normal_palette ; 4 ; First target palette entry
 
; Palette for the SEGA screen (wiping and post-wipe foreground) (7 frames)
;pal_3A51A:
    BINCLUDE    "art/palettes/Sega Screen 3.bin"
 
; off_3A58A:
ObjB0_SubObjData:
    subObjData ObjB1_MapUnc_3A5A6,make_art_tile(ArtTile_ArtUnc_Giant_Sonic,2,1),0,1,$10,0
 
; off_3A594:
ObjB1_SubObjData:
    subObjData ObjB1_MapUnc_3A5A6,make_art_tile(ArtTile_ArtNem_Sega_Logo+2,0,0),0,2,8,0
 
; animation script
; off_3A59E:
Ani_objB0:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   0,  0,  1,  2,  3,$FF
        even
 
; ------------------------------------------------------------------------------
; sprite mappings
; Gigantic Sonic (2x size) mappings for the SEGA screen
; also has the "trademark hider" mappings
; ------------------------------------------------------------------------------
ObjB1_MapUnc_3A5A6: BINCLUDE "mappings/sprite/objB1.bin"
; ===========================================================================
;loc_3A68A
SegaScr_VInt:
    move.w  (SegaScr_VInt_Subrout).w,d0
    beq.w   return_37A48
    clr.w   (SegaScr_VInt_Subrout).w
    move.w  off_3A69E-2(pc,d0.w),d0
    jmp off_3A69E(pc,d0.w)
; ===========================================================================
off_3A69E:  offsetTable
        offsetTableEntry.w loc_3A6A2    ; 0
        offsetTableEntry.w loc_3A6D4    ; 2
; ===========================================================================
 
loc_3A6A2:
    dma68kToVDP SegaScreenScaledSpriteDataStart,tiles_to_bytes(ArtTile_ArtUnc_Giant_Sonic),\
                SegaScreenScaledSpriteDataEnd-SegaScreenScaledSpriteDataStart,VRAM
 
    lea ObjB1_Streak_fade_to_right(pc),a1
    ; 9 full lines ($100 bytes each) plus $28 8-pixel cells
    move.l  #vdpComm(VRAM_SegaScr_Plane_A_Name_Table + planeLocH80($28,9),VRAM,WRITE),d0    ; $49500003
    bra.w   loc_3A710
; ===========================================================================
 
loc_3A6D4:
    dmaFillVRAM 0,VRAM_SegaScr_Plane_A_Name_Table,VRAM_SegaScr_Plane_Table_Size ; clear Plane A pattern name table
 
    lea ObjB1_Streak_fade_to_left(pc),a1
    ; $49A00003; 9 full lines ($100 bytes each) plus $50 8-pixel cells
    move.l  #vdpComm(VRAM_SegaScr_Plane_A_Name_Table + planeLocH80($50,9),VRAM,WRITE),d0
    bra.w   loc_3A710
loc_3A710:
    lea (VDP_data_port).l,a6
    ; This is the line delta; for each line, the code below
    ; writes $30 entries, leaving $50 untouched.
    move.l  #vdpCommDelta(planeLocH80(0,1)),d6  ; $1000000
    moveq   #7,d1   ; Inner loop: repeat 8 times
    moveq   #9,d2   ; Outer loop: repeat $A times
-
    move.l  d0,4(a6)    ; Send command to VDP: set address to write to
    move.w  d1,d3       ; Reset inner loop counter
    movea.l a1,a2       ; Reset data pointer
-
    move.w  (a2)+,d4    ; Read one pattern name table entry
    bclr    #$A,d4      ; Test bit $A and clear (flag for end of line)
    beq.s   +           ; Branch if bit was clear
    bsr.w   loc_3A742   ; Fill rest of line with this set of pixels
+
    move.w  d4,(a6)     ; Write PNT entry
    dbf d3,-
    add.l   d6,d0       ; Point to the next VRAM area to be written to
    dbf d2,--
    rts
; ===========================================================================
 
loc_3A742:
    moveq   #$28,d5     ; Fill next $29 entries...
-
    move.w  d4,(a6)     ; ... using the PNT entry that had bit $A set
    dbf d5,-
    rts
; ===========================================================================
; Pattern A name table entries, with special flag detailed below
; These are used for the streaks, and point to VRAM in the $1000-$10FF range
ObjB1_Streak_fade_to_right:
    dc.w make_block_tile(ArtTile_ArtNem_Trails+0,0,0,1,1)   ; 0
    dc.w make_block_tile(ArtTile_ArtNem_Trails+1,0,0,1,1)   ; 2
    dc.w make_block_tile(ArtTile_ArtNem_Trails+2,0,0,1,1)   ; 4
    dc.w make_block_tile(ArtTile_ArtNem_Trails+3,0,0,1,1)   ; 6
    dc.w make_block_tile(ArtTile_ArtNem_Trails+4,0,0,1,1)   ; 8
    dc.w make_block_tile(ArtTile_ArtNem_Trails+5,0,0,1,1)   ; 10
    dc.w make_block_tile(ArtTile_ArtNem_Trails+6,0,0,1,1)   ; 12
    dc.w make_block_tile(ArtTile_ArtNem_Trails+7,0,0,1,1) | (1 << $A)   ; 14    ; Bit $A is used as a flag to use this tile $29 times
ObjB1_Streak_fade_to_left:
    dc.w make_block_tile(ArtTile_ArtNem_Trails+7,0,0,1,1) | (1 << $A)   ;  0    ; Bit $A is used as a flag to use this tile $29 times
    dc.w make_block_tile(ArtTile_ArtNem_Trails+6,0,0,1,1)   ; 2
    dc.w make_block_tile(ArtTile_ArtNem_Trails+5,0,0,1,1)   ; 4
    dc.w make_block_tile(ArtTile_ArtNem_Trails+4,0,0,1,1)   ; 6
    dc.w make_block_tile(ArtTile_ArtNem_Trails+3,0,0,1,1)   ; 8
    dc.w make_block_tile(ArtTile_ArtNem_Trails+2,0,0,1,1)   ; 10
    dc.w make_block_tile(ArtTile_ArtNem_Trails+1,0,0,1,1)   ; 12
    dc.w make_block_tile(ArtTile_ArtNem_Trails+0,0,0,1,1)   ; 14
Streak_Horizontal_offsets:
    dc.b $12
    dc.b   4    ; 1
    dc.b   4    ; 2
    dc.b   2    ; 3
    dc.b   2    ; 4
    dc.b   2    ; 5
    dc.b   2    ; 6
    dc.b   0    ; 7
    dc.b   0    ; 8
    dc.b   0    ; 9
    dc.b   0    ; 10
    dc.b   0    ; 11
    dc.b   0    ; 12
    dc.b   0    ; 13
    dc.b   0    ; 14
    dc.b   4    ; 15
    dc.b   4    ; 16
    dc.b   6    ; 17
    dc.b  $A    ; 18
    dc.b   8    ; 19
    dc.b   6    ; 20
    dc.b   4    ; 21
    dc.b   4    ; 22
    dc.b   4    ; 23
    dc.b   4    ; 24
    dc.b   6    ; 25
    dc.b   6    ; 26
    dc.b   8    ; 27
    dc.b   8    ; 28
    dc.b  $A    ; 29
    dc.b  $A    ; 30
    dc.b  $C    ; 31
    dc.b  $E    ; 32
    dc.b $10    ; 33
    dc.b $16    ; 34
    dc.b   0    ; 35
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B2 - The Tornado (Tails' plane)
; ----------------------------------------------------------------------------
; Sprite_3A790:
ObjB2:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB2_Index(pc,d0.w),d1
    jmp ObjB2_Index(pc,d1.w)
; ===========================================================================
; off_3A79E:
ObjB2_Index:    offsetTable
        offsetTableEntry.w ObjB2_Init   ;  0
        offsetTableEntry.w ObjB2_Main_SCZ   ;  2
        offsetTableEntry.w ObjB2_Main_WFZ_Start ;  4
        offsetTableEntry.w ObjB2_Main_WFZ_End   ;  6
        offsetTableEntry.w ObjB2_Invisible_grabber  ;  8
        offsetTableEntry.w loc_3AD0C    ; $A
        offsetTableEntry.w loc_3AD2A    ; $C
        offsetTableEntry.w loc_3AD42    ; $E
; ===========================================================================
; loc_3A7AE:
ObjB2_Init:
    bsr.w   LoadSubObject
    moveq   #0,d0
    move.b  subtype(a0),d0
    subi.b  #$4E,d0
    move.b  d0,routine(a0)
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    cmpi.b  #8,d0
    bhs.s   +
    move.b  #4,mapping_frame(a0)
    move.b  #1,anim(a0)
+ ; BranchTo5_JmpTo45_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3A7DE:
ObjB2_Main_SCZ:
    bsr.w   ObjB2_Animate_Pilot
    tst.w   (Debug_placement_mode).w
    bne.w   ObjB2_animate
    lea (MainCharacter).w,a1 ; a1=character
    move.w  art_tile(a1),d0
    andi.w  #high_priority,d0
    move.w  art_tile(a0),d1
    andi.w  #drawing_mask,d1
    or.w    d0,d1
    move.w  d1,art_tile(a0)
    move.w  x_pos(a0),-(sp)
    bsr.w   ObjB2_Move_with_player
    move.b  status(a0),objoff_2E(a0)
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo27_SolidObject
    bsr.w   ObjB2_Move_obbey_player
    move.b  objoff_2E(a0),d0
    move.b  status(a0),d1
    if gameRevision<2
    andi.b  #p1_standing,d0 ; 'on object' bit
    andi.b  #p1_standing,d1 ; 'on object' bit
    else
    ; 'fixes' the player being able to spin dash off the Tornado
    andi.b  #1,d0   ; 'in air' bit
    andi.b  #1,d1   ; 'in air' bit
    endif
    eor.b   d0,d1
    move.b  d1,objoff_2E(a0)
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),d1
    move.w  (Camera_X_pos).w,d0
    move.w  d0,(Camera_Min_X_pos).w
    move.w  d0,d2
    addi.w  #$11,d2
    cmp.w   d2,d1
    bhi.s   +
    addq.w  #1,d1
    move.w  d1,x_pos(a1)
+ ; loc_3A85E:
    cmpi.w  #$1400,d0
    blo.s   loc_3A878
    cmpi.w  #$1568,d1
    bhs.s   ObjB2_SCZ_Finished
    st  (Control_Locked).w
    move.w  #(button_right_mask<<8)|button_right_mask,(Ctrl_1_Logical).w
    bra.w   loc_3A87C
; ===========================================================================
 
loc_3A878:
    subi.w  #$40,d0
 
loc_3A87C:
    move.w  d0,(Camera_Max_X_pos).w
; loc_3A880:
ObjB2_animate:
    lea (Ani_objB2_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3A88E:
ObjB2_SCZ_Finished:
    bsr.w   ObjB2_Deactivate_level
    move.w  #wing_fortress_zone_act_1,(Current_ZoneAndAct).w
    bra.s   ObjB2_animate
; ===========================================================================
; loc_3A89A:
ObjB2_Main_WFZ_Start:
    bsr.w   ObjB2_Animate_Pilot
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3A8BA(pc,d0.w),d1
    jsr off_3A8BA(pc,d1.w)
    lea (Ani_objB2_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (Obj_DeleteOffScreen).l, Obj_DeleteOffScreen
; ===========================================================================
off_3A8BA:  offsetTable
        offsetTableEntry.w ObjB2_Main_WFZ_Start_init    ; 0
        offsetTableEntry.w ObjB2_Main_WFZ_Start_main    ; 2
        offsetTableEntry.w ObjB2_Main_WFZ_Start_shot_down   ; 4
        offsetTableEntry.w ObjB2_Main_WFZ_Start_fall_down   ; 6
; ===========================================================================
; loc_3A8C2:
ObjB2_Main_WFZ_Start_init:
    addq.b  #2,routine_secondary(a0)
    move.w  #$C0,objoff_32(a0)
    move.w  #$100,x_vel(a0)
    rts
; ===========================================================================
; loc_3A8D4:
ObjB2_Main_WFZ_Start_main:
    subq.w  #1,objoff_32(a0)
    bmi.s   +
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo27_SolidObject
    bra.w   ObjB2_Horizontal_limit
; ===========================================================================
+ ; loc_3A8FC:
    addq.b  #2,routine_secondary(a0)
    move.w  #$60,objoff_2A(a0)
    move.w  #1,objoff_32(a0)
    move.w  #$100,x_vel(a0)
    move.w  #$100,y_vel(a0)
    rts
; ===========================================================================
; loc_3A91A:
ObjB2_Main_WFZ_Start_shot_down:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +
    moveq   #SndID_Scatter,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
+ ; loc_3A92A:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
- ; loc_3A930:
    bsr.w   ObjB2_Align_plane
    subq.w  #1,objoff_32(a0)
    bne.w   return_37A48
    move.w  #$E,objoff_32(a0)
    bra.w   ObjB2_Main_WFZ_Start_load_smoke
; ===========================================================================
+ ; loc_3A946:
    addq.b  #2,routine_secondary(a0)
    bra.w   loc_3B7BC
; ===========================================================================
; loc_3A94E:
ObjB2_Main_WFZ_Start_fall_down:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bra.s   -
; ===========================================================================
; loc_3A954:
ObjB2_Main_WFZ_End:
    bsr.w   ObjB2_Animate_Pilot
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjB2_Main_WFZ_states(pc,d0.w),d1
    jsr ObjB2_Main_WFZ_states(pc,d1.w)
    lea (Ani_objB2_a).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
; off_3A970:
ObjB2_Main_WFZ_states:  offsetTable
        offsetTableEntry.w ObjB2_Wait_Leader_position   ;   0
        offsetTableEntry.w ObjB2_Move_Leader_edge   ;   2
        offsetTableEntry.w ObjB2_Wait_for_plane ;   4
        offsetTableEntry.w ObjB2_Prepare_to_jump    ;   6
        offsetTableEntry.w ObjB2_Jump_to_plane  ;   8
        offsetTableEntry.w ObjB2_Landed_on_plane    ;  $A
        offsetTableEntry.w ObjB2_Approaching_ship   ;  $C
        offsetTableEntry.w ObjB2_Jump_to_ship   ;  $E
        offsetTableEntry.w ObjB2_Dock_on_DEZ    ; $10
; ===========================================================================
; loc_3A982:
ObjB2_Wait_Leader_position:
    lea (MainCharacter).w,a1 ; a1=character
    cmpi.w  #$5EC,y_pos(a1)
    blo.s   +   ; rts
    clr.w   (Ctrl_1_Logical).w
    addq.w  #1,objoff_2E(a0)
    cmpi.w  #$40,objoff_2E(a0)
    bhs.s   ++
+ ; return_3A99E:
    rts
; ===========================================================================
+ ; loc_3A9A0:
    addq.b  #2,routine_secondary(a0)
    move.w  #$2E58,x_pos(a0)
    move.w  #$66C,y_pos(a0)
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   ObjB2_Waiting_animation
    lea (word_3AFBC).l,a2
    bsr.w   LoadChildObject
    move.w  #$3118,x_pos(a1)
    move.w  #$3F0,y_pos(a1)
    lea (word_3AFB8).l,a2
    bsr.w   LoadChildObject
    move.w  #$3070,x_pos(a1)
    move.w  #$3B0,y_pos(a1)
    lea (word_3AFB8).l,a2
    bsr.w   LoadChildObject
    move.w  #$3070,x_pos(a1)
    move.w  #$430,y_pos(a1)
    lea (word_3AFC0).l,a2
    bsr.w   LoadChildObject
    clr.w   x_pos(a1)
    clr.w   y_pos(a1)
    rts
; ===========================================================================
; loc_3AA0E: ObjB2_Move_Leader_egde:
ObjB2_Move_Leader_edge:
    lea (MainCharacter).w,a1 ; a1=character
    cmpi.w  #$2E30,x_pos(a1)
    bhs.s   +
    move.w  #(button_right_mask<<8)|button_right_mask,(Ctrl_1_Logical).w
    rts
; ===========================================================================
+ ; loc_3AA22:
    addq.b  #2,routine_secondary(a0)
    clr.w   (Ctrl_1_Logical).w
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    move.w  #$600,(Sonic_top_speed).w
    move.w  #$C,(Sonic_acceleration).w
    move.w  #$80,(Sonic_deceleration).w
    bra.w   ObjB2_Waiting_animation
; ===========================================================================
; loc_3AA4C:
ObjB2_Wait_for_plane:
    cmpi.w  #$380,(Camera_BG_X_offset).w
    bhs.s   +
    clr.w   (Ctrl_1_Logical).w
    bra.w   ObjB2_Waiting_animation
; ===========================================================================
+ ; loc_3AA5C:
    addq.b  #2,routine_secondary(a0)
    move.w  #$100,x_vel(a0)
    move.w  #-$100,y_vel(a0)
    clr.w   objoff_2A(a0)
    bra.w   ObjB2_Waiting_animation
; ===========================================================================
; loc_3AA74:
ObjB2_Prepare_to_jump:
    bsr.w   ObjB2_Waiting_animation
    addq.w  #1,objoff_2A(a0)
    cmpi.w  #$30,objoff_2A(a0)
    bne.s   +
    addq.b  #2,routine_secondary(a0)
    move.w  #(button_A_mask<<8)|button_A_mask,(Ctrl_1_Logical).w
    move.w  #$38,objoff_2E(a0)
    tst.b   (Super_Sonic_flag).w
    beq.s   +
    move.w  #$28,objoff_2E(a0)
+ ; loc_3AAA0:
    bsr.w   ObjB2_Align_plane
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3AAA8:
ObjB2_Jump_to_plane:
    clr.w   (Ctrl_1_Logical).w
    addq.w  #1,objoff_2A(a0)
    subq.w  #1,objoff_2E(a0)
    bmi.s   +
    move.w  #((button_right_mask|button_A_mask)<<8)|button_right_mask|button_A_mask,(Ctrl_1_Logical).w
+ ; loc_3AABC:
    bsr.w   ObjB2_Align_plane
    btst    #p1_standing_bit,status(a0)
    beq.s   +
    addq.b  #2,routine_secondary(a0)
    move.w  #$20,objoff_2E(a0)
    lea (Level_Layout+$0D2).w,a1
    move.l  #$501F0025,(a1)+
    lea (Level_Layout+$1D2).w,a1
    move.l  #$25001F50,(a1)+
    lea (Level_Layout+$BD6).w,a1
    move.l  #$501F0025,(a1)+
    lea (Level_Layout+$CD6).w,a1
    move.l  #$25001F50,(a1)+
+ ; BranchTo6_JmpTo45_DisplaySprite:
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3AAFE:
ObjB2_Landed_on_plane:
    addq.w  #1,objoff_2A(a0)
    cmpi.w  #$100,objoff_2A(a0)
    blo.s   loc_3AB18
    addq.b  #2,routine_secondary(a0)
    movea.w objoff_3A(a0),a1 ; a1=object ??
    move.b  #2,routine_secondary(a1)
 
loc_3AB18:
    clr.w   (Ctrl_1_Logical).w
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a0),x_pos(a1)
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    clr.w   inertia(a1)
    bclr    #1,status(a1)
    bclr    #2,status(a1)
    move.l  #$1000505,mapping_frame(a1)
    move.w  #$100,anim_frame_duration(a1)
    move.b  #$13,y_radius(a1)
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    move.b  #$F,y_radius(a1)
+ ; loc_3AB60:
    bsr.w   ObjB2_Align_plane
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3AB68:
ObjB2_Approaching_ship:
    clr.w   (Ctrl_1_Logical).w
    bsr.w   ObjB2_Waiting_animation
    cmpi.w  #$437,objoff_2A(a0)
    blo.s   loc_3AB8A
    addq.b  #2,routine_secondary(a0)
; loc_3AB7C:
ObjB2_Jump_to_ship:
    cmpi.w  #$447,objoff_2A(a0)
    bhs.s   loc_3AB8A
    move.w  #(button_A_mask<<8)|button_A_mask,(Ctrl_1_Logical).w
 
loc_3AB8A:
    cmpi.w  #$460,objoff_2A(a0)
    blo.s   ObjB2_Dock_on_DEZ
    move.b  #6,(Dynamic_Resize_Routine).w ; => LevEvents_WFZ_Routine4
    addq.b  #2,routine_secondary(a0)
    lea (word_3AFB8).l,a2
    bsr.w   LoadChildObject
    move.w  #$3090,x_pos(a1)
    move.w  #$3D0,y_pos(a1)
    lea (word_3AFB8).l,a2
    bsr.w   LoadChildObject
    move.w  #$30C0,x_pos(a1)
    move.w  #$3F0,y_pos(a1)
    lea (word_3AFB8).l,a2
    bsr.w   LoadChildObject
    move.w  #$3090,x_pos(a1)
    move.w  #$410,y_pos(a1)
; loc_3ABDE:
ObjB2_Dock_on_DEZ:
    cmpi.w  #$9C0,objoff_2A(a0)
    bhs.s   ObjB2_Start_DEZ
    move.w  objoff_2A(a0),d0
    addq.w  #1,d0
    move.w  d0,objoff_2A(a0)
    move.w  objoff_34(a0),d1
    move.w  word_3AC16(pc,d1.w),d2
    cmp.w   d2,d0
    blo.s   loc_3AC0E
    addq.w  #2,d1
    move.w  d1,objoff_34(a0)
    lea byte_3AC2A(pc,d1.w),a1
    move.b  (a1)+,x_vel(a0)
    move.b  (a1)+,y_vel(a0)
 
loc_3AC0E:
    bsr.w   ObjB2_Align_plane
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
word_3AC16:
    dc.w  $1E0
    dc.w  $260  ; 1
    dc.w  $2A0  ; 2
    dc.w  $2C0  ; 3
    dc.w  $300  ; 4
    dc.w  $3A0  ; 5
    dc.w  $3F0  ; 6
    dc.w  $460  ; 7
    dc.w  $4A0  ; 8
    dc.w  $580  ; 9
byte_3AC2A:
    dc.b $FF
    dc.b $FF    ; 1
    dc.b   1    ; 2
    dc.b   0    ; 3
    dc.b   0    ; 4
    dc.b   1    ; 5
    dc.b   1    ; 6
    dc.b $FF    ; 7
    dc.b   1    ; 8
    dc.b   1    ; 9
    dc.b   1    ; 10
    dc.b $FF    ; 11
    dc.b $FF    ; 12
    dc.b   1    ; 13
    dc.b $FF    ; 14
    dc.b $FF    ; 15
    dc.b $FF    ; 16
    dc.b   1    ; 17
    dc.b $FE    ; 18
    dc.b   0    ; 19
    dc.b   0    ; 20
    dc.b   0    ; 21
; ===========================================================================
; loc_3AC40:
ObjB2_Start_DEZ:
    move.w  #death_egg_zone_act_1,(Current_ZoneAndAct).w
; loc_3AC46:
ObjB2_Deactivate_level:
    move.w  #1,(Level_Inactive_flag).w
    clr.b   (Last_star_pole_hit).w
    clr.b   (Last_star_pole_hit_2P).w
    rts
; ===========================================================================
; loc_3AC56:
ObjB2_Waiting_animation:
    lea (MainCharacter).w,a1 ; a1=character
    move.l  #$1000505,mapping_frame(a1)
    move.w  #$100,anim_frame_duration(a1)
    rts
; ===========================================================================
; loc_3AC6A:
ObjB2_Invisible_grabber:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3AC78(pc,d0.w),d1
    jmp off_3AC78(pc,d1.w)
; ===========================================================================
off_3AC78:  offsetTable
        offsetTableEntry.w loc_3AC7E    ; 0
        offsetTableEntry.w loc_3AC84    ; 2
        offsetTableEntry.w loc_3ACF2    ; 4
; ===========================================================================
 
loc_3AC7E:
    move.b  #$C7,collision_flags(a0)
 
loc_3AC84:
    tst.b   collision_property(a0)
    beq.s   return_3ACF0
    addq.b  #2,routine_secondary(a0)
    clr.b   collision_flags(a0)
    move.w  #(224/2)+8,(Camera_Y_pos_bias).w
    movea.w objoff_2C(a0),a1 ; a1=object
    bset    #6,status(a1)
    lea (MainCharacter).w,a1 ; a1=character
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    move.w  x_pos(a0),d0
    subi.w  #$10,d0
    move.w  d0,x_pos(a1)
    cmpi.w  #2,(Player_mode).w
    bne.s   loc_3ACC8
    subi.w  #$10,y_pos(a1)
 
loc_3ACC8:
    bset    #0,status(a1)
    bclr    #1,status(a1)
    bclr    #2,status(a1)
    move.b  #AniIDSonAni_Hang,anim(a1)
    move.b  #1,(MainCharacter+obj_control).w
    move.b  #1,(WindTunnel_holding_flag).w
    clr.w   (Ctrl_1_Logical).w
 
return_3ACF0:
    rts
; ===========================================================================
 
loc_3ACF2:
    lea (MainCharacter).w,a1 ; a1=character
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    move.w  x_pos(a0),d0
    subi.w  #$10,d0
    move.w  d0,x_pos(a1)
    rts
; ===========================================================================
 
loc_3AD0C:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3AD1A(pc,d0.w),d1
    jmp off_3AD1A(pc,d1.w)
; ===========================================================================
off_3AD1A:  offsetTable
        offsetTableEntry.w +    ; 0
; ===========================================================================
+ ; loc_3AD1C:
    bchg    #2,status(a0)
    bne.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3AD2A:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3AD38(pc,d0.w),d1
    jmp off_3AD38(pc,d1.w)
; ===========================================================================
off_3AD38:  offsetTable
        offsetTableEntry.w +    ; 0
; ===========================================================================
+ ; loc_3AD3A:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3AD42:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3AD50(pc,d0.w),d1
    jmp off_3AD50(pc,d1.w)
; ===========================================================================
off_3AD50:  offsetTable
        offsetTableEntry.w loc_3AD54    ; 0
        offsetTableEntry.w loc_3AD5C    ; 2
; ===========================================================================
 
loc_3AD54:
    bsr.w   loc_3AD6E
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3AD5C:
    bsr.w   loc_3AD6E
    lea (Ani_objB2_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3AD6E:
    movea.w objoff_2C(a0),a1 ; a1=object
    move.w  x_pos(a1),d0
    subi.w  #$C,d0
    move.w  d0,x_pos(a0)
    move.w  y_pos(a1),d0
    addi.w  #$28,d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
; loc_3AD8C:
ObjB2_Align_plane:
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_36776
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  (sp)+,d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
; loc_3ADAA:
ObjB2_Move_with_player:
    lea (MainCharacter).w,a1 ; a1=character
    btst    #3,status(a1)
    beq.s   ObjB2_Move_below_player
    bsr.w   ObjB2_Move_vert
    bsr.w   ObjB2_Vertical_limit
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bra.w   loc_36776
; ===========================================================================
; loc_3ADC6:
ObjB2_Move_below_player:
    tst.b   objoff_2E(a0)
    beq.s   loc_3ADD4
    bsr.w   Obj_GetOrientationToPlayer
    move.w  d2,objoff_38(a0)
 
loc_3ADD4:
    move.w  #1,d0
    move.w  objoff_38(a0),d3
    beq.s   loc_3ADE8
    bmi.s   loc_3ADE2
    neg.w   d0
 
loc_3ADE2:
    add.w   d0,d3
    move.w  d3,objoff_38(a0)
 
loc_3ADE8:
    move.w  x_pos(a1),d1
    add.w   d3,d1
    move.w  d1,x_pos(a0)
    bra.w   loc_36776
; ===========================================================================
; loc_3ADF6:
ObjB2_Move_vert:
    tst.b   objoff_2F(a0)
    bne.s   loc_3AE16
    tst.b   objoff_2E(a0)
    beq.s   return_3AE38
    st  objoff_2F(a0)
    clr.b   objoff_30(a0)
    move.w  #$200,y_vel(a0)
    move.b  #$14,objoff_31(a0)
 
loc_3AE16:
    subq.b  #1,objoff_31(a0)
    bpl.s   loc_3AE26
    clr.b   objoff_2F(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_3AE26:
    move.w  y_vel(a0),d0
    cmpi.w  #-$100,d0
    ble.s   loc_3AE34
    addi.w  #-$20,d0
 
loc_3AE34:
    move.w  d0,y_vel(a0)
 
return_3AE38:
    rts
; ===========================================================================
; loc_3AE3A:
ObjB2_Move_obbey_player:
    lea (MainCharacter).w,a1 ; a1=character
    btst    #3,status(a1)
    beq.s   ObjB2_Move_vert2
    tst.b   objoff_2F(a0)
    bne.s   loc_3AE72
    clr.w   y_vel(a0)
    move.w  (Ctrl_1).w,d2
    move.w  #$80,d3
    andi.w  #(button_up_mask|button_down_mask)<<8,d2
    beq.s   loc_3AE72
    andi.w  #button_down_mask<<8,d2
    bne.s   loc_3AE66
    neg.w   d3
 
loc_3AE66:
    move.w  d3,y_vel(a0)
    bsr.w   ObjB2_Vertical_limit
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
 
loc_3AE72:
    bsr.w   Obj_GetOrientationToPlayer
    moveq   #$10,d3
    add.w   d3,d2
    cmpi.w  #$20,d2
    blo.s   return_3AE9E
    mvabs.w inertia(a1),d2
    cmpi.w  #$900,d2
    bhs.s   return_3AE9E
    tst.w   d0
    beq.s   loc_3AE94
    neg.w   d3
 
loc_3AE94:
    move.w  x_pos(a1),d1
    add.w   d3,d1
    move.w  d1,x_pos(a0)
 
return_3AE9E:
    rts
; ===========================================================================
; loc_3AEA0:
ObjB2_Move_vert2:
    tst.b   objoff_30(a0)
    bne.s   loc_3AEC0
    tst.b   objoff_2E(a0)
    beq.s   return_3AE9E
    st  objoff_30(a0)
    clr.b   objoff_2F(a0)
    move.w  #$200,y_vel(a0)
    move.b  #$2B,objoff_31(a0)
 
loc_3AEC0:
    subq.b  #1,objoff_31(a0)
    bpl.s   loc_3AED0
    clr.b   objoff_30(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_3AED0:
    move.w  y_vel(a0),d0
    cmpi.w  #-$100,d0
    ble.s   loc_3AEDE
    addi.w  #-$20,d0
 
loc_3AEDE:
    move.w  d0,y_vel(a0)
    bsr.w   ObjB2_Vertical_limit
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    rts
; ===========================================================================
; loc_3AEEC:
ObjB2_Horizontal_limit:
    bsr.w   Obj_GetOrientationToPlayer
    moveq   #$10,d3
    add.w   d3,d2
    cmpi.w  #$20,d2
    blo.s   return_3AF0A
    tst.w   d0
    beq.s   loc_3AF00
    neg.w   d3
 
loc_3AF00:
    move.w  x_pos(a0),d1
    sub.w   d3,d1
    move.w  d1,x_pos(a1)
 
return_3AF0A:
    rts
; ===========================================================================
; loc_3AF0C:
ObjB2_Vertical_limit:
    move.w  (Camera_Y_pos).w,d0
    move.w  y_pos(a0),d1
    move.w  y_vel(a0),d2
    beq.s   return_3AF32
    bpl.s   loc_3AF26
    addi.w  #$34,d0
    cmp.w   d0,d1
    blo.s   loc_3AF2E
    rts
; ===========================================================================
 
loc_3AF26:
    addi.w  #$A8,d0
    cmp.w   d0,d1
    blo.s   return_3AF32
 
loc_3AF2E:
    clr.w   y_vel(a0)
 
return_3AF32:
    rts
; ===========================================================================
; loc_3AF34:
ObjB2_Main_WFZ_Start_load_smoke:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   +
    _move.b #ObjID_TornadoSmoke2,id(a1) ; load objC3
    move.b  #$90,subtype(a1) ; <== ObjC3_SubObjData
    move.w  a0,objoff_2C(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
+ ; return_3AF56:
    rts
; ===========================================================================
; loc_3AF58:
ObjB2_Animate_Pilot:
    subq.b  #1,objoff_37(a0)
    bmi.s   +
    rts
; ===========================================================================
+ ; loc_3AF60:
    move.b  #8,objoff_37(a0)
    moveq   #0,d0
    move.b  objoff_36(a0),d0
    moveq   #Tails_pilot_frames_end-Tails_pilot_frames,d1
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    moveq   #Sonic_pilot_frames_end-Sonic_pilot_frames,d1
+ ; loc_3AF78:
    addq.b  #1,d0
    cmp.w   d1,d0
    blo.s   +
    moveq   #0,d0
+ ; loc_3AF80:
    move.b  d0,objoff_36(a0)
    cmpi.w  #2,(Player_mode).w
    bne.s   +
    move.b  Sonic_pilot_frames(pc,d0.w),d0
    jmpto   (LoadSonicDynPLC_Part2).l, JmpTo_LoadSonicDynPLC_Part2
; ===========================================================================
+ ; loc_3AF94:
    move.b  Tails_pilot_frames(pc,d0.w),d0
    jmpto   (LoadTailsDynPLC_Part2).l, JmpTo_LoadTailsDynPLC_Part2
; ===========================================================================
; byte_3AF9C:
Sonic_pilot_frames:
    dc.b $2D
    dc.b $2E    ; 1
    dc.b $2F    ; 2
    dc.b $30    ; 3
Sonic_pilot_frames_end:
 
; byte_3AFA0:
Tails_pilot_frames:
    dc.b $10
    dc.b $10    ; 1
    dc.b $10    ; 2
    dc.b $10    ; 3
    dc.b   1    ; 4
    dc.b   2    ; 5
    dc.b   3    ; 6
    dc.b   2    ; 7
    dc.b   1    ; 8
    dc.b   1    ; 9
    dc.b $10    ; 10
    dc.b $10    ; 11
    dc.b $10    ; 12
    dc.b $10    ; 13
    dc.b   1    ; 14
    dc.b   2    ; 15
    dc.b   3    ; 16
    dc.b   2    ; 17
    dc.b   1    ; 18
    dc.b   1    ; 19
    dc.b   4    ; 20
    dc.b   4    ; 21
    dc.b   1    ; 22
    dc.b   1    ; 23
Tails_pilot_frames_end:
 
word_3AFB8:
    dc.w objoff_3E
    dc.b ObjID_Tornado
    dc.b $58
word_3AFBC:
    dc.w objoff_3C
    dc.b ObjID_Tornado
    dc.b $56
word_3AFC0:
    dc.w objoff_3A
    dc.b ObjID_Tornado
    dc.b $5C
; seems unused
    dc.w objoff_3E
    dc.b ObjID_Tornado
    dc.b $5A
; off_3AFC8:
ObjB2_SubObjData:
    subObjData ObjB2_MapUnc_3AFF2,make_art_tile(ArtTile_ArtNem_Tornado,0,1),4,4,$60,0
; off_3AFD2:
ObjB2_SubObjData2:
    subObjData ObjB2_MapUnc_3B292,make_art_tile(ArtTile_ArtNem_TornadoThruster,0,0),4,3,$40,0
; animation script
; off_3AFDC:
Ani_objB2_a:    offsetTable
        offsetTableEntry.w byte_3AFE0   ; 0
        offsetTableEntry.w byte_3AFE6   ; 1
byte_3AFE0: dc.b   0,  0,  1,  2,  3,$FF
byte_3AFE6: dc.b   0,  4,  5,  6,  7,$FF
        even
; animation script
; off_3AFEC:
Ani_objB2_b:    offsetTable
        offsetTableEntry.w +    ; 0
; byte_3AFEE:
+       dc.b   0,  1,  2,$FF
        even
; -----------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------
ObjB2_MapUnc_3AFF2: BINCLUDE "mappings/sprite/objB2_a.bin"
; -----------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------
ObjB2_MapUnc_3B292: BINCLUDE "mappings/sprite/objB2_b.bin"
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B3 - Clouds (placeable object) from SCZ
; ----------------------------------------------------------------------------
; Sprite_3B2DE:
ObjB3:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB3_Index(pc,d0.w),d1
    jmp ObjB3_Index(pc,d1.w)
; ===========================================================================
; off_3B2EC:
ObjB3_Index:    offsetTable
        offsetTableEntry.w ObjB3_Init   ; 0
        offsetTableEntry.w ObjB3_Main   ; 2
; ===========================================================================
; loc_3B2F0:
ObjB3_Init:
    bsr.w   LoadSubObject
    moveq   #0,d0
    move.b  subtype(a0),d0
    subi.b  #$5E,d0
    move.w  word_3B30C(pc,d0.w),x_vel(a0)
    lsr.w   #1,d0
    move.b  d0,mapping_frame(a0)
    rts
; ===========================================================================
word_3B30C:
    dc.w  -$80
    dc.w  -$40  ; 1
    dc.w  -$20  ; 2
; ===========================================================================
; loc_3B312:
ObjB3_Main:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.w  (Tornado_Velocity_X).w,d0
    add.w   d0,x_pos(a0)
    bra.w   Obj_DeleteBehindScreen
; ===========================================================================
; off_3B322:
ObjB3_SubObjData:
    subObjData ObjB3_MapUnc_3B32C,make_art_tile(ArtTile_ArtNem_Clouds,2,0),4,6,$30,0
 
; -----------------------------------------------------------------------------
; sprite mappings
; -----------------------------------------------------------------------------
ObjB3_MapUnc_3B32C: BINCLUDE "mappings/sprite/objB3.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B4 - Vertical propeller from WFZ
; ----------------------------------------------------------------------------
; Sprite_3B36A:
ObjB4:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB4_Index(pc,d0.w),d1
    jmp ObjB4_Index(pc,d1.w)
; ===========================================================================
; off_3B378:
ObjB4_Index:    offsetTable
        offsetTableEntry.w ObjB4_Init   ; 0
        offsetTableEntry.w ObjB4_Main   ; 2
; ===========================================================================
; loc_3B37C:
ObjB4_Init:
    bsr.w   LoadSubObject
    bclr    #1,render_flags(a0)
    beq.s   +
    clr.b   collision_flags(a0)
+
    rts
; ===========================================================================
; loc_3B38E:
ObjB4_Main:
    lea (Ani_objB4).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +
    moveq   #SndID_Helicopter,d0
    jsrto   (PlaySoundLocal).l, JmpTo_PlaySoundLocal
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3B3AC:
ObjB4_SubObjData:
    subObjData ObjB4_MapUnc_3B3BE,make_art_tile(ArtTile_ArtNem_WfzVrtclPrpllr,1,1),4,4,4,$A8
; animation script
; off_3B3B6:
Ani_objB4:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,  2,$FF,  0
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjB4_MapUnc_3B3BE: BINCLUDE "mappings/sprite/objB4.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B5 - Horizontal propeller from WFZ
; ----------------------------------------------------------------------------
; Sprite_3B3FA:
ObjB5:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB5_Index(pc,d0.w),d1
    jmp ObjB5_Index(pc,d1.w)
; ===========================================================================
; off_3B408:
ObjB5_Index:    offsetTable
        offsetTableEntry.w ObjB5_Init       ; 0
        offsetTableEntry.w ObjB5_Main       ; 2 - used in WFZ
        offsetTableEntry.w ObjB5_Animate    ; 4 - used in SCZ, no effect on players
; ===========================================================================
; loc_3B40E:
ObjB5_Init:
    bsr.w   LoadSubObject
    move.b  #4,anim(a0)
    move.b  subtype(a0),d0
    subi.b  #$64,d0
    move.b  d0,routine(a0)
    rts
; ===========================================================================
; loc_3B426:
ObjB5_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3B442(pc,d0.w),d1
    jsr off_3B442(pc,d1.w)
    lea (Ani_objB5).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3B442:  offsetTable
        offsetTableEntry.w +    ; 0
; ===========================================================================
+   bra.w   ObjB5_CheckPlayers
; ===========================================================================
; loc_3B448:
ObjB5_Animate:
    lea (Ani_objB5).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_3B456:
ObjB5_CheckPlayers:
    cmpi.b  #4,anim(a0)
    bne.s   ++  ; rts
    lea (MainCharacter).w,a1 ; a1=character
    bsr.w   ObjB5_CheckPlayer
    lea (Sidekick).w,a1 ; a1=character
; loc_3B46A:
ObjB5_CheckPlayer:
    move.w  x_pos(a1),d0
    sub.w   x_pos(a0),d0
    addi.w  #$40,d0
    cmpi.w  #$80,d0
    bhs.s   ++  ; rts
    moveq   #0,d1
    move.b  (Oscillating_Data+$14).w,d1
    add.w   y_pos(a1),d1
    addi.w  #$60,d1
    sub.w   y_pos(a0),d1
    bcs.s   ++  ; rts
    cmpi.w  #$90,d1
    bhs.s   ++  ; rts
    subi.w  #$60,d1
    bcs.s   +
    not.w   d1
    add.w   d1,d1
+
    addi.w  #$60,d1
    neg.w   d1
    asr.w   #4,d1
    add.w   d1,y_pos(a1)
    bset    #1,status(a1)
    move.w  #0,y_vel(a1)
    move.w  #1,inertia(a1)
    tst.b   flip_angle(a1)
    bne.s   +   ; rts
    move.b  #1,flip_angle(a1)
    move.b  #AniIDSonAni_Float2,anim(a1)
    move.b  #$7F,flips_remaining(a1)
    move.b  #8,flip_speed(a1)
+
    rts
; ===========================================================================
; off_3B4DE:
ObjB5_SubObjData:
    subObjData ObjB5_MapUnc_3B548,make_art_tile(ArtTile_ArtNem_WfzHrzntlPrpllr,1,1),4,4,$40,0
 
; animation script
; off_3B4E8:
Ani_objB5:  offsetTable
        offsetTableEntry.w byte_3B4FC   ; 0
        offsetTableEntry.w byte_3B506   ; 1
        offsetTableEntry.w byte_3B50E   ; 2
        offsetTableEntry.w byte_3B516   ; 3
        offsetTableEntry.w byte_3B51C   ; 4
        offsetTableEntry.w byte_3B524   ; 5
        offsetTableEntry.w byte_3B52A   ; 6
        offsetTableEntry.w byte_3B532   ; 7
        offsetTableEntry.w byte_3B53A   ; 8
        offsetTableEntry.w byte_3B544   ; 9
byte_3B4FC: dc.b   7,  0,  1,  2,  3,  4,  5,$FD,  1,  0
byte_3B506: dc.b   4,  0,  1,  2,  3,  4,$FD,  2
byte_3B50E: dc.b   3,  5,  0,  1,  2,$FD,  3,  0
byte_3B516: dc.b   2,  3,  4,  5,$FD,  4
byte_3B51C: dc.b   1,  0,  1,  2,  3,  4,  5,$FF
byte_3B524: dc.b   2,  5,  4,  3,$FD,  6
byte_3B52A: dc.b   3,  2,  1,  0,  5,$FD,  7,  0
byte_3B532: dc.b   4,  4,  3,  2,  1,  0,$FD,  8
byte_3B53A: dc.b   7,  5,  4,  3,  2,  1,  0,$FD,  9,  0
byte_3B544: dc.b $7E,  0,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjB5_MapUnc_3B548: BINCLUDE "mappings/sprite/objB5.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B6 - Tilting platform from WFZ
; ----------------------------------------------------------------------------
; Sprite_3B5D0:
ObjB6:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB6_Index(pc,d0.w),d1
    jmp ObjB6_Index(pc,d1.w)
; ===========================================================================
; off_3B5DE:
ObjB6_Index:    offsetTable
        offsetTableEntry.w ObjB6_Init   ; 0
        offsetTableEntry.w loc_3B602    ; 2
        offsetTableEntry.w loc_3B65C    ; 4
        offsetTableEntry.w loc_3B6C8    ; 6
        offsetTableEntry.w loc_3B73C    ; 8
; ===========================================================================
; loc_3B5E8:
ObjB6_Init:
    moveq   #0,d0
    move.b  #($35<<1),d0
    bsr.w   LoadSubObject_Part2
    move.b  subtype(a0),d0
    andi.b  #6,d0
    addq.b  #2,d0
    move.b  d0,routine(a0)
    rts
; ===========================================================================
 
loc_3B602:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3B614(pc,d0.w),d1
    jsr off_3B614(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3B614:  offsetTable
        offsetTableEntry.w loc_3B61C    ; 0
        offsetTableEntry.w loc_3B624    ; 2
        offsetTableEntry.w loc_3B644    ; 4
        offsetTableEntry.w loc_3B64E    ; 6
; ===========================================================================
 
loc_3B61C:
    addq.b  #2,routine_secondary(a0)
    bra.w   loc_3B77E
; ===========================================================================
 
loc_3B624:
    bsr.w   loc_3B790
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$F0,d0
    cmp.b   subtype(a0),d0
    beq.s   loc_3B638
    rts
; ===========================================================================
 
loc_3B638:
    addq.b  #2,routine_secondary(a0)
    clr.b   anim(a0)
    bra.w   loc_3B7BC
; ===========================================================================
 
loc_3B644:
    lea (Ani_objB6).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
 
loc_3B64E:
    move.b  #2,routine_secondary(a0)
    move.w  #$C0,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3B65C:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3B66E(pc,d0.w),d1
    jsr off_3B66E(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3B66E:  offsetTable
        offsetTableEntry.w loc_3B61C
        offsetTableEntry.w loc_3B674
        offsetTableEntry.w loc_3B6A6
; ===========================================================================
 
loc_3B674:
    bsr.w   loc_3B790
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.b  #$20,objoff_2A(a0)
    move.b  #3,anim(a0)
    clr.b   anim_frame(a0)
    clr.b   anim_frame_duration(a0)
    bsr.w   loc_3B7BC
    bsr.w   loc_3B7F8
    moveq   #SndID_Fire,d0
    jmpto   (PlaySound).l, JmpTo12_PlaySound
; ===========================================================================
 
loc_3B6A6:
    subq.b  #1,objoff_2A(a0)
    bmi.s   +
    lea (Ani_objB6).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
+
    move.b  #2,routine_secondary(a0)
    clr.b   mapping_frame(a0)
    move.w  #$C0,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3B6C8:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3B6DA(pc,d0.w),d1
    jsr off_3B6DA(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3B6DA:  offsetTable
        offsetTableEntry.w loc_3B6E2    ; 0
        offsetTableEntry.w loc_3B6FE    ; 2
        offsetTableEntry.w loc_3B72C    ; 4
        offsetTableEntry.w loc_3B736    ; 6
; ===========================================================================
 
loc_3B6E2:
    bsr.w   loc_3B790
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    bne.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$10,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3B6FE:
    bsr.w   loc_3B790
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    rts
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.b  #0,anim(a0)
    bsr.w   Obj_GetOrientationToPlayer
    bclr    #0,status(a0)
    tst.w   d0
    bne.s   +
    bset    #0,status(a0)
+
    bra.w   loc_3B7BC
; ===========================================================================
 
loc_3B72C:
    lea (Ani_objB6).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
 
loc_3B736:
    clr.b   routine_secondary(a0)
    rts
; ===========================================================================
 
loc_3B73C:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3B74E(pc,d0.w),d1
    jsr off_3B74E(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3B74E:  offsetTable
        offsetTableEntry.w loc_3B756    ; 0
        offsetTableEntry.w loc_3B764    ; 2
        offsetTableEntry.w loc_3B644    ; 4
        offsetTableEntry.w loc_3B64E    ; 6
; ===========================================================================
 
loc_3B756:
    addq.b  #2,routine_secondary(a0)
    move.b  #2,mapping_frame(a0)
    bra.w   loc_3B77E
; ===========================================================================
 
loc_3B764:
    bsr.w   loc_3B7A6
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3B770
    rts
; ===========================================================================
 
loc_3B770:
    addq.b  #2,routine_secondary(a0)
    move.b  #4,anim(a0)
    bra.w   loc_3B7BC
; ===========================================================================
 
loc_3B77E:
    move.b  subtype(a0),d0
    andi.w  #$F0,d0
    move.b  d0,subtype(a0)
    move.w  d0,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3B790:
    move.w  x_pos(a0),-(sp)
    move.w  #$23,d1
    move.w  #4,d2
    move.w  #4,d3
    move.w  (sp)+,d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
 
loc_3B7A6:
    move.w  x_pos(a0),-(sp)
    move.w  #$F,d1
    move.w  #$18,d2
    move.w  #$18,d3
    move.w  (sp)+,d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
 
loc_3B7BC:
    move.b  status(a0),d0
    if gameRevision<2
    andi.b  #standing_mask,d0
    else
    ; I don't know what this change was meant to do, but it causes
    ; Sonic to not fall off ObjBD's ascending platforms when they retract,
    ; making him hover.
    andi.b  #2,d0
    endif
    beq.s   return_3B7F6
    bclr    #p1_standing_bit,status(a0)
    beq.s   loc_3B7DE
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #3,status(a1)
    bset    #1,status(a1)
 
loc_3B7DE:
    bclr    #p2_standing_bit,status(a0)
    beq.s   return_3B7F6
    lea (Sidekick).w,a1 ; a1=character
    bclr    #4,status(a1)
    bset    #1,status(a1)
 
return_3B7F6:
    rts
; ===========================================================================
 
loc_3B7F8:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   +
    _move.b #ObjID_VerticalLaser,id(a1) ; load objB7 (huge unused vertical laser!)
    move.b  #$72,subtype(a1) ; <== ObjB7_SubObjData
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
+
    rts
; ===========================================================================
; off_3B818:
ObjB6_SubObjData:
    subObjData ObjB6_MapUnc_3B856,make_art_tile(ArtTile_ArtNem_WfzTiltPlatforms,1,1),4,4,$10,0
 
; animation script
; off_3B822:
Ani_objB6:  offsetTable
        offsetTableEntry.w byte_3B830   ; 0
        offsetTableEntry.w byte_3B836   ; 1
        offsetTableEntry.w byte_3B83A   ; 2
        offsetTableEntry.w byte_3B840   ; 3
        offsetTableEntry.w byte_3B846   ; 4
        offsetTableEntry.w byte_3B84C   ; 5
        offsetTableEntry.w byte_3B850   ; 6
byte_3B830: dc.b   3,  1,  2,$FD,  1,  0
byte_3B836: dc.b $3F,  2,$FD,  2
byte_3B83A: dc.b   3,  2,  1,  0,$FA,  0
byte_3B840: dc.b   1,  0,  1,  2,  3,$FF
byte_3B846: dc.b   3,  1,  0,$FD,  5,  0
byte_3B84C: dc.b $3F,  0,$FD,  6
byte_3B850: dc.b   3,  0,  1,  2,$FA,  0
    even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjB6_MapUnc_3B856: BINCLUDE "mappings/sprite/objB6.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B7 - Unused huge vertical laser from WFZ
; ----------------------------------------------------------------------------
; Sprite_3B8A6:
ObjB7:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB7_Index(pc,d0.w),d1
    jmp ObjB7_Index(pc,d1.w)
; ===========================================================================
; off_3B8B4:
ObjB7_Index:    offsetTable
        offsetTableEntry.w ObjB7_Init   ; 0
        offsetTableEntry.w ObjB7_Main   ; 2
; ===========================================================================
; loc_3B8B8:
ObjB7_Init:
    bsr.w   LoadSubObject
    move.b  #$20,objoff_2A(a0)
    rts
; ===========================================================================
; loc_3B8C4:
ObjB7_Main:
    subq.b  #1,objoff_2A(a0)
    beq.w   JmpTo65_DeleteObject
    bchg    #0,objoff_2B(a0)
    beq.w   return_37A48
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3B8DA:
ObjB7_SubObjData:
    subObjData ObjB7_MapUnc_3B8E4,make_art_tile(ArtTile_ArtNem_WfzVrtclLazer,2,1),4,4,$18,$A9
ObjB7_MapUnc_3B8E4: BINCLUDE "mappings/sprite/objB7.bin"
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B8 - Wall turret from WFZ
; ----------------------------------------------------------------------------
; Sprite_3B968:
ObjB8:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB8_Index(pc,d0.w),d1
    jmp ObjB8_Index(pc,d1.w)
; ===========================================================================
; off_3B976:
ObjB8_Index:    offsetTable
        offsetTableEntry.w ObjB8_Init   ; 0
        offsetTableEntry.w loc_3B980    ; 2
        offsetTableEntry.w loc_3B9AA    ; 4
; ===========================================================================
; BranchTo5_LoadSubObject 
ObjB8_Init:
    bra.w   LoadSubObject
; ===========================================================================
 
loc_3B980:
    tst.b   render_flags(a0)
    bpl.s   +
    bsr.w   Obj_GetOrientationToPlayer
    tst.w   d1
    beq.s   +
    addi.w  #$60,d2
    cmpi.w  #$C0,d2
    blo.s   ++
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  #2,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3B9AA:
    bsr.w   Obj_GetOrientationToPlayer
    moveq   #0,d6
    addi.w  #$20,d2
    cmpi.w  #$40,d2
    blo.s   loc_3B9C0
    move.w  d0,d6
    lsr.w   #1,d6
    addq.w  #1,d6
 
loc_3B9C0:
    move.b  d6,mapping_frame(a0)
    subq.w  #1,objoff_2A(a0)
    bne.s   +
    move.w  #$60,objoff_2A(a0)
    bsr.w   loc_3B9D8
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3B9D8:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   +   ; rts
    _move.b #ObjID_Projectile,id(a1) ; load obj98
    move.b  #3,mapping_frame(a1)
    move.b  #$8E,subtype(a1) ; <== ObjB8_SubObjData2
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    lea_    Obj98_WallTurretShotMove,a2
    move.l  a2,objoff_2A(a1)
    moveq   #0,d0
    move.b  mapping_frame(a0),d0
    lsl.w   #2,d0
    lea byte_3BA2A(pc,d0.w),a2
    move.b  (a2)+,d0
    ext.w   d0
    add.w   d0,x_pos(a1)
    move.b  (a2)+,d0
    ext.w   d0
    add.w   d0,y_pos(a1)
    move.b  (a2)+,x_vel(a1)
    move.b  (a2)+,y_vel(a1)
+
    rts
; ===========================================================================
byte_3BA2A:
    dc.b   0
    dc.b $18    ; 1
    dc.b   0    ; 2
    dc.b   1    ; 3
    dc.b $EF    ; 4
    dc.b $10    ; 5
    dc.b $FF    ; 6
    dc.b   1    ; 7
    dc.b $11    ; 8
    dc.b $10    ; 9
    dc.b   1    ; 10
    dc.b   1    ; 11
; off_3BA36:
ObjB8_SubObjData:
    subObjData ObjB8_Obj98_MapUnc_3BA46,make_art_tile(ArtTile_ArtNem_WfzWallTurret,0,0),4,4,$10,0
; animation script
; off_3BA40:
Ani_WallTurretShot: offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   2,  3,  4,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjB8_Obj98_MapUnc_3BA46:   BINCLUDE "mappings/sprite/objB8.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object B9 - Laser from WFZ that shoots down the Tornado
; ----------------------------------------------------------------------------
; Sprite_3BABA:
ObjB9:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjB9_Index(pc,d0.w),d1
    jmp ObjB9_Index(pc,d1.w)
; ===========================================================================
; off_3BAC8:
ObjB9_Index:    offsetTable
        offsetTableEntry.w ObjB9_Init
        offsetTableEntry.w loc_3BAD2
        offsetTableEntry.w loc_3BAF0
; ===========================================================================
; BranchTo6_LoadSubObject 
ObjB9_Init:
    bra.w   LoadSubObject
; ===========================================================================
 
loc_3BAD2:
    tst.b   render_flags(a0)
    bmi.s   +
    bra.w   loc_3BAF8
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  #-$1000,x_vel(a0)
    moveq   #SndID_LargeLaser,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    bra.w   loc_3BAF8
; ===========================================================================
 
loc_3BAF0:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bra.w   loc_3BAF8
loc_3BAF8:
    move.w  x_pos(a0),d0
    move.w  (Camera_X_pos).w,d1
    subi.w  #$40,d1
    cmp.w   d1,d0
    blt.w   JmpTo65_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; off_3BB0E:
ObjB9_SubObjData:
    subObjData ObjB9_MapUnc_3BB18,make_art_tile(ArtTile_ArtNem_WfzHrzntlLazer,2,1),4,1,$60,0
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjB9_MapUnc_3BB18: BINCLUDE "mappings/sprite/objB9.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BA - Wheel from WFZ
; ----------------------------------------------------------------------------
; Sprite_3BB4C:
ObjBA:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBA_Index(pc,d0.w),d1
    jmp ObjBA_Index(pc,d1.w)
; ===========================================================================
; off_3BB5A:
ObjBA_Index:    offsetTable
        offsetTableEntry.w ObjBA_Init   ; 0
        offsetTableEntry.w ObjBA_Main   ; 2
; ===========================================================================
; BranchTo7_LoadSubObject 
ObjBA_Init:
    bra.w   LoadSubObject
; ===========================================================================
; BranchTo14_JmpTo39_MarkObjGone 
ObjBA_Main:
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3BB66:
ObjBA_SubObjData:
    subObjData ObjBA_MapUnc_3BB70,make_art_tile(ArtTile_ArtNem_WfzConveyorBeltWheel,2,1),4,4,$10,0
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBA_MapUnc_3BB70: BINCLUDE "mappings/sprite/objBA.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BB - Removed object (unknown, unused)
; ----------------------------------------------------------------------------
; Sprite_3BB7C:
ObjBB:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBB_Index(pc,d0.w),d1
    jmp ObjBB_Index(pc,d1.w)
; ===========================================================================
; off_3BB8A:
ObjBB_Index:    offsetTable
        offsetTableEntry.w ObjBB_Init   ; 0
        offsetTableEntry.w ObjBB_Main   ; 2
; ===========================================================================
; BranchTo8_LoadSubObject 
ObjBB_Init:
    bra.w   LoadSubObject
; ===========================================================================
; BranchTo15_JmpTo39_MarkObjGone 
ObjBB_Main:
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3BB96:
ObjBB_SubObjData:
    subObjData ObjBB_MapUnc_3BBA0,make_art_tile(ArtTile_ArtNem_Unknown,1,0),4,4,$C,9
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBB_MapUnc_3BBA0: BINCLUDE "mappings/sprite/objBB.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BC - Fire coming out of Robotnik's ship in WFZ
; ----------------------------------------------------------------------------
; Sprite_3BBBC:
ObjBC:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBC_Index(pc,d0.w),d1
    jmp ObjBC_Index(pc,d1.w)
; ===========================================================================
; off_3BBCA:
ObjBC_Index:    offsetTable
        offsetTableEntry.w ObjBC_Init
        offsetTableEntry.w ObjBC_Main
; ===========================================================================
; loc_3BBCE:
ObjBC_Init:
    bsr.w   LoadSubObject
    move.w  x_pos(a0),objoff_2C(a0)
    rts
; ===========================================================================
; loc_3BBDA:
ObjBC_Main:
    move.w  objoff_2C(a0),d0
    move.w  (Camera_BG_X_offset).w,d1
    cmpi.w  #$380,d1
    bhs.w   JmpTo65_DeleteObject
    add.w   d1,d0
    move.w  d0,x_pos(a0)
    bchg    #0,objoff_2A(a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; off_3BBFE:
ObjBC_SubObjData2:
    subObjData ObjBC_MapUnc_3BC08,make_art_tile(ArtTile_ArtNem_WfzThrust,2,0),4,4,$10,0
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBC_MapUnc_3BC08: BINCLUDE "mappings/sprite/objBC.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BD - Ascending/descending metal platforms from WFZ
; ----------------------------------------------------------------------------
; Sprite_3BC1C:
ObjBD:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBD_Index(pc,d0.w),d1
    jmp ObjBD_Index(pc,d1.w)
; ===========================================================================
; off_3BC2A:
ObjBD_Index:    offsetTable
        offsetTableEntry.w ObjBD_Init   ; 0
        offsetTableEntry.w loc_3BC3C    ; 2
        offsetTableEntry.w loc_3BC50    ; 4
; ===========================================================================
; loc_3BC30:
ObjBD_Init:
    addq.b  #2,routine(a0)
    move.w  #1,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3BC3C:
    subq.w  #1,objoff_2A(a0)
    bne.s   +
    move.w  #$40,objoff_2A(a0)
    bsr.w   loc_3BCF8
+
    jmpto   (MarkObjGone3).l, JmpTo8_MarkObjGone3
; ===========================================================================
 
loc_3BC50:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3BC62(pc,d0.w),d1
    jsr off_3BC62(pc,d1.w)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3BC62:  offsetTable
        offsetTableEntry.w loc_3BC6C    ; 0
        offsetTableEntry.w loc_3BCAC    ; 2
        offsetTableEntry.w loc_3BCB6    ; 4
        offsetTableEntry.w loc_3BCCC    ; 6
        offsetTableEntry.w loc_3BCD6    ; 8
; ===========================================================================
 
loc_3BC6C:
    bsr.w   LoadSubObject
    move.b  #2,mapping_frame(a0)
    subq.b  #2,routine(a0)
    addq.b  #2,routine_secondary(a0)
    move.w  #$C7,objoff_2A(a0)
    btst    #0,render_flags(a0)
    beq.s   loc_3BC92
    move.w  #$1C7,objoff_2A(a0)
 
loc_3BC92:
    moveq   #0,d0
    move.b  subtype(a0),d0
    subi.b  #$7E,d0
    move.b  d0,subtype(a0)
    move.w  word_3BCA8(pc,d0.w),y_vel(a0)
    rts
; ===========================================================================
word_3BCA8:
    dc.w -$100
    dc.w  $100  ; 1
; ===========================================================================
 
loc_3BCAC:
    lea (Ani_objBD).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
 
loc_3BCB6:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3BCC0
    bra.w   loc_3BCDE
; ===========================================================================
 
loc_3BCC0:
    addq.b  #2,routine_secondary(a0)
    move.b  #1,anim(a0)
    rts
; ===========================================================================
 
loc_3BCCC:
    lea (Ani_objBD).l,a1
    jmpto   (AnimateSprite).l, JmpTo25_AnimateSprite
; ===========================================================================
 
loc_3BCD6:
    bsr.w   loc_3B7BC
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
loc_3BCDE:
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.w  #$23,d1
    move.w  #4,d2
    move.w  #5,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo9_PlatformObject
; ===========================================================================
 
loc_3BCF8:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   +   ; rts
    _move.b #ObjID_SmallMetalPform,id(a1) ; load objBD
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.b  #4,routine(a1)
    move.b  subtype(a0),subtype(a1)
    move.b  render_flags(a0),render_flags(a1)
+
    rts
; ===========================================================================
; off_3BD24:
ObjBD_SubObjData:
    subObjData ObjBD_MapUnc_3BD3E,make_art_tile(ArtTile_ArtNem_WfzBeltPlatform,3,1),4,4,$18,0
; animation script
; off_3BD2E:
Ani_objBD:  offsetTable
        offsetTableEntry.w byte_3BD32   ; 0
        offsetTableEntry.w byte_3BD38   ; 1
byte_3BD32: dc.b   3,  2,  1,  0,$FA,  0
byte_3BD38: dc.b   1,  0,  1,  2,$FA
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBD_MapUnc_3BD3E: BINCLUDE "mappings/sprite/objBD.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BE - Lateral cannon (temporary platform that pops in/out) from WFZ
; ----------------------------------------------------------------------------
; Sprite_3BD7A:
ObjBE:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBE_Index(pc,d0.w),d1
    jmp ObjBE_Index(pc,d1.w)
; ===========================================================================
; off_3BD88:
ObjBE_Index:    offsetTable
        offsetTableEntry.w ObjBE_Init   ;  0
        offsetTableEntry.w loc_3BDA2    ;  2
        offsetTableEntry.w loc_3BDC6    ;  4
        offsetTableEntry.w loc_3BDD4    ;  6
        offsetTableEntry.w loc_3BDC6    ;  8
        offsetTableEntry.w loc_3BDF4    ; $A
; ===========================================================================
; loc_3BD94:
ObjBE_Init:
    moveq   #0,d0
    move.b  #($41<<1),d0
    bsr.w   LoadSubObject_Part2
    bra.w   loc_3B77E
; ===========================================================================
 
loc_3BDA2:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$F0,d0
    cmp.b   subtype(a0),d0
    beq.s   +
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine(a0)
    clr.b   anim(a0)
    move.w  #$A0,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3BDC6:
    lea (Ani_objBE).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3BDD4:
    subq.w  #1,objoff_2A(a0)
    beq.s   +
    bsr.w   loc_3BE04
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine(a0)
    move.b  #1,anim(a0)
    bsr.w   loc_3B7BC
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3BDF4:
    move.b  #2,routine(a0)
    move.w  #$40,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3BE04:
    move.b  mapping_frame(a0),d0
    cmpi.b  #3,d0
    beq.s   +
    cmpi.b  #4,d0
    bne.w   loc_3B7BC
+
    move.w  x_pos(a0),-(sp)
    move.w  #$23,d1
    move.w  #$18,d2
    move.w  #$19,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo9_PlatformObject
; ===========================================================================
; off_3BE2C:
ObjBE_SubObjData:
    subObjData ObjBE_MapUnc_3BE46,make_art_tile(ArtTile_ArtNem_WfzGunPlatform,3,1),4,4,$18,0
; animation script
; off_3BE36:
Ani_objBE:  offsetTable
        offsetTableEntry.w byte_3BE3A   ; 0
        offsetTableEntry.w byte_3BE40   ; 1
byte_3BE3A: dc.b   5,  0,  1,  2,  3,$FC
byte_3BE40: dc.b   5,  3,  2,  1,  0,$FC
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBE_MapUnc_3BE46: BINCLUDE "mappings/sprite/objBE.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object BF - Rotaty-stick badnik from WFZ
; ----------------------------------------------------------------------------
; Sprite_3BEAA:
ObjBF:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjBF_Index(pc,d0.w),d1
    jmp ObjBF_Index(pc,d1.w)
; ===========================================================================
; off_3BEB8:
ObjBF_Index:    offsetTable
        offsetTableEntry.w ObjBF_Init       ; 0
        offsetTableEntry.w ObjBF_Animate    ; 2
; ===========================================================================
; BranchTo9_LoadSubObject 
ObjBF_Init:
    bra.w   LoadSubObject
; ===========================================================================
; loc_3BEC0:
ObjBF_Animate:
    lea (Ani_objBF).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3BECE:
ObjBE_SubObjData2:
    subObjData ObjBF_MapUnc_3BEE0,make_art_tile(ArtTile_ArtNem_WfzUnusedBadnik,3,1),4,4,4,4
; animation script
; off_3BED8:
Ani_objBF:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,  2,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjBF_MapUnc_3BEE0: BINCLUDE "mappings/sprite/objBF.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C0 - Speed launcher from WFZ
; ----------------------------------------------------------------------------
; Sprite_3BF04:
ObjC0:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC0_Index(pc,d0.w),d1
    jmp ObjC0_Index(pc,d1.w)
; ===========================================================================
; off_3BF12:
ObjC0_Index:    offsetTable
        offsetTableEntry.w ObjC0_Init   ; 0
        offsetTableEntry.w ObjC0_Main   ; 2
; ===========================================================================
; loc_3BF16:
ObjC0_Init:
    move.w  #($43<<1),d0
    bsr.w   LoadSubObject_Part2
    moveq   #0,d0
    move.b  subtype(a0),d0
    lsl.w   #4,d0
    btst    #0,status(a0)
    bne.s   +
    neg.w   d0
+
    move.w  x_pos(a0),d1
    move.w  d1,objoff_34(a0)
    add.w   d1,d0
    move.w  d0,objoff_32(a0)
; loc_3BF3E:
ObjC0_Main:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3BF60(pc,d0.w),d1
    jsr off_3BF60(pc,d1.w)
    move.w  #$10,d1
    move.w  #$11,d3
    move.w  x_pos(a0),d4
    jsrto   (PlatformObject).l, JmpTo9_PlatformObject
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
off_3BF60:  offsetTable
        offsetTableEntry.w loc_3BF66
        offsetTableEntry.w loc_3BFD8
        offsetTableEntry.w loc_3C062
; ===========================================================================
 
loc_3BF66:
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   +++ ; rts
    addq.b  #2,routine_secondary(a0)
    move.w  #$C00,x_vel(a0)
    move.w  #$80,objoff_30(a0)
    btst    #0,status(a0)
    bne.s   +
    neg.w   x_vel(a0)
    neg.w   objoff_30(a0)
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.b  status(a0),d0
    move.b  d0,d1
    andi.b  #p1_standing,d1
    beq.s   +
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_3BFB4
+
    andi.b  #p2_standing,d0
    beq.s   +   ; rts
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   loc_3BFB4
+
    rts
; ===========================================================================
 
loc_3BFB4:
    clr.w   inertia(a1)
    clr.w   x_vel(a1)
    move.w  x_pos(a0),x_pos(a1)
    bclr    #0,status(a1)
    btst    #0,status(a0)
    bne.s   +
    bset    #0,status(a1)
+
    rts
; ===========================================================================
 
loc_3BFD8:
    move.w  objoff_30(a0),d0
    add.w   d0,x_vel(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.w  objoff_32(a0),d0
    sub.w   x_pos(a0),d0
    btst    #0,status(a0)
    beq.s   +
    neg.w   d0
+
    tst.w   d0
    bpl.s   loc_3C034
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   return_3C01E
    move.b  d0,d1
    andi.b  #p1_standing,d1
    beq.s   +
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_3BFB4
+
    andi.b  #p2_standing,d0
    beq.s   return_3C01E
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   loc_3BFB4
 
return_3C01E:
    rts
; ===========================================================================
 
loc_3C020:
    move.w  x_vel(a0),x_vel(a1)
    move.w  #-$400,y_vel(a1)
    bset    #1,status(a1)
    rts
; ===========================================================================
 
loc_3C034:
    addq.b  #2,routine_secondary(a0)
    move.w  objoff_32(a0),x_pos(a0)
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   loc_3C062
    move.b  d0,d1
    andi.b  #p1_standing,d1
    beq.s   loc_3C056
    lea (MainCharacter).w,a1 ; a1=character
    bsr.s   loc_3C020
 
loc_3C056:
    andi.b  #p2_standing,d0
    beq.s   loc_3C062
    lea (Sidekick).w,a1 ; a1=character
    bsr.s   loc_3C020
 
loc_3C062:
    move.w  x_pos(a0),d0
    moveq   #4,d1
    tst.w   objoff_30(a0)   ; if objoff_30(a0) is positive,
    spl d2      ; then set d2 to $FF, else set d2 to $00
    bmi.s   +
    neg.w   d1
+
    add.w   d1,d0
    cmp.w   objoff_34(a0),d0
    bhs.s   +
    not.b   d2
+
    tst.b   d2
    bne.s   +
    clr.b   routine_secondary(a0)
    move.w  objoff_34(a0),d0
+
    move.w  d0,x_pos(a0)
    rts
; ===========================================================================
; off_3C08E:
ObjC0_SubObjData:
    subObjData ObjC0_MapUnc_3C098,make_art_tile(ArtTile_ArtNem_WfzLaunchCatapult,1,0),4,4,$10,0
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC0_MapUnc_3C098: BINCLUDE "mappings/sprite/objC0.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C1 - Breakable plating from WFZ
; (and what sonic hangs onto on the back of Robotnic's getaway ship)
; ----------------------------------------------------------------------------
; Sprite_3C0AC:
ObjC1:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC1_Index(pc,d0.w),d1
    jmp ObjC1_Index(pc,d1.w)
; ===========================================================================
; off_3C0BA:
ObjC1_Index:    offsetTable
        offsetTableEntry.w ObjC1_Init   ; 0
        offsetTableEntry.w ObjC1_Main   ; 2
        offsetTableEntry.w ObjC1_Breakup    ; 4
; ===========================================================================
; loc_3C0C0:
ObjC1_Init:
    move.w  #($44<<1),d0
    bsr.w   LoadSubObject_Part2
    moveq   #0,d0
    move.b  subtype(a0),d0
    mulu.w  #$3C,d0
    move.w  d0,objoff_30(a0)
 
ObjC1_Main:
    tst.b   objoff_32(a0)
    beq.s   loc_3C140
    tst.w   objoff_30(a0)
    beq.s   +
    subq.w  #1,objoff_30(a0)
    beq.s   loc_3C12E
+
    lea (MainCharacter).w,a1 ; a1=character
    move.w  y_pos(a0),d0
    subi.w  #$18,d0
    btst    #button_up,(Ctrl_1_Held).w
    beq.s   +
    subq.w  #1,y_pos(a1)
    cmp.w   y_pos(a1),d0
    blo.s   +
    move.w  d0,y_pos(a1)
+
    addi.w  #$30,d0
    btst    #button_down,(Ctrl_1_Held).w
    beq.s   +
    addq.w  #1,y_pos(a1)
    cmp.w   y_pos(a1),d0
    bhs.s   +
    move.w  d0,y_pos(a1)
+
    move.b  (Ctrl_1_Press_Logical).w,d0
    andi.w  #button_B_mask|button_C_mask|button_A_mask,d0
    beq.s   BranchTo16_JmpTo39_MarkObjGone
 
loc_3C12E:
    clr.b   collision_flags(a0)
    clr.b   (MainCharacter+obj_control).w
    clr.b   (WindTunnel_holding_flag).w
    clr.b   objoff_32(a0)
    bra.s   loc_3C19A
; ===========================================================================
 
loc_3C140:
    tst.b   collision_property(a0)
    beq.s   BranchTo16_JmpTo39_MarkObjGone
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a0),d0
    subi.w  #$14,d0
    cmp.w   x_pos(a1),d0
    bhs.s   BranchTo16_JmpTo39_MarkObjGone
    clr.b   collision_property(a0)
    cmpi.b  #4,routine(a1)
    bhs.s   BranchTo16_JmpTo39_MarkObjGone
    clr.w   x_vel(a1)
    clr.w   y_vel(a1)
    move.w  x_pos(a0),d0
    subi.w  #$14,d0
    move.w  d0,x_pos(a1)
    bset    #0,status(a1)
    move.b  #AniIDSonAni_Hang,anim(a1)
    move.b  #1,(MainCharacter+obj_control).w
    move.b  #1,(WindTunnel_holding_flag).w
    move.b  #1,objoff_32(a0)
 
BranchTo16_JmpTo39_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3C19A:
    lea (byte_3C1E4).l,a4
    lea (byte_3C1E0).l,a2
    bsr.w   loc_3C1F4
 
ObjC1_Breakup:
    tst.b   objoff_3F(a0)
    beq.s   +
    subq.b  #1,objoff_3F(a0)
    bra.s   ++
; ===========================================================================
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    addi_.w #8,y_vel(a0)
    lea (Ani_objC1).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
+
    tst.b   render_flags(a0)
    bpl.w   JmpTo65_DeleteObject
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; animation script
; off_3C1D6:
Ani_objC1:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   3,  2,  3,  4,  5,  1,$FF
        even
 
; unknown
byte_3C1E0:
    dc.b   0
    dc.b   4    ; 1
    dc.b $18    ; 2
    dc.b $20    ; 3
byte_3C1E4:
    dc.w  -$10
    dc.w  -$10  ; 2
    dc.w  -$10  ; 4
    dc.w   $10  ; 6
    dc.w  -$30  ; 8
    dc.w  -$10  ; 10
    dc.w  -$30  ; 12
    dc.w   $10  ; 14
; ===========================================================================
 
loc_3C1F4:
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    move.b  priority(a0),d4
    subq.b  #1,d4
    moveq   #3,d1
    movea.l a0,a1
    bra.s   loc_3C20E
; ===========================================================================
 
loc_3C208:
    jsrto   (SingleObjLoad2).l, JmpTo25_SingleObjLoad2
    bne.s   loc_3C26C
 
loc_3C20E:
    move.b  #4,routine(a1)
    _move.b id(a0),id(a1) ; load obj
    move.l  mappings(a0),mappings(a1)
    move.w  art_tile(a0),art_tile(a1)
    move.b  #$84,render_flags(a1)
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  (a4)+,d0
    add.w   d2,d0
    move.w  d0,x_pos(a1)
    move.w  (a4)+,d0
    add.w   d3,d0
    move.w  d0,y_pos(a1)
    move.b  d4,priority(a1)
    move.b  #$10,width_pixels(a1)
    move.b  #1,mapping_frame(a1)
    move.w  #-$400,x_vel(a1)
    move.w  #0,y_vel(a1)
    move.b  (a2)+,objoff_3F(a1)
    dbf d1,loc_3C208
 
loc_3C26C:
    move.w  #SndID_SlowSmash,d0
    jmp (PlaySound).l
; ===========================================================================
; off_3C276:
ObjC1_SubObjData:
    subObjData ObjC1_MapUnc_3C280,make_art_tile(ArtTile_ArtNem_BreakPanels,3,1),4,4,$40,$E1
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC1_MapUnc_3C280: BINCLUDE "mappings/sprite/objC1.bin"
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C2 - Rivet thing you bust to get into ship at the end of WFZ
; ----------------------------------------------------------------------------
; Sprite_3C328:
ObjC2:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC2_Index(pc,d0.w),d1
    jmp ObjC2_Index(pc,d1.w)
; ===========================================================================
; off_3C336:
ObjC2_Index:    offsetTable
        offsetTableEntry.w ObjC2_Init   ; 0
        offsetTableEntry.w ObjC2_Main   ; 2
; ===========================================================================
; BranchTo10_LoadSubObject 
ObjC2_Init:
    bra.w   LoadSubObject
; ===========================================================================
; loc_3C33E:
ObjC2_Main:
    move.b  (MainCharacter+anim).w,objoff_30(a0)
    move.w  x_pos(a0),-(sp)
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #9,d3
    move.w  (sp)+,d4
    jsrto   (SolidObject).l, JmpTo27_SolidObject
    btst    #p1_standing_bit,status(a0)
    bne.s   ObjC2_Bust
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; loc_3C366:
ObjC2_Bust:
    cmpi.b  #2,objoff_30(a0)
    bne.s   +
    move.w  #$2880,(Camera_Min_X_pos).w
    bclr    #p1_standing_bit,status(a0)
    _move.b #ObjID_Explosion,id(a0) ; load 0bj27 (transform into explosion)
    move.b  #2,routine(a0)
    bset    #1,(MainCharacter+status).w
    bclr    #3,(MainCharacter+status).w
    lea (Level_Layout+$850).w,a1    ; alter the level layout
    move.l  #$8A707172,(a1)+
    move.w  #$7374,(a1)+
    lea (Level_Layout+$950).w,a1
    move.l  #$6E787978,(a1)+
    move.w  #$787A,(a1)+
    move.b  #1,(Screen_redraw_flag).w
+
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3C3B8:
ObjC2_SubObjData:
    subObjData ObjC2_MapUnc_3C3C2,make_art_tile(ArtTile_ArtNem_WfzSwitch,1,1),4,4,$10,0
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC2_MapUnc_3C3C2: BINCLUDE "mappings/sprite/objC2.bin"
 
Invalid_SubObjData2:
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C3,C4 - Plane's smoke from WFZ
; ----------------------------------------------------------------------------
; Sprite_3C3D6:
ObjC3:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC3_Index(pc,d0.w),d1
    jmp ObjC3_Index(pc,d1.w)
; ===========================================================================
; off_3C3E4:
ObjC3_Index:    offsetTable
        offsetTableEntry.w ObjC3_Init
        offsetTableEntry.w ObjC3_Main
; ===========================================================================
; loc_3C3E8:
ObjC3_Init:
    bsr.w   LoadSubObject
    move.b  #7,anim_frame_duration(a0)
    jsrto   (RandomNumber).l, JmpTo6_RandomNumber
    move.w  (RNG_seed).w,d0
    andi.w  #$1C,d0
    sub.w   d0,x_pos(a0)
    addi.w  #$10,y_pos(a0)
    move.w  #-$100,y_vel(a0)
    move.w  #-$100,x_vel(a0)
    rts
; ===========================================================================
; loc_3C416:
ObjC3_Main:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #5,mapping_frame(a0)
    beq.w   JmpTo65_DeleteObject
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; off_3C438:
ObjC3_SubObjData:
    subObjData Obj27_MapUnc_21120,make_art_tile(ArtTile_ArtNem_Explosion,0,0),4,5,$C,0
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C5 - WFZ boss
; ----------------------------------------------------------------------------
; Sprite_3C442:
ObjC5:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC5_Index(pc,d0.w),d1
    jmp ObjC5_Index(pc,d1.w)
; ===========================================================================
ObjC5_Index:    offsetTable
        offsetTableEntry.w ObjC5_Init           ;   0 - Main loading sequence
        offsetTableEntry.w ObjC5_LaserCase      ;   2 - Laser case (inside is laser)
        offsetTableEntry.w ObjC5_LaserWall      ;   4 - Laser wall
        offsetTableEntry.w ObjC5_PlatformReleaser   ;   6 - Platform releaser
        offsetTableEntry.w ObjC5_Platform       ;   8 - Platform
        offsetTableEntry.w ObjC5_PlatformHurt       ;  $A - Invisible object that gets the platform's spikes to hurt sonic
        offsetTableEntry.w ObjC5_LaserShooter       ;  $C - Laser shooter
        offsetTableEntry.w ObjC5_Laser          ;  $E - Laser
        offsetTableEntry.w ObjC5_Robotnik       ; $10 - Robotnik
        offsetTableEntry.w ObjC5_RobotnikPlatform   ; $12 - Platform Robotnik's on
; ===========================================================================
 
ObjC5_Init:
    bsr.w   LoadSubObject
    move.b  subtype(a0),d0
    subi.b  #$90,d0
    move.b  d0,routine(a0)
    rts
; ===========================================================================
 
ObjC5_LaserCase:    ; also the "mother" object
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_CaseIndex(pc,d0.w),d1
    jsr ObjC5_CaseIndex(pc,d1.w)
    bra.w   ObjC5_HandleHits
; ===========================================================================
ObjC5_CaseIndex:offsetTable
        offsetTableEntry.w ObjC5_CaseBoundary       ;   0 - Sets up boundaries for movement and basic things
        offsetTableEntry.w ObjC5_CaseWaitStart      ;   2 - Waits for sonic to start
        offsetTableEntry.w ObjC5_CaseWaitDown       ;   4 - Waits to make the laser go down
        offsetTableEntry.w ObjC5_CaseDown       ;   6 - Moves the case down
        offsetTableEntry.w ObjC5_CaseXSpeed     ;   8 - Sets an X speed for the case
        offsetTableEntry.w ObjC5_CaseBoundaryChk    ;  $A - Checks to make sure the case doesn't go through the boundaries
        offsetTableEntry.w ObjC5_CaseAnimate        ;  $C - Animates the case (opening and closing)
        offsetTableEntry.w ObjC5_CaseLSLoad     ;  $E - Laser shooter loading
        offsetTableEntry.w ObjC5_CaseLSDown     ; $10 - Moves the laser shooter down
        offsetTableEntry.w ObjC5_CaseWaitLoadLaser  ; $12 - Waits to load the laser
        offsetTableEntry.w ObjC5_CaseWaitMove       ; $14 - Waits to move (checks if laser is completely loaded (as big as it gets))
        offsetTableEntry.w ObjC5_CaseBoundaryLaserChk   ; $16 - Checks boundaries when moving with the laser
        offsetTableEntry.w ObjC5_CaseLSUp       ; $18 - wait for laser shooter to go back up
        offsetTableEntry.w ObjC5_CaseAnimate        ; $1A - Animates the case (opening and closing)
        offsetTableEntry.w ObjC5_CaseStartOver      ; $1C - Sets secondary routine to 8
        offsetTableEntry.w ObjC5_CaseDefeated       ; $1E - When defeated goes here (explosions and stuff)
; ===========================================================================
 
ObjC5_CaseBoundary:
    addq.b  #2,routine_secondary(a0)
    move.b  #0,collision_flags(a0)
    move.b  #8,collision_property(a0)   ; Hit points
    move.w  #$442,d0
    move.w  d0,(Camera_Max_Y_pos_now).w
    move.w  d0,(Camera_Max_Y_pos).w
    move.w  x_pos(a0),d0
    subi.w  #$60,d0         ; Max Left position
    move.w  d0,objoff_34(a0)
    addi.w  #$C0,d0         ; Max Right Position
    move.w  d0,objoff_36(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseWaitStart:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$20,d2
    cmpi.w  #$40,d2         ; How far away sonic is to start the boss
    blo.s   ObjC5_CaseStart
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseStart:
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,y_vel(a0)      ; Speed at which the laser carrier goes down
    lea (ObjC5_LaserWallData).l,a2
    bsr.w   LoadChildObject
    subi.w  #$88,x_pos(a1)      ; where to load the left laser wall (x)
    addi.w  #$60,y_pos(a1)      ; left laser wall (y)
    lea (ObjC5_LaserWallData).l,a2
    bsr.w   LoadChildObject
    addi.w  #$88,x_pos(a1)      ; right laser wall (x)
    addi.w  #$60,y_pos(a1)      ; right laser wall (y)
    lea (ObjC5_LaserShooterData).l,a2
    bsr.w   LoadChildObject
    lea (ObjC5_PlatformReleaserData).l,a2
    bsr.w   LoadChildObject
    lea (ObjC5_RobotnikData).l,a2
    bsr.w   LoadChildObject
    move.w  #$5A,objoff_2A(a0)  ; How long for the boss music to start playing and the boss to start
    moveq   #MusID_FadeOut,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseWaitDown:
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_CaseSpeedDown
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseSpeedDown:
    addq.b  #2,routine_secondary(a0)
    move.w  #$60,objoff_2A(a0)  ; How long the laser carrier goes down
    moveq   #MusID_Boss,d0
    jsrto   (PlayMusic).l, JmpTo5_PlayMusic
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseDown:
    subq.w  #1,objoff_2A(a0)
    beq.s   ObjC5_CaseStopDown
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseStopDown:
    addq.b  #2,routine_secondary(a0)
    clr.w   y_vel(a0)       ; stop the laser carrier from going down
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseXSpeed:
    addq.b  #2,routine_secondary(a0)
    bsr.w   Obj_GetOrientationToPlayer
    move.w  #$100,d1        ; Speed of carrier (when going back and forth before sending out laser)
    tst.w   d0
    bne.s   ObjC5_CasePMLoader
    neg.w   d1
 
ObjC5_CasePMLoader:
    move.w  d1,x_vel(a0)
    bset    #2,status(a0)       ; makes the platform maker load
    move.w  #$70,objoff_2A(a0)  ; how long to go back and forth before letting out laser
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseBoundaryChk:          ; waits and makes sure the carrier does not go beyond the limit
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_CaseOpeningAnim
    move.w  x_pos(a0),d0
    tst.w   x_vel(a0)
    bmi.s   ObjC5_CaseBoundaryChk2
    cmp.w   objoff_36(a0),d0
    bhs.s   ObjC5_CaseNegSpeed
    bra.w   ObjC5_CaseMoveDisplay
; ===========================================================================
 
ObjC5_CaseBoundaryChk2:
    cmp.w   objoff_34(a0),d0
    bhs.s   ObjC5_CaseMoveDisplay
 
ObjC5_CaseNegSpeed:
    neg.w   x_vel(a0)
 
ObjC5_CaseMoveDisplay:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseOpeningAnim:
    addq.b  #2,routine_secondary(a0)
    clr.b   anim(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseAnimate:
    lea (Ani_objC5).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseLSLoad:       ; loads up the laser shooter (LS)
    addq.b  #2,routine_secondary(a0)
    move.w  #$E,objoff_2A(a0)   ; Time the laser shooter moves down
    movea.w objoff_3C(a0),a1 ; a1=object (laser shooter)
    move.b  #4,routine_secondary(a1)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseLSDown:
    subq.w  #1,objoff_2A(a0)
    beq.s   ObjC5_CaseAddCollision
    movea.w objoff_3C(a0),a1 ; a1=object (laser shooter)
    addq.w  #1,y_pos(a1)    ; laser shooter down speed
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseAddCollision:
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,objoff_2A(a0)  ; Length before shooting laser
    bset    #4,status(a0)       ; makes the hit sound and flashes happen only once when you hit it
    bset    #6,status(a0)       ; makes sure collision gets restored
    move.b  #6,collision_flags(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseWaitLoadLaser:
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_CaseLoadLaser
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseLoadLaser:
    addq.b  #2,routine_secondary(a0)
    lea (ObjC5_LaserData).l,a2  
    bsr.w   LoadChildObject     ; loads laser
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseWaitMove:
    movea.w parent(a0),a1 ; a1=object
    btst    #2,status(a1)       ; waits to check if laser fired
    bne.s   ObjC5_CaseLaserSpeed
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseLaserSpeed:
    addq.b  #2,routine_secondary(a0)
    move.w  #$80,objoff_2A(a0)  ; how long to move the laser
    bsr.w   Obj_GetOrientationToPlayer  ; tests if sonic is to the right or left
    move.w  #$80,d1     ; Speed when moving with laser
    tst.w   d0
    bne.s   ObjC5_CaseLaserSpeedSet
    neg.w   d1
 
ObjC5_CaseLaserSpeedSet:
    move.w  d1,x_vel(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseBoundaryLaserChk:     ; make sure you stay in range when firing laser
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_CaseStopLaserDelete
    move.w  x_pos(a0),d0
    tst.w   x_vel(a0)
    bmi.s   ObjC5_CaseBoundaryLaserChk2
    cmp.w   objoff_36(a0),d0
    bhs.s   ObjC5_CaseLaserStopMove
    bra.w   ObjC5_CaseLaserMoveDisplay
; ===========================================================================
 
ObjC5_CaseBoundaryLaserChk2:
    cmp.w   objoff_34(a0),d0
    bhs.s   ObjC5_CaseLaserMoveDisplay
 
ObjC5_CaseLaserStopMove:
    clr.w   x_vel(a0)   ; stop moving
 
ObjC5_CaseLaserMoveDisplay:
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseStopLaserDelete:      ; stops collision and deletes laser
    addq.b  #2,routine_secondary(a0)
    move.w  #$E,objoff_2A(a0)   ; time for laser shooter to move back up
    bclr    #3,status(a0)
    bclr    #4,status(a0)
    bclr    #6,status(a0)
    clr.b   collision_flags(a0) ; no more collision
    movea.w parent(a0),a1       ; a1=object (laser)
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2 ; delete the laser
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseLSUp:
    subq.w  #1,objoff_2A(a0)
    beq.s   ObjC5_CaseClosingAnim
    movea.w objoff_3C(a0),a1 ; a1=object (laser shooter)
    subq.w  #1,y_pos(a1)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseClosingAnim: ;sets which animation to do 
    addq.b  #2,routine_secondary(a0)
    move.b  #1,anim(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseStartOver:
    move.b  #8,routine_secondary(a0)
    bsr.w   ObjC5_CaseXSpeed
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_CaseDefeated:
    clr.b   collision_flags(a0)
    st  collision_property(a0)
    bclr    #6,status(a0)
    subq.w  #1,objoff_30(a0)    ; timer
    bmi.s   ObjC5_End
    jsrto   (Boss_LoadExplosion).l, JmpTo_Boss_LoadExplosion
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_End:  ; play music and change camera speed
    moveq   #MusID_WFZ,d0
    jsrto   (PlayMusic).l, JmpTo5_PlayMusic
    move.w  #$720,d0
    move.w  d0,(Camera_Max_Y_pos_now).w
    move.w  d0,(Camera_Max_Y_pos).w
    bsr.w   JmpTo65_DeleteObject
    addq.w  #4,sp
    rts
; ===========================================================================
 
ObjC5_LaserWall:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_LaserWallIndex(pc,d0.w),d1
    jsr ObjC5_LaserWallIndex(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    move.w  x_pos(a0),-(sp)
    move.w  #$13,d1
    move.w  #$40,d2
    move.w  #$80,d3
    move.w  (sp)+,d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
ObjC5_LaserWallIndex: offsetTable
    offsetTableEntry.w ObjC5_LaserWallMappings  ; 0 - selects the mappings
    offsetTableEntry.w ObjC5_LaserWallWaitDelete    ; 2 - Waits till set to delete (when the boss is defeated)
    offsetTableEntry.w ObjC5_LaserWallDelete    ; 4 - After a little time it deletes
; ===========================================================================
 
ObjC5_LaserWallMappings:
    addq.b  #2,routine_secondary(a0)
    move.b  #$C,mapping_frame(a0)   ; loads the laser wall from the WFZ boss art
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_LaserWallWaitDelete:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #5,status(a1)
    bne.s   ObjC5_LaserWallTimerSet
    bchg    #0,objoff_2F(a0)    ; makes it "flash" if set it won't flash
    bne.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_LaserWallTimerSet:    ; sets a small timer
    addq.b  #2,routine_secondary(a0)
    move.b  #4,objoff_30(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_LaserWallDelete:
    subq.b  #1,anim_frame_duration(a0)
    bpl.w   return_37A48
    move.b  anim_frame_duration(a0),d0
    move.b  anim_frame(a0),d1
    addq.b  #2,d0
    bpl.s   ObjC5_LaserWallDisplay
    move.b  d1,anim_frame_duration(a0)
    subq.b  #1,objoff_30(a0)
    bpl.s   ObjC5_LaserWallDisplay
    move.b  #$10,objoff_30(a0)
    addq.b  #1,d1
    cmpi.b  #5,d1
    bhs.w   JmpTo65_DeleteObject
    move.b  d1,anim_frame(a0)
    move.b  d1,anim_frame_duration(a0)
 
ObjC5_LaserWallDisplay:
    bclr    #0,objoff_2F(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaser:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_PlatformReleaserIndex(pc,d0.w),d1
    jmp ObjC5_PlatformReleaserIndex(pc,d1.w)
; ===========================================================================
ObjC5_PlatformReleaserIndex: offsetTable
    offsetTableEntry.w ObjC5_PlatformReleaserInit       ; 0 - Load mappings and position
    offsetTableEntry.w ObjC5_PlatformReleaserWaitDown   ; 2 - Waits for laser case to move down
    offsetTableEntry.w ObjC5_PlatformReleaserDown       ; 4 - Goes down until time limit is up
    offsetTableEntry.w ObjC5_PlatformReleaserLoadWait   ; 6 - Waits to load the platforms (the interval of time between each is from this) and makes sure only 3 are loaded
    offsetTableEntry.w ObjC5_PlatformReleaserDelete     ; 8 - Explodes then deletes
; ===========================================================================
 
ObjC5_PlatformReleaserInit:
    addq.b  #2,routine_secondary(a0)
    move.b  #5,mapping_frame(a0)
    addq.w  #8,y_pos(a0)        ; Move down a little
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserWaitDown:
    movea.w objoff_2C(a0),a1 ; a1=object laser case
    btst    #2,status(a1)       ; checks if laser case is done moving down (so it starts loading the platforms)
    bne.s   ObjC5_PlatformReleaserSetDown
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserSetDown:
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,objoff_2A(a0)  ; time to go down
    move.w  #$40,y_vel(a0)      ; speed to go down
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserDown:
    subq.w  #1,objoff_2A(a0)
    beq.s   ObjC5_PlatformReleaserStop
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserStop:
    addq.b  #2,routine_secondary(a0)
    clr.w   y_vel(a0)
    move.w  #$10,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserLoadWait:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #5,status(a1)
    bne.s   ObjC5_PlatformReleaserDestroyP
    subq.w  #1,objoff_2A(a0)
    bne.s   BranchTo8_JmpTo45_DisplaySprite
    move.w  #$80,objoff_2A(a0)  ; Time between loading platforms
    moveq   #0,d0
    move.b  objoff_2E(a0),d0
    addq.b  #1,d0
    cmpi.b  #3,d0           ; How many platforms to load
    blo.s   ObjC5_PlatformReleaserLoadP
    moveq   #0,d0
 
ObjC5_PlatformReleaserLoadP:    ; P=Platforms
    move.b  d0,objoff_2E(a0)
    tst.b   objoff_30(a0,d0.w)
    bne.s   BranchTo8_JmpTo45_DisplaySprite
    st  objoff_30(a0,d0.w)
    lea (ObjC5_PlatformData).l,a2
    bsr.w   LoadChildObject
    move.b  objoff_2E(a0),objoff_2E(a1)
 
BranchTo8_JmpTo45_DisplaySprite 
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserDestroyP:     ; P=Platforms
    addq.b  #2,routine_secondary(a0)
    bset    #5,status(a0)       ; destroy platforms
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_PlatformReleaserDelete:
    movea.w objoff_2C(a0),a1 ; a1=object
    cmpi.b  #ObjID_WFZBoss,id(a1)
    bne.w   JmpTo65_DeleteObject
    jsrto   (Boss_LoadExplosion).l, JmpTo_Boss_LoadExplosion
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_Platform:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_PlatformIndex(pc,d0.w),d1
    jsr ObjC5_PlatformIndex(pc,d1.w)
    lea (Ani_objC5).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
ObjC5_PlatformIndex: offsetTable
    offsetTableEntry.w ObjC5_PlatformInit           ; 0 - Selects mappings, anim ation, y speed and loads the object that hurts sonic (by spiky area)
    offsetTableEntry.w ObjC5_PlatformDownWait       ; 2 - Wait till the platform goes down some
    offsetTableEntry.w ObjC5_PlatformTestChangeDirection    ; 4 - checks if time limit is over and if so to change direction
; ===========================================================================
 
ObjC5_PlatformInit:
    addq.b  #2,routine_secondary(a0)
    move.b  #3,anim(a0)
    move.b  #7,mapping_frame(a0)
    move.w  #$100,y_vel(a0)         ; Y speed
    move.w  #$60,objoff_2A(a0)
    lea (ObjC5_PlatformHurtData).l,a2   ; loads the invisible object that hurts sonic
    bra.w   LoadChildObject
; ===========================================================================
 
ObjC5_PlatformDownWait:     ; waits for it to go down some
    bsr.w   ObjC5_PlatformCheckExplode
    subq.w  #1,objoff_2A(a0)
    beq.s   ObjC5_PlatformLeft
    bra.w   ObjC5_PlatformMakeSolid
; ===========================================================================
 
ObjC5_PlatformLeft:         ; goes left and makes a time limit (for going left)
    addq.b  #2,routine_secondary(a0)
    move.w  #$60,objoff_2A(a0)
    move.w  #-$100,x_vel(a0)        ; X speed
    move.w  y_pos(a0),objoff_34(a0)
    bra.w   ObjC5_PlatformMakeSolid
; ===========================================================================
 
ObjC5_PlatformTestChangeDirection:
    bsr.w   ObjC5_PlatformCheckExplode
    subq.w  #1,objoff_2A(a0)
    bne.s   ObjC5_PlatformTestLeftRight
    move.w  #$C0,objoff_2A(a0)
    neg.w   x_vel(a0)
 
ObjC5_PlatformTestLeftRight:    ; tests to see if a value should be added to go left or right
    moveq   #4,d0
    move.w  y_pos(a0),d1
    cmp.w   objoff_34(a0),d1
    blo.s   ObjC5_PlatformChangeY
    neg.w   d0
 
ObjC5_PlatformChangeY:  ; give it that curving feel
    add.w   d0,y_vel(a0)
    bra.w   ObjC5_PlatformMakeSolid
 
ObjC5_PlatformMakeSolid:    ; makes into a platform and moves
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.w  #$10,d1
    move.w  #8,d2
    move.w  #8,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo9_PlatformObject
; ===========================================================================
 
ObjC5_PlatformCheckExplode: ; checks to see if platforms should explode
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #5,status(a1)
    bne.w   ObjC5_PlatformExplode
    rts
; ===========================================================================
 
ObjC5_PlatformExplode:
    bsr.w   loc_3B7BC
    move.b  #ObjID_BossExplosion,id(a0) ; load 0bj58 (explosion)
    clr.b   routine(a0)
    movea.w objoff_3C(a0),a1 ; a1=object (invisible hurting thing)
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2
    addq.w  #4,sp
    rts
; ===========================================================================
 
ObjC5_PlatformHurt:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_PlatformHurtIndex(pc,d0.w),d1
    jmp ObjC5_PlatformHurtIndex(pc,d1.w)
; ===========================================================================
ObjC5_PlatformHurtIndex: offsetTable
    offsetTableEntry.w ObjC5_PlatformHurtCollision      ; 0 - Gives collision that hurts sonic
    offsetTableEntry.w ObjC5_PlatformHurtFollowPlatform ; 2 - Follows around the platform and waits to be deleted
; ===========================================================================
 
ObjC5_PlatformHurtCollision:
    addq.b  #2,routine_secondary(a0)
    move.b  #$98,collision_flags(a0)
    rts
; ===========================================================================
 
ObjC5_PlatformHurtFollowPlatform:
    movea.w objoff_2C(a0),a1 ; a1=object (platform)
    btst    #5,status(a1)
    bne.w   JmpTo65_DeleteObject
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),d0
    addi.w  #$C,d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
 
ObjC5_LaserShooter:
    movea.w objoff_2C(a0),a1 ; a1=object (laser case)
    btst    #5,status(a1)
    bne.w   JmpTo65_DeleteObject
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_LaserShooterIndex(pc,d0.w),d1
    jmp ObjC5_LaserShooterIndex(pc,d1.w)
; ===========================================================================
ObjC5_LaserShooterIndex: offsetTable
    offsetTableEntry.w ObjC5_LaserShooterInit   ; 0 - Loads up mappings
    offsetTableEntry.w ObjC5_LaserShooterFollow ; 2 - Goes back and forth with the laser case
    offsetTableEntry.w ObjC5_LaserShooterDown   ; 4 - Laser case sets it to this routine which then makes it go down
; ===========================================================================
 
ObjC5_LaserShooterInit:
    addq.b  #2,routine_secondary(a0)
    move.b  #4,mapping_frame(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_LaserShooterFollow:
    movea.w objoff_2C(a0),a1 ; a1=object (laser case)
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_LaserShooterDown:
    movea.w objoff_2C(a0),a1 ; a1=object (laser case)
    move.w  x_pos(a1),x_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_Laser:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #5,status(a1)
    bne.w   JmpTo65_DeleteObject
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_LaserIndex(pc,d0.w),d1
    jsr ObjC5_LaserIndex(pc,d1.w)
    bchg    #0,objoff_2F(a0)
    bne.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
ObjC5_LaserIndex: offsetTable
    offsetTableEntry.w ObjC5_LaserInit  ; 0 - Loads mappings and collision and such
    offsetTableEntry.w ObjC5_LaserFlash ; 2 - Makes the laser flash (gives the charging up effect)
    offsetTableEntry.w ObjC5_LaseWaitShoot  ; 4 - Waits a little to launch the laser when it's done flickering (charging)
    offsetTableEntry.w ObjC5_LaserShoot ; 6 - Shoots down the laser untill it's fully shot out
    offsetTableEntry.w ObjC5_LaserMove  ; 8 - Moves with laser case and shooter
; ===========================================================================
 
ObjC5_LaserInit:
    addq.b  #2,routine_secondary(a0)
    move.b  #$D,mapping_frame(a0)
    move.b  #4,priority(a0)
    move.b  #0,collision_flags(a0)
    addi.w  #$10,y_pos(a0)
    move.b  #$C,anim_frame(a0)
    subq.w  #3,y_pos(a0)
    rts
; ===========================================================================
 
ObjC5_LaserFlash:
    bset    #0,objoff_2F(a0)
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   ObjC5_LaserNoLaser
    move.b  anim_frame_duration(a0),d0
    addq.b  #2,d0
    bpl.s   ObjC5_LaserFlicker
    move.b  anim_frame(a0),d0
    subq.b  #1,d0
    beq.s   ObjC5_LaseNext
    move.b  d0,anim_frame(a0)
    move.b  d0,anim_frame_duration(a0)
 
ObjC5_LaserFlicker: ; this is what makes the laser flicker before being fully loaded (covering laser shooter)
    bclr    #0,objoff_2F(a0)
 
ObjC5_LaserNoLaser: ; without this the laser would just stay on the shooter not going down
    rts
; ===========================================================================
 
ObjC5_LaseNext:     ; just sets up a time to wait for the laser to shoot when it's loaded and done flickering
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,objoff_2A(a0)
    rts
; ===========================================================================
 
ObjC5_LaseWaitShoot:
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_LaseStartShooting
    rts
; ===========================================================================
 
ObjC5_LaseStartShooting:
    addq.b  #2,routine_secondary(a0)
    addi.w  #$10,y_pos(a0)
    rts
; ===========================================================================
 
ObjC5_LaserShoot:
    moveq   #0,d0
    move.b  objoff_2E(a0),d0
    addq.b  #1,d0
    cmpi.b  #5,d0
    bhs.s   ObjC5_LaseShotOut
    addi.w  #$10,y_pos(a0)
    move.b  d0,objoff_2E(a0)
    move.b  ObjC5_LaserMappingsData(pc,d0.w),mapping_frame(a0)
    move.b  ObjC5_LaserCollisionData(pc,d0.w),collision_flags(a0)
    rts
; ===========================================================================
 
ObjC5_LaseShotOut:  ; laser is fully shot out and lets the laser case know so it moves
    addq.b  #2,routine_secondary(a0)
    move.w  #$80,objoff_2A(a0)
    bset    #2,status(a0)
    movea.w objoff_2C(a0),a1 ; a1=object (laser case)
    bset    #3,status(a1)
    rts
; ===========================================================================
ObjC5_LaserMappingsData:
    dc.b  $E
    dc.b  $F    ; 1
    dc.b $10    ; 2
    dc.b $11    ; 3
    dc.b $12    ; 4
    dc.b   0    ; 5
ObjC5_LaserCollisionData:
    dc.b $86
    dc.b $AB    ; 1
    dc.b $AC    ; 2
    dc.b $AD    ; 3
    dc.b $AE    ; 4
    dc.b   0    ; 5
; ===========================================================================
 
ObjC5_LaserMove:
    movea.w objoff_2C(a0),a1 ; a1=object
    move.w  x_pos(a1),x_pos(a0)
    rts
; ===========================================================================
 
ObjC5_Robotnik:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC5_RobotnikIndex(pc,d0.w),d1
    jmp ObjC5_RobotnikIndex(pc,d1.w)
; ===========================================================================
ObjC5_RobotnikIndex: offsetTable
    offsetTableEntry.w ObjC5_RobotnikInit       ; 0 - Loads art, animation and position
    offsetTableEntry.w ObjC5_RobotnikAnimate    ; 2 - Animates Robotnik and waits till the case is defeated
    offsetTableEntry.w ObjC5_RobotnikDown       ; 4 - Goes down until timer is up
; ===========================================================================
 
ObjC5_RobotnikInit:
    addq.b  #2,routine_secondary(a0)
    move.b  #0,mapping_frame(a0)
    move.b  #1,anim(a0)
    move.w  #$2C60,x_pos(a0)
    move.w  #$4E6,y_pos(a0)
    lea (ObjC5_RobotnikPlatformData).l,a2
    bsr.w   LoadChildObject
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_RobotnikAnimate:
    movea.w objoff_2C(a0),a1 ; a1=object (laser case)
    btst    #5,status(a1)
    bne.s   ObjC5_RobotnikTimer
    lea (Ani_objC5_objC6).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_RobotnikTimer:        ; Increase routine and set timer
    addq.b  #2,routine_secondary(a0)
    move.w  #$C0,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_RobotnikDown:
    subq.w  #1,objoff_2A(a0)
    bmi.s   ObjC5_RobotnikDelete
    addq.w  #1,y_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
ObjC5_RobotnikDelete:       ; Deletes robotnik and the platform he's on
    movea.w parent(a0),a1 ; a1=object (Robotnik Platform)
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
ObjC5_RobotnikPlatform: ; Just displays the platform and move accordingly to the robotnik object
    movea.w objoff_2C(a0),a1 ; a1=object (robotnik)
    move.w  y_pos(a1),d0
    addi.w  #$26,d0
    move.w  d0,y_pos(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
    ; some unused/dead code, At one point it appears a section of the platform was solid
    move.w  x_pos(a0),-(sp)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    move.w  #$F,d1
    move.w  #8,d2
    move.w  #8,d3
    move.w  (sp)+,d4
    jmpto   (PlatformObject).l, JmpTo9_PlatformObject
; ===========================================================================
 
ObjC5_HandleHits:
    tst.b   collision_property(a0)
    beq.s   ObjC5_NoHitPointsLeft
    tst.b   collision_flags(a0)
    bne.s   return_3CC3A
    tst.b   objoff_30(a0)
    bne.s   ObjC5_FlashSetUp
    btst    #6,status(a0)
    beq.s   return_3CC3A
    move.b  #$20,objoff_30(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
 
ObjC5_FlashSetUp:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   ObjC5_FlashCollisionRestore
    move.w  #$EEE,d0
 
ObjC5_FlashCollisionRestore:
    move.w  d0,(a1)
    subq.b  #1,objoff_30(a0)
    bne.s   return_3CC3A
    btst    #4,status(a0)   ; makes sure the boss doesn't need collision
    beq.s   return_3CC3A
    move.b  #6,collision_flags(a0)  ; restore collision
 
return_3CC3A:
    rts
; ===========================================================================
 
ObjC5_NoHitPointsLeft:  ; when the boss is defeated this tells it what to do
    moveq   #100,d0
    bsr.w   AddPoints
    clr.b   collision_flags(a0)
    move.w  #$EF,objoff_30(a0)
    move.b  #$1E,routine_secondary(a0)
    bset    #5,status(a0)
    bclr    #6,status(a0)
    rts
; ===========================================================================
ObjC5_LaserWallData:
    dc.w objoff_2A
    dc.b ObjID_WFZBoss
    dc.b $94
ObjC5_PlatformData:
    dc.w objoff_3E
    dc.b ObjID_WFZBoss
    dc.b $98
ObjC5_PlatformHurtData:
    dc.w objoff_3C
    dc.b ObjID_WFZBoss
    dc.b $9A
ObjC5_LaserShooterData:
    dc.w objoff_3C
    dc.b ObjID_WFZBoss
    dc.b $9C
ObjC5_PlatformReleaserData:
    dc.w objoff_3A
    dc.b ObjID_WFZBoss
    dc.b $96
ObjC5_LaserData:
    dc.w objoff_3E
    dc.b ObjID_WFZBoss
    dc.b $9E
ObjC5_RobotnikData:
    dc.w objoff_38
    dc.b ObjID_WFZBoss
    dc.b $A0
ObjC5_RobotnikPlatformData:
    dc.w objoff_3E
    dc.b ObjID_WFZBoss
    dc.b $A2
 
; off_3CC80:
ObjC5_SubObjData:       ; Laser Case
    subObjData ObjC5_MapUnc_3CCD8,make_art_tile(ArtTile_ArtNem_WFZBoss,0,0),4,4,$20,0
; off_3CC8A:
ObjC5_SubObjData2:      ; Laser Walls
    subObjData ObjC5_MapUnc_3CCD8,make_art_tile(ArtTile_ArtNem_WFZBoss,0,0),4,1,8,0
; off_3CC94:
ObjC5_SubObjData3:      ; Platforms, platform releaser, laser and laser shooter
    subObjData ObjC5_MapUnc_3CCD8,make_art_tile(ArtTile_ArtNem_WFZBoss,0,0),4,5,$10,0
; off_3CC9E:
ObjC6_SubObjData2:      ; Robotnik
    subObjData ObjC6_MapUnc_3D0EE,make_art_tile(ArtTile_ArtKos_LevelArt,0,0),4,5,$20,0
; off_3CCA8:
ObjC5_SubObjData4:      ; Robotnik platform
    subObjData ObjC5_MapUnc_3CEBC,make_art_tile(ArtTile_ArtNem_WfzFloatingPlatform,1,1),4,5,$20,0
 
; animation script
; off_3CCB2:
Ani_objC5:  offsetTable
        offsetTableEntry.w byte_3CCBA   ; 0
        offsetTableEntry.w byte_3CCC4   ; 1
        offsetTableEntry.w byte_3CCCC   ; 2
        offsetTableEntry.w byte_3CCD0   ; 3
byte_3CCBA: dc.b   5,  0,  1,  2,  3,  3,  3,  3,$FA,  0
byte_3CCC4: dc.b   3,  3,  2,  1,  0,  0,$FA,  0
byte_3CCCC: dc.b   3,  5,  6,$FF
byte_3CCD0: dc.b   3,  7,  8,  9, $A, $B,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC5_MapUnc_3CCD8: BINCLUDE "mappings/sprite/objC5_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC5_MapUnc_3CEBC: BINCLUDE "mappings/sprite/objC5_b.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C6 - Eggman
; ----------------------------------------------------------------------------
; Sprite_3CED0:
ObjC6:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC6_Index(pc,d0.w),d1
    jmp ObjC6_Index(pc,d1.w)
; ===========================================================================
; off_3CEDE: ObjC6_States:
ObjC6_Index:    offsetTable
        offsetTableEntry.w ObjC6_Init   ; 0 
        offsetTableEntry.w ObjC6_State2 ; 2
        offsetTableEntry.w ObjC6_State3 ; 4
        offsetTableEntry.w ObjC6_State4 ; 6
; ===========================================================================
; loc_3CEE6:
ObjC6_Init:
    bsr.w   LoadSubObject
    move.b  subtype(a0),d0
    subi.b  #$A4,d0
    move.b  d0,routine(a0) ; => ObjC6_State2, ObjC6_State3, or ObjC6_State4 ??
    rts
; ===========================================================================
; loc_3CEF8:
ObjC6_State2:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC6_State2_States(pc,d0.w),d1
    jmp ObjC6_State2_States(pc,d1.w)
; ===========================================================================
; off_3CF06:
ObjC6_State2_States: offsetTable
    offsetTableEntry.w ObjC6_State2_State1  ; 0
    offsetTableEntry.w ObjC6_State2_State2  ; 2
    offsetTableEntry.w ObjC6_State2_State3  ; 4
    offsetTableEntry.w ObjC6_State2_State4  ; 6
    offsetTableEntry.w ObjC6_State2_State5  ; 8
; ===========================================================================
; loc_3CF10:
ObjC6_State2_State1: ; a1=object (set in loc_3D94C)
    addq.b  #2,routine_secondary(a0) ; => ObjC6_State2_State2
    lea (word_3D0D0).l,a2
    bsr.w   LoadChildObject
    move.w  #$3F8,x_pos(a1)
    move.w  #$160,y_pos(a1)
    move.w  a0,(DEZ_Eggman).w
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3CF32:
ObjC6_State2_State2:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$5C,d2
    cmpi.w  #$B8,d2
    blo.s   loc_3CF44
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
loc_3CF44:
    addq.b  #2,routine_secondary(a0) ; => ObjC6_State2_State3
    move.w  #$18,objoff_2A(a0)
    move.b  #1,mapping_frame(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3CF58:
ObjC6_State2_State3:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3CF62
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
loc_3CF62:
    addq.b  #2,routine_secondary(a0) ; => ObjC6_State2_State4
    bset    #2,status(a0)
    move.w  #$200,x_vel(a0)
    move.w  #$10,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3CF7C:
ObjC6_State2_State4:
    cmpi.w  #$810,x_pos(a0)
    bhs.s   loc_3CFC0
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$50,d2
    cmpi.w  #$A0,d2
    bhs.s   +
    move.w  x_pos(a1),d0
    addi.w  #$50,d0
    move.w  d0,x_pos(a0)
+
    subq.w  #1,objoff_2A(a0)
    bpl.s   +
    move.w  #$20,objoff_2A(a0)
    bsr.w   loc_3D00C
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objC5_objC6).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3CFC0:
    move.b  #2,mapping_frame(a0)
    clr.w   x_vel(a0)
    tst.b   render_flags(a0)
    bpl.s   +
    addq.b  #2,routine_secondary(a0) ; => ObjC6_State2_State5
    move.w  #$80,x_vel(a0)
    move.w  #-$200,y_vel(a0)
    move.b  #2,mapping_frame(a0)
    move.w  #$50,objoff_2A(a0)
    bset    #3,status(a0)
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3CFF6:
ObjC6_State2_State5:
    subq.w  #1,objoff_2A(a0)
    bmi.w   JmpTo65_DeleteObject
    addi.w  #$10,y_vel(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3D00C:
    lea (word_3D0D4).l,a2
    bsr.w   LoadChildObject
    move.b  #$AA,subtype(a1) ; <== ObjC6_SubObjData
    move.b  #5,mapping_frame(a1)
    move.w  #-$100,x_vel(a1)
    subi.w  #$18,y_pos(a1)
    move.w  #8,objoff_2A(a1)
    rts
; ===========================================================================
; loc_3D036:
ObjC6_State3:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  ObjC6_State3_States(pc,d0.w),d1
    jmp ObjC6_State3_States(pc,d1.w)
; ===========================================================================
; off_3D044:
ObjC6_State3_States: offsetTable
    offsetTableEntry.w ObjC6_State3_State1  ; 0
    offsetTableEntry.w ObjC6_State3_State2  ; 2
    offsetTableEntry.w ObjC6_State3_State3  ; 4
; ===========================================================================
; loc_3D04A:
ObjC6_State3_State1:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #2,status(a1)
    bne.s   loc_3D05E
    bsr.w   loc_3D086
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
loc_3D05E:
    addq.b  #2,routine_secondary(a0) ; => ObjC6_State3_State2
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3D066:
ObjC6_State3_State2:
    bsr.w   loc_3D086
    lea (Ani_objC6).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
; loc_3D078:
ObjC6_State3_State3:
    lea (MainCharacter).w,a1 ; a1=character
    bclr    #5,status(a1)
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
loc_3D086:
    move.w  x_pos(a0),-(sp)
    move.w  #$13,d1
    move.w  #$20,d2
    move.w  #$20,d3
    move.w  (sp)+,d4
    jmpto   (SolidObject).l, JmpTo27_SolidObject
; ===========================================================================
; loc_3D09C:
ObjC6_State4:
    subq.w  #1,objoff_2A(a0)
    bmi.w   JmpTo65_DeleteObject
    addi.w  #$10,y_vel(a0)
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
; off_3D0B2:
ObjC6_SubObjData3:
    subObjData ObjC6_MapUnc_3D0EE,make_art_tile(ArtTile_ArtKos_LevelArt,0,0),4,5,$18,0
; off_3D0BC:
ObjC6_SubObjData4:
    subObjData ObjC6_MapUnc_3D1DE,make_art_tile(ArtTile_ArtNem_ConstructionStripes_1,1,0),4,1,8,0
; off_3D0C6:
ObjC6_SubObjData:
    subObjData ObjC6_MapUnc_3D0EE,make_art_tile(ArtTile_ArtKos_LevelArt,0,0),4,5,4,0
word_3D0D0:
    dc.w objoff_3E
    dc.b ObjID_Eggman
    dc.b $A8
word_3D0D4:
    dc.w objoff_3C
    dc.b ObjID_Eggman
    dc.b $AA
; animation script
; off_3D0D8:
Ani_objC5_objC6:offsetTable
        offsetTableEntry.w byte_3D0DC   ; 0
        offsetTableEntry.w byte_3D0E2   ; 1
byte_3D0DC: dc.b   5,  2,  3,  4,$FF,  0
byte_3D0E2: dc.b   5,  6,  7,$FF
        even
; animation script
; off_3D0E6:
Ani_objC6:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b   1,  0,  1,  2,  3,$FA
        even
; ----------------------------------------------------------------------------
; sprite mappings ; Robotnik running
; ----------------------------------------------------------------------------
ObjC6_MapUnc_3D0EE: BINCLUDE "mappings/sprite/objC6_a.bin"
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
ObjC6_MapUnc_3D1DE: BINCLUDE "mappings/sprite/objC6_b.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C8 - Crawl (shield badnik) from CNZ
; ----------------------------------------------------------------------------
; Sprite_3D23E:
ObjC8:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC8_Index(pc,d0.w),d1
    jmp ObjC8_Index(pc,d1.w)
; ===========================================================================
; off_3D24C:
ObjC8_Index:    offsetTable
        offsetTableEntry.w ObjC8_Init   ; 0
        offsetTableEntry.w loc_3D27C    ; 2
        offsetTableEntry.w loc_3D2A6    ; 4
        offsetTableEntry.w loc_3D2D4    ; 6
; ===========================================================================
; loc_3D254:
ObjC8_Init:
    bsr.w   LoadSubObject
    move.w  #$200,objoff_2A(a0)
    moveq   #$20,d0
    btst    #0,render_flags(a0)
    bne.s   +
    neg.w   d0
+
    move.w  d0,x_vel(a0)
    move.b  #$F,y_radius(a0)
    move.b  #$10,x_radius(a0)
    rts
; ===========================================================================
 
loc_3D27C:
    subq.w  #1,objoff_2A(a0)
    beq.s   +
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    bsr.w   loc_3D416
    lea (Ani_objC8).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    addq.b  #2,routine(a0)
    move.w  #$3B,objoff_2A(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D2A6:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    bsr.w   loc_3D416
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
+
    move.b  #2,routine(a0)
    move.w  #$200,objoff_2A(a0)
    neg.w   x_vel(a0)
    bchg    #0,render_flags(a0)
    bchg    #0,status(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D2D4:
    move.b  #$D7,collision_flags(a0)
    bsr.w   Obj_GetOrientationToPlayer
    move.w  d2,d4
    addi.w  #$40,d2
    cmpi.w  #$80,d2
    bhs.w   loc_3D39A
    addi.w  #$40,d3
    cmpi.w  #$80,d3
    bhs.w   loc_3D39A
    bclr    #3,status(a0)
    bne.w   loc_3D386
    move.b  collision_property(a0),d0
    beq.s   BranchTo18_JmpTo39_MarkObjGone
    bclr    #0,collision_property(a0)
    beq.s   +++
    cmpi.b  #AniIDSonAni_Roll,anim(a1)
    bne.s   loc_3D36C
    btst    #1,status(a1)
    bne.s   ++
    bsr.w   Obj_GetOrientationToPlayer
    btst    #0,render_flags(a0)
    beq.s   +
    subq.w  #2,d0
+
    tst.w   d0
    bne.s   loc_3D390
+
    bsr.s   loc_3D3A4
+
    lea (Sidekick).w,a1 ; a1=character
    bclr    #1,collision_property(a0)
    beq.s   +++
    cmpi.b  #AniIDTailsAni_Roll,anim(a1)
    bne.s   loc_3D36C
    btst    #1,status(a1)
    bne.s   ++
    bsr.w   Obj_GetOrientationToPlayer
    btst    #0,render_flags(a0)
    beq.s   +
    subq.w  #2,d0
+
    tst.w   d0
    bne.s   loc_3D390
+
    bsr.s   loc_3D3A4
+
    clr.b   collision_property(a0)
 
BranchTo18_JmpTo39_MarkObjGone 
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D36C:
    move.b  #$97,collision_flags(a0)
    btst    #status_sec_isInvincible,status_secondary(a1)
    beq.s   +
    move.b  #$17,collision_flags(a0)
+
    bset    #3,status(a0)
 
loc_3D386:
    move.b  #1,mapping_frame(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D390:
    move.b  #$17,collision_flags(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D39A:
    move.b  objoff_2C(a0),routine(a0)
    jmpto   (MarkObjGone).l, JmpTo39_MarkObjGone
; ===========================================================================
 
loc_3D3A4:
    move.b  #2,mapping_frame(a0)
    btst    #1,status(a1)
    beq.s   +
    move.b  #3,mapping_frame(a0)
+
    move.w  x_pos(a0),d1
    move.w  y_pos(a0),d2
    sub.w   x_pos(a1),d1
    sub.w   y_pos(a1),d2
    jsr (CalcAngle).l
    move.b  (Timer_frames).w,d1
    andi.w  #3,d1
    add.w   d1,d0
    jsr (CalcSine).l
    muls.w  #-$700,d1
    asr.l   #8,d1
    move.w  d1,x_vel(a1)
    muls.w  #-$700,d0
    asr.l   #8,d0
    move.w  d0,y_vel(a1)
    bset    #1,status(a1)
    bclr    #4,status(a1)
    bclr    #5,status(a1)
    clr.b   jumping(a1)
    move.w  #SndID_Bumper,d0
    jsr (PlaySound).l
    rts
; ===========================================================================
    ; unused
    rts
; ===========================================================================
 
loc_3D416:
    bsr.w   Obj_GetOrientationToPlayer
    addi.w  #$40,d2
    cmpi.w  #$80,d2
    bhs.s   +   ; rts
    addi.w  #$40,d3
    cmpi.w  #$80,d3
    bhs.s   +   ; rts
    move.b  routine(a0),objoff_2C(a0)
    move.b  #6,routine(a0)
    clr.b   mapping_frame(a0)
+
    rts
; ===========================================================================
; off_3D440:
ObjC8_SubObjData:
    subObjData ObjC8_MapUnc_3D450,make_art_tile(ArtTile_ArtNem_Crawl,0,1),4,3,$10,$D7
; animation script
; off_3D44A:
Ani_objC8:  offsetTable
        offsetTableEntry.w +    ; 0
+       dc.b $13,  0,  1,$FF
        even
; ----------------------------------------------------------------------------
; sprite mappings ; Crawl CNZ
; ----------------------------------------------------------------------------
ObjC8_MapUnc_3D450: BINCLUDE "mappings/sprite/objC8.bin"
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object C7 - Eggrobo (final boss) from Death Egg
; ----------------------------------------------------------------------------
; Sprite_3D4C8:
ObjC7:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  ObjC7_Index(pc,d0.w),d1
    jmp ObjC7_Index(pc,d1.w)
; ===========================================================================
; off_3D4D6:
ObjC7_Index:    offsetTable
        offsetTableEntry.w ObjC7_Init   ;   0
        offsetTableEntry.w ObjC7_Body   ;   2
        offsetTableEntry.w ObjC7_Shoulder   ;   4
        offsetTableEntry.w ObjC7_FrontLowerLeg  ;   6
        offsetTableEntry.w ObjC7_FrontForearm   ;   8
        offsetTableEntry.w ObjC7_Arm    ;  $A
        offsetTableEntry.w ObjC7_FrontThigh ;  $C
        offsetTableEntry.w ObjC7_Head   ;  $E
        offsetTableEntry.w ObjC7_Jet    ; $10
        offsetTableEntry.w ObjC7_BackLowerLeg   ; $12
        offsetTableEntry.w ObjC7_BackForearm    ; $14
        offsetTableEntry.w ObjC7_BackThigh  ; $16
        offsetTableEntry.w ObjC7_TargettingSensor   ; $18
        offsetTableEntry.w ObjC7_TargettingLock ; $1A
        offsetTableEntry.w ObjC7_EggmanBomb ; $1C
        offsetTableEntry.w ObjC7_FallingPieces  ; $1E
        offsetTableEntry.w ObjC7_SetupEnding    ; $20
; ===========================================================================
; loc_3D4F8:
ObjC7_Init:
    lea ObjC7_SubObjData(pc),a1
    bsr.w   LoadSubObject_Part3
    move.b  subtype(a0),routine(a0)
    rts
; ===========================================================================
;loc_3D508
ObjC7_Body:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3D51A(pc,d0.w),d1
    jsr off_3D51A(pc,d1.w)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3D51A:  offsetTable
        offsetTableEntry.w loc_3D52A    ;  0
        offsetTableEntry.w loc_3D5A8    ;  2
        offsetTableEntry.w loc_3D5C2    ;  4
        offsetTableEntry.w loc_3D5EA    ;  6
        offsetTableEntry.w loc_3D62E    ;  8
        offsetTableEntry.w loc_3D640    ; $A
        offsetTableEntry.w loc_3D684    ; $C
        offsetTableEntry.w loc_3D8D2    ; $E
; ===========================================================================
 
loc_3D52A:
    addq.b  #2,routine_secondary(a0)
    move.b  #3,mapping_frame(a0)
    move.b  #5,priority(a0)
    lea (ChildObjC7_Shoulder).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_FrontForearm).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_FrontLowerLeg).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_Arm).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_FrontThigh).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_Head).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_Jet).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_BackLowerLeg).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_BackForearm).l,a2
    bsr.w   LoadChildObject
    lea (ChildObjC7_BackThigh).l,a2
    bsr.w   LoadChildObject
    lea (ObjC7_ChildDeltas).l,a1
    bra.w   ObjC7_PositionChildren
; ===========================================================================
 
loc_3D5A8:
    btst    #2,status(a0)
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.b  #$3C,anim_frame_duration(a0)
    moveq   #MusID_FadeOut,d0
    jmpto   (PlaySound).l, JmpTo12_PlaySound
; ===========================================================================
 
loc_3D5C2:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.b  #$79,anim_frame_duration(a0)
    move.w  #-$100,y_vel(a0)
    movea.w objoff_38(a0),a1 ; a1=object
    move.b  #4,routine_secondary(a1)
    moveq   #MusID_EndBoss,d0
    jmpto   (PlayMusic).l, JmpTo5_PlayMusic
; ===========================================================================
 
loc_3D5EA:
    subq.b  #1,anim_frame_duration(a0)
    beq.s   +
    moveq   #SndID_Rumbling,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (ObjC7_ChildDeltas).l,a1
    bra.w   ObjC7_PositionChildren
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    clr.w   y_vel(a0)
    move.b  #$1F,anim_frame_duration(a0)
    move.b  #$16,collision_flags(a0)
    move.b  #$C,collision_property(a0)
    bsr.w   ObjC7_InitCollision
    movea.w objoff_38(a0),a1 ; a1=object
    move.b  #6,routine_secondary(a1)
    rts
; ===========================================================================
 
loc_3D62E:
    bsr.w   ObjC7_CheckHit
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    rts
; ===========================================================================
 
loc_3D640:
    bsr.w   ObjC7_CheckHit
    addq.b  #2,routine_secondary(a0)
    move.b  #$20,anim_frame_duration(a0)
    move.b  angle(a0),d0
    addq.b  #1,d0
    move.b  d0,angle(a0)
    andi.w  #3,d0
    move.b  byte_3D680(pc,d0.w),d0
    move.b  d0,anim(a0)
    clr.b   next_anim(a0)
    cmpi.b  #2,d0
    bne.s   +   ; rts
    movea.w objoff_38(a0),a1 ; a1=object
    move.b  #4,routine_secondary(a1)
    move.b  #2,anim(a1)
+
    rts
; ===========================================================================
byte_3D680:
    dc.b   2
    dc.b   0    ; 1
    dc.b   2    ; 2
    dc.b   4    ; 3
; ===========================================================================
 
loc_3D684:
    bsr.w   ObjC7_CheckHit
    moveq   #0,d0
    move.b  anim(a0),d0
    move.w  off_3D696(pc,d0.w),d1
    jmp off_3D696(pc,d1.w)
; ===========================================================================
off_3D696:  offsetTable
        offsetTableEntry.w loc_3D6AA    ; 0
        offsetTableEntry.w loc_3D702    ; 2
        offsetTableEntry.w loc_3D83C    ; 4
; ===========================================================================
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,anim(a0)
    rts
; ===========================================================================
 
loc_3D6AA:
    moveq   #0,d0
    move.b  next_anim(a0),d0
    move.w  off_3D6B8(pc,d0.w),d1
    jmp off_3D6B8(pc,d1.w)
; ===========================================================================
off_3D6B8:  offsetTable
        offsetTableEntry.w loc_3D6C0    ; 0
        offsetTableEntry.w loc_3D6CE    ; 2
        offsetTableEntry.w loc_3D6C0    ; 4
        offsetTableEntry.w loc_3D6E8    ; 6
; ===========================================================================
 
loc_3D6C0:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    rts
; ===========================================================================
 
loc_3D6CE:
    lea (off_3E40C).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    move.b  #$40,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_3D6E8:
    lea (off_3E42C).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    subq.b  #2,routine_secondary(a0)
    move.b  #$40,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_3D702:
    moveq   #0,d0
    move.b  next_anim(a0),d0
    move.w  off_3D710(pc,d0.w),d1
    jmp off_3D710(pc,d1.w)
; ===========================================================================
off_3D710:  offsetTable
        offsetTableEntry.w loc_3D6C0    ;  0
        offsetTableEntry.w loc_3D720    ;  2
        offsetTableEntry.w loc_3D744    ;  4
        offsetTableEntry.w loc_3D6C0    ;  6
        offsetTableEntry.w loc_3D784    ;  8
        offsetTableEntry.w loc_3D7B8    ; $A
        offsetTableEntry.w loc_3D7F0    ; $C
        offsetTableEntry.w loc_3D82E    ; $C
; ===========================================================================
 
loc_3D720:
    lea (off_3E3D0).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    move.b  #$80,anim_frame_duration(a0)
    clr.w   x_vel(a0)
    move.w  #-$200,y_vel(a0)
    rts
; ===========================================================================
 
loc_3D744:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   ++
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +
    moveq   #SndID_Fire,d0
    jsrto   (PlaySoundLocal).l, JmpTo_PlaySoundLocal
+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (ObjC7_ChildDeltas).l,a1
    bra.w   ObjC7_PositionChildren
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    clr.w   y_vel(a0)
    lea (ChildObjC7_TargettingSensor).l,a2
    bsr.w   LoadChildObject
    clr.w   x_vel(a0)
    clr.w   objoff_28(a0)
    rts
; ===========================================================================
 
loc_3D784:
    move.w  objoff_28(a0),d0
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    move.w  d0,x_pos(a0)
    bclr    #0,render_flags(a0)
    cmpi.w  #$780,d0
    bhs.s   +
    bset    #0,render_flags(a0)
+
    bsr.w   loc_3E168
    move.w  #$800,y_vel(a0)
    move.b  #$20,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_3D7B8:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (ObjC7_ChildDeltas).l,a1
    bra.w   ObjC7_PositionChildren
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    clr.w   y_vel(a0)
    move.b  #1,(Screen_Shaking_Flag).w
    move.w  #$40,(DEZ_Shake_Timer).w
    movea.w objoff_38(a0),a1 ; a1=object
    move.b  #6,routine_secondary(a1)
    moveq   #SndID_Smash,d0
    jmpto   (PlaySound).l, JmpTo12_PlaySound
; ===========================================================================
 
loc_3D7F0:
    lea (off_3E30A).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    lea (ObjC7_ChildDeltas).l,a1
    bsr.w   ObjC7_PositionChildren
    bsr.w   Obj_GetOrientationToPlayer
    btst    #0,render_flags(a0)
    beq.s   +
    subq.w  #2,d0
+
    tst.w   d0
    bne.s   +
    subq.b  #2,routine_secondary(a0)
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    move.b  #$60,anim_frame_duration(a0)
    bra.w   CreateEggmanBombs
; ===========================================================================
 
loc_3D82E:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    subq.b  #2,routine_secondary(a0)
    rts
; ===========================================================================
 
loc_3D83C:
    moveq   #0,d0
    move.b  next_anim(a0),d0
    move.w  off_3D84A(pc,d0.w),d1
    jmp off_3D84A(pc,d1.w)
; ===========================================================================
off_3D84A:  offsetTable
        offsetTableEntry.w loc_3D6C0    ;  0
        offsetTableEntry.w loc_3D856    ;  2
        offsetTableEntry.w loc_3D6C0    ;  4
        offsetTableEntry.w loc_3D89E    ;  6
        offsetTableEntry.w loc_3D6C0    ;  8
        offsetTableEntry.w loc_3D8B8    ; $A
; ===========================================================================
 
loc_3D856:
    bset    #6,status(a0)
    lea (off_3E2F6).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    bsr.w   Obj_GetOrientationToPlayer
    btst    #0,render_flags(a0)
    beq.s   +
    subq.w  #2,d0
+
    tst.w   d0
    bne.s   +
    addq.b  #2,next_anim(a0)
    move.b  #$40,anim_frame_duration(a0)
    bset    #4,status(a0)
    rts
; ---------------------------------------------------------------------------
+
    move.b  #8,next_anim(a0)
    move.b  #$20,anim_frame_duration(a0)
    bra.w   CreateEggmanBombs
; ===========================================================================
 
loc_3D89E:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,next_anim(a0)
    bset    #5,status(a0)
    move.b  #$40,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_3D8B8:
    lea (off_3E300).l,a1
    bsr.w   loc_3E1AA
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    subq.b  #2,routine_secondary(a0)
    bclr    #6,status(a0)
    rts
; ===========================================================================
 
loc_3D8D2:
    moveq   #0,d0
    move.b  anim(a0),d0
    move.w  off_3D8E0(pc,d0.w),d1
    jmp off_3D8E0(pc,d1.w)
; ===========================================================================
off_3D8E0:  offsetTable
        offsetTableEntry.w loc_3D8E6    ; 0
        offsetTableEntry.w loc_3D922    ; 2
        offsetTableEntry.w loc_3D93C    ; 4
; ===========================================================================
 
loc_3D8E6:
    jsrto   (Boss_LoadExplosion).l, JmpTo_Boss_LoadExplosion
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    move.w  y_pos(a0),d0
    cmpi.w  #$15C,d0
    bhs.s   +
    rts
; ---------------------------------------------------------------------------
+
    move.w  #$15C,y_pos(a0)
    move.w  y_vel(a0),d0
    bmi.s   +
    lsr.w   #2,d0
    cmpi.w  #$100,d0
    blo.s   +
    neg.w   d0
    move.w  d0,y_vel(a0)
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,anim(a0)
    move.b  #$40,anim_frame_duration(a0)
    rts
; ===========================================================================
 
loc_3D922:
    subq.b  #1,anim_frame_duration(a0)
    bmi.s   +
    jmpto   (Boss_LoadExplosion).l, JmpTo_Boss_LoadExplosion
; ---------------------------------------------------------------------------
+
    addq.b  #2,anim(a0)
    st  (Control_Locked).w
    move.w  #$1000,(Camera_Max_X_pos).w
    rts
; ===========================================================================
 
loc_3D93C:
    move.w  #(button_right_mask<<8)|button_right_mask,(Ctrl_1_Logical).w
    cmpi.w  #$840,(Camera_X_pos).w
    bhs.s   +
    rts
; ---------------------------------------------------------------------------
+
    move.b  #$20,routine(a0)
    clr.b   routine_secondary(a0)
    move.w  #$20,objoff_2A(a0)
    move.b  #1,(Screen_Shaking_Flag).w
    move.w  #$1000,(DEZ_Shake_Timer).w
    movea.w objoff_36(a0),a1 ; a1=object
    jmpto   (DeleteObject2).l, JmpTo6_DeleteObject2
; ===========================================================================
;loc_3D970
ObjC7_SetupEnding:
    move.b  (Vint_runcount+3).w,d0
    andi.b  #$1F,d0
    bne.s   +
    moveq   #SndID_Rumbling2,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    subq.w  #1,objoff_2A(a0)
+
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),d0
    sub.w   objoff_2A(a0),d0
    move.w  d0,x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    bsr.w   loc_3DFBA
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3D9AC(pc,d0.w),d1
    jmp off_3D9AC(pc,d1.w)
; ===========================================================================
off_3D9AC:  offsetTable
        offsetTableEntry.w loc_3D9B0    ; 0
        offsetTableEntry.w loc_3D9D6    ; 2
; ===========================================================================
 
loc_3D9B0:
    lea (MainCharacter).w,a1 ; a1=character
    cmpi.w  #$EC0,x_pos(a1)
    bhs.s   loc_3D9BE
    rts
; ===========================================================================
 
loc_3D9BE:
    addq.b  #2,routine_secondary(a0)
    move.w  #$3F,(Palette_fade_range).w
    move.b  #$16,anim_frame_duration(a0)
    move.w  #$7FFF,(PalCycle_Timer).w
    rts
; ===========================================================================
 
loc_3D9D6:
    subq.b  #1,anim_frame_duration(a0)
    beq.w   +
    movea.l a0,a1
    lea (Normal_palette).w,a0
 
    moveq   #$3F,d0
-   jsrto   (Pal_FadeToWhite.UpdateColour).l, JmpTo_Pal_FadeToWhite_UpdateColour
    dbf d0,-
    movea.l a1,a0
    rts
; ---------------------------------------------------------------------------
+
    move.l  #$EEE0EEE,d0
    lea (Normal_palette).w,a1
 
    moveq   #$1F,d6
-   move.l  d0,(a1)+
    dbf d6,-
 
    moveq   #MusID_FadeOut,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
    move.b  #GameModeID_EndingSequence,(Game_Mode).w ; => EndingSequence
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
 
ObjC7_Shoulder:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DA34(pc,d0.w),d1
    jsr off_3DA34(pc,d1.w)
    lea byte_3DA38(pc),a1
    bsr.w   loc_3E282
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DA34:  offsetTable
        offsetTableEntry.w loc_3DA3C    ; 0
        offsetTableEntry.w return_3DA48 ; 2
; ===========================================================================
byte_3DA38:
    dc.b   0
    dc.b  $C    ; 1
    dc.b $FF    ; 2
    dc.b $EC    ; 3
; ===========================================================================
 
loc_3DA3C:
    addq.b  #2,routine_secondary(a0)
    move.b  #4,mapping_frame(a0)
    rts
; ===========================================================================
 
return_3DA48:
    rts
; ===========================================================================
;loc_3DA4A
ObjC7_FrontLowerLeg:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DA62(pc,d0.w),d1
    jsr off_3DA62(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DA62:  offsetTable
        offsetTableEntry.w loc_3DA66    ; 0
        offsetTableEntry.w return_3DA72 ; 2
; ===========================================================================
 
loc_3DA66:
    addq.b  #2,routine_secondary(a0)
    move.b  #$B,mapping_frame(a0)
    rts
; ===========================================================================
 
return_3DA72:
    rts
; ===========================================================================
;loc_3DA74
ObjC7_FrontForearm:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DA96(pc,d0.w),d1
    jsr off_3DA96(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    btst    #6,status(a0)
    bne.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DA96:  offsetTable
        offsetTableEntry.w loc_3DAA0    ; 0
        offsetTableEntry.w loc_3DAAC    ; 2
        offsetTableEntry.w loc_3DACC    ; 4
        offsetTableEntry.w loc_3DB32    ; 6
        offsetTableEntry.w loc_3DB5A    ; 8
; ===========================================================================
 
loc_3DAA0:
    addq.b  #2,routine_secondary(a0)
    move.b  #6,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_3DAAC:
    movea.w objoff_2C(a0),a1 ; a1=object
    bclr    #4,status(a1)
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$10,objoff_2A(a0)
    move.w  y_pos(a0),objoff_2E(a0)
    rts
; ===========================================================================
 
loc_3DACC:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    addi.w  #$20,y_vel(a0)
    jmpto   (ObjectMove).l, JmpTo26_ObjectMove
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$20,objoff_2A(a0)
    bsr.w   Obj_GetOrientationToPlayer
    abs.w   d2
    cmpi.w  #$100,d2
    blo.s   +
    move.w  #$FF,d2
+
    andi.w  #$C0,d2
    lsr.w   #5,d2
    move.w  word_3DB2A(pc,d2.w),d2
    tst.w   d1
    bne.s   +
    neg.w   d2
+
    move.w  d2,y_vel(a0)
    move.w  #$800,d2
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #0,render_flags(a0)
    bne.s   +
    neg.w   d2
+
    move.w  d2,x_vel(a0)
    moveq   #SndID_SpindashRelease,d0
    jmpto   (PlaySound).l, JmpTo12_PlaySound
; ===========================================================================
word_3DB2A:
    dc.w  $200
    dc.w  $100  ; 1
    dc.w   $80  ; 2
    dc.w     0  ; 3
; ===========================================================================
 
loc_3DB32:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    jmpto   (ObjectMove).l, JmpTo26_ObjectMove
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    neg.w   x_vel(a0)
    move.w  #$20,objoff_2A(a0)
    move.w  objoff_2E(a0),d0
    sub.w   y_pos(a0),d0
    asl.w   #3,d0
    move.w  d0,y_vel(a0)
    rts
; ===========================================================================
 
loc_3DB5A:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    jmpto   (ObjectMove).l, JmpTo26_ObjectMove
; ---------------------------------------------------------------------------
+
    move.b  #2,routine_secondary(a0)
    clr.w   x_vel(a0)
    clr.w   y_vel(a0)
    rts
; ===========================================================================
;loc_3DB74
ObjC7_Arm:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DB8C(pc,d0.w),d1
    jsr off_3DB8C(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DB8C:  offsetTable
        offsetTableEntry.w loc_3DB90    ; 0
        offsetTableEntry.w return_3DB9C ; 2
; ===========================================================================
 
loc_3DB90:
    addq.b  #2,routine_secondary(a0)
    move.b  #5,mapping_frame(a0)
    rts
; ===========================================================================
 
return_3DB9C:
    rts
; ===========================================================================
;loc_3DB9E
ObjC7_FrontThigh:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DBB6(pc,d0.w),d1
    jsr off_3DBB6(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DBB6:  offsetTable
        offsetTableEntry.w loc_3DBBA    ; 0
        offsetTableEntry.w return_3DBC6 ; 2
; ===========================================================================
 
loc_3DBBA:
    addq.b  #2,routine_secondary(a0)
    move.b  #$A,mapping_frame(a0)
    rts
; ===========================================================================
 
return_3DBC6:
    rts
; ===========================================================================
;loc_3DBC8
ObjC7_Head:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DBE8(pc,d0.w),d1
    jsr off_3DBE8(pc,d1.w)
    lea byte_3DBF2(pc),a1
    bsr.w   loc_3E282
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DBE8:  offsetTable
        offsetTableEntry.w loc_3DBF6    ; 0
        offsetTableEntry.w loc_3DC02    ; 2
        offsetTableEntry.w loc_3DC1C    ; 4
        offsetTableEntry.w loc_3DC2A    ; 6
        offsetTableEntry.w loc_3DC46    ; 8
; ===========================================================================
byte_3DBF2:
    dc.b   0
    dc.b   0    ; 1
    dc.b $FF    ; 2
    dc.b $CC    ; 3
; ===========================================================================
 
loc_3DBF6:
    addq.b  #2,routine_secondary(a0)
    move.b  #$15,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_3DC02:
    movea.w (DEZ_Eggman).w,a1
    btst    #3,$22(a1)
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,objoff_2A(a0)
    rts
; ===========================================================================
 
loc_3DC1C:
    lea (Ani_objC7_a).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DC2A:
    subq.w  #1,objoff_2A(a0)
    bmi.s   +
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    movea.w objoff_2C(a0),a1 ; a1=object
    bset    #2,status(a1)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DC46:
    move.b  #-1,collision_property(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
;loc_3DC50
ObjC7_Jet:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DC66(pc,d0.w),d1
    jsr off_3DC66(pc,d1.w)
    lea byte_3DC70(pc),a1
    bra.w   loc_3E282
; ===========================================================================
off_3DC66:  offsetTable
        offsetTableEntry.w loc_3DC74
        offsetTableEntry.w loc_3DC80
        offsetTableEntry.w loc_3DC86
        offsetTableEntry.w loc_3DC94
        offsetTableEntry.w loc_3DC80
; ===========================================================================
byte_3DC70:
    dc.b   0
    dc.b $38    ; 1
    dc.b   0    ; 2
    dc.b $18    ; 3
; ===========================================================================
 
loc_3DC74:
    addq.b  #2,routine_secondary(a0)
    move.b  #$C,mapping_frame(a0)
    rts
; ===========================================================================
 
loc_3DC80:
    move.b  #3,anim(a0)
 
loc_3DC86:
    lea (Ani_objC7_b).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DC94:
    move.b  #1,anim(a0)
    bra.s   loc_3DC86
; ===========================================================================
;loc_3DC9C
ObjC7_BackLowerLeg:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DCB4(pc,d0.w),d1
    jsr off_3DCB4(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DCB4:  offsetTable
        offsetTableEntry.w loc_3DCB8    ; 0
        offsetTableEntry.w return_3DCCA ; 2
; ===========================================================================
 
loc_3DCB8:
    addq.b  #2,routine_secondary(a0)
    move.b  #$B,mapping_frame(a0)
    move.b  #5,priority(a0)
    rts
; ===========================================================================
 
return_3DCCA:
    rts
; ===========================================================================
;loc_3DCCC
ObjC7_BackForearm:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DCE4(pc,d0.w),d1
    jsr off_3DCE4(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DCE4:  offsetTable
        offsetTableEntry.w loc_3DCEE    ; 0
        offsetTableEntry.w loc_3DD00    ; 2
        offsetTableEntry.w loc_3DACC    ; 4
        offsetTableEntry.w loc_3DB32    ; 6
        offsetTableEntry.w loc_3DB5A    ; 8
; ===========================================================================
 
loc_3DCEE:
    addq.b  #2,routine_secondary(a0)
    move.b  #6,mapping_frame(a0)
    move.b  #5,priority(a0)
    rts
; ===========================================================================
 
loc_3DD00:
    movea.w objoff_2C(a0),a1 ; a1=object
    bclr    #5,status(a1)
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$10,objoff_2A(a0)
    move.w  y_pos(a0),objoff_2E(a0)
    rts
; ===========================================================================
;loc_3DD20
ObjC7_BackThigh:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DD38(pc,d0.w),d1
    jsr off_3DD38(pc,d1.w)
    tst.b   (a0)
    beq.w   return_37A48
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
off_3DD38:  offsetTable
        offsetTableEntry.w loc_3DD3C    ; 0
        offsetTableEntry.w return_3DD4E ; 2
; ===========================================================================
 
loc_3DD3C:
    addq.b  #2,routine_secondary(a0)
    move.b  #$A,mapping_frame(a0)
    move.b  #5,priority(a0)
    rts
; ===========================================================================
 
return_3DD4E:
    rts
; ===========================================================================
;loc_3DD50
ObjC7_TargettingSensor:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DD5E(pc,d0.w),d1
    jmp off_3DD5E(pc,d1.w)
; ===========================================================================
off_3DD5E:  offsetTable
        offsetTableEntry.w loc_3DD64    ; 0
        offsetTableEntry.w loc_3DDA6    ; 2
        offsetTableEntry.w loc_3DE3C    ; 4
; ===========================================================================
 
loc_3DD64:
    addq.b  #2,routine_secondary(a0)
    move.b  #$10,mapping_frame(a0)
    ori.w   #high_priority,art_tile(a0)
    move.b  #1,priority(a0)
    move.w  #$A0,objoff_2A(a0)
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    move.w  x_vel(a1),objoff_30(a0)
    move.w  y_vel(a1),objoff_32(a0)
    move.w  #$18,angle(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DDA6:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3DE0A
    lea next_object(a0),a1 ; a1=object
    movea.l a1,a2
    move.w  -(a1),y_vel(a0)
    move.w  -(a1),x_vel(a0)
 
    moveq   #2,d6
-   move.l  -(a1),-(a2)
    dbf d6,-
 
    lea (MainCharacter).w,a2 ; a2=character
    move.w  x_vel(a2),d0
    bne.s   +
    move.w  x_pos(a2),x_pos(a0)
+
    move.w  d0,(a1)+
    move.w  y_vel(a2),d0
    bne.s   +
    move.w  y_pos(a2),y_pos(a0)
+
    move.w  d0,(a1)+
    jsrto   (ObjectMove).l, JmpTo26_ObjectMove
    lea (Ani_objC7_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    subq.b  #1,angle(a0)
    bpl.s   +
    subq.b  #1,objoff_27(a0)
    move.b  objoff_27(a0),angle(a0)
    moveq   #SndID_Beep,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DE0A:
    addq.b  #2,routine_secondary(a0)
    move.w  #$40,objoff_2A(a0)
    move.b  #4,angle(a0)
    lea (MainCharacter).w,a1 ; a1=character
    move.w  x_pos(a1),x_pos(a0)
    move.w  y_pos(a1),y_pos(a0)
    lea (ChildObjC7_TargettingLock).l,a2
    bsr.w   LoadChildObject
    clr.w   x_vel(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DE3C:
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3DE62
    lea (Ani_objC7_c).l,a1
    jsrto   (AnimateSprite).l, JmpTo25_AnimateSprite
    subq.b  #1,angle(a0)
    bpl.s   +
    move.b  #4,angle(a0)
    moveq   #SndID_Beep,d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DE62:
    movea.w objoff_2C(a0),a1 ; a1=object
    move.w  x_pos(a0),objoff_28(a1)
    bra.w   JmpTo65_DeleteObject
; ===========================================================================
;loc_3DE70
ObjC7_TargettingLock:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DE7E(pc,d0.w),d1
    jmp off_3DE7E(pc,d1.w)
; ===========================================================================
off_3DE7E:  offsetTable
        offsetTableEntry.w loc_3DE82    ; 0
        offsetTableEntry.w loc_3DEA2    ; 2
; ===========================================================================
 
loc_3DE82:
    addq.b  #2,routine_secondary(a0)
    move.b  #$14,mapping_frame(a0)
    move.b  #1,priority(a0)
    ori.w   #high_priority,art_tile(a0)
    move.w  #4,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DEA2:
    movea.w objoff_2C(a0),a1 ; a1=object
    tst.b   (a1)
    beq.w   JmpTo65_DeleteObject
    subq.w  #1,objoff_2A(a0)
    bne.s   +
    move.w  #4,objoff_2A(a0)
    bchg    #palette_bit_0,art_tile(a0)
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
;loc_3DEC2
ObjC7_EggmanBomb:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3DED0(pc,d0.w),d1
    jmp off_3DED0(pc,d1.w)
; ===========================================================================
off_3DED0:  offsetTable
        offsetTableEntry.w loc_3DED8
        offsetTableEntry.w loc_3DF04
        offsetTableEntry.w loc_3DF36
        offsetTableEntry.w loc_3DF80
; ===========================================================================
 
loc_3DED8:
    addq.b  #2,routine_secondary(a0)
    move.b  #$E,mapping_frame(a0)
    move.b  #$89,collision_flags(a0)
    move.b  #5,priority(a0)
    move.b  #$C,width_pixels(a0)
    lea byte_3DF00(pc),a1
    bsr.w   loc_3E282
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
byte_3DF00:
    dc.b   0
    dc.b $38    ; 1
    dc.b $FF    ; 2
    dc.b $EC    ; 3
; ===========================================================================
 
loc_3DF04:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #7,status(a1)
    bne.s   loc_3DF4C
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    move.w  y_pos(a0),d0
    cmpi.w  #$170,d0
    bhs.s   +
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
+
    addq.b  #2,routine_secondary(a0)
    move.w  #$170,y_pos(a0)
    move.w  #$40,objoff_2A(a0)
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DF36:
    movea.w objoff_2C(a0),a1 ; a1=object
    btst    #7,status(a1)
    bne.s   loc_3DF4C
    subq.w  #1,objoff_2A(a0)
    bmi.s   loc_3DF4C
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DF4C:
    move.b  #6,routine_secondary(a0)
    move.l  #Obj58_MapUnc_2D50A,mappings(a0)
    move.w  #make_art_tile(ArtTile_ArtNem_FieryExplosion,0,0),art_tile(a0)
    move.b  #1,priority(a0)
    move.b  #7,anim_frame_duration(a0)
    move.b  #0,mapping_frame(a0)
    move.w  #SndID_BossExplosion,d0
    jsr (PlaySound).l
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DF80:
    subq.b  #1,anim_frame_duration(a0)
    bpl.s   +
    move.b  #7,anim_frame_duration(a0)
    addq.b  #1,mapping_frame(a0)
    cmpi.b  #5,mapping_frame(a0)
    blo.s   +
    clr.b   collision_flags(a0)
    cmpi.b  #7,mapping_frame(a0)
    beq.w   JmpTo65_DeleteObject
+
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
;loc_3DFAA
ObjC7_FallingPieces:
    subq.w  #1,objoff_2A(a0)
    bmi.w   JmpTo65_DeleteObject
    jsrto   (ObjectMoveAndFall).l, JmpTo8_ObjectMoveAndFall
    jmpto   (DisplaySprite).l, JmpTo45_DisplaySprite
; ===========================================================================
 
loc_3DFBA:
    jsr (SingleObjLoad).l
    bne.s   +   ; rts
    _move.b #ObjID_BossExplosion,id(a1) ; load obj
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    jsr (RandomNumber).l
    move.w  d0,d1
    moveq   #0,d1
    move.b  d0,d1
    lsr.b   #2,d1
    subi.w  #$30,d1
    add.w   d1,x_pos(a1)
    lsr.w   #8,d0
    lsr.b   #2,d0
    subi.w  #$30,d0
    add.w   d0,y_pos(a1)
+
    rts
; ===========================================================================
;loc_3DFF8
ObjC7_CheckHit:
    tst.b   collision_property(a0)
    beq.s   ObjC7_Beaten
    tst.b   objoff_2A(a0)
    bne.s   ObjC7_Flashing
    tst.b   collision_flags(a0)
    beq.s   +
    movea.w objoff_36(a0),a1 ; a1=object
    tst.b   collision_flags(a1)
    bne.s   +++     ; rts
    clr.b   collision_flags(a0)
    subq.b  #1,collision_property(a0)
    beq.s   ObjC7_Beaten
+
    move.b  #$3C,objoff_2A(a0)
    move.w  #SndID_BossHit,d0
    jsr (PlaySound).l
;loc_3E02E
ObjC7_Flashing:
    lea (Normal_palette_line2+2).w,a1
    moveq   #0,d0
    tst.w   (a1)
    bne.s   +
    move.w  #$EEE,d0
+
    move.w  d0,(a1)
    subq.b  #1,objoff_2A(a0)
    bne.s   +
    clr.w   (Normal_palette_line2+2).w
    move.b  #$16,collision_flags(a0)
    movea.w objoff_36(a0),a1 ; a1=object
    move.b  #$2A,collision_flags(a1)
+
    rts
; ===========================================================================
;loc_3E05A
ObjC7_Beaten:
    moveq   #100,d0
    bsr.w   AddPoints
    clr.b   anim_frame_duration(a0)
    move.b  #$E,routine_secondary(a0)
    bset    #7,status(a0)
    clr.b   anim(a0)
    clr.b   collision_flags(a0)
    clr.w   x_vel(a0)
    clr.w   y_vel(a0)
    bsr.w   ObjC7_RemoveCollision
    bsr.w   ObjC7_Break
    movea.w objoff_38(a0),a1 ; a1=object
    jsrto   (DeleteObject2).l, JmpTo6_DeleteObject2
    addq.w  #4,sp
    rts
; ===========================================================================
;loc_3E094
ObjC7_Break:
    lea (ObjC7_BreakOffsets).l,a1
    lea ObjC7_BreakSpeeds(pc),a2
    moveq   #0,d0
    moveq   #ObjC7_BreakOffsets_End-ObjC7_BreakOffsets-1,d6
 
-   move.b  (a1)+,d0
    movea.w (a0,d0.w),a3 ; a3=object
    move.b  #$1E,routine(a3)
    clr.b   routine_secondary(a3)
    move.w  #$80,objoff_2A(a3)
    move.w  (a2)+,x_vel(a3)
    move.w  (a2)+,y_vel(a3)
    dbf d6,-
    rts
; ===========================================================================
;word_3E0C6
ObjC7_BreakSpeeds:
    dc.w  $200,-$400
    dc.w -$100,-$100    ; 2
    dc.w  $300,-$300    ; 4
    dc.w -$100,-$400    ; 6
    dc.w  $180,-$200    ; 8
    dc.w -$200,-$300    ; 10
    dc.w     0,-$400    ; 12
    dc.w  $100,-$300    ; 14
ObjC7_BreakSpeeds_End
;byte_3E0E6
ObjC7_BreakOffsets:
    dc.b objoff_2C
    dc.b objoff_2E  ; 1
    dc.b objoff_30  ; 2
    dc.b objoff_32  ; 3
    dc.b objoff_34  ; 4
    dc.b objoff_3A  ; 5
    dc.b objoff_3C  ; 6
    dc.b objoff_3E  ; 7
ObjC7_BreakOffsets_End
; ===========================================================================
;loc_3E0EE
ObjC7_InitCollision:
    lea ObjC7_ChildOffsets(pc),a1
    lea ObjC7_ChildCollision(pc),a2
    moveq   #0,d0
 
    moveq   #ObjC7_ChildCollision_End-ObjC7_ChildCollision-1,d6
-   move.b  (a1)+,d0
    movea.w (a0,d0.w),a3 ; a3=object
    move.b  (a2)+,collision_flags(a3)
    dbf d6,-
 
    rts
; ===========================================================================
;byte_3E10A
ObjC7_ChildCollision:
    dc.b   0
    dc.b $8F    ; 1
    dc.b $9C    ; 2
    dc.b   0    ; 3
    dc.b $86    ; 4
    dc.b $2A    ; 5
    dc.b $8B    ; 6
    dc.b $8F    ; 7
    dc.b $9C    ; 8
    dc.b $8B    ; 9
ObjC7_ChildCollision_End
;byte_3E114
ObjC7_ChildOffsets:
    dc.b objoff_2C
    dc.b objoff_2E  ; 1
    dc.b objoff_30  ; 2
    dc.b objoff_32  ; 3
    dc.b objoff_34  ; 4
    dc.b objoff_36  ; 5
    dc.b objoff_38  ; 6
    dc.b objoff_3A  ; 7
    dc.b objoff_3C  ; 8
    dc.b objoff_3E  ; 9
ObjC7_ChildOffsets_End
; ===========================================================================
;loc_3E11E
ObjC7_RemoveCollision:
    lea ObjC7_ChildOffsets(pc),a1
    moveq   #0,d0
    moveq   #ObjC7_ChildOffsets_End-ObjC7_ChildOffsets-1,d6
 
-   move.b  (a1)+,d0
    movea.w (a0,d0.w),a3 ; a3=object
    clr.b   collision_flags(a3)
    dbf d6,-
    rts
; ===========================================================================
;loc_3E136
CreateEggmanBombs:
    lea EggmanBomb_InitSpeeds(pc),a3
    moveq   #1,d6
 
-   lea (ChildObjC7_EggmanBomb).l,a2
    bsr.w   LoadChildObject
    move.w  (a3)+,d0
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d0
+
    move.w  d0,x_vel(a1)
    move.w  (a3)+,y_vel(a1)
    dbf d6,-
    rts
; ===========================================================================
;word_3E160
EggmanBomb_InitSpeeds:
    dc.w   $60,-$800
    dc.w   $C0,-$A00
; ===========================================================================
 
loc_3E168:
    move.b  render_flags(a0),d0
    andi.b  #1,d0
    moveq   #0,d1
    lea byte_3E19E(pc),a1
 
-   move.b  (a1)+,d1
    beq.w   return_37A48
    movea.w (a0,d1.w),a2 ; a2=object
    move.b  render_flags(a2),d2
    andi.b  #$FE,d2
    or.b    d0,d2
    move.b  d2,render_flags(a2)
    move.b  status(a2),d2
    andi.b  #$FE,d2
    or.b    d0,d2
    move.b  d2,status(a2)
    bra.s   -
; ===========================================================================
byte_3E19E:
    dc.b $2C
    dc.b $2E    ; 1
    dc.b $30    ; 2
    dc.b $32    ; 3
    dc.b $34    ; 4
    dc.b $36    ; 5
    dc.b $38    ; 6
    dc.b $3A    ; 7
    dc.b $3C    ; 8
    dc.b $3E    ; 9
    dc.b   0    ; 10
    dc.b   0    ; 11
; ===========================================================================
 
loc_3E1AA:
    movea.l (a1)+,a2
    moveq   #0,d0
    move.b  anim_frame(a0),d0
    move.b  (a1,d0.w),d0
    move.b  d0,d1
    moveq   #0,d4
    andi.w  #$C0,d1
    beq.s   +
    bsr.w   loc_3E23E
+
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.b  (a2)+,d0
    move.b  (a2)+,d3
    move.b  objoff_1F(a0),d2
    addq.b  #1,d2
    cmp.b   d3,d2
    blo.s   +
    addq.b  #1,anim_frame(a0)
    moveq   #0,d2
+
    move.b  d2,objoff_1F(a0)
    moveq   #0,d5
 
-   move.b  (a2)+,d5
    movea.w (a0,d5.w),a3 ; a3=object
    tst.w   d5
    bne.s   +
    movea.l a0,a3
+
    move.l  x_pos(a3),d2
    move.b  (a2)+,d1
    ext.w   d1
    asl.w   #4,d1
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d1
+
    tst.w   d4
    beq.s   +
    neg.w   d1
+
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d2
    move.l  d2,x_pos(a3)
    move.l  y_pos(a3),d3
    move.b  (a2)+,d1
    ext.w   d1
    asl.w   #4,d1
    tst.w   d4
    beq.s   +
    neg.w   d1
+
    ext.l   d1
    asl.l   #8,d1
    add.l   d1,d3
    move.l  d3,y_pos(a3)
    dbf d0,-
 
    moveq   #0,d1
    rts
; ===========================================================================
 
loc_3E236:
    clr.b   anim_frame(a0)
    moveq   #1,d1
 
return_3E23C:
    rts
; ===========================================================================
 
loc_3E23E:
    andi.b  #$3F,d0
    rol.b   #3,d1
    move.w  off_3E24C-2(pc,d1.w),d1
    jmp off_3E24C(pc,d1.w)
; ===========================================================================
off_3E24C:  offsetTable
        offsetTableEntry.w loc_3E252
        offsetTableEntry.w loc_3E27A
        offsetTableEntry.w loc_3E27E
; ===========================================================================
 
loc_3E252:
    tst.b   objoff_1F(a0)
    bne.s   return_3E23C
    move.b  anim_frame(a0),d1
    addq.b  #1,d1
    move.b  (a1,d1.w),d0
    jsrto   (PlaySound).l, JmpTo12_PlaySound ; sound id most likely came from off_3E40C or off_3E42C
    addq.b  #1,d1
    move.b  d1,anim_frame(a0)
    move.b  (a1,d1.w),d0
    move.b  d0,d1
    andi.b  #$C0,d1
    bne.s   loc_3E23E
    rts
; ===========================================================================
 
loc_3E27A:
    moveq   #1,d4
    rts
; ===========================================================================
 
loc_3E27E:
    addq.w  #4,sp
    bra.s   loc_3E236
; ===========================================================================
 
loc_3E282:
    movea.w objoff_2C(a0),a2 ; a2=object
    move.w  x_pos(a2),d0
    move.w  (a1)+,d1
    btst    #0,render_flags(a2)
    beq.s   +
    neg.w   d1
+
    add.w   d1,d0
    move.w  d0,x_pos(a0)
    move.w  y_pos(a2),d0
    add.w   (a1)+,d0
    move.w  d0,y_pos(a0)
    rts
; ===========================================================================
;loc_3E2A8
ObjC7_PositionChildren:
    moveq   #0,d0
    moveq   #0,d6
 
    move.b  (a1)+,d6
-   move.b  (a1)+,d0
    movea.w (a0,d0.w),a2 ; a2=object
    move.w  x_pos(a0),d1
    move.b  (a1)+,d2
    ext.w   d2
    btst    #0,render_flags(a0)
    beq.s   +
    neg.w   d2
+
    add.w   d2,d1
    move.w  d1,x_pos(a2)
    move.w  y_pos(a0),d1
    move.b  (a1)+,d2
    ext.w   d2
    add.w   d2,d1
    move.w  d1,y_pos(a2)
    dbf d6,-
    rts
; ===========================================================================
;byte_3E2E0
ObjC7_ChildDeltas:
    dc.b   6
    dc.b $2E    ; 1
    dc.b $FC    ; 2
    dc.b $3C    ; 3
    dc.b $30    ; 4
    dc.b $F4    ; 5
    dc.b   8    ; 6
    dc.b $32    ; 7
    dc.b  $C    ; 8
    dc.b $F8    ; 9
    dc.b $34    ; 10
    dc.b   4    ; 11
    dc.b $24    ; 12
    dc.b $3A    ; 13
    dc.b $FC    ; 14
    dc.b $3C    ; 15
    dc.b $3C    ; 16
    dc.b $F4    ; 17
    dc.b   8    ; 18
    dc.b $3E    ; 19
    dc.b   4    ; 20
    dc.b $24    ; 21
off_3E2F6:
    dc.l ObjC7_GroupAni_3E318
    dc.b 0, 1, 2, 3, $FF, 0
off_3E300:
    dc.l ObjC7_GroupAni_3E318
    dc.b 5, 6, 7, 8, $FF, 0
off_3E30A:
    dc.l ObjC7_GroupAni_3E318
    dc.b 0, 1, 2, 3, 4, 5, 6, 7, 8, $C0
; -----------------------------------------------------------------------------
; Custom animation
; -----------------------------------------------------------------------------
; must be on the same line as a label that has a corresponding _End label later
c7anilistheader macro maxframe,{INTLABEL}
__LABEL__ label *
    dc.b ((__LABEL___End - __LABEL__ - 2) / 3) - 1,maxframe
    endm
 
; macro for a animation data
c7ani macro pieceOffset,deltax,deltay
    dc.b    pieceOffset,deltax,deltay
    endm
 
ObjC7_GroupAni_3E318:       offsetTable ;BINCLUDE "mappings/sprite/objC7_a.bin"
        offsetTableEntry.w byte_3E32A
        offsetTableEntry.w byte_3E33E
        offsetTableEntry.w byte_3E352
        offsetTableEntry.w byte_3E366
        offsetTableEntry.w byte_3E37A
        offsetTableEntry.w byte_3E380
        offsetTableEntry.w byte_3E394
        offsetTableEntry.w byte_3E3A8
        offsetTableEntry.w byte_3E3BC
 
byte_3E32A: c7anilistheader 8
    c7ani       $00, $E0, $0C
    c7ani objoff_30, $E0, $0C
    c7ani objoff_32, $E0, $0C
    c7ani objoff_3C, $E0, $0C
    c7ani objoff_34, $F8, $04
    c7ani objoff_3E, $F8, $04
byte_3E32A_End
 
byte_3E33E: c7anilistheader 8
    c7ani       $00, $EC, $14
    c7ani objoff_30, $EC, $14
    c7ani objoff_32, $EC, $14
    c7ani objoff_3C, $EC, $14
    c7ani objoff_34, $FA, $06
    c7ani objoff_3E, $FA, $06
byte_3E33E_End
 
byte_3E352: c7anilistheader 8
    c7ani       $00, $F8, $14
    c7ani objoff_30, $F8, $14
    c7ani objoff_32, $F8, $14
    c7ani objoff_3C, $F8, $14
    c7ani objoff_34, $FE, $04
    c7ani objoff_3E, $FE, $04
byte_3E352_End
 
byte_3E366: c7anilistheader 8
    c7ani       $00, $FC, $0C
    c7ani objoff_30, $FC, $0C
    c7ani objoff_32, $FC, $0C
    c7ani objoff_3C, $FC, $0c
    c7ani objoff_34, $00, $02
    c7ani objoff_3E, $00, $02
byte_3E366_End
 
byte_3E37A: c7anilistheader 8
    c7ani       $00, $00, $00
byte_3E37A_End
    even
byte_3E380: c7anilistheader 8
    c7ani       $00, $04, $E8
    c7ani objoff_30, $04, $E8
    c7ani objoff_32, $04, $E8
    c7ani objoff_3C, $04, $E8
    c7ani objoff_34, $02, $FA
    c7ani objoff_3E, $02, $FA
byte_3E380_End
 
byte_3E394: c7anilistheader 8
    c7ani       $00, $0C, $E8
    c7ani objoff_30, $0C, $E8
    c7ani objoff_32, $0C, $E8
    c7ani objoff_3C, $0C, $E8
    c7ani objoff_34, $04, $FC
    c7ani objoff_3E, $04, $FC
byte_3E394_End
 
byte_3E3A8: c7anilistheader 8
    c7ani       $00, $18, $F4
    c7ani objoff_30, $18, $F4
    c7ani objoff_32, $18, $F4
    c7ani objoff_3C, $18, $F4
    c7ani objoff_34, $04, $FC
    c7ani objoff_3E, $04, $FC
byte_3E3A8_End
 
byte_3E3BC: c7anilistheader 8
    c7ani       $00, $18, $FC
    c7ani objoff_30, $18, $FC
    c7ani objoff_32, $18, $FC
    c7ani objoff_3C, $18, $FC
    c7ani objoff_34, $06, $FE
    c7ani objoff_3E, $06, $FE
byte_3E3BC_End
 
off_3E3D0:
    dc.l ObjC7_GroupAni_3E3D8
    dc.b 0, 1, 2, $C0
; -----------------------------------------------------------------------------
; Custom animation
; -----------------------------------------------------------------------------
ObjC7_GroupAni_3E3D8:       offsetTable ;BINCLUDE "mappings/sprite/objC7_b.bin"
        offsetTableEntry.w byte_3E3DE
        offsetTableEntry.w byte_3E3F2
        offsetTableEntry.w byte_3E3F8
 
byte_3E3DE: c7anilistheader $10
    c7ani       $00, $00, $04
    c7ani objoff_30, $00, $04
    c7ani objoff_32, $00, $04
    c7ani objoff_3C, $00, $04
    c7ani objoff_34, $00, $04
    c7ani objoff_3E, $00, $04
byte_3E3DE_End
 
byte_3E3F2: c7anilistheader $10
    c7ani       $00, $00, $00
byte_3E3F2_End
    even
byte_3E3F8: c7anilistheader 8
    c7ani       $00, $00, $F8
    c7ani objoff_30, $00, $F8
    c7ani objoff_32, $00, $F8
    c7ani objoff_3C, $00, $F8
    c7ani objoff_34, $00, $F8
    c7ani objoff_3E, $00, $F8
byte_3E3F8_End
 
off_3E40C:
    dc.l ObjC7_GroupAni_3E438
    dc.b   0,  1,  2,  3, $40, SndID_Hammer
    dc.b   4,  5,  6,  7,   8, $40, SndID_Hammer
    dc.b   9, $A,  1,  2,   3, $40, SndID_Hammer
    dc.b   4,  5,  6,  7,   8, $40, SndID_Hammer, $C0
off_3E42C:
    dc.l ObjC7_GroupAni_3E438
    dc.b $88, $87, $86, $85, $B, $40, SndID_Hammer, $C0
; -----------------------------------------------------------------------------
; Custom animation
; -----------------------------------------------------------------------------
ObjC7_GroupAni_3E438:       offsetTable ;BINCLUDE "mappings/sprite/objC7_c.bin"
        offsetTableEntry.w byte_3E450
        offsetTableEntry.w byte_3E468
        offsetTableEntry.w byte_3E480
        offsetTableEntry.w byte_3E494
        offsetTableEntry.w byte_3E4AC
        offsetTableEntry.w byte_3E4C4
        offsetTableEntry.w byte_3E4D6
        offsetTableEntry.w byte_3E4EE
        offsetTableEntry.w byte_3E502
        offsetTableEntry.w byte_3E51A
        offsetTableEntry.w byte_3E532
        offsetTableEntry.w byte_3E544
 
byte_3E450: c7anilistheader $20
    c7ani objoff_34, $F8, $F8
    c7ani objoff_2E, $F8, $F8
    c7ani       $00, $00, $FC
    c7ani objoff_30, $04, $FB
    c7ani objoff_32, $03, $FB
    c7ani objoff_3C, $FC, $FB
    c7ani objoff_3E, $00, $FE
byte_3E450_End
    even
byte_3E468: c7anilistheader $10
    c7ani objoff_34, $F0, $FC
    c7ani objoff_2E, $F0, $FC
    c7ani       $00, $F0, $FC
    c7ani objoff_30, $F4, $FB
    c7ani objoff_32, $F3, $FB
    c7ani objoff_3C, $EC, $FB
    c7ani objoff_3E, $F8, $00
byte_3E468_End
    even
byte_3E480: c7anilistheader $10
    c7ani objoff_34, $F8, $04
    c7ani objoff_2E, $F8, $04
    c7ani       $00, $F8, $04
    c7ani objoff_30, $FC, $03
    c7ani objoff_32, $FB, $03
    c7ani objoff_3C, $F4, $03
byte_3E480_End
 
byte_3E494: c7anilistheader $10
    c7ani objoff_34, $FC, $10
    c7ani objoff_2E, $F8, $10
    c7ani       $00, $00, $08
    c7ani objoff_30, $F8, $0A
    c7ani objoff_32, $FA, $0A
    c7ani objoff_3C, $08, $0A
    c7ani objoff_3E, $00, $08
byte_3E494_End
    even
byte_3E4AC: c7anilistheader $20
    c7ani objoff_34, $FE, $FE
    c7ani       $00, $F4, $FC
    c7ani objoff_30, $F0, $FD
    c7ani objoff_32, $F1, $FD
    c7ani objoff_3C, $F8, $FD
    c7ani objoff_3E, $EC, $FA
    c7ani objoff_3A, $E8, $FC
byte_3E4AC_End
    even
byte_3E4C4: c7anilistheader $20
    c7ani objoff_3E, $F8, $FC
    c7ani objoff_3A, $F8, $FC
    c7ani objoff_30, $FC, $FF
    c7ani objoff_32, $FD, $FF
    c7ani objoff_3C, $04, $FF
byte_3E4C4_End
    even
byte_3E4D6: c7anilistheader $10
    c7ani objoff_3E, $F0, $FC
    c7ani objoff_3A, $F0, $FC
    c7ani       $00, $F0, $FC
    c7ani objoff_30, $EC, $FB
    c7ani objoff_32, $ED, $FB
    c7ani objoff_3C, $F4, $FB
    c7ani objoff_34, $F8, $00
byte_3E4D6_End
    even
byte_3E4EE: c7anilistheader $10
    c7ani objoff_3E, $F8, $04
    c7ani objoff_3A, $F8, $04
    c7ani       $00, $F8, $04
    c7ani objoff_30, $F4, $03
    c7ani objoff_32, $F5, $03
    c7ani objoff_3C, $FC, $03
byte_3E4EE_End
 
byte_3E502: c7anilistheader $10
    c7ani objoff_3E, $FC, $10
    c7ani objoff_3A, $F8, $10
    c7ani       $00, $00, $08
    c7ani objoff_30, $08, $0A
    c7ani objoff_32, $06, $0A
    c7ani objoff_3C, $F8, $0A
    c7ani objoff_34, $00, $08
byte_3E502_End
    even
byte_3E51A: c7anilistheader $20
    c7ani objoff_3E, $FE, $FE
    c7ani       $00, $F4, $FC
    c7ani objoff_30, $F8, $FD
    c7ani objoff_32, $F7, $FD
    c7ani objoff_3C, $F1, $FD
    c7ani objoff_34, $EC, $FA
    c7ani objoff_2E, $E8, $FC
byte_3E51A_End
    even
byte_3E532: c7anilistheader $20
    c7ani objoff_34, $F8, $FC
    c7ani objoff_2E, $F8, $FC
    c7ani objoff_30, $04, $FF
    c7ani objoff_32, $03, $FF
    c7ani objoff_3C, $FC, $FF
byte_3E532_End
    even
byte_3E544: c7anilistheader $10
    c7ani objoff_3E, $00, $08
    c7ani objoff_3A, $00, $08
    c7ani       $00, $00, $08
    c7ani objoff_30, $00, $08
    c7ani objoff_32, $00, $08
    c7ani objoff_3C, $00, $08
    c7ani objoff_34, $00, $08
byte_3E544_End
    even
 
;word_3E55C
ChildObjC7_Shoulder:
    dc.w objoff_2C
    dc.b ObjID_Eggrobo
    dc.b   4
;word_3E560
ChildObjC7_FrontLowerLeg:
    dc.w objoff_2E
    dc.b ObjID_Eggrobo
    dc.b   6
;word_3E564
ChildObjC7_FrontForearm:
    dc.w objoff_30
    dc.b ObjID_Eggrobo
    dc.b   8
;word_3E568
ChildObjC7_Arm:
    dc.w objoff_32
    dc.b ObjID_Eggrobo
    dc.b  $A
;word_3E56C
ChildObjC7_FrontThigh:
    dc.w objoff_34
    dc.b ObjID_Eggrobo
    dc.b  $C
;word_3E570
ChildObjC7_Head:
    dc.w objoff_36
    dc.b ObjID_Eggrobo
    dc.b  $E
;word_3E574
ChildObjC7_Jet:
    dc.w objoff_38
    dc.b ObjID_Eggrobo
    dc.b $10
;word_3E578
ChildObjC7_BackLowerLeg:
    dc.w objoff_3A
    dc.b ObjID_Eggrobo
    dc.b $12
;word_3E57C
ChildObjC7_BackForearm:
    dc.w objoff_3C
    dc.b ObjID_Eggrobo
    dc.b $14
;word_3E580
ChildObjC7_BackThigh:
    dc.w objoff_3E
    dc.b ObjID_Eggrobo
    dc.b $16
;word_3E584
ChildObjC7_TargettingSensor:
    dc.w objoff_10
    dc.b ObjID_Eggrobo
    dc.b $18
;word_3E588
ChildObjC7_TargettingLock:
    dc.w objoff_10
    dc.b ObjID_Eggrobo
    dc.b $1A
;word_3E58C
ChildObjC7_EggmanBomb:
    dc.w objoff_10
    dc.b ObjID_Eggrobo
    dc.b $1C
;off_3E590
ObjC7_SubObjData:
    subObjData ObjC7_MapUnc_3E5F8,make_art_tile(ArtTile_ArtNem_DEZBoss,0,0),4,4,$38,$00
 
; animation script
; off_3E59A:
Ani_objC7_a:    offsetTable
        offsetTableEntry.w +
+       dc.b   7,$15,$15,$15,$15,$15,$15,$15,$15,  0,  1,  2,$FA
        even
 
; animation script
; off_3E5AA:
Ani_objC7_b:    offsetTable
        offsetTableEntry.w byte_3E5B2
        offsetTableEntry.w byte_3E5B6
        offsetTableEntry.w byte_3E5D0
        offsetTableEntry.w byte_3E5EA
byte_3E5B2: dc.b   1, $C, $D,$FF
byte_3E5B6: dc.b   1, $C, $D, $C, $C, $D, $D, $C, $C, $C, $D, $D, $D, $C, $C, $C
        dc.b  $C, $C, $D, $D, $D, $D, $D, $D,$FA,  0; 16
byte_3E5D0: dc.b   1, $D, $D, $D, $D, $D, $D, $C, $C, $C, $C, $C, $D, $D, $D, $C
        dc.b  $C, $C, $D, $D, $C, $C, $D, $C,$FD,  0; 16
byte_3E5EA: dc.b   0, $D,$15,$FF
        even
 
; animation script
; off_3E5EE:
Ani_objC7_c:    offsetTable
        offsetTableEntry.w byte_3E5F0
byte_3E5F0: dc.b   3,$13,$12,$11,$10,$16,$FF
        even
; ------------------------------------------------------------------------------
; sprite mappings
; ------------------------------------------------------------------------------
ObjC7_MapUnc_3E5F8: BINCLUDE "mappings/sprite/objC7.bin"
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to upscale graphics by a factor of 2x, based on given mappings
; data for correct positioning of tiles.
;
; This code is awfully structured and planned: whenever a 3-column sprite piece
; is scaled, it scales the next tiles that were copied to RAM as if the piece
; had 4 columns; this will then be promptly overwritten by the next piece. If
; this happens near the end of the buffer, you will get a buffer overrun.
; Moreover, when the number of rows in the sprite piece is also 3 or 4, the code
; will make an incorrect computation for the output of the next subpiece, which
; causes the output to overwrite art from the previous subpiece. Thus, this code
; fails if there is a 3x3 or a 3x4 sprite piece in the source mappings. Sadly,
; this issue is basically unfixable without rewriting the code entirely.
;
; Input:
;   a1  Location of tiles to be enlarged
;   a2  Destination buffer for enlarged tiles
;   d0  Width-1 of sprite piece
;   d1  Height-1 of sprite piece
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
;loc_3E89E
Scale_2x:
    move.w  d1,d2                   ; Copy piece height-1
    andi.w  #1,d2                   ; Want only low bit -- this is 1 for Wx2 or Wx4 pieces, 0 otherwise
    addq.w  #1,d2                   ; Make it into 2 for Wx2 or Wx4 pieces, 1 otherwise
    lsl.w   #6,d2                   ; This is now $80 (4 tiles) for Wx2 or Wx4 pieces, $40 (2 tiles) otherwise
    swap    d2                      ; Save it to high word
    move.w  d1,d3                   ; Copy piece height-1 again
    lsr.w   #1,d3                   ; This time, want high bit (1 for Wx3 or Wx4, 0 for Wx2 or Wx1)
    addq.w  #1,d3                   ; Make it into 2 for Wx3 or Wx4 pieces, 1 otherwise
    lsl.w   #6,d3                   ; This is now $80 (4 tiles) for Wx3 or Wx4 pieces, $40 (2 tiles) otherwise
    swap    d3                      ; Save it to high word
    bsr.w   .upscale_part1          ; Scale the first line???; sets a3 = ???, a5 = ???
    btst    #1,d0                   ; Is this a 1xH or a 2xH piece?
    beq.w   return_37A48            ; Return if yes
    btst    #1,d1                   ; Is this a Wx3 or a Wx4 piece?
    bne.s   .set_dest               ; Branch if yes
    movea.l a3,a5                   ; Advance to next column instead
 
.set_dest:
    movea.l a5,a2                   ; Set new output location
 
.upscale_part1:
    movea.l a2,a4                   ; Copy destination to a4
    swap    d2                      ; Get height offset
    lea (a2,d2.w),a3                ; Output location for next tile
    swap    d2                      ; Save height offset again
    move.w  d1,d5                   ; Copy height-1
    andi.w  #1,d5                   ; How many tiles we want to do-1 -- this is 1 for Wx2 or Wx4 pieces, 0 otherwise
    bsr.w   Scale2x_SingleTile
    btst    #1,d1                   ; Are we upscaling a Wx3 or Wx4 piece?
    beq.s   .done_cols              ; Branch if not
    swap    d2                      ; Get height offset
    move.w  d2,d4                   ; Copy it to d4
    swap    d2                      ; Save height offset again
    add.w   d4,d4                   ; This is now $100 (8 tiles) for Wx4 pieces, $80 (4 tiles) for Wx3 pieces
    move.w  d0,d3                   ; Copy piece width-1
    andi.w  #1,d3                   ; Want only low bit -- this is 1 for 2xH or 4xH pieces, 0 otherwise
    lsl.w   d3,d4                   ; This is now: $200 (16 tiles) for 2x4 or 4x4 pieces; $100 (8 tiles) for 2x3, 4x3, 1x4 or 3x4 pieces; $80 (4 tiles) for 1x3 or 3x3 pieces
    adda.w  d4,a4                   ; Advance to this location
    move.w  d1,d5                   ; Copy height-1
    lsr.w   #1,d5                   ; How many tiles we want to do-1 -- this is 1 for Wx4 pieces, 0 for Wx3 pieces
    swap    d3                      ; Get height offset
    lea (a4,d3.w),a5                ; Output location for next tile
    swap    d3                      ; Save height offset again
    bsr.w   Scale2x_SingleTile2
 
.done_cols:
    btst    #0,d0                   ; Is this a 1xH or 3xH piece?
    bne.s   .keep_upscaling         ; Branch if not
    btst    #1,d0                   ; Was this a single column piece?
    beq.s   .done                   ; Return if so
 
.keep_upscaling:
    swap    d2                      ; Get height offset
    lea (a2,d2.w),a2                ; Output location for next tile
    lea (a2,d2.w),a3                ; Output location for next tile
    swap    d2                      ; Save height offset again
    move.w  d1,d5                   ; Copy height-1
    andi.w  #1,d5                   ; How many tiles we want to do -- this is 1 for Wx2 or Wx4 pieces, 0 otherwise
    bsr.w   Scale2x_SingleTile
    btst    #1,d1                   ; Are we upscaling a Wx3 or Wx4 piece?
    beq.s   .done                   ; Branch if not
    move.w  d1,d5                   ; Copy height-1
    lsr.w   #1,d5                   ; How many tiles we want to do-1 -- this is 1 for Wx4 or Wx3 pieces, 0 otherwise
    swap    d3                      ; Get height offset
    lea (a4,d3.w),a4                ; Output location for next tile
    lea (a4,d3.w),a5                ; Output location for next tile
    swap    d3                      ; Save height offset again
    bsr.w   Scale2x_SingleTile2
 
.done:
    rts
; ===========================================================================
; Upscales the given tile to the pair of tiles on the output pointers.
;
; Input:
;   a1  Pixel source
;   d5  Number of tiles-1 to upscale
;   a2  Location of output tiles for left pixels
;   a3  Location of output tiles for right pixels
; Output:
;   a1  Pixel source after processed tiles
;   a2  Location of output tiles for left pixels after scaled tiles
;   a3  Location of output tiles for right pixels after scaled tiles
;loc_3E944
Scale2x_SingleTile:
    moveq   #7,d6                   ; 8 rows per tile
 
.loop:
    bsr.w   Scale_2x_LeftPixels     ; Upscale pixels 0-3 of current row
    addq.w  #4,a2                   ; Advance write destination by one row (8 pixels)
    bsr.w   Scale_2x_RightPixels    ; Upscale pixels 4-7 of current row
    addq.w  #4,a3                   ; Advance write destination by one row (8 pixels)
    dbf d6,.loop
 
    dbf d5,Scale2x_SingleTile
 
    rts
; ===========================================================================
; Upscales the given tile to the pair of tiles on the output pointers.
;
; Input:
;   a1  Pixel source
;   d5  Number of tiles-1 to upscale
;   a4  Location of output tiles for left pixels
;   a5  Location of output tiles for right pixels
; Output:
;   a1  Pixel source after processed tiles
;   a4  Location of output tiles for left pixels after scaled tiles
;   a5  Location of output tiles for right pixels after scaled tiles
;loc_3E95C
Scale2x_SingleTile2:
    moveq   #7,d6                   ; 8 rows per tile
 
.loop:
    bsr.w   Scale_2x_LeftPixels2    ; Upscale pixels 0-3 of current row
    addq.w  #4,a4                   ; Advance write destination by one row (8 pixels)
    bsr.w   Scale_2x_RightPixels2   ; Upscale pixels 4-7 of current row
    addq.w  #4,a5                   ; Advance write destination by one row (8 pixels)
    dbf d6,.loop
 
    dbf d5,Scale2x_SingleTile2
 
    rts
; ===========================================================================
; Upscales the leftmost 4 pixels on the current row into the corresponding two
; rows of the output tile
;loc_3E974
Scale_2x_LeftPixels:
    bsr.w   .upscale_pixel_pair
 
.upscale_pixel_pair:
    move.b  (a1)+,d2                ; Read two pixels
    move.b  d2,d3                   ; Save them
    andi.b  #$F0,d2                 ; Get left pixel
    move.b  d2,d4                   ; Copy it...
    lsr.b   #4,d4                   ; ... shift it down into place...
    or.b    d2,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a2)+                ; Save to top tile, both on one row...
    move.b  d4,3(a2)                ; ... and on the row below
    andi.b  #$F,d3                  ; Get saved right pixel
    move.b  d3,d4                   ; Copy it...
    lsl.b   #4,d4                   ; ... shift it up into place...
    or.b    d3,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a2)+                ; Save to top tile, both on one row...
    move.b  d4,3(a2)                ; ... and on the row below
    rts
; ===========================================================================
; Upscales the rightmost 4 pixels on the current row into the corresponding two
; rows of the output tile
;loc_3E99E
Scale_2x_RightPixels:
    bsr.w   .upscale_pixel_pair
 
.upscale_pixel_pair:
    move.b  (a1)+,d2                ; Read two pixels
    move.b  d2,d3                   ; Save them
    andi.b  #$F0,d2                 ; Get left pixel
    move.b  d2,d4                   ; Copy it...
    lsr.b   #4,d4                   ; ... shift it down into place...
    or.b    d2,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a3)+                ; Save to bottom tile, both on one row...
    move.b  d4,3(a3)                ; ... and on the row below
    andi.b  #$F,d3                  ; Get saved right pixel
    move.b  d3,d4                   ; Copy it...
    lsl.b   #4,d4                   ; ... shift it up into place...
    or.b    d3,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a3)+                ; Save to bottom tile, both on one row...
    move.b  d4,3(a3)                ; ... and on the row below
    rts
; ===========================================================================
; Upscales the leftmost 4 pixels on the current row into the corresponding two
; rows of the output tile
;loc_3E9C8
Scale_2x_LeftPixels2:
    bsr.w   .upscale_pixel_pair
 
.upscale_pixel_pair:
    move.b  (a1)+,d2                ; Read two pixels
    move.b  d2,d3                   ; Save them
    andi.b  #$F0,d2                 ; Get left pixel
    move.b  d2,d4                   ; Copy it...
    lsr.b   #4,d4                   ; ... shift it down into place...
    or.b    d2,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a4)+                ; Save to top tile, both on one row...
    move.b  d4,3(a4)                ; ... and on the row below
    andi.b  #$F,d3                  ; Get saved right pixel
    move.b  d3,d4                   ; Copy it...
    lsl.b   #4,d4                   ; ... shift it up into place...
    or.b    d3,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a4)+                ; Save to top tile, both on one row...
    move.b  d4,3(a4)                ; ... and on the row below
    rts
; ===========================================================================
; Upscales the rightmost 4 pixels on the current row into the corresponding two
; rows of the output tile
;loc_3E9F2
Scale_2x_RightPixels2:
    bsr.w   .upscale_pixel_pair
 
.upscale_pixel_pair:
    move.b  (a1)+,d2                ; Read two pixels
    move.b  d2,d3                   ; Save them
    andi.b  #$F0,d2                 ; Get left pixel
    move.b  d2,d4                   ; Copy it...
    lsr.b   #4,d4                   ; ... shift it down into place...
    or.b    d2,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a5)+                ; Save to bottom tile, both on one row...
    move.b  d4,3(a5)                ; ... and on the row below
    andi.b  #$F,d3                  ; Get saved right pixel
    move.b  d3,d4                   ; Copy it...
    lsl.b   #4,d4                   ; ... shift it up into place...
    or.b    d3,d4                   ; ... and make it into two pixels of the same color
    move.b  d4,(a5)+                ; Save to bottom tile, both on one row...
    move.b  d4,3(a5)                ; ... and on the row below
    rts
; ===========================================================================
 
    ; this data seems to be unused
    dc.b $12,$34,$56,$78
    dc.b $12,$34,$56,$78    ; 4
    dc.b $12,$34,$56,$78    ; 8
    dc.b $12,$34,$56,$78    ; 12
    dc.b $12,$34,$56,$78    ; 16
    dc.b $12,$34,$56,$78    ; 20
    dc.b $12,$34,$56,$78    ; 24
    dc.b $12,$34,$56,$78    ; 28
 
; ===========================================================================
 
    if ~~removeJmpTos
JmpTo5_DisplaySprite3 
    jmp (DisplaySprite3).l
JmpTo45_DisplaySprite 
    jmp (DisplaySprite).l
JmpTo65_DeleteObject 
    jmp (DeleteObject).l
JmpTo19_SingleObjLoad 
    jmp (SingleObjLoad).l
JmpTo39_MarkObjGone 
    jmp (MarkObjGone).l
JmpTo6_DeleteObject2 
    jmp (DeleteObject2).l
JmpTo12_PlaySound 
    jmp (PlaySound).l
JmpTo25_SingleObjLoad2 
    jmp (SingleObjLoad2).l
JmpTo25_AnimateSprite 
    jmp (AnimateSprite).l
JmpTo_PlaySoundLocal 
    jmp (PlaySoundLocal).l
JmpTo6_RandomNumber 
    jmp (RandomNumber).l
JmpTo2_MarkObjGone_P1 
    jmp (MarkObjGone_P1).l
JmpTo_Pal_FadeToWhite_UpdateColour 
    jmp (Pal_FadeToWhite.UpdateColour).l
JmpTo_LoadTailsDynPLC_Part2 
    jmp (LoadTailsDynPLC_Part2).l
JmpTo_LoadSonicDynPLC_Part2 
    jmp (LoadSonicDynPLC_Part2).l
JmpTo8_MarkObjGone3 
    jmp (MarkObjGone3).l
JmpTo64_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
JmpTo5_PlayMusic 
    jmp (PlayMusic).l
JmpTo_Boss_LoadExplosion 
    jmp (Boss_LoadExplosion).l
JmpTo9_PlatformObject 
    jmp (PlatformObject).l
JmpTo27_SolidObject 
    jmp (SolidObject).l
JmpTo8_ObjectMoveAndFall 
    jmp (ObjectMoveAndFall).l
; loc_3EAC0:
JmpTo26_ObjectMove 
    jmp (ObjectMove).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 8A - Sonic Team Presents/Credits (leftover from S1) (seemingly unused)
; ----------------------------------------------------------------------------
; Sprite_3EAC8:
Obj8A: ; (screen-space obj)
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj8A_Index(pc,d0.w),d1
    jmp Obj8A_Index(pc,d1.w)
; ===========================================================================
; off_3EAD6:
Obj8A_Index:    offsetTable
        offsetTableEntry.w Obj8A_Init
        offsetTableEntry.w Obj8A_Display
; ===========================================================================
; loc_3EADA:
Obj8A_Init:
    addq.b  #2,routine(a0)
    move.w  #$120,x_pixel(a0)
    move.w  #$F0,y_pixel(a0)
    move.l  #Obj8A_MapUnc_3EB4E,mappings(a0)
    move.w  #make_art_tile($05A0,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo65_Adjust2PArtPointer
    move.w  (Ending_demo_number).w,d0
    move.b  d0,mapping_frame(a0)
    move.b  #0,render_flags(a0)
    move.b  #0,priority(a0)
    cmpi.b  #GameModeID_TitleScreen,(Game_Mode).w   ; title screen??
    bne.s   Obj8A_Display   ; if not, branch
    move.w  #make_art_tile($0300,0,0),art_tile(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo65_Adjust2PArtPointer
    move.b  #$A,mapping_frame(a0)
    tst.b   ($FFFFFFD3).w
    beq.s   Obj8A_Display
    cmpi.b  #button_down_mask|button_B_mask|button_C_mask|button_A_mask,(Ctrl_1_Held).w
    bne.s   Obj8A_Display
    move.w  #$EEE,(Target_palette_line3).w
    move.w  #$880,(Target_palette_line3+2).w
    jmp (DeleteObject).l
; ===========================================================================
; JmpTo46_DisplaySprite 
Obj8A_Display:
    jmp (DisplaySprite).l
; ===========================================================================
; ----------------------------------------------------------------------------
; sprite mappings (unused?)
; ----------------------------------------------------------------------------
Obj8A_MapUnc_3EB4E: BINCLUDE "mappings/sprite/obj8A.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo65_Adjust2PArtPointer 
    jmp (Adjust2PArtPointer).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ----------------------------------------------------------------------------
; Object 3E - Egg prison
; ----------------------------------------------------------------------------
; Sprite_3F1E4:
Obj3E:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj3E_Index(pc,d0.w),d1
    jmp Obj3E_Index(pc,d1.w)
; ===========================================================================
; off_3F1F2:
Obj3E_Index:    offsetTable
        offsetTableEntry.w loc_3F212    ;  0
        offsetTableEntry.w loc_3F278    ;  2
        offsetTableEntry.w loc_3F354    ;  4
        offsetTableEntry.w loc_3F38E    ;  6
        offsetTableEntry.w loc_3F3A8    ;  8
        offsetTableEntry.w loc_3F406    ; $A
; ----------------------------------------------------------------------------
; byte_3F1FE:
Obj3E_ObjLoadData:
    dc.b   0,  2,$20,  4,  0
    dc.b $28,  4,$10,  5,  4    ; 5
    dc.b $18,  6,  8,  3,  5    ; 10
    dc.b   0,  8,$20,  4,  0    ; 15
; ===========================================================================
 
loc_3F212:
    movea.l a0,a1
    lea objoff_38(a0),a3
    lea Obj3E_ObjLoadData(pc),a2
    moveq   #3,d1
    bra.s   loc_3F228
; ===========================================================================
 
loc_3F220:
    jsrto   (SingleObjLoad).l, JmpTo20_SingleObjLoad
    bne.s   loc_3F272
    move.w  a1,(a3)+
 
loc_3F228:
    _move.b id(a0),id(a1) ; load obj
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  y_pos(a0),objoff_30(a1)
    move.l  #Obj3E_MapUnc_3F436,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtNem_Capsule,1,0),art_tile(a1)
    move.b  #$84,render_flags(a1)
    moveq   #0,d0
    move.b  (a2)+,d0
    sub.w   d0,y_pos(a1)
    move.w  y_pos(a1),objoff_30(a1)
    move.b  (a2)+,routine(a1)
    move.b  (a2)+,width_pixels(a1)
    move.b  (a2)+,priority(a1)
    move.b  (a2)+,mapping_frame(a1)
 
loc_3F272:
    dbf d1,loc_3F220
    rts
; ===========================================================================
 
loc_3F278:
    moveq   #0,d0
    move.b  routine_secondary(a0),d0
    move.w  off_3F2AE(pc,d0.w),d1
    jsr off_3F2AE(pc,d1.w)
    move.w  #$2B,d1
    move.w  #$18,d2
    move.w  #$18,d3
    move.w  x_pos(a0),d4
    jsr (SolidObject).l
    lea (Ani_obj3E).l,a1
    jsr (AnimateSprite).l
    jmp (MarkObjGone).l
; ===========================================================================
off_3F2AE:  offsetTable
        offsetTableEntry.w loc_3F2B4    ; 0
        offsetTableEntry.w loc_3F2FC    ; 2
        offsetTableEntry.w return_3F352 ; 4
; ===========================================================================
 
loc_3F2B4:
    movea.w objoff_38(a0),a1 ; a1=object
    tst.w   objoff_32(a1)
    beq.s   ++  ; rts
    movea.w objoff_3A(a0),a2 ; a2=object
    jsr (SingleObjLoad).l
    bne.s   +
    _move.b #ObjID_Explosion,id(a1) ; load obj
    addq.b  #2,routine(a1)
    move.w  x_pos(a2),x_pos(a1)
    move.w  y_pos(a2),y_pos(a1)
+
    move.w  #-$400,y_vel(a2)
    move.w  #$800,x_vel(a2)
    addq.b  #2,routine_secondary(a2)
    move.w  #$1D,objoff_34(a0)
    addq.b  #2,routine_secondary(a0)
+
    rts
; ===========================================================================
 
loc_3F2FC:
    subq.w  #1,objoff_34(a0)
    bpl.s   return_3F352
    move.b  #1,anim(a0)
    moveq   #7,d6
    move.w  #$9A,d5
    moveq   #-$1C,d4
 
-   jsr (SingleObjLoad).l
    bne.s   +
    _move.b #ObjID_Animal,id(a1) ; load obj
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    add.w   d4,x_pos(a1)
    move.b  #1,objoff_38(a1)
    addq.w  #7,d4
    move.w  d5,objoff_36(a1)
    subq.w  #8,d5
    dbf d6,-
+
    movea.w objoff_3C(a0),a2 ; a2=object
    move.w  #$B4,anim_frame_duration(a2)
    addq.b  #2,routine_secondary(a2)
    addq.b  #2,routine_secondary(a0)
 
return_3F352:
    rts
; ===========================================================================
 
loc_3F354:
    move.w  #$1B,d1
    move.w  #8,d2
    move.w  #8,d3
    move.w  x_pos(a0),d4
    jsr (SolidObject).l
    move.w  objoff_30(a0),y_pos(a0)
    move.b  status(a0),d0
    andi.b  #standing_mask,d0
    beq.s   +
    addq.w  #8,y_pos(a0)
    clr.b   (Update_HUD_timer).w
    move.w  #1,objoff_32(a0)
+
    jmp (MarkObjGone).l
; ===========================================================================
 
loc_3F38E:
    tst.b   routine_secondary(a0)
    beq.s   +
    tst.b   render_flags(a0)
    bpl.w   JmpTo66_DeleteObject
    jsr (ObjectMoveAndFall).l
+
    jmp (MarkObjGone).l
 
    if removeJmpTos
JmpTo66_DeleteObject 
    jmp (DeleteObject).l
    endif
; ===========================================================================
 
loc_3F3A8:
    tst.b   routine_secondary(a0)
    beq.s   return_3F404
    move.b  (Vint_runcount+3).w,d0
    andi.b  #7,d0
    bne.s   loc_3F3F4
    jsr (SingleObjLoad).l
    bne.s   loc_3F3F4
    _move.b #ObjID_Animal,id(a1) ; load obj
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    jsr (RandomNumber).l
    andi.w  #$1F,d0
    subq.w  #6,d0
    tst.w   d1
    bpl.s   +
    neg.w   d0
+
    add.w   d0,x_pos(a1)
    move.b  #1,objoff_38(a1)
    move.w  #$C,objoff_36(a1)
 
loc_3F3F4:
    subq.w  #1,anim_frame_duration(a0)
    bne.s   return_3F404
    addq.b  #2,routine(a0)
    move.w  #$B4,anim_frame_duration(a0)
 
return_3F404:
    rts
; ===========================================================================
 
loc_3F406:
    moveq   #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d0
    moveq   #ObjID_Animal,d1
    lea (Dynamic_Object_RAM).w,a1
 
-   cmp.b   id(a1),d1
    beq.s   +   ; rts
    lea next_object(a1),a1 ; a1=object
    dbf d0,-
 
    jsr (Load_EndOfAct).l
    jmp (DeleteObject).l
; ===========================================================================
+   rts
; ===========================================================================
; animation script
; off_3F428:
Ani_obj3E:  offsetTable
        offsetTableEntry.w byte_3F42C   ; 0
        offsetTableEntry.w byte_3F42F   ; 1
byte_3F42C: dc.b  $F,  0,$FF
        rev02even
byte_3F42F: dc.b   3,  0,  1,  2,  3,$FE,  1
        even
; ----------------------------------------------------------------------------
; sprite mappings
; ----------------------------------------------------------------------------
Obj3E_MapUnc_3F436: BINCLUDE "mappings/sprite/obj3E.bin"
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo66_DeleteObject 
    jmp (DeleteObject).l
JmpTo20_SingleObjLoad 
    jmp (SingleObjLoad).l
 
    align 4
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Object touch response subroutine - $20(a0) in the object RAM
; collides Sonic with most objects (enemies, rings, monitors...) in the level
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_3F554:
TouchResponse:
    nop
    jsrto   (Touch_Rings).l, JmpTo_Touch_Rings
    ; Bumpers in CNZ
    cmpi.b  #casino_night_zone,(Current_Zone).w
    bne.s   +
    jsrto   (Check_CNZ_bumpers).l, JmpTo_Check_CNZ_bumpers
+
    tst.b   (Current_Boss_ID).w
    bne.w   Touch_Boss
    move.w  x_pos(a0),d2 ; load Sonic's position into d2,d3
    move.w  y_pos(a0),d3
    subi_.w #8,d2
    moveq   #0,d5
    move.b  y_radius(a0),d5
    subq.b  #3,d5
    sub.w   d5,d3
    cmpi.b  #$4D,mapping_frame(a0)  ; is Sonic ducking?
    bne.s   Touch_NoDuck        ; if not, branch
    addi.w  #$C,d3
    moveq   #$A,d5
; loc_3F592:
Touch_NoDuck:
    move.w  #$10,d4
    add.w   d5,d5
    lea (Dynamic_Object_RAM).w,a1
    move.w  #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d6
; loc_3F5A0:
Touch_Loop:
    move.b  collision_flags(a1),d0
    bne.w   Touch_Width
; loc_3F5A8:
Touch_NextObj:
    lea next_object(a1),a1 ; load obj address ; goto next object
    dbf d6,Touch_Loop ; repeat 6F more times
 
    moveq   #0,d0
    rts
; ===========================================================================
; loc_3F5B4: Touch_Height:
Touch_Width:
    andi.w  #$3F,d0
    add.w   d0,d0
    lea Touch_Sizes(pc,d0.w),a2
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  x_pos(a1),d0
    sub.w   d1,d0
    sub.w   d2,d0
    bcc.s   loc_3F5D6
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   Touch_Height
    bra.w   Touch_NextObj
; ===========================================================================
 
loc_3F5D6:
    cmp.w   d4,d0
    bhi.w   Touch_NextObj
; loc_3F5DC: Touch_Width:
Touch_Height:
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  y_pos(a1),d0
    sub.w   d1,d0
    sub.w   d3,d0
    bcc.s   loc_3F5F6
    add.w   d1,d1
    add.w   d1,d0
    bcs.w   Touch_ChkValue
    bra.w   Touch_NextObj
; ===========================================================================
 
loc_3F5F6:
    cmp.w   d5,d0
    bhi.w   Touch_NextObj
    bra.w   Touch_ChkValue
; ===========================================================================
; collision sizes (width,height)
; byte_3F600:
Touch_Sizes:
    dc.b   4,  4    ;   0
    dc.b $14,$14    ;   1
    dc.b  $C,$14    ;   2
    dc.b $14, $C    ;   3
    dc.b   4,$10    ;   4
    dc.b  $C,$12    ;   5
    dc.b $10,$10    ;   6 - monitors
    dc.b   6,  6    ;   7 - rings
    dc.b $18, $C    ;   8
    dc.b  $C,$10    ;   9
    dc.b $10,  8    ;  $A
    dc.b   8,  8    ;  $B
    dc.b $14,$10    ;  $C
    dc.b $14,  8    ;  $D
    dc.b  $E, $E    ;  $E
    dc.b $18,$18    ;  $F
    dc.b $28,$10    ; $10
    dc.b $10,$18    ; $11
    dc.b   8,$10    ; $12
    dc.b $20,$70    ; $13
    dc.b $40,$20    ; $14
    dc.b $80,$20    ; $15
    dc.b $20,$20    ; $16
    dc.b   8,  8    ; $17
    dc.b   4,  4    ; $18
    dc.b $20,  8    ; $19
    dc.b  $C, $C    ; $1A
    dc.b   8,  4    ; $1B
    dc.b $18,  4    ; $1C
    dc.b $28,  4    ; $1D
    dc.b   4,  8    ; $1E
    dc.b   4,$18    ; $1F
    dc.b   4,$28    ; $20
    dc.b   4,$10    ; $21
    dc.b $18,$18    ; $22
    dc.b  $C,$18    ; $23
    dc.b $48,  8    ; $24
    dc.b $18,$28    ; $25
    dc.b $10,  4    ; $26
    dc.b $20,  2    ; $27
    dc.b   4,$40    ; $28
    dc.b $18,$80    ; $29
    dc.b $20,$10    ; $2A
    dc.b $10,$20    ; $2B
    dc.b $10,$30    ; $2C
    dc.b $10,$40    ; $2D
    dc.b $10,$50    ; $2E
    dc.b $10,  2    ; $2F
    dc.b $10,  1    ; $30
    dc.b   2,  8    ; $31
    dc.b $20,$1C    ; $32
; ===========================================================================
; loc_3F666:
Touch_Boss:
    lea Touch_Sizes(pc),a3
    move.w  x_pos(a0),d2
    move.w  y_pos(a0),d3
    subi_.w #8,d2
    moveq   #0,d5
    move.b  y_radius(a0),d5
    subq.b  #3,d5
    sub.w   d5,d3
    cmpi.b  #$4D,mapping_frame(a0)
    bne.s   +
    addi.w  #$C,d3
    moveq   #$A,d5
+
    move.w  #$10,d4
    add.w   d5,d5
    lea (Dynamic_Object_RAM).w,a1
    move.w  #(Dynamic_Object_RAM_End-Dynamic_Object_RAM)/object_size-1,d6
 
loc_3F69C:
    move.b  collision_flags(a1),d0
    bne.s   loc_3F6AE
 
loc_3F6A2:
    lea next_object(a1),a1 ; a1=object
    dbf d6,loc_3F69C
 
    moveq   #0,d0
    rts
; ===========================================================================
 
loc_3F6AE:
    bsr.w   BossSpecificCollision
    andi.w  #$3F,d0
    beq.s   loc_3F6A2
    add.w   d0,d0
    lea (a3,d0.w),a2
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  x_pos(a1),d0
    sub.w   d1,d0
    sub.w   d2,d0
    bcc.s   loc_3F6D4
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   loc_3F6D8
    bra.s   loc_3F6A2
; ===========================================================================
 
loc_3F6D4:
    cmp.w   d4,d0
    bhi.s   loc_3F6A2
 
loc_3F6D8:
    moveq   #0,d1
    move.b  (a2)+,d1
    move.w  y_pos(a1),d0
    sub.w   d1,d0
    sub.w   d3,d0
    bcc.s   loc_3F6EE
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   Touch_ChkValue
    bra.s   loc_3F6A2
; ===========================================================================
 
loc_3F6EE:
    cmp.w   d5,d0
    bhi.s   loc_3F6A2
; loc_3F6F2:
Touch_ChkValue:
    move.b  collision_flags(a1),d1  ; load touch response number
    andi.b  #$C0,d1         ; is touch response $40 or higher?
    beq.w   Touch_Enemy     ; if not, branch
    cmpi.b  #$C0,d1         ; is touch response $C0 or higher?
    beq.w   Touch_Special       ; if yes, branch
    tst.b   d1          ; is touch response $80-$BF ?
    bmi.w   Touch_ChkHurt       ; if yes, branch
    ; touch response is $40-$7F
    move.b  collision_flags(a1),d0
    andi.b  #$3F,d0
    cmpi.b  #6,d0           ; is touch response $46 ?
    beq.s   Touch_Monitor       ; if yes, branch
    move.w  (MainCharacter+invulnerable_time).w,d0
    tst.w   (Two_player_mode).w
    beq.s   +
    move.w  invulnerable_time(a0),d0
+
    cmpi.w  #90,d0
    bhs.w   +
    move.b  #4,routine(a1)  ; set the object's routine counter
    move.w  a0,parent(a1)
+
    rts
; ===========================================================================
; loc_3F73C:
Touch_Monitor:
    tst.w   y_vel(a0)   ; is Sonic moving upwards?
    bpl.s   loc_3F768   ; if not, branch
    move.w  y_pos(a0),d0
    subi.w  #$10,d0
    cmp.w   y_pos(a1),d0
    blo.s   return_3F78A
    neg.w   y_vel(a0)   ; reverse Sonic's y-motion
    move.w  #-$180,y_vel(a1)
    tst.b   routine_secondary(a1)
    bne.s   return_3F78A
    move.b  #4,routine_secondary(a1) ; set the monitor's routine counter
    rts
; ===========================================================================
 
loc_3F768:
    cmpa.w  #MainCharacter,a0
    beq.s   +
    tst.w   (Two_player_mode).w
    beq.s   return_3F78A
+
    cmpi.b  #AniIDSonAni_Roll,anim(a0)
    bne.s   return_3F78A
    neg.w   y_vel(a0)   ; reverse Sonic's y-motion
    move.b  #4,routine(a1)
    move.w  a0,parent(a1)
 
return_3F78A:
    rts
; ===========================================================================
; loc_3F78C:
Touch_Enemy:
    btst    #status_sec_isInvincible,status_secondary(a0)   ; is Sonic invincible?
    bne.s   +           ; if yes, branch
    cmpi.b  #AniIDSonAni_Spindash,anim(a0)
    beq.s   +
    cmpi.b  #AniIDSonAni_Roll,anim(a0)      ; is Sonic rolling?
    bne.w   Touch_ChkHurt       ; if not, branch
+
    btst    #6,render_flags(a1)
    beq.s   Touch_Enemy_Part2
    tst.b   boss_hitcount2(a1)
    beq.s   return_3F7C6
    neg.w   x_vel(a0)
    neg.w   y_vel(a0)
    move.b  #0,collision_flags(a1)
    subq.b  #1,boss_hitcount2(a1)
 
return_3F7C6:
    rts
; ---------------------------------------------------------------------------
; loc_3F7C8:
Touch_Enemy_Part2:
    tst.b   collision_property(a1)
    beq.s   Touch_KillEnemy
    neg.w   x_vel(a0)
    neg.w   y_vel(a0)
    move.b  #0,collision_flags(a1)
    subq.b  #1,collision_property(a1)
    bne.s   return_3F7E8
    bset    #7,status(a1)
 
return_3F7E8:
    rts
; ===========================================================================
; loc_3F7EA:
Touch_KillEnemy:
    bset    #7,status(a1)
    moveq   #0,d0
    move.w  (Chain_Bonus_counter).w,d0
    addq.w  #2,(Chain_Bonus_counter).w  ; add 2 to chain bonus counter
    cmpi.w  #6,d0
    blo.s   loc_3F802
    moveq   #6,d0
 
loc_3F802:
    move.w  d0,objoff_3E(a1)
    move.w  Enemy_Points(pc,d0.w),d0
    cmpi.w  #$20,(Chain_Bonus_counter).w    ; have 16 enemies been destroyed?
    blo.s   loc_3F81C           ; if not, branch
    move.w  #1000,d0            ; fix bonus to 10000 points
    move.w  #$A,objoff_3E(a1)
 
loc_3F81C:
    movea.w a0,a3
    bsr.w   AddPoints2
    _move.b #ObjID_Explosion,id(a1) ; load obj
    move.b  #0,routine(a1)
    tst.w   y_vel(a0)
    bmi.s   loc_3F844
    move.w  y_pos(a0),d0
    cmp.w   y_pos(a1),d0
    bhs.s   loc_3F84C
    neg.w   y_vel(a0)
    rts
; ===========================================================================
 
loc_3F844:
    addi.w  #$100,y_vel(a0)
    rts
; ===========================================================================
 
loc_3F84C:
    subi.w  #$100,y_vel(a0)
    rts
; ===========================================================================
; byte_3F854:
Enemy_Points:   dc.w 10, 20, 50, 100
; ===========================================================================
 
loc_3F85C:
    bset    #7,status(a1)
 
; ---------------------------------------------------------------------------
; Subroutine for checking if Sonic/Tails should be hurt and hurting them if so
; note: sonic or tails must be at a0
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_3F862:
Touch_ChkHurt:
    btst    #status_sec_isInvincible,status_secondary(a0)   ; is Sonic invincible?
    beq.s   Touch_Hurt      ; if not, branch
; loc_3F86A:
Touch_NoHurt:
    moveq   #-1,d0
    rts
; ---------------------------------------------------------------------------
; loc_3F86E:
Touch_Hurt:
    nop
    tst.w   invulnerable_time(a0)
    bne.s   Touch_NoHurt
    movea.l a1,a2
 
; End of function TouchResponse
; continue straight to HurtCharacter
 
; ---------------------------------------------------------------------------
; Hurting Sonic/Tails subroutine
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_3F878: HurtSonic:
HurtCharacter:
    move.w  (Ring_count).w,d0
    cmpa.w  #MainCharacter,a0
    beq.s   loc_3F88C
    tst.w   (Two_player_mode).w
    beq.s   Hurt_Sidekick
    move.w  (Ring_count_2P).w,d0
 
loc_3F88C:
    btst    #status_sec_hasShield,status_secondary(a0)
    bne.s   Hurt_Shield
    tst.w   d0
    beq.w   KillCharacter
    jsr (SingleObjLoad).l
    bne.s   Hurt_Shield
    _move.b #ObjID_LostRings,id(a1) ; load obj
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    move.w  a0,parent(a1)
 
; loc_3F8B8:
Hurt_Shield:
    bclr    #status_sec_hasShield,status_secondary(a0) ; remove shield
 
; loc_3F8BE:
Hurt_Sidekick:
    move.b  #4,routine(a0)
    jsrto   (Sonic_ResetOnFloor_Part2).l, JmpTo_Sonic_ResetOnFloor_Part2
    bset    #1,status(a0)
    move.w  #-$400,y_vel(a0) ; make Sonic bounce away from the object
    move.w  #-$200,x_vel(a0)
    btst    #6,status(a0)   ; underwater?
    beq.s   Hurt_Reverse    ; if not, branch
    move.w  #-$200,y_vel(a0) ; bounce slower
    move.w  #-$100,x_vel(a0)
 
; loc_3F8EE:
Hurt_Reverse:
    move.w  x_pos(a0),d0
    cmp.w   x_pos(a2),d0
    blo.s   Hurt_ChkSpikes  ; if Sonic is left of the object, branch
    neg.w   x_vel(a0)   ; if Sonic is right of the object, reverse
 
; loc_3F8FC:
Hurt_ChkSpikes:
    move.w  #0,inertia(a0)
    move.b  #AniIDSonAni_Hurt2,anim(a0)
    move.w  #$78,invulnerable_time(a0)
    move.w  #SndID_Hurt,d0  ; load normal damage sound
    cmpi.b  #ObjID_Spikes,(a2)  ; was damage caused by spikes?
    bne.s   Hurt_Sound  ; if not, branch
    move.w  #SndID_HurtBySpikes,d0  ; load spikes damage sound
 
; loc_3F91C:
Hurt_Sound:
    jsr (PlaySound).l
    moveq   #-1,d0
    rts
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Subroutine to kill Sonic or Tails
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_3F926: KillSonic:
KillCharacter:
    tst.w   (Debug_placement_mode).w
    bne.s   ++
    clr.b   status_secondary(a0)
    move.b  #6,routine(a0)
    jsrto   (Sonic_ResetOnFloor_Part2).l, JmpTo_Sonic_ResetOnFloor_Part2
    bset    #1,status(a0)
    move.w  #-$700,y_vel(a0)
    move.w  #0,x_vel(a0)
    move.w  #0,inertia(a0)
    move.b  #AniIDSonAni_Death,anim(a0)
    bset    #high_priority_bit,art_tile(a0)
    move.w  #SndID_Hurt,d0
    cmpi.b  #ObjID_Spikes,id(a2)
    bne.s   +
    move.w  #SndID_HurtBySpikes,d0
+
    jsr (PlaySound).l
+
    moveq   #-1,d0
    rts
; ===========================================================================
;loc_3F976:
Touch_Special:
    move.b  collision_flags(a1),d1
    andi.b  #$3F,d1
    cmpi.b  #6,d1
    beq.s   loc_3FA00
    cmpi.b  #7,d1
    beq.w   loc_3FA18
    cmpi.b  #$B,d1
    beq.s   BranchTo_loc_3F85C
    cmpi.b  #$A,d1
    beq.s   loc_3FA00
    cmpi.b  #$C,d1
    beq.s   loc_3F9CE
    cmpi.b  #$14,d1
    beq.s   loc_3FA00
    cmpi.b  #$15,d1
    beq.s   loc_3FA00
    cmpi.b  #$16,d1
    beq.s   loc_3FA00
    cmpi.b  #$17,d1
    beq.s   loc_3FA00
    cmpi.b  #$18,d1
    beq.s   loc_3FA00
    cmpi.b  #$1A,d1
    beq.s   loc_3FA22
    cmpi.b  #$21,d1
    beq.s   loc_3FA12
    rts
; ===========================================================================
 
BranchTo_loc_3F85C 
    bra.w   loc_3F85C
; ===========================================================================
 
loc_3F9CE:
    sub.w   d0,d5
    cmpi.w  #8,d5
    bhs.s   BranchTo_Touch_Enemy
    move.w  x_pos(a1),d0
    subq.w  #4,d0
    btst    #0,status(a1)
    beq.s   loc_3F9E8
    subi.w  #$10,d0
 
loc_3F9E8:
    sub.w   d2,d0
    bcc.s   loc_3F9F4
    addi.w  #$18,d0
    bcs.s   BranchTo_Touch_ChkHurt
    bra.s   BranchTo_Touch_Enemy
; ===========================================================================
 
loc_3F9F4:
    cmp.w   d4,d0
    bhi.s   BranchTo_Touch_Enemy
 
BranchTo_Touch_ChkHurt 
    bra.w   Touch_ChkHurt
; ===========================================================================
 
BranchTo_Touch_Enemy 
    bra.w   Touch_Enemy
; ===========================================================================
 
loc_3FA00:
    move.w  a0,d1
    subi.w  #Object_RAM,d1
    beq.s   +
    addq.b  #1,collision_property(a1)
+
    addq.b  #1,collision_property(a1)
    rts
; ===========================================================================
 
loc_3FA12:
    addq.b  #1,collision_property(a1)
    rts
; ===========================================================================
 
loc_3FA18:
    move.b  #2,collision_property(a1)
    bra.w   Touch_Enemy
; ===========================================================================
 
loc_3FA22:
    move.b  #-1,collision_property(a1)
    bra.w   Touch_Enemy
; ===========================================================================
; loc_3FA2C:
BossSpecificCollision:
    cmpi.b  #$F,d0
    bne.s   +   ; rts
    moveq   #0,d0
    move.b  (Current_Boss_ID).w,d0
    beq.s   +   ; rts
    subq.w  #1,d0
    add.w   d0,d0
    move.w  BossCollision_Index(pc,d0.w),d0
    jmp BossCollision_Index(pc,d0.w)
; ===========================================================================
+   rts
; ===========================================================================
; off_3FA48:
BossCollision_Index:offsetTable ; jump depending on boss ID
    offsetTableEntry.w BossCollision_EHZ_CPZ
    offsetTableEntry.w BossCollision_EHZ_CPZ
    offsetTableEntry.w BossCollision_HTZ
    offsetTableEntry.w BossCollision_ARZ
    offsetTableEntry.w BossCollision_MCZ
    offsetTableEntry.w BossCollision_CNZ
    offsetTableEntry.w BossCollision_MTZ
    offsetTableEntry.w BossCollision_OOZ
    offsetTableEntry.w return_3FA5E
; ===========================================================================
;loc_3FA5A:
BossCollision_EHZ_CPZ:
    move.b  collision_flags(a1),d0
 
return_3FA5E:
    rts
; ===========================================================================
;loc_3FA60:
BossCollision_HTZ:
    tst.b   (Boss_CollisionRoutine).w
    bne.s   +
    rts
; ---------------------------------------------------------------------------
+
    move.w  d7,-(sp)
    moveq   #0,d1
    move.b  objoff_15(a1),d1
    subq.b  #2,d1
    cmpi.b  #7,d1
    bgt.s   loc_3FAA8
    move.w  d1,d7
    add.w   d7,d7
    move.w  x_pos(a1),d0
    btst    #0,render_flags(a1)
    beq.s   loc_3FA8E
    add.w   word_3FAB0(pc,d7.w),d0
    bra.s   loc_3FA92
; ===========================================================================
 
loc_3FA8E:
    sub.w   word_3FAB0(pc,d7.w),d0
 
loc_3FA92:
    move.b  byte_3FAC0(pc,d1.w),d1
    ori.l   #$40000,d1
    move.w  y_pos(a1),d7
    subi.w  #$1C,d7
    bsr.w   Boss_DoCollision
 
loc_3FAA8:
    move.w  (sp)+,d7
    move.b  collision_flags(a1),d0
    rts
; ===========================================================================
word_3FAB0:
    dc.w   $1C
    dc.w   $20  ; 1
    dc.w   $28  ; 2
    dc.w   $34  ; 3
    dc.w   $3C  ; 4
    dc.w   $44  ; 5
    dc.w   $60  ; 6
    dc.w   $70  ; 7
byte_3FAC0:
    dc.b   4
    dc.b   4    ; 1
    dc.b   8    ; 2
    dc.b  $C    ; 3
    dc.b $14    ; 4
    dc.b $1C    ; 5
    dc.b $24    ; 6
    dc.b   8    ; 7
; ===========================================================================
;loc_3FAC8:
BossCollision_ARZ:
    move.w  d7,-(sp)
    move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    tst.b   (Boss_CollisionRoutine).w
    beq.s   ++
    addi_.w #4,d7
    subi.w  #$50,d0
    btst    #0,render_flags(a1)
    beq.s   +
    addi.w  #$A0,d0
+
    move.l  #$140010,d1
    bsr.w   Boss_DoCollision
+
    move.w  (sp)+,d7
    move.b  collision_flags(a1),d0
    rts
; ===========================================================================
;loc_3FAFE:
BossCollision_MCZ:
    sf  boss_hurt_sonic(a1)
    cmpi.b  #1,(Boss_CollisionRoutine).w
    blt.s   BossCollision_MCZ2
; Boss_CollisionRoutine = 1, i.e. diggers pointing to the side
    move.w  d7,-(sp)
    move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    addi_.w #4,d7
    subi.w  #$30,d0
    btst    #0,render_flags(a1) ; left or right?
    beq.s   +
    addi.w  #$60,d0         ; x+$30, otherwise x-$30
+
    move.l  #$40004,d1      ; heigth 4, width 4
    bsr.w   Boss_DoCollision
    move.w  (sp)+,d7
    move.b  collision_flags(a1),d0
    cmpi.w  #$78,invulnerable_time(a0)
    bne.s   +   ; rts
    st  boss_hurt_sonic(a1) ; sonic has just been hurt flag
+
    rts
; ===========================================================================
; Boss_CollisionRoutine = 0, i.e. diggers pointing towards top
;loc_3FB46:
BossCollision_MCZ2:
    move.w  d7,-(sp)
    movea.w #$14,a5
    movea.w #0,a4
 
-   move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    subi.w  #$20,d7
    add.w   a5,d0           ; first check x+$14, second x-$14
    move.l  #$100004,d1     ; heigth $10, width 4
    bsr.w   Boss_DoCollision
    movea.w #-$14,a5
    adda_.w #1,a4
    cmpa.w  #1,a4
    beq.s   -           ; jump back once for second check
    move.w  (sp)+,d7
    move.b  collision_flags(a1),d0
    cmpi.w  #$78,invulnerable_time(a0)
    bne.s   +   ; rts
    st  boss_hurt_sonic(a1) ; sonic has just been hurt flag
+
    rts
; ===========================================================================
;loc_3FB8A:
BossCollision_CNZ:
    tst.b   (Boss_CollisionRoutine).w
    beq.s   ++
    move.w  d7,-(sp)
    move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    addi.w  #$28,d7
    move.l  #$80010,d1
    cmpi.b  #1,(Boss_CollisionRoutine).w
    beq.s   +
    move.w  #$20,d1
    subi_.w #8,d7
    addi_.w #4,d0
+
    bsr.w   Boss_DoCollision
    move.w  (sp)+,d7
+
    move.b  collision_flags(a1),d0
    rts
; ===========================================================================
;loc_3FBC4:
BossCollision_MTZ:
    move.b  collision_flags(a1),d0
    rts
; ===========================================================================
;loc_3FBCA:
BossCollision_OOZ:
    cmpi.b  #1,(Boss_CollisionRoutine).w
    blt.s   loc_3FC46
    beq.s   loc_3FC1C
    move.w  d7,-(sp)
    move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    moveq   #0,d1
    move.b  mainspr_mapframe(a1),d1
    subq.b  #2,d1
    add.w   d1,d1
    btst    #0,render_flags(a1)
    beq.s   loc_3FBF6
    add.w   word_3FC10(pc,d1.w),d0
    bra.s   loc_3FBFA
; ===========================================================================
 
loc_3FBF6:
    sub.w   word_3FC10(pc,d1.w),d0
 
loc_3FBFA:
    sub.w   word_3FC10+2(pc,d1.w),d7
    move.l  #$60008,d1
    bsr.w   Boss_DoCollision
    move.w  (sp)+,d7
    move.w  #0,d0
    rts
; ===========================================================================
word_3FC10:
    dc.w   $14,    0
    dc.w   $10,  $10
    dc.w   $10, -$10
; ===========================================================================
 
loc_3FC1C:
    move.w  d7,-(sp)
    move.w  x_pos(a1),d0
    move.w  y_pos(a1),d7
    moveq   #$10,d1
    btst    #0,render_flags(a1)
    beq.s   +
    neg.w   d1
+
    sub.w   d1,d0
    move.l  #$8000C,d1
    bsr.w   loc_3FC7A
    move.w  (sp)+,d7
    move.b  #0,d0
    rts
; ===========================================================================
 
loc_3FC46:
    move.b  collision_flags(a1),d0
    rts
; ===========================================================================
;loc_3FC4C:
    ; d7 = y_boss, d3 = y_sonic, d1 (high word) = heigth
    ; d0 = x_boss, d2 = x_sonic, d1 (low word)  = width
Boss_DoCollision:
    sub.w   d1,d0
    sub.w   d2,d0
    bcc.s   loc_3FC5A
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   loc_3FC5E
 
return_3FC58:
    rts
; ===========================================================================
 
loc_3FC5A:
    cmp.w   d4,d0
    bhi.s   return_3FC58
 
loc_3FC5E:
    swap    d1
    sub.w   d1,d7
    sub.w   d3,d7
    bcc.s   loc_3FC70
    add.w   d1,d1
    add.w   d1,d7
    bcs.w   Touch_ChkHurt
    bra.s   return_3FC58
; ===========================================================================
 
loc_3FC70:
    cmp.w   d5,d7
    bhi.w   return_3FC58
    bra.w   Touch_ChkHurt
; ===========================================================================
 
loc_3FC7A:
    sub.w   d1,d0
    sub.w   d2,d0
    bcc.s   loc_3FC88
    add.w   d1,d1
    add.w   d1,d0
    bcs.s   loc_3FC8C
 
return_3FC86:
    rts
; ===========================================================================
 
loc_3FC88:
    cmp.w   d4,d0
    bhi.s   return_3FC86
 
loc_3FC8C:
    swap    d1
    sub.w   d1,d7
    sub.w   d3,d7
    bcc.s   loc_3FC9E
    add.w   d1,d1
    add.w   d1,d7
    bcs.w   loc_3FCA4
    bra.s   return_3FC86
; ===========================================================================
 
loc_3FC9E:
    cmp.w   d5,d7
    bhi.w   return_3FC86
 
loc_3FCA4:
    neg.w   x_vel(a0)
    neg.w   y_vel(a0)
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo_Sonic_ResetOnFloor_Part2 
    jmp (Sonic_ResetOnFloor_Part2).l
JmpTo_Check_CNZ_bumpers
    jmp (Check_CNZ_bumpers).l
JmpTo_Touch_Rings 
    jmp (Touch_Rings).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
;loc_3FCC4:
AniArt_Load:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  PLC_DYNANM+2(pc,d0.w),d1
    lea PLC_DYNANM(pc,d1.w),a2
    move.w  PLC_DYNANM(pc,d0.w),d0
    jmp PLC_DYNANM(pc,d0.w)
; ===========================================================================
    rts
; ===========================================================================
 
 
 
 
; ---------------------------------------------------------------------------
; ZONE ANIMATION PROCEDURES AND SCRIPTS
;
; Each zone gets two entries in this jump table. The first entry points to the
; zone's animation procedure (usually Dynamic_Normal, but some zones have special
; procedures for complicated animations). The second points to the zone's animation
; script.
;
; Note that Animated_Null is not a valid animation script, so don't pair it up
; with anything except Dynamic_Null, or bad things will happen (for example, a bus error exception).
; ---------------------------------------------------------------------------
PLC_DYNANM: zoneOrderedOffsetTable 2,2      ; Zone ID
    zoneOffsetTableEntry.w Dynamic_Normal   ; $00
    zoneOffsetTableEntry.w Animated_EHZ
 
    zoneOffsetTableEntry.w Dynamic_Null ; $01
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_Null ; $02
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_Null ; $03
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $04
    zoneOffsetTableEntry.w Animated_MTZ
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $05
    zoneOffsetTableEntry.w Animated_MTZ
 
    zoneOffsetTableEntry.w Dynamic_Null ; $06
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_HTZ  ; $07
    zoneOffsetTableEntry.w Animated_HTZ
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $08
    zoneOffsetTableEntry.w Animated_HPZ
 
    zoneOffsetTableEntry.w Dynamic_Null ; $09
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $0A
    zoneOffsetTableEntry.w Animated_OOZ
 
    zoneOffsetTableEntry.w Dynamic_Null ; $0B
    zoneOffsetTableEntry.w Animated_Null
 
    zoneOffsetTableEntry.w Dynamic_CNZ  ; $0C
    zoneOffsetTableEntry.w Animated_CNZ
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $0D
    zoneOffsetTableEntry.w Animated_CPZ
 
    zoneOffsetTableEntry.w Dynamic_Normal   ; $0E
    zoneOffsetTableEntry.w Animated_DEZ
 
    zoneOffsetTableEntry.w Dynamic_ARZ  ; $0F
    zoneOffsetTableEntry.w Animated_ARZ
 
    zoneOffsetTableEntry.w Dynamic_Null ; $10
    zoneOffsetTableEntry.w Animated_Null
    zoneTableEnd
; ===========================================================================
 
Dynamic_Null:
    rts
; ===========================================================================
 
Dynamic_HTZ:
    tst.w   (Two_player_mode).w
    bne.w   Dynamic_Normal
    lea (Anim_Counters).w,a3
    moveq   #0,d0
    move.w  (Camera_X_pos).w,d1
    neg.w   d1
    asr.w   #3,d1
    move.w  (Camera_X_pos).w,d0
    lsr.w   #4,d0
    add.w   d1,d0
    subi.w  #$10,d0
    divu.w  #$30,d0
    swap    d0
    cmp.b   1(a3),d0
    beq.s   BranchTo_loc_3FE5C
    move.b  d0,1(a3)
    move.w  d0,d2
    andi.w  #7,d0
    add.w   d0,d0
    add.w   d0,d0
    add.w   d0,d0
    move.w  d0,d1
    add.w   d0,d0
    add.w   d1,d0
    andi.w  #$38,d2
    lsr.w   #2,d2
    add.w   d2,d0
    lea word_3FD9C(pc,d0.w),a4
    moveq   #5,d5
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_HTZMountains),d4
 
loc_3FD7C:
    moveq   #-1,d1
    move.w  (a4)+,d1
    andi.l  #$FFFFFF,d1
    move.w  d4,d2
    moveq   #$40,d3
    jsr (QueueDMATransfer).l
    addi.w  #$80,d4
    dbf d5,loc_3FD7C
 
BranchTo_loc_3FE5C 
    bra.w   loc_3FE5C
; ===========================================================================
; HTZ mountain art main RAM addresses?
word_3FD9C:
    dc.w   $80, $180, $280, $580, $600, $700    ; 6
    dc.w   $80, $180, $280, $580, $600, $700    ; 12
    dc.w  $980, $A80, $B80, $C80, $D00, $D80    ; 18
    dc.w  $980, $A80, $B80, $C80, $D00, $D80    ; 24
    dc.w  $E80,$1180,$1200,$1280,$1300,$1380    ; 30
    dc.w  $E80,$1180,$1200,$1280,$1300,$1380    ; 36
    dc.w $1400,$1480,$1500,$1580,$1600,$1900    ; 42
    dc.w $1400,$1480,$1500,$1580,$1600,$1900    ; 48
    dc.w $1D00,$1D80,$1E00,$1F80,$2400,$2580    ; 54
    dc.w $1D00,$1D80,$1E00,$1F80,$2400,$2580    ; 60
    dc.w $2600,$2680,$2780,$2B00,$2F00,$3280    ; 66
    dc.w $2600,$2680,$2780,$2B00,$2F00,$3280    ; 72
    dc.w $3600,$3680,$3780,$3C80,$3D00,$3F00    ; 78
    dc.w $3600,$3680,$3780,$3C80,$3D00,$3F00    ; 84
    dc.w $3F80,$4080,$4480,$4580,$4880,$4900    ; 90
    dc.w $3F80,$4080,$4480,$4580,$4880,$4900    ; 96
; ===========================================================================
 
loc_3FE5C:
    lea (TempArray_LayerDef).w,a1
    move.w  (Camera_X_pos).w,d2
    neg.w   d2
    asr.w   #3,d2
    move.l  a2,-(sp)
    lea (ArtUnc_HTZClouds).l,a0
    lea (Chunk_Table+$7C00).l,a2
    moveq   #$F,d1
 
loc_3FE78:
    move.w  (a1)+,d0
    neg.w   d0
    add.w   d2,d0
    andi.w  #$1F,d0
    lsr.w   #1,d0
    bcc.s   loc_3FE8A
    addi.w  #$200,d0
 
loc_3FE8A:
    lea (a0,d0.w),a4
    lsr.w   #1,d0
    bcs.s   loc_3FEB4
    move.l  (a4)+,(a2)+
    adda.w  #$3C,a2
    move.l  (a4)+,(a2)+
    adda.w  #$3C,a2
    move.l  (a4)+,(a2)+
    adda.w  #$3C,a2
    move.l  (a4)+,(a2)+
    suba.w  #$C0,a2
    adda.w  #$20,a0
    dbf d1,loc_3FE78
    bra.s   loc_3FEEC
; ===========================================================================
 
loc_3FEB4:
    rept 3
      rept 4
    move.b  (a4)+,(a2)+
      endm
    adda.w  #$3C,a2
    endm
    rept 4
    move.b  (a4)+,(a2)+
    endm
    suba.w  #$C0,a2
    adda.w  #$20,a0
    dbf d1,loc_3FE78
 
loc_3FEEC:
    move.l  #(Chunk_Table+$7C00) & $FFFFFF,d1
    move.w  #tiles_to_bytes(ArtTile_ArtUnc_HTZClouds),d2
    move.w  #$80,d3
    jsr (QueueDMATransfer).l
    movea.l (sp)+,a2
    addq.w  #2,a3
    bra.w   loc_3FF30
; ===========================================================================
 
Dynamic_CNZ:
    tst.b   (Current_Boss_ID).w
    beq.s   +
    rts
; ---------------------------------------------------------------------------
+
    lea (Animated_CNZ).l,a2
    tst.w   (Two_player_mode).w
    beq.s   Dynamic_Normal
    lea (Animated_CNZ_2P).l,a2
    bra.s   Dynamic_Normal
; ===========================================================================
 
Dynamic_ARZ:
    tst.b   (Current_Boss_ID).w
    beq.s   Dynamic_Normal
    rts
; ===========================================================================
 
Dynamic_Normal:
    lea (Anim_Counters).w,a3
 
loc_3FF30:
    move.w  (a2)+,d6    ; Get number of scripts in list
    ; S&K checks for empty lists, here
;   bpl.s   .listnotempty   ; If there are any, continue
;   rts
;.listnotempty:
 
; loc_3FF32:
.loop:
    subq.b  #1,(a3)     ; Tick down frame duration
    bcc.s   .nextscript ; If frame isn't over, move on to next script
 
;.nextframe:
    moveq   #0,d0
    move.b  1(a3),d0    ; Get current frame
    cmp.b   6(a2),d0    ; Have we processed the last frame in the script?
    blo.s   .notlastframe
    moveq   #0,d0       ; If so, reset to first frame
    move.b  d0,1(a3)    ; ''
; loc_3FF48:
.notlastframe:
    addq.b  #1,1(a3)    ; Consider this frame processed; set counter to next frame
    move.b  (a2),(a3)   ; Set frame duration to global duration value
    bpl.s   .globalduration
    ; If script uses per-frame durations, use those instead
    add.w   d0,d0
    move.b  9(a2,d0.w),(a3) ; Set frame duration to current frame's duration value
; loc_3FF56:
.globalduration:
; Prepare for DMA transfer
    ; Get relative address of frame's art
    move.b  8(a2,d0.w),d0   ; Get tile ID
    lsl.w   #5,d0       ; Turn it into an offset
    ; Get VRAM destination address
    move.w  4(a2),d2
    ; Get ROM source address
    move.l  (a2),d1     ; Get start address of animated tile art
    andi.l  #$FFFFFF,d1
    add.l   d0,d1       ; Offset into art, to get the address of new frame
    ; Get size of art to be transferred 
    moveq   #0,d3
    move.b  7(a2),d3
    lsl.w   #4,d3       ; Turn it into actual size (in words)
    ; Use d1, d2 and d3 to queue art for transfer
    jsr (QueueDMATransfer).l
; loc_3FF78:
.nextscript:
    move.b  6(a2),d0    ; Get total size of frame data
    tst.b   (a2)        ; Is per-frame duration data present?
    bpl.s   .globalduration2; If not, keep the current size; it's correct
    add.b   d0,d0       ; Double size to account for the additional frame duration data
; loc_3FF82:
.globalduration2:
    addq.b  #1,d0
    andi.w  #$FE,d0     ; Round to next even address, if it isn't already
    lea 8(a2,d0.w),a2   ; Advance to next script in list
    addq.w  #2,a3       ; Advance to next script's slot in a3 (usually Anim_Counters)
    dbf d6,.loop
    rts
; ===========================================================================
; ZONE ANIMATION SCRIPTS
;
; The Dynamic_Normal subroutine uses these scripts to reload certain tiles,
; thus animating them. All the relevant art must be uncompressed, because
; otherwise the subroutine would spend so much time waiting for the art to be
; decompressed that the VBLANK window would close before all the animating was done.
 
;    zoneanimdecl -1, ArtUnc_Flowers1, ArtTile_ArtUnc_Flowers1, 6, 2
;   -1          Global frame duration. If -1, then each frame will use its own duration, instead
;   ArtUnc_Flowers1     Source address
;   ArtTile_ArtUnc_Flowers1 Destination VRAM address
;   6           Number of frames
;   2           Number of tiles to load into VRAM for each frame
 
;    dc.b   0,$7F       ; Start of the script proper
;   0           Tile ID of first tile in ArtUnc_Flowers1 to transfer
;   $7F         Frame duration. Only here if global duration is -1
 
; loc_3FF94:
Animated_EHZ:   zoneanimstart
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers1, ArtTile_ArtUnc_Flowers1, 6, 2
    dc.b   0,$7F        ; Start of the script proper
    dc.b   2,$13
    dc.b   0,  7
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2,  7
    even
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers2, ArtTile_ArtUnc_Flowers2, 8, 2
    dc.b   2,$7F
    dc.b   0, $B
    dc.b   2, $B
    dc.b   0, $B
    dc.b   2,  5
    dc.b   0,  5
    dc.b   2,  5
    dc.b   0,  5
    even
    ; Flowers
    zoneanimdecl 7, ArtUnc_Flowers3, ArtTile_ArtUnc_Flowers3, 2, 2
    dc.b   0
    dc.b   2
    even
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers4, ArtTile_ArtUnc_Flowers4, 8, 2
    dc.b   0,$7F
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2, $B
    dc.b   0, $B
    dc.b   2, $B
    even
    ; Pulsing thing against checkered background
    zoneanimdecl -1, ArtUnc_EHZPulseBall, ArtTile_ArtUnc_EHZPulseBall, 6, 2
    dc.b   0,$17
    dc.b   2,  9
    dc.b   4, $B
    dc.b   6,$17
    dc.b   4, $B
    dc.b   2,  9
    even
 
    zoneanimend
 
Animated_MTZ:   zoneanimstart
    ; Spinning metal cylinder
    zoneanimdecl 0, ArtUnc_MTZCylinder, ArtTile_ArtUnc_MTZCylinder, 8,$10
    dc.b   0
    dc.b $10
    dc.b $20
    dc.b $30
    dc.b $40
    dc.b $50
    dc.b $60
    dc.b $70
    even
    ; lava
    zoneanimdecl $D, ArtUnc_Lava, ArtTile_ArtUnc_Lava, 6,$C
    dc.b   0
    dc.b  $C
    dc.b $18
    dc.b $24
    dc.b $18
    dc.b  $C
    even
    ; MTZ background animated section
    zoneanimdecl -1, ArtUnc_MTZAnimBack, ArtTile_ArtUnc_MTZAnimBack_1, 4, 6
    dc.b   0,$13
    dc.b   6,  7
    dc.b  $C,$13
    dc.b   6,  7
    even
    ; MTZ background animated section
    zoneanimdecl -1, ArtUnc_MTZAnimBack, ArtTile_ArtUnc_MTZAnimBack_2, 4, 6
    dc.b  $C,$13
    dc.b   6,  7
    dc.b   0,$13
    dc.b   6,  7
    even
 
    zoneanimend
 
Animated_HTZ:   zoneanimstart
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers1, ArtTile_ArtUnc_Flowers1, 6, 2
    dc.b   0,$7F
    dc.b   2,$13
    dc.b   0,  7
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2,  7
    even
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers2, ArtTile_ArtUnc_Flowers2, 8, 2
    dc.b   2,$7F
    dc.b   0, $B
    dc.b   2, $B
    dc.b   0, $B
    dc.b   2,  5
    dc.b   0,  5
    dc.b   2,  5
    dc.b   0,  5
    even
    ; Flowers
    zoneanimdecl 7, ArtUnc_Flowers3, ArtTile_ArtUnc_Flowers3, 2, 2
    dc.b   0
    dc.b   2
    even
    ; Flowers
    zoneanimdecl -1, ArtUnc_Flowers4, ArtTile_ArtUnc_Flowers4, 8, 2
    dc.b   0,$7F
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2,  7
    dc.b   0,  7
    dc.b   2, $B
    dc.b   0, $B
    dc.b   2, $B
    even
    ; Pulsing thing against checkered background
    zoneanimdecl -1, ArtUnc_EHZPulseBall, ArtTile_ArtUnc_EHZPulseBall, 6, 2
    dc.b   0,$17
    dc.b   2,  9
    dc.b   4, $B
    dc.b   6,$17
    dc.b   4, $B
    dc.b   2,  9
    even
 
    zoneanimend
 
; word_4009C: Animated_OOZ:
Animated_HPZ:   zoneanimstart
    ; Supposed to be the pulsing orb from HPZ, but uses OOZ's pulsing ball art
    zoneanimdecl 8, ArtUnc_HPZPulseOrb, ArtTile_ArtUnc_HPZPulseOrb_1, 6, 8
    dc.b   0
    dc.b   0
    dc.b   8
    dc.b $10
    dc.b $10
    dc.b   8
    even
    ; Supposed to be the pulsing orb from HPZ, but uses OOZ's pulsing ball art
    zoneanimdecl 8, ArtUnc_HPZPulseOrb, ArtTile_ArtUnc_HPZPulseOrb_2, 6, 8
    dc.b   8
    dc.b $10
    dc.b $10
    dc.b   8
    dc.b   0
    dc.b   0
    even
    ; Supposed to be the pulsing orb from HPZ, but uses OOZ's pulsing ball art
    zoneanimdecl 8, ArtUnc_HPZPulseOrb, ArtTile_ArtUnc_HPZPulseOrb_3, 6, 8
    dc.b $10
    dc.b   8
    dc.b   0
    dc.b   0
    dc.b   8
    dc.b $10
    even
 
    zoneanimend
 
; word_400C8:  Animated_OOZ2:
Animated_OOZ:   zoneanimstart
    ; Pulsing ball from OOZ
    zoneanimdecl -1, ArtUnc_OOZPulseBall, ArtTile_ArtUnc_OOZPulseBall, 4, 4
    dc.b   0, $B
    dc.b   4,  5
    dc.b   8,  9
    dc.b   4,  3
    even
    ; Square rotating around ball in OOZ
    zoneanimdecl 6, ArtUnc_OOZSquareBall1, ArtTile_ArtUnc_OOZSquareBall1, 4, 4
    dc.b   0
    dc.b   4
    dc.b   8
    dc.b  $C
    even
    ; Square rotating around ball
    zoneanimdecl 6, ArtUnc_OOZSquareBall2, ArtTile_ArtUnc_OOZSquareBall2, 4, 4
    dc.b   0
    dc.b   4
    dc.b   8
    dc.b  $C
    even
    ; Oil
    zoneanimdecl $11, ArtUnc_Oil1, ArtTile_ArtUnc_Oil1, 6,$10
    dc.b   0
    dc.b $10
    dc.b $20
    dc.b $30
    dc.b $20
    dc.b $10
    even
    ; Oil
    zoneanimdecl $11, ArtUnc_Oil2, ArtTile_ArtUnc_Oil2, 6,$10
    dc.b   0
    dc.b $10
    dc.b $20
    dc.b $30
    dc.b $20
    dc.b $10
    even
 
    zoneanimend
 
Animated_CNZ:   zoneanimstart
    ; Flipping foreground section in CNZ
    zoneanimdecl -1, ArtUnc_CNZFlipTiles, ArtTile_ArtUnc_CNZFlipTiles_2, $10,$10
    dc.b   0,$C7
    dc.b $10,  5
    dc.b $20,  5
    dc.b $30,  5
    dc.b $40,$C7
    dc.b $50,  5
    dc.b $20,  5
    dc.b $60,  5
    dc.b   0,  5
    dc.b $10,  5
    dc.b $20,  5
    dc.b $30,  5
    dc.b $40,  5
    dc.b $50,  5
    dc.b $20,  5
    dc.b $60,  5
    even
    ; Flipping foreground section in CNZ
    zoneanimdecl -1, ArtUnc_CNZFlipTiles, ArtTile_ArtUnc_CNZFlipTiles_1, $10,$10
    dc.b $70,  5
    dc.b $80,  5
    dc.b $20,  5
    dc.b $90,  5
    dc.b $A0,  5
    dc.b $B0,  5
    dc.b $20,  5
    dc.b $C0,  5
    dc.b $70,$C7
    dc.b $80,  5
    dc.b $20,  5
    dc.b $90,  5
    dc.b $A0,$C7
    dc.b $B0,  5
    dc.b $20,  5
    dc.b $C0,  5
    even
 
    zoneanimend
 
; word_40160:
Animated_CNZ_2P:    zoneanimstart
    ; Flipping foreground section in CNZ
    zoneanimdecl -1, ArtUnc_CNZFlipTiles, ArtTile_ArtUnc_CNZFlipTiles_2_2p, $10,$10
    dc.b   0,$C7
    dc.b $10,  5
    dc.b $20,  5
    dc.b $30,  5
    dc.b $40,$C7
    dc.b $50,  5
    dc.b $20,  5
    dc.b $60,  5
    dc.b   0,  5
    dc.b $10,  5
    dc.b $20,  5
    dc.b $30,  5
    dc.b $40,  5
    dc.b $50,  5
    dc.b $20,  5
    dc.b $60,  5
    even
    ; Flipping foreground section in CNZ
    zoneanimdecl -1, ArtUnc_CNZFlipTiles, ArtTile_ArtUnc_CNZFlipTiles_1_2p, $10,$10
    dc.b $70,  5
    dc.b $80,  5
    dc.b $20,  5
    dc.b $90,  5
    dc.b $A0,  5
    dc.b $B0,  5
    dc.b $20,  5
    dc.b $C0,  5
    dc.b $70,$C7
    dc.b $80,  5
    dc.b $20,  5
    dc.b $90,  5
    dc.b $A0,$C7
    dc.b $B0,  5
    dc.b $20,  5
    dc.b $C0,  5
    even
 
    zoneanimend
 
Animated_CPZ:   zoneanimstart
    ; Animated background section in CPZ and DEZ
    zoneanimdecl 4, ArtUnc_CPZAnimBack, ArtTile_ArtUnc_CPZAnimBack, 8, 2
    dc.b   0
    dc.b   2
    dc.b   4
    dc.b   6
    dc.b   8
    dc.b  $A
    dc.b  $C
    dc.b  $E
    even
 
    zoneanimend
 
Animated_DEZ:   zoneanimstart
    ; Animated background section in CPZ and DEZ
    zoneanimdecl 4, ArtUnc_CPZAnimBack, ArtTile_ArtUnc_DEZAnimBack, 8, 2
    dc.b   0
    dc.b   2
    dc.b   4
    dc.b   6
    dc.b   8
    dc.b  $A
    dc.b  $C
    dc.b  $E
    even
 
    zoneanimend
 
Animated_ARZ:   zoneanimstart
    ; Waterfall patterns
    zoneanimdecl 5, ArtUnc_Waterfall1, ArtTile_ArtUnc_Waterfall1_2, 2, 4
    dc.b   0
    dc.b   4
    even
    ; Waterfall patterns
    zoneanimdecl 5, ArtUnc_Waterfall1, ArtTile_ArtUnc_Waterfall1_1, 2, 4
    dc.b   4
    dc.b   0
    even
    ; Waterfall patterns
    zoneanimdecl 5, ArtUnc_Waterfall2, ArtTile_ArtUnc_Waterfall2, 2, 4
    dc.b   0
    dc.b   4
    even
    ; Waterfall patterns
    zoneanimdecl 5, ArtUnc_Waterfall3, ArtTile_ArtUnc_Waterfall3, 2, 4
    dc.b   0
    dc.b   4
    even
 
    zoneanimend
 
Animated_Null:
    ; invalid
; ===========================================================================
 
; ---------------------------------------------------------------------------
; Unused mystery function
; In CPZ, within a certain range of camera X coordinates spanning
; exactly 2 screens (a boss fight or cutscene?),
; once every 8 frames, make the entire screen refresh and do... SOMETHING...
; (in 2 separate 512-byte blocks of memory, move around a bunch of bytes)
; Maybe some abandoned scrolling effect?
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_40200:
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    beq.s   +
-   rts
; ===========================================================================
; this shifts all blocks of the chunks $EA-$ED and $FA-$FD one block to the
; left and the last block in each row (chunk $ED/$FD) to the beginning
; i.e. rotates the blocks to the left by one
+
    move.w  (Camera_X_pos).w,d0
    cmpi.w  #$1940,d0
    blo.s   -   ; rts
    cmpi.w  #$1F80,d0
    bhs.s   -   ; rts
    subq.b  #1,(CPZ_UnkScroll_Timer).w
    bpl.s   -   ; rts   ; do it every 8th frame
    move.b  #7,(CPZ_UnkScroll_Timer).w
    move.b  #1,(Screen_redraw_flag).w
    lea (Chunk_Table+$7500).l,a1 ; chunks $EA-$ED, $FFFF7500 - $FFFF7700
    bsr.s   +
    lea (Chunk_Table+$7D00).l,a1 ; chunks $FA-$FD, $FFFF7D00 - $FFFF7F00
+
    move.w  #7,d1
 
-   move.w  (a1),d0
    rept 3          ; do this for 3 chunks
      rept 7
    move.w  2(a1),(a1)+ ; shift 1st line of chunk by 1 block to the left (+3*14 bytes)
      endm
    move.w  $72(a1),(a1)+   ; first block of next chunk to the left into previous chunk (+3*2 bytes)
    adda.w  #$70,a1     ; go to next chunk (+336 bytes)
    endm
      rept 7            ; now do it for the 4th chunk
    move.w  2(a1),(a1)+ ; shift 1st line of chunk by 1 block to the left (+14 bytes)
      endm
    move.w  d0,(a1)+    ; move 1st block of 1st chunk to last block of last chunk (+2 bytes, subsubtotal = 400 bytes)
    suba.w  #$180,a1    ; go to the next row in the first chunk (-384 bytes, subtotal = -16 bytes)
    dbf d1,-        ; now do this again for rows 2-8 in these chunks
                ; 400 + 7 * (-16) = 512 byte range was affected
    rts
; ===========================================================================
 
loc_402D4:
    cmpi.b  #hill_top_zone,(Current_Zone).w
    bne.s   +
    bsr.w   PatchHTZTiles
    move.b  #-1,(Anim_Counters+1).w
    move.w  #-1,(TempArray_LayerDef+$20).w
+
    cmpi.b  #chemical_plant_zone,(Current_Zone).w
    bne.s   +
    move.b  #-1,(Anim_Counters+1).w
+
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
    add.w   d0,d0
    move.w  AnimPatMaps(pc,d0.w),d0
    lea AnimPatMaps(pc,d0.w),a0
    tst.w   (Two_player_mode).w
    beq.s   +
    cmpi.b  #casino_night_zone,(Current_Zone).w
    bne.s   +
    lea (APM_CNZ2P).l,a0
+
    tst.w   (a0)
    beq.s   +   ; rts
    lea (Block_Table).w,a1
    adda.w  (a0)+,a1
    move.w  (a0)+,d1
    tst.w   (Two_player_mode).w
    bne.s   LoadLevelBlocks_2P
 
; loc_40330:
LoadLevelBlocks:
    move.w  (a0)+,(a1)+ ; copy blocks to RAM
    dbf d1,LoadLevelBlocks  ; loop using d1
+
    rts
; ===========================================================================
; loc_40338:
LoadLevelBlocks_2P:
    ; There's a bug in here, where d1, the loop counter,
    ; is overwritten with VRAM data
    move.w  (a0)+,d0
    move.w  d0,d1
    andi.w  #nontile_mask,d0    ; d0 holds the preserved non-tile data
    andi.w  #tile_mask,d1       ; d1 holds the tile index (overwrites loop counter!)
    lsr.w   #1,d1           ; half tile index
    or.w    d1,d0           ; put them back together
    move.w  d0,(a1)+
    dbf d1,LoadLevelBlocks_2P   ; loop using d1, which we just overwrote
    rts
; ===========================================================================
 
; --------------------------------------------------------------------------------------
; Animated Pattern Mappings (16x16)
; --------------------------------------------------------------------------------------
; off_40350:
AnimPatMaps: zoneOrderedOffsetTable 2,1
    zoneOffsetTableEntry.w APM_EHZ      ;  0
    zoneOffsetTableEntry.w APM_Null     ;  1
    zoneOffsetTableEntry.w APM_Null     ;  2
    zoneOffsetTableEntry.w APM_Null     ;  3
    zoneOffsetTableEntry.w APM_MTZ      ;  4
    zoneOffsetTableEntry.w APM_MTZ      ;  5
    zoneOffsetTableEntry.w APM_Null     ;  6
    zoneOffsetTableEntry.w APM_EHZ      ;  7
    zoneOffsetTableEntry.w APM_HPZ      ;  8
    zoneOffsetTableEntry.w APM_Null     ;  9
    zoneOffsetTableEntry.w APM_OOZ      ; $A
    zoneOffsetTableEntry.w APM_Null     ; $B
    zoneOffsetTableEntry.w APM_CNZ      ; $C
    zoneOffsetTableEntry.w APM_CPZ      ; $D
    zoneOffsetTableEntry.w APM_DEZ      ; $E
    zoneOffsetTableEntry.w APM_ARZ      ; $F
    zoneOffsetTableEntry.w APM_Null     ;$10
    zoneTableEnd
 
begin_animpat macro {INTLABEL}
__LABEL__ label *
__LABEL___Len := __LABEL___End - __LABEL___Blocks
    dc.w $1800 - __LABEL___Len
    dc.w bytesToWcnt(__LABEL___Len)
__LABEL___Blocks:
    endm
 
; byte_40372:
APM_EHZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$0 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$4 ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$1 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$5 ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$8 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$C ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$9 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$D ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$10,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$14,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$11,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$15,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$2 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$6 ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$3 ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$7 ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$A ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$E ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$B ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$F ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$12,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$16,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$13,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$17,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$18,0,0,3,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$1A,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$19,0,0,3,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$1B,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$1C,0,0,3,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$1E,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZMountains+$1D,0,0,3,0),make_block_tile(ArtTile_ArtUnc_EHZMountains+$1F,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$0,1,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$1,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$1,1,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtKos_Checkers+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$0,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtKos_Checkers+$1,0,0,2,0),make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$1,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$0,1,0,2,0),make_block_tile(ArtTile_ArtKos_Checkers+$0,1,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_EHZPulseBall+$1,1,0,2,0),make_block_tile(ArtTile_ArtKos_Checkers+$1,1,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers1+$0,0,0,3,0),make_block_tile(ArtTile_ArtUnc_Flowers1+$0,1,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers1+$1,0,0,3,0),make_block_tile(ArtTile_ArtUnc_Flowers1+$1,1,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers2+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_Flowers2+$0,1,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers2+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_Flowers2+$1,1,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers3+$0,0,0,3,0),make_block_tile(ArtTile_ArtUnc_Flowers3+$0,1,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers3+$1,0,0,3,0),make_block_tile(ArtTile_ArtUnc_Flowers3+$1,1,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers4+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_Flowers4+$0,1,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Flowers4+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_Flowers4+$1,1,0,3,1)
APM_EHZ_End:
 
 
 
; byte_403EE:
APM_MTZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$0,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$0,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$1,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$1,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$2,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$2,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$3,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$3,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$E,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$E,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$F,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$F,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$C,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$C,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$D,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$D,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$A,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$A,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$B,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$B,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$8,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$8,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$9,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$9,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$6,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$6,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$7,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$7,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$4,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$4,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$5,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$5,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$2,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$2,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$3,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$3,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$0,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$0,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$1,0,0,3,0),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$1,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$4,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$4,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$5,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_1+$5,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$0,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$0,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$1,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$1,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$2,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$2,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$3,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$3,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$4,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$4,1,0,1,0)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$5,0,0,1,0),make_block_tile(ArtTile_ArtUnc_MTZAnimBack_2+$5,1,0,1,0)
    
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,1),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$0    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$1    ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,1),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$2    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$3    ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$4    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$5    ,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$8    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$9    ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$6    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$7    ,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Lava+$A    ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Lava+$B    ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$E,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$E,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$F,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$F,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$C,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$C,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$D,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$D,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$A,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$B,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$8,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$9,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$6,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$6,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$7,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$7,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$4,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$4,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$5,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$5,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$2,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$3,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$0,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_MTZCylinder+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_MTZCylinder+$1,0,0,3,1)
APM_MTZ_End:
 
 
 
; byte_404C2:
; byte_405B6:
APM_OOZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_OOZPulseBall+$0,0,0,0,1),make_block_tile(ArtTile_ArtUnc_OOZPulseBall+$2,0,0,0,1)
    dc.w make_block_tile(ArtTile_ArtUnc_OOZPulseBall+$1,0,0,0,1),make_block_tile(ArtTile_ArtUnc_OOZPulseBall+$3,0,0,0,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall1+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_OOZSquareBall1+$1,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall1+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_OOZSquareBall1+$3,0,0,3,1)
    
    if gameRevision<2
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$0,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$2,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$1,0,0,3,0),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$3,0,0,3,0),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,0,0)
    else
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$0,0,0,3,0)
    dc.w make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$2,0,0,3,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$1,0,0,3,0),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_OOZSquareBall2+$3,0,0,3,0),make_block_tile(ArtTile_ArtKos_LevelArt+$0,0,0,2,0)
    endif
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$0,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$1,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$8,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$9,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$2,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$3,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$A,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$B,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$4,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$5,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$C,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$D,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$6,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$7,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil1+$E,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil1+$F,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$0,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$1,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$8,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$9,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$2,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$3,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$A,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$B,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$4,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$5,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$C,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$D,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$6,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$7,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Oil2+$E,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Oil2+$F,0,0,2,1)
APM_OOZ_End:
 
 
 
; byte_4061A:
APM_CNZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$4,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$5,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$C,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$D,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$6,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$7,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$E,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2+$F,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$4,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$5,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$C,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$D,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$6,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$7,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$E,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1+$F,0,0,3,1)
APM_CNZ_End:
 
 
 
; byte_406BE:
APM_CNZ2P:  begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_1_2p+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_2_2p+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$0,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$4,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$1,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$5,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$8,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$C,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$9,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$D,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$2,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$6,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$3,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$7,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$A,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$E,0,0,0,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$B,0,0,0,0),make_block_tile(ArtTile_ArtUnc_CNZSlotPics_3_2p+$F,0,0,0,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$4,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$5,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$C,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$D,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$6,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$7,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$E,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_2_2p+$F,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$4,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$5,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$C,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$D,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$6,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$7,0,0,3,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$E,0,0,3,1)
    dc.w make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_CNZFlipTiles_1_2p+$F,0,0,3,1)
APM_CNZ2P_End:
 
 
 
; byte_40762:
APM_CPZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_CPZAnimBack+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_CPZAnimBack+$1,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_CPZAnimBack+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_CPZAnimBack+$1,0,0,2,0)
APM_CPZ_End:
 
 
 
; byte_4076E:
APM_DEZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_DEZAnimBack+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_DEZAnimBack+$1,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_DEZAnimBack+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_DEZAnimBack+$1,0,0,2,0)
APM_DEZ_End:
 
 
 
; byte_4077A:
APM_ARZ:    begin_animpat
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall3+$0  ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall3+$1  ,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall3+$2  ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall3+$3  ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall2+$0  ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall2+$1  ,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall2+$2  ,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall2+$3  ,0,0,2,1)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$0,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$1,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$2,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$3,0,0,2,1)
    
    ;These are invalid animation entries for waterfalls (bug in original game):
        if 1==1
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$C,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$D,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$E,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$F,0,0,2,1)
        else
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$0,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$1,0,0,2,1)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$2,0,0,2,1),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$3,0,0,2,1)
        endif
    
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall3+$0  ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall3+$1  ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall3+$2  ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall3+$3  ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall2+$0  ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall2+$1  ,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall2+$2  ,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall2+$3  ,0,0,2,0)
    
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$1,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$2,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_1+$3,0,0,2,0)
    
    ;These are invalid animation entries for waterfalls (bug in original game):
        if 1==1
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$C,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$D,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$E,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$F,0,0,2,0)
        else
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$0,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$1,0,0,2,0)
    dc.w make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$2,0,0,2,0),make_block_tile(ArtTile_ArtUnc_Waterfall1_2+$3,0,0,2,0)
        endif
APM_ARZ_End:
 
 
 
; byte_407BE:
APM_Null:   dc.w   0
; ===========================================================================
; loc_407C0:
PatchHTZTiles:
    lea (ArtNem_HTZCliffs).l,a0
    lea (Object_RAM+$800).w,a4
    jsrto   (NemDecToRAM).l, JmpTo2_NemDecToRAM
    lea (Object_RAM+$800).w,a1
    lea_    word_3FD9C,a4
    moveq   #0,d2
    moveq   #7,d4
 
loc_407DA:
    moveq   #5,d3
 
loc_407DC:
    moveq   #-1,d0
    move.w  (a4)+,d0
    movea.l d0,a2
    moveq   #$1F,d1
 
loc_407E4:
    move.l  (a1),(a2)+
    move.l  d2,(a1)+
    dbf d1,loc_407E4
    dbf d3,loc_407DC
    adda.w  #$C,a4
    dbf d4,loc_407DA
    rts
; ===========================================================================
 
    if gameRevision<2
    nop
    endif
 
    if ~~removeJmpTos
JmpTo2_NemDecToRAM 
    jmp (NemDecToRAM).l
 
    align 4
    endif
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to draw the HUD
; ---------------------------------------------------------------------------
 
hud_letter_num_tiles = 2
hud_letter_vdp_delta = vdpCommDelta(tiles_to_bytes(hud_letter_num_tiles))
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_40804:
BuildHUD:
    tst.w   (Ring_count).w
    beq.s   ++  ; blink ring count if it's 0
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   +   ; only blink on certain frames
    cmpi.b  #9,(Timer_minute).w ; should the minutes counter blink?
    bne.s   +   ; if not, branch
    addq.w  #2,d1   ; set mapping frame time counter blink
+
    bra.s   ++
+
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   +   ; only blink on certain frames
    addq.w  #1,d1   ; set mapping frame for ring count blink
    cmpi.b  #9,(Timer_minute).w
    bne.s   +
    addq.w  #2,d1   ; set mapping frame for double blink
+
    move.w  #128+16,d3  ; set X pos
    move.w  #128+136,d2 ; set Y pos
    lea (HUD_MapUnc_40A9A).l,a1
    movea.w #make_art_tile(ArtTile_ArtNem_HUD,0,1),a3   ; set art tile and flags
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    bmi.s   +
    jsrto   (DrawSprite_Loop).l, JmpTo_DrawSprite_Loop  ; draw frame
+
    rts
; End of function BuildHUD
 
; ===========================================================================
 
BuildHUD_P1:
    tst.w   (Ring_count).w
    beq.s   BuildHUD_P1_NoRings
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   +
    cmpi.b  #9,(Timer_minute).w
    bne.s   +
    addq.w  #2,d1   ; make TIME flash
+
    bra.s   BuildHUD_P1_Continued
; ===========================================================================
; loc_40876:
BuildHUD_P1_NoRings:
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   BuildHUD_P1_Continued
    addq.w  #1,d1   ; make RINGS flash
    cmpi.b  #9,(Timer_minute).w
    bne.s   BuildHUD_P1_Continued
    addq.w  #2,d1   ; make TIME flash
; loc_4088C:
BuildHUD_P1_Continued:
    move.w  #$90,d3
    move.w  #$188,d2
    lea (HUD_MapUnc_40BEA).l,a1
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Text_2P,0,1),a3
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    move.w  #$B8,d3
    move.w  #$108,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.b  (Timer_minute).w,d7
    bsr.w   sub_4092E
    bsr.w   sub_4096A
    moveq   #0,d7
    move.b  (Timer_second).w,d7
    bsr.w   loc_40938
    move.w  #$C0,d3
    move.w  #$118,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.w  (Ring_count).w,d7
    bsr.w   sub_40984
    tst.b   (Update_HUD_timer_2P).w
    bne.s   +
    tst.b   (Update_HUD_timer).w
    beq.s   +
    move.w  #$110,d3
    move.w  #$1B8,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.b  (Loser_Time_Left).w,d7
    bsr.w   loc_40938
+
    moveq   #4,d1
    move.w  #$90,d3
    move.w  #$188,d2
    lea (HUD_MapUnc_40BEA).l,a1
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Text_2P,0,1),a3
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    moveq   #0,d4
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_4092E:
 
    lea (Hud_1).l,a4
    moveq   #0,d6
    bra.s   loc_40940
; ===========================================================================
 
loc_40938:
 
    lea (Hud_10).l,a4
    moveq   #1,d6
 
loc_40940:
 
    moveq   #0,d1
    move.l  (a4)+,d4
 
loc_40944:
    sub.l   d4,d7
    bcs.s   loc_4094C
    addq.w  #1,d1
    bra.s   loc_40944
; ===========================================================================
 
loc_4094C:
    add.l   d4,d7
    lea (HUD_MapUnc_40C82).l,a1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    addq.w  #8,d3
    dbf d6,loc_40940
    rts
; End of function sub_4092E
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_4096A:
 
    moveq   #$A,d1
    lea (HUD_MapUnc_40C82).l,a1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    addq.w  #8,d3
    rts
; End of function sub_4096A
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_40984:
 
    lea (Hud_100).l,a4
    moveq   #2,d6
 
loc_4098C:
    moveq   #0,d1
    move.l  (a4)+,d4
 
loc_40990:
    sub.l   d4,d7
    bcs.s   loc_40998
    addq.w  #1,d1
    bra.s   loc_40990
; ===========================================================================
 
loc_40998:
    add.l   d4,d7
    tst.w   d6
    beq.s   loc_409AA
    tst.w   d1
    beq.s   loc_409A6
    bset    #$1F,d6
 
loc_409A6:
    tst.l   d6
    bpl.s   loc_409BE
 
loc_409AA:
    lea (HUD_MapUnc_40C82).l,a1
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
 
loc_409BE:
    addq.w  #8,d3
    dbf d6,loc_4098C
    rts
; End of function sub_40984
 
; ===========================================================================
 
BuildHUD_P2:
    tst.w   (Ring_count_2P).w
    beq.s   BuildHUD_P2_NoRings
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   +
    cmpi.b  #9,(Timer_minute_2P).w
    bne.s   +
    addq.w  #2,d1
+
    bra.s   BuildHUD_P2_Continued
; ===========================================================================
; loc_409E2:
BuildHUD_P2_NoRings:
    moveq   #0,d1
    btst    #3,(Timer_frames+1).w
    bne.s   BuildHUD_P2_Continued
    addq.w  #1,d1
    cmpi.b  #9,(Timer_minute_2P).w
    bne.s   BuildHUD_P2_Continued
    addq.w  #2,d1
; loc_409F8:
BuildHUD_P2_Continued:
    move.w  #$90,d3
    move.w  #$268,d2
    lea (HUD_MapUnc_40BEA).l,a1
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Text_2P,0,1),a3
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    move.w  #$B8,d3
    move.w  #$1E8,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.b  (Timer_minute_2P).w,d7
    bsr.w   sub_4092E
    bsr.w   sub_4096A
    moveq   #0,d7
    move.b  (Timer_second_2P).w,d7
    bsr.w   loc_40938
    move.w  #$C0,d3
    move.w  #$1F8,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.w  (Ring_count_2P).w,d7
    bsr.w   sub_40984
    tst.b   (Update_HUD_timer).w
    bne.s   +
    tst.b   (Update_HUD_timer_2P).w
    beq.s   +
    move.w  #$110,d3
    move.w  #$298,d2
    movea.w #make_art_tile_2p(ArtTile_Art_HUD_Numbers_2P,0,1),a3
    moveq   #0,d7
    move.b  (Loser_Time_Left).w,d7
    bsr.w   loc_40938
+
    moveq   #5,d1
    move.w  #$90,d3
    move.w  #$268,d2
    lea (HUD_MapUnc_40BEA).l,a1
    movea.w #make_art_tile_2p(ArtTile_ArtNem_Powerups,0,1),a3
    add.w   d1,d1
    adda.w  (a1,d1.w),a1
    move.w  (a1)+,d1
    subq.w  #1,d1
    jsrto   (DrawSprite_2P_Loop).l, JmpTo_DrawSprite_2P_Loop
    moveq   #0,d4
    rts
; ===========================================================================
 
; sprite mappings for the HUD
; uses the art in VRAM from $D940 - $FC00
HUD_MapUnc_40A9A:   BINCLUDE "mappings/sprite/hud_a.bin"
 
 
HUD_MapUnc_40BEA:   BINCLUDE "mappings/sprite/hud_b.bin"
 
 
HUD_MapUnc_40C82:   BINCLUDE "mappings/sprite/hud_c.bin"
 
; ---------------------------------------------------------------------------
; Add points subroutine
; subroutine to add to Player 1's score
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_40D06:
AddPoints:
    move.b  #1,(Update_HUD_score).w
    lea (Score).w,a3
    add.l   d0,(a3) ; add d0*10 to the score
    move.l  #999999,d1
    cmp.l   (a3),d1 ; is #999999 higher than the score?
    bhi.s   +   ; if yes, branch
    move.l  d1,(a3) ; set score to #999999
+
    move.l  (a3),d0
    cmp.l   (Next_Extra_life_score).w,d0
    blo.s   +   ; rts
    addi.l  #5000,(Next_Extra_life_score).w
    addq.b  #1,(Life_count).w
    addq.b  #1,(Update_HUD_lives).w
    move.w  #MusID_ExtraLife,d0
    jmp (PlayMusic).l
; ===========================================================================
+   rts
; End of function AddPoints
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; ---------------------------------------------------------------------------
; Add points subroutine
; subroutine to add to Player 2's score
; (goes to AddPoints to add to Player 1's score instead if this is not Player 2)
; ---------------------------------------------------------------------------
 
; sub_40D42:
AddPoints2:
    tst.w   (Two_player_mode).w
    beq.s   AddPoints
    cmpa.w  #MainCharacter,a3
    beq.s   AddPoints
    move.b  #1,(Update_HUD_score_2P).w
    lea (Score_2P).w,a3
    add.l   d0,(a3) ; add d0*10 to the score
    move.l  #999999,d1
    cmp.l   (a3),d1 ; is #999999 higher than the score?
    bhi.s   +   ; if yes, branch
    move.l  d1,(a3) ; set score to #999999
+
    move.l  (a3),d0
    cmp.l   (Next_Extra_life_score_2P).w,d0
    blo.s   +   ; rts
    addi.l  #5000,(Next_Extra_life_score_2P).w
    addq.b  #1,(Life_count_2P).w
    addq.b  #1,(Update_HUD_lives_2P).w
    move.w  #MusID_ExtraLife,d0
    jmp (PlayMusic).l
; ===========================================================================
+   rts
; End of function AddPoints2
 
; ---------------------------------------------------------------------------
; Subroutine to update the HUD
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_40D8A:
HudUpdate:
    nop
    lea (VDP_data_port).l,a6
    tst.w   (Two_player_mode).w
    bne.w   loc_40F50
    tst.w   (Debug_mode_flag).w ; is debug mode on?
    bne.w   loc_40E9A   ; if yes, branch
    tst.b   (Update_HUD_score).w    ; does the score need updating?
    beq.s   Hud_ChkRings    ; if not, branch
    clr.b   (Update_HUD_score).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Score),VRAM,WRITE),d0   ; set VRAM address
    move.l  (Score).w,d1    ; load score
    bsr.w   Hud_Score
; loc_40DBA:
Hud_ChkRings:
    tst.b   (Update_HUD_rings).w    ; does the ring counter need updating?
    beq.s   Hud_ChkTime ; if not, branch
    bpl.s   loc_40DC6
    bsr.w   Hud_InitRings
 
loc_40DC6:
    clr.b   (Update_HUD_rings).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Rings),VRAM,WRITE),d0
    moveq   #0,d1
    move.w  (Ring_count).w,d1
    bsr.w   Hud_Rings
; loc_40DDA:
Hud_ChkTime:
    tst.b   (Update_HUD_timer).w    ; does the time need updating?
    beq.s   Hud_ChkLives    ; if not, branch
    tst.w   (Game_paused).w ; is the game paused?
    bne.s   Hud_ChkLives    ; if yes, branch
    lea (Timer).w,a1
    cmpi.l  #$93B3B,(a1)+   ; is the time 9.59?
    beq.w   loc_40E84   ; if yes, branch
    addq.b  #1,-(a1)
    cmpi.b  #60,(a1)
    blo.s   Hud_ChkLives
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #60,(a1)
    blo.s   +
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #9,(a1)
    blo.s   +
    move.b  #9,(a1)
+
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Minutes),VRAM,WRITE),d0
    moveq   #0,d1
    move.b  (Timer_minute).w,d1
    bsr.w   Hud_Mins
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Seconds),VRAM,WRITE),d0
    moveq   #0,d1
    move.b  (Timer_second).w,d1
    bsr.w   Hud_Secs
; loc_40E38:
Hud_ChkLives:
    tst.b   (Update_HUD_lives).w    ; does the lives counter need updating?
    beq.s   Hud_ChkBonus    ; if not, branch
    clr.b   (Update_HUD_lives).w
    bsr.w   Hud_Lives
; loc_40E46:
Hud_ChkBonus:
    tst.b   (Update_Bonus_score).w  ; do time/ring bonus counters need updating?
    beq.s   Hud_End ; if not, branch
    clr.b   (Update_Bonus_score).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Bonus_Score),VRAM,WRITE),(VDP_control_port).l
    moveq   #0,d1
    move.w  (Total_Bonus_Countdown).w,d1
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_1).w,d1     ; load time bonus
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_2).w,d1     ; load ring bonus
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_3).w,d1     ; load perfect bonus
    bsr.w   Hud_TimeRingBonus
; return_40E82:
Hud_End:
    rts
; ===========================================================================
 
loc_40E84:
    clr.b   (Update_HUD_timer).w
    lea (MainCharacter).w,a0 ; a0=character
    movea.l a0,a2
    bsr.w   KillCharacter
    move.b  #1,(Time_Over_flag).w
    rts
; ===========================================================================
 
loc_40E9A:
    bsr.w   HudDb_XY
    tst.b   (Update_HUD_rings).w
    beq.s   loc_40EBE
    bpl.s   loc_40EAA
    bsr.w   Hud_InitRings
 
loc_40EAA:
    clr.b   (Update_HUD_rings).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Rings),VRAM,WRITE),d0
 
    moveq   #0,d1
    move.w  (Ring_count).w,d1
    bsr.w   Hud_Rings
 
loc_40EBE:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Seconds),VRAM,WRITE),d0
    moveq   #0,d1
    move.b  (Sprite_count).w,d1
    bsr.w   Hud_Secs
    tst.b   (Update_HUD_lives).w
    beq.s   loc_40EDC
    clr.b   (Update_HUD_lives).w
    bsr.w   Hud_Lives
 
loc_40EDC:
    tst.b   (Update_Bonus_score).w
    beq.s   loc_40F18
    clr.b   (Update_Bonus_score).w
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Bonus_Score),VRAM,WRITE),(VDP_control_port).l
    moveq   #0,d1
    move.w  (Total_Bonus_Countdown).w,d1
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_1).w,d1
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_2).w,d1
    bsr.w   Hud_TimeRingBonus
    moveq   #0,d1
    move.w  (Bonus_Countdown_3).w,d1
    bsr.w   Hud_TimeRingBonus
 
loc_40F18:
    tst.w   (Game_paused).w
    bne.s   return_40F4E
    lea (Timer).w,a1
    cmpi.l  #$93B3B,(a1)+
    nop
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   return_40F4E
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   return_40F4E
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #9,(a1)
    blo.s   return_40F4E
    move.b  #9,(a1)
 
return_40F4E:
    rts
; ===========================================================================
 
loc_40F50:
    tst.w   (Game_paused).w
    bne.w   return_4101A
    tst.b   (Update_HUD_timer).w
    beq.s   loc_40F90
    lea (Timer).w,a1
    cmpi.l  #$93B3B,(a1)+
    beq.w   TimeOver
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   loc_40F90
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   loc_40F90
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #9,(a1)
    blo.s   loc_40F90
    move.b  #9,(a1)
 
loc_40F90:
    tst.b   (Update_HUD_timer_2P).w
    beq.s   loc_40FC8
    lea (Timer_2P).w,a1
    cmpi.l  #$93B3B,(a1)+
    beq.w   TimeOver2
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   loc_40FC8
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #$3C,(a1)
    blo.s   loc_40FC8
    move.b  #0,(a1)
    addq.b  #1,-(a1)
    cmpi.b  #9,(a1)
    blo.s   loc_40FC8
    move.b  #9,(a1)
 
loc_40FC8:
    tst.b   (Update_HUD_lives).w
    beq.s   loc_40FD6
    clr.b   (Update_HUD_lives).w
    bsr.w   Hud_Lives
 
loc_40FD6:
    tst.b   (Update_HUD_lives_2P).w
    beq.s   loc_40FE4
    clr.b   (Update_HUD_lives_2P).w
    bsr.w   Hud_Lives2
 
loc_40FE4:
    move.b  (Update_HUD_timer).w,d0
    or.b    (Update_HUD_timer_2P).w,d0
    beq.s   return_4101A
    lea (Loser_Time_Left).w,a1
    tst.w   (a1)+
    beq.s   return_4101A
    subq.b  #1,-(a1)
    bhi.s   return_4101A
    move.b  #$3C,(a1)
    cmpi.b  #$C,-1(a1)
    bne.s   loc_41010
    move.w  #MusID_Countdown,d0
    jsr (PlayMusic).l
 
loc_41010:
    subq.b  #1,-(a1)
    bcc.s   return_4101A
    move.w  #0,(a1)
    bsr.s   TimeOver0
 
return_4101A:
 
    rts
; End of function HudUpdate
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4101C:
TimeOver0:
    tst.b   (Update_HUD_timer).w
    bne.s   TimeOver
    tst.b   (Update_HUD_timer_2P).w
    bne.s   TimeOver2
    rts
; ===========================================================================
; loc_4102A:
TimeOver:
    clr.b   (Update_HUD_timer).w
    lea (MainCharacter).w,a0 ; a0=character
    movea.l a0,a2
    bsr.w   KillCharacter
    move.b  #1,(Time_Over_flag).w
    tst.b   (Update_HUD_timer_2P).w
    beq.s   +   ; rts
; loc_41044:
TimeOver2:
    clr.b   (Update_HUD_timer_2P).w
    lea (Sidekick).w,a0 ; a0=character
    movea.l a0,a2
    bsr.w   KillCharacter
    move.b  #1,(Time_Over_flag_2P).w
+
    rts
; End of function TimeOver0
 
 
; ---------------------------------------------------------------------------
; Subroutine to initialize ring counter on the HUD
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4105A:
; Hud_LoadZero:
Hud_InitRings:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Rings),VRAM,WRITE),(VDP_control_port).l
    lea Hud_TilesRings(pc),a2
    move.w  #(Hud_TilesBase_End-Hud_TilesRings)-1,d2
    bra.s   loc_41090
 
; ---------------------------------------------------------------------------
; Subroutine to load uncompressed HUD patterns ("E", "0", colon)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; loc_4106E:
Hud_Base:
    lea (VDP_data_port).l,a6
    bsr.w   Hud_Lives
    tst.w   (Two_player_mode).w
    bne.s   loc_410BC
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Score_E),VRAM,WRITE),(VDP_control_port).l
    lea Hud_TilesBase(pc),a2
    move.w  #(Hud_TilesBase_End-Hud_TilesBase)-1,d2
 
loc_41090:
    lea Art_Hud(pc),a1
 
loc_41094:
    move.w  #8*hud_letter_num_tiles-1,d1
    move.b  (a2)+,d0
    bmi.s   loc_410B0
    ext.w   d0
    lsl.w   #5,d0
    lea (a1,d0.w),a3
 
loc_410A4:
    move.l  (a3)+,(a6)
    dbf d1,loc_410A4
 
loc_410AA:
    dbf d2,loc_41094
    rts
; ===========================================================================
 
loc_410B0:
    move.l  #0,(a6)
    dbf d1,loc_410B0
    bra.s   loc_410AA
; End of function Hud_Base
 
; ===========================================================================
 
loc_410BC:
    bsr.w   Hud_Lives2
    move.l  #Art_Hud,d1 ; source addreses
    move.w  #tiles_to_bytes(ArtTile_Art_HUD_Numbers_2P),d2 ; destination VRAM address
    move.w  #$160,d3 ; DMA transfer length
    jmp (QueueDMATransfer).l
; ===========================================================================
 
    charset ' ',$FF
    charset '0',0
    charset '1',2
    charset '2',4
    charset '3',6
    charset '4',8
    charset '5',$A
    charset '6',$C
    charset '7',$E
    charset '8',$10
    charset '9',$12
    charset ':',$14
    charset 'E',$16
 
; byte_410D4:
Hud_TilesBase:
    dc.b "E      0"
    dc.b "0:00"
; byte_410E0:
; Hud_TilesZero:
Hud_TilesRings:
    dc.b "  0"
Hud_TilesBase_End
 
    charset
    even
 
; ---------------------------------------------------------------------------
; Subroutine to load debug mode numbers patterns
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_410E4:
HudDb_XY:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_HUD_Score_E),VRAM,WRITE),(VDP_control_port).l
    move.w  (Camera_X_pos).w,d1
    swap    d1
    move.w  (MainCharacter+x_pos).w,d1
    bsr.s   HudDb_XY2
    move.w  (Camera_Y_pos).w,d1
    swap    d1
    move.w  (MainCharacter+y_pos).w,d1
; loc_41104:
HudDb_XY2:
    moveq   #7,d6
    lea (Art_Text).l,a1
; loc_4110C:
HudDb_XYLoop:
    rol.w   #4,d1
    move.w  d1,d2
    andi.w  #$F,d2
    cmpi.w  #$A,d2
    blo.s   loc_4111E
    addi_.w #7,d2
 
loc_4111E:
    lsl.w   #5,d2
    lea (a1,d2.w),a3
    rept 8
    move.l  (a3)+,(a6)
    endm
    swap    d1
    dbf d6,HudDb_XYLoop
    rts
; End of function HudDb_XY
 
; ---------------------------------------------------------------------------
; Subroutine to load rings numbers patterns
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_4113C:
Hud_Rings:
    lea (Hud_100).l,a2
    moveq   #2,d6
    bra.s   Hud_LoadArt
; End of function Hud_Rings
 
; ---------------------------------------------------------------------------
; Subroutine to load score numbers patterns
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_41146:
Hud_Score:
    lea (Hud_100000).l,a2
    moveq   #5,d6
; loc_4114E:
Hud_LoadArt:
    moveq   #0,d4
    lea Art_Hud(pc),a1
; loc_41154:
Hud_ScoreLoop:
    moveq   #0,d2
    move.l  (a2)+,d3
 
loc_41158:
    sub.l   d3,d1
    bcs.s   loc_41160
    addq.w  #1,d2
    bra.s   loc_41158
; ===========================================================================
 
loc_41160:
    add.l   d3,d1
    tst.w   d2
    beq.s   loc_4116A
    move.w  #1,d4
 
loc_4116A:
    tst.w   d4
    beq.s   loc_41198
    lsl.w   #6,d2
    move.l  d0,4(a6)
    lea (a1,d2.w),a3
    rept 8*hud_letter_num_tiles
    move.l  (a3)+,(a6)
    endm
 
loc_41198:
    addi.l  #hud_letter_vdp_delta,d0
    dbf d6,Hud_ScoreLoop
    rts
; End of function Hud_Score
 
; ---------------------------------------------------------------------------
; Subroutine to load countdown numbers on the continue screen
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_411A4:
ContScrCounter:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ContinueCountdown),VRAM,WRITE),(VDP_control_port).l
    lea (VDP_data_port).l,a6
    lea (Hud_10).l,a2
    moveq   #1,d6
    moveq   #0,d4
    lea Art_Hud(pc),a1
; loc_411C2:
ContScr_Loop:
    moveq   #0,d2
    move.l  (a2)+,d3
 
loc_411C6:
    sub.l   d3,d1
    bcs.s   loc_411CE
    addq.w  #1,d2
    bra.s   loc_411C6
; ===========================================================================
 
loc_411CE:
    add.l   d3,d1
    lsl.w   #6,d2
    lea (a1,d2.w),a3
    rept 16
    move.l  (a3)+,(a6)
    endm
    dbf d6,ContScr_Loop ; repeat 1 more time
    rts
; End of function ContScrCounter
 
; ===========================================================================
; ---------------------------------------------------------------------------
; for HUD counter
; ---------------------------------------------------------------------------
                ; byte_411FC:
Hud_100000: dc.l 100000 ; byte_41200: ; Hud_10000:
        dc.l 10000  ; byte_41204:
Hud_1000:   dc.l 1000   ; byte_41208:
Hud_100:    dc.l 100    ; byte_4120C:
Hud_10:     dc.l 10     ; byte_41210:
Hud_1:      dc.l 1
 
; ---------------------------------------------------------------------------
; Subroutine to load time numbers patterns
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_41214:
Hud_Mins:
    lea_    Hud_1,a2
    moveq   #0,d6
    bra.s   loc_41222
; ===========================================================================
; loc_4121C:
Hud_Secs:
    lea_    Hud_10,a2
    moveq   #1,d6
 
loc_41222:
    moveq   #0,d4
    lea Art_Hud(pc),a1
; loc_41228:
Hud_TimeLoop:
    moveq   #0,d2
    move.l  (a2)+,d3
 
loc_4122C:
    sub.l   d3,d1
    bcs.s   loc_41234
    addq.w  #1,d2
    bra.s   loc_4122C
; ===========================================================================
 
loc_41234:
    add.l   d3,d1
    tst.w   d2
    beq.s   loc_4123E
    move.w  #1,d4
 
loc_4123E:
    lsl.w   #6,d2
    move.l  d0,4(a6)
    lea (a1,d2.w),a3
    rept 8*hud_letter_num_tiles
    move.l  (a3)+,(a6)
    endm
    addi.l  #hud_letter_vdp_delta,d0
    dbf d6,Hud_TimeLoop
    rts
; End of function Hud_Mins
 
; ---------------------------------------------------------------------------
; Subroutine to load time/ring bonus numbers patterns
; ---------------------------------------------------------------------------
 
; ===========================================================================
; loc_41274:
Hud_TimeRingBonus:
    lea_    Hud_1000,a2
    moveq   #3,d6
    moveq   #0,d4
    lea Art_Hud(pc),a1
; loc_41280:
Hud_BonusLoop:
    moveq   #0,d2
    move.l  (a2)+,d3
 
loc_41284:
    sub.l   d3,d1
    bcs.s   loc_4128C
    addq.w  #1,d2
    bra.s   loc_41284
; ===========================================================================
 
loc_4128C:
    add.l   d3,d1
    tst.w   d2
    beq.s   loc_41296
    move.w  #1,d4
 
loc_41296:
    tst.w   d4
    beq.s   Hud_ClrBonus
    lsl.w   #6,d2
    lea (a1,d2.w),a3
    rept 8*hud_letter_num_tiles
    move.l  (a3)+,(a6)
    endm
 
loc_412C0:
    dbf d6,Hud_BonusLoop ; repeat 3 more times
    rts
; ===========================================================================
; loc_412C6:
Hud_ClrBonus:
    moveq   #8*hud_letter_num_tiles-1,d5
; loc_412C8:
Hud_ClrBonusLoop:
    move.l  #0,(a6)
    dbf d5,Hud_ClrBonusLoop
    bra.s   loc_412C0
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; ---------------------------------------------------------------------------
; Subroutine to load uncompressed lives counter patterns (Sonic)
; ---------------------------------------------------------------------------
 
; sub_412D4:
Hud_Lives2:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtUnc_2p_life_counter_lives),VRAM,WRITE),d0
    moveq   #0,d1
    move.b  (Life_count_2P).w,d1
    bra.s   loc_412EE
; End of function Hud_Lives2
 
; ---------------------------------------------------------------------------
; Subroutine to load uncompressed lives counter patterns (Tails)
; ---------------------------------------------------------------------------
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_412E2:
Hud_Lives:
    move.l  #vdpComm(tiles_to_bytes(ArtTile_ArtNem_life_counter_lives),VRAM,WRITE),d0
    moveq   #0,d1
    move.b  (Life_count).w,d1
 
loc_412EE:
    lea_    Hud_10,a2
    moveq   #1,d6
    moveq   #0,d4
    lea Art_LivesNums(pc),a1
; loc_412FA:
Hud_LivesLoop:
    move.l  d0,4(a6)
    moveq   #0,d2
    move.l  (a2)+,d3
-   sub.l   d3,d1
    bcs.s   loc_4130A
    addq.w  #1,d2
    bra.s   -
; ===========================================================================
 
loc_4130A:
    add.l   d3,d1
    tst.w   d2
    beq.s   loc_41314
    move.w  #1,d4
 
loc_41314:
    tst.w   d4
    beq.s   Hud_ClrLives
 
loc_41318:
    lsl.w   #5,d2
    lea (a1,d2.w),a3
    rept 8
    move.l  (a3)+,(a6)
    endm
 
loc_4132E:
    addi.l  #hud_letter_vdp_delta,d0
    dbf d6,Hud_LivesLoop ; repeat 1 more time
    rts
; ===========================================================================
; loc_4133A:
Hud_ClrLives:
    tst.w   d6
    beq.s   loc_41318
    moveq   #7,d5
; loc_41340:
Hud_ClrLivesLoop:
    move.l  #0,(a6)
    dbf d5,Hud_ClrLivesLoop
    bra.s   loc_4132E
; End of function Hud_Lives
 
; ===========================================================================
; ArtUnc_4134C:
Art_Hud:    BINCLUDE    "art/uncompressed/Big and small numbers used on counters - 1.bin"
; ArtUnc_4164C:
Art_LivesNums:  BINCLUDE    "art/uncompressed/Big and small numbers used on counters - 2.bin"
; ArtUnc_4178C:
Art_Text:   BINCLUDE    "art/uncompressed/Big and small numbers used on counters - 3.bin"
 
    if ~~removeJmpTos
JmpTo_DrawSprite_2P_Loop 
    jmp (DrawSprite_2P_Loop).l
JmpTo_DrawSprite_Loop 
    jmp (DrawSprite_Loop).l
 
    align 4
    endif
 
 
 
 
; ===========================================================================
; ---------------------------------------------------------------------------
; When debug mode is currently in use
; ---------------------------------------------------------------------------
; loc_41A78:
DebugMode:
    moveq   #0,d0
    move.b  (Debug_placement_mode).w,d0
    move.w  Debug_Index(pc,d0.w),d1
    jmp Debug_Index(pc,d1.w)
; ===========================================================================
; off_41A86:
Debug_Index:    offsetTable
        offsetTableEntry.w Debug_Init   ; 0
        offsetTableEntry.w Debug_Main   ; 2
; ===========================================================================
; loc_41A8A: Debug_Main:
Debug_Init:
    addq.b  #2,(Debug_placement_mode).w
    move.w  (Camera_Min_Y_pos).w,(Camera_Min_Y_pos_Debug_Copy).w
    move.w  (Camera_Max_Y_pos).w,(Camera_Max_Y_pos_Debug_Copy).w
    cmpi.b  #sky_chase_zone,(Current_Zone).w
    bne.s   +
    move.w  #0,(Camera_Min_X_pos).w
    move.w  #$3FFF,(Camera_Max_X_pos).w
+
    andi.w  #$7FF,(MainCharacter+y_pos).w
    andi.w  #$7FF,(Camera_Y_pos).w
    andi.w  #$7FF,(Camera_BG_Y_pos).w
    clr.b   (Scroll_lock).w
    move.b  #0,mapping_frame(a0)
    move.b  #AniIDSonAni_Walk,anim(a0)
    ; S1 leftover
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w ; special stage mode? (you can't enter debug mode in S2's special stage)
    bne.s   .islevel    ; if not, branch
    moveq   #6,d0       ; force zone 6's debug object list (was the ending in S1)
    bra.s   .selectlist
; ===========================================================================
.islevel:
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
 
.selectlist:
    lea (JmpTbl_DbgObjLists).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d6
    cmp.b   (Debug_object).w,d6
    bhi.s   +
    move.b  #0,(Debug_object).w
+
    bsr.w   LoadDebugObjectSprite
    move.b  #$C,(Debug_Accel_Timer).w
    move.b  #1,(Debug_Speed).w
; loc_41B0C:
Debug_Main:
    ; S1 leftover
    moveq   #6,d0       ; force zone 6's debug object list (was the ending in S1)
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w  ; special stage mode? (you can't enter debug mode in S2's special stage)
    beq.s   .isntlevel  ; if yes, branch
 
    moveq   #0,d0
    move.b  (Current_Zone).w,d0
 
.isntlevel:
    lea (JmpTbl_DbgObjLists).l,a2
    add.w   d0,d0
    adda.w  (a2,d0.w),a2
    move.w  (a2)+,d6
    bsr.w   Debug_Control
    jmp (DisplaySprite).l
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_41B34:
Debug_Control:
;Debug_ControlMovement:
    moveq   #0,d4
    move.w  #1,d1
    move.b  (Ctrl_1_Press).w,d4
    andi.w  #button_up_mask|button_down_mask|button_left_mask|button_right_mask,d4
    bne.s   Debug_Move
    move.b  (Ctrl_1_Held).w,d0
    andi.w  #button_up_mask|button_down_mask|button_left_mask|button_right_mask,d0
    bne.s   Debug_ContinueMoving
    move.b  #$C,(Debug_Accel_Timer).w
    move.b  #$F,(Debug_Speed).w
    bra.w   Debug_ControlObjects
; ===========================================================================
; loc_41B5E:
Debug_ContinueMoving:
    subq.b  #1,(Debug_Accel_Timer).w
    bne.s   Debug_TimerNotOver
    move.b  #1,(Debug_Accel_Timer).w
    addq.b  #1,(Debug_Speed).w
    bne.s   Debug_Move
    move.b  #-1,(Debug_Speed).w
; loc_41B76:
Debug_Move:
    move.b  (Ctrl_1_Held).w,d4
; loc_41B7A:
Debug_TimerNotOver:
    moveq   #0,d1
    move.b  (Debug_Speed).w,d1
    addq.w  #1,d1
    swap    d1
    asr.l   #4,d1
    move.l  y_pos(a0),d2
    move.l  x_pos(a0),d3
 
    ; Move up
    btst    #button_up,d4
    beq.s   .upNotHeld
    sub.l   d1,d2
    moveq   #0,d0
    move.w  (Camera_Min_Y_pos).w,d0
    swap    d0
    cmp.l   d0,d2
    bge.s   .minYPosNotReached
    move.l  d0,d2
.minYPosNotReached:
; loc_41BA4:
.upNotHeld:
    ; Move down
    btst    #button_down,d4
    beq.s   .downNotHeld
    add.l   d1,d2
    moveq   #0,d0
    move.w  (Camera_Max_Y_pos).w,d0
    addi.w  #224-1,d0
    swap    d0
    cmp.l   d0,d2
    blt.s   .maxYPosNotReached
    move.l  d0,d2
.maxYPosNotReached:
; loc_41BBE:
.downNotHeld:
    ; Move left
    btst    #button_left,d4
    beq.s   .leftNotHeld
    sub.l   d1,d3
    bcc.s   .minXPosNotReached
    moveq   #0,d3
.minXPosNotReached:
; loc_41BCA:
.leftNotHeld:
    ; Move right
    btst    #button_right,d4
    beq.s   .rightNotHeld
    add.l   d1,d3
; loc_41BD2:
.rightNotHeld:
    move.l  d2,y_pos(a0)
    move.l  d3,x_pos(a0)
; loc_41BDA:
Debug_ControlObjects:
;Debug_CycleObjectsBackwards:
    btst    #button_A,(Ctrl_1_Held).w
    beq.s   Debug_SpawnObject
    btst    #button_C,(Ctrl_1_Press).w
    beq.s   Debug_CycleObjects
    ; Cycle backwards though object list
    subq.b  #1,(Debug_object).w
    bcc.s   BranchTo_LoadDebugObjectSprite
    add.b   d6,(Debug_object).w
    bra.s   BranchTo_LoadDebugObjectSprite
; ===========================================================================
; loc_41BF6:
Debug_CycleObjects:
    btst    #button_A,(Ctrl_1_Press).w
    beq.s   Debug_SpawnObject
    ; Cycle forwards though object list
    addq.b  #1,(Debug_object).w
    cmp.b   (Debug_object).w,d6
    bhi.s   BranchTo_LoadDebugObjectSprite
    move.b  #0,(Debug_object).w
 
BranchTo_LoadDebugObjectSprite 
    bra.w   LoadDebugObjectSprite
; ===========================================================================
; loc_41C12:
Debug_SpawnObject:
    btst    #button_C,(Ctrl_1_Press).w
    beq.s   Debug_ExitDebugMode
    ; Spawn object
    jsr (SingleObjLoad).l
    bne.s   Debug_ExitDebugMode
    move.w  x_pos(a0),x_pos(a1)
    move.w  y_pos(a0),y_pos(a1)
    _move.b mappings(a0),id(a1) ; load obj
    move.b  render_flags(a0),render_flags(a1)
    move.b  render_flags(a0),status(a1)
    andi.b  #$7F,status(a1)
    moveq   #0,d0
    move.b  (Debug_object).w,d0
    lsl.w   #3,d0
    move.b  4(a2,d0.w),subtype(a1)
    rts
; ===========================================================================
; loc_41C56:
Debug_ExitDebugMode:
    btst    #button_B,(Ctrl_1_Press).w
    beq.s   return_41CB6
    ; Exit debug mode
    moveq   #0,d0
    move.w  d0,(Debug_placement_mode).w
    lea (MainCharacter).w,a1 ; a1=character
    move.l  #Mapunc_Sonic,mappings(a1)
    move.w  #make_art_tile(ArtTile_ArtUnc_Sonic,0,0),art_tile(a1)
    tst.w   (Two_player_mode).w
    beq.s   .notTwoPlayerMode
    move.w  #make_art_tile_2p(ArtTile_ArtUnc_Sonic,0,0),art_tile(a1)
; loc_41C82:
.notTwoPlayerMode:
    bsr.s   sub_41CB8
    move.b  #$13,y_radius(a1)
    move.b  #9,x_radius(a1)
    move.w  (Camera_Min_Y_pos_Debug_Copy).w,(Camera_Min_Y_pos).w
    move.w  (Camera_Max_Y_pos_Debug_Copy).w,(Camera_Max_Y_pos).w
    ; useless leftover; this is for S1's special stage
    cmpi.b  #GameModeID_SpecialStage,(Game_Mode).w  ; special stage mode?
    bne.s   return_41CB6        ; if not, branch
    move.b  #AniIDSonAni_Roll,(MainCharacter+anim).w
    bset    #2,(MainCharacter+status).w
    bset    #1,(MainCharacter+status).w
 
return_41CB6:
    rts
; End of function Debug_Control
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_41CB8:
    move.b  d0,anim(a1)
    move.w  d0,2+x_pos(a1) ; subpixel x
    move.w  d0,2+y_pos(a1) ; subpixel y
    move.b  d0,obj_control(a1)
    move.b  d0,spindash_flag(a1)
    move.w  d0,x_vel(a1)
    move.w  d0,y_vel(a1)
    move.w  d0,inertia(a1)
    move.b  #2,status(a1)
    move.b  #2,routine(a1)
    move.b  #0,routine_secondary(a1)
    rts
; End of function sub_41CB8
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
; sub_41CEC:
LoadDebugObjectSprite:
    moveq   #0,d0
    move.b  (Debug_object).w,d0
    lsl.w   #3,d0
    move.l  (a2,d0.w),mappings(a0)
    move.w  6(a2,d0.w),art_tile(a0)
    move.b  5(a2,d0.w),mapping_frame(a0)
    jsrto   (Adjust2PArtPointer).l, JmpTo66_Adjust2PArtPointer
    rts
; End of function LoadDebugObjectSprite
 
; ===========================================================================
; ---------------------------------------------------------------------------
; OBJECT DEBUG LISTS
 
; The jump table goes by level ID, so Metropolis Zone's list is repeated to
; account for its third act. Hidden Palace Zone uses Oil Ocean Zone's list.
; ---------------------------------------------------------------------------
JmpTbl_DbgObjLists: zoneOrderedOffsetTable 2,1
    zoneOffsetTableEntry.w DbgObjList_EHZ   ; 0
    zoneOffsetTableEntry.w DbgObjList_Def   ; 1
    zoneOffsetTableEntry.w DbgObjList_Def   ; 2
    zoneOffsetTableEntry.w DbgObjList_Def   ; 3
    zoneOffsetTableEntry.w DbgObjList_MTZ   ; 4
    zoneOffsetTableEntry.w DbgObjList_MTZ   ; 5
    zoneOffsetTableEntry.w DbgObjList_WFZ   ; 6
    zoneOffsetTableEntry.w DbgObjList_HTZ   ; 7
    zoneOffsetTableEntry.w DbgObjList_HPZ   ; 8
    zoneOffsetTableEntry.w DbgObjList_Def   ; 9
    zoneOffsetTableEntry.w DbgObjList_OOZ   ; $A
    zoneOffsetTableEntry.w DbgObjList_MCZ   ; $B
    zoneOffsetTableEntry.w DbgObjList_CNZ   ; $C
    zoneOffsetTableEntry.w DbgObjList_CPZ   ; $D
    zoneOffsetTableEntry.w DbgObjList_Def   ; $E
    zoneOffsetTableEntry.w DbgObjList_ARZ   ; $F
    zoneOffsetTableEntry.w DbgObjList_SCZ   ; $10
    zoneTableEnd
 
; macro for a debug object list header
; must be on the same line as a label that has a corresponding _End label later
dbglistheader macro {INTLABEL}
__LABEL__ label *
    dc.w ((__LABEL___End - __LABEL__ - 2) >> 3)
    endm
 
; macro to define debug list object data
dbglistobj macro   obj, mapaddr, subtype, frame, vram
    dc.l obj<<24|mapaddr
    dc.b subtype,frame
    dc.w vram
    endm
 
DbgObjList_Def: dbglistheader
    dbglistobj ObjID_Ring, Obj25_MapUnc_12382,   0,   0, make_art_tile(ArtTile_ArtNem_Ring,1,0) ; obj25 = ring
    dbglistobj ObjID_Monitor, Obj26_MapUnc_12D36,   8,   0, make_art_tile(ArtTile_ArtNem_Powerups,0,0) ; obj26 = monitor
; dbglistheader
;   dbglistobj ObjID_Ring, Obj25_MapUnc_12382,   0,   0, make_art_tile(ArtTile_ArtNem_Ring,1,0)
;   dbglistobj ObjID_Monitor, Obj26_MapUnc_12D36,   8,   0, make_art_tile(ArtTile_ArtNem_Powerups,0,0)
;DbgObjList_HPZ_End
; ---------------------------------------------------------------------------
; "MAIN LEVEL LOAD BLOCK" (after Nemesis)
;
; This struct array tells the engine where to find all the art associated with
; a particular zone. Each zone gets three longwords, in which it stores three
; pointers (in the lower 24 bits) and three jump table indeces (in the upper eight
; bits). The assembled data looks something like this:
;
; aaBBBBBB
; ccDDDDDD
; eeFFFFFF
;
; aa = index for primary pattern load request list
; BBBBBB = pointer to level art
; cc = index for secondary pattern load request list
; DDDDDD = pointer to 16x16 block mappings
; ee = index for palette
; FFFFFF = pointer to 128x128 block mappings
;
; Nemesis refers to this as the "main level load block". However, that name implies
; that this is code (obviously, it isn't), or at least that it points to the level's
; collision, object and ring placement arrays (it only points to art...
; although the 128x128 mappings do affect the actual level layout and collision)
; ---------------------------------------------------------------------------
 
; declare some global variables to be used by the levartptrs macro
cur_zone_id := 0
cur_zone_str := "0"
 
; macro for declaring a "main level load block" (MLLB)
levartptrs macro plc1,plc2,palette,art,map16x16,map128x128
    !org LevelArtPointers+zone_id_{cur_zone_str}*12
    dc.l (plc1<<24)|art
    dc.l (plc2<<24)|map16x16
    dc.l (palette<<24)|map128x128
cur_zone_id := cur_zone_id+1
cur_zone_str := "\{cur_zone_id}"
    endm
 
; BEGIN SArt_Ptrs Art_Ptrs_Array[17]
; dword_42594: MainLoadBlocks: saArtPtrs:
LevelArtPointers:
    levartptrs PLCID_Ehz1,     PLCID_Ehz2,      PalID_EHZ,  ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   0 ; EHZ  ; EMERALD HILL ZONE
    levartptrs PLCID_Miles1up, PLCID_MilesLife, PalID_EHZ2, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   1 ; LEV1 ; LEVEL 1 (UNUSED)
    levartptrs PLCID_Tails1up, PLCID_TailsLife, PalID_WZ,   ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   2 ; LEV2 ; LEVEL 2 (UNUSED)
    levartptrs PLCID_Unused1,  PLCID_Unused2,   PalID_EHZ3, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   3 ; LEV3 ; LEVEL 3 (UNUSED)
    levartptrs PLCID_Mtz1,     PLCID_Mtz2,      PalID_MTZ,  ArtKos_MTZ, BM16_MTZ, BM128_MTZ ;   4 ; MTZ  ; METROPOLIS ZONE ACTS 1 & 2
    levartptrs PLCID_Mtz1,     PLCID_Mtz2,      PalID_MTZ,  ArtKos_MTZ, BM16_MTZ, BM128_MTZ ;   5 ; MTZ3 ; METROPOLIS ZONE ACT 3
    levartptrs PLCID_Wfz1,     PLCID_Wfz2,      PalID_WFZ,  ArtKos_SCZ, BM16_WFZ, BM128_WFZ ;   6 ; WFZ  ; WING FORTRESS ZONE
    levartptrs PLCID_Htz1,     PLCID_Htz2,      PalID_HTZ,  ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   7 ; HTZ  ; HILL TOP ZONE
    levartptrs PLCID_Hpz1,     PLCID_Hpz2,      PalID_HPZ,  ArtKos_HPZ, BM16_HPZ, BM128_HPZ ;   8 ; HPZ  ; HIDDEN PALACE ZONE (UNUSED)
    levartptrs PLCID_Unused3,  PLCID_Unused4,   PalID_EHZ4, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ;   9 ; LEV9 ; LEVEL 9 (UNUSED)
    levartptrs PLCID_Ooz1,     PLCID_Ooz2,      PalID_OOZ,  ArtKos_OOZ, BM16_OOZ, BM128_OOZ ;  $A ; OOZ  ; OIL OCEAN ZONE
    levartptrs PLCID_Mcz1,     PLCID_Mcz2,      PalID_MCZ,  ArtKos_MCZ, BM16_MCZ, BM128_MCZ ;  $B ; MCZ  ; MYSTIC CAVE ZONE
    levartptrs PLCID_Cnz1,     PLCID_Cnz2,      PalID_CNZ,  ArtKos_CNZ, BM16_CNZ, BM128_CNZ ;  $C ; CNZ  ; CASINO NIGHT ZONE
    levartptrs PLCID_Cpz1,     PLCID_Cpz2,      PalID_CPZ,  ArtKos_CPZ, BM16_CPZ, BM128_CPZ ;  $D ; CPZ  ; CHEMICAL PLANT ZONE
    levartptrs PLCID_Dez1,     PLCID_Dez2,      PalID_DEZ,  ArtKos_CPZ, BM16_CPZ, BM128_CPZ ;  $E ; DEZ  ; DEATH EGG ZONE
    levartptrs PLCID_Arz1,     PLCID_Arz2,      PalID_ARZ,  ArtKos_ARZ, BM16_ARZ, BM128_ARZ ;  $F ; ARZ  ; AQUATIC RUIN ZONE
    levartptrs PLCID_Scz1,     PLCID_Scz2,      PalID_SCZ,  ArtKos_SCZ, BM16_WFZ, BM128_WFZ ; $10 ; SCZ  ; SKY CHASE ZONE
 
    if (cur_zone_id<>no_of_zones)&&(MOMPASS=1)
    message "Warning: Table LevelArtPointers has \{cur_zone_id/1.0} entries, but it should have \{no_of_zones/1.0} entries"
    endif
    !org LevelArtPointers+cur_zone_id*12
 
; ---------------------------------------------------------------------------
; END Art_Ptrs_Array[17]
 
 
 
 
; ---------------------------------------------------------------------------
; PATTERN LOAD REQUEST LISTS
;
; Pattern load request lists are simple structures used to load
; Nemesis-compressed art for sprites.
;
; The decompressor predictably moves down the list, so request 0 is processed first, etc.
; This only matters if your addresses are bad and you overwrite art loaded in a previous request.
;
 
; NOTICE: The load queue buffer can only hold $10 (16) load requests. None of the routines
; that load PLRs into the queue do any bounds checking, so it's possible to create a buffer
; overflow and completely screw up the variables stored directly after the queue buffer.
; (in my experience this is a guaranteed crash or hang)
;
; Many levels queue more than 16 items overall,
; but they don't exceed the limit because
; their PLRs are split into multiple parts (like PlrList_Mtz1 and PlrList_Mtz2)
; and they fully process the first part before requesting the rest.
; 
; If you can find some extra RAM for it (which is easy in Sonic 2),
; you can increase this limit by increasing the size of Plc_Buffer.
; ---------------------------------------------------------------------------
 
;---------------------------------------------------------------------------------------
; Table of pattern load request lists. Remember to use word-length data when adding lists
; otherwise you'll break the array.
;---------------------------------------------------------------------------------------
; word_42660 ; OffInd_PlrLists:
ArtLoadCues:        offsetTable
PLCptr_Std1:        offsetTableEntry.w PlrList_Std1         ; 0
PLCptr_Std2:        offsetTableEntry.w PlrList_Std2         ; 1
PLCptr_StdWtr:      offsetTableEntry.w PlrList_StdWtr       ; 2
PLCptr_GameOver:    offsetTableEntry.w PlrList_GameOver     ; 3
PLCptr_Ehz1:        offsetTableEntry.w PlrList_Ehz1         ; 4
PLCptr_Ehz2:        offsetTableEntry.w PlrList_Ehz2         ; 5
PLCptr_Miles1up:    offsetTableEntry.w PlrList_Miles1up     ; 6
PLCptr_MilesLife:   offsetTableEntry.w PlrList_MilesLifeCounter ; 7
PLCptr_Tails1up:    offsetTableEntry.w PlrList_Tails1up     ; 8
PLCptr_TailsLife:   offsetTableEntry.w PlrList_TailsLifeCounter ; 9
PLCptr_Unused1:     offsetTableEntry.w PlrList_Mtz1         ; 10
PLCptr_Unused2:     offsetTableEntry.w PlrList_Mtz1         ; 11
PLCptr_Mtz1:        offsetTableEntry.w PlrList_Mtz1         ; 12
PLCptr_Mtz2:        offsetTableEntry.w PlrList_Mtz2         ; 13
            offsetTableEntry.w PlrList_Wfz1         ; 14
            offsetTableEntry.w PlrList_Wfz1         ; 15
PLCptr_Wfz1:        offsetTableEntry.w PlrList_Wfz1         ; 16
PLCptr_Wfz2:        offsetTableEntry.w PlrList_Wfz2         ; 17
PLCptr_Htz1:        offsetTableEntry.w PlrList_Htz1         ; 18
PLCptr_Htz2:        offsetTableEntry.w PlrList_Htz2         ; 19
PLCptr_Hpz1:        offsetTableEntry.w PlrList_Hpz1         ; 20
PLCptr_Hpz2:        offsetTableEntry.w PlrList_Hpz2         ; 21
PLCptr_Unused3:     offsetTableEntry.w PlrList_Ooz1         ; 22
PLCptr_Unused4:     offsetTableEntry.w PlrList_Ooz1         ; 23
PLCptr_Ooz1:        offsetTableEntry.w PlrList_Ooz1         ; 24
PLCptr_Ooz2:        offsetTableEntry.w PlrList_Ooz2         ; 25
PLCptr_Mcz1:        offsetTableEntry.w PlrList_Mcz1         ; 26
PLCptr_Mcz2:        offsetTableEntry.w PlrList_Mcz2         ; 27
PLCptr_Cnz1:        offsetTableEntry.w PlrList_Cnz1         ; 28
PLCptr_Cnz2:        offsetTableEntry.w PlrList_Cnz2         ; 29
PLCptr_Cpz1:        offsetTableEntry.w PlrList_Cpz1         ; 30
PLCptr_Cpz2:        offsetTableEntry.w PlrList_Cpz2         ; 31
PLCptr_Dez1:        offsetTableEntry.w PlrList_Dez1         ; 32
PLCptr_Dez2:        offsetTableEntry.w PlrList_Dez2         ; 33
PLCptr_Arz1:        offsetTableEntry.w PlrList_Arz1         ; 34
PLCptr_Arz2:        offsetTableEntry.w PlrList_Arz2         ; 35
PLCptr_Scz1:        offsetTableEntry.w PlrList_Scz1         ; 36
PLCptr_Scz2:        offsetTableEntry.w PlrList_Scz2         ; 37
PLCptr_Results:     offsetTableEntry.w PlrList_Results      ; 38
PLCptr_Signpost:    offsetTableEntry.w PlrList_Signpost     ; 39
PLCptr_CpzBoss:     offsetTableEntry.w PlrList_CpzBoss      ; 40
PLCptr_EhzBoss:     offsetTableEntry.w PlrList_EhzBoss      ; 41
PLCptr_HtzBoss:     offsetTableEntry.w PlrList_HtzBoss      ; 42
PLCptr_ArzBoss:     offsetTableEntry.w PlrList_ArzBoss      ; 43
PLCptr_MczBoss:     offsetTableEntry.w PlrList_MczBoss      ; 44
PLCptr_CnzBoss:     offsetTableEntry.w PlrList_CnzBoss      ; 45
PLCptr_MtzBoss:     offsetTableEntry.w PlrList_MtzBoss      ; 46
PLCptr_OozBoss:     offsetTableEntry.w PlrList_OozBoss      ; 47
PLCptr_FieryExplosion:  offsetTableEntry.w PlrList_FieryExplosion   ; 48
PLCptr_DezBoss:     offsetTableEntry.w PlrList_DezBoss      ; 49
PLCptr_EhzAnimals:  offsetTableEntry.w PlrList_EhzAnimals       ; 50
PLCptr_MczAnimals:  offsetTableEntry.w PlrList_MczAnimals       ; 51
PLCptr_HtzAnimals:
PLCptr_MtzAnimals:
PLCptr_WfzAnimals:  offsetTableEntry.w PlrList_WfzAnimals       ; 52
PLCptr_DezAnimals:  offsetTableEntry.w PlrList_DezAnimals       ; 53
PLCptr_HpzAnimals:  offsetTableEntry.w PlrList_HpzAnimals       ; 54
PLCptr_OozAnimals:  offsetTableEntry.w PlrList_OozAnimals       ; 55
PLCptr_SczAnimals:  offsetTableEntry.w PlrList_SczAnimals       ; 56
PLCptr_CnzAnimals:  offsetTableEntry.w PlrList_CnzAnimals       ; 57
PLCptr_CpzAnimals:  offsetTableEntry.w PlrList_CpzAnimals       ; 58
PLCptr_ArzAnimals:  offsetTableEntry.w PlrList_ArzAnimals       ; 59
PLCptr_SpecialStage:    offsetTableEntry.w PlrList_SpecialStage     ; 60
PLCptr_SpecStageBombs:  offsetTableEntry.w PlrList_SpecStageBombs   ; 61
PLCptr_WfzBoss:     offsetTableEntry.w PlrList_WfzBoss      ; 62
PLCptr_Tornado:     offsetTableEntry.w PlrList_Tornado      ; 63
PLCptr_Capsule:     offsetTableEntry.w PlrList_Capsule      ; 64
PLCptr_Explosion:   offsetTableEntry.w PlrList_Explosion        ; 65
PLCptr_ResultsTails:    offsetTableEntry.w PlrList_ResultsTails     ; 66
 
; macro for a pattern load request list header
; must be on the same line as a label that has a corresponding _End label later
plrlistheader macro {INTLABEL}
__LABEL__ label *
    dc.w (((__LABEL___End - __LABEL__Plc) / 6) - 1)
__LABEL__Plc:
    endm
 
; macro for a pattern load request
plreq macro toVRAMaddr,fromROMaddr
    dc.l    fromROMaddr
    dc.w    tiles_to_bytes(toVRAMaddr)
    endm
 
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Standard 1 - loaded for every level
;---------------------------------------------------------------------------------------
PlrList_Std1: plrlistheader
    plreq ArtTile_ArtNem_HUD, ArtNem_HUD
    plreq ArtTile_ArtNem_life_counter, ArtNem_Sonic_life_counter
    plreq ArtTile_ArtNem_Ring, ArtNem_Ring
    plreq ArtTile_ArtNem_Numbers, ArtNem_Numbers
PlrList_Std1_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Standard 2 - loaded for every level
;---------------------------------------------------------------------------------------
PlrList_Std2: plrlistheader
    plreq ArtTile_ArtNem_Checkpoint, ArtNem_Checkpoint
    plreq ArtTile_ArtNem_Powerups, ArtNem_Powerups
    plreq ArtTile_ArtNem_Shield, ArtNem_Shield
    plreq ArtTile_ArtNem_Invincible_stars, ArtNem_Invincible_stars
PlrList_Std2_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Aquatic level standard
;---------------------------------------------------------------------------------------
PlrList_StdWtr: plrlistheader
    plreq ArtTile_ArtNem_Explosion, ArtNem_Explosion
    plreq ArtTile_ArtNem_SuperSonic_stars, ArtNem_SuperSonic_stars
    plreq ArtTile_ArtNem_Bubbles, ArtNem_Bubbles
PlrList_StdWtr_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Game/Time over
;---------------------------------------------------------------------------------------
PlrList_GameOver: plrlistheader
    plreq ArtTile_ArtNem_Game_Over, ArtNem_Game_Over
PlrList_GameOver_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Emerald Hill Zone primary
;---------------------------------------------------------------------------------------
PlrList_Ehz1: plrlistheader
    plreq ArtTile_ArtNem_Waterfall, ArtNem_Waterfall
    plreq ArtTile_ArtNem_EHZ_Bridge, ArtNem_EHZ_Bridge
    plreq ArtTile_ArtNem_Buzzer_Fireball_2, ArtNem_Buzzer_Fireball
    plreq ArtTile_ArtNem_Buzzer, ArtNem_Buzzer
    plreq ArtTile_ArtNem_Coconuts, ArtNem_Coconuts
    plreq ArtTile_ArtNem_Masher, ArtNem_Masher
PlrList_Ehz1_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Emerald Hill Zone secondary
;---------------------------------------------------------------------------------------
PlrList_Ehz2: plrlistheader
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_DignlSprng, ArtNem_DignlSprng
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Ehz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Miles 1up patch
;---------------------------------------------------------------------------------------
PlrList_Miles1up: plrlistheader
    plreq ArtTile_ArtUnc_2p_life_counter, ArtUnc_MilesLife
PlrList_Miles1up_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Miles life counter
;---------------------------------------------------------------------------------------
PlrList_MilesLifeCounter: plrlistheader
    plreq ArtTile_ArtNem_life_counter, ArtUnc_MilesLife
PlrList_MilesLifeCounter_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Tails 1up patch
;---------------------------------------------------------------------------------------
PlrList_Tails1up: plrlistheader
    plreq ArtTile_ArtUnc_2p_life_counter, ArtNem_TailsLife
PlrList_Tails1up_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Tails life counter
;---------------------------------------------------------------------------------------
PlrList_TailsLifeCounter: plrlistheader
    plreq ArtTile_ArtNem_life_counter, ArtNem_TailsLife
PlrList_TailsLifeCounter_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Metropolis Zone primary
;---------------------------------------------------------------------------------------
PlrList_Mtz1: plrlistheader
    plreq ArtTile_ArtNem_MtzWheel, ArtNem_MtzWheel
    plreq ArtTile_ArtNem_MtzWheelIndent, ArtNem_MtzWheelIndent
    plreq ArtTile_ArtNem_LavaCup, ArtNem_LavaCup
    plreq ArtTile_ArtNem_BoltEnd_Rope, ArtNem_BoltEnd_Rope
    plreq ArtTile_ArtNem_MtzSteam, ArtNem_MtzSteam
    plreq ArtTile_ArtNem_MtzSpikeBlock, ArtNem_MtzSpikeBlock
    plreq ArtTile_ArtNem_MtzSpike, ArtNem_MtzSpike
    plreq ArtTile_ArtNem_Crabmeat, ArtNem_Crabmeat
    plreq ArtTile_ArtNem_MtzSupernova, ArtNem_MtzSupernova
PlrList_Mtz1_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Metropolis Zone secondary
;---------------------------------------------------------------------------------------
PlrList_Mtz2: plrlistheader
    plreq ArtTile_ArtNem_Button, ArtNem_Button
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_MtzMantis, ArtNem_MtzMantis
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
    plreq ArtTile_ArtNem_MtzAsstBlocks, ArtNem_MtzAsstBlocks
    plreq ArtTile_ArtNem_MtzLavaBubble, ArtNem_MtzLavaBubble
    plreq ArtTile_ArtNem_MtzCog, ArtNem_MtzCog
    plreq ArtTile_ArtNem_MtzSpinTubeFlash, ArtNem_MtzSpinTubeFlash
PlrList_Mtz2_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Wing Fortress Zone primary
;---------------------------------------------------------------------------------------
PlrList_Wfz1: plrlistheader
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
    plreq ArtTile_ArtNem_WfzVrtclPrpllr, ArtNem_WfzVrtclPrpllr
    plreq ArtTile_ArtNem_WfzHrzntlPrpllr, ArtNem_WfzHrzntlPrpllr
    plreq ArtTile_ArtNem_Balkrie, ArtNem_Balkrie
    plreq ArtTile_ArtNem_BreakPanels, ArtNem_BreakPanels
    plreq ArtTile_ArtNem_WfzScratch, ArtNem_WfzScratch
    plreq ArtTile_ArtNem_WfzTiltPlatforms, ArtNem_WfzTiltPlatforms
    ; These two are already in the list, so this is redundant
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
PlrList_Wfz1_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Wing Fortress Zone secondary
;---------------------------------------------------------------------------------------
PlrList_Wfz2: plrlistheader
    plreq ArtTile_ArtNem_WfzVrtclPrpllr, ArtNem_WfzVrtclPrpllr
    plreq ArtTile_ArtNem_WfzHrzntlPrpllr, ArtNem_WfzHrzntlPrpllr
    plreq ArtTile_ArtNem_WfzVrtclLazer, ArtNem_WfzVrtclLazer
    plreq ArtTile_ArtNem_WfzWallTurret, ArtNem_WfzWallTurret
    plreq ArtTile_ArtNem_WfzHrzntlLazer, ArtNem_WfzHrzntlLazer
    plreq ArtTile_ArtNem_WfzConveyorBeltWheel, ArtNem_WfzConveyorBeltWheel
    plreq ArtTile_ArtNem_WfzHook, ArtNem_WfzHook
    plreq ArtTile_ArtNem_WfzThrust, ArtNem_WfzThrust
    plreq ArtTile_ArtNem_WfzBeltPlatform, ArtNem_WfzBeltPlatform
    plreq ArtTile_ArtNem_WfzGunPlatform, ArtNem_WfzGunPlatform
    plreq ArtTile_ArtNem_WfzUnusedBadnik, ArtNem_WfzUnusedBadnik
    plreq ArtTile_ArtNem_WfzLaunchCatapult, ArtNem_WfzLaunchCatapult
    plreq ArtTile_ArtNem_WfzSwitch, ArtNem_WfzSwitch
    plreq ArtTile_ArtNem_WfzFloatingPlatform, ArtNem_WfzFloatingPlatform
PlrList_Wfz2_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Hill Top Zone primary
;---------------------------------------------------------------------------------------
PlrList_Htz1: plrlistheader
    plreq ArtTile_ArtNem_Buzzer_Fireball_1, ArtNem_Buzzer_Fireball
    plreq ArtTile_ArtNem_HtzRock, ArtNem_HtzRock
    plreq ArtTile_ArtNem_HtzSeeSaw, ArtNem_HtzSeeSaw
    plreq ArtTile_ArtNem_Sol, ArtNem_Sol
    plreq ArtTile_ArtNem_Rexon, ArtNem_Rexon
    plreq ArtTile_ArtNem_Spiker, ArtNem_Spiker
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_DignlSprng, ArtNem_DignlSprng
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Htz1_End
;---------------------------------------------------------------------------------------
; PATTERN LOAD REQUEST LIST
; Hill Top Zone secondary
;---------------------------------------------------------------------------------------
PlrList_Htz2: plrlistheader
    plreq ArtTile_ArtNem_HtzZipline, ArtNem_HtzZipline
    plreq ArtTile_ArtNem_HtzFireball, ArtNem_HtzFireball
    plreq ArtTile_ArtNem_HtzValveBarrier, ArtNem_HtzValveBarrier
PlrList_Htz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; HPZ Primary
;---------------------------------------------------------------------------------------
PlrList_Hpz1: ;plrlistheader
;   plreq ArtTile_ArtNem_WaterSurface, ArtNem_WaterSurface
;PlrList_Hpz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; HPZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Hpz2: ;plrlistheader
;PlrList_Hpz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; OOZ Primary
;---------------------------------------------------------------------------------------
PlrList_Ooz1: plrlistheader
    plreq ArtTile_ArtNem_OOZBurn, ArtNem_OOZBurn
    plreq ArtTile_ArtNem_OOZElevator, ArtNem_OOZElevator
    plreq ArtTile_ArtNem_SpikyThing, ArtNem_SpikyThing
    plreq ArtTile_ArtNem_BurnerLid, ArtNem_BurnerLid
    plreq ArtTile_ArtNem_StripedBlocksVert, ArtNem_StripedBlocksVert
    plreq ArtTile_ArtNem_Oilfall, ArtNem_Oilfall
    plreq ArtTile_ArtNem_Oilfall2, ArtNem_Oilfall2
    plreq ArtTile_ArtNem_BallThing, ArtNem_BallThing
    plreq ArtTile_ArtNem_LaunchBall, ArtNem_LaunchBall
PlrList_Ooz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; OOZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Ooz2: plrlistheader
    plreq ArtTile_ArtNem_OOZPlatform, ArtNem_OOZPlatform
    plreq ArtTile_ArtNem_PushSpring, ArtNem_PushSpring
    plreq ArtTile_ArtNem_OOZSwingPlat, ArtNem_OOZSwingPlat
    plreq ArtTile_ArtNem_StripedBlocksHoriz, ArtNem_StripedBlocksHoriz
    plreq ArtTile_ArtNem_OOZFanHoriz, ArtNem_OOZFanHoriz
    plreq ArtTile_ArtNem_Button, ArtNem_Button
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_DignlSprng, ArtNem_DignlSprng
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
    plreq ArtTile_ArtNem_Aquis, ArtNem_Aquis
    plreq ArtTile_ArtNem_Octus, ArtNem_Octus
PlrList_Ooz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; MCZ Primary
;---------------------------------------------------------------------------------------
PlrList_Mcz1: plrlistheader
    plreq ArtTile_ArtNem_Crate, ArtNem_Crate
    plreq ArtTile_ArtNem_MCZCollapsePlat, ArtNem_MCZCollapsePlat
    plreq ArtTile_ArtNem_VineSwitch, ArtNem_VineSwitch
    plreq ArtTile_ArtNem_VinePulley, ArtNem_VinePulley
    plreq ArtTile_ArtNem_Flasher, ArtNem_Flasher
    plreq ArtTile_ArtNem_Crawlton, ArtNem_Crawlton
PlrList_Mcz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; MCZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Mcz2: plrlistheader
    plreq ArtTile_ArtNem_HorizSpike, ArtNem_HorizSpike
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_MCZGateLog, ArtNem_MCZGateLog
    plreq ArtTile_ArtNem_LeverSpring, ArtNem_LeverSpring
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Mcz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CNZ Primary
;---------------------------------------------------------------------------------------
PlrList_Cnz1: plrlistheader
    plreq ArtTile_ArtNem_Crawl, ArtNem_Crawl
    plreq ArtTile_ArtNem_BigMovingBlock, ArtNem_BigMovingBlock
    plreq ArtTile_ArtNem_CNZSnake, ArtNem_CNZSnake
    plreq ArtTile_ArtNem_CNZBonusSpike, ArtNem_CNZBonusSpike
    plreq ArtTile_ArtNem_CNZElevator, ArtNem_CNZElevator
    plreq ArtTile_ArtNem_CNZCage, ArtNem_CNZCage
    plreq ArtTile_ArtNem_CNZHexBumper, ArtNem_CNZHexBumper
    plreq ArtTile_ArtNem_CNZRoundBumper, ArtNem_CNZRoundBumper
    plreq ArtTile_ArtNem_CNZFlipper, ArtNem_CNZFlipper
    plreq ArtTile_ArtNem_CNZMiniBumper, ArtNem_CNZMiniBumper
PlrList_Cnz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CNZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Cnz2: plrlistheader
    plreq ArtTile_ArtNem_CNZDiagPlunger, ArtNem_CNZDiagPlunger
    plreq ArtTile_ArtNem_CNZVertPlunger, ArtNem_CNZVertPlunger
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_DignlSprng, ArtNem_DignlSprng
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Cnz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CPZ Primary
;---------------------------------------------------------------------------------------
PlrList_Cpz1: plrlistheader
    plreq ArtTile_ArtNem_CPZMetalThings, ArtNem_CPZMetalThings
    plreq ArtTile_ArtNem_ConstructionStripes_2, ArtNem_ConstructionStripes
    plreq ArtTile_ArtNem_CPZBooster, ArtNem_CPZBooster
    plreq ArtTile_ArtNem_CPZElevator, ArtNem_CPZElevator
    plreq ArtTile_ArtNem_CPZAnimatedBits, ArtNem_CPZAnimatedBits
    plreq ArtTile_ArtNem_CPZTubeSpring, ArtNem_CPZTubeSpring
    plreq ArtTile_ArtNem_WaterSurface, ArtNem_WaterSurface
    plreq ArtTile_ArtNem_CPZStairBlock, ArtNem_CPZStairBlock
    plreq ArtTile_ArtNem_CPZMetalBlock, ArtNem_CPZMetalBlock
PlrList_Cpz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CPZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Cpz2: plrlistheader
    plreq ArtTile_ArtNem_Grabber, ArtNem_Grabber
    plreq ArtTile_ArtNem_Spiny, ArtNem_Spiny
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_DignlSprng, ArtNem_CPZDroplet
    plreq ArtTile_ArtNem_LeverSpring, ArtNem_LeverSpring
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Cpz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; DEZ Primary
;---------------------------------------------------------------------------------------
PlrList_Dez1: plrlistheader
    plreq ArtTile_ArtNem_ConstructionStripes_1, ArtNem_ConstructionStripes
PlrList_Dez1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; DEZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Dez2: plrlistheader
    plreq ArtTile_ArtNem_SilverSonic, ArtNem_SilverSonic
    plreq ArtTile_ArtNem_DEZWindow, ArtNem_DEZWindow
    plreq ArtTile_ArtNem_RobotnikRunning, ArtNem_RobotnikRunning
    plreq ArtTile_ArtNem_RobotnikUpper, ArtNem_RobotnikUpper
    plreq ArtTile_ArtNem_RobotnikLower, ArtNem_RobotnikLower
PlrList_Dez2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; ARZ Primary
;---------------------------------------------------------------------------------------
PlrList_Arz1: plrlistheader
    plreq ArtTile_ArtNem_ARZBarrierThing, ArtNem_ARZBarrierThing
    plreq ArtTile_ArtNem_WaterSurface, ArtNem_WaterSurface2
    plreq ArtTile_ArtNem_Leaves, ArtNem_Leaves
    plreq ArtTile_ArtNem_ArrowAndShooter, ArtNem_ArrowAndShooter
PlrList_Arz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; ARZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Arz2: plrlistheader
    plreq ArtTile_ArtNem_ChopChop, ArtNem_ChopChop
    plreq ArtTile_ArtNem_Whisp, ArtNem_Whisp
    plreq ArtTile_ArtNem_Grounder, ArtNem_Grounder
    plreq ArtTile_ArtNem_BigBubbles, ArtNem_BigBubbles
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_LeverSpring, ArtNem_LeverSpring
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Arz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; SCZ Primary
;---------------------------------------------------------------------------------------
PlrList_Scz1: plrlistheader
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
PlrList_Scz1_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; SCZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Scz2: plrlistheader
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
    plreq ArtTile_ArtNem_WfzVrtclPrpllr, ArtNem_WfzVrtclPrpllr
    plreq ArtTile_ArtNem_WfzHrzntlPrpllr, ArtNem_WfzHrzntlPrpllr
    plreq ArtTile_ArtNem_Balkrie, ArtNem_Balkrie
    plreq ArtTile_ArtNem_Turtloid, ArtNem_Turtloid
    plreq ArtTile_ArtNem_Nebula, ArtNem_Nebula
PlrList_Scz2_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Sonic end of level results screen
;---------------------------------------------------------------------------------------
PlrList_Results: plrlistheader
    plreq ArtTile_ArtNem_TitleCard, ArtNem_TitleCard
    plreq ArtTile_ArtNem_ResultsText, ArtNem_ResultsText
    plreq ArtTile_ArtNem_MiniCharacter, ArtNem_MiniSonic
    plreq ArtTile_ArtNem_Perfect, ArtNem_Perfect
PlrList_Results_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; End of level signpost
;---------------------------------------------------------------------------------------
PlrList_Signpost: plrlistheader
    plreq ArtTile_ArtNem_Signpost, ArtNem_Signpost
PlrList_Signpost_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CPZ Boss
;---------------------------------------------------------------------------------------
PlrList_CpzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_3, ArtNem_Eggpod
    plreq ArtTile_ArtNem_CPZBoss, ArtNem_CPZBoss
    plreq ArtTile_ArtNem_EggpodJets_1, ArtNem_EggpodJets
    plreq ArtTile_ArtNem_BossSmoke_1, ArtNem_BossSmoke
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_CpzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; EHZ Boss
;---------------------------------------------------------------------------------------
PlrList_EhzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_1, ArtNem_Eggpod
    plreq ArtTile_ArtNem_EHZBoss, ArtNem_EHZBoss
    plreq ArtTile_ArtNem_EggChoppers, ArtNem_EggChoppers
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_EhzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; HTZ Boss
;---------------------------------------------------------------------------------------
PlrList_HtzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_2, ArtNem_Eggpod
    plreq ArtTile_ArtNem_HTZBoss, ArtNem_HTZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
    plreq ArtTile_ArtNem_BossSmoke_2, ArtNem_BossSmoke
PlrList_HtzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; ARZ Boss
;---------------------------------------------------------------------------------------
PlrList_ArzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_ARZBoss, ArtNem_ARZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_ArzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; MCZ Boss
;---------------------------------------------------------------------------------------
PlrList_MczBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_MCZBoss, ArtNem_MCZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_MczBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CNZ Boss
;---------------------------------------------------------------------------------------
PlrList_CnzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_CNZBoss, ArtNem_CNZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_CnzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; MTZ Boss
;---------------------------------------------------------------------------------------
PlrList_MtzBoss: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_MTZBoss, ArtNem_MTZBoss
    plreq ArtTile_ArtNem_EggpodJets_2, ArtNem_EggpodJets
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_MtzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; OOZ Boss
;---------------------------------------------------------------------------------------
PlrList_OozBoss: plrlistheader
    plreq ArtTile_ArtNem_OOZBoss, ArtNem_OOZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_OozBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Fiery Explosion
;---------------------------------------------------------------------------------------
PlrList_FieryExplosion: plrlistheader
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_FieryExplosion_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Death Egg
;---------------------------------------------------------------------------------------
PlrList_DezBoss: plrlistheader
    plreq ArtTile_ArtNem_DEZBoss, ArtNem_DEZBoss
PlrList_DezBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; EHZ Animals
;---------------------------------------------------------------------------------------
PlrList_EhzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Squirrel
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_EhzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; MCZ Animals
;---------------------------------------------------------------------------------------
PlrList_MczAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Mouse
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_MczAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; HTZ/MTZ/WFZ animals
;---------------------------------------------------------------------------------------
PlrList_HtzAnimals:
PlrList_MtzAnimals:
PlrList_WfzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Beaver
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Eagle
PlrList_HtzAnimals_End
PlrList_MtzAnimals_End
PlrList_WfzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; DEZ Animals
;---------------------------------------------------------------------------------------
PlrList_DezAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Pig
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_DezAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; HPZ animals
;---------------------------------------------------------------------------------------
PlrList_HpzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Mouse
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Seal
PlrList_HpzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; OOZ Animals
;---------------------------------------------------------------------------------------
PlrList_OozAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Penguin
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Seal
PlrList_OozAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; SCZ Animals
;---------------------------------------------------------------------------------------
PlrList_SczAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Turtle
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_SczAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CNZ Animals
;---------------------------------------------------------------------------------------
PlrList_CnzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Bear
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_CnzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; CPZ Animals
;---------------------------------------------------------------------------------------
PlrList_CpzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Rabbit
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Eagle
PlrList_CpzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; ARZ Animals
;---------------------------------------------------------------------------------------
PlrList_ArzAnimals: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Penguin
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_ArzAnimals_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Special Stage
;---------------------------------------------------------------------------------------
PlrList_SpecialStage: plrlistheader
    plreq ArtTile_ArtNem_SpecialEmerald, ArtNem_SpecialEmerald
    plreq ArtTile_ArtNem_SpecialMessages, ArtNem_SpecialMessages
    plreq ArtTile_ArtNem_SpecialHUD, ArtNem_SpecialHUD
    plreq ArtTile_ArtNem_SpecialFlatShadow, ArtNem_SpecialFlatShadow
    plreq ArtTile_ArtNem_SpecialDiagShadow, ArtNem_SpecialDiagShadow
    plreq ArtTile_ArtNem_SpecialSideShadow, ArtNem_SpecialSideShadow
    plreq ArtTile_ArtNem_SpecialExplosion, ArtNem_SpecialExplosion
    plreq ArtTile_ArtNem_SpecialRings, ArtNem_SpecialRings
    plreq ArtTile_ArtNem_SpecialStart, ArtNem_SpecialStart
    plreq ArtTile_ArtNem_SpecialPlayerVSPlayer, ArtNem_SpecialPlayerVSPlayer
    plreq ArtTile_ArtNem_SpecialBack, ArtNem_SpecialBack
    plreq ArtTile_ArtNem_SpecialStars, ArtNem_SpecialStars
    plreq ArtTile_ArtNem_SpecialTailsText, ArtNem_SpecialTailsText
PlrList_SpecialStage_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Special Stage Bombs
;---------------------------------------------------------------------------------------
PlrList_SpecStageBombs: plrlistheader
    plreq ArtTile_ArtNem_SpecialBomb, ArtNem_SpecialBomb
PlrList_SpecStageBombs_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; WFZ Boss
;---------------------------------------------------------------------------------------
PlrList_WfzBoss: plrlistheader
    plreq ArtTile_ArtNem_WFZBoss, ArtNem_WFZBoss
    plreq ArtTile_ArtNem_RobotnikRunning, ArtNem_RobotnikRunning
    plreq ArtTile_ArtNem_RobotnikUpper, ArtNem_RobotnikUpper
    plreq ArtTile_ArtNem_RobotnikLower, ArtNem_RobotnikLower
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_WfzBoss_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Tornado
;---------------------------------------------------------------------------------------
PlrList_Tornado: plrlistheader
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
    plreq ArtTile_ArtNem_TornadoThruster, ArtNem_TornadoThruster
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
PlrList_Tornado_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Capsule/Egg Prison
;---------------------------------------------------------------------------------------
PlrList_Capsule: plrlistheader
    plreq ArtTile_ArtNem_Capsule, ArtNem_Capsule
PlrList_Capsule_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Normal explosion
;---------------------------------------------------------------------------------------
PlrList_Explosion: plrlistheader
    plreq ArtTile_ArtNem_Explosion, ArtNem_Explosion
PlrList_Explosion_End
;---------------------------------------------------------------------------------------
; Pattern load queue
; Tails end of level results screen
;---------------------------------------------------------------------------------------
PlrList_ResultsTails: plrlistheader
    plreq ArtTile_ArtNem_TitleCard, ArtNem_TitleCard
    plreq ArtTile_ArtNem_ResultsText, ArtNem_ResultsText
    plreq ArtTile_ArtNem_MiniCharacter, ArtNem_MiniTails
    plreq ArtTile_ArtNem_Perfect, ArtNem_Perfect
PlrList_ResultsTails_End
 
 
 
 
;---------------------------------------------------------------------------------------
; Weird revision-specific duplicates of portions of the PLR lists (unused)
;---------------------------------------------------------------------------------------
    if gameRevision=0
    ; half of PlrList_ResultsTails
    plreq ArtTile_ArtNem_MiniCharacter, ArtNem_MiniTails
    plreq ArtTile_ArtNem_Perfect, ArtNem_Perfect
PlrList_ResultsTails_Dup_End
    dc.l    0
    elseif gameRevision=2
    ; half of the second ARZ PLR list
    ;plreq ArtTile_ArtNem_Grounder, ArtNem_Grounder ; cut in half
    ;dc.l   ArtNem_Grounder
    dc.w    tiles_to_bytes(ArtTile_ArtNem_Grounder)
 
    plreq ArtTile_ArtNem_BigBubbles, ArtNem_BigBubbles
    plreq ArtTile_ArtNem_Spikes, ArtNem_Spikes
    plreq ArtTile_ArtNem_LeverSpring, ArtNem_LeverSpring
    plreq ArtTile_ArtNem_VrtclSprng, ArtNem_VrtclSprng
    plreq ArtTile_ArtNem_HrzntlSprng, ArtNem_HrzntlSprng
PlrList_Arz2_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; SCZ Primary
;---------------------------------------------------------------------------------------
PlrList_Scz1_Dup: plrlistheader
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
PlrList_Scz1_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; SCZ Secondary
;---------------------------------------------------------------------------------------
PlrList_Scz2_Dup: plrlistheader
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
    plreq ArtTile_ArtNem_WfzVrtclPrpllr, ArtNem_WfzVrtclPrpllr
    plreq ArtTile_ArtNem_WfzHrzntlPrpllr, ArtNem_WfzHrzntlPrpllr
    plreq ArtTile_ArtNem_Balkrie, ArtNem_Balkrie
    plreq ArtTile_ArtNem_Turtloid, ArtNem_Turtloid
    plreq ArtTile_ArtNem_Nebula, ArtNem_Nebula
PlrList_Scz2_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Sonic end of level results screen
;---------------------------------------------------------------------------------------
PlrList_Results_Dup: plrlistheader
    plreq ArtTile_ArtNem_TitleCard, ArtNem_TitleCard
    plreq ArtTile_ArtNem_ResultsText, ArtNem_ResultsText
    plreq ArtTile_ArtNem_MiniCharacter, ArtNem_MiniSonic
    plreq ArtTile_ArtNem_Perfect, ArtNem_Perfect
PlrList_Results_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; End of level signpost
;---------------------------------------------------------------------------------------
PlrList_Signpost_Dup: plrlistheader
    plreq ArtTile_ArtNem_Signpost, ArtNem_Signpost
PlrList_Signpost_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; CPZ Boss
;---------------------------------------------------------------------------------------
PlrList_CpzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_3, ArtNem_Eggpod
    plreq ArtTile_ArtNem_CPZBoss, ArtNem_CPZBoss
    plreq ArtTile_ArtNem_EggpodJets_1, ArtNem_EggpodJets
    plreq ArtTile_ArtNem_BossSmoke_1, ArtNem_BossSmoke
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_CpzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; EHZ Boss
;---------------------------------------------------------------------------------------
PlrList_EhzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_1, ArtNem_Eggpod
    plreq ArtTile_ArtNem_EHZBoss, ArtNem_EHZBoss
    plreq ArtTile_ArtNem_EggChoppers, ArtNem_EggChoppers
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_EhzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; HTZ Boss
;---------------------------------------------------------------------------------------
PlrList_HtzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_2, ArtNem_Eggpod
    plreq ArtTile_ArtNem_HTZBoss, ArtNem_HTZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
    plreq ArtTile_ArtNem_BossSmoke_2, ArtNem_BossSmoke
PlrList_HtzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; ARZ Boss
;---------------------------------------------------------------------------------------
PlrList_ArzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_ARZBoss, ArtNem_ARZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_ArzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; MCZ Boss
;---------------------------------------------------------------------------------------
PlrList_MczBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_MCZBoss, ArtNem_MCZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_MczBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; CNZ Boss
;---------------------------------------------------------------------------------------
PlrList_CnzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_CNZBoss, ArtNem_CNZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_CnzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; MTZ Boss
;---------------------------------------------------------------------------------------
PlrList_MtzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_Eggpod_4, ArtNem_Eggpod
    plreq ArtTile_ArtNem_MTZBoss, ArtNem_MTZBoss
    plreq ArtTile_ArtNem_EggpodJets_2, ArtNem_EggpodJets
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_MtzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; OOZ Boss
;---------------------------------------------------------------------------------------
PlrList_OozBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_OOZBoss, ArtNem_OOZBoss
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_OozBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Fiery Explosion
;---------------------------------------------------------------------------------------
PlrList_FieryExplosion_Dup: plrlistheader
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_FieryExplosion_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Death Egg
;---------------------------------------------------------------------------------------
PlrList_DezBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_DEZBoss, ArtNem_DEZBoss
PlrList_DezBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; EHZ Animals
;---------------------------------------------------------------------------------------
PlrList_EhzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Squirrel
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_EhzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; MCZ Animals
;---------------------------------------------------------------------------------------
PlrList_MczAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Mouse
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_MczAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; HTZ/MTZ/WFZ animals
;---------------------------------------------------------------------------------------
PlrList_HtzAnimals_Dup:
PlrList_MtzAnimals_Dup:
PlrList_WfzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Beaver
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Eagle
PlrList_HtzAnimals_Dup_End
PlrList_MtzAnimals_Dup_End
PlrList_WfzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; DEZ Animals
;---------------------------------------------------------------------------------------
PlrList_DezAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Pig
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_DezAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; HPZ animals
;---------------------------------------------------------------------------------------
PlrList_HpzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Mouse
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Seal
PlrList_HpzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; OOZ Animals
;---------------------------------------------------------------------------------------
PlrList_OozAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Penguin
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Seal
PlrList_OozAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; SCZ Animals
;---------------------------------------------------------------------------------------
PlrList_SczAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Turtle
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Chicken
PlrList_SczAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; CNZ Animals
;---------------------------------------------------------------------------------------
PlrList_CnzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Bear
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_CnzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; CPZ Animals
;---------------------------------------------------------------------------------------
PlrList_CpzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Rabbit
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Eagle
PlrList_CpzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; ARZ Animals
;---------------------------------------------------------------------------------------
PlrList_ArzAnimals_Dup: plrlistheader
    plreq ArtTile_ArtNem_Animal_1, ArtNem_Penguin
    plreq ArtTile_ArtNem_Animal_2, ArtNem_Bird
PlrList_ArzAnimals_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Special Stage
;---------------------------------------------------------------------------------------
PlrList_SpecialStage_Dup: plrlistheader
    plreq ArtTile_ArtNem_SpecialEmerald, ArtNem_SpecialEmerald
    plreq ArtTile_ArtNem_SpecialMessages, ArtNem_SpecialMessages
    plreq ArtTile_ArtNem_SpecialHUD, ArtNem_SpecialHUD
    plreq ArtTile_ArtNem_SpecialFlatShadow, ArtNem_SpecialFlatShadow
    plreq ArtTile_ArtNem_SpecialDiagShadow, ArtNem_SpecialDiagShadow
    plreq ArtTile_ArtNem_SpecialSideShadow, ArtNem_SpecialSideShadow
    plreq ArtTile_ArtNem_SpecialExplosion, ArtNem_SpecialExplosion
    plreq ArtTile_ArtNem_SpecialRings, ArtNem_SpecialRings
    plreq ArtTile_ArtNem_SpecialStart, ArtNem_SpecialStart
    plreq ArtTile_ArtNem_SpecialPlayerVSPlayer, ArtNem_SpecialPlayerVSPlayer
    plreq ArtTile_ArtNem_SpecialBack, ArtNem_SpecialBack
    plreq ArtTile_ArtNem_SpecialStars, ArtNem_SpecialStars
    plreq ArtTile_ArtNem_SpecialTailsText, ArtNem_SpecialTailsText
PlrList_SpecialStage_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Special Stage Bombs
;---------------------------------------------------------------------------------------
PlrList_SpecStageBombs_Dup: plrlistheader
    plreq ArtTile_ArtNem_SpecialBomb, ArtNem_SpecialBomb
PlrList_SpecStageBombs_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; WFZ Boss
;---------------------------------------------------------------------------------------
PlrList_WfzBoss_Dup: plrlistheader
    plreq ArtTile_ArtNem_WFZBoss, ArtNem_WFZBoss
    plreq ArtTile_ArtNem_RobotnikRunning, ArtNem_RobotnikRunning
    plreq ArtTile_ArtNem_RobotnikUpper, ArtNem_RobotnikUpper
    plreq ArtTile_ArtNem_RobotnikLower, ArtNem_RobotnikLower
    plreq ArtTile_ArtNem_FieryExplosion, ArtNem_FieryExplosion
PlrList_WfzBoss_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Tornado
;---------------------------------------------------------------------------------------
PlrList_Tornado_Dup: plrlistheader
    plreq ArtTile_ArtNem_Tornado, ArtNem_Tornado
    plreq ArtTile_ArtNem_TornadoThruster, ArtNem_TornadoThruster
    plreq ArtTile_ArtNem_Clouds, ArtNem_Clouds
PlrList_Tornado_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Capsule/Egg Prison
;---------------------------------------------------------------------------------------
PlrList_Capsule_Dup: plrlistheader
    plreq ArtTile_ArtNem_Capsule, ArtNem_Capsule
PlrList_Capsule_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Normal explosion
;---------------------------------------------------------------------------------------
PlrList_Explosion_Dup: plrlistheader
    plreq ArtTile_ArtNem_Explosion, ArtNem_Explosion
PlrList_Explosion_Dup_End
;---------------------------------------------------------------------------------------
; Pattern load queue (duplicate)
; Tails end of level results screen
;---------------------------------------------------------------------------------------
PlrList_ResultsTails_Dup: plrlistheader
    plreq ArtTile_ArtNem_TitleCard, ArtNem_TitleCard
    plreq ArtTile_ArtNem_ResultsText, ArtNem_ResultsText
    plreq ArtTile_ArtNem_MiniCharacter, ArtNem_MiniTails
    plreq ArtTile_ArtNem_Perfect, ArtNem_Perfect
PlrList_ResultsTails_Dup_End
    endif
 
 
 
;---------------------------------------------------------------------------------------
; Curve and resistance mapping
;---------------------------------------------------------------------------------------
ColCurveMap:    BINCLUDE    "collision/Curve and resistance mapping.bin"
    even
;--------------------------------------------------------------------------------------
; Collision arrays
;--------------------------------------------------------------------------------------
ColArray:   BINCLUDE    "collision/Collision array 1.bin"
ColArray2:  BINCLUDE    "collision/Collision array 2.bin"
    even
;---------------------------------------------------------------------------------------
; EHZ and HTZ primary 16x16 collision index (Kosinski compression)
ColP_EHZHTZ:    BINCLUDE    "collision/EHZ and HTZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; EHZ and HTZ secondary 16x16 collision index (Kosinski compression)
ColS_EHZHTZ:    BINCLUDE    "collision/EHZ and HTZ secondary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; MTZ primary 16x16 collision index (Kosinski compression)
ColP_MTZ:   BINCLUDE    "collision/MTZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; HPZ primary 16x16 collision index (Kosinski compression)
ColP_HPZ:   ;BINCLUDE   "collision/HPZ primary 16x16 collision index.bin"
    ;even
;---------------------------------------------------------------------------------------
; HPZ secondary 16x16 collision index (Kosinski compression)
ColS_HPZ:   ;BINCLUDE   "collision/HPZ secondary 16x16 collision index.bin"
    ;even
;---------------------------------------------------------------------------------------
; OOZ primary 16x16 collision index (Kosinski compression)
ColP_OOZ:   BINCLUDE    "collision/OOZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; MCZ primary 16x16 collision index (Kosinski compression)
ColP_MCZ:   BINCLUDE    "collision/MCZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; CNZ primary 16x16 collision index (Kosinski compression)
ColP_CNZ:   BINCLUDE    "collision/CNZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; CNZ secondary 16x16 collision index (Kosinski compression)
ColS_CNZ:   BINCLUDE    "collision/CNZ secondary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; CPZ and DEZ primary 16x16 collision index (Kosinski compression)
ColP_CPZDEZ:    BINCLUDE    "collision/CPZ and DEZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; CPZ and DEZ secondary 16x16 collision index (Kosinski compression)
ColS_CPZDEZ:    BINCLUDE    "collision/CPZ and DEZ secondary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; ARZ primary 16x16 collision index (Kosinski compression)
ColP_ARZ:   BINCLUDE    "collision/ARZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; ARZ secondary 16x16 collision index (Kosinski compression)
ColS_ARZ:   BINCLUDE    "collision/ARZ secondary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; WFZ/SCZ primary 16x16 collision index (Kosinski compression)
ColP_WFZSCZ:    BINCLUDE    "collision/WFZ and SCZ primary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
; WFZ/SCZ secondary 16x16 collision index (Kosinski compression)
ColS_WFZSCZ:    BINCLUDE    "collision/WFZ and SCZ secondary 16x16 collision index.bin"
    even
;---------------------------------------------------------------------------------------
 
ColP_Invalid:
 
 
 
 
;---------------------------------------------------------------------------------------
; Offset index of level layouts
; Two entries per zone, pointing to the level layouts for acts 1 and 2 of each zone
; respectively.
;---------------------------------------------------------------------------------------
Off_Level: zoneOrderedOffsetTable 2,2
    zoneOffsetTableEntry.w Level_EHZ1
    zoneOffsetTableEntry.w Level_EHZ2   ; 1
    zoneOffsetTableEntry.w Level_EHZ1   ; 2
    zoneOffsetTableEntry.w Level_EHZ1   ; 3
    zoneOffsetTableEntry.w Level_EHZ1   ; 4
    zoneOffsetTableEntry.w Level_EHZ1   ; 5
    zoneOffsetTableEntry.w Level_EHZ1   ; 6
    zoneOffsetTableEntry.w Level_EHZ1   ; 7
    zoneOffsetTableEntry.w Level_MTZ1   ; 8
    zoneOffsetTableEntry.w Level_MTZ2   ; 9
    zoneOffsetTableEntry.w Level_MTZ3   ; 10
    zoneOffsetTableEntry.w Level_MTZ3   ; 11
    zoneOffsetTableEntry.w Level_WFZ    ; 12
    zoneOffsetTableEntry.w Level_WFZ    ; 13
    zoneOffsetTableEntry.w Level_HTZ1   ; 14
    zoneOffsetTableEntry.w Level_HTZ2   ; 15
    zoneOffsetTableEntry.w Level_HPZ1   ; 16
    zoneOffsetTableEntry.w Level_HPZ1   ; 17
    zoneOffsetTableEntry.w Level_EHZ1   ; 18
    zoneOffsetTableEntry.w Level_EHZ1   ; 19
    zoneOffsetTableEntry.w Level_OOZ1   ; 20
    zoneOffsetTableEntry.w Level_OOZ2   ; 21
    zoneOffsetTableEntry.w Level_MCZ1   ; 22
    zoneOffsetTableEntry.w Level_MCZ2   ; 23
    zoneOffsetTableEntry.w Level_CNZ1   ; 24
    zoneOffsetTableEntry.w Level_CNZ2   ; 25
    zoneOffsetTableEntry.w Level_CPZ1   ; 26
    zoneOffsetTableEntry.w Level_CPZ2   ; 27
    zoneOffsetTableEntry.w Level_DEZ    ; 28
    zoneOffsetTableEntry.w Level_DEZ    ; 29
    zoneOffsetTableEntry.w Level_ARZ1   ; 30
    zoneOffsetTableEntry.w Level_ARZ2   ; 31
    zoneOffsetTableEntry.w Level_SCZ    ; 32
    zoneOffsetTableEntry.w Level_SCZ    ; 33
    zoneTableEnd
;---------------------------------------------------------------------------------------
; EHZ act 1 level layout (Kosinski compression)
Level_EHZ1: BINCLUDE    "level/layout/EHZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; EHZ act 2 level layout (Kosinski compression)
Level_EHZ2: BINCLUDE    "level/layout/EHZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; MTZ act 1 level layout (Kosinski compression)
Level_MTZ1: BINCLUDE    "level/layout/MTZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; MTZ act 2 level layout (Kosinski compression)
Level_MTZ2: BINCLUDE    "level/layout/MTZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; MTZ act 3 level layout (Kosinski compression)
Level_MTZ3: BINCLUDE    "level/layout/MTZ_3.bin"
    even
;---------------------------------------------------------------------------------------
; WFZ level layout (Kosinski compression)
Level_WFZ:  BINCLUDE    "level/layout/WFZ.bin"
    even
;---------------------------------------------------------------------------------------
; HTZ act 1 level layout (Kosinski compression)
Level_HTZ1: BINCLUDE    "level/layout/HTZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; HTZ act 2 level layout (Kosinski compression)
Level_HTZ2: BINCLUDE    "level/layout/HTZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; HPZ act 1 level layout (Kosinski compression)
Level_HPZ1: ;BINCLUDE   "level/layout/HPZ_1.bin"
    ;even
;---------------------------------------------------------------------------------------
; OOZ act 1 level layout (Kosinski compression)
Level_OOZ1: BINCLUDE    "level/layout/OOZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; OOZ act 2 level layout (Kosinski compression)
Level_OOZ2: BINCLUDE    "level/layout/OOZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; MCZ act 1 level layout (Kosinski compression)
Level_MCZ1: BINCLUDE    "level/layout/MCZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; MCZ act 2 level layout (Kosinski compression)
Level_MCZ2: BINCLUDE    "level/layout/MCZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; CNZ act 1 level layout (Kosinski compression)
Level_CNZ1: BINCLUDE    "level/layout/CNZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; CNZ act 2 level layout (Kosinski compression)
Level_CNZ2: BINCLUDE    "level/layout/CNZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; CPZ act 1 level layout (Kosinski compression)
Level_CPZ1: BINCLUDE    "level/layout/CPZ_1.bin"
    even
;---------------------------------------------------------------------------------------
; CPZ act 2 level layout (Kosinski compression)
Level_CPZ2: BINCLUDE    "level/layout/CPZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; DEZ level layout (Kosinski compression)
Level_DEZ:  BINCLUDE    "level/layout/DEZ.bin"
    even
;---------------------------------------------------------------------------------------
; ARZ act 1 level layout (Kosinski compression)
Level_ARZ1: BINCLUDE    "level/layout/ARZ_1.bin"
    even
 
;---------------------------------------------------------------------------------------
; ARZ act 2 level layout (Kosinski compression)
Level_ARZ2: BINCLUDE    "level/layout/ARZ_2.bin"
    even
;---------------------------------------------------------------------------------------
; SCZ level layout (Kosinski compression)
Level_SCZ:  BINCLUDE    "level/layout/SCZ.bin"
    even
 
 
 
 
;---------------------------------------------------------------------------------------
; Uncompressed art
; Animated flowers in EHZ and HTZ ; ArtUnc_49714: ArtUnc_49794: ArtUnc_49814: ArtUnc_49894:
;---------------------------------------------------------------------------------------
ArtUnc_Flowers1:    BINCLUDE    "art/uncompressed/EHZ and HTZ flowers - 1.bin"
ArtUnc_Flowers2:    BINCLUDE    "art/uncompressed/EHZ and HTZ flowers - 2.bin"
ArtUnc_Flowers3:    BINCLUDE    "art/uncompressed/EHZ and HTZ flowers - 3.bin"
ArtUnc_Flowers4:    BINCLUDE    "art/uncompressed/EHZ and HTZ flowers - 4.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Pulsing thing against checkered backing from EHZ ; ArtUnc_49914:
ArtUnc_EHZPulseBall:    BINCLUDE    "art/uncompressed/Pulsing ball against checkered background (EHZ).bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (192 blocks)
; Dynamically reloaded cliffs in background from HTZ ; ArtNem_49A14: ArtUnc_HTZCliffs:
ArtNem_HTZCliffs:   BINCLUDE    "art/nemesis/Dynamically reloaded cliffs in HTZ background.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Dynamically reloaded clouds in background from HTZ ; ArtUnc_4A33E:
ArtUnc_HTZClouds:   BINCLUDE    "art/uncompressed/Background clouds (HTZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Spinning metal cylinder patterns in MTZ ; ArtUnc_4A73E:
ArtUnc_MTZCylinder: BINCLUDE    "art/uncompressed/Spinning metal cylinder (MTZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Lava patterns in MTZ and HTZ  ; ArtUnc_4B73E:
ArtUnc_Lava:    BINCLUDE    "art/uncompressed/Lava.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Animated section of MTZ background ; ArtUnc_4BD3E:
ArtUnc_MTZAnimBack: BINCLUDE    "art/uncompressed/Animated section of MTZ background.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Pulsing orb in HPZ
ArtUnc_HPZPulseOrb: ;BINCLUDE   "art/uncompressed/Pulsing orb (HPZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Pulsing ball in OOZ   ; ArtUnc_4BF7E:
ArtUnc_OOZPulseBall:    BINCLUDE    "art/uncompressed/Pulsing ball (OOZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Square rotating around ball in OOZ ; ArtUnc_4C0FE: ArtUnc_4C2FE:
ArtUnc_OOZSquareBall1:  BINCLUDE    "art/uncompressed/Square rotating around ball in OOZ - 1.bin"
ArtUnc_OOZSquareBall2:  BINCLUDE    "art/uncompressed/Square rotating around ball in OOZ - 2.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Oil in OOZ    ; ArtUnc_4C4FE: ArtUnc_4CCFE:
ArtUnc_Oil1:    BINCLUDE    "art/uncompressed/Oil - 1.bin"
ArtUnc_Oil2:    BINCLUDE    "art/uncompressed/Oil - 2.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Flipping foreground section in CNZ ; ArtUnc_4D4FE:
ArtUnc_CNZFlipTiles:    BINCLUDE    "art/uncompressed/Flipping foreground section (CNZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Bonus pictures for slots in CNZ ; ArtUnc_4EEFE:
ArtUnc_CNZSlotPics: BINCLUDE    "art/uncompressed/Slot pictures.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Animated background section in CPZ and DEZ ; ArtUnc_4FAFE:
ArtUnc_CPZAnimBack: BINCLUDE    "art/uncompressed/Animated background section (CPZ and DEZ).bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Waterfall patterns from ARZ   ; ArtUnc_4FCFE: ArtUnc_4FDFE: ArtUnc_4FEFE:
ArtUnc_Waterfall1:  BINCLUDE    "art/uncompressed/ARZ waterfall patterns - 1.bin"
ArtUnc_Waterfall2:  BINCLUDE    "art/uncompressed/ARZ waterfall patterns - 2.bin"
ArtUnc_Waterfall3:  BINCLUDE    "art/uncompressed/ARZ waterfall patterns - 3.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Patterns for Sonic  ; ArtUnc_50000:
;---------------------------------------------------------------------------------------
    align $20
ArtUnc_Sonic:   BINCLUDE    "art/uncompressed/Sonic's art.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Patterns for Tails  ; ArtUnc_64320:
;---------------------------------------------------------------------------------------
    align $20
ArtUnc_Tails:   BINCLUDE    "art/uncompressed/Tails's art.bin"
;--------------------------------------------------------------------------------------
; Sprite Mappings
; Sonic         ; MapUnc_6FBE0: SprTbl_Sonic:
;--------------------------------------------------------------------------------------
Mapunc_Sonic:   BINCLUDE    "mappings/sprite/Sonic.bin"
;--------------------------------------------------------------------------------------
; Sprite Dynamic Pattern Reloading
; Sonic DPLCs           ; MapRUnc_714E0:
;--------------------------------------------------------------------------------------
; WARNING: the build script needs editing if you rename this label
;          or if you move Sonic's running frame to somewhere else than frame $2D
MapRUnc_Sonic:  BINCLUDE    "mappings/spriteDPLC/Sonic.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Shield            ; ArtNem_71D8E:
ArtNem_Shield:  BINCLUDE    "art/nemesis/Shield.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (34 blocks)
; Invincibility stars       ; ArtNem_71F14:
ArtNem_Invincible_stars:    BINCLUDE    "art/nemesis/Invincibility stars.bin"
;--------------------------------------------------------------------------------------
; Uncompressed art
; Splash in water       ; ArtUnc_71FFC:
ArtUnc_Splash:  BINCLUDE    "art/uncompressed/Splash.bin"
;--------------------------------------------------------------------------------------
; Uncompressed art
; Smoke from Skidding       ; ArtUnc_7373C:
ArtUnc_SkidDust:    BINCLUDE    "art/uncompressed/Skid smoke.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (14 blocks)
; Supersonic stars      ; ArtNem_7393C:     
ArtNem_SuperSonic_stars:    BINCLUDE    "art/nemesis/Super Sonic stars.bin"
;--------------------------------------------------------------------------------------
; Sprite Mappings
; Tails         ; MapUnc_739E2:
;--------------------------------------------------------------------------------------
MapUnc_Tails:   BINCLUDE    "mappings/sprite/Tails.bin"
;--------------------------------------------------------------------------------------
; Sprite Dynamic Pattern Reloading
; Tails DPLCs   ; MapRUnc_7446C:
;--------------------------------------------------------------------------------------
MapRUnc_Tails:  BINCLUDE    "mappings/spriteDPLC/Tails.bin"
;-------------------------------------------------------------------------------------
; Nemesis compressed art (127 blocks)
; "SEGA" Patterns   ; ArtNem_74876:
ArtNem_SEGA:    BINCLUDE    "art/nemesis/SEGA.bin"
;-------------------------------------------------------------------------------------
; Nemesis compressed art (9 blocks)
; Shaded blocks from intro  ; ArtNem_74CF6:
ArtNem_IntroTrails: BINCLUDE    "art/nemesis/Shaded blocks from intro.bin"
;---------------------------------------------------------------------------------------
; Enigma compressed art mappings
; "SEGA" mappings       ; MapEng_74D0E:
MapEng_SEGA:    BINCLUDE    "mappings/misc/SEGA mappings.bin"
;---------------------------------------------------------------------------------------
; Enigma compressed art mappings
; Mappings for title screen background  ; ArtNem_74DC6:
MapEng_TitleScreen: BINCLUDE    "mappings/misc/Mappings for title screen background.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed art mappings
; Mappings for title screen background (smaller part, water/horizon)    ; MapEng_74E3A:
MapEng_TitleBack:   BINCLUDE    "mappings/misc/Mappings for title screen background 2.bin"
;---------------------------------------------------------------------------------------
; Enigma compressed art mappings
; "Sonic the Hedgehog 2" title screen logo mappings ; MapEng_74E86:
MapEng_TitleLogo:   BINCLUDE    "mappings/misc/Sonic the Hedgehog 2 title screen logo mappings.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (336 blocks)
; Main patterns from title screen   ; ArtNem_74F6C:
    even
ArtNem_Title:   BINCLUDE    "art/nemesis/Main patterns from title screen.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (674 blocks)
; Sonic and tails from title screen ; ArtNem_7667A:
    even
ArtNem_TitleSprites:    BINCLUDE    "art/nemesis/Sonic and Tails from title screen.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; A few menu patterns   ; ArtNem_78CBC:
    even
ArtNem_MenuJunk:    BINCLUDE    "art/nemesis/A few menu blocks.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Button            ArtNem_78DAC:
    even
ArtNem_Button:  BINCLUDE    "art/nemesis/Button.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Vertical Spring       ArtNem_78E84:
    even
ArtNem_VrtclSprng:  BINCLUDE    "art/nemesis/Vertical spring.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Horizontal spring     ArtNem_78FA0:
    even
ArtNem_HrzntlSprng: BINCLUDE    "art/nemesis/Horizontal spring.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Diagonal spring       ArtNem_7906A:
    even
ArtNem_DignlSprng:  BINCLUDE    "art/nemesis/Diagonal spring.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Score, Rings, Time patterns   ArtNem_7923E:
    even
ArtNem_HUD: BINCLUDE    "art/nemesis/HUD.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Sonic lives counter       ArtNem_79346:
    even
ArtNem_Sonic_life_counter:  BINCLUDE    "art/nemesis/Sonic lives counter.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (14 blocks)
; Ring              ArtNem_7945C:
    even
ArtNem_Ring:    BINCLUDE    "art/nemesis/Ring.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (60 blocks)
; Monitors and contents     ArtNem_79550:
    even
ArtNem_Powerups:    BINCLUDE    "art/nemesis/Monitor and contents.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Spikes            7995C:
    even
ArtNem_Spikes:  BINCLUDE    "art/nemesis/Spikes.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Numbers           799AC:
    even
ArtNem_Numbers: BINCLUDE    "art/nemesis/Numbers.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Star pole         79A86:
    even
ArtNem_Checkpoint:  BINCLUDE    "art/nemesis/Star pole.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (78 blocks)
; Signpost      ; ArtNem_79BDE:
    even
ArtNem_Signpost:    BINCLUDE    "art/nemesis/Signpost.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Signpost      ; ArtUnc_7A18A:
; Yep, it's in the ROM twice: once compressed and once uncompressed
    even
ArtUnc_Signpost:    BINCLUDE    "art/uncompressed/Signpost.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Lever spring      ; ArtNem_7AB4A:
    even
ArtNem_LeverSpring: BINCLUDE    "art/nemesis/Lever spring.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Long horizontal spike     ; ArtNem_7AC9A:
    even
ArtNem_HorizSpike:  BINCLUDE    "art/nemesis/Long horizontal spike.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Bubble thing from underwater  ; ArtNem_7AD16:
    even
ArtNem_BigBubbles:  BINCLUDE    "art/nemesis/Bubble generator.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; Bubbles from character    7AEE2:
    even
ArtNem_Bubbles: BINCLUDE    "art/nemesis/Bubbles.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Countdown text for drowning   ; ArtUnc_7AF80:
    even
ArtUnc_Countdown:   BINCLUDE    "art/uncompressed/Numbers for drowning countdown.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (34 blocks)
; Game/Time over text       7B400:
    even
ArtNem_Game_Over:   BINCLUDE    "art/nemesis/Game and Time Over text.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (68 blocks)
; Explosion         7B592:
    even
ArtNem_Explosion:   BINCLUDE    "art/nemesis/Explosion.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Miles life counter    ; ArtNem_7B946:
    even
ArtUnc_MilesLife:   BINCLUDE    "art/nemesis/Miles life counter.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (49 blocks)
; Egg prison        ; ArtNem_7BA32:
    even
ArtNem_Capsule: BINCLUDE    "art/nemesis/Egg Prison.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (36 blocks)
; Tails on the continue screen (nagging Sonic)  ; ArtNem_7BDBE:
    even
ArtNem_ContinueTails:   BINCLUDE    "art/nemesis/Tails on continue screen.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Sonic extra continue icon ; ArtNem_7C0AA:
    even
ArtNem_MiniSonic:   BINCLUDE    "art/nemesis/Sonic continue.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Tails life counter        ; ArtNem_7C20C:
    even
ArtNem_TailsLife:   BINCLUDE    "art/nemesis/Tails life counter.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Tails extra continue icon ; ArtNem_7C2F2:
    even
ArtNem_MiniTails:   BINCLUDE    "art/nemesis/Tails continue.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (88 blocks)
; Standard font     ; ArtNem_7C43A:
    even
ArtNem_FontStuff:   BINCLUDE    "art/nemesis/Standard font.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (38 blocks)
; 1P/2P wins text from 2P mode      ; ArtNem_7C9AE:
    even
ArtNem_1P2PWins:    BINCLUDE    "art/nemesis/1P and 2P wins text from 2P mode.bin"
;---------------------------------------------------------------------------------------
; Enigma compressed art mappings
; Sonic/Miles animated background mappings  ; MapEng_7CB80:
MapEng_MenuBack:    BINCLUDE    "mappings/misc/Sonic and Miles animated background.bin"
;---------------------------------------------------------------------------------------
; Uncompressed art
; Sonic/Miles animated background patterns  ; ArtUnc_7CD2C:
    even
ArtUnc_MenuBack:    BINCLUDE    "art/uncompressed/Sonic and Miles animated background.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (94 blocks)
; Title card patterns       ; ArtNem_7D22C:
    even
ArtNem_TitleCard:   BINCLUDE    "art/nemesis/Title card.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (92 blocks)
; Alphabet for font using large broken letters  ; ArtNem_7D58A:
    even
ArtNem_TitleCard2:  BINCLUDE    "art/nemesis/Font using large broken letters.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (21 blocks)
; A menu box with a shadow  ; ArtNem_7D990:
    even
ArtNem_MenuBox: BINCLUDE    "art/nemesis/A menu box with a shadow.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (170 blocks)
; Pictures in level preview box in level select     ; ArtNem_7DA10:
    even
ArtNem_LevelSelectPics: BINCLUDE    "art/nemesis/Pictures in level preview box from level select.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (68 blocks)
; Text for Sonic or Tails Got Through Act and Bonus/Perfect ; ArtNem_7E86A:
    even
ArtNem_ResultsText: BINCLUDE    "art/nemesis/End of level results text.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (72 blocks)
; Text for end of special stage, along with patterns for 3 emeralds.    ; ArtNem_7EB58:
    even
ArtNem_SpecialStageResults: BINCLUDE    "art/nemesis/Special stage results screen art and some emeralds.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (14 blocks)
; "Perfect" text    ; ArtNem_7EEBE:
    even
ArtNem_Perfect: BINCLUDE    "art/nemesis/Perfect text.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Flicky        ; ArtNem_7EF60:
    even
ArtNem_Bird:    BINCLUDE    "art/nemesis/Flicky.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Squirrel      ; ArtNem_7F0A2:
    even
ArtNem_Squirrel:    BINCLUDE    "art/nemesis/Squirrel.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Mouse         ; ArtNem_7F206:
    even
ArtNem_Mouse:   BINCLUDE    "art/nemesis/Mouse.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Chicken       ; ArtNem_7F340:
    even
ArtNem_Chicken: BINCLUDE    "art/nemesis/Chicken.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Beaver        ; ArtNem_7F4A2:
    even
ArtNem_Beaver:  BINCLUDE    "art/nemesis/Beaver.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Some bird     ; ArtNem_7F5E2:
    even
ArtNem_Eagle:   BINCLUDE    "art/nemesis/Penguin.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; Pig           ; ArtNem_7F710:
    even
ArtNem_Pig: BINCLUDE    "art/nemesis/Pig.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (14 blocks)
; Seal          ; ArtNem_7F846:
    even
ArtNem_Seal:    BINCLUDE    "art/nemesis/Seal.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Penguin       ; ArtNem_7F962:
    even
ArtNem_Penguin: BINCLUDE    "art/nemesis/Penguin 2.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Turtle        ; ArtNem_7FADE:
    even
ArtNem_Turtle:  BINCLUDE    "art/nemesis/Turtle.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Bear          ; ArtNem_7FC90:
    even
ArtNem_Bear:    BINCLUDE    "art/nemesis/Bear.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Splats        ; ArtNem_7FDD2:
    even
ArtNem_Rabbit:  BINCLUDE    "art/nemesis/Rabbit.bin"
;---------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Rivet thing that you bust to get inside ship at the end of WFZ    ; ArtNem_7FF2A:
    even
ArtNem_WfzSwitch:   BINCLUDE    "art/nemesis/WFZ boss chamber switch.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (15 blocks)
; Breakaway panels in WFZ   ; ArtNem_7FF98:
    even
ArtNem_BreakPanels: BINCLUDE    "art/nemesis/Breakaway panels from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Spiked thing from OOZ     ; ArtNem_8007C:
    even
ArtNem_SpikyThing:  BINCLUDE    "art/nemesis/Spiked ball from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (6 blocks)
; Green platform over the burners in OOZ    ; ArtNem_80274:
    even
ArtNem_BurnerLid:   BINCLUDE    "art/nemesis/Burner Platform from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Striped blocks from OOZ   ; ArtNem_8030A:
    even
ArtNem_StripedBlocksVert:   BINCLUDE    "art/nemesis/Striped blocks from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Oil splashing into oil in OOZ ; ArtNem_80376:
    even
ArtNem_Oilfall: BINCLUDE    "art/nemesis/Cascading oil hitting oil from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (13 blocks)
; Cascading oil from OOZ    ; ArtNem_804F2:
    even
ArtNem_Oilfall2:    BINCLUDE    "art/nemesis/Cascading oil from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Ball thing (unused?) from OOZ ; ArtNem_805C0:
    even
ArtNem_BallThing:   BINCLUDE    "art/nemesis/Ball on spring from OOZ (beta holdovers).bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (53 blocks)
; Spinball from OOZ ; ArtNem_806E0:
    even
ArtNem_LaunchBall:  BINCLUDE    "art/nemesis/Transporter ball from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (40 blocks)
; Collapsing platform from OOZ  ; ArtNem_809D0:
    even
ArtNem_OOZPlatform: BINCLUDE    "art/nemesis/OOZ collapsing platform.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (30 blocks)
; Diagonal and vertical weird spring from OOZ   ; ArtNem_80C64:
    even
ArtNem_PushSpring:  BINCLUDE    "art/nemesis/Push spring from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Swinging platform from OOZ    ; ArtNem_80E26:
    even
ArtNem_OOZSwingPlat:    BINCLUDE    "art/nemesis/Swinging platform from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; 4 stripy blocks from OOZ  ; ArtNem_81048:
    even
ArtNem_StripedBlocksHoriz:  BINCLUDE    "art/nemesis/4 stripy blocks from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Raising platform from OOZ ; ArtNem_810B8:
    even
ArtNem_OOZElevator: BINCLUDE    "art/nemesis/Rising platform from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (30 blocks)
; Fan in OOZ        ; ArtNem_81254:
    even
ArtNem_OOZFanHoriz: BINCLUDE    "art/nemesis/Fan from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Green flame thing that shoots platform up in OOZ  ; ArtNem_81514:
    even
ArtNem_OOZBurn: BINCLUDE    "art/nemesis/Green flame from OOZ burners.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Patterns for appearing and disappearing string of platforms in CNZ    ; ArtNem_81600:
    even
ArtNem_CNZSnake:    BINCLUDE    "art/nemesis/Caterpiller platforms from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Spikey ball from pokie in CNZ     ; ArtNem_81668:
    even
ArtNem_CNZBonusSpike:   BINCLUDE    "art/nemesis/Spikey ball from CNZ slots.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Moving cube from either CNZ or CPZ    ; ArtNem_816C8:
    even
ArtNem_BigMovingBlock:  BINCLUDE    "art/nemesis/Moving block from CNZ and CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Elevator in CNZ       ; ArtNem_817B4:
    even
ArtNem_CNZElevator: BINCLUDE    "art/nemesis/CNZ elevator.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Bars from pokies in CNZ   ; ArtNem_81826:
    even
ArtNem_CNZCage: BINCLUDE    "art/nemesis/CNZ slot machine bars.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (6 blocks)
; Hexagonal bumper in CNZ   ; ArtNem_81894:
    even
ArtNem_CNZHexBumper:    BINCLUDE    "art/nemesis/Hexagonal bumper from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Normal round bumper from CNZ  ; ArtNem_8191E:
    even
ArtNem_CNZRoundBumper:  BINCLUDE    "art/nemesis/Round bumper from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Diagonal spring from CNZ that you charge up   ; ArtNem_81AB0:
    even
ArtNem_CNZDiagPlunger:  BINCLUDE    "art/nemesis/Diagonal impulse spring from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Vertical red spring       ; ArtNem_81C96:
    even
ArtNem_CNZVertPlunger:  BINCLUDE    "art/nemesis/Vertical impulse spring.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Weird blocks from CNZ that you hit 3 times to get rid of  ; ArtNem_81DCC:
    even
ArtNem_CNZMiniBumper:   BINCLUDE    "art/nemesis/Drop target from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (52 blocks)
; Flippers from CNZ ; ArtNem_81EF2:
    even
ArtNem_CNZFlipper:  BINCLUDE    "art/nemesis/Flippers.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Large moving platform from CPZ    ; ArtNem_82216:
    even
ArtNem_CPZElevator: BINCLUDE    "art/nemesis/Large moving platform from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Top of water in HPZ and CPZ   ; ArtNem_82364:
    even
ArtNem_WaterSurface:    BINCLUDE    "art/nemesis/Top of water in HPZ and CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Booster things in CPZ     ; ArtNem_824D4:
    even
ArtNem_CPZBooster:  BINCLUDE    "art/nemesis/Speed booster from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; CPZ droplet chain enemy   ; ArtNem_8253C:
    even
ArtNem_CPZDroplet:  BINCLUDE    "art/nemesis/CPZ worm enemy.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (33 blocks)
; CPZ metal things (girder, cylinders)  ; ArtNem_825AE:
    even
ArtNem_CPZMetalThings:  BINCLUDE    "art/nemesis/CPZ metal things.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; CPZ metal block       ; ArtNem_827B8:
    even
ArtNem_CPZMetalBlock:   BINCLUDE    "art/nemesis/CPZ large moving platform blocks.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Yellow and black stripy tiles from DEZ    ; ArtNem_827F8:
    even
ArtNem_ConstructionStripes: BINCLUDE    "art/nemesis/Stripy blocks from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (48 blocks)
; Yellow flipping platforms and stuff CPZ   ; ArtNem_82864:
    even
ArtNem_CPZAnimatedBits: BINCLUDE    "art/nemesis/Small yellow moving platform from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Moving block from CPZ     ; ArtNem_82A46:
    even
ArtNem_CPZStairBlock:   BINCLUDE    "art/nemesis/Moving block from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Spring that covers tube in CPZ    ; ArtNem_82C06:
    even
ArtNem_CPZTubeSpring:   BINCLUDE    "art/nemesis/CPZ spintube exit cover.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Top of water in ARZ       ; ArtNem_82E02:
    even
ArtNem_WaterSurface2:   BINCLUDE    "art/nemesis/Top of water in ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (7 blocks)
; Leaves from ARZ   ; ArtNem_82EE8:
    even
ArtNem_Leaves:  BINCLUDE    "art/nemesis/Leaves in ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (17 blocks)
; Arrow shooter and arrow from ARZ  ; ArtNem_82F74:
    even
ArtNem_ArrowAndShooter: BINCLUDE    "art/nemesis/Arrow shooter and arrow from ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; One way barrier from ARZ (unused?)    ; ArtNem_830D2:
    even
ArtNem_ARZBarrierThing: BINCLUDE    "art/nemesis/One way barrier from ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Buzz bomber           ; ArtNem_8316A:
    even
ArtNem_Buzzer:  BINCLUDE    "art/nemesis/Buzzer enemy.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (58 blocks)
; Octopus badnik from OOZ   ; ArtNem_8336A:
    even
ArtNem_Octus:   BINCLUDE    "art/nemesis/Octopus badnik from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (56 blocks)
; Flying badnik from OOZ    ; ArtNem_8368A:
    even
ArtNem_Aquis:   BINCLUDE    "art/nemesis/Seahorse from OOZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (22 blocks)
; Fish badnik from EHZ      ; ArtNem_839EA: ArtNem_Pirahna:
    even
ArtNem_Masher:  BINCLUDE    "art/nemesis/EHZ Pirahna badnik.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (96 blocks)
; Robotnik's main ship      ; ArtNem_83BF6:
    even
ArtNem_Eggpod:  BINCLUDE    "art/nemesis/Eggpod.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (111 blocks)
; CPZ Boss          ; ArtNem_84332:
    even
ArtNem_CPZBoss: BINCLUDE    "art/nemesis/CPZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (100 blocks)
; Large explosion       ; ArtNem_84890:
    even
ArtNem_FieryExplosion:  BINCLUDE    "art/nemesis/Large explosion.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Horizontal jet        ; ArtNem_84F18:
    even
ArtNem_EggpodJets:  BINCLUDE    "art/nemesis/Horizontal jet.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Smoke trail from CPZ and HTZ bosses   ; ArtNem_84F96:
    even
ArtNem_BossSmoke:   BINCLUDE    "art/nemesis/Smoke trail from CPZ and HTZ bosses.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (128 blocks)
; EHZ Boss  ; ArtNem_8507C:
    even
ArtNem_EHZBoss: BINCLUDE    "art/nemesis/EHZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Helicopter blades for EHZ boss    ; ArtNem_85868:
    even
ArtNem_EggChoppers: BINCLUDE    "art/nemesis/Chopper blades for EHZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (107 blocks)
; HTZ boss          ; ArtNem_8595C:
    even
ArtNem_HTZBoss: BINCLUDE    "art/nemesis/HTZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (166 blocks)
; ARZ boss          ; ArtNem_86128:
    even
ArtNem_ARZBoss: BINCLUDE    "art/nemesis/ARZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (204 blocks)
; MCZ boss          ; ArtNem_86B6E:
    even
ArtNem_MCZBoss: BINCLUDE    "art/nemesis/MCZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (133 blocks)
; CNZ boss          ; ArtNem_87AAC:
    even
ArtNem_CNZBoss: BINCLUDE    "art/nemesis/CNZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (181 blocks)
; OOZ boss          ; ArtNem_882D6:
    even
ArtNem_OOZBoss: BINCLUDE    "art/nemesis/OOZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (124 blocks)
; MTZ boss          ; ArtNem_88DA6:
    even
ArtNem_MTZBoss: BINCLUDE    "art/nemesis/MTZ boss.bin"
;--------------------------------------------------------------------------------------
; Uncompressed art (8 blocks)
; Falling rocks and stalactites from MCZ    ; ArtUnc_894E4:
    even
ArtUnc_FallingRocks:    BINCLUDE    "art/uncompressed/Falling rocks and stalactites from MCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (9 blocks)
; Blowfly from ARZ  ; ArtNem_895E4:
    even
ArtNem_Whisp:   BINCLUDE    "art/nemesis/Blowfly from ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (50 blocks)
; Grounder from ARZ ; ArtNem_8970E:
    even
ArtNem_Grounder:    BINCLUDE    "art/nemesis/Grounder from ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Fish from ARZ     ; ArtNem_89B9A:
    even
ArtNem_ChopChop:    BINCLUDE    "art/nemesis/Shark from ARZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (19 blocks)
; Lava snake from HTZ       89DEC: ArtNem_HtzRexxon:
    even
ArtNem_Rexon:   BINCLUDE    "art/nemesis/Rexxon (lava snake) from HTZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Enemy with spike cone on top from HTZ     89FAA:  ArtNem_HtzDriller:
    even
ArtNem_Spiker:  BINCLUDE    "art/nemesis/Driller badnik from HTZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Bomber badnik from SCZ    ; ArtNem_8A142:
    even
ArtNem_Nebula:  BINCLUDE    "art/nemesis/Bomber badnik from SCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (57 blocks)
; Turtle badnik from SCZ    ; ArtNem_8A362:
    even
ArtNem_Turtloid:    BINCLUDE    "art/nemesis/Turtle badnik from SCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (38 blocks)
; Coconuts monkey badnik from EHZ
    even
ArtNem_Coconuts:    BINCLUDE    "art/nemesis/Coconuts badnik from EHZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; Snake badnik from MCZ     ; ArtNem_8AB36:
    even
ArtNem_Crawlton:    BINCLUDE    "art/nemesis/Snake badnik from MCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Firefly from MCZ      ; ArtNem_8AC5E:
    even
ArtNem_Flasher: BINCLUDE    "art/nemesis/Firefly from MCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Praying mantis badnik from MTZ    8AD80:
    even
ArtNem_MtzMantis:   BINCLUDE    "art/nemesis/Praying mantis badnik from MTZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (36 blocks)
; Crab badnik from MCZ          8B058:
    even
ArtNem_Crabmeat:    BINCLUDE    "art/nemesis/Crabmeat badnik from MCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (15 blocks)
; Exploding star badnik from MTZ    8B300:
    even
ArtNem_MtzSupernova:    BINCLUDE    "art/nemesis/Exploding star badnik from MTZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Weird crawling badnik from CPZ    ; ArtNem_8B430:
    even
ArtNem_Spiny:   BINCLUDE    "art/nemesis/Weird crawling badnik from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (45 blocks)
; Spider badnik from CPZ    ArtNem_8B6B4:
    even
ArtNem_Grabber: BINCLUDE    "art/nemesis/Spider badnik from CPZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (26 blocks)
; Chicken badnik from WFZ       8B9DC:
    even
ArtNem_WfzScratch:  BINCLUDE    "art/nemesis/Scratch from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (25 blocks)
; Jet like badnik from SCZ      8BC16:
    even
ArtNem_Balkrie: BINCLUDE    "art/nemesis/Balkrie (jet badnik) from SCZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (217 blocks)
; Silver Sonic          ; ArtNem_8BE12:
    even
ArtNem_SilverSonic: BINCLUDE    "art/nemesis/Silver Sonic.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (79 blocks)
; The Tornado           8CC44:
    even
ArtNem_Tornado: BINCLUDE    "art/nemesis/The Tornado.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Wall turret from WFZ      8D1A0:
    even
ArtNem_WfzWallTurret:   BINCLUDE    "art/nemesis/Wall turret from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Hook on chain in WFZ      8D388:
    even
ArtNem_WfzHook: BINCLUDE    "art/nemesis/Hook on chain from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (54 blocks)
; Retracting platform from WFZ      8D540:
    even
ArtNem_WfzGunPlatform:  BINCLUDE    "art/nemesis/Retracting platform from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Wheel for belt in WFZ     8D7D8:
    even
ArtNem_WfzConveyorBeltWheel:    BINCLUDE    "art/nemesis/Wheel for belt in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Moving platform in WFZ    8D96E:
    even
ArtNem_WfzFloatingPlatform: BINCLUDE    "art/nemesis/Moving platform from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Giant unused vertical red laser in WFZ    8DA6E:
    even
ArtNem_WfzVrtclLazer:   BINCLUDE    "art/nemesis/Unused vertical laser in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (18 blocks)
; Clouds            8DAFC:
    even
ArtNem_Clouds:  BINCLUDE    "art/nemesis/Clouds.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; Red horizontal laser in WFZ       8DC42:
    even
ArtNem_WfzHrzntlLazer:  BINCLUDE    "art/nemesis/Red horizontal laser from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (5 blocks)
; Catapult that shoots sonic across quickly in WFZ  8DCA2:
    even
ArtNem_WfzLaunchCatapult:   BINCLUDE    "art/nemesis/Catapult that shoots Sonic to the side from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Rising platforms on belt from WFZ 8DD0C:
    even
ArtNem_WfzBeltPlatform: BINCLUDE    "art/nemesis/Platform on belt in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Unused badnik in WFZ      8DDF6:
    even
ArtNem_WfzUnusedBadnik: BINCLUDE    "art/nemesis/Unused badnik from WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Vertical spinning blades from WFZ 8DEB8:
    even
ArtNem_WfzVrtclPrpllr:  BINCLUDE    "art/nemesis/Vertical spinning blades in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (29 blocks)
; Horizontal spinning blades from WFZ       8DEE8:
    even
ArtNem_WfzHrzntlPrpllr: BINCLUDE    "art/nemesis/Horizontal spinning blades in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Platforms that tilt in WFZ        8E010:
    even
ArtNem_WfzTiltPlatforms:    BINCLUDE    "art/nemesis/Tilting plaforms in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Thrust from Robotnic's getaway ship in WFZ        8E0C4:
    even
ArtNem_WfzThrust:   BINCLUDE    "art/nemesis/Thrust from Robotnik's getaway ship in WFZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (117 blocks)
; Laser boss from WFZ   ; ArtNem_8E138:
    even
ArtNem_WFZBoss: BINCLUDE    "art/nemesis/WFZ boss.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Robotnik's head   ; ArtNem_8E886:
    even
ArtNem_RobotnikUpper:   BINCLUDE    "art/nemesis/Robotnik's head.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (76 blocks)
; Robotnik      ; ArtNem_8EA5A:
    even
ArtNem_RobotnikRunning: BINCLUDE    "art/nemesis/Robotnik.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (28 blocks)
; Robotnik's lower half ; ArtNem_8EE52:
    even
ArtNem_RobotnikLower:   BINCLUDE    "art/nemesis/Robotnik's lover half.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Window in back that Robotnic looks through in DEZ ; ArtNem_8EF96:
    even
ArtNem_DEZWindow:   BINCLUDE    "art/nemesis/Window in back that Robotnik looks through in DEZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (327 blocks)
; Eggrobo       ; ArtNem_8F024:
    even
ArtNem_DEZBoss: BINCLUDE    "art/nemesis/Eggrobo.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (42 blocks)
; Bouncer badnik from CNZ   ; ArtNem_901A4:
    even
ArtNem_Crawl:   BINCLUDE    "art/nemesis/Bouncer badnik from CNZ.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (26 blocks)
; Rocket thruster for Tornado   ; ArtNem_90520:
    even
ArtNem_TornadoThruster: BINCLUDE    "art/nemesis/Rocket thruster for Tornado.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Frame 1 of end of game sequence   ; MapEng_906E0:
MapEng_Ending1: BINCLUDE    "mappings/misc/End of game sequence frame 1.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Frame 2 of end of game sequence   ; MapEng_906F8:
MapEng_Ending2: BINCLUDE    "mappings/misc/End of game sequence frame 2.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Frame 3 of end of game sequence   ; MapEng_90722:
MapEng_Ending3: BINCLUDE    "mappings/misc/End of game sequence frame 3.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Frame 4 of end of game sequence   ; MapEng_9073C:
MapEng_Ending4: BINCLUDE    "mappings/misc/End of game sequence frame 4.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Closeup of Tails flying plane in ending sequence  ; MapEng_9076E:
MapEng_EndingTailsPlane:    BINCLUDE    "mappings/misc/Closeup of Tails flying plane in ending sequence.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Closeup of Sonic flying plane in ending sequence  ; MapEng_907C0:
MapEng_EndingSonicPlane:    BINCLUDE    "mappings/misc/Closeup of Sonic flying plane in ending sequence.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (duplicate of MapEng_EndGameLogo)
; MapEng_9082A:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 1.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_90852:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 2.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_9087A:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 3.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_908A2:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 4.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_908CA:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 5.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_908F2:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 6.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_9091A:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 7.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_90942:
    BINCLUDE    "mappings/misc/Strange unused mappings 1 - 8.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed sprite mappings
; Strange unused mappings (same as above)
; MapEng_9096A:
    BINCLUDE    "mappings/misc/Strange unused mappings 2.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (363 blocks)
; Movie sequence at end of game     ; ArtNem_90992:
    even
ArtNem_EndingPics:  BINCLUDE    "art/nemesis/Movie sequence at end of game.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (127 blocks)
; Final image of Tornado with it and Sonic facing screen    ; ArtNem_91F3C:
    even
ArtNem_EndingFinalTornado:  BINCLUDE    "art/nemesis/Final image of Tornado with it and Sonic facing screen.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (109 blocks)
; Mini pictures of Tornado in final ending sequence ; ArtNem_927E0:
    even
ArtNem_EndingMiniTornado:   BINCLUDE    "art/nemesis/Small pictures of Tornado in final ending sequence.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (135 blocks)
; Mini pictures of Sonic and final image of Sonic
    even
ArtNem_EndingSonic: BINCLUDE    "art/nemesis/Small pictures of Sonic and final image of Sonic.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (117 blocks)
; Mini pictures of Sonic and final image of Sonic in supersonic mode    ; ArtNem_93848:
    even
ArtNem_EndingSuperSonic:    BINCLUDE    "art/nemesis/Small pictures of Sonic and final image of Sonic in Super Sonic mode.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (181 blocks)
; Final image of Tails      ; ArtNem_93F3C:
    even
ArtNem_EndingTails: BINCLUDE    "art/nemesis/Final image of Tails.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (72 blocks)
; Sonic the Hedgehog 2 image at end of credits  ; ArtNem_94B28:
    even
ArtNem_EndingTitle: BINCLUDE    "art/nemesis/Sonic the Hedgehog 2 image at end of credits.bin"
 
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; LEVEL ART AND BLOCK MAPPINGS (16x16 and 128x128)
;
; #define BLOCK_TBL_LEN  // table length unknown
; #define BIGBLOCK_TBL_LEN // table length unknown
; typedef uint16_t uword
;
; struct blockMapElement {
;  uword unk : 5;    // u
;  uword patternIndex : 11; };  // i
; // uuuu uiii iiii iiii
;
; blockMapElement (*blockMapTable)[BLOCK_TBL_LEN][4] = 0xFFFF9000
;
; struct bigBlockMapElement {
;  uword : 4
;  uword blockMapIndex : 12; };  //I
; // 0000 IIII IIII IIII
;
; bigBlockMapElement (*bigBlockMapTable)[BIGBLOCK_TBL_LEN][64] = 0xFFFF0000
;
; /*
; This data determines how the level blocks will be constructed graphically. There are
; two kinds of block mappings: 16x16 and 128x128.
;
; 16x16 blocks are made up of four cells arranged in a square (thus, 16x16 pixels).
; Two bytes are used to define each cell, so the block is 8 bytes long. It can be
; represented by the bitmap blockMapElement, of which the members are:
;
; unk
;  These bits have to do with pattern orientation. I do not know their exact
;  meaning.
; patternIndex
;  The pattern's address divided by $20. Otherwise said: an index into the
;  pattern array.
;
; Each mapping can be expressed as an array of four blockMapElements, while the
; whole table is expressed as a two-dimensional array of blockMapElements (blockMapTable).
; The maps are read in left-to-right, top-to-bottom order.
;
; 128x128 maps are basically lists of indices into blockMapTable. The levels are built
; out of these "big blocks", rather than the "small" 16x16 blocks. bigBlockMapTable is,
; predictably, the table of big block mappings.
; Each big block is 8 16x16 blocks, or 16 cells, square. This produces a total of 16
; blocks or 64 cells.
; As noted earlier, each element of the table provides 'i' for blockMapTable[i][j].
; */
 
;----------------------------------------------------------------------------------
; EHZ 16x16 block mappings (Kosinski compression) ; was: (Kozinski compression)
BM16_EHZ:   BINCLUDE    "mappings/16x16/EHZ.bin"
;-----------------------------------------------------------------------------------
; EHZ/HTZ main level patterns (Kosinski compression)
; ArtKoz_95C24:
ArtKos_EHZ: BINCLUDE    "art/kosinski/EHZ_HTZ.bin"
;-----------------------------------------------------------------------------------
; HTZ 16x16 block mappings (Kosinski compression)
BM16_HTZ:   BINCLUDE    "mappings/16x16/HTZ.bin"
;-----------------------------------------------------------------------------------
; HTZ pattern suppliment to EHZ level patterns (Kosinski compression)
; ArtKoz_98AB4:
ArtKos_HTZ: BINCLUDE    "art/kosinski/HTZ_Supp.bin"
;-----------------------------------------------------------------------------------
; EHZ/HTZ 128x128 block mappings (Kosinski compression)
BM128_EHZ:  BINCLUDE    "mappings/128x128/EHZ_HTZ.bin"
;-----------------------------------------------------------------------------------
; MTZ 16x16 block mappings (Kosinski compression)
BM16_MTZ:   BINCLUDE    "mappings/16x16/MTZ.bin"
;-----------------------------------------------------------------------------------
; MTZ main level patterns (Kosinski compression)
; ArtKoz_9DB64:
ArtKos_MTZ: BINCLUDE    "art/kosinski/MTZ.bin"
;-----------------------------------------------------------------------------------
; MTZ 128x128 block mappings (Kosinski compression)
BM128_MTZ:  BINCLUDE    "mappings/128x128/MTZ.bin"
;-----------------------------------------------------------------------------------
; HPZ 16x16 block mappings (Kosinski compression)
BM16_HPZ:   ;BINCLUDE   "mappings/16x16/HPZ.bin"
;-----------------------------------------------------------------------------------
; HPZ main level patterns (Kosinski compression)
ArtKos_HPZ: ;BINCLUDE   "art/kosinski/HPZ.bin"
;-----------------------------------------------------------------------------------
; HPZ 128x128 block mappings (Kosinski compression)
BM128_HPZ:  ;BINCLUDE   "mappings/128x128/HPZ.bin"
;-----------------------------------------------------------------------------------
; OOZ 16x16 block mappings (Kosinski compression)
BM16_OOZ:   BINCLUDE    "mappings/16x16/OOZ.bin"
;-----------------------------------------------------------------------------------
; OOZ main level patterns (Kosinski compression)
; ArtKoz_A4204:
ArtKos_OOZ: BINCLUDE    "art/kosinski/OOZ.bin"
;-----------------------------------------------------------------------------------
; OOZ 128x128 block mappings (Kosinski compression)
BM128_OOZ:  BINCLUDE    "mappings/128x128/OOZ.bin"
;-----------------------------------------------------------------------------------
; MCZ 16x16 block mappings (Kosinski compression)
BM16_MCZ:   BINCLUDE    "mappings/16x16/MCZ.bin"
;-----------------------------------------------------------------------------------
; MCZ main level patterns (Kosinski compression)
; ArtKoz_A9D74:
ArtKos_MCZ: BINCLUDE    "art/kosinski/MCZ.bin"
;-----------------------------------------------------------------------------------
; MCZ 128x128 block mappings (Kosinski compression)
BM128_MCZ:  BINCLUDE    "mappings/128x128/MCZ.bin"
;-----------------------------------------------------------------------------------
; CNZ 16x16 block mappings (Kosinski compression)
BM16_CNZ:   BINCLUDE    "mappings/16x16/CNZ.bin"
;-----------------------------------------------------------------------------------
; CNZ main level patterns (Kosinski compression)
; ArtKoz_B0894:
ArtKos_CNZ: BINCLUDE    "art/kosinski/CNZ.bin"
;-----------------------------------------------------------------------------------
; CNZ 128x128 block mappings (Kosinski compression)
BM128_CNZ:  BINCLUDE    "mappings/128x128/CNZ.bin"
;-----------------------------------------------------------------------------------
; CPZ/DEZ 16x16 block mappings (Kosinski compression)
BM16_CPZ:   BINCLUDE    "mappings/16x16/CPZ_DEZ.bin"
;-----------------------------------------------------------------------------------
; CPZ/DEZ main level patterns (Kosinski compression)
; ArtKoz_B6174:
ArtKos_CPZ: BINCLUDE    "art/kosinski/CPZ_DEZ.bin"
;-----------------------------------------------------------------------------------
; CPZ/DEZ 128x128 block mappings (Kosinski compression)
BM128_CPZ:  BINCLUDE    "mappings/128x128/CPZ_DEZ.bin"
;-----------------------------------------------------------------------------------
; ARZ 16x16 block mappings (Kosinski compression)
BM16_ARZ:   BINCLUDE    "mappings/16x16/ARZ.bin"
;-----------------------------------------------------------------------------------
; ARZ main level patterns (Kosinski compression)
; ArtKoz_BCC24:
ArtKos_ARZ: BINCLUDE    "art/kosinski/ARZ.bin"
;-----------------------------------------------------------------------------------
; ARZ 128x128 block mappings (Kosinski compression)
BM128_ARZ:  BINCLUDE    "mappings/128x128/ARZ.bin"
;-----------------------------------------------------------------------------------
; WFZ/SCZ 16x16 block mappings (Kosinski compression)
BM16_WFZ:   BINCLUDE    "mappings/16x16/WFZ_SCZ.bin"
;-----------------------------------------------------------------------------------
; WFZ/SCZ main level patterns (Kosinski compression)
; ArtKoz_C5004:
ArtKos_SCZ: BINCLUDE    "art/kosinski/WFZ_SCZ.bin"
;-----------------------------------------------------------------------------------
; WFZ pattern suppliment to SCZ tiles (Kosinski compression)
; ArtKoz_C7EC4:
ArtKos_WFZ: BINCLUDE    "art/kosinski/WFZ_Supp.bin"
;-----------------------------------------------------------------------------------
; WFZ/SCZ 128x128 block mappings (Kosinski compression)
BM128_WFZ:  BINCLUDE    "mappings/128x128/WFZ_SCZ.bin"
 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;-----------------------------------------------------------------------------------
; Exit curve + slope up
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CA904:
MapSpec_Rise1:  BINCLUDE    "mappings/special stage/Slope up - Frame 1.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CADA8:
MapSpec_Rise2:  BINCLUDE    "mappings/special stage/Slope up - Frame 2.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CB376:
MapSpec_Rise3:  BINCLUDE    "mappings/special stage/Slope up - Frame 3.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CB92E:
MapSpec_Rise4:  BINCLUDE    "mappings/special stage/Slope up - Frame 4.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CBF92:
MapSpec_Rise5:  BINCLUDE    "mappings/special stage/Slope up - Frame 5.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CC5BE:
MapSpec_Rise6:  BINCLUDE    "mappings/special stage/Slope up - Frame 6.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CCC7A:
MapSpec_Rise7:  BINCLUDE    "mappings/special stage/Slope up - Frame 7.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CD282:
MapSpec_Rise8:  BINCLUDE    "mappings/special stage/Slope up - Frame 8.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CD7C0:
MapSpec_Rise9:  BINCLUDE    "mappings/special stage/Slope up - Frame 9.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CDD44:
MapSpec_Rise10: BINCLUDE    "mappings/special stage/Slope up - Frame 10.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CE2BE:
MapSpec_Rise11: BINCLUDE    "mappings/special stage/Slope up - Frame 11.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CE7DE:
MapSpec_Rise12: BINCLUDE    "mappings/special stage/Slope up - Frame 12.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CEC52:
MapSpec_Rise13: BINCLUDE    "mappings/special stage/Slope up - Frame 13.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CF0BC:
MapSpec_Rise14: BINCLUDE    "mappings/special stage/Slope up - Frame 14.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CF580:
MapSpec_Rise15: BINCLUDE    "mappings/special stage/Slope up - Frame 15.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CFA00:
MapSpec_Rise16: BINCLUDE    "mappings/special stage/Slope up - Frame 16.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_CFE4A:
MapSpec_Rise17: BINCLUDE    "mappings/special stage/Slope up - Frame 17.bin"
 
;-----------------------------------------------------------------------------------
; Straight path
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D028C:
MapSpec_Straight1:  BINCLUDE    "mappings/special stage/Straight path - Frame 1.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D090A:
MapSpec_Straight2:  BINCLUDE    "mappings/special stage/Straight path - Frame 2.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D0EA6:
MapSpec_Straight3:  BINCLUDE    "mappings/special stage/Straight path - Frame 3.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D1400:
MapSpec_Straight4:  BINCLUDE    "mappings/special stage/Straight path - Frame 4.bin"
 
;-----------------------------------------------------------------------------------
; Exit curve + slope down
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D19FC:
MapSpec_Drop1:  BINCLUDE    "mappings/special stage/Slope down - Frame 1.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D1EAC:
MapSpec_Drop2:  BINCLUDE    "mappings/special stage/Slope down - Frame 2.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D23AE:
MapSpec_Drop3:  BINCLUDE    "mappings/special stage/Slope down - Frame 3.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D27C6:
MapSpec_Drop4:  BINCLUDE    "mappings/special stage/Slope down - Frame 4.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D2C14:
MapSpec_Drop5:  BINCLUDE    "mappings/special stage/Slope down - Frame 5.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D3092:
MapSpec_Drop6:  BINCLUDE    "mappings/special stage/Slope down - Frame 6.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D3522:
MapSpec_Drop7:  BINCLUDE    "mappings/special stage/Slope down - Frame 7.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D39EC:
MapSpec_Drop8:  BINCLUDE    "mappings/special stage/Slope down - Frame 8.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D3F78:
MapSpec_Drop9:  BINCLUDE    "mappings/special stage/Slope down - Frame 9.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D4660:
MapSpec_Drop10: BINCLUDE    "mappings/special stage/Slope down - Frame 10.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D4DA6:
MapSpec_Drop11: BINCLUDE    "mappings/special stage/Slope down - Frame 11.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D53FC:
MapSpec_Drop12: BINCLUDE    "mappings/special stage/Slope down - Frame 12.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D5958:
MapSpec_Drop13: BINCLUDE    "mappings/special stage/Slope down - Frame 13.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D5F02:
MapSpec_Drop14: BINCLUDE    "mappings/special stage/Slope down - Frame 14.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D6596:
MapSpec_Drop15: BINCLUDE    "mappings/special stage/Slope down - Frame 15.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D6BAA:
MapSpec_Drop16: BINCLUDE    "mappings/special stage/Slope down - Frame 16.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D702E:
MapSpec_Drop17: BINCLUDE    "mappings/special stage/Slope down - Frame 17.bin"
 
;-----------------------------------------------------------------------------------
; Curved path
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D749C:
MapSpec_Turning1:   BINCLUDE    "mappings/special stage/Curve right - Frame 1.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D7912:
MapSpec_Turning2:   BINCLUDE    "mappings/special stage/Curve right - Frame 2.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D7DAA:
MapSpec_Turning3:   BINCLUDE    "mappings/special stage/Curve right - Frame 3.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D8250:
MapSpec_Turning4:   BINCLUDE    "mappings/special stage/Curve right - Frame 4.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D85F8:
MapSpec_Turning5:   BINCLUDE    "mappings/special stage/Curve right - Frame 5.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings ; MapSpec_D89EC:
MapSpec_Turning6:   BINCLUDE    "mappings/special stage/Curve right - Frame 6.bin"
 
;-----------------------------------------------------------------------------------
; Exit curve
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Exit curve  ; MapSpec_D8E24:
MapSpec_Unturn1:    BINCLUDE    "mappings/special stage/Curve right - Frame 7.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Exit curve  ; MapSpec_D92B6:
MapSpec_Unturn2:    BINCLUDE    "mappings/special stage/Curve right - Frame 8.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Exit curve  ; MapSpec_D9778:
MapSpec_Unturn3:    BINCLUDE    "mappings/special stage/Curve right - Frame 9.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Exit curve  ; MapSpec_D9B80:
MapSpec_Unturn4:    BINCLUDE    "mappings/special stage/Curve right - Frame 10.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Exit curve  ; MapSpec_DA016:
MapSpec_Unturn5:    BINCLUDE    "mappings/special stage/Curve right - Frame 11.bin"
 
;-----------------------------------------------------------------------------------
; Enter curve
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DA4CE:
MapSpec_Turn1:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 1.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DAB20:
MapSpec_Turn2:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 2.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DB086:
MapSpec_Turn3:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 3.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DB5AE:
MapSpec_Turn4:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 4.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DBB62:
MapSpec_Turn5:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 5.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DC154:
MapSpec_Turn6:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 6.bin"
;-----------------------------------------------------------------------------------
; Special stage tube mappings
; Begin curve right ; MapSpec_DC5E8:
MapSpec_Turn7:  BINCLUDE    "mappings/special stage/Begin curve right - Frame 7.bin"
 
;--------------------------------------------------------------------------------------
; Kosinski compressed art
; Special stage level patterns
; Note: Only one line of each tile is stored in this archive. The other 7 lines are
;  the same as this one line, so to get the full tiles, each line needs to be
;  duplicated 7 times over.                 ; ArtKoz_DCA38:
;--------------------------------------------------------------------------------------
ArtKos_Special: BINCLUDE    "art/kosinski/SpecStag.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (127 blocks)
; Background patterns for special stage     ; ArtNem_DCD68:
    even
ArtNem_SpecialBack: BINCLUDE    "art/nemesis/Background art for special stage.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed tile mappings
; Main background mappings for special stage    ; MapEng_DD1DE:
MapEng_SpecialBack: BINCLUDE    "mappings/misc/Main background mappings for special stage.bin"
;--------------------------------------------------------------------------------------
; Enigma compressed tile mappings
; Lower background mappings for special stage   ; MapEng_DD30C:
MapEng_SpecialBackBottom:   BINCLUDE    "mappings/misc/Lower background mappings for special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (62 blocks)
; Sonic/Miles and number text from special stage    ; ArtNem_DD48A:
    even
ArtNem_SpecialHUD:  BINCLUDE    "art/nemesis/Sonic and Miles number text from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (48 blocks)
; "Start" and checkered flag patterns in special stage  ; ArtNem_DD790:
    even
ArtNem_SpecialStart:    BINCLUDE    "art/nemesis/Start text from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (37 blocks)
; Stars in special stage    ; ArtNem_DD8CE:
    even
ArtNem_SpecialStars:    BINCLUDE    "art/nemesis/Stars in special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (13 blocks)
; Text for most of the "Player VS Player" message in 2P special stage   ; ArtNem_DD9C8:
    even
ArtNem_SpecialPlayerVSPlayer:   BINCLUDE    "art/nemesis/Special stage Player VS Player text.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (104 blocks)
; Ring patterns in special stage    ; ArtNem_DDA7E:
    even
ArtNem_SpecialRings:    BINCLUDE    "art/nemesis/Special stage ring art.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (38 blocks)
; Horizontal shadow patterns in special stage   ; ArtNem_DDFA4:
    even
ArtNem_SpecialFlatShadow:   BINCLUDE    "art/nemesis/Horizontal shadow from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (58 blocks)
; Diagonal shadow patterns in special stage ; ArtNem_DE05A:
    even
ArtNem_SpecialDiagShadow:   BINCLUDE    "art/nemesis/Diagonal shadow from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (25 blocks)
; Vertical shadow patterns in special stage ; ArtNem_DE120:
    even
ArtNem_SpecialSideShadow:   BINCLUDE    "art/nemesis/Vertical shadow from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (48 blocks)
; Explosion patterns in special stage   ; ArtNem_DE188:
    even
ArtNem_SpecialExplosion:    BINCLUDE    "art/nemesis/Explosion from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (80 blocks)
; Bomb patterns in special stage    ; ArtNem_DE4BC:
    even
ArtNem_SpecialBomb: BINCLUDE    "art/nemesis/Bomb from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (46 blocks)
; Emerald patterns in special stage ; ArtNem_DE8AC:
    even
ArtNem_SpecialEmerald:  BINCLUDE    "art/nemesis/Emerald from special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (99 blocks)
; Text for the messages and thumbs up/down icon in special stage    ; ArtNem_DEAF4:
    even
ArtNem_SpecialMessages: BINCLUDE    "art/nemesis/Special stage messages and icons.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (851 blocks)
; Sonic and Tails animation frames from special stage
; Art for Obj09 and Obj10 and Obj88 ; ArtNem_DEEAE:
    even
ArtNem_SpecialSonicAndTails:    BINCLUDE    "art/nemesis/Sonic and Tails animation frames in special stage.bin"
;--------------------------------------------------------------------------------------
; Nemesis compressed art (5 blocks)
; "Tails" patterns from special stage   ; ArtNem_E247E:
    even
ArtNem_SpecialTailsText:    BINCLUDE    "art/nemesis/Tails text patterns from special stage.bin"
 
;--------------------------------------------------------------------------------------
; Special stage object perspective data (Kosinski compression)  ; MiscKoz_E24FE:
;--------------------------------------------------------------------------------------
MiscKoz_SpecialPerspective: BINCLUDE    "misc/Special stage object perspective data (Kosinski compression).bin"
;--------------------------------------------------------------------------------------
; Special stage level layout (Nemesis compression)  ; MiscNem_E34EE:
;--------------------------------------------------------------------------------------
MiscKoz_SpecialLevelLayout: BINCLUDE    "misc/Special stage level layouts (Nemesis compression).bin"
;--------------------------------------------------------------------------------------
; Special stage object location list (Kosinski compression) ; MiscKoz_E35F2:
;--------------------------------------------------------------------------------------
MiscKoz_SpecialObjectLocations: BINCLUDE    "misc/Special stage object location lists (Kosinski compression).bin"
    
;--------------------------------------------------------------------------------------
; Filler (free space) (unnecessary; could be replaced with "even")
;--------------------------------------------------------------------------------------
    align $100
 
 
 
 
;--------------------------------------------------------------------------------------
; Offset index of ring locations
;  The first commented number on each line is an array index; the second is the
;  associated zone.
;--------------------------------------------------------------------------------------
Off_Rings: zoneOrderedOffsetTable 2,2
    zoneOffsetTableEntry.w  Rings_EHZ_1 ; 0  $00
    zoneOffsetTableEntry.w  Rings_EHZ_2 ; 1
    zoneOffsetTableEntry.w  Rings_Lev1_1    ; 2  $01
    zoneOffsetTableEntry.w  Rings_Lev1_2    ; 3
    zoneOffsetTableEntry.w  Rings_Lev2_1    ; 4  $02
    zoneOffsetTableEntry.w  Rings_Lev2_2    ; 5
    zoneOffsetTableEntry.w  Rings_Lev3_1    ; 6  $03
    zoneOffsetTableEntry.w  Rings_Lev3_2    ; 7
    zoneOffsetTableEntry.w  Rings_MTZ_1 ; 8  $04
    zoneOffsetTableEntry.w  Rings_MTZ_2 ; 9
    zoneOffsetTableEntry.w  Rings_MTZ_3 ; 10 $05
    zoneOffsetTableEntry.w  Rings_MTZ_4 ; 11
    zoneOffsetTableEntry.w  Rings_WFZ_1 ; 12 $06
    zoneOffsetTableEntry.w  Rings_WFZ_2 ; 13
    zoneOffsetTableEntry.w  Rings_HTZ_1 ; 14 $07
    zoneOffsetTableEntry.w  Rings_HTZ_2 ; 15
    zoneOffsetTableEntry.w  Rings_HPZ_1 ; 16 $08
    zoneOffsetTableEntry.w  Rings_HPZ_2 ; 17
    zoneOffsetTableEntry.w  Rings_Lev9_1    ; 18 $09
    zoneOffsetTableEntry.w  Rings_Lev9_2    ; 19
    zoneOffsetTableEntry.w  Rings_OOZ_1 ; 20 $0A
    zoneOffsetTableEntry.w  Rings_OOZ_2 ; 21
    zoneOffsetTableEntry.w  Rings_MCZ_1 ; 22 $0B
    zoneOffsetTableEntry.w  Rings_MCZ_2 ; 23
    zoneOffsetTableEntry.w  Rings_CNZ_1 ; 24 $0C
    zoneOffsetTableEntry.w  Rings_CNZ_2 ; 25
    zoneOffsetTableEntry.w  Rings_CPZ_1 ; 26 $0D
    zoneOffsetTableEntry.w  Rings_CPZ_2 ; 27
    zoneOffsetTableEntry.w  Rings_DEZ_1 ; 28 $0E
    zoneOffsetTableEntry.w  Rings_DEZ_2 ; 29
    zoneOffsetTableEntry.w  Rings_ARZ_1 ; 30 $0F
    zoneOffsetTableEntry.w  Rings_ARZ_2 ; 31
    zoneOffsetTableEntry.w  Rings_SCZ_1 ; 32 $10
    zoneOffsetTableEntry.w  Rings_SCZ_2 ; 33
    zoneTableEnd
 
Rings_EHZ_1:    BINCLUDE    "level/rings/EHZ_1.bin"
Rings_EHZ_2:    BINCLUDE    "level/rings/EHZ_2.bin"
Rings_Lev1_1:   BINCLUDE    "level/rings/01_1.bin"
Rings_Lev1_2:   BINCLUDE    "level/rings/01_2.bin"
Rings_Lev2_1:   BINCLUDE    "level/rings/02_1.bin"
Rings_Lev2_2:   BINCLUDE    "level/rings/02_2.bin"
Rings_Lev3_1:   BINCLUDE    "level/rings/03_1.bin"
Rings_Lev3_2:   BINCLUDE    "level/rings/03_2.bin"
Rings_MTZ_1:    BINCLUDE    "level/rings/MTZ_1.bin"
Rings_MTZ_2:    BINCLUDE    "level/rings/MTZ_2.bin"
Rings_MTZ_3:    BINCLUDE    "level/rings/MTZ_3.bin"
Rings_MTZ_4:    BINCLUDE    "level/rings/MTZ_4.bin"
Rings_HTZ_1:    BINCLUDE    "level/rings/HTZ_1.bin"
Rings_HTZ_2:    BINCLUDE    "level/rings/HTZ_2.bin"
Rings_HPZ_1:    BINCLUDE    "level/rings/HPZ_1.bin"
Rings_HPZ_2:    BINCLUDE    "level/rings/HPZ_2.bin"
Rings_Lev9_1:   BINCLUDE    "level/rings/09_1.bin"
Rings_Lev9_2:   BINCLUDE    "level/rings/09_2.bin"
Rings_OOZ_1:    BINCLUDE    "level/rings/OOZ_1.bin"
Rings_OOZ_2:    BINCLUDE    "level/rings/OOZ_2.bin"
Rings_MCZ_1:    BINCLUDE    "level/rings/MCZ_1.bin"
Rings_MCZ_2:    BINCLUDE    "level/rings/MCZ_2.bin"
Rings_CNZ_1:    BINCLUDE    "level/rings/CNZ_1.bin"
Rings_CNZ_2:    BINCLUDE    "level/rings/CNZ_2.bin"
Rings_CPZ_1:    BINCLUDE    "level/rings/CPZ_1.bin"
Rings_CPZ_2:    BINCLUDE    "level/rings/CPZ_2.bin"
Rings_DEZ_1:    BINCLUDE    "level/rings/DEZ_1.bin"
Rings_DEZ_2:    BINCLUDE    "level/rings/DEZ_2.bin"
Rings_WFZ_1:    BINCLUDE    "level/rings/WFZ_1.bin"
Rings_WFZ_2:    BINCLUDE    "level/rings/WFZ_2.bin"
Rings_ARZ_1:    BINCLUDE    "level/rings/ARZ_1.bin"
Rings_ARZ_2:    BINCLUDE    "level/rings/ARZ_2.bin"
Rings_SCZ_1:    BINCLUDE    "level/rings/SCZ_1.bin"
Rings_SCZ_2:    BINCLUDE    "level/rings/SCZ_2.bin"
 
; --------------------------------------------------------------------------------------
; Filler (free space) (unnecessary; could be replaced with "even")
; --------------------------------------------------------------------------------------
    align $200
 
; --------------------------------------------------------------------------------------
; Offset index of object locations
; --------------------------------------------------------------------------------------
Off_Objects: zoneOrderedOffsetTable 2,2
    zoneOffsetTableEntry.w  Objects_EHZ_1   ; 0  $00
    zoneOffsetTableEntry.w  Objects_EHZ_2   ; 1
    zoneOffsetTableEntry.w  Objects_Null3   ; 2  $01
    zoneOffsetTableEntry.w  Objects_Null3   ; 3
    zoneOffsetTableEntry.w  Objects_Null3   ; 4  $02
    zoneOffsetTableEntry.w  Objects_Null3   ; 5
    zoneOffsetTableEntry.w  Objects_Null3   ; 6  $03
    zoneOffsetTableEntry.w  Objects_Null3   ; 7
    zoneOffsetTableEntry.w  Objects_MTZ_1   ; 8  $04
    zoneOffsetTableEntry.w  Objects_MTZ_2   ; 9
    zoneOffsetTableEntry.w  Objects_MTZ_3   ; 10 $05
    zoneOffsetTableEntry.w  Objects_MTZ_3   ; 11
    zoneOffsetTableEntry.w  Objects_WFZ_1   ; 12 $06
    zoneOffsetTableEntry.w  Objects_WFZ_2   ; 13
    zoneOffsetTableEntry.w  Objects_HTZ_1   ; 14 $07
    zoneOffsetTableEntry.w  Objects_HTZ_2   ; 15
    zoneOffsetTableEntry.w  Objects_HPZ_1   ; 16 $08
    zoneOffsetTableEntry.w  Objects_HPZ_2   ; 17
    zoneOffsetTableEntry.w  Objects_Null3   ; 18 $09
    zoneOffsetTableEntry.w  Objects_Null3   ; 19
    zoneOffsetTableEntry.w  Objects_OOZ_1   ; 20 $0A
    zoneOffsetTableEntry.w  Objects_OOZ_2   ; 21
    zoneOffsetTableEntry.w  Objects_MCZ_1   ; 22 $0B
    zoneOffsetTableEntry.w  Objects_MCZ_2   ; 23
    zoneOffsetTableEntry.w  Objects_CNZ_1   ; 24 $0C
    zoneOffsetTableEntry.w  Objects_CNZ_2   ; 25
    zoneOffsetTableEntry.w  Objects_CPZ_1   ; 26 $0D
    zoneOffsetTableEntry.w  Objects_CPZ_2   ; 27
    zoneOffsetTableEntry.w  Objects_DEZ_1   ; 28 $0E
    zoneOffsetTableEntry.w  Objects_DEZ_2   ; 29
    zoneOffsetTableEntry.w  Objects_ARZ_1   ; 30 $0F
    zoneOffsetTableEntry.w  Objects_ARZ_2   ; 31
    zoneOffsetTableEntry.w  Objects_SCZ_1   ; 32 $10
    zoneOffsetTableEntry.w  Objects_SCZ_2   ; 33
    zoneTableEnd
 
;Objects_Null1: ; looks unused, but it's really not. there must be a null entry first or you will get crashes. (try going left from second screen of EHZ1)
        BINCLUDE    "level/objects/Null_1.bin"
 
Objects_EHZ_1:  BINCLUDE    "level/objects/EHZ_1.bin"
 
    if gameRevision=0
Objects_EHZ_2:  BINCLUDE    "level/objects/EHZ_2 (REV00).bin"
    else
; a collision switcher was moved
Objects_EHZ_2:  BINCLUDE    "level/objects/EHZ_2.bin"
    endif
 
Objects_MTZ_1:  BINCLUDE    "level/objects/MTZ_1.bin"
Objects_MTZ_2:  BINCLUDE    "level/objects/MTZ_2.bin"
Objects_MTZ_3:  BINCLUDE    "level/objects/MTZ_3.bin"
 
    if gameRevision=0
Objects_WFZ_1:  BINCLUDE    "level/objects/WFZ_1 (REV00).bin"
    else
; lampposts' 'remember state' flags were set
Objects_WFZ_1:  BINCLUDE    "level/objects/WFZ_1.bin"
    endif
 
Objects_WFZ_2:  BINCLUDE    "level/objects/WFZ_2.bin"
Objects_HTZ_1:  BINCLUDE    "level/objects/HTZ_1.bin"
Objects_HTZ_2:  BINCLUDE    "level/objects/HTZ_2.bin"
Objects_HPZ_1:  BINCLUDE    "level/objects/HPZ_1.bin"
Objects_HPZ_2:  BINCLUDE    "level/objects/HPZ_2.bin"
 
;Objects_Null2: ; unused
        BINCLUDE    "level/objects/Null_2.bin"
 
Objects_OOZ_1:  BINCLUDE    "level/objects/OOZ_1.bin"
Objects_OOZ_2:  BINCLUDE    "level/objects/OOZ_2.bin"
Objects_MCZ_1:  BINCLUDE    "level/objects/MCZ_1.bin"
Objects_MCZ_2:  BINCLUDE    "level/objects/MCZ_2.bin"
 
    if gameRevision=0
Objects_CNZ_1:  BINCLUDE    "level/objects/CNZ_1 (REV00).bin"
Objects_CNZ_2:  BINCLUDE    "level/objects/CNZ_2 (REV00).bin"
    else
; the signposts were moved up slightly so they weren't poking out the bottom of the ground
Objects_CNZ_1:  BINCLUDE    "level/objects/CNZ_1.bin"
Objects_CNZ_2:  BINCLUDE    "level/objects/CNZ_2.bin"
    endif
 
Objects_CPZ_1:  BINCLUDE    "level/objects/CPZ_1.bin"
Objects_CPZ_2:  BINCLUDE    "level/objects/CPZ_2.bin"
Objects_DEZ_1:  BINCLUDE    "level/objects/DEZ_1.bin"
Objects_DEZ_2:  BINCLUDE    "level/objects/DEZ_2.bin"
Objects_ARZ_1:  BINCLUDE    "level/objects/ARZ_1.bin"
Objects_ARZ_2:  BINCLUDE    "level/objects/ARZ_2.bin"
Objects_SCZ_1:  BINCLUDE    "level/objects/SCZ_1.bin"
Objects_SCZ_2:  BINCLUDE    "level/objects/SCZ_2.bin"
Objects_Null3:  BINCLUDE    "level/objects/Null_3.bin"
 
;Objects_Null4: ; unused
        BINCLUDE    "level/objects/Null_4.bin"
;Objects_Null5: ; unused
        BINCLUDE    "level/objects/Null_5.bin"
;Objects_Null6: ; unused
        BINCLUDE    "level/objects/Null_6.bin"
 
; --------------------------------------------------------------------------------------
; Filler (free space) (unnecessary; could be replaced with "even")
; --------------------------------------------------------------------------------------
    align $1000
 
 
 
 
; ---------------------------------------------------------------------------
; Subroutine to load the sound driver
; ---------------------------------------------------------------------------
; sub_EC000:
SoundDriverLoad:
    move    sr,-(sp)
    movem.l d0-a6,-(sp)
    move    #$2700,sr
    lea (Z80_Bus_Request).l,a3
    lea (Z80_Reset).l,a2
    moveq   #0,d2
    move.w  #$100,d1
    move.w  d1,(a3) ; get Z80 bus
    move.w  d1,(a2) ; release Z80 reset (was held high by console on startup)
-   btst    d2,(a3)
    bne.s   -   ; wait until the 68000 has the bus
    jsr DecompressSoundDriver(pc)
    btst    #0,(VDP_control_port+1).l   ; check video mode
    sne (Z80_RAM+zPalModeByte).l    ; set if PAL
    move.w  d2,(a2) ; hold Z80 reset
    move.w  d2,(a3) ; release Z80 bus
    moveq   #$E6,d0
-   dbf d0,-    ; wait for 2,314 cycles
    move.w  d1,(a2) ; release Z80 reset
    movem.l (sp)+,d0-a6
    move    (sp)+,sr
    rts
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
; slightly modified Saxman decompression of the sound driver
; a4 == $A00000 (start of Z80 RAM)
; a5 == current position in Z80 RAM?
; a6 == current position in compressed sound driver?
; d0 == data to decompress? (byte)
; d4 == ???
; d5 == ???
; d6 == ???
; d7 == bytes left to decompress
; loc_EC04A:
DecompressSoundDriver:
    lea Snd_Driver(pc),a6
; WARNING: the build script needs editing if you rename this label
movewZ80CompSize:   move.w  #Snd_Driver_End-Snd_Driver,d7 ; patched (by fixpointer.exe) after compression since the exact size can't be known beforehand
    moveq   #0,d6
    lea (Z80_RAM).l,a5
    moveq   #0,d5
    lea (Z80_RAM).l,a4
 
loc_EC062:
    lsr.w   #1,d6
    btst    #8,d6
    bne.s   +
    jsr sub_EC0DE(pc)
    move.b  d0,d6
    ori.w   #$FF00,d6
+
    btst    #0,d6
    beq.s   loc_EC086
    jsr sub_EC0DE(pc)
    move.b  d0,(a5)+
    addq.w  #1,d5
    bra.w   loc_EC062
; ---------------------------------------------------------------------------
 
loc_EC086:
    jsr sub_EC0DE(pc)
    moveq   #0,d4
    move.b  d0,d4
    jsr sub_EC0DE(pc)
    move.b  d0,d3
    andi.w  #$F,d3
    addq.w  #2,d3
    andi.w  #$F0,d0
    lsl.w   #4,d0
    add.w   d0,d4
    addi.w  #$12,d4
    andi.w  #$FFF,d4
    move.w  d5,d0
    andi.w  #$F000,d0
    add.w   d0,d4
    cmp.w   d4,d5
    bhs.s   loc_EC0CC
    subi.w  #$1000,d4
    bcc.s   loc_EC0CC
    add.w   d3,d5
    addq.w  #1,d5
 
-   move.b  #0,(a5)+
    dbf d3,-
 
    bra.w   loc_EC062
; ---------------------------------------------------------------------------
 
loc_EC0CC:
    add.w   d3,d5
    addq.w  #1,d5
 
-   move.b  (a4,d4.w),(a5)+
    addq.w  #1,d4
    dbf d3,-
 
    bra.w   loc_EC062
; End of function DecompressSoundDriver
 
 
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
 
 
sub_EC0DE:
    move.b  (a6)+,d0
    subq.w  #1,d7
    bne.s   +
    addq.w  #4,sp
+
    rts
; End of function sub_EC0DE
 
; ===========================================================================
; ---------------------------------------------------------------------------
; S2 sound driver (Sound driver compression (slightly modified Saxman))
; ---------------------------------------------------------------------------
; loc_EC0E8:
Snd_Driver:
    save
    include "s2.sounddriver.asm" ; CPU Z80
    restore
    padding off
    !org (Snd_Driver+Size_of_Snd_driver_guess) ; don't worry; I know what I'm doing
 
 
; loc_ED04C:
Snd_Driver_End:
 
 
 
 
; ---------------------------------------------------------------------------
; Filler (free space)
; ---------------------------------------------------------------------------
    ; the DAC data has to line up with the end of the bank.
 
    ; actually it only has to fit within one bank, but we'll line it up to the end anyway
    ; because the padding gives the sound driver some room to grow
    cnop -Size_of_DAC_samples, $8000
 
; ---------------------------------------------------------------------------
; DAC samples
; ---------------------------------------------------------------------------
; loc_ED100:
SndDAC_Start:
 
SndDAC_Sample1:
    BINCLUDE    "sound/DAC/Sample 1.bin"
SndDAC_Sample1_End
 
SndDAC_Sample2:
    BINCLUDE    "sound/DAC/Sample 2.bin"
SndDAC_Sample2_End
 
SndDAC_Sample5:
    BINCLUDE    "sound/DAC/Sample 5.bin"
SndDAC_Sample5_End
 
SndDAC_Sample6:
    BINCLUDE    "sound/DAC/Sample 6.bin"
SndDAC_Sample6_End
 
SndDAC_Sample3:
    BINCLUDE    "sound/DAC/Sample 3.bin"
SndDAC_Sample3_End
 
SndDAC_Sample4:
    BINCLUDE    "sound/DAC/Sample 4.bin"
SndDAC_Sample4_End
 
SndDAC_Sample7:
    BINCLUDE    "sound/DAC/Sample 7.bin"
SndDAC_Sample7_End
 
SndDAC_End
 
    if SndDAC_End - SndDAC_Start > $8000
        fatal "DAC samples must fit within $8000 bytes, but you have $\{SndDAC_End-SndDAC_Start } bytes of DAC samples."
    endif
    if SndDAC_End - SndDAC_Start > Size_of_DAC_samples
        fatal "Size_of_DAC_samples = $\{Size_of_DAC_samples}, but you have $\{SndDAC_End-SndDAC_Start} bytes of DAC samples."
    endif
 
; ---------------------------------------------------------------------------
; Music pointers
; ---------------------------------------------------------------------------
; loc_F0000:
MusicPoint1:    startBank
MusPtr_Continue:    rom_ptr_z80 Mus_Continue
 
 
Mus_Continue:   BINCLUDE    "sound/music/Continue.bin"
 
    finishBank
 
; --------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Buzzer's fireball
ArtNem_Buzzer_Fireball: BINCLUDE    "art/nemesis/Fireball 1 (Buzzer).bin"
; --------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Waterfall tiles
ArtNem_Waterfall:   BINCLUDE    "art/nemesis/Waterfall tiles.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Another fireball
ArtNem_HtzFireball: BINCLUDE    "art/nemesis/Fireball 2.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Bridge in EHZ
ArtNem_EHZ_Bridge:  BINCLUDE    "art/nemesis/EHZ bridge.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (48 blocks)
; Diagonally moving lift in HTZ
ArtNem_HtzZipline:  BINCLUDE    "art/nemesis/HTZ zip-line platform.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; One way barrier from HTZ
ArtNem_HtzValveBarrier: BINCLUDE    "art/nemesis/One way barrier from HTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; See-saw in HTZ
ArtNem_HtzSeeSaw:   BINCLUDE    "art/nemesis/See-saw in HTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (24 blocks)
; Unused Fireball
;ArtNem_F0B06:
    BINCLUDE    "art/nemesis/Fireball 3.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Rock from HTZ
ArtNem_HtzRock: BINCLUDE    "art/nemesis/Rock from HTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Orbit badnik from HTZ     ; ArtNem_HtzSol:
ArtNem_Sol: BINCLUDE    "art/nemesis/Sol badnik from HTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (120 blocks)
; Large spinning wheel from MTZ
ArtNem_MtzWheel:    BINCLUDE    "art/nemesis/Large spinning wheel from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (9 blocks)
; Indent in large spinning wheel from MTZ
ArtNem_MtzWheelIndent:  BINCLUDE    "art/nemesis/Large spinning wheel from MTZ - indent.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Spike block from MTZ
ArtNem_MtzSpikeBlock:   BINCLUDE    "art/nemesis/MTZ spike block.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (15 blocks)
; Steam from MTZ
ArtNem_MtzSteam:    BINCLUDE    "art/nemesis/Steam from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; Spike from MTZ
ArtNem_MtzSpike:    BINCLUDE    "art/nemesis/Spike from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (54 blocks)
; Similarly shaded blocks from MTZ
ArtNem_MtzAsstBlocks:   BINCLUDE    "art/nemesis/Similarly shaded blocks from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (9 blocks)
; Lava bubble from MTZ
ArtNem_MtzLavaBubble:   BINCLUDE    "art/nemesis/Lava bubble from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Lava cup
ArtNem_LavaCup: BINCLUDE    "art/nemesis/Lava cup from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (8 blocks)
; End of a bolt and rope from MTZ
ArtNem_BoltEnd_Rope:    BINCLUDE    "art/nemesis/Bolt end and rope from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (12 blocks)
; Small cog from MTZ
ArtNem_MtzCog:  BINCLUDE    "art/nemesis/Small cog from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (4 blocks)
; Flash inside spin tube from MTZ
ArtNem_MtzSpinTubeFlash:    BINCLUDE    "art/nemesis/Spin tube flash from MTZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (32 blocks)
; Large wooden box from MCZ ; ArtNem_F187C:
ArtNem_Crate:   BINCLUDE    "art/nemesis/Large wooden box from MCZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (26 blocks)
; Collapsing platform from MCZ  ; ArtNem_F1ABA:
ArtNem_MCZCollapsePlat: BINCLUDE    "art/nemesis/Collapsing platform from MCZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (16 blocks)
; Switch that you pull on from MCZ  ; ArtNem_F1C64:
ArtNem_VineSwitch:  BINCLUDE    "art/nemesis/Pull switch from MCZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (10 blocks)
; Vine that lowers in MCZ   ; ArtNem_F1D5C:
ArtNem_VinePulley:  BINCLUDE    "art/nemesis/Vine that lowers from MCZ.bin"
; --------------------------------------------------------------------
; Nemesis compressed art (20 blocks)
; Log viewed from the end for folding gates in MCZ (start of MCZ2)  ; ArtNem_F1E06:
ArtNem_MCZGateLog:  BINCLUDE    "art/nemesis/Drawbridge logs from MCZ.bin"
 
; ----------------------------------------------------------------------------------
; Filler (free space)
; ----------------------------------------------------------------------------------
    ; the PCM data has to line up with the end of the bank.
    cnop -Size_of_SEGA_sound, $8000
 
; -------------------------------------------------------------------------------
; Sega Intro Sound
; 8-bit unsigned raw audio at 16Khz
; -------------------------------------------------------------------------------
; loc_F1E8C:
Snd_Sega:   BINCLUDE    "sound/PCM/SEGA.bin"
Snd_Sega_End:
 
    if Snd_Sega_End - Snd_Sega > $8000
        fatal "Sega sound must fit within $8000 bytes, but you have a $\{Snd_Sega_End-Snd_Sega} byte Sega sound."
    endif
    if Snd_Sega_End - Snd_Sega > Size_of_SEGA_sound
        fatal "Size_of_SEGA_sound = $\{Size_of_SEGA_sound}, but you have a $\{Snd_Sega_End-Snd_Sega} byte Sega sound."
    endif
 
; ------------------------------------------------------------------------------
; Music pointers
; ------------------------------------------------------------------------------
; loc_F8000:
MusicPoint2:    startBank
MusPtr_CNZ_2P:      rom_ptr_z80 Mus_CNZ_2P
MusPtr_EHZ:     rom_ptr_z80 Mus_EHZ
MusPtr_MTZ:     rom_ptr_z80 Mus_MTZ
MusPtr_CNZ:     rom_ptr_z80 Mus_CNZ
MusPtr_MCZ:     rom_ptr_z80 Mus_MCZ
MusPtr_MCZ_2P:      rom_ptr_z80 Mus_MCZ_2P
MusPtr_ARZ:     rom_ptr_z80 Mus_ARZ
MusPtr_DEZ:     rom_ptr_z80 Mus_DEZ
MusPtr_SpecStage:   rom_ptr_z80 Mus_SpecStage
MusPtr_Options:     rom_ptr_z80 Mus_Options
MusPtr_Ending:      rom_ptr_z80 Mus_Ending
MusPtr_EndBoss:     rom_ptr_z80 Mus_EndBoss
MusPtr_CPZ:     rom_ptr_z80 Mus_CPZ
MusPtr_Boss:        rom_ptr_z80 Mus_Boss
MusPtr_SCZ:     rom_ptr_z80 Mus_SCZ
MusPtr_OOZ:     rom_ptr_z80 Mus_OOZ
MusPtr_WFZ:     rom_ptr_z80 Mus_WFZ
MusPtr_EHZ_2P:      rom_ptr_z80 Mus_EHZ_2P
MusPtr_2PResult:    rom_ptr_z80 Mus_2PResult
MusPtr_SuperSonic:  rom_ptr_z80 Mus_SuperSonic
MusPtr_HTZ:     rom_ptr_z80 Mus_HTZ
MusPtr_ExtraLife:   rom_ptr_z80 Mus_ExtraLife
MusPtr_Title:       rom_ptr_z80 Mus_Title
MusPtr_EndLevel:    rom_ptr_z80 Mus_EndLevel
MusPtr_GameOver:    rom_ptr_z80 Mus_GameOver
MusPtr_Invincible:  rom_ptr_z80 Mus_Invincible
MusPtr_Emerald:     rom_ptr_z80 Mus_Emerald
MusPtr_HPZ:     rom_ptr_z80 Mus_HPZ
MusPtr_Drowning:    rom_ptr_z80 Mus_Drowning
MusPtr_Credits:     rom_ptr_z80 Mus_Credits
 
; loc_F803C:
Mus_HPZ:    BINCLUDE    "sound/music/HPZ.bin"
Mus_Drowning:   BINCLUDE    "sound/music/Drowning.bin"
Mus_Invincible: BINCLUDE    "sound/music/Invincible.bin"
Mus_CNZ_2P: BINCLUDE    "sound/music/CNZ_2p.bin"
Mus_EHZ:    BINCLUDE    "sound/music/EHZ.bin"
Mus_MTZ:    BINCLUDE    "sound/music/MTZ.bin"
Mus_CNZ:    BINCLUDE    "sound/music/CNZ.bin"
Mus_MCZ:    BINCLUDE    "sound/music/MCZ.bin"
Mus_MCZ_2P: BINCLUDE    "sound/music/MCZ_2p.bin"
Mus_ARZ:    BINCLUDE    "sound/music/ARZ.bin"
Mus_DEZ:    BINCLUDE    "sound/music/DEZ.bin"
Mus_SpecStage:  BINCLUDE    "sound/music/SpecStg.bin"
Mus_Options:    BINCLUDE    "sound/music/Options.bin"
Mus_Ending: BINCLUDE    "sound/music/Ending.bin"
Mus_EndBoss:    BINCLUDE    "sound/music/End_Boss.bin"
Mus_CPZ:    BINCLUDE    "sound/music/CPZ.bin"
Mus_Boss:   BINCLUDE    "sound/music/Boss.bin"
Mus_SCZ:    BINCLUDE    "sound/music/SCZ.bin"
Mus_OOZ:    BINCLUDE    "sound/music/OOZ.bin"
Mus_WFZ:    BINCLUDE    "sound/music/WFZ.bin"
Mus_EHZ_2P: BINCLUDE    "sound/music/EHZ_2p.bin"
Mus_2PResult:   BINCLUDE    "sound/music/2player results screen.bin"
Mus_SuperSonic: BINCLUDE    "sound/music/Supersonic.bin"
Mus_HTZ:    BINCLUDE    "sound/music/HTZ.bin"
Mus_Title:  BINCLUDE    "sound/music/Title screen.bin"
Mus_EndLevel:   BINCLUDE    "sound/music/End of level.bin"
 
    ; The following act mostly like sound effects
    ; despite being listed with the music.
    ; This means they're uncompressed format with absolute pointers
    ; instead of compressed with relative pointers.
    ; Because they have absolute pointers,
    ; they have to be assembled rather than BINCLUDE'd.
    ; See below (right before Sound20) for other notes
    ; about the sound format that apply to these too.
 
;Mus_ExtraLife: BINCLUDE    "sound/music/Extra life.bin"
Mus_ExtraLife:  dc.w z80_ptr(Mus_EL_Voices),$0603,$02CD
        dc.w z80_ptr(Mus_EL_DAC),$0000
        dc.w z80_ptr(Mus_EL_FM1),$E810
        dc.w z80_ptr(Mus_EL_FM2),$E810
        dc.w z80_ptr(Mus_EL_FM3),$E810
        dc.w z80_ptr(Mus_EL_FM4),$E810
        dc.w z80_ptr(Mus_EL_FM5),$E810
        dc.w z80_ptr(Mus_EL_PSG1),$D008,$0005
        dc.w z80_ptr(Mus_EL_PSG2),$DC08,$0005
        dc.w z80_ptr(Mus_EL_PSG3),$DC00,$0004
Mus_EL_FM4: dc.b $E1,$03,$E0,$40,$F6
        dc.w z80_ptr(+)
Mus_EL_FM1: dc.b $E0,$80
+       dc.b $EF,$00,$E8,$06,$D9,$06,$03,$03,$06,$06
        dc.b $E8,$00,$DB,$09,$D7,$D6,$06,$D9,$18,$F2
Mus_EL_FM2: dc.b $EF,$01,$E8,$06,$E2,$01,$D6,$06,$03,$03,$06,$06
        dc.b $E8,$00,$D7,$09,$D4,$D2,$06,$D6,$18,$E2,$01,$F2
Mus_EL_FM5: dc.b $E1,$03,$E0,$40,$F6
        dc.w z80_ptr(+)
Mus_EL_FM3: dc.b $E0,$80
+       dc.b $EF,$02,$BA,$0C,$80,$06,$BA,$B8,$80,$03
        dc.b $B8,$06,$80,$03,$B8,$06,$BA,$18,$F2
Mus_EL_PSG1:    dc.b $E8,$06,$D6,$06,$03,$03,$06,$06,$E8,$00,$D7,$09
        dc.b $D4,$D2,$06,$D6,$18
Mus_EL_PSG2:
Mus_EL_PSG3:    dc.b $F2
Mus_EL_DAC: dc.b $88,$12,$06,$8B,$09,$09,$06,$88,$06,$8A,$88,$8A
        dc.b $88,$0C,$E4
Mus_EL_Voices:  dc.b $3A,$01,$01,$07,$01,$8E,$8D,$8E,$53,$0E,$0E,$0E
        dc.b $03,$00,$00,$00,$00,$1F,$1F,$FF,$0F,$18,$16,$4E,$80
        dc.b $3A,$01,$01,$07,$01,$8E,$8D,$8E,$53,$0E,$0E,$0E
        dc.b $03,$00,$00,$00,$00,$1F,$1F,$FF,$0F,$18,$27,$28,$80
        dc.b $3A,$01,$01,$07,$01,$8E,$8D,$8E,$53,$0E,$0E,$0E
        dc.b $03,$00,$00,$00,$07,$1F,$1F,$FF,$0F,$18,$27,$28,$80
 
 
;Mus_GameOver:  BINCLUDE    "sound/music/Game over.bin"
Mus_GameOver:   dc.w z80_ptr(MusGO_Voices),$0603,$02F2
        dc.w z80_ptr(MusGOver_DAC),$0000
        dc.w z80_ptr(MusGOver_FM1),$E80A
        dc.w z80_ptr(MusGOver_FM2),$F40F
        dc.w z80_ptr(MusGOver_FM3),$F40F
        dc.w z80_ptr(MusGOver_FM4),$F40D
        dc.w z80_ptr(MusGOver_FM5),$DC16
        dc.w z80_ptr(MusGOver_PSG),$D003,$0005
        dc.w z80_ptr(MusGOver_PSG),$DC06,$0005
        dc.w z80_ptr(MusGOver_PSG),$DC00,$0004
MusGOver_FM1:   dc.b $EF,$00
        dc.b $F0,$20,$01,$04,$05
        dc.b $80,$0C,$CA,$12,$80,$06,$CA,$80,$CB,$12,$C8,$1E
        dc.b $CA,$06,$80,$CA,$80,$CA,$80,$C6,$80,$C4,$12,$C8
        dc.b $0C,$80,$12,$C9,$04,$80,$C9,$C8,$06,$80,$C7,$80
        dc.b $C6,$80
        dc.b $F0,$28,$01,$18,$05
        dc.b $C5,$60,$F2
MusGOver_FM2:   dc.b $EF,$01,$80,$01,$D9,$06,$80,$D9,$80,$D6,$80,$D6
        dc.b $80,$D7,$15,$D7,$1B,$D9,$06,$80,$D9,$80,$D6,$80
        dc.b $D6,$80,$DC,$15,$DC,$1B,$F2
MusGOver_FM3:   dc.b $EF,$01,$D6,$0C,$D6,$D2,$D2,$D4,$15,$D4,$1B,$D6
        dc.b $0C,$D6,$D2,$D2,$D7,$15,$D7,$1B,$F2
MusGOver_FM4:   dc.b $EF,$02,$E2,$01,$AE,$06,$80,$AE,$80,$A9,$80,$A9
        dc.b $80,$AC,$15,$AB,$0C,$AC,$03,$AB,$0C,$AE,$06,$80
        dc.b $AE,$80,$A9,$80,$A9,$80,$B3,$15,$B2,$0C,$B3,$03
        dc.b $B2,$0C,$AE,$04,$80,$AE,$AD,$06,$80,$AC,$80,$AB
        dc.b $80,$AB,$60,$E2,$01,$F2
MusGOver_FM5:   dc.b $EF,$03,$80,$30,$D7,$12,$80,$03,$D7,$1B,$80,$30
        dc.b $DC,$12,$80,$03,$DC,$1B
MusGOver_PSG:   dc.b $F2
MusGOver_DAC:   dc.b $80,$18,$81
        dc.b $F7,$00,$04
        dc.w z80_ptr(MusGOver_DAC)
        dc.b $F2
MusGO_Voices:   dc.b $3A,$51,$51,$08,$02,$1E,$1E,$1E,$10,$1F,$1F,$1F
        dc.b $0F,$00,$00,$00,$02,$0F,$0F,$0F,$1F,$18,$22,$24,$81
        dc.b $3C,$33,$73,$30,$70,$94,$96,$9F,$9F,$12,$14,$00
        dc.b $0F,$04,$04,$0A,$0D,$2F,$4F,$0F,$2F,$33,$1A,$80,$80
        dc.b $3A,$01,$01,$07,$01,$8E,$8D,$8E,$53,$0E,$0E,$0E
        dc.b $03,$00,$00,$00,$07,$1F,$1F,$FF,$0F,$1C,$27,$28,$80
        dc.b $1F,$66,$53,$31,$22,$1C,$1F,$98,$1F,$12,$0F,$0F
        dc.b $0F,$00,$00,$00,$00,$FF,$0F,$0F,$0F,$8C,$8A,$8D,$8B
 
;Mus_Emerald:   BINCLUDE    "sound/music/Got an emerald.bin"
Mus_Emerald:    dc.w z80_ptr(MusEmrldVoices),$0703,$01D5
        dc.w z80_ptr(MusEmeraldDAC),$0000
        dc.w z80_ptr(MusEmeraldFM1),$F408
        dc.w z80_ptr(MusEmeraldFM2),$F408
        dc.w z80_ptr(MusEmeraldFM3),$F407
        dc.w z80_ptr(MusEmeraldFM4),$F416
        dc.w z80_ptr(MusEmeraldFM5),$F416
        dc.w z80_ptr(MusEmeraldFM6),$F416
        dc.w z80_ptr(MusEmeraldPSG1),$F402,$0004
        dc.w z80_ptr(MusEmeraldPSG2),$F402,$0005
        dc.w z80_ptr(MusEmeraldPSG3),$F400,$0004
MusEmeraldFM3:  dc.b $E1,$02
MusEmeraldFM1:  dc.b $EF,$00,$C1,$06,$C4,$C9,$CD,$0C,$C9,$D0,$2A,$F2
MusEmeraldFM2:  dc.b $EF,$00,$BD,$06,$C1,$C4,$C9,$0C,$C6,$CB,$2A,$F2
MusEmeraldFM4:  dc.b $EF,$01,$C1,$0C,$C1,$06,$C4,$06,$80,$C4,$80,$C9
        dc.b $2A,$F2
MusEmeraldFM5:  dc.b $EF,$01,$C9,$0C,$C9,$06,$CD,$06,$80,$CD,$80,$D0
        dc.b $2A,$F2
MusEmeraldFM6:  dc.b $EF,$01,$C4,$0C,$C4,$06,$C9,$06,$80,$C9,$80,$CD
        dc.b $2A,$F2
MusEmeraldPSG2: dc.b $80,$2D
-       dc.b $C4,$06,$C2,$C1,$BF,$EC,$03
        dc.b $F7,$00,$04
        dc.w z80_ptr(-)
        dc.b $F2
MusEmeraldPSG1: dc.b $E2,$01,$80,$02,$80,$2D
-       dc.b $C4,$06,$C2,$C1,$BF,$EC,$03
        dc.b $F7,$00,$04
        dc.w z80_ptr(-)
MusEmeraldPSG3:
MusEmeraldDAC:  dc.b $E2,$01,$F2
MusEmrldVoices: dc.b $04,$35,$54,$72,$46,$1F,$1F,$1F,$1F,$07,$07,$0A
        dc.b $0D,$00,$00,$0B,$0B,$1F,$1F,$0F,$0F,$23,$1D,$14,$80
        dc.b $3C,$31,$50,$52,$30,$52,$52,$53,$53,$08,$08,$00
        dc.b $00,$04,$04,$00,$00,$10,$10,$07,$07,$1A,$16,$80,$80
 
;Mus_Credits:   BINCLUDE    "sound/music/Credits.bin"
Mus_Credits:    dc.w z80_ptr(MusCred_Voices),$0603,$01F0
        dc.w z80_ptr(MusCred_DAC),$0000
        dc.w z80_ptr(MusCred_FM1),$000E
        dc.w z80_ptr(MusCred_FM2),$180A
        dc.w z80_ptr(MusCred_FM3),$0014
        dc.w z80_ptr(MusCred_FM4),$0016
        dc.w z80_ptr(MusCred_FM5),$0C16
        dc.w z80_ptr(MusCred_PSG1),$E806,$000B
        dc.w z80_ptr(MusCred_PSG2),$DC07,$000B
        dc.w z80_ptr(MusCred_PSG3),$0002,$0003
MusCred_FM1:    dc.b $E9,$F4,$E6,$FE,$F8
        dc.w z80_ptr(MusCreditsDB06)
        dc.b $E9,$0C,$E6,$02
-       dc.b $80,$30
        dc.b $F7,$00,$08
        dc.w z80_ptr(-)
        dc.b $EF,$03,$F8
        dc.w z80_ptr(MusCreditsD9D1)
        dc.b $AE,$06,$A2,$F8
        dc.w z80_ptr(MusCreditsD9D1)
        dc.b $E6,$FD
-       dc.b $EF,$00,$B7,$06,$BA,$F8
        dc.w z80_ptr(MusCreditsDA13)
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$06,$80,$80,$30,$80,$EF,$0B,$E9,$18,$E6,$02
-       dc.b $94,$0C,$8F,$92,$8F,$06,$94,$05,$94,$07,$06,$8F
        dc.b $0C,$92,$8F
        dc.b $F7,$00,$05
        dc.w z80_ptr(-)
        dc.b $80,$30,$80,$EF,$0E,$E6,$FF,$E9,$E8,$F8
        dc.w z80_ptr(MusCreditsDAE5)
        dc.b $80,$12,$91,$94,$06,$80,$18,$96,$12,$9A,$06,$80
        dc.b $80,$12,$8F,$93,$08,$80,$16,$96,$06,$91,$92,$94
        dc.b $96,$F8
        dc.w z80_ptr(MusCreditsDAE5)
        dc.b $80,$12,$9D,$9A,$08,$80,$16,$96,$12,$9D,$08,$80
        dc.b $04,$EF,$12
        dc.b $F0,$18,$01,$0A,$04
        dc.b $80,$30,$80,$F8
        dc.w z80_ptr(MusCreditsDA5F)
        dc.b $E7,$24,$E7,$C5,$01,$E7,$C4,$E7,$C3,$E7,$C2,$E7
        dc.b $C1,$E7,$C0,$E7,$BF,$E7,$BE,$E7,$BD,$E7,$BC,$E7
        dc.b $BB,$E7,$BA,$80,$60,$EF,$01,$E9,$F4,$E6,$FA,$F4
        dc.b $F8
        dc.w z80_ptr(MusCreditsDA99)
        dc.b $B1,$03,$F8
        dc.w z80_ptr(MusCreditsDA99)
        dc.b $80,$03,$80,$60,$E6,$04,$E1,$01,$EF,$1B,$E6,$06
        dc.b $C1,$0C,$E8,$06,$BD,$06,$BA,$BD,$0C,$80,$80,$EF
        dc.b $1C,$E6,$FA,$E8,$00,$BC,$0C,$12,$06,$EF,$1B,$E6
        dc.b $06,$E8,$06,$C2,$06,$C2,$80,$C2,$80,$C2,$E8,$00
        dc.b $C3,$0C,$C4,$80,$E8,$06,$C4,$06,$06,$C6,$C4,$E8
        dc.b $00,$C1,$0C,$E8,$06,$BD,$06,$BA,$BD,$0C,$80,$80
        dc.b $E8,$00,$EF,$1C,$E6,$FA,$C1,$C4,$C1,$EF,$1A,$E6
        dc.b $06,$E8,$06,$C2,$06,$C2,$80,$C2,$80,$C2,$E8,$00
        dc.b $C3,$0C,$C4,$06,$80,$80,$24,$80,$30,$80,$EF,$1F
        dc.b $E9,$18,$E6,$F7,$E1,$00,$80,$06,$AC,$AE,$80,$B1
        dc.b $80,$B3,$80,$B4,$80,$B3,$80,$B1,$B3,$80,$B1,$E9
        dc.b $F4,$EF,$00,$80,$0C,$AC,$06,$AE,$B1,$80,$12,$AC
        dc.b $06,$AE,$B1,$80,$B4,$B1,$80,$B1,$E9,$0C,$EF,$1F
        dc.b $80,$06,$B8,$12,$B4,$06,$80,$B3,$80,$B4,$80,$B3
        dc.b $80,$B1,$AE,$80,$B1,$E9,$F4,$EF,$00,$80,$06,$AF
        dc.b $12,$AE,$06,$80,$12,$AF,$06,$80,$AE,$80,$AF,$B1
        dc.b $80,$B1,$80,$30,$80,$EF,$21,$E9,$0C,$80,$30,$80
        dc.b $08,$A0,$04,$9E,$0C,$9D,$9B,$99,$08,$04,$91,$0C
        dc.b $92,$93,$94,$98,$99,$9B,$9D,$98,$95,$93,$91,$98
        dc.b $9D,$91,$96,$98,$99,$98,$96,$99,$9D,$96,$95,$97
        dc.b $99,$97,$95,$96,$97,$98,$99,$98,$99,$9B,$9D,$08
        dc.b $04,$98,$0C,$91,$95,$96,$98,$99,$9D,$9E,$08,$96
        dc.b $10,$97,$0C,$98,$F8
        dc.w z80_ptr(MusCreditsDAFE)
        dc.b $9E,$E6,$04,$F8
        dc.w z80_ptr(MusCreditsDAFE)
        dc.b $9E,$E6,$FC,$F8
        dc.w z80_ptr(MusCreditsDAFE)
        dc.b $9E,$08,$99,$04,$EF,$23,$E9,$E8,$E6,$07,$80,$60
        dc.b $F8
        dc.w z80_ptr(MusCreditsDABE)
        dc.b $80,$60,$E6,$FB,$80,$0C,$CD,$06,$80,$D4,$CD,$06
        dc.b $80,$0C,$CD,$06,$80,$D4,$CD,$06,$80,$18,$E6,$05
        dc.b $80,$0C,$AE,$80,$AE,$80,$24,$E1,$02,$E6,$08,$A2
        dc.b $6C,$F2
MusCreditsD9D1: dc.b $A5,$0C,$B1,$06,$80,$B1,$0C,$AC,$B3,$12,$B1,$0C
        dc.b $AC,$06,$AE,$B1,$A7,$0C,$B3,$06,$80,$B3,$0C,$AE
        dc.b $B5,$12,$B3,$06,$80,$AE,$B0,$B3,$A3,$0C,$AF,$06
        dc.b $80,$AF,$0C,$AA,$B1,$12,$AF,$0C,$AA,$06,$AC,$AF
        dc.b $A2,$0C,$AE,$06,$A2,$A4,$0C,$B0,$06,$A4,$A5,$0C
        dc.b $B1,$06,$A5,$A2,$0C,$E3
MusCreditsDA13: dc.b $BE,$0C,$BC,$06,$BA,$BC,$BA,$04,$E7,$08,$BA,$04
        dc.b $80,$0E,$EF,$07,$B7,$06,$B2,$B5,$B7,$EF,$00,$B7
        dc.b $BA,$BE,$0C,$BC,$06,$BA,$BC,$BA,$0C,$BC,$04,$80
        dc.b $08,$BA,$04,$80,$08,$BC,$04,$80,$08,$BE,$12,$BA
        dc.b $06,$B7,$80,$B7,$80,$24,$EF,$07,$B7,$06,$B2,$B5
        dc.b $B7,$80,$0C,$80,$30,$BE,$06,$BE,$BA,$04,$80,$08
        dc.b $BC,$06,$BE,$E3
MusCreditsDA5F: dc.b $C3,$01,$E7,$C4,$E7,$C5,$E7,$C6,$2D,$E9,$02,$C3
        dc.b $01,$E7,$C4,$E7,$C5,$E7,$C6,$2D,$E9,$01,$C3,$01
        dc.b $E7,$C4,$E7,$C5,$E7,$C6,$2D,$E9,$FC,$C3,$01,$E7
        dc.b $C4,$E7,$C5,$E7,$C6,$2D,$E9,$01,$C3,$01,$E7,$C4
        dc.b $E7,$C5,$E7,$C6,$2D,$E7,$30,$E7,$30,$E3
MusCreditsDA99: dc.b $A7,$0C,$B3,$06,$80,$B1,$80,$B3,$0C,$A7,$03,$80
        dc.b $06,$A7,$03,$B3,$0C,$B1,$B3,$09,$AE,$03,$AC,$06
        dc.b $80,$AC,$0C,$AE,$06,$80,$AE,$0C,$AF,$06,$80,$27
        dc.b $E3
MusCreditsDABE: dc.b $80,$0C,$CA,$15,$80,$03,$CA,$06,$80,$CB,$0F,$80
        dc.b $03,$C8,$18,$80,$06,$CA,$80,$CA,$80,$CA,$80,$C6
        dc.b $80,$C4,$0F,$80,$03,$C8,$18,$80,$06
        dc.b $F7,$00,$02
        dc.w z80_ptr(MusCreditsDABE)
        dc.b $E3
MusCreditsDAE5: dc.b $80,$12,$94,$97,$06,$80,$18,$99,$12,$94,$06,$80
        dc.b $80,$12,$92,$96,$06,$80,$18,$97,$12,$92,$06,$80
        dc.b $E3
MusCreditsDAFE: dc.b $80,$99,$80,$99,$80,$9E,$80,$E3
MusCreditsDB06: dc.b $EF,$07,$80,$54,$C7,$04,$C8,$C9,$CA,$24,$CD,$D2
        dc.b $18,$D0,$24,$CF,$CB,$18,$CB,$0C,$CA,$80,$CD,$60
        dc.b $E7,$3C,$CA,$24,$CD,$D2,$18,$D4,$24,$D0,$D4,$18
        dc.b $D4,$24,$D6,$60,$E7,$3C,$E3
MusCred_FM2:    dc.b $80,$60,$EF,$01,$E8,$06,$F8
        dc.w z80_ptr(MusCreditsDE2A)
        dc.b $F8
        dc.w z80_ptr(MusCreditsDE2A)
-       dc.b $85,$0C
        dc.b $F7,$00,$0C
        dc.w z80_ptr(-)
        dc.b $8A,$87,$88,$89,$F8
        dc.w z80_ptr(MusCreditsDE2A)
-       dc.b $88
        dc.b $F7,$00,$0B
        dc.w z80_ptr(-)
-       dc.b $8A
        dc.b $F7,$00,$0A
        dc.w z80_ptr(-)
        dc.b $E8,$00,$E6,$FC,$8A,$8B,$8C,$E6,$04,$E8,$09
-       dc.b $8D,$0C
        dc.b $F7,$00,$0C
        dc.w z80_ptr(-)
        dc.b $E8,$00,$8D,$8A,$8B,$8C,$E8,$09
-       dc.b $8D,$0C
        dc.b $F7,$00,$0C
        dc.w z80_ptr(-)
        dc.b $8D,$06,$99,$E8,$00,$8A,$0C,$8B,$8C,$E9,$E8,$E6
        dc.b $0C,$EF,$04
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDD59)
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $E6,$F9,$EF,$08
MusCreditsDB93: dc.b $F8
        dc.w z80_ptr(MusCreditsDD8D)
-       dc.b $9F,$04,$80,$08,$9F,$0C
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $06,$9C,$12,$9D,$0C,$9E,$F8
        dc.w z80_ptr(MusCreditsDD8D)
-       dc.b $9D,$04,$80,$08,$9D,$0C
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
-       dc.b $9C,$04,$80,$08,$9C,$0C
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $F7,$01,$02
        dc.w z80_ptr(MusCreditsDB93)
        dc.b $80,$60,$80,$48,$EF,$0C,$E6,$13,$F8
        dc.w z80_ptr(MusCreditsDD9D)
        dc.b $24,$80,$60,$EF,$0F,$E6,$F3
        dc.b $F0,$04,$02,$03,$02
        dc.b $F8
        dc.w z80_ptr(MusCreditsDDB5)
        dc.b $C4,$18,$C3,$30,$E7,$18,$80,$0C,$F8
        dc.w z80_ptr(MusCreditsDDB5)
        dc.b $BE,$EF,$13,$E6,$F5,$F4,$80,$60
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDDEA)
        dc.b $A8,$0C,$A9,$08,$A1,$10,$F8
        dc.w z80_ptr(MusCreditsDDEA)
        dc.b $A8,$08,$A9,$04,$80,$18
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$17,$E1,$02,$E9,$F4,$E6,$0A,$F8
        dc.w z80_ptr(MusCreditsDDD5)
        dc.b $CE,$15,$CD,$03,$CB,$06,$80,$C9,$0C,$CD,$06,$80
        dc.b $C9,$0C,$CB,$06,$80,$12,$80,$60,$EF,$1B,$E1,$00
        dc.b $E8,$06,$80,$3C,$B8,$06,$06,$BA,$BD,$BD,$BA,$EF
        dc.b $1D,$E6,$FA,$E8,$00,$F8
        dc.w z80_ptr(MusCreditsDDF9)
        dc.b $80,$F8
        dc.w z80_ptr(MusCreditsDE09)
        dc.b $F8
        dc.w z80_ptr(MusCreditsDDF9)
        dc.b $EF,$1C,$BD,$EF,$1D,$F8
        dc.w z80_ptr(MusCreditsDE09)
        dc.b $80,$30,$80,$EF,$01,$E9,$18,$E6,$F9
-       dc.b $99,$0C,$A5,$06,$80,$96,$0C,$A2,$06,$80,$97,$0C
        dc.b $A3,$06,$80,$98,$0C,$A8,$06,$A7,$99,$06,$99,$12
        dc.b $96,$0C,$A2,$06,$80,$97,$0C,$A3,$06,$80,$98,$0C
        dc.b $A4,$06,$80
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$22,$E9,$E8,$E6,$03
        dc.b $F0,$1C,$01,$06,$04
        dc.b $80,$50,$AC,$04,$AE,$08,$B1,$04,$B5,$30,$80,$0C
        dc.b $B5,$08,$80,$04,$B6,$08,$B5,$10,$B9,$08,$04,$80
        dc.b $08,$B5,$34,$80,$0C,$B5,$BA,$08,$04,$80,$08,$B5
        dc.b $04,$B1,$24,$80,$0C,$B1,$08,$80,$04,$B3,$08,$B1
        dc.b $04,$B4,$0C,$B3,$08,$B1,$4C,$80,$0C,$B5,$08,$80
        dc.b $04,$B6,$08,$80,$04,$B5,$08,$80,$04,$B9,$08,$04
        dc.b $80,$08,$B5,$1C,$80,$0C,$BA,$18,$BC,$08,$BA,$04
        dc.b $BD,$18,$80,$0C,$BA,$04,$80,$08,$B8,$18,$B5,$B1
        dc.b $B3,$0C,$E6,$04,$F8
        dc.w z80_ptr(MusCreditsDE17)
        dc.b $B3,$0C,$E6,$FC,$F8
        dc.w z80_ptr(MusCreditsDE17)
        dc.b $B3,$14,$B1,$04,$E6,$FF,$EF,$24,$F4,$80,$60
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDE20)
        dc.b $AC,$12,$AB,$0C,$AC,$06,$AB,$0C,$F8
        dc.w z80_ptr(MusCreditsDE20)
        dc.b $B3,$12,$B2,$0C,$B3,$06,$B2,$0C
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $AC,$06,$80,$A9,$80,$AA,$80,$AB,$80,$AC,$AC,$A9
        dc.b $80,$AA,$80,$AC,$80,$A9,$80,$A9,$80,$AD,$80,$AD
        dc.b $80,$B0,$80,$B0,$80,$B3,$80,$B3,$80,$80,$0C,$A2
        dc.b $12,$80,$06,$A2,$12,$AD,$AE,$06,$80,$E6,$FD,$A2
        dc.b $6C,$F2
MusCreditsDD59: dc.b $80,$0C,$C4,$06,$80,$C6,$80,$C4,$80,$C9,$80,$C9
        dc.b $80,$CB,$CD,$80,$0C,$80,$CB,$18,$C6,$06,$80,$C9
        dc.b $C9,$80,$CB,$0C,$80,$12,$80,$1E,$C7,$06,$C9,$C7
        dc.b $CB,$80,$C9,$80,$C7,$C9,$80,$C6,$E7,$C6,$30,$E7
        dc.b $18,$80,$18,$E3
MusCreditsDD8D: dc.b $9F,$04,$80,$08,$9F,$0C
        dc.b $F7,$00,$03
        dc.w z80_ptr(MusCreditsDD8D)
        dc.b $06,$AB,$9F,$0C,$E3
MusCreditsDD9D: dc.b $B8,$08,$BA,$BC,$B6,$30,$E7,$30,$E7,$B6,$80,$18
        dc.b $B8,$08,$BA,$BC,$B6,$30,$E7,$30,$E7,$30,$E7,$E3
MusCreditsDDB5: dc.b $BF,$06,$BD,$BF,$12,$C2,$BF,$0C,$C1,$80,$06,$12
        dc.b $C4,$0C,$C2,$06,$80,$C9,$C6,$3C,$80,$06,$0C,$C7
        dc.b $12,$C6,$C4,$06,$C2,$C1,$18,$E3
MusCreditsDDD5: dc.b $CE,$15,$CD,$03,$CB,$06,$80,$C9,$0C,$CD,$06,$80
        dc.b $C9,$0C,$CB,$06,$80,$12,$80,$60,$E3
MusCreditsDDEA: dc.b $A2,$0C,$AE,$AC,$08,$AE,$04,$AC,$08,$A9,$04,$A7
        dc.b $08,$04,$E3
MusCreditsDDF9: dc.b $80,$0C,$B1,$AE,$06,$06,$AC,$0C,$80,$B0,$AE,$06
        dc.b $06,$AC,$0C,$E3
MusCreditsDE09: dc.b $AE,$AC,$06,$06,$AA,$0C,$80,$AC,$0C,$06,$06,$AE
        dc.b $AC,$E3
MusCreditsDE17: dc.b $BA,$04,$80,$08,$B8,$18,$B5,$B1,$E3
MusCreditsDE20: dc.b $AE,$06,$80,$AE,$80,$A9,$80,$A9,$80,$E3
MusCreditsDE2A: dc.b $8A,$0C
        dc.b $F7,$00,$08
        dc.w z80_ptr(MusCreditsDE2A)
        dc.b $E3
MusCred_FM3:    dc.b $80,$60,$F8
        dc.w z80_ptr(MusCreditsE065)
        dc.b $E9,$18,$EF,$02,$F8
        dc.w z80_ptr(MusCreditsE040)
        dc.b $B8,$3C,$F8
        dc.w z80_ptr(MusCreditsE040)
        dc.b $BD,$3C,$E9,$E8,$E6,$02,$E1,$03,$EF,$04,$E0,$80
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDD59)
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $EF,$09,$E9,$0C,$E6,$FD,$E0,$40
        dc.b $F0,$06,$01,$05,$04
        dc.b $E1,$00
-       dc.b $9F,$0C,$AB,$06,$80,$A9,$80,$AB,$9F,$80,$9F,$AB
        dc.b $80,$A9,$80,$AB,$0C
        dc.b $F7,$00,$03
        dc.w z80_ptr(-)
        dc.b $9D,$0C,$A9,$06,$80,$A8,$80,$A9,$9C,$80,$9C,$A8
        dc.b $80,$A6,$80,$A8,$0C
        dc.b $F7,$01,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$0D,$E6,$FB,$E0,$C0,$F4,$80,$60
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDFF2)
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$0F,$E0,$80,$E6,$0B,$F8
        dc.w z80_ptr(MusCreditsDDB5)
        dc.b $C4,$18,$C3,$48,$80,$0C,$F8
        dc.w z80_ptr(MusCreditsDDB5)
        dc.b $BE,$0C
        dc.b $F0,$18,$01,$03,$04
        dc.b $E6,$F3,$E0,$C0,$EF,$14,$A2,$14,$A4,$04,$A5,$04
        dc.b $80,$08,$A9,$04,$80,$08,$A8,$04,$80,$08,$A9,$04
        dc.b $80,$08,$AC,$08,$A9,$10
-       dc.b $80,$30
        dc.b $F7,$00,$0A
        dc.w z80_ptr(-)
        dc.b $EF,$18,$E9,$F4,$E6,$08,$F4,$E0,$40,$80,$60,$80
        dc.b $30,$C6,$06,$80,$C2,$0C,$C4,$09,$C2,$03,$BF,$0C
        dc.b $80,$60,$80,$3C,$80,$60,$EF,$1B,$E6,$FB,$E0,$C0
        dc.b $E8,$06,$C4,$06,$06,$C6,$C9,$C9,$C6,$E8,$00,$CD
        dc.b $0C,$E8,$06,$C9,$06,$C6,$C9,$0C,$80,$80,$12,$EF
        dc.b $1C,$E8,$00,$BD,$BA,$0C,$E8,$06,$EF,$1B,$CE,$06
        dc.b $CE,$80,$CE,$80,$CE,$E8,$00,$CF,$0C,$D0,$80,$E8
        dc.b $06,$D0,$06,$06,$D2,$D0,$E8,$00,$CD,$0C,$E8,$06
        dc.b $C9,$06,$C6,$C9,$0C,$E8,$00,$EF,$1C,$80,$1E,$C2
        dc.b $0C,$C2,$BD,$06,$80,$60,$80,$60,$EF,$00,$E9,$18
        dc.b $80,$60,$80,$0C,$AC,$06,$AE,$B1,$80,$12,$AC,$06
        dc.b $AE,$B1,$80,$B4,$B1,$80,$B1,$80,$60,$80,$06,$AF
        dc.b $12,$AE,$06,$80,$12,$AF,$06,$80,$AE,$80,$AF,$B1
        dc.b $80,$B1,$80,$60,$EF,$22,$E9,$DC,$E6,$FF,$E0,$80
        dc.b $80,$60,$F8
        dc.w z80_ptr(MusCreditsE004)
        dc.b $CD,$30,$CB,$18,$CD,$0C,$CB,$C9,$30,$CE,$F8
        dc.w z80_ptr(MusCreditsE051)
        dc.b $E6,$04,$F8
        dc.w z80_ptr(MusCreditsE051)
        dc.b $E6,$FC,$80,$C4,$80,$C4,$80,$C6,$18,$08,$C4,$04
        dc.b $E9,$0C,$E6,$FF,$E0,$C0,$EF,$00,$80,$60
-       dc.b $F8
        dc.w z80_ptr(MusCreditsE05B)
        dc.b $CB,$12,$CB,$1E,$F8
        dc.w z80_ptr(MusCreditsE05B)
        dc.b $D0,$12,$D0,$1E
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$0C,$CB,$12,$80,$06,$CB,$80,$CA,$12,$CB,$CA
        dc.b $0C,$C5,$18,$C8,$CB,$D1,$80,$0C,$CD,$80,$CD,$12
        dc.b $CC,$CD,$06,$80,$E6,$F8,$EF,$01,$E1,$03,$A2,$6C
        dc.b $F2
MusCreditsDFF2: dc.b $80,$60,$BC,$06,$BD,$BC,$B8,$BA,$B6,$0C,$B8,$B3
        dc.b $B3,$06,$B6,$0C,$B8,$E3
MusCreditsE004: dc.b $80,$0C,$CD,$04,$80,$10,$CD,$04,$80,$0C,$CD,$0C
        dc.b $CE,$08,$CD,$04,$80,$18,$80,$0C,$CB,$04,$80,$10
        dc.b $CB,$04,$80,$0C,$CB,$0C,$CD,$08,$CB,$04,$80,$18
-       dc.b $80,$0C,$C9,$04,$80,$10,$C9,$04,$80,$0C,$C9,$0C
        dc.b $CB,$08,$C9,$04,$80,$18
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $E3
MusCreditsE040: dc.b $80,$18,$B8,$0B,$80,$0D,$BA,$0C,$0B,$80,$19,$BD
        dc.b $0C,$0B,$80,$0D,$E3
MusCreditsE051: dc.b $80,$0C,$C4,$80,$C4,$80,$C6,$80,$C6,$E3
MusCreditsE05B: dc.b $CD,$06,$80,$CD,$80,$CA,$80,$CA,$80,$E3
MusCreditsE065: dc.b $EF,$05,$E9,$F4,$C6,$60,$CB,$CD,$E7,$CD,$C6,$60
        dc.b $D0,$D0,$24,$D2,$60,$E7,$3C,$E3
MusCred_FM4:    dc.b $80,$60,$E9,$FB,$E6,$FE,$F8
        dc.w z80_ptr(MusCreditsE065)
        dc.b $E9,$1D,$E6,$02,$EF,$02,$F8
        dc.w z80_ptr(MusCreditsE2AE)
        dc.b $B5,$3C,$F8
        dc.w z80_ptr(MusCreditsE2AE)
        dc.b $B8,$3C,$E6,$06,$EF,$05
        dc.b $F0,$02,$01,$FE,$04
-       dc.b $C1,$30,$E7,$30,$C3,$E7,$30,$BF,$E7,$30,$BD,$E7
        dc.b $30
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $EF,$0A,$E9,$F4,$E6,$F7
        dc.b $F0,$0C,$01,$FB,$04
-       dc.b $F8
        dc.w z80_ptr(MusCreditsE2BF)
        dc.b $80,$25,$C3,$06,$C3,$80,$0C,$C3,$06,$C3,$05,$80
        dc.b $0D,$C3,$06,$C5,$30,$E7,$06,$F8
        dc.w z80_ptr(MusCreditsE2BF)
        dc.b $80,$31,$80,$60
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$80,$48,$EF,$0C,$E6,$05,$F4,$E1,$02,$E0
        dc.b $80,$F8
        dc.w z80_ptr(MusCreditsDD9D)
        dc.b $24,$80,$0C,$80,$60,$EF,$10,$E6,$F7,$E1,$00,$E0
        dc.b $40,$F8
        dc.w z80_ptr(MusCreditsE2D2)
        dc.b $B3,$B7,$06,$AE,$0C,$B1,$B3,$B7,$06,$80,$B7,$AE
        dc.b $0C,$B1,$F8
        dc.w z80_ptr(MusCreditsE2D2)
        dc.b $EF,$15,$E6,$01,$F8
        dc.w z80_ptr(MusCreditsE22D)
-       dc.b $EF,$14,$80,$4E,$E0,$40,$A1,$12,$A2,$06,$E0,$C0
        dc.b $EF,$16,$80,$30,$80,$06,$BA,$08,$B9,$04,$B8,$08
        dc.b $B7,$04,$B6,$08,$B5,$04
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$17,$E9,$F4,$E6,$02,$E0,$C0
        dc.b $F0,$01,$01,$03,$03
-       dc.b $F8
        dc.w z80_ptr(MusCreditsDDD5)
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $80,$60,$EF,$1E,$E0,$40,$E6,$FE,$E9,$F4,$F4,$E8
        dc.b $06,$80,$0C,$C1,$06,$12,$18,$C4,$06,$12,$0C,$EF
        dc.b $1C,$E0,$C0,$E6,$FA,$E8,$00,$C6,$E8,$06,$E6,$06
        dc.b $EF,$1E,$E0,$40,$C2,$06,$12,$18,$C4,$06,$12,$18
        dc.b $C1,$06,$12,$18,$C4,$06,$12,$0C,$EF,$1A,$E0,$C0
        dc.b $E9,$0C,$C6,$06,$C6,$80,$C6,$80,$C6,$E8,$00,$C7
        dc.b $0C,$C8,$06,$EF,$1E,$E0,$40,$E9,$F4,$E8,$06,$80
        dc.b $C4,$06,$12,$0C,$80,$60,$EF,$20,$E9,$18,$E6,$FA
        dc.b $E0,$C0,$E8,$00,$B4,$03,$E7,$B6,$5D,$B3,$03,$E7
        dc.b $B5,$5D,$B1,$03,$E7,$B3,$5D,$B3,$03,$E7,$B5,$5D
        dc.b $80,$60,$EF,$22,$E0,$40,$E9,$E8,$E6,$04,$80,$30
        dc.b $80,$F8
        dc.w z80_ptr(MusCreditsE246)
        dc.b $C9,$30,$C8,$18,$C9,$0C,$C8,$C6,$30,$C9,$80,$0C
        dc.b $C1,$80,$C1,$80,$C2,$80,$C2,$E6,$04,$80,$C1,$80
        dc.b $C1,$80,$C2,$80,$C2,$E6,$FC,$80,$C1,$80,$C1,$80
        dc.b $C2,$18,$08,$C1,$04,$E9,$0C,$E6,$FF,$E0,$C0,$EF
        dc.b $00,$80,$60
-       dc.b $F8
        dc.w z80_ptr(MusCreditsE2C8)
        dc.b $C8,$12,$C8,$1E,$F8
        dc.w z80_ptr(MusCreditsE2C8)
        dc.b $CB,$12,$CB,$1E
        dc.b $F7,$00,$02
        dc.w z80_ptr(-)
        dc.b $E1,$03,$E6,$08,$F8
        dc.w z80_ptr(MusCreditsE28F)
        dc.b $E6,$F0,$EF,$01
        dc.b $F0,$00,$01,$06,$04
        dc.b $A2,$6C,$F2
MusCreditsE22D: dc.b $A2,$14,$A4,$04,$A5,$04,$80,$08,$A9,$04,$80,$08
        dc.b $A8,$04,$80,$08,$A9,$04,$80,$08,$AC,$08,$A9,$10
        dc.b $E3
MusCreditsE246: dc.b $80,$0C
        dc.b $C9,$04,$80,$10
        dc.b $C9,$04,$80,$0C
        dc.b $C9,$0C
        dc.b $CB,$08
        dc.b $C9,$04,$80,$18,$80,$0C
        dc.b $C8,$04,$80,$10
        dc.b $C8,$04,$80,$0C
        dc.b $C8,$0C
        dc.b $C9,$08
        dc.b $C8,$04,$80,$18,$80,$0C
 
    if 1==1
        ; this part of the original credits music (CNZ PSG) sounds buggy (dissonant)
        dc.b $C6,$04,$80,$10
        dc.b $C6,$04,$80,$0C
        dc.b $C6,$0C
        dc.b $C8,$08
        dc.b $C6,$04,$80,$18,$80,$0C
        dc.b $C5,$04,$80,$10
        dc.b $C5,$04,$80,$0C
        dc.b $C5,$0C
        dc.b $C7,$08
    else
        ; replace the above block of notes with this to fix it.
        ; (I'm not sure why, but the notes $C6 and $C7 are broken here,
        ;  so I've replaced them with pitch-shifted $C8s)
        dc.b    $E1,-64
        dc.b $C8,$04,$80,$10 ; $C6
        dc.b $C8,$04,$80,$0C ; $C6
        dc.b $C8,$0C ; $C6
        dc.b    $E1,0
        dc.b $C8,$08
        dc.b    $E1,-64
        dc.b $C8,$04,$80,$24 ; $C6
        dc.b    $E1,0
        dc.b $C5,$04,$80,$10
        dc.b $C5,$04,$80,$0C
        dc.b $C5,$0C
        dc.b    $E1,-32
        dc.b $C8,$08 ; $C7
; end of Mus_Credits
 
; ------------------------------------------------------------------------------------------
; Sound effect pointers
; ------------------------------------------------------------------------------------------
; WARNING the sound driver treats certain sounds specially
; going by the ID of the sound.
; SndID_Ring, SndID_RingLeft, SndID_Gloop, SndID_SpindashRev
; are referenced by the sound driver directly.
; If needed you can change this in s2.sounddriver.asm
 
 
; NOTE: the exact order of this list determines the priority of each sound, since it determines the sound's SndID.
;       a sound can get dropped if a higher-priority sound is already playing.
;   see zSFXPriority for the priority allocation itself.
; loc_FEE91: SoundPoint:
SoundIndex:
SndPtr_Jump:        rom_ptr_z80 Sound20 ; jumping sound
SndPtr_Checkpoint:  rom_ptr_z80 Sound21 ; checkpoint ding-dong sound
SndPtr_SpikeSwitch: rom_ptr_z80 Sound22 ; spike switch sound
SndPtr_Hurt:        rom_ptr_z80 Sound23 ; hurt sound
SndPtr_Skidding:    rom_ptr_z80 Sound24 ; skidding sound
SndPtr_BlockPush:   rom_ptr_z80 Sound25 ; block push sound
SndPtr_HurtBySpikes:    rom_ptr_z80 Sound26 ; spiky impalement sound
SndPtr_Sparkle:     rom_ptr_z80 Sound27 ; sparkling sound
SndPtr_Beep:        rom_ptr_z80 Sound28 ; short beep
SndPtr_Bwoop:       rom_ptr_z80 Sound29 ; bwoop (unused)
SndPtr_Splash:      rom_ptr_z80 Sound2A ; splash sound
SndPtr_Swish:       rom_ptr_z80 Sound2B ; swish
SndPtr_BossHit:     rom_ptr_z80 Sound2C ; boss hit
SndPtr_InhalingBubble:  rom_ptr_z80 Sound2D ; inhaling a bubble
SndPtr_ArrowFiring:
SndPtr_LavaBall:    rom_ptr_z80 Sound2E ; arrow firing
SndPtr_Shield:      rom_ptr_z80 Sound2F ; shield sound
SndPtr_LaserBeam:   rom_ptr_z80 Sound30 ; laser beam
SndPtr_Zap:     rom_ptr_z80 Sound31 ; zap (unused)
SndPtr_Drown:       rom_ptr_z80 Sound32 ; drownage
SndPtr_FireBurn:    rom_ptr_z80 Sound33 ; fire + burn
SndPtr_Bumper:      rom_ptr_z80 Sound34 ; bumper bing
SndPtr_Ring:
SndPtr_RingRight:   rom_ptr_z80 Sound35 ; ring sound
SndPtr_SpikesMove:  rom_ptr_z80 Sound36
SndPtr_Rumbling:    rom_ptr_z80 Sound37 ; rumbling
            rom_ptr_z80 Sound38 ; (unused)
SndPtr_Smash:       rom_ptr_z80 Sound39 ; smash/breaking
            rom_ptr_z80 Sound3A ; nondescript ding (unused)
SndPtr_DoorSlam:    rom_ptr_z80 Sound3B ; door slamming shut
SndPtr_SpindashRelease: rom_ptr_z80 Sound3C ; spindash unleashed
SndPtr_Hammer:      rom_ptr_z80 Sound3D ; slide-thunk
SndPtr_Roll:        rom_ptr_z80 Sound3E ; rolling sound
SndPtr_ContinueJingle:  rom_ptr_z80 Sound3F ; got continue
SndPtr_CasinoBonus: rom_ptr_z80 Sound40 ; short bonus ding
SndPtr_Explosion:   rom_ptr_z80 Sound41 ; badnik bust
SndPtr_WaterWarning:    rom_ptr_z80 Sound42 ; warning ding-ding
SndPtr_EnterGiantRing:  rom_ptr_z80 Sound43 ; special stage ring flash (mostly unused)
SndPtr_BossExplosion:   rom_ptr_z80 Sound44 ; thunk
SndPtr_TallyEnd:    rom_ptr_z80 Sound45 ; cha-ching
SndPtr_RingSpill:   rom_ptr_z80 Sound46 ; losing rings
            rom_ptr_z80 Sound47 ; chain pull chink-chink (unused)
SndPtr_Flamethrower:    rom_ptr_z80 Sound48 ; flamethrower
SndPtr_Bonus:       rom_ptr_z80 Sound49 ; bonus pwoieeew (mostly unused)
SndPtr_SpecStageEntry:  rom_ptr_z80 Sound4A ; special stage entry
SndPtr_SlowSmash:   rom_ptr_z80 Sound4B ; slower smash/crumble
SndPtr_Spring:      rom_ptr_z80 Sound4C ; spring boing
SndPtr_Blip:        rom_ptr_z80 Sound4D ; selection blip
SndPtr_RingLeft:    rom_ptr_z80 Sound4E ; another ring sound (only plays in the left speaker?)
SndPtr_Signpost:    rom_ptr_z80 Sound4F ; signpost spin sound
SndPtr_CNZBossZap:  rom_ptr_z80 Sound50 ; mosquito zapper
            rom_ptr_z80 Sound51 ; (unused)
            rom_ptr_z80 Sound52 ; (unused)
SndPtr_Signpost2P:  rom_ptr_z80 Sound53
SndPtr_OOZLidPop:   rom_ptr_z80 Sound54 ; OOZ lid pop sound
SndPtr_SlidingSpike:    rom_ptr_z80 Sound55
SndPtr_CNZElevator: rom_ptr_z80 Sound56
SndPtr_PlatformKnock:   rom_ptr_z80 Sound57
SndPtr_BonusBumper: rom_ptr_z80 Sound58 ; CNZ bonusy bumper sound
SndPtr_LargeBumper: rom_ptr_z80 Sound59 ; CNZ baaang bumper sound
SndPtr_Gloop:       rom_ptr_z80 Sound5A ; CNZ gloop / water droplet sound
SndPtr_PreArrowFiring:  rom_ptr_z80 Sound5B
SndPtr_Fire:        rom_ptr_z80 Sound5C
SndPtr_ArrowStick:  rom_ptr_z80 Sound5D ; chain clink
SndPtr_Helicopter:
SndPtr_WingFortress:    rom_ptr_z80 Sound5E ; helicopter
SndPtr_SuperTransform:  rom_ptr_z80 Sound5F
SndPtr_SpindashRev: rom_ptr_z80 Sound60 ; spindash charge
SndPtr_Rumbling2:   rom_ptr_z80 Sound61 ; rumbling
SndPtr_CNZLaunch:   rom_ptr_z80 Sound62
SndPtr_Flipper:     rom_ptr_z80 Sound63 ; CNZ blooing bumper
SndPtr_HTZLiftClick:    rom_ptr_z80 Sound64 ; HTZ track click sound
SndPtr_Leaves:      rom_ptr_z80 Sound65 ; kicking up leaves sound
SndPtr_MegaMackDrop:    rom_ptr_z80 Sound66 ; leaf splash?
SndPtr_DrawbridgeMove:  rom_ptr_z80 Sound67
SndPtr_QuickDoorSlam:   rom_ptr_z80 Sound68 ; door slamming quickly (unused)
SndPtr_DrawbridgeDown:  rom_ptr_z80 Sound69
SndPtr_LaserBurst:  rom_ptr_z80 Sound6A ; robotic laser burst
SndPtr_Scatter:
SndPtr_LaserFloor:  rom_ptr_z80 Sound6B ; scatter
SndPtr_Teleport:    rom_ptr_z80 Sound6C
SndPtr_Error:       rom_ptr_z80 Sound6D ; error sound
SndPtr_MechaSonicBuzz:  rom_ptr_z80 Sound6E ; silver sonic buzz saw
SndPtr_LargeLaser:  rom_ptr_z80 Sound6F
SndPtr_OilSlide:    rom_ptr_z80 Sound70
SndPtr__End:
 
    ; There are many non-relative pointers in these sound effects,
    ; so the sounds shouldn't simply be BINCLUDE'd.
    ; They could be included as separate .asm files using "include" instead of "binclude",
    ; but I wanted to minimize the number of included asm files.
 
    ; some comments on what the various script commands do (after the header):
    ;  0x00-0x7F sets the note duration (of the previous note and following notes)
    ;  0x81-0xDF plays a note (the valid range may be smaller for PSG or DAC)
    ;  0x80 plays silence
    ;  0xE0-0xFF does special things. I won't list them here... search for "Coordination flags" sonic 2.
 
    ; the FM voices (poorly named "ssamp" or "samples" below)
    ; are 25 bytes each and go directly to YM2612 registers.
    ; they can be hard to edit (there's an art to it)
    ; but search for sonic "Voice editing" for more info if you want to try.
 
; jumping sound
Sound20:    dc.w $0000,$0101
        dc.w $8080,z80_ptr(+),$F400
+       dc.b $F5,$00,$9E,$05,$F0,$02,$01,$F8,$65,$A3,$15,$F2
 
; checkpoint ding-dong sound
Sound21:    dc.w z80_ptr(ssamp21),$0101
        dc.w $8005,z80_ptr(+),$0001
ssamp21:    dc.b $3C,$05,$0A,$01,$01,$56,$5C,$5C,$5C,$0E,$11,$11
        dc.b $11,$09,$06,$0A,$0A,$4F,$3F,$3F,$3F,$17,$20,$80,$80
+       dc.b $EF,$00,$BD,$06,$BA,$16,$F2
 
; spike switch sound
Sound22:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F0,$01,$01,$F0,$08,$F3,$E7,$C0,$04,$CA,$04
-       dc.b $C0,$01,$EC
        dc.w $01F7,$0006,z80_ptr(-)
        dc.b $F2
 
; hurt sound
Sound23:    dc.w z80_ptr(ssamp23),$0101
        dc.w $8005,z80_ptr(+),$F400
+       dc.b $EF,$00,$B0,$07,$E7,$AD
-       dc.b $01,$E6
        dc.w $01F7,$002F,z80_ptr(-)
        dc.b $F2
ssamp23:    dc.b $30,$30,$30,$30,$30,$9E,$DC,$D8,$DC,$0E,$04,$0A
        dc.b $05,$08,$08,$08,$08,$BF,$BF,$BF,$BF,$14,$14,$3C,$80
 
; skidding sound
Sound24:    dc.w $0000,$0102 ; sound header... no sample and 2 script entries
        dc.w $80A0,z80_ptr(+),$F400 ; entry 1 header
        dc.w $80C0,z80_ptr(++),$F400 ; entry 2 header
+       dc.b $F5,$00,$AF,$01,$80,$AF,$80,$03 ; script entry 1
-       dc.b $AF,$01,$80
        dc.w $01F7,$000B,z80_ptr(-) ; loopback
        dc.b $F2 ; script 1 end
+       dc.b $F5,$00,$80,$01,$AD,$80,$AD,$80,$03 ; script entry 2
-       dc.b $AD,$01,$80
        dc.w $01F7,$000B,z80_ptr(-) ; loopback
        dc.b $F2 ; script 2 end
 
; block push sound
Sound25:    dc.w z80_ptr(ssamp25),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$80,$01,$8B,$0A,$80,$02,$F2
ssamp25:    dc.b $FA,$21,$10,$30,$32,$2F,$2F,$1F,$2F,$05,$09,$08
        dc.b $02,$06,$06,$0F,$02,$1F,$4F,$2F,$2F,$0F,$0E,$1A,$80
 
; spiky impalement sound
Sound26:    dc.w z80_ptr(ssamp26),$0101
        dc.w $8005,z80_ptr(+),$F200
+       dc.b $EF,$00,$F0,$01,$01,$10,$FF,$CF,$05,$D7,$25,$F2
ssamp26:    dc.b $3B,$3C,$30,$39,$31,$DF,$1F,$1F,$DF,$04,$04,$05
        dc.b $01,$04,$04,$04,$02,$FF,$1F,$0F,$AF,$29,$0F,$20,$80
 
; sparkling sound
Sound27:    dc.w z80_ptr(ssamp27),$0101
        dc.w $8004,z80_ptr(+),$0C1C
+       dc.b $EF,$00,$C1,$05,$C4,$05,$C9,$2B,$F2
ssamp27:    dc.b $07,$73,$33,$33,$73,$0F,$19,$14,$1A,$0A,$0A,$0A
        dc.b $0A,$0A,$0A,$0A,$0A,$57,$57,$57,$57,$00,$00,$00,$00
 
; short beep
Sound28:    dc.w $0000,$0101
        dc.w $8080,z80_ptr(+),$E803
+       dc.b $F5,$04,$CB,$04,$F2
 
; bwoop (unused)
Sound29:    dc.w $0000,$0101
        dc.w $80A0,z80_ptr(+),$0000
+       dc.b $F0,$01,$01,$E6,$35,$8E,$06,$F2
 
; splash sound
Sound2A:    dc.w z80_ptr(ssamp2A),$0102
        dc.w $80C0,z80_ptr(+),$0000
        dc.w $8005,z80_ptr(++),$0003
+       dc.b $F5,$00,$F3,$E7,$C2,$05,$C6,$05,$E7
-       dc.b $07,$EC,$01
        dc.w $E7F7,$000F,z80_ptr(-)
        dc.b $F2
+       dc.b $EF,$00,$A6,$14,$F2
ssamp2A:    dc.b $00,$00,$02,$03,$00,$D9,$1F,$DF,$1F,$12,$14,$11
        dc.b $0F,$0A,$0A,$00,$0D,$FF,$FF,$FF,$FF,$22,$27,$07,$80
 
; swish
Sound2B:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F5,$00,$F3,$E7,$C6,$03,$80,$03,$C6,$01,$E7
-       dc.b $01,$EC,$01
        dc.w $E7F7,$0015,z80_ptr(-)
        dc.b $F2
 
; boss hit
Sound2C:    dc.w z80_ptr(smashsamp),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$F0,$01,$01,$0C,$01
-       dc.b $81,$0A,$E6
        dc.w $10F7,$0004,z80_ptr(-)
        dc.b $F2
smashsamp:  dc.b $F9,$21,$10,$30,$32,$1F,$1F,$1F,$1F,$05,$09,$18
        dc.b $02,$0B,$10,$1F,$05,$1F,$4F,$2F,$2F,$0E,$04,$07,$80
 
; inhaling a bubble
Sound2D:    dc.w z80_ptr(ssamp2D),$0101
        dc.w $8005,z80_ptr(+),$0E00
+       dc.b $EF,$00,$F0,$01,$01,$21,$6E,$A6,$07
        dc.b $80,$06,$F0,$01,$01,$44,$1E,$AD,$08,$F2
ssamp2D:    dc.b $35,$05,$08,$09,$07,$1E,$0D,$0D,$0E,$0C,$03,$15
        dc.b $06,$16,$09,$0E,$10,$2F,$1F,$2F,$1F,$15,$12,$12,$80
 
; arrow firing
Sound2E:    dc.w z80_ptr(ssamp2E),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$80,$01,$F0,$01,$01,$40,$48,$83,$06,$85,$02,$F2
+       dc.b $F5,$00,$80,$0B,$F3,$E7,$C6,$01,$E7
-       dc.b $02,$EC,$01
        dc.w $E7F7,$0010,z80_ptr(-)
        dc.b $F2
ssamp2E:    dc.b $FA,$02,$00,$03,$05,$12,$0F,$11,$13,$05,$09,$18
        dc.b $02,$06,$06,$0F,$02,$1F,$4F,$2F,$2F,$2F,$0E,$1A,$80
 
; shield sound
Sound2F:    dc.w z80_ptr(ssamp2F),$0101
        dc.w $8005,z80_ptr(+),$0C00
+       dc.b $EF,$00,$80,$01,$A3,$05,$E7,$A4,$26,$F2
ssamp2F:    dc.b $30,$30,$30,$30,$30,$9E,$AC,$A8,$DC,$0E,$04,$0A
        dc.b $05,$08,$08,$08,$08,$BF,$BF,$BF,$BF,$04,$14,$2C,$80
 
; laser beam
Sound30:    dc.w z80_ptr(ssamp30),$0101 ; sound header... a voice and 1 script entry
        dc.w $8005,z80_ptr(+),$FB05 ; script entry header
+       dc.b $EF,$00,$DF,$7F ; script start
-       dc.b $DF,$02,$E6 ; script continued
        dc.w $01F7,$001B,z80_ptr(-) ; loopback
        dc.b $F2 ; script end
ssamp30:    dc.b $83,$1F,$1F,$15,$1F,$1F,$1F,$1F,$1F,$00,$00,$00 ; voice
        dc.b $00,$02,$02,$02,$02,$2F,$FF,$2F,$3F,$0B,$01,$16,$82 ; (fixed length)
 
; zap (unused)
Sound31:    dc.w z80_ptr(ssamp31),$0101
        dc.w $8005,z80_ptr(+),$FB02
+       dc.b $EF,$00,$B3,$05,$80,$01,$B3,$09,$F2
ssamp31:    dc.b $83,$12,$13,$10,$1E,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$02,$02,$02,$02,$2F,$FF,$2F,$3F,$05,$34,$10,$87
 
; drownage
Sound32:    dc.w z80_ptr(ssamp32),$0102
        dc.w $8004,z80_ptr(++),$0C04
        dc.w $8005,z80_ptr(+),$0E02
+       dc.b $EF,$00,$F0,$01,$01,$83,$0C
-       dc.b $8A,$05,$05,$E6
        dc.w $03F7,$000A,z80_ptr(-)
        dc.b $F2
+       dc.b $80,$06,$EF,$00,$F0,$01,$01,$6F,$0E
-       dc.b $8D,$04,$05,$E6
        dc.w $03F7,$000A,z80_ptr(-)
        dc.b $F2
ssamp32:    dc.b $35,$14,$04,$1A,$09,$0E,$11,$10,$0E,$0C,$03,$15
        dc.b $06,$16,$09,$0E,$10,$2F,$4F,$2F,$4F,$2F,$12,$12,$80
 
; fire + burn
Sound33:    dc.w z80_ptr(ssamp2E),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$80,$01,$F0,$01,$01,$40,$48,$83,$06,$85,$02,$F2
+       dc.b $F5,$00,$80,$0B,$F3,$E7,$A7,$25,$E7
-       dc.b $02,$EC,$01
        dc.w $E7F7,$0010,z80_ptr(-)
        dc.b $F2
 
; bumper bing
Sound34:    dc.w z80_ptr(ssamp34),$0103
        dc.w $8005,z80_ptr(+),$0000
        dc.w $8004,z80_ptr(++),$0000
        dc.w $8002,z80_ptr(+++),$0002
+       dc.b $EF,$00,$F6
        dc.w z80_ptr(Sound34_3)
+       dc.b $EF,$00,$E1,$07,$80,$01
Sound34_3:
        dc.b $BA,$20,$F2
+       dc.b $EF,$01,$9A,$03,$F2
ssamp34:    dc.b $3C,$05,$0A,$01,$01,$56,$5C,$5C,$5C,$0E,$11,$11
        dc.b $11,$09,$06,$0A,$0A,$4F,$3F,$3F,$3F,$1F,$2B,$80,$80
        dc.b $05,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$12,$0C,$0C
        dc.b $0C,$12,$08,$08,$08,$1F,$5F,$5F,$5F,$07,$80,$80,$80
 
; ring sound
Sound35:    dc.w z80_ptr(ringsamp),$0101
        dc.w $8005,z80_ptr(+),$0005
+       dc.b $EF,$00,$E0,$40,$C1,$05,$C4,$05,$C9,$1B,$F2
 
 
Sound36:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F0,$01,$01,$F0,$08,$F3,$E7,$C1,$07
-       dc.b $D0,$01,$EC
        dc.w $01F7,$000C,z80_ptr(-)
        dc.b $F2
 
; rumbling
Sound37:    dc.w z80_ptr(ssamp37),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$F0,$01,$01,$20,$08
-       dc.b $8B
        dc.w $0AF7,$0008,z80_ptr(-)
-       dc.b $8B,$10,$E6
        dc.w $03F7,$0009,z80_ptr(-)
        dc.b $F2
ssamp37:    dc.b $FA,$21,$10,$30,$32,$1F,$1F,$1F,$1F,$05,$09,$18
        dc.b $02,$06,$06,$0F,$02,$1F,$4F,$2F,$2F,$0F,$0E,$1A,$80
 
; (unused)
Sound38:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F0,$01,$01,$F0,$08,$F3,$E7,$B4,$08
-       dc.b $B0,$02,$EC
        dc.w $01F7,$0003,z80_ptr(-)
        dc.b $F2
 
; smash/breaking
Sound39:    dc.w z80_ptr(smashsamp),$0104
        dc.w $8002,z80_ptr(+),$1000
        dc.w $8004,z80_ptr(+++),$0000
        dc.w $8005,z80_ptr(++),$1000
        dc.w $80C0,z80_ptr(s39s4),$0000
+       dc.b $E0,$40,$80,$02,$F6
        dc.w z80_ptr(++)
+       dc.b $E0,$80,$80,$01
+       dc.b $EF,$00,$F0,$03,$01,$20,$04
-       dc.b $81,$18,$E6
        dc.w $0AF7,$0006,z80_ptr(-)
        dc.b $F2
s39s4:      dc.b $F0,$01,$01,$0F,$05,$F3,$E7
-       dc.b $B0,$18,$E7,$EC
        dc.w $03F7,$0005,z80_ptr(-)
        dc.b $F2
 
; nondescript ding (unused)
Sound3A:    dc.w z80_ptr(ssamp3A),$0101
        dc.w $8005,z80_ptr(+),$0007
+       dc.b $EF,$00,$AE,$08,$F2
ssamp3A:    dc.b $1C,$2E,$0F,$02,$02,$1F,$1F,$1F,$1F,$18,$14,$0F
        dc.b $0E,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$20,$1B,$80,$80
 
; door slamming shut
Sound3B:    dc.w z80_ptr(ssamp3B),$0101
        dc.w $8005,z80_ptr(+),$F400
+       dc.b $EF,$00,$9B,$04,$80,$A0,$06,$F2
ssamp3B:    dc.b $3C,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$00,$0F,$16
        dc.b $0F,$00,$00,$00,$00,$0F,$FF,$AF,$FF,$00,$0A,$80,$80
 
; spindash unleashed
Sound3C:    dc.w z80_ptr(ssamp3C),$0102
        dc.w $8005,z80_ptr(+),$9000
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$F0,$01,$01,$C5,$1A,$CD,$07,$F2
+       dc.b $F5,$07,$80,$07,$F0,$01,$02,$05,$FF,$F3,$E7,$BB,$4F,$F2
ssamp3C:    dc.b $FD,$09,$00,$03,$00,$1F,$1F,$1F,$1F,$10,$0C,$0C
        dc.b $0C,$0B,$10,$1F,$05,$1F,$4F,$2F,$2F,$09,$92,$84,$8E
 
; slide-thunk
Sound3D:    dc.w z80_ptr(ssamp3D),$0102
        dc.w $8005,z80_ptr(+),$100A
        dc.w $8004,z80_ptr(++),$0000
+       dc.b $EF,$00,$F0,$01,$01,$60,$01,$A7,$08,$F2
+       dc.b $80,$08,$EF,$01,$84,$22,$F2
ssamp3D:    dc.b $FA,$21,$19,$3A,$30,$1F,$1F,$1F,$1F,$05,$09,$18
        dc.b $02,$0B,$10,$1F,$05,$1F,$4F,$2F,$2F,$0E,$04,$07,$80
        dc.b $FA,$31,$10,$30,$32,$1F,$1F,$1F,$1F,$05,$05,$18
        dc.b $10,$0B,$10,$1F,$10,$1F,$1F,$2F,$2F,$0D,$01,$00,$80
 
; rolling sound
Sound3E:    dc.w z80_ptr(ssamp3E),$0101
        dc.w $8004,z80_ptr(+),$0C05
+       dc.b $EF,$00,$80,$01,$F0,$03,$01,$09,$FF,$CA,$25,$F4
-       dc.b $E7,$E6,$01,$D0
        dc.w $02F7,$002A,z80_ptr(-)
        dc.b $F2
ssamp3E:    dc.b $3C,$00,$02,$44,$02,$1F,$1F,$1F,$15,$00,$00,$1F
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$0D,$28,$00,$00
 
; got continue
Sound3F:    dc.w z80_ptr(ssamp3F),$0103
        dc.w $8002,z80_ptr(+),$F406
        dc.w $8004,z80_ptr(++),$F406
        dc.w $8005,z80_ptr(+++),$F406
+       dc.b $EF,$00,$C9,$07,$CD,$D0,$CB,$CE,$D2,$CD,$D0,$D4,$CE,$D2,$D5
-       dc.b $D0,$07,$D4,$D7,$E6
        dc.w $05F7,$0008,z80_ptr(-)
        dc.b $F2
+       dc.b $EF,$00,$E1,$01,$80,$07,$CD,$15,$CE,$D0,$D2
-       dc.b $D4,$15,$E6
        dc.w $05F7,$0008,z80_ptr(-)
        dc.b $F2
+       dc.b $EF,$00,$E1,$01,$C9,$15,$CB,$CD,$CE
-       dc.b $D0,$15,$E6
        dc.w $05F7,$0008,z80_ptr(-)
        dc.b $F2
ssamp3F:    dc.b $14,$25,$36,$33,$11,$1F,$1F,$1F,$1F,$15,$1C,$18
        dc.b $13,$0B,$0D,$08,$09,$0F,$8F,$9F,$0F,$24,$0A,$05,$80
 
; short bonus ding
Sound40:    dc.w z80_ptr(ssamp3F),$0102
        dc.w $8005,z80_ptr(++),$0008
        dc.w $8004,z80_ptr(+),$0008
+       dc.b $E1,$03,$80,$02
+       dc.b $EF,$00,$C4,$16,$F2
 
; badnik bust
Sound41:    dc.w z80_ptr(ssamp41),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0002
+       dc.b $F0,$03,$01,$72,$0B,$EF,$00,$BA,$16,$F2
+       dc.b $F5,$01,$F3,$E7,$B0,$1B,$F2
ssamp41:    dc.b $3C,$0F,$03,$01,$01,$1F,$1F,$1F,$1F,$19,$19,$12
        dc.b $0E,$05,$00,$12,$0F,$0F,$FF,$7F,$FF,$00,$00,$80,$80
 
; warning ding-ding
Sound42:    dc.w z80_ptr(ssamp3F),$0101
        dc.w $8005,z80_ptr(+),$0C08
+       dc.b $EF,$00,$BA,$08,$BA,$25,$F2
 
; special stage ring flash (mostly unused)
Sound43:    dc.w z80_ptr(ssamp43),$0102
        dc.w $8004,z80_ptr(+),$0C00
        dc.w $8005,z80_ptr(++),$0013
+       dc.b $EF,$01,$80,$01,$A2,$08,$EF,$00,$E7,$AD,$26,$F2
+       dc.b $EF,$02,$F0,$06,$01,$03,$FF,$80,$0A
-       dc.b $C3
        dc.w $06F7,$0005,z80_ptr(-)
        dc.b $C3,$17,$F2
ssamp43:    dc.b $30,$30,$34,$5C,$30,$9E,$AC,$A8,$DC,$0E,$04,$0A
        dc.b $05,$08,$08,$08,$08,$BF,$BF,$BF,$BF,$24,$04,$1C,$80
        dc.b $30,$30,$34,$5C,$30,$9E,$AC,$A8,$DC,$0E,$04,$0A
        dc.b $05,$08,$08,$08,$08,$BF,$BF,$BF,$BF,$24,$04,$2C,$80
        dc.b $04,$37,$77,$72,$49,$1F,$1F,$1F,$1F,$07,$07,$0A
        dc.b $0D,$00,$00,$0B,$0B,$1F,$1F,$0F,$0F,$13,$13,$81,$88
 
; thunk
Sound44:    dc.w z80_ptr(ssamp44),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$8A,$22,$F2
ssamp44:    dc.b $FA,$21,$10,$30,$32,$1F,$1F,$1F,$1F,$05,$05,$18
        dc.b $10,$0B,$10,$1F,$10,$1F,$4F,$2F,$2F,$0D,$04,$07,$80
 
; cha-ching
Sound45:    dc.w z80_ptr(ssamp45),$0103
        dc.w $8005,z80_ptr(+),$0000
        dc.w $8004,z80_ptr(++),$0000
        dc.w $80C0,z80_ptr(+++),$0000
+       dc.b $EF,$00,$8A,$08,$80,$02,$8A,$08,$F2
+       dc.b $EF,$01,$80,$12,$C6,$55,$F2
+       dc.b $F5,$02,$F3,$E7,$80,$02,$C2,$05,$C4,$04,$C2,$05,$C4,$04,$F2
ssamp45:    dc.b $3B,$03,$02,$02,$06,$18,$1A,$1A,$96,$17,$0A,$0E
        dc.b $10,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$00,$39,$28,$80
ringsamp:   dc.b $04,$37,$77,$72,$49,$1F,$1F,$1F,$1F,$07,$07,$0A
        dc.b $0D,$00,$00,$0B,$0B,$1F,$1F,$0F,$0F,$23,$23,$80,$80
 
; losing rings (scatter)
Sound46:    dc.w z80_ptr(ringsamp),$0102
        dc.w $8004,z80_ptr(+),$0005
        dc.w $8005,z80_ptr(++),$0008
+       dc.b $EF,$00,$C6,$02,$05,$05,$05,$05,$05,$05,$3A,$F2
+       dc.b $EF,$00,$80,$02,$C4,$02,$05,$15,$02,$05,$32,$F2
 
; chain pull chink-chink (unused)
Sound47:    dc.w z80_ptr(ssamp47),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$BE,$05,$80,$04,$BE,$04,$80,$04,$F2
ssamp47:    dc.b $28,$2F,$37,$5F,$2B,$1F,$1F,$1F,$1F,$15,$15,$15
        dc.b $13,$13,$0D,$0C,$10,$2F,$3F,$2F,$2F,$00,$1F,$10,$80
 
; flamethrower
Sound48:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F5,$00,$F3,$E7,$A7,$25,$F2
 
; bonus pwoieeew (mostly unused)
Sound49:    dc.w z80_ptr(ssamp49),$0101
        dc.w $8005,z80_ptr(+),$0E00
+       dc.b $EF,$00,$F0,$01,$01,$33,$18,$B9,$1A,$F2
ssamp49:    dc.b $3B,$0A,$05,$31,$02,$5F,$5F,$5F,$5F,$04,$16,$14
        dc.b $0C,$00,$00,$04,$00,$1F,$D8,$6F,$FF,$03,$00,$25,$80
 
; special stage entry
Sound4A:    dc.w z80_ptr(ssamp4A),$0101
        dc.w $8005,z80_ptr(+),$0002
+       dc.b $EF,$00,$F0,$01,$01,$5B,$02,$CC,$65,$F2
ssamp4A:    dc.b $20,$36,$30,$35,$31,$41,$3B,$49,$4B,$09,$09,$06
        dc.b $08,$01,$02,$03,$A9,$0F,$0F,$0F,$0F,$29,$23,$27,$80
 
; slower smash/crumble
Sound4B:    dc.w z80_ptr(smashsamp),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$F0,$03,$01,$20,$04
-       dc.b $81,$18,$E6
        dc.w $0AF7,$0006,z80_ptr(-)
        dc.b $F2
+       dc.b $F0,$01,$01,$0F,$05,$F3,$E7
-       dc.b $B0,$18,$E7,$EC
        dc.w $03F7,$0005,z80_ptr(-)
        dc.b $F2
 
; spring boing
Sound4C:    dc.w z80_ptr(ssamp4C),$0101
        dc.w $8004,z80_ptr(+),$0002
+       dc.b $EF,$00,$80,$01,$F0,$03,$01,$5D,$0F,$B0,$0C,$F4
-       dc.b $E7,$E6,$02,$BD
        dc.w $02F7,$0019,z80_ptr(-)
        dc.b $F2
ssamp4C:    dc.b $20,$36,$30,$35,$31,$DF,$9F,$DF,$9F,$07,$09,$06
        dc.b $06,$07,$06,$06,$08,$2F,$1F,$1F,$FF,$16,$13,$30,$80
 
; selection blip
Sound4D:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $BB,$02,$F2
 
; another ring sound (only plays in the left speaker?)
Sound4E:    dc.w z80_ptr(ringsamp),$0101
        dc.w $8004,z80_ptr(+),$0005
+       dc.b $EF,$00,$E0,$80,$C1,$04,$C4,$05,$C9,$1B,$F2
 
; signpost spin sound
Sound4F:    dc.w z80_ptr(ssamp4F),$0102
        dc.w $8004,z80_ptr(+),$2703
        dc.w $8005,z80_ptr(++),$2700
+       dc.b $80,$04
+       dc.b $EF,$00
-       dc.b $B4,$05,$E6
        dc.w $02F7,$0015,z80_ptr(-)
        dc.b $F2
ssamp4F:    dc.b $F4,$06,$0F,$04,$0E,$1F,$1F,$1F,$1F,$00,$0B,$00
        dc.b $0B,$00,$05,$00,$08,$0F,$FF,$0F,$FF,$0C,$03,$8B,$80
 
; mosquito zapper
Sound50:    dc.w z80_ptr(ssamp50),$0101
        dc.w $8005,z80_ptr(+),$F400
+       dc.b $EF,$00,$B3,$04,$80,$01
-       dc.b $B4,$04,$80
        dc.w $01F7,$0004,z80_ptr(-)
        dc.b $F2
ssamp50:    dc.b $83,$12,$13,$10,$1E,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$02,$02,$02,$02,$2F,$FF,$2F,$3F,$06,$34,$10,$87
 
; (unused)
Sound51:    dc.w z80_ptr(ssamp51),$0102
        dc.w $80C0,z80_ptr(+),$0001
        dc.w $8005,z80_ptr(++),$000B
+       dc.b $F5,$02,$F3,$E4,$B0,$04,$85,$02,$F2
+       dc.b $EF,$00,$E8,$04,$A5,$06,$F2
ssamp51:    dc.b $3C,$02,$01,$00,$01,$1F,$1F,$1F,$1F,$00,$19,$0E
        dc.b $10,$00,$00,$0C,$0F,$0F,$FF,$EF,$FF,$05,$00,$80,$80
 
; (unused)
Sound52:    dc.w z80_ptr(ssamp52),$0101
        dc.w $8005,z80_ptr(+),$0002
+       dc.b $F0,$01,$01,$2A,$07,$EF,$00
-       dc.b $A5,$03
        dc.w $E7F7,$0013,z80_ptr(-)
-       dc.b $A5,$03,$E7,$E6
        dc.w $02F7,$0013,z80_ptr(-)
        dc.b $F2
ssamp52:    dc.b $28,$21,$21,$21,$30,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$29,$20,$29,$80
 
 
Sound53:    dc.w z80_ptr(ssamp53),$0101
        dc.w $8005,z80_ptr(+),$F503
+       dc.b $EF,$00,$F0,$01,$01,$46,$09,$A7,$14,$E7,$14,$E7,$E6,$04
        dc.b $14,$E7,$E6,$04,$14,$E7,$E6,$04,$0A,$E7,$E6,$04,$0A,$F2
ssamp53:    dc.b $07,$0A,$0C,$0C,$0C,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$2A,$0F,$0F,$80
 
; OOZ lid pop sound
Sound54:    dc.w z80_ptr(ssamp54),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0006
+       dc.b $EF,$00,$B6,$15,$F2
+       dc.b $F3,$E7,$F5,$04,$C6,$03,$E7,$C5,$E7
        dc.b $C4,$E7,$C3,$E7,$C2,$E7,$C1,$E7,$C0,$F2
ssamp54:    dc.b $07,$03,$02,$03,$00,$FF,$6F,$6F,$3F,$12,$14,$11
        dc.b $0E,$1A,$0A,$03,$0D,$FF,$FF,$FF,$FF,$03,$07,$07,$80
 
 
Sound55:    dc.w z80_ptr(ssamp55),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$AA,$07,$B6,$15,$F2
ssamp55:    dc.b $42,$20,$0E,$0F,$0F,$1F,$1F,$1F,$1F,$1F,$1F,$1F
        dc.b $1F,$0F,$0E,$0F,$0E,$0F,$0F,$0F,$0F,$2E,$80,$20,$80
 
 
Sound56:    dc.w z80_ptr(ssamp56),$0101
        dc.w $8005,z80_ptr(+),$100E
+       dc.b $EF,$00,$F0,$01,$01,$1E,$FF,$8F,$1C,$F4
-       dc.b $E7,$9A
        dc.w $05F7,$0009,z80_ptr(-)
-       dc.b $E7,$9A,$04,$E6,$02,$E7,$9A,$04,$E6
        dc.w $02F7,$0008,z80_ptr(-)
        dc.b $F2
ssamp56:    dc.b $0D,$06,$00,$00,$E5,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$27,$80,$80,$80
 
 
Sound57:    dc.w z80_ptr(ssamp57),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$CA,$15,$F2
ssamp57:    dc.b $04,$09,$70,$00,$30,$1C,$1F,$DF,$1F,$15,$12,$0B
        dc.b $0F,$0C,$0D,$00,$0D,$07,$2F,$FA,$FA,$00,$29,$00,$00
 
; CNZ bonusy bumper sound
Sound58:    dc.w z80_ptr(ssamp58),$0101
        dc.w $8005,z80_ptr(+),$0007
+       dc.b $EF,$00,$B3,$06,$B3,$15,$F2
ssamp58:    dc.b $3C,$05,$0A,$01,$01,$56,$5C,$5C,$5C,$0E,$11,$11
        dc.b $11,$09,$06,$0A,$0A,$4F,$3F,$3F,$3F,$17,$20,$80,$80
 
; CNZ baaang bumper sound
Sound59:    dc.w z80_ptr(ssamp59),$0103
        dc.w $8004,z80_ptr(+),$0000
        dc.w $8002,z80_ptr(++),$0002
        dc.w $8005,z80_ptr(+++),$0000
+       dc.b $EF,$00,$E1,$0C,$B5,$14,$F2
+       dc.b $EF,$01,$9A,$03,$F2
+       dc.b $EF,$00,$B6,$14,$F2
ssamp59:    dc.b $32,$30,$30,$40,$70,$1F,$1F,$1F,$1F,$12,$0A,$01
        dc.b $0D,$00,$01,$01,$0C,$00,$23,$C3,$F6,$08,$07,$1C,$03
        dc.b $05,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$12,$0C,$0C
        dc.b $0C,$12,$08,$08,$08,$1F,$5F,$5F,$5F,$07,$80,$80,$80
 
; CNZ gloop / water droplet sound
Sound5A:    dc.w z80_ptr(ssamp5A),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$F0,$01,$01,$7F,$F1,$AA,$0A,$F2
ssamp5A:    dc.b $47,$03,$02,$02,$04,$5F,$5F,$5F,$5F,$0E,$1A,$11
        dc.b $0A,$09,$0A,$0A,$0A,$4F,$3F,$3F,$3F,$7F,$80,$80,$A3
 
 
Sound5B:    dc.w z80_ptr(ssamp5B),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$80,$02,$A5,$01,$E7
-       dc.b $01,$E7,$E6
        dc.w $02F7,$0005,z80_ptr(-)
        dc.b $F2
ssamp5B:    dc.b $38,$0F,$0F,$0F,$0F,$1F,$1F,$1F,$0E,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$1F,$00,$00,$00,$80
 
 
Sound5C:    dc.w z80_ptr(ssamp5C),$0102
        dc.w $8004,z80_ptr(+),$000E
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$85,$40
-       dc.b $E7,$04,$E6
        dc.w $04F7,$000A,z80_ptr(-)
        dc.b $F2
+       dc.b $F5,$00,$F3,$E7,$A7,$40
-       dc.b $E7,$08,$E6
        dc.w $01F7,$0005,z80_ptr(-)
        dc.b $F2
ssamp5C:    dc.b $FA,$12,$01,$01,$01,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$81,$8E,$14,$80
 
; chain clink
Sound5D:    dc.w z80_ptr(ssamp5D),$0101
        dc.w $8005,z80_ptr(+),$0000
+       dc.b $EF,$00,$C0,$04,$F2
ssamp5D:    dc.b $28,$2F,$37,$5F,$2B,$1F,$1F,$1F,$1F,$15,$15,$15
        dc.b $13,$13,$0D,$0C,$10,$2F,$3F,$2F,$2F,$00,$1F,$10,$80
 
; helicopter
Sound5E:    dc.w z80_ptr(ssamp5E),$0101
        dc.w $8002,z80_ptr(+),$1405
+       dc.b $EF,$00
-       dc.b $95,$02,$95
        dc.w $01F7,$0013,z80_ptr(-)
-       dc.b $95,$02,$95,$01,$E6
        dc.w $01F7,$001B,z80_ptr(-)
        dc.b $F2
ssamp5E:    dc.b $35,$30,$44,$40,$51,$1F,$1F,$1F,$1F,$10,$00,$13
        dc.b $15,$1F,$00,$1F,$1A,$7F,$0F,$7F,$5F,$02,$A8,$80,$80
 
 
Sound5F:    dc.w z80_ptr(ssamp5F),$0103
        dc.w $8005,z80_ptr(s5Fs1),$0000
        dc.w $80C0,z80_ptr(s5Fs2),$0000
        dc.w $80A0,z80_ptr(s5Fs3),$0000
s5Fs1       dc.b $EF,$00,$F0,$01,$01,$C5,$1A,$CD,$07,$E6,$0A,$80
        dc.b $06,$EF,$01,$F0,$01,$01,$11,$FF,$A2,$28
-       dc.b $E7,$03,$E6
        dc.w $03F7,$0005,z80_ptr(-)
        dc.b $F2
s5Fs2       dc.b $80,$07,$F0,$01,$02,$05,$FF,$F3,$E7,$BB,$1D
-       dc.b $E7,$07,$EC
        dc.w $01F7,$0010,z80_ptr(-)
        dc.b $F2
s5Fs3       dc.b $80,$16,$F5,$03
-       dc.b $BF,$04,$C1,$C3,$EC,$01,$E9
        dc.w $FFF7,$0005,z80_ptr(-)
-       dc.b $BF,$04,$C1,$C3,$EC,$01,$E9
        dc.w $01F7,$0007,z80_ptr(-)
        dc.b $F2
ssamp5F:    dc.b $FD,$09,$00,$03,$00,$1F,$1F,$1F,$1F,$10,$0C,$0C
        dc.b $0C,$0B,$10,$1F,$05,$1F,$4F,$2F,$2F,$09,$92,$84,$8E
        dc.b $3A,$70,$30,$04,$01,$0F,$14,$19,$16,$08,$0A,$0B
        dc.b $05,$03,$03,$03,$05,$1F,$6F,$8F,$5F,$1F,$22,$1F,$80
 
; spindash charge
Sound60:    dc.w z80_ptr(ssamp60),$0101
        dc.w $8005,z80_ptr(+),$FE00
+       dc.b $EF,$00,$F0,$00,$01,$20,$F6,$C4,$16,$E7,$F4,$D0,$18,$E7
-       dc.b $04,$E7,$E6
        dc.w $03F7,$0010,z80_ptr(-)
        dc.b $F2
ssamp60:    dc.b $34,$00,$03,$0C,$09,$9F,$8C,$8F,$95,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$00,$1D,$00,$00
 
; rumbling
Sound61:    dc.w z80_ptr(ssamp61),$0101
        dc.w $8004,z80_ptr(+),$0004
+       dc.b $80,$01,$EF,$00,$F0,$00,$01,$70,$06,$82,$06,$85,$08,$83
        dc.b $01,$82,$05,$86,$06,$89,$03,$82,$08,$88,$04,$82,$06,$E6
        dc.b $02,$85,$08,$E6,$02,$83,$01,$E6,$02,$82,$05,$E6,$02,$86
        dc.b $06,$E6,$02,$89,$03,$E6,$02,$82,$08,$E6,$02,$88,$04,$E6,$02,$F2
ssamp61:    dc.b $32,$30,$30,$50,$30,$1F,$0E,$19,$0E,$07,$12,$15
        dc.b $09,$0A,$09,$1D,$06,$E8,$03,$0A,$17,$07,$00,$00,$00
 
 
Sound62:    dc.w z80_ptr(ssamp62),$0101
        dc.w $8005,z80_ptr(+),$FF00
+       dc.b $EF,$00,$A6,$05,$F0,$01,$01,$E7,$40
-       dc.b $C4,$02,$E7,$E6
        dc.w $01F7,$0012,z80_ptr(-)
        dc.b $F2
ssamp62:    dc.b $34,$0C,$10,$73,$0C,$AF,$AC,$FF,$D5,$06,$00,$02
        dc.b $01,$02,$0A,$04,$08,$BF,$BF,$BF,$BF,$00,$08,$80,$80
 
; CNZ blooing bumper
Sound63:    dc.w z80_ptr(ssamp63),$0101
        dc.w $8005,z80_ptr(+),$0907
+       dc.b $EF,$00,$F0,$01,$01,$04,$56,$92,$03,$9A,$25,$F2
ssamp63:    dc.b $3D,$12,$10,$77,$30,$5F,$5F,$5F,$5F,$0F,$0A,$00
        dc.b $01,$0A,$0A,$0D,$0D,$4F,$0F,$0F,$0F,$13,$80,$80,$80
 
; HTZ track click sound
Sound64:    dc.w z80_ptr(ssamp64),$0101
        dc.w $8005,z80_ptr(+),$1100
+       dc.b $EF,$00,$C7,$02,$F2
ssamp64:    dc.b $24,$2A,$02,$05,$01,$1A,$1F,$10,$1F,$0F,$1F,$1F
        dc.b $1F,$0C,$0D,$11,$11,$0C,$09,$09,$0F,$0E,$04,$80,$80
 
; kicking up leaves sound
Sound65:    dc.w z80_ptr(ssamp65),$0101
        dc.w $80C0,z80_ptr(+),$F800
+       dc.b $F5,$03,$F3,$E7,$CE,$03,$F5,$06,$CE,$04,$EC
        dc.b $02,$CE,$02,$F5,$03,$EC,$FE,$CE,$08,$CE,$18,$F2
ssamp65:    ; uhm... apparently they forgot to null out the pointer to here.
        ; luckily, sound 65 doesn't really use its sample
 
; leaf splash?
Sound66:    dc.w z80_ptr(ssamp66),$0102
        dc.w $8005,z80_ptr(++),$EE08
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F3,$E7,$F5,$09,$C6,$36,$F2
+       dc.b $EF,$00,$80,$01,$92,$02,$02,$02,$30,$F2
ssamp66:    dc.b $32,$33,$17,$34,$13,$0F,$0D,$1B,$17,$00,$04,$02
        dc.b $0B,$08,$00,$08,$09,$6F,$5F,$4F,$6F,$05,$00,$00,$80
 
 
Sound67:    dc.w z80_ptr(ssamp67),$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F5,$06,$F3,$E7,$90,$0A,$94,$0A,$98,$0A,$9C
        dc.b $0A,$A0,$0A,$A4,$08,$A8,$08,$AC,$08,$B0,$08,$F2
ssamp67:    ; another not-really-used sample (like Sound65)
 
; door slamming quickly (unused)
Sound68:    dc.w z80_ptr(ssamp68),$0101
        dc.w $8005,z80_ptr(+),$F400
+       dc.b $EF,$00,$9B,$04,$A5,$06,$F2
ssamp68:    dc.b $3C,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$00,$0F,$16
        dc.b $0F,$00,$00,$00,$00,$0F,$FF,$AF,$FF,$00,$0A,$80,$80
 
 
Sound69:    dc.w z80_ptr(ssamp69),$0102
        dc.w $8005,z80_ptr(+),$F400
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$9B,$03,$A8,$06,$9E,$08,$F2
+       dc.b $F5,$04,$F3,$E7,$C6,$03,$C6,$06,$C6,$08,$F2
ssamp69:    dc.b $3C,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$00,$0F,$16
        dc.b $0F,$00,$00,$00,$00,$0F,$FF,$AF,$FF,$00,$0A,$80,$80
 
; robotic laser burst
Sound6A:    dc.w z80_ptr(ssamp6A),$0101
        dc.w $8005,z80_ptr(+),$0004
+       dc.b $EF,$00,$DF,$14,$E6,$18,$06,$F2
ssamp6A:    dc.b $3D,$09,$34,$34,$28,$1F,$16,$16,$16,$00,$00,$00
        dc.b $04,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$15,$02,$02,$00
 
; scatter
Sound6B:    dc.w z80_ptr(ssamp6B),$0101
        dc.w $8004,z80_ptr(+),$0002
+       dc.b $EF,$00,$81,$04,$80,$0C,$F2
ssamp6B:    dc.b $3A,$30,$30,$40,$70,$1F,$1F,$1F,$1F,$12,$0A,$01
        dc.b $07,$00,$01,$01,$03,$00,$23,$C3,$46,$08,$07,$1C,$03
 
 
Sound6C:    dc.w z80_ptr(ssamp6C),$0104
        dc.w $8005,z80_ptr(++),$0010
        dc.w $8004,z80_ptr(+),$0010
        dc.w $80C0,z80_ptr(s5Fs2),$0000
        dc.w $80A0,z80_ptr(s5Fs3),$0000
+       dc.b $E1,$10
+       dc.b $EF,$01,$F0,$01,$01,$EC,$56,$C0,$24,$F4,$EF,$00,$E6,$F0
-       dc.b $BB,$02,$E7,$E6,$02,$E9
        dc.w $01F7,$0020,z80_ptr(-)
        dc.b $F2
ssamp6C:    dc.b $00,$53,$30,$03,$30,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$00,$00,$00,$0F,$0F,$06,$23,$80
        dc.b $3C,$72,$32,$32,$72,$14,$14,$0F,$0F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$02,$02,$08,$08,$35,$14,$00,$00
 
; error sound
Sound6D:    dc.w z80_ptr(ssamp6D),$0101
        dc.w $8005,z80_ptr(+),$0004
+       dc.b $EF,$00,$B0,$06,$80,$06,$B0,$18,$F2
ssamp6D:    dc.b $38,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$00,$00,$00
        dc.b $00,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$1F,$0C,$17,$00
 
; silver sonic buzz saw
Sound6E:    dc.w z80_ptr(ssamp6E),$0102
        dc.w $8005,z80_ptr(+),$0000
        dc.w $80C0,z80_ptr(++),$0000
+       dc.b $EF,$00,$C6,$24,$E7
-       dc.b $C6,$04,$E7,$E6
        dc.w $04F7,$0008,z80_ptr(-)
        dc.b $F2
+       dc.b $F3,$E7,$C7,$44,$F2
ssamp6E:    dc.b $33,$00,$10,$00,$31,$1F,$1D,$1E,$0E,$00,$0C,$1D
        dc.b $00,$00,$00,$01,$00,$0F,$0F,$0F,$0F,$08,$06,$07,$80
 
 
Sound6F:    dc.w z80_ptr(ssamp6A),$0103
        dc.w $8005,z80_ptr(++),$000B
        dc.w $8004,z80_ptr(+),$0012
        dc.w $80C0,z80_ptr(+++),$0000
+       dc.b $E1,$02,$80,$02
+       dc.b $EF,$00,$E6,$0C,$DF,$06,$E7,$E6,$F4,$06,$E7
        dc.b $E6,$F4,$12,$E7,$E6,$0C,$06,$E7,$E6,$0C,$06,$F2
+       dc.b $F3,$E7,$C6,$04,$C0,$BA,$B4,$AE,$E6
        dc.b $01,$AE,$E6,$01,$AE,$E6,$01,$AE,$F2
 
 
Sound70:    dc.w $0000,$0101
        dc.w $80C0,z80_ptr(+),$0000
+       dc.b $F3,$E7,$C6,$18
-       dc.b $E7,$03,$E6
        dc.w $01F7,$0008,z80_ptr(-)
        dc.b $F2
 
 
    finishBank
 
; end of 'ROM'
    if padToPowerOfTwo && (*)&(*-1)
        cnop    -1,2<<lastbit(*-1)
        dc.b    0
paddingSoFar    := paddingSoFar+1
    else
        even
    endif
    if MOMPASS=2
        ; "About" because it will be off by the same amount that Size_of_Snd_driver_guess is incorrect (if you changed it), and because I may have missed a small amount of internal padding somewhere
        message "ROM size is $\{*} bytes (\{*/1024.0} kb). About $\{paddingSoFar} bytes are padding. "
    endif
    ; share these symbols externally (WARNING: don't rename, move or remove these labels!)
    shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic,movewZ80CompSize
EndOfRom:
    END

Comments