;
;       Disassembled by:
;               DASMx object code disassembler
;               (c) Copyright 1996-1999   Conquest Consultants
;               Version 1.30 (Oct  6 1999)
;       Commented by:
;               Annotate 1.5a (16 Dec 2007) by Amigan Software
;               (and by hand)
;
;       File:           COMBATA.bin
;
;       Size:           2048 bytes
;       Checksum:       7D18
;       CRC-32:         5E8EE224
;
;       Date:           Sun Oct 14 20:50:24 2007
;
;       CPU:            Signetics 2650 (2650 family)
;       Platform:       Interton VC 4000 family, type "A" (2K ROM + 0K RAM)
;
;$VER: 1.0 (7.2.2008)
;Disassembled by Amigan Software in January and February 2008.
;Please inform us of any mistakes found...
;URL:   http://amigan.classicgaming.gamespy.com/
;EMail: amigansoftware@gmail.com
;
;This game does not work properly (problems with duplicate sprites) under
; Ami/WinArcadia 5.5 (at least), in "twin plane" modes.
;
;Hardware Equates/Memory Map----------------------------------------------
;                   $0000..$07FF: (R/-)  2K of ROM
;                   $0800..$15FF: (-/-)  unused
;                   $1600..$17FF:        mirror of $1E00..$1FFF
;                   $1800..$1DFF: (-/-)  unused
;                   $1E00..$1E7F: (-/-)  unused
NOISE           equ $1E80        ;(?/W)  noise register
;    bits 7..6:                          unused?
;    bit  5:                             bkgrnd colour inversion on/off
;    bit  4:                             noise on/off
;    bit  3:                             unknown
;    bit  2:                             sound to TV speaker?
;    bits 1..0:                          unused?
;                   $1E81..$1E87: (-/-)  unmapped
P1LEFTKEYS      equ $1E88        ;(R/-)
;    bit  7:                             p1 (left)  '1' button
;    bit  6:                             p1 (left)  '4' button
;    bit  5:                             p1 (left)  '7' button
;    bit  4:                             p1 (left)  'C' button (Clear)
;    bits 3..0:                          unused
P1MIDDLEKEYS    equ $1E89        ;(R/-)
;    bit  7:                             p1 (left)  '2' button
;    bit  6:                             p1 (left)  '5' button
;    bit  5:                             p1 (left)  '8' button
;    bit  4:                             p1 (left)  '0' button
;    bits 3..0:                          unused
P1RIGHTKEYS     equ $1E8A        ;(R/-)
;    bit  7:                             p1 (left)  '3' button
;    bit  6:                             p1 (left)  '6' button
;    bit  5:                             p1 (left)  '9' button
;    bit  4:                             p1 (left)  'E' button (Enter)
;    bits 3..0:                          unused
CONSOLE         equ $1E8B        ;(R/-)
;    bit  7:                             'SELECT'       button
;    bit  6:                             'START'        button
;    bit  5:                             unused
;    bit  4:                             unused
;    bits 3..0:                          unused
P2LEFTKEYS      equ $1E8C        ;(R/-)
;    bit  7:                             p2 (right) '1' button
;    bit  6:                             p2 (right) '4' button
;    bit  5:                             p2 (right) '7' button
;    bit  4:                             p2 (right) 'C' button (Clear)
;    bits 3..0:                          unused
P2MIDDLEKEYS    equ $1E8D        ;(R/-)
;    bit  7:                             p2 (right) '2' button
;    bit  6:                             p2 (right) '5' button
;    bit  5:                             p2 (right) '8' button
;    bit  4:                             p2 (right) '0' button
;    bits 3..0:                          unused
P2RIGHTKEYS     equ $1E8E        ;(R/-)
;    bit  7:                             p2 (right) '3' button
;    bit  6:                             p2 (right) '6' button
;    bit  5:                             p2 (right) '9' button
;    bit  4:                             p2 (right) 'E' button (Enter)
;    bits 3..0:                          unused
;                   $1E8F..$1E97  (-/-)  unmapped
;                   $1E98..$1E9B  (R/-)  mirror of $1E88..$1E8B
;                   $1E9C..$1EA7  (-/-)  unmapped
;                   $1EA8..$1EAE  (R/-)  mirror of $1E88..$1E8E
;                   $1EAF..$1EB7  (-/-)  unmapped
;                   $1EB8..$1EBB  (R/-)  mirror of $1E88..$1E8B
;                   $1EBC..$1EC7  (-/-)  unmapped
;                   $1EC8..$1ECE  (R/-)  mirror of $1E88..$1E8E
;                   $1ECF..$1ED7  (-/-)  unmapped
;                   $1ED8..$1EDB  (R/-)  mirror of $1E88..$1E8B
;                   $1EDC..$1EE7  (-/-)  unmapped
;                   $1EE8..$1EEE  (R/-)  mirror of $1E88..$1E8E
;                   $1EEF..$1EF7  (-/-)  unmapped
;                   $1EF8..$1EFB  (R/-)  mirror of $1E88..$18EB
;                   $1EFC..$1EFF  (-/-)  unmapped
;                   $1F00..$1F09: (R/W)  imagery for sprite #0 (8*10)
SPRITE0AX       equ $1F0A        ;(R/W)
SPRITE0BX       equ $1F0B        ;(R/W)
SPRITE0AY       equ $1F0C        ;(R/W)
SPRITE0BY       equ $1F0D        ;(R/W)
;                   $1F0E..$1F0F: (R/W)  motherboard RAM
;                   $1F10..$1F19: (R/W)  imagery for sprite #1 (8*10)
SPRITE1AX       equ $1F1A        ;(R/W)
SPRITE1BX       equ $1F1B        ;(R/W)
SPRITE1AY       equ $1F1C        ;(R/W)
SPRITE1BY       equ $1F1D        ;(R/W)
;                   $1F1E..$1F1F: (R/W)  motherboard RAM
;                   $1F20..$1F29: (R/W)  imagery for sprite #2 (8*10)
SPRITE2AX       equ $1F2A        ;(R/W)
SPRITE2BX       equ $1F2B        ;(R/W)
SPRITE2AY       equ $1F2C        ;(R/W)
SPRITE2BY       equ $1F2D        ;(R/W)
;                   $1F2E..$1F3F: (-/-)  unmapped
;                   $1F40..$1F49: (R/W)  imagery for sprite #3 (8*10)
SPRITE3AX       equ $1F4A        ;(R/W)
SPRITE3BX       equ $1F4B        ;(R/W)
SPRITE3AY       equ $1F4C        ;(R/W)
SPRITE3BY       equ $1F4D        ;(R/W)
;                   $1F4E..$1F6D: (R/W)  motherboard RAM
;                   $1F6E..$1F7F: (-/-)  unmapped
;                   $1F80..$1FA7 ;(R/W)  vertical grid
HORIZ1          equ $1FA8        ;(R/W)  horizontal grid #1
HORIZ2          equ $1FA9        ;(R/W)  horizontal grid #2
HORIZ3          equ $1FAA        ;(R/W)  horizontal grid #3
HORIZ4          equ $1FAB        ;(R/W)  horizontal grid #4
HORIZ5          equ $1FAC        ;(R/W)  horizontal grid #5
;                   $1FAD:        (R/W)  motherboard RAM
;                   $1FAE..$1FBF: (-/-)  unmapped
SIZES           equ $1FC0        ;(-/W)
SPR01COLOURS    equ $1FC1        ;(-/W)
;    bits 7..6:                          unused
;    bits 5..3:                          colour of sprite #0
;                                        (inverted RGB mask)
;    bits 2..0:                          colour of sprite #1
;                                        (inverted RGB mask)
SPR23COLOURS    equ $1FC2        ;(-/W)
;    bits 7..6:                          unused
;    bits 5..3:                          colour of sprite #2
;                                        (inverted RGB mask)
;    bits 2..0:                          colour of sprite #3
;                                        (inverted RGB mask)
SCORECTRL       equ $1FC3        ;(-/W)
;    bits 7..2:                          unused
;    bit  1:                             score format
;                                        0 = 2 groups of 2 digits
;                                        1 = 1 group  of 4 digits
;    bit  0:                             score position
;                                        0 = top    of screen
;                                        1 = bottom of screen
;                   $1FC4..$1FC5: (-/-)  unused
BGCOLOUR        equ $1FC6        ;(-/W)
;    bit  7:                             unused
;    bits 6..4:                          grid colour (normal RGB HB mask)
;    bit  3:                             grid/background enable flag
;                                        (0=off, 1=on)
;    bits 2..0:                          screen colour (normal RGB HB
;                                        mask) (black if bit 3 is clear)
PITCH           equ $1FC7        ;(-/W)
;    bits 7..0:                          pitch
SCORELT         equ $1FC8        ;(-/W)  left digit pair
;    bits 7..4:                          BCD value of 1st digit
;    bits 3..0:                          BCD value of 2nd digit
SCORERT         equ $1FC9        ;(-/W)  right digit pair
;    bits 7..4:                          BCD value of 3rd digit
;    bits 3..0:                          BCD value of 4th digit
BGCOLLIDE       equ $1FCA        ;(R/-)  read-once!
;    bit  7:                             sprite #0 collision with bkgrnd
;    bit  6:                             sprite #1 collision with bkgrnd
;    bit  5:                             sprite #2 collision with bkgrnd
;    bit  4:                             sprite #3 collision with bkgrnd
;    bit  3:                             sprite #0 display complete
;    bit  2:                             sprite #1 display complete
;    bit  1:                             sprite #2 display complete
;    bit  0:                             sprite #3 display complete
SPRITECOLLIDE   equ $1FCB        ;(R/-)  read-once!
;    bit  7:                             unused
;    bit  6:                             vertical reset flag
;    bit  5:                             sprites #0/#1 collision
;    bit  4:                             sprites #0/#2 collision
;    bit  3:                             sprites #0/#3 collision
;    bit  2:                             sprites #1/#2 collision
;    bit  1:                             sprites #1/#3 collision
;    bit  0:                             sprites #2/#3 collision
P1PADDLE        equ $1FCC        ;(R/-)
P2PADDLE        equ $1FCD        ;(R/-)
;                   $1FCE..$1FCF ;(-/-)  unused
;                   $1FD0..$1FDF:        semi-mirror of $1FC0..$1FCF
;                   $1FE0..$1FEF:        semi-mirror of $1FC0..$1FCF
;                   $1FF0..$1FFF:        semi-mirror of $1FC0..$1FCF
;                   $2000..$3FFF:        mirror of $0000..$1FFF
;                   $4000..$5FFF:        mirror of $0000..$1FFF
;                   $6000..$7FFF:        mirror of $0000..$1FFF
;2650 Equates-------------------------------------------------------------
z               equ 0
eq              equ z
p               equ 1
gt              equ p
n               equ 2
lt              equ n
un              equ 3
r4              equ r1
r5              equ r2
r6              equ r3
;User Variables-----------------------------------------------------------
OPTION          equ $1F0E ;BCD equivalent of current game option
                          ;high bit indicates whether game in progress, so...
                          ;$00..$09 =  0.. 9, game not in progress
                          ;$10..$19 = 10..19, game not in progress
                          ;$20..$26 = 20..26, game not in progress
                          ;$80..$89 =  0.. 9, game is  in progress
                          ;$90..$99 = 10..19, game is  in progress
                          ;$A0..$A6 = 20..26, game is  in progress
DERIVED         equ $1F0F ;derived from option
                          ;= (option - 1) * 3
                          ;which is different to (OPTION - 1) * 3
                          ;gives a range of $00..$4B for options '1'..'26'
                          ;eg. if option  '1', OPTION2 is $00
                          ;    if option '10', OPTION2 is $1B [27]
                          ;    if option '20', OPTION2 is $1B [57]
P1SCORE         equ $1F1E ;score of left player
P2SCORE         equ $1F1F ;score of right player
BGCOLLIDECOPY   equ $1F4E ;copy of BGCOLLIDE
SPRCOLLIDECOPY  equ $1F4F ;copy of SPRITECOLLIDE
;                   $1F50: ?
BULLET1DIST     equ $1F51 ;distance travelled by p1's bullet(s) (0 if no bullets)
BULLET2DIST     equ $1F52 ;distance travelled by p2's bullet(s) (0 if no bullets)
;            $1F53..$1F5C: ?
P1VANGLE        equ $1F5D ;angle of p1's vehicle(s)
                          ;$0 = N      $8 = S
                          ;$1 = NNE    $9 = SSW
                          ;$2 = NE     $A = SW
                          ;$3 = ENE    $B = WSW
                          ;$4 = E      $C = W
                          ;$5 = ESE    $D = WNW
                          ;$6 = SE     $E = NW
                          ;$7 = SSE    $F = NNW
P2VANGLE        equ $1F5E ;angle of p2's vehicle(s)
P1BANGLE        equ $1F5F ;angle of p1's bullet(s)
MONOTONIC       equ $1F5F ;yes, same variable as P1BANGLE, reused as delay counter
                          ;(it is set to $E7 at eg. reset, and increments
                          ;once per frame until reaching $00)
P2BANGLE        equ $1F60 ;angle of p2's bullet(s)
;            $1F61..$1F62: ?
SPRITE0AXCOPY   equ $1F63 ;?
SPRITE1AXCOPY   equ $1F64 ;?
SPRITE0AYCOPY   equ $1F65 ;?
SPRITE1AYCOPY   equ $1F66 ;?
VEHICLECOLOURS  equ $1F67 ;usually is a copy of SPR01COLOURS
BULLETRANGE     equ $1F68 ;maximum range for bullets
;                   $1F69: ranges between 0..3, counts down by 1
PRESERVER0      equ $1F6A
PRESERVEPSL     equ $1F6B
;                   $1F6C: ?
IDLE_H          equ $1F6D ;high byte of idle counter
                          ;(counts down by 1 whenever IDLE_L hits zero)
                          ;(resets to zero whenever input is received)
IDLE_L          equ $1FAD ;low byte of idle counter
                          ;(counts down by 8 per frame)
                          ;(resets to zero whenever input is received)
;-------------------------------------------------------------------------
        org     $0000
;
BOOT:                                                                   ;0
        eorz    r0           ;r0 = 0;                                 ;2,1
        bctr,un BOOT_1;      ;goto BOOT_1;                            ;3,2
;Interrupt Vector---------------------------------------------------------
L0003:
        bcta,un L03F6        ;goto L03F6;                             ;3,3
;-------------------------------------------------------------------------
BOOT_1:                                                                ;$6
        lodi,r2 $01          ;r2 = $01;                               ;2,2
        strz    r3           ;r3 = r0;                                ;2,1
L0009:
        eorz    r0           ;r0 = 0;                                 ;2,1
        lpsl                 ;PSL = r0 [0];                           ;2,1
        lpsu                 ;PSU = r0 [0];                           ;2,1
;inhibit interrupts and set Stack Pointer to 7
        ppsu    $27          ;PSU |= ..I..!!!;                        ;3,2
;select unsigned comparisons
        ppsl    $02          ;PSL |= ......M.;                        ;3,2

;*($1F00..$1FFF) = 0;
        strz    r1           ;r1 = r0 [0]; // loop iterator           ;2,1
L0011:
        stra,r0 $1F00,r1     ;*($1F00 + r1) = r0 [0];                 ;4,3
        birr,r1 L0011        ;if (++r1 != 0) goto L0011;              ;3,2
;end of loop

        stra,r2 OPTION       ;OPTION = r2; // motherboard RAM         ;4,3
        andi,r2 $7F          ;r2 &= %01111111;                        ;2,2
        stra,r2 SCORERT      ;SCORERT = r2; // hardware registers     ;4,3

        lodi,r0 $FF          ;r0 = $FF;                               ;2,2
        stra,r0 SCORELT      ;SCORELT = r0 ['  ']; // hardware regs   ;4,3

        stra,r3 DERIVED      ;DERIVED = r3; // motherboard RAM        ;4,3

;this sets up *($1F80..$1FAC) (VERTGRID, HORIZ1..HORIZ5)
;if ((*($7AE + r3) & %00001111) != 0)
;{   r1 = *($7A6 + (*($7AE + r3) & %00001111));
;    for (r3 = 45; r3 >= 1; r3--)
;    {   *($1F7F + r3) = *($6C6 + --r1); // vertical grid
;}   }
        loda,r0 $07AE,r3     ;r0 = *($07AE + r3);                     ;4,3
        andi,r0 $0F          ;r0 &= %00001111;                        ;2,2
        bctr,eq L003B        ;if == goto L003B;                       ;3,2
        loda,r0 $07A6,r0     ;r0 = *($07A6 + r0);                     ;4,3
        strz    r1           ;r1 = r0;                                ;2,1
        lodi,r3 $2D          ;r3 = $2D; // start of loop              ;2,2
L0033:
        loda,r0 $06C6,r1-    ;r0 = *($06C6 + --r1);                   ;4,3
        stra,r0 $1F7F,r3     ;*($1F7F + r3) = r0;                     ;4,3
        bdrr,r3 L0033        ;if (--r3 != 0) goto L0033;              ;3,2
;end of loop

L003B:

;*($1F4E..$1F6C) = 0; // mobo RAM
        eorz    r0           ;r0 = 0;                                 ;2,1
        lodi,r3 $1F          ;r3 = $1F; // loop iterator              ;2,2
L003E:
        stra,r0 $1F4D,r3     ;*($1F4D + r3) = r0 [0];                 ;4,3
        bdrr,r3 L003E        ;if (--r3 != 0) goto L003E;              ;3,2
;end of loop

        strz    r1           ;r1 = r0;                                ;2,1
        bsta,un L02DC        ;gosub L02DC;                            ;3,3
        lodi,r1 $01          ;r1 = $01;                               ;2,2
        lodi,r0 $08          ;r0 = $08;                               ;2,2
        bstr,un *$0045       ;gosub *($0045); // ROM operand          ;3,2
                             ;or, gosub L02DC; // ROM code
        lodi,r0 $26          ;r0 = $26;                               ;2,2
        stra,r0 SPRITE0AX    ;SPRITE0AX = r0 [38]; // hardware regs   ;4,3
        lodi,r0 $8A          ;r0 = $8A;                               ;2,2
        stra,r0 SPRITE1AX    ;SPRITE1AX = r0 [$8A]; // hardware regs  ;4,3
        lodi,r0 $69          ;r0 = $69;                               ;2,2
        stra,r0 SPRITE0AY    ;SPRITE0AY = r0 [$69]; // hardware regs  ;4,3
        stra,r0 SPRITE1AY    ;SPRITE1AY = r0 [$69]; // hardware regs  ;4,3

;VEHICLECOLOURS = SPR01COLOURS = *($7AC + DERIVED);
        lodr,r2 *$0024       ;r2 = *(*($0024)); // ROM operand        ;3,2
                             ;or, r2 = DERIVED; // user RAM
        loda,r0 $07AC,r2     ;r0 = *($07AC + r2);                     ;4,3
        stra,r0 SPR01COLOURS ;SPR01COLOURS = r0; // hardware registers;4,3
        stra,r0 VEHICLECOLOURS
                             ;VEHICLECOLOURS = r0; // motherboard RAM ;4,3

;*($1F22..$1F27) = *($62A..$62F); // sprite #2 imagery (3rd..8th rows) (bullet)
;*($1F42..$1F47) = *($62A..$62F); // sprite #3 imagery (3rd..8th rows) (bullet)
        lodi,r1 $06          ;r1 = $06; // loop iterator              ;2,2
L006C:
        loda,r0 $0629,r1     ;r0 = *($0629 + r1);                     ;4,3
        stra,r0 $1F21,r1     ;*($1F21 + r1) = r0;                     ;4,3
        stra,r0 $1F41,r1     ;*($1F41 + r1) = r0;                     ;4,3
        bdrr,r1 L006C        ;if (--r1 != 0) goto L006C;              ;3,2
;end of loop

;be silent
        lodi,r3 $00          ;r3 = $00;                               ;2,2
        bsta,un MAKENOISE    ;gosub MAKENOISE;                        ;3,3 0079

;set sprites #2 and #3 (bullets) to red
        lodi,r0 $1B          ;r0 = $1B;                               ;2,2
        stra,r0 SPR23COLOURS ;SPR23COLOURS = r0 [%00,011,011]; // hw regs
                                                                      ;4,3

        loda,r0 $07AD,r2     ;r0 = *($07AD + r2);                     ;4,3
        stra,r0 BGCOLOUR     ;BGCOLOUR = r0; // hardware registers    ;4,3
        lodi,r0 $E7          ;r0 = $E7;                               ;2,2
        bsta,un L03DF        ;gosub L03DF;                            ;3,3
        stra,r0 BGCOLLIDECOPY;BGCOLLIDECOPY = r0 [%0000,0000]; // mobo RAM
                                                                      ;4,3
        stra,r0 SPRCOLLIDECOPY;SPRCOLLIDECOPY = r0 [%0,0,000000]; // mobo RAM
                                                                      ;4,3
        strz    r1           ;r1 = r0;                                ;2,1
        bsta,un KILLBULLETS  ;gosub KILLBULLETS;                      ;3,3

MAINLOOP:                                                             ;$96
;wait (if necessary) for player to choose options and start
        loda,r0 OPTION       ;r0 = OPTION; // motherboard RAM         ;4,3
        bcfr,lt MAINLOOP     ;if >= goto MAINLOOP;                    ;3,2

;ok, game is starting
        lodi,r0 $FF          ;r0 = $FF;                               ;2,2
        stra,r0 SCORELT      ;SCORELT = r0 ['  ']; // hardware regs   ;4,3
        stra,r0 SCORERT      ;SCORERT = r0 ['  ']; // hardware regs   ;4,3
        lodi,r1 $00          ;r1 = $00;                               ;2,2
        bsta,un CHECKBULLET  ;gosub CHECKBULLET(0);                   ;3,3
;we want 2 groups of 2 digits at the bottom of the screen
        lodi,r1 $01          ;r1 = $01;                               ;2,2
        stra,r1 SCORECTRL    ;SCORECTRL = r1 [%000000,0,1]; // h/w regs
                                                                      ;4,3
        bstr,un *$00A6       ;gosub *($00A6); // ROM operand          ;3,2
                             ;or, gosub CHECKBULLET(1); // ROM code
        lodi,r1 $00          ;r1 = $00;                               ;2,2
        bsta,un L016E        ;gosub L016E(0);                         ;3,3
        lodi,r1 $01          ;r1 = $01;                               ;2,2
        bstr,un *$00B2       ;gosub *($00B2); // ROM operand          ;3,2
                             ;or, gosub L016E(1); // ROM code
        bctr,un MAINLOOP     ;goto MAINLOOP;                          ;3,2
;Subroutine CHECKBULLET---------------------------------------------------
CHECKBULLET:                                                          ;$BA
;r1 is passed as an argument, it is always either 0 or 1

;if r1 == 0, r0 = %00000010 (ie. sprite #2)
;if r1 == 1, r0 = %00000001 (ie. sprite #3)
        loda,r0 $05DA,r1     ;r0 = *($05DA + r1); // ROM data         ;4,3

;check the player's bullet
        bsta,un CHECKBGCOLLIDE;gosub CHECKBGCOLLIDE;                  ;3,3
        retc,eq              ;if == return;                           ;3,1

;player's bullet has completed displaying
        loda,r2 DERIVED      ;r2 = DERIVED; // motherboard RAM        ;4,3

;if (r1 == 0)
;{   r0 = SPRITE2AY;
;} elif (r1 == 1)
;{   r0 = SPRITE3AY;
;}
        loda,r0 $05E6,r1     ;r0 = *($05E6 + r1);                     ;4,3
        loda,r0 $1F0C,r0     ;r0 = *(&SPRITE0AY + r0);                ;4,3

        bcta,eq CHECKBULLET_6;if == goto CHECKBULLET_6;               ;3,3

;if (r1 == 0)
;{   r0 = %00100000; // sprite #2
;} elif (r1 == 1)
;{   r0 = %00010000; // sprite #3
;}
        loda,r0 $05D6,r1     ;r0 = *($05D6 + r1);                     ;4,3
        bstr,un *$00BE       ;gosub *($00BE); // ROM operand          ;3,2
                             ;or, gosub CHECKBGCOLLIDE; // ROM code
        bctr,eq CHECKBULLET_3;if == goto CHECKBULLET_3;               ;3,2

;player's bullet has collided with background

;if (*($7AC + DERIVED) & $80) goto CHECKBULLET_3;
;or, if (planes) goto CHECKBULLET_3;
        loda,r0 $07AC,r2     ;r0 = *($07AC + r2);                     ;4,3
        bctr,lt CHECKBULLET_3;if < goto CHECKBULLET_3;                ;3,2

;tanks game

;if (!(*($7AD + DERIVED) & $80)) goto KILLBULLET;
;or, if (not rebounding barricades) goto KILLBULLET;
        loda,r0 $07AD,r2     ;r0 = *($07AD + r2);                     ;4,3
        bcfa,lt KILLBULLET   ;if >= goto KILLBULLET;                  ;3,3

;rebound the bullet

;if ((PnBANGLE % 4) == 0) r3 = PnBANGLE + 1; else r3 = PnBANGLE;
        loda,r0 P1BANGLE,r1  ;r0 = *(&P1BANGLE + r1);                 ;4,3
        strz    r3           ;r3 = r0;                                ;2,1
        andi,r0 $03          ;r0 &= %00000011;                        ;2,2
        bcfr,eq CHECKBULLET_1;if != goto CHECKBULLET_1;               ;3,2
        addi,r3 $01          ;r3++;                                   ;2,2

CHECKBULLET_1:                                                        ;$E9
        eori,r3 $FF          ;r3 ^= %11111111;                        ;2,2
        addi,r3 $09          ;r3 += $09;                              ;2,2

;if (SPRITEnAY >= $1E && SPRITEnAY <= $B9) // n is 2 or 3 for player 0 or 1 respectively
;{   PnBANGLE = (r3 + 8) & %00001111; // n is 0 or 1 for player 0 or 1 respectively
;} else
;{   PnBANGLE =  r3      & %00001111; // n is 0 or 1 for player 0 or 1 respectively
;}
        loda,r0 $05E6,r1     ;r0 = *($05E6 + r1);                     ;4,3
        loda,r0 $1F0C,r0     ;r0 = *($1F0C + r0);                     ;4,3
        comi,r0 $1E          ;compare r0 against $1E;                 ;2,2
        bctr,lt CHECKBULLET_2;if < goto CHECKBULLET_2;                ;3,2
        comi,r0 $B9          ;compare r0 against $B9;                 ;2,2
        bctr,gt CHECKBULLET_2;if > goto CHECKBULLET_2;                ;3,2
        addi,r3 $08          ;r3 += $08;                              ;2,2
CHECKBULLET_2:                                                        ;$FD
        andi,r3 $0F          ;r3 &= %00001111;                        ;2,2
        lodz    r3           ;r0 = r3;                                ;2,1
        stra,r0 P1BANGLE,r1  ;*(&P1BANGLE + r1) = r0;                 ;4,3
;PnBANGLE has now been adjusted

;if (r1 == 0)
;{   r1 = 2;
;} elif (r1 == 1)
;{   r1 = 3;
;}
        addi,r1 $02          ;r1 += $02;                              ;2,2

        bstr,un *$0129       ;gosub *($0129); // ROM operand          ;3,2
                             ;or, gosub L01CF; // ROM code

;if (r1 == 2)
;{   r1 = 0;
;} elif (r1 == 3)
;{   r1 = 1;
;}
        subi,r1 $02          ;r1 -= $02;                              ;2,2

;*($1F69) = 3;
        lodi,r0 $03          ;r0 = $03;                               ;2,2
        stra,r0 $1F69        ;*($1F69) = r0 [3]; // motherboard RAM   ;4,3

CHECKBULLET_3:                                                       ;$10E

;if (r1 == 0)
;{   r0 = %00000100 (sprite #1);
;} elif (r1 == 1)
;{   r0 = %00001000 (sprite #0);
;}
        lodi,r0 $08          ;r0 = $08;                               ;2,2
        brnr,r1 CHECKBULLET_4;if (r1 != 0) goto CHECKBULLET_4;        ;3,2
        rrr,r0               ;r0 >>= 1;                               ;2,1

CHECKBULLET_4:                                                       ;$113
        bsta,un CHECKSPRCOLLIDE;gosub CHECKSPRCOLLIDE;                ;3,3
        bcta,gt KILLPLAYER   ;if > goto KILLPLAYER;                   ;3,3

;didn't collide with enemy vehicle

;BULLETnDIST += 2;
        lodi,r0 $02          ;r0 = $02;                               ;2,2
        adda,r0 BULLET1DIST,r1
                             ;r0 += *(&BULLET1DIST + r1);             ;4,3
        stra,r0 BULLET1DIST,r1
                             ;*(&BULLET1DIST + r1) = r0;              ;4,3

;if (BULLETnDIST == BULLETRANGE) goto KILLBULLET;
        comr,r0 *$013E       ;compare r0 against *(*($013E)); // ROM operand
                                                                      ;3,2
                             ;or, compare r0 against BULLETRANGE; // mobo RAM
        bcta,eq KILLBULLET   ;if == goto KILLBULLET;                  ;3,3

CHECKBULLET_5:                                                       ;$126
        addi,r1 $02          ;r1 += $02;                              ;2,2
        bsta,un L01CF        ;gosub L01CF;                            ;3,3
        retc,eq              ;if == return;                           ;3,1

;*($1F4F + r1) = BULLETRANGE - 2;
        lodi,r0 $FE          ;r0 = $FE;                               ;2,2
        addr,r0 *$013E       ;r0 += *(*($013E)); // ROM operand       ;3,2
                             ;or, r0 += BULLETRANGE; // mobo RAM
        stra,r0 $1F4F,r1     ;*($1F4F + r1) = r0;                     ;4,3

        retc,un              ;return;                                 ;3,1
;
CHECKBULLET_6:                                                       ;$134
;bullet has reached top of screen?
        bsta,un L036A        ;gosub L036A;                            ;3,3
        retc,eq              ;if == return;                           ;3,1

;BULLETRANGE = *($7AE + r2) & $20;
        loda,r0 $07AE,r2     ;r0 = *($07AE + r2); // ROM data         ;4,3
        andi,r0 $20          ;r0 &= %00100000;                        ;2,2
        stra,r0 BULLETRANGE  ;BULLETRANGE = r0; // motherboard RAM    ;4,3

        loda,r0 $07AC,r2     ;r0 = *($07AC + r2);                     ;4,3
        strz    r3           ;r3 = r0;                                ;2,1
        loda,r0 $07AE,r2     ;r0 = *($07AE + r2); // useless!         ;4,3
        bsta,lt VEHICLECOLOUR;if < gosub VEHICLECOLOUR(r1, r3);       ;3,3

;PnBANGLE = PnVANGLE;
        loda,r0 P1VANGLE,r1  ;r0 = *(&P1VANGLE + r1);                 ;4,3
        stra,r0 P1BANGLE,r1  ;*(&P1BANGLE + r1) = r0;                 ;4,3

        eorz    r0           ;r0 = 0;                                 ;2,1
        stra,r0 $1F55,r1     ;*($1F55 + r1) = r0 [0];                 ;4,3
        stra,r0 $1F59,r1     ;*($1F59 + r1) = r0 [0];                 ;4,3

;*($1F0C + *($5E6 + r1)) = *($1F0C + *($5E4 + r1));
;*($1F0A + *($5E6 + r1)) = *($1F0A + *($5E4 + r1));
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        strz    r3           ;r3 = r0;                                ;2,1
        loda,r0 $05E6,r1     ;r0 = *($05E6 + r1);                     ;4,3
        strz    r2           ;r2 = r0;                                ;2,1
        loda,r0 $1F0C,r3     ;r0 = *($1F0C + r3);                     ;4,3
        stra,r0 $1F0C,r2     ;*($1F0C + r2) = r0;                     ;4,3
        loda,r0 $1F0A,r3     ;r0 = *($1F0A + r3);                     ;4,3
        stra,r0 $1F0A,r2     ;*($1F0A + r2) = r0;                     ;4,3

        bcta,un CHECKBULLET_5;goto CHECKBULLET_5;                     ;3,3
;Subroutine L016E---------------------------------------------------------
L016E:
;r1 is passed as an argument, it is always either 0 or 1

;if (r1 == 0) r0 = %00001000; // sprite #0 display complete
;if (r1 == 1) r0 = %00000100; // sprite #1 display complete
        loda,r0 $05D8,r1     ;r0 = *($05D8 + r1);                     ;4,3
        bsta,un CHECKBGCOLLIDE;gosub CHECKBGCOLLIDE(8 >> r1);         ;3,3
        retc,eq              ;if == return;                           ;3,1

;display of player's vehicle has completed
        stra,r1 $1F6C        ;*($1F6C) = r1; // motherboard RAM       ;4,3
        loda,r2 DERIVED      ;r2 = DERIVED; // motherboard RAM        ;4,3

;if (r1 == 0) r0 = %10000000; // sprite #0 collision with background
;if (r1 == 1) r0 = %01000000; // sprite #1 collision with background
        loda,r0 $05D4,r1     ;r0 = *($05D4 + r1);                     ;4,3
        bstr,un *$0172       ;gosub *($0172); // ROM operand          ;3,2
                             ;or, gosub CHECKBGCOLLIDE; // ROM code
        bctr,eq L01AB        ;if == goto L01AB;                       ;3,2

;player's vehicle has collided with background

;if (*($7AE + DERIVED) & $40)
;or, if (minefields)
;{   r1 ^= %00000001; // swap players
;    goto KILLPLAYER;
;}
        loda,r0 $07AE,r2     ;r0 = *($07AE + r2);                     ;4,3
                             ;or, r0 = *($7AE + DERIVED);
        rrl,r0               ;r0 <<= 1;                               ;2,1
        bcfr,lt L018D        ;if >= goto L018D;                       ;3,2
        eori,r1 $01          ;r1 ^= %00000001;                        ;2,2
        bcta,un KILLPLAYER   ;goto KILLPLAYER;                        ;3,3

L018D:
;no minefields

;if (*($7AC + DERIVED) & $80) || *($7AC + DERIVED) == 0)
;or, if (planes) // *($7AC + DERIVED) is actually never 0
;{   gosub VEHICLECOLOUR(r1, $36); // change colour of this plane
;    goto L01C1;
;}
        loda,r0 $07AC,r2     ;r0 = *($07AC + r2);                     ;4,3
                             ;or, r0 = *($7AC + DERIVED);
        bctr,gt L0199        ;if > goto L0199;                        ;3,2
        lodi,r3 $36          ;r3 = $36;                               ;2,2
L0194:
        bsta,un VEHICLECOLOUR;gosub VEHICLECOLOUR(r1, r3);            ;3,3
        bctr,un L01C1        ;goto L01C1;                             ;3,2
;
L0199:

;SPRITEnAX = SPRITEnAXCOPY;
;SPRITEnAY = SPRITEnAYCOPY;
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        strz    r2           ;r2 = r0;                                ;2,1
        loda,r0 $1F63,r1     ;r0 = *($1F63 + r1);                     ;4,3
        stra,r0 $1F0A,r2     ;*(&SPRITE0AX + r2) = r0;                ;4,3
        loda,r0 $1F65,r1     ;r0 = *($1F65 + r1);                     ;4,3
        stra,r0 $1F0C,r2     ;*(&SPRITE0AY + r2) = r0;                ;4,3

        bctr,un L01C1        ;goto L01C1;                             ;3,2
;
L01AB:

;vehicle has not collided with background

;if (*($7AC + DERIVED) & $80)
;or, if (planes)
;{   gosub VEHICLECOLOUR(r1, *($7AC + DERIVED));
;    goto L01C1;
;}
        loda,r0 $07AC,r2     ;r0 = *($07AC + r2);                     ;4,3
                             ;or, r0 = *($7AC + DERIVED);
        strz    r3           ;r3 = r0;                                ;2,1
        bctr,lt L0194        ;if < goto L0194;                        ;3,2

;SPRITEnAXCOPY = SPRITEnAX;
;SPRITEnAYCOPY = SPRITEnAY;
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        strz    r2           ;r2 = r0;                                ;2,1
        loda,r0 $1F0A,r2     ;r0 = *(&SPRITE0AX + r2);                ;4,3
        stra,r0 $1F63,r1     ;*($1F63 + r1) = r0;                     ;4,3
        loda,r0 $1F0C,r2     ;r0 = *(&SPRITE0AY + r2);                ;4,3
        stra,r0 $1F65,r1     ;*($1F65 + r1) = r0;                     ;4,3

L01C1:
        lodi,r0 $20          ;r0 = %00100000; // sprites #0/#1 collision
                                                                      ;2,2
        bsta,un CHECKSPRCOLLIDE;gosub CHECKSPRCOLLIDE;                ;3,3
        bcta,gt KILLPLAYER_6 ;if > goto KILLPLAYER_6;                 ;3,3

;sprites #0 and #1 (vehicles) have not collided

        bsta,un L0288        ;gosub L0288;                            ;3,3
        loda,r1 $1F6C        ;r1 = *($1F6C); // motherboard RAM       ;4,3

L01CF:
;alternate entry point for this subroutine
        strr,r1 *$020C       ;*(*($020C)) = r1; // ROM operand        ;3,2
                             ;or, *($1F6C) = r1; // mobo RAM
        lodi,r3 $00          ;r3 = $00;                               ;2,2
L01D3:
        lodr,r0 *$020C       ;r0 = *(*($020C)); // ROM operand        ;3,2
                             ;or, r0 = *($1F6C); // mobo RAM
        addz    r3           ;r0 += r3;                               ;2,1
        addz    r3           ;r0 += r3;                               ;2,1
        strz    r2           ;r2 = r0;                                ;2,1
        loda,r0 $1F53,r2     ;r0 = *($1F53 + r2);                     ;4,3
        strz    r1           ;r1 = r0;                                ;2,1
        andi,r1 $F0          ;r1 &= %11110000;                        ;2,2
        bcfa,eq L0243        ;if != goto L0243;                       ;3,3
        strz    r2           ;r2 = r0;                                ;2,1
        lodr,r1 *$020C       ;r1 = *(*($020C)); // ROM operand        ;3,2
                             ;or, r1 = *($1F6C); // mobo RAM
        loda,r0 P1VANGLE,r1  ;r0 = *(&P1VANGLE + r1);                 ;4,3
        brnr,r3 L0201        ;if (r3 != 0) goto L0201;                ;3,2
        comi,r0 $08          ;compare r0 against $08;                 ;2,2
        bctr,gt L01FB        ;if > goto L01FB;                        ;3,2
L01ED:
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        addz    r3           ;r0 += r3;                               ;2,1
        strz    r1           ;r1 = r0;                                ;2,1
        loda,r0 $1F0A,r1     ;r0 = *($1F0A + r1);                     ;4,3
        addz    r2           ;r0 += r2;                               ;2,1
        stra,r0 $1F0A,r1     ;*($1F0A + r1) = r0;                     ;4,3
        bctr,un L020B        ;goto L020B;                             ;3,2
;
L01FB:
        eori,r2 $FF          ;r2 ^= %11111111;                        ;2,2
        addi,r2 $01          ;r2++;                                   ;2,2
        bctr,un L01ED        ;goto L01ED;                             ;3,2
;
L0201:
;r0 is passed as an argument to this code section

;if (r0 < 4 || r0 > 12) goto L01FB; else goto L01ED;
        comi,r0 $0C          ;compare r0 against $0C;                 ;2,2
        bctr,gt L01FB        ;if > goto L01FB;                        ;3,2
        comi,r0 $04          ;compare r0 against $04;                 ;2,2
        bctr,lt L01FB        ;if < goto L01FB;                        ;3,2
        bctr,un L01ED        ;goto L01ED;                             ;3,2

L020B:

;r0 = *(&P1VANGLE + *($1F6C)) & 7;
;if (*($1F6C) > 1) goto L0238;
;if (r3 == 0)
;{   r0 += 8;
;}
        loda,r1 $1F6C        ;r1 = *($1F6C); // motherboard RAM       ;4,3
        loda,r0 P1VANGLE,r1  ;r0 = *(&P1VANGLE + r1);                 ;4,3
        andi,r0 $07          ;r0 &= %00000111;                        ;2,2
        comi,r1 $01          ;compare r1 against $01;                 ;2,2
        bctr,gt L0238        ;if > goto L0238;                        ;3,2
        brnr,r3 L021B        ;if (r3 != 0) goto L021B;                ;3,2
        addi,r0 $08          ;r0 += $08;                              ;2,2

L021B:

;r0 = *($602 + r0); // ROM data
;if (r0 != 0)
;{   r2 = r0;
;    gosub L027C;
;    r0 += r2;
;    r2 = r0;
;    gosub CALCR0;
;    r0 += r2;
;    r0 = *($610 + r0);
;}
        loda,r0 $0602,r0     ;r0 = *($0602 + r0);                     ;4,3
        bctr,eq L022D        ;if == goto L022D;                       ;3,2
        strz    r2           ;r2 = r0;                                ;2,1
        bsta,un L027C        ;gosub L027C;                            ;3,3
        addz    r2           ;r0 += r2;                               ;2,1
        strz    r2           ;r2 = r0;                                ;2,1
        bsta,un CALCR0       ;gosub CALCR0;                           ;3,3
        addz    r2           ;r0 += r2;                               ;2,1
        loda,r0 $0610,r0     ;r0 = *($0610 + r0); // ROM data         ;4,3
L022D:

;r1 += (r3 * 2);
        strz    r2           ;r2 = r0;                                ;2,1
        lodz    r1           ;r0 = r1;                                ;2,1
        addz    r3           ;r0 += r3;                               ;2,1
        addz    r3           ;r0 += r3;                               ;2,1
        strz    r1           ;r1 = r0;                                ;2,1
        lodz    r2           ;r0 = r2;                                ;2,1

        stra,r0 $1F53,r1     ;*($1F53 + r1) = r0;                     ;4,3
        bctr,un L0248        ;goto L0248;                             ;3,2
;
L0238:

;r0 = *($5E8 + r0) + (*($5E8 + r0) / 2);
        loda,r0 $05E8,r0     ;r0 = *($05E8 + r0);                     ;4,3
        rrr,r3               ;r3 >>= 1;                               ;2,1
        addz    r3           ;r0 += r3;                               ;2,1
        loda,r0 $05F8,r0     ;r0 = *($05F8 + r0);                     ;4,3
        rrl,r3               ;r3 <<= 1;                               ;2,1

        bctr,un L022D        ;goto L022D;                             ;3,2
;
L0243:
        subi,r0 $10          ;r0 -= $10;                              ;2,2
        stra,r0 $1F53,r2     ;*($1F53 + r2) = r0;                     ;4,3
L0248:
        brnr,r3 L024F        ;if (r3 != 0) goto L024F;                ;3,2
        lodi,r3 $02          ;r3 = $02;                               ;2,2
        bcta,un L01D3        ;goto L01D3;                             ;3,3
;
L024F:
;r1 = *($5E4 + *($1F6C));
;r2 = 0;
;do
;{   if (*($278 + r3) < *($1F0A + r1))
;    {   *($1F0A + r1) = *($278 + r3);
;        r2 = *($278 + r3);
;    } elif (*($279 + r3) > *($1F0A + r1))
;    {   *($1F0A + r1) = *($279 + r3);
;        r2 = *($279 + r3);
;    }
;    r1 += 2;
;    r3 -= 2;
;} while (r3 == 0);
;r1 = *($1F6C);
;r0 = r2;
;return;
        lodr,r1 *$026E       ;r1 = *(*($026E)); // ROM operand        ;3,2
                             ;or, r1 = *($1F6C); // mobo RAM
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        strz    r1           ;r1 = r0;                                ;2,1
        lodi,r2 $00          ;r2 = $00;                               ;2,2
L0257:
        loda,r0 $0278,r3     ;r0 = *($0278 + r3); // ROM data         ;4,3
        coma,r0 $1F0A,r1     ;compare r0 against *($1F0A + r1);       ;4,3
        bctr,lt L0272        ;if < goto L0272;                        ;3,2
        loda,r0 $0279,r3     ;r0 = *($0279 + r3); // ROM data         ;4,3
        coma,r0 $1F0A,r1     ;compare r0 against *($1F0A + r1);       ;4,3
        bctr,gt L0272        ;if > goto L0272;                        ;3,2
L0267:
        addi,r1 $02          ;r1 += $02;                              ;2,2
        subi,r3 $02          ;r3 -= $02;                              ;2,2
        bctr,eq L0257        ;if == goto L0257;                       ;3,2
        loda,r1 $1F6C        ;r1 = *($1F6C); // motherboard RAM       ;4,3
        lodz    r2           ;r0 = r2;                                ;2,1
        retc,un              ;return;                                 ;3,1
L0272:
        stra,r0 $1F0A,r1     ;*($1F0A + r1) = r0;                     ;4,3
        strz    r2           ;r2 = r0;                                ;2,1
        bctr,un L0267        ;goto L0267;                             ;3,2
;Data---------------------------------------------------------------------
X0278:
        db      $F9
X0279:
        db      $06, $AE, $0C
;
L027C:
        loda,r0 $1F62        ;r0 = *($1F62); // motherboard RAM       ;4,3
L027F:
        brnr,r1 L0285        ;if (r1 != 0) goto L0285;                ;3,2
        rrr,r0               ;r0 >>= 1;                               ;2,1
        rrr,r0               ;r0 >>= 1;                               ;2,1
        rrr,r0               ;r0 >>= 1;                               ;2,1
        rrr,r0               ;r0 >>= 1;                               ;2,1
L0285:
        andi,r0 $0F          ;r0 &= %00001111;                        ;2,2
        retc,un              ;return;                                 ;3,1
;
L0288:
        loda,r0 $1F5B,r1     ;r0 = *($1F5B + r1);                     ;4,3
        bctr,eq L0293        ;if == goto L0293;                       ;3,2
        subi,r0 $01          ;r0--;                                   ;2,2
L028F:
        stra,r0 $1F5B,r1     ;*($1F5B + r1) = r0;                     ;4,3
        retc,un              ;return;                                 ;3,1
;
L0293:
        bstr,un L027C        ;gosub L027C;                            ;3,2
        strz    r2           ;r2 = r0;                                ;2,1
        bsta,un CALCR0       ;gosub CALCR0;                           ;3,3
        addz    r2           ;r0 += r2;                               ;2,1
        loda,r0 $0623,r0     ;r0 = *($0623 + r0);                     ;4,3
        bstr,un L028F        ;gosub L028F;                            ;3,2
        loda,r0 $1F61        ;r0 = *($1F61); // motherboard RAM       ;4,3
        bstr,un L027F        ;gosub L027F;                            ;3,2
        subi,r0 $01          ;r0--;                                   ;2,2
        adda,r0 P1VANGLE,r1  ;r0 += *(&P1VANGLE + r1);                ;4,3
        andi,r0 $0F          ;r0 &= %00001111;                        ;2,2
        bcta,un L02DC        ;goto L02DC;                             ;3,3
;Subroutine VEHICLECOLOUR-------------------------------------------------
VEHICLECOLOUR:                                                       ;$2AE
;r1 is passed as an argument: it is which player (0 or 1).
;r3 is passed as an argument: it is which colour.
        brnr,r1 VEHICLECOLOUR_1
                             ;if (r1 != 0) goto VEHICLECOLOUR_1;      ;3,2

;player 1 (sprite #0)
        lodi,r0 $07          ;r0 = $07; // SPR01COLOURS bits to preserve
                                                                      ;2,2
        andi,r3 $38          ;r3 &= %00111000;                        ;2,2
        bctr,un VEHICLECOLOUR_2
                             ;goto VEHICLECOLOUR_2;                   ;3,2

VEHICLECOLOUR_1:                                                     ;$2B6
;player 2 (sprite #1)
        lodi,r0 $38          ;r0 = $38; // SPR01COLOURS bits to preserve
                                                                      ;2,2
        andi,r3 $07          ;r3 &= %00000111;                        ;2,2

VEHICLECOLOUR_2:                                                     ;$2BA

;VEHICLECOLOURS = SPR01COLOURS = (r0 & VEHICLECOLOURS) ^ r3;
        anda,r0 VEHICLECOLOURS
                             ;r0 &= VEHICLECOLOURS; // motherboard RAM;4,3
        eorz    r3           ;r0 ^= r3;                               ;2,1
        strr,r0 *$02BB       ;*(*($02BB)) = r0; // ROM operand        ;3,2
                             ;or, VEHICLECOLOURS = r0; // mobo RAM
        stra,r0 SPR01COLOURS ;SPR01COLOURS = r0; // hardware registers;4,3

        retc,un              ;return;                                 ;3,1
;Subroutines CHECKBGCOLLIDE and CHECKSPRCOLLIDE---------------------------
;r0 is passed as an argument.
;It always has just one bit set (derived from $5D4..$5DB).
;The return value is the Condition Code.
;Although r0 is modified during execution, it is not used as a return code
; by any of the callers.
;r1 and r2 are unused.
;r3 is scratch.

CHECKBGCOLLIDE:                                                      ;$2C4
        lodi,r3 $00          ;r3 = $00;                               ;2,2
        bctr,un L02CA        ;goto L02CA;                             ;3,2

CHECKSPRCOLLIDE:             ;alternate entry point                  ;$2C8
        lodi,r3 $01          ;r3 = $01;                               ;2,2

L02CA:
;inhibit interrupts
        ppsu    $20          ;PSU |= ..I.....;                        ;3,2

;r3 is always either 0 or 1.
;if the bit we are interested in is clear, return eq.
;if the bit we are interested in is set, clear it and return gt.
;thus, the bit will always be clear after this routine.

;if (entry point was CHECKBGCOLLIDE)
;{   if (BGCOLLIDECOPY & r0) == 0)
;    {   rete(eq);
;    } else
;    {   BGCOLLIDECOPY = (BGCOLLIDECOPY & r0) ^ BGCOLLIDECOPY;
;        or, BGCOLLIDECOPY &= ~r0;
;        rete(gt);
;}   }
;else
;{   assert(entry point was CHECKSPRCOLLIDE);
;    if (SPRCOLLIDECOPY & r0) == 0)
;    {   rete(eq);
;    } else
;    {   SPRCOLLIDECOPY = (SPRCOLLIDECOPY & r0) ^ SPRCOLLIDECOPY;
;        or, SPRCOLLIDECOPY &= ~r0;
;        rete(gt);
;}   }
;or,
;if (*($1F4E + r3) & r0 == 0)
;{   rete(eq);
;} else
;{   *($1F4E + r3) = (*($1F4E + r3) & r0) ^ *($1F4E + r3);
;    rete(gt);
;}
        anda,r0 $1F4E,r3     ;r0 &= *($1F4E + r3);                    ;4,3
        rete,eq              ;if == then { PSU &= ~PSU_II; return; }  ;3,1
        eora,r0 $1F4E,r3     ;r0 ^= *($1F4E + r3);                    ;4,3
        stra,r0 $1F4E,r3     ;*($1F4E + r3) = r0;                     ;4,3
        lodi,r3 $01          ;r3 = $01;                               ;2,2
        rete,un              ;PSU &= ~PSU_II; return;                 ;3,1
;Data for Subroutine L02DC------------------------------------------------
;$2D9:
        db      $0A, $3C, $6E
;Subroutine L02DC---------------------------------------------------------
L02DC:
;r0 and r1 are passed as arguments

;*(&P1VANGLE + r1) = r3 = r0;
        stra,r0 P1VANGLE,r1  ;*(&P1VANGLE + r1) = r0;                 ;4,3
        strz    r3           ;r3 = r0;                                ;2,1

;r2 = *($5F0 + (r0 & %00000111));
        andi,r0 $07          ;r0 &= %00000111;                        ;2,2
        loda,r0 $05F0,r0     ;r0 = *($05F0 + r0);                     ;4,3
        strz    r2           ;r2 = r0;                                ;2,1

;r1 = *($5E4 + r1);
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r1);                     ;4,3
        strz    r1           ;r1 = r0;                                ;2,1

        bsta,un CALCR0       ;gosub CALCR0;                           ;3,3

;r0 = *($2D8 + r0) + r2;
        loda,r0 $02D8,r0     ;r0 = *($02D8 + r0);                     ;4,3
        addz    r2           ;r0 += r2;                               ;2,1
        strz    r2           ;r2 = r0;                                ;2,1

;if (r3 >= 5 && r3 <= 11)
;{   do
;    {   r2--;
;        r1++;
;        *($1EFF + r1) = *($630 + r2);
;        test bits %00001010 of r1;
;    } while (<);
;} else
;{   do
;    {   r2++;
;        r1++;
;        *($1EFF + r1) = *($625 + r2);
;        test bits %00001010 of r1;
;    } while (<);
;}
        comi,r3 $05          ;compare r3 against $05;                 ;2,2
        bctr,lt L0306        ;if < goto L0306;                        ;3,2
        comi,r3 $0B          ;compare r3 against $0B;                 ;2,2
        bctr,gt L0306        ;if > goto L0306;                        ;3,2
L02FA:
        loda,r0 $0630,r2-    ;r0 = *($0630 + --r2);                   ;4,3
        stra,r0 $1EFF,r1+    ;*($1EFF + ++r1) = r0;                   ;4,3
        tmi,r1  $0A          ;test bits %00001010 of r1;              ;3,2
        bctr,lt L02FA        ;if < goto L02FA;                        ;3,2
        bctr,un L0310        ;goto L0310;                             ;3,2
L0306:
        loda,r0 $0625,r2+    ;r0 = *($0625 + ++r2);                   ;4,3
        stra,r0 $1EFF,r1+    ;*($1EFF + ++r1) = r0;                   ;4,3
        tmi,r1  $0A          ;test bits %00001010 of r1;              ;3,2
        bctr,lt L0306        ;if < goto L0306;                        ;3,2

L0310:
        comi,r3 $09          ;compare r3 against $09;                 ;2,2
        retc,lt              ;if < return;                            ;3,1
L0313:
        loda,r0 $1EFF,r1     ;r0 = *($1EFF + r1);                     ;4,3
        strz    r3           ;r3 = r0;                                ;2,1
        lodi,r2 $04          ;r2 = $04;                               ;2,2
L0319:
        anda,r0 $0333,r2     ;r0 &= *($0333 + r2);                    ;4,3
        bctr,eq L0328        ;if == goto L0328;                       ;3,2
        suba,r0 $0333,r2     ;r0 -= *($0333 + r2);                    ;4,3
        bctr,eq L0328        ;if == goto L0328;                       ;3,2
        loda,r0 $0333,r2     ;r0 = *($0333 + r2);                     ;4,3
        eorz    r3           ;r0 ^= r3;                               ;2,1
        strz    r3           ;r3 = r0;                                ;2,1
L0328:
        lodz    r3           ;r0 = r3;                                ;2,1
        bdrr,r2 L0319        ;if (--r2 != 0) goto L0319;              ;3,2
        stra,r0 $1F00,r1-    ;*($1F00 + --r1) = r0;                   ;4,3
        lodz    r1           ;r0 = r1;                                ;2,1
        andi,r0 $0F          ;r0 &= %00001111;                        ;2,2
        bcfr,eq L0313        ;if != goto L0313;                       ;3,2
X0333:
        retc,un              ;return;                                 ;3,1
;(More) Data for Subroutine L02DC-----------------------------------------
        db      $81, $42, $24, $18
;Subroutine CALCR0--------------------------------------------------------
CALCR0:                                                              ;$338
;this takes no arguments
;result is in r0

;r0 = (*($7AC + DERIVED) << 2) & %00000011;
        loda,r0 DERIVED      ;r0 = DERIVED; // motherboard RAM        ;4,3
        loda,r0 $07AC,r0     ;r0 = *($07AC + r0);                     ;4,3
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        andi,r0 $03          ;r0 &= %00000011;                        ;2,2

        retc,un              ;return;                                 ;3,1
;Subroutine KILLBULLETS---------------------------------------------------
KILLBULLETS:                                                         ;$343
;Effectively runs KILLBULLET twice, once for each player. The value of r1
; passed to KILLBULLETS is unimportant.

        bstr,un KILLBULLET   ;gosub KILLBULLET;                       ;3,2
        eori,r1 $01          ;r1 ^= %00000001;                        ;2,2

KILLBULLET:                                                          ;$347
;this is an alternate entry point.
;r1 is an argument.
;r0 and r3 are scratch?
;r2 is unused?

;SPRITE2AX or SPRITE3AX = 0;
;SPRITE2AY or SPRITE3AY = 0;
;BULLET1DIST or BULLET2DIST = 0;
        loda,r0 $05E6,r1     ;r0 = *($05E6 + r1);                     ;4,3
        strz    r3           ;r3 = r0;                                ;2,1
        eorz    r0           ;r0 = 0;                                 ;2,1
        stra,r0 $1F0A,r3     ;*($1F0A + r3) = r0 [0];                 ;4,3
        stra,r0 $1F0C,r3     ;*($1F0C + r3) = r0 [0];                 ;4,3
        stra,r0 BULLET1DIST,r1
                             ;*(&BULLET1DIST + r1) = r0 [0];          ;4,3

;if (*($7AE + DERIVED) & $80) // if night
;{   r3 = (*($7AD + DERIVED) & 7) * 9;
;    // gets %00000rgb from ROM data...
;    // ...and puts %00rgbrgb into r3
;    gosub L02AE(r1, r3);
;}
        lodr,r3 *$0339       ;r3 = *(*($0339)); // ROM operand        ;3,2
                             ;or, r3 = DERIVED; // mobo RAM
        loda,r0 $07AE,r3     ;r0 = *($07AE + r3);                     ;4,3
        bcfr,lt L036A        ;if >= goto L036A;                       ;3,2
        loda,r0 $07AD,r3     ;r0 = *($07AD + r3);                     ;4,3
        andi,r0 $07          ;r0 &= %00000111;                        ;2,2
        strz    r3           ;r3 = r0;                                ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        addz    r3           ;r0 += r3;                               ;2,1
        strz    r3           ;r3 = r0;                                ;2,1
        bsta,un VEHICLECOLOUR;gosub VEHICLECOLOUR(r1, r3);            ;3,3

L036A:
        loda,r0 $05D6,r1     ;r0 = *($05D6 + r1);                     ;4,3
        lodi,r3 $02          ;r3 = $02;                               ;2,2
        bcta,un L02CA        ;goto L02CA;                             ;3,3
;Code Section KILLPLAYER--------------------------------------------------
KILLPLAYER:                                                          ;$372

;PnSCORE = BCD(PnSCORE + 1);
        loda,r0 P1SCORE,r1   ;r0 = *(&P1SCORE + r1);                  ;4,3
        addi,r0 $67          ;r0 += $67;                              ;2,2
        dar,r0               ;r0 = BCD(r0);                           ;3,1
        stra,r0 P1SCORE,r1   ;*(&P1SCORE + r1) = r0;                  ;4,3

        loda,r0 $03C6,r1     ;r0 = *($03C6 + r1); // ROM data         ;4,3
        strz    r2           ;r2 = r0;                                ;2,1
KILLPLAYER_1:                                                        ;$37F
        bstr,un KILLBULLETS  ;gosub KILLBULLETS;                      ;3,2

        lodi,r3 $02          ;r3 = $02; // loop iterator (loop twice) ;2,2
KILLPLAYER_2:                                                        ;$383
        loda,r0 $1F1D,r3     ;r0 = *($1F1D + r3);                     ;4,3
        stra,r0 $1FC7,r3     ;*($1FC7 + r3) = r0;                     ;4,3
        bdrr,r3 KILLPLAYER_2 ;if (--r3 != 0) goto KILLPLAYER_2;       ;3,2
;end of loop

        lodi,r3 $10          ;r3 = $10;                               ;2,2
        ppsu    $20          ;PSU |= ..I.....; // inhibit interrupts  ;3,2
        bsta,un MAKENOISE    ;gosub MAKENOISE;                        ;3,3 038F
        lodi,r0 $FE          ;r0 = $FE;                               ;2,2
        bsta,un L03DF        ;gosub L03DF;                            ;3,3
        strz    r3           ;r3 = r0;                                ;2,1
        bstr,un *$0390       ;gosub *($0390); // ROM operand          ;3,2
                             ;or, gosub MAKENOISE; // ROM code

        lodi,r0 $03          ;r0 = $03; // loop iterator              ;2,2
KILLPLAYER_3:                                                        ;$39C
        stra,r0 $1F6C        ;*($1F6C) = r0; // motherboard RAM       ;4,3
        lodz    r2           ;r0 = r2;                                ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        bstr,un L03D2        ;gosub L03D2;                            ;3,2
        lodz    r2           ;r0 = r2;                                ;2,1
        bstr,un L03D2        ;gosub L03D2;                            ;3,2
        lodz    r2           ;r0 = r2;                                ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        addz    r2           ;r0 += r2;                               ;2,1
        bstr,un L03D2        ;gosub L03D2;                            ;3,2
        lodr,r0 *$039D       ;r0 = *(*($039D)); // ROM operand        ;3,2
                             ;or, r0 = *($1F6C); // mobo RAM
        bdrr,r0 KILLPLAYER_3 ;if (--r0 != 0) goto KILLPLAYER_3;       ;3,2
;end of loop

        strr,r0 *$03D3       ;*(*($03D3)) = r0 [0]; // ROM operand    ;3,2
                             ;or, SIZES = r0 [%00,00,00,00]; // h/ware regs

        lodi,r1 $02          ;r1 = $02; // loop iterator              ;2,2
KILLPLAYER_4:                                                        ;$3B3
        loda,r0 $1F1D,r1     ;r0 = *($1F1D + r1);                     ;4,3
        comi,r0 $15          ;compare r0 against $15;                 ;2,2
        bcfr,eq KILLPLAYER_5 ;if != goto KILLPLAYER_5;                ;3,2
                             ;or, if (r0 != 21) continue;
        loda,r2 OPTION       ;r2 = OPTION; // motherboard RAM         ;4,3
        andi,r2 $7F          ;r2 &= %01111111;                        ;2,2
        strr,r2 *$03BB       ;*(*($03BB)) = r2; // ROM operand        ;3,2
                             ;or, OPTION = r2; // mobo RAM
KILLPLAYER_5:                                                        ;$3C1
        bdrr,r1 KILLPLAYER_4 ;if (--r1 != 0) goto KILLPLAYER_4;       ;3,2
;end of loop

        bcta,un L003B        ;goto L003B;                             ;3,3
;Data for Code Section KILLPLAYER-----------------------------------------
X03C6:
        db      $04, $01
;Code Section KILLPLAYER_6------------------------------------------------
KILLPLAYER_6:                                                        ;$3C8
;alternate entry point for code section KILLPLAYER

        lodi,r3 $1B          ;r3 = $1B;                               ;2,2
        stra,r3 SPR01COLOURS ;SPR01COLOURS = r3 [%00,011,011]; // h/w regs
                                                                      ;4,3
        lodi,r2 $05          ;r2 = $05;                               ;2,2
        bcta,un KILLPLAYER_1 ;goto KILLPLAYER_1;                      ;3,3
;Subroutine L03D2---------------------------------------------------------
L03D2:
;r0 is passed as an argument, it is the desired contents of SIZES
        stra,r0 SIZES        ;SIZES = r0; // hardware registers       ;4,3

;r3 = VEHICLECOLOURS + %00,001,001; // mobo RAM
        loda,r3 VEHICLECOLOURS
                             ;r3 = VEHICLECOLOURS; // motherboard RAM ;4,3
        addi,r3 $09          ;r3 += $09;                              ;2,2

        bsta,un VEHICLECOLOUR;gosub VEHICLECOLOUR(r1, r3);            ;3,3
        lodi,r0 $FB          ;r0 = $FB;                               ;2,2
L03DF:
;alternate entry point
;r0 is $E7, $FB or $FD depending on how long a delay is desired
        stra,r0 MONOTONIC    ;MONOTONIC = r0; // motherboard RAM      ;4,3
        cpsu    $20          ;PSU &= SFi!!!!!; // enable interrupts   ;3,2
L03E4:

;do
;{   r0 = MONOTONIC; // motherboard RAM
;} while (r0 & %10000000);
;only an interrupt can get us out of this loop
        lodr,r0 *$03E0       ;r0 = *(*($03E0)); // ROM operand        ;3,2
                             ;or, r0 = MONOTONIC; // motherboard RAM
        bctr,lt L03E4        ;if < goto L03E4;                        ;3,2

        retc,un              ;return;                                 ;3,1
;Subroutine CHECKTWINS----------------------------------------------------
CHECKTWINS:                                                          ;$3E9
;This subroutine is only called from interrupt code.
;Its return code is the Condition Code register (gt or lt).
;lt means twins (planes).
;gt means singles (tanks or planes).
;Although r0 is also set, the callers do not use this.

;if this is a tank game, return(gt);
;if (*($7AC + DERIVED) > then return(gt);
;or, if (!(*($7AC + DERIVED) & %10000000)) then return(gt);
        loda,r0 DERIVED      ;r0 = DERIVED; // motherboard RAM        ;4,3
        loda,r0 $07AC,r0     ;r0 = *($07AC + r0);                     ;4,3
        retc,gt              ;if > return;                            ;3,1

;it is a plane game
;set CC according to *($7AD + derived);
;r0 = (*($7AD + DERIVED)); // useless, except to adjust CC!
        lodr,r0 *$03EA       ;r0 = *(*($03EA)); // ROM operand        ;3,2
                             ;or, r0 = DERIVED;
        loda,r0 $07AD,r0     ;r0 = *($07AD + r0);                     ;4,3

;if it is a twin plane game, return(lt); else return(gt);
;return(lt/gt);
        retc,un              ;return;                                 ;3,1
;Interrupt Handler--------------------------------------------------------
L03F6:
        stra,r0 PRESERVER0   ;PRESERVER0 = r0; // motherboard RAM     ;4,3
        ppsl    $10          ;PSL |= ...R....; // use alt. reg. bank  ;3,2
        spsl                 ;r0 = PSL;                               ;2,1
        stra,r0 PRESERVEPSL  ;PRESERVEPSL = r0 [PSL]; // mobo RAM     ;4,3

;SPRCOLLIDECOPY |= SPRITECOLLIDE; // motherboard RAM
;BGCOLLIDECOPY  |= BGCOLLIDE;     // motherboard RAM
;r6 = BGCOLLIDE; // but doesn't read it directly, just a copy as it's read-once
        lodi,r1 $02          ;r4 = $02; // loop iterator              ;2,2
L0401:
        loda,r0 $1FC9,r1     ;r0 = *($1FC9 + r4);                     ;4,3
        strz    r3           ;r6 = r0;                                ;2,1
        iora,r0 $1F4D,r1     ;r0 |= *($1F4D + r4);                    ;4,3
        stra,r0 $1F4D,r1     ;*($1F4D + r4) = r0;                     ;4,3
        bdrr,r1 L0401        ;if (--r4 != 0) goto L0401;              ;3,2
;end of loop

;start of loop
;r4 is the loop iterator
;it goes 0..3 (for which sprite we are interested in)
L040D:
;extract "display complete" bits
        andi,r3 $0F          ;r6 &= %00001111;                        ;2,2
        bctr,eq L0443        ;if == goto L0443;                       ;3,2

;at least one sprite is complete
        loda,r0 $05D8,r1     ;r0 = *($05D8 + r4 [0..3]);              ;4,3
;when r4 is 0..3, r0 = 8 >> r4;
;when r4 is    4, r0 = %0000,1110;
        andz    r3           ;r0 &= r6;                               ;2,1

;check sprite r4
        bctr,eq L0441        ;if == goto L0441;                       ;3,2

;sprite r4 is complete
;clear bit in r6 to mark that we have handled this sprite
        eorz    r3           ;r0 ^= r6;                               ;2,1
        strz    r3           ;r6 = r0;                                ;2,1

;*($1F0B + *($5E4 + r4) = *($1F0A + *($5E4 + r4));
;or, SPRITEnBX = SPRITEnAX;
;also, r5 = $00, $10, $20 or $40 for sprite #0, #1, #2 or #3 respectively
        loda,r0 $05E4,r1     ;r0 = *($05E4 + r4);                     ;4,3
        strz    r2           ;r5 = r0;                                ;2,1
        loda,r0 $1F0A,r2     ;r0 = *($1F0A + r5);                     ;4,3
        stra,r0 $1F0B,r2     ;*($1F0B + r5) = r0;                     ;4,3

        bsta,un CHECKTWINS   ;gosub CHECKTWINS;                       ;3,3
        bctr,gt L043C        ;if > goto L043C;                        ;3,2

;this is a twin game

;if (SPRITEnBY == 17)
;{   BGCOLLIDECOPY ^= 8 >> r4; // flip the "display complete" bit for this sprite
;    SPRITEnBY = $FD;
;} else
;{   SPRITEnBY = $FE; // don't reuse this sprite again
;}
        lodi,r0 $11          ;r0 = $11;                               ;2,2
        coma,r0 $1F0D,r2     ;compare r0 [17] against *($1F0D + r5);  ;4,3@R
        bcfr,eq L043C        ;if != goto L043C;                       ;3,2
;SPRITEnBY == 17
        loda,r0 BGCOLLIDECOPY;r0 = BGCOLLIDECOPY; // motherboard RAM  ;4,3
        eora,r0 $05D8,r1     ;r0 ^= *($05D8 + r4); // ROM data        ;4,3
        stra,r0 BGCOLLIDECOPY;BGCOLLIDECOPY = r0; // motherboard RAM  ;4,3
        lodi,r0 $FD          ;r0 = $FD;                               ;2,2
        bctr,un L043E        ;goto L043E;                             ;3,2
L043C:
;SPRITEnBY != 17
        lodi,r0 $FE          ;r0 = $FE;                               ;2,2
L043E:
        stra,r0 $1F0D,r2     ;*(&SPRITE0BY + r5) = r0 [$FD or $FE];   ;4,3@W
L0441:
        birr,r1 L040D        ;if (++r4 != 0) goto L040D;              ;3,2
;end of loop

L0443:
        tpsu    $80          ;test bits S....... of PSU;              ;3,2
        bcta,lt INTERRUPT_END;if < goto INTERRUPT_END;                ;3,3

;we are in vertical blank

;PSU ^= %01000000; // flip Flag bit
        spsu                 ;r0 = PSU;                               ;2,1
        eori,r0 $40          ;r0 ^= %01000000;                        ;2,2
        lpsu                 ;PSU = r0;                               ;2,1

        lodi,r1 $02          ;r4 = $02;                               ;2,2
L044E:
        eorz    r0           ;r0 = 0;                                 ;2,1
        strz    r2           ;r5 = r0;                                ;2,1
        strz    r3           ;r6 = r0;                                ;2,1
        loda,r0 $1FCB,r1     ;r0 = *($1FCB + r4);                     ;4,3
        tpsu    $40          ;test bit .F...... of PSU; // Flag bit   ;3,2
        bcfr,eq L047D        ;if != goto L047D;                       ;3,2
        comi,r0 $30          ;compare r0 against $30;                 ;2,2
        bctr,lt L0464        ;if < goto L0464;                        ;3,2
        lodi,r3 $01          ;r6 = $01;                               ;2,2
        comi,r0 $96          ;compare r0 against $96;                 ;2,2
        bctr,lt L0464        ;if < goto L0464;                        ;3,2
        addi,r3 $01          ;r6++;                                   ;2,2
L0464:
        loda,r0 $1F61,r2     ;r0 = *($1F61 + r5);                     ;4,3
        comi,r1 $02          ;compare r4 against $02;                 ;2,2
        bctr,eq L0479        ;if == goto L0479;                       ;3,2
        rrr,r3               ;r6 >>= 1;                               ;2,1
        rrr,r3               ;r6 >>= 1;                               ;2,1
        rrr,r3               ;r6 >>= 1;                               ;2,1
        rrr,r3               ;r6 >>= 1;                               ;2,1
        andi,r0 $0F          ;r0 &= %00001111;                        ;2,2
L0471:
        addz    r3           ;r0 += r6;                               ;2,1
        stra,r0 $1F61,r2     ;*($1F61 + r5) = r0;                     ;4,3
        bdrr,r1 L044E        ;if (--r4 != 0) goto L044E;              ;3,2
        bctr,un L048E        ;goto L048E;                             ;3,2
;
L0479:
        andi,r0 $F0          ;r0 &= %11110000;                        ;2,2
        bctr,un L0471        ;goto L0471;                             ;3,2
;
L047D:
        lodi,r2 $01          ;r5 = $01;                               ;2,2
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        andi,r0 $07          ;r0 &= %00000111;                        ;2,2
        eori,r0 $FF          ;r0 ^= %11111111;                        ;2,2
        addi,r0 $04          ;r0 += $04;                              ;2,2
        bctr,gt L048B        ;if > goto L048B;                        ;3,2
        eorz    r0           ;r0 = 0;                                 ;2,1
L048B:
        strz    r3           ;r6 = r0;                                ;2,1
        bctr,un L0464        ;goto L0464;                             ;3,2
;
L048E:
        bsta,un CHECKTWINS   ;gosub CHECKTWINS;                       ;3,3
        bctr,gt L04B0        ;if > goto L04B0;                        ;3,2

;this is a twin game

;for (r4 = 4; r4 >= 1; r4--)
;{   if (SPRITEnBY == $FD)
;    {   BGCOLLIDECOPY |= 1 << (r4 - 1);
;    }
;    SPRITEnBY = 17;
;}
;or,
;if (SPRITE3BY == $FD) BGCOLLIDECOPY |= 8; else SPRITE3BY = 17;
;if (SPRITE2BY == $FD) BGCOLLIDECOPY |= 4; else SPRITE2BY = 17;
;if (SPRITE1BY == $FD) BGCOLLIDECOPY |= 2; else SPRITE1BY = 17;
;if (SPRITE0BY == $FD) BGCOLLIDECOPY |= 1; else SPRITE0BY = 17;
        lodi,r3 $01          ;r6 = $01;                               ;2,2
        lodi,r1 $04          ;r4 = $04; // loop iterator              ;2,2
L0497:
        loda,r0 $05E3,r1     ;r0 = *($05E3 + r4);                     ;4,3
        strz    r2           ;r5 = r0;                                ;2,1
        loda,r0 $1F0D,r2     ;r0 = *($1F0D + r5);                     ;4,3@R
        comi,r0 $FD          ;compare r0 against $FD;                 ;2,2
        bcfr,eq L04A8        ;if != goto L04A8;                       ;3,2
        loda,r0 BGCOLLIDECOPY;r0 = BGCOLLIDECOPY; // motherboard RAM  ;4,3
        iorz    r3           ;r0 |= r6;                               ;2,1
        strr,r0 *$04A3       ;*(*($04A3)) = r0; // ROM operand        ;3,2
                             ;or, BGCOLLIDECOPY = r0; // mobo RAM
L04A8:
        lodi,r0 $11          ;r0 = $11;                               ;2,2
        stra,r0 $1F0D,r2     ;*(&SPRITE0BY + r5) = r0 [17];           ;4,3@W
        rrl,r3               ;r6 <<= 1;                               ;2,1
        bdrr,r1 L0497        ;if (--r4 != 0) goto L0497;              ;3,2
;end of loop

L04B0:

;if (MONOTONIC >= $80)
;{   MONOTONIC++;
;    goto L05B5;
;}
        loda,r0 MONOTONIC    ;r0 = MONOTONIC; // motherboard RAM      ;4,3
        bcfr,lt L04BC        ;if >= goto L04BC;                       ;3,2
        addi,r0 $01          ;r0++;                                   ;2,2
        strr,r0 *$04B1       ;*(*($04B1)) = r0; // ROM operand        ;3,2
                             ;or, MONOTONIC = r0; // mobo RAM
        bcta,un L05B5        ;goto L05B5;                             ;3,3
;
L04BC:
        loda,r0 $1F50        ;r0 = *($1F50); // motherboard RAM       ;4,3
        strz    r3           ;r6 = r0;                                ;2,1
        loda,r1 P1MIDDLEKEYS ;r4 = P1MIDDLEKEYS; // hardware registers;4,3
        bctr,lt L04C9        ;if < goto L04C9;                        ;3,2
L04C5:
        andi,r3 $FD          ;r6 &= %11111101;                        ;2,2
        bctr,un L04D3        ;goto L04D3;                             ;3,2
;
L04C9:
        tmi,r3  $02          ;test bits %00000010 of r6;              ;3,2
        bctr,lt L04D1        ;if < goto L04D1;                        ;3,2
        iori,r3 $20          ;r6 |= %00100000;                        ;2,2
        bctr,un L04C5        ;goto L04C5;                             ;3,2
;
L04D1:
        iori,r3 $02          ;r6 |= %00000010;                        ;2,2
L04D3:
        loda,r1 CONSOLE      ;r4 = CONSOLE; // hardware registers     ;4,3
        bctr,lt L04DC        ;if < goto L04DC;                        ;3,2

;SELECT key is not pressed
        andi,r3 $F7          ;r6 &= %11110111;                        ;2,2
        bctr,un L04F6        ;goto L04F6;                             ;3,2
;
L04DC:
;SELECT key is pressed
        tmi,r3  $08          ;test bits %00001000 of r6;              ;3,2
        bctr,lt L04F4        ;if < goto L04F4;                        ;3,2
        cpsl    $10          ;PSL &= !!DrWOMC;                        ;3,2
        lodr,r2 *$0504       ;r5 = *(*($0504)); // ROM operand        ;3,2
                             ;or, r5 = OPTION; // mobo RAM
        andi,r2 $7F          ;r5 &= %01111111;                        ;2,2
        addi,r2 $67          ;r5 += $67;                              ;2,2
        dar,r2               ;r5 = BCD(r5);                           ;3,1
        lodr,r3 *$0509       ;r6 = *(*($0509)); // ROM operand        ;3,2
                             ;or, r6 = DERIVED; // mobo RAM
        addi,r3 $03          ;r6 += $03;                              ;2,2
        comi,r2 $26          ;compare r5 against $26;                 ;2,2
        bcta,gt BOOT         ;if > goto BOOT; // yes, $0000!          ;3,3
        bctr,un L050B        ;goto L050B;                             ;3,2
;
L04F4:
        iori,r3 $08          ;r6 |= %00001000;                        ;2,2
L04F6:
        rrl,r1               ;r4 <<= 1;                               ;2,1
        bctr,lt L04FD        ;if < goto L04FD;                        ;3,2
        andi,r3 $FB          ;r6 &= %11111011;                        ;2,2
        bctr,un L0510        ;goto L0510;                             ;3,2
;
L04FD:
        tmi,r3  $04          ;test bits %00000100 of r6;              ;3,2
        bctr,lt L050E        ;if < goto L050E;                        ;3,2

        cpsl    $10          ;PSL &= !!DrWOMC; // use main reg. bank  ;3,2
        loda,r2 OPTION       ;r2 = OPTION; // motherboard RAM         ;4,3
        iori,r2 $80          ;r2 |= %10000000; // start game          ;2,2
        loda,r3 DERIVED      ;r3 = DERIVED; // motherboard RAM        ;4,3
L050B:
        bcta,un L0009        ;goto L0009;                             ;3,3
;
L050E:
        iori,r3 $04          ;r6 |= %00000100;                        ;2,2
L0510:
        loda,r1 P2MIDDLEKEYS ;r4 = P2MIDDLEKEYS; // hardware registers;4,3
        bctr,lt L0519        ;if < goto L0519;                        ;3,2
L0515:
        andi,r3 $FE          ;r6 &= %11111110;                        ;2,2
        bctr,un L0523        ;goto L0523;                             ;3,2
;
L0519:
        tmi,r3  $01          ;test bits %00000001 of r6;              ;3,2
        bctr,lt L0521        ;if < goto L0521;                        ;3,2
        iori,r3 $10          ;r6 |= %00010000;                        ;2,2
        bctr,un L0515        ;goto L0515;                             ;3,2
;
L0521:
        iori,r3 $01          ;r6 |= %00000001;                        ;2,2
L0523:
        stra,r3 $1F50        ;*($1F50) = r6; // motherboard RAM       ;4,3
        lodi,r1 $00          ;r4 = $00;                               ;2,2
        subz    r3           ;r0 -= r6;                               ;2,1
        bcfr,eq L055D        ;if != goto L055D;                       ;3,2

;decrement IDLE_L (by 8)
        lodr,r0 *$0562       ;r0 = *(*($0562)); // ROM operand        ;3,2
                             ;or, r0 = IDLE_L; // mobo RAM
        subi,r0 $08          ;r0 -= $08;                              ;2,2
        bcfa,eq L0561        ;if != goto L0561;                       ;3,3

;IDLE_L is zero, so decrement IDLE_H (by 1)
        lodr,r1 *$055E       ;r4 = *(*($055E)); // ROM operand        ;3,2
                             ;or, r4 = IDLE_H; // mobo RAM
        bdrr,r1 L055D        ;if (--r4 != 0) goto L055D;              ;3,2

;IDLE_H is zero

;VEHICLECOLOURS ^= %11111111; // flip all bits
;SPR01COLOURS = VEHICLECOLOURS;
        loda,r0 VEHICLECOLOURS
                             ;r0 = *($1F67); // motherboard RAM       ;4,3
        eori,r0 $FF          ;r0 ^= %11111111;                        ;2,2
        strr,r0 *$0537       ;*(*($0537)) = r0; // ROM operand        ;3,2
                             ;or, VEHICLECOLOURS = r0; // mobo RAM
        stra,r0 SPR01COLOURS ;SPR01COLOURS = r0; // hardware registers;4,3

;r0 = *($7AD + DERIVED);
        loda,r0 DERIVED      ;r0 = DERIVED; // motherboard RAM        ;4,3
        loda,r0 $07AD,r0     ;r0 = *($07AD + r0);                     ;4,3

;P1VANGLE ^= %11111111;
        loda,r1 P1VANGLE     ;r4 = P1VANGLE; // motherboard RAM       ;4,3
        eori,r1 $FF          ;r4 ^= %11111111;                        ;2,2
        strr,r1 *$0547       ;*(*($0547)) = r4; // ROM operand        ;3,2
                             ;or, P1VANGLE = r4; // mobo RAM

        bcfr,lt L0551        ;if >= goto L0551;                       ;3,2
        eori,r0 $F7          ;r0 ^= %11110111;                        ;2,2
L0551:
        stra,r0 BGCOLOUR     ;BGCOLOUR = r0; // hardware registers    ;4,3

;OPTION &= %01111111;
        loda,r2 OPTION       ;r5 = OPTION; // motherboard RAM         ;4,3
        andi,r2 $7F          ;r5 &= %01111111; // stop game           ;2,2
        strr,r2 *$0555       ;*(*($0555)) = r5; // ROM operand        ;3,2
                             ;or, OPTION = r5; // motherboard RAM

        lodi,r1 $02          ;r4 = $02;                               ;2,2
L055D:
        stra,r1 IDLE_H       ;IDLE_H = r4; // motherboard RAM         ;4,3
        eorz    r0           ;r0 = 0;                                 ;2,1
L0561:
        stra,r0 IDLE_L       ;IDLE_L = r0; // motherboard RAM         ;4,3
        eorz    r0           ;r0 = 0;                                 ;2,1
        strz    r1           ;r4 = r0;                                ;2,1
        strz    r3           ;r6 = r0;                                ;2,1
        lodr,r2 *$0555       ;r5 = *(*($0555)); // ROM operand        ;3,2
                             ;or, r5 = OPTION; // mobo RAM
        bcfr,lt L0578        ;if >= goto L0578;                       ;3,2

;if (*($1F69) != 0)
;{   *($1F69)--;
;    r0 = 3;
;    r6 = 4;
;    goto L05B0;
;}
        loda,r0 $1F69        ;r0 = *($1F69); // motherboard RAM       ;4,3
        bctr,eq L057A        ;if == goto L057A;                       ;3,2
        subi,r0 $01          ;r0--;                                   ;2,2
        strr,r0 *$056C       ;*(*($056C)) = r0; // ROM operand        ;3,2
                             ;or, *($1F69) = r0; // mobo RAM

        lodi,r0 $03          ;r0 = $03;                               ;2,2
L0576:
        lodi,r3 $04          ;r6 = $04;                               ;2,2
L0578:
        bctr,un L05B0        ;goto L05B0;                             ;3,2
;
L057A:
        loda,r0 BULLET1DIST  ;r0 = BULLET1DIST; // motherboard RAM    ;4,3
        loda,r2 BULLET2DIST  ;r5 = BULLET2DIST; // motherboard RAM    ;4,3
        comz    r2           ;compare r0 against r5;                  ;2,1
        bctr,gt L0584        ;if > goto L0584;                        ;3,2
        lodz    r2           ;r0 = r5;                                ;2,1
L0584:
        rrr,r0               ;r0 >>= 1;                               ;2,1
        bctr,eq L058B        ;if == goto L058B;                       ;3,2
        addi,r0 $08          ;r0 += $08;                              ;2,2
        bctr,un L0576        ;goto L0576;                             ;3,2
;
L058B:
        lodi,r3 $C8          ;r6 = $C8;                               ;2,2
        lodi,r2 $00          ;r5 = $00;                               ;2,2
L058F:
        bsta,un L027C        ;gosub L027C;                            ;3,3
        bctr,eq L0596        ;if == goto L0596;                       ;3,2
        subi,r3 $40          ;r6 -= $40;                              ;2,2
L0596:
        addz    r2           ;r0 += r5;                               ;2,1
        strz    r2           ;r5 = r0;                                ;2,1
        brnr,r1 L059C        ;if (r4 != 0) goto L059C;                ;3,2
        birr,r1 L058F        ;if (++r4 != 0) goto L058F;              ;3,2
L059C:
        rrr,r2               ;r5 >>= 1;                               ;2,1
        andi,r2 $03          ;r5 &= %00000011;                        ;2,2
        bsta,un CALCR0       ;gosub CALCR0;                           ;3,3
        comi,r0 $03          ;compare r0 against $03;                 ;2,2
        bctr,eq L05AE        ;if == goto L05AE;                       ;3,2
        rrl,r0               ;r0 <<= 1;                               ;2,1
        rrl,r0               ;r0 <<= 1;                               ;2,1
        addz    r2           ;r0 += r5;                               ;2,1
        loda,r0 $05D8,r0     ;r0 = *($05D8 + r0);                     ;4,3
        bctr,un L05B0        ;goto L05B0;                             ;3,2
;
L05AE:
        eori,r3 $18          ;r6 ^= %00011000;                        ;2,2
L05B0:
        stra,r0 PITCH        ;PITCH = r0; // hardware registers       ;4,3
        bstr,un MAKENOISE    ;gosub MAKENOISE;                        ;3,2 05B3

;wait for end of vertical blank
L05B5:
        tpsu    $80          ;test bit S....... of PSU; // Sense bit  ;3,2
        bctr,eq L05B5        ;if == goto L05B5;                       ;3,2

INTERRUPT_END:                                                       ;$5B9

;r0 = r4 = PSL = PRESERVEPSL;
        loda,r0 PRESERVEPSL  ;r0 = PRESERVEPSL; // motherboard RAM    ;4,3
        strz    r1           ;r4 = r0;                                ;2,1
        lpsl                 ;PSL = r0 [PRESERVEPSL];                 ;2,1

        loda,r0 PRESERVER0   ;r0 = PRESERVER0; // motherboard RAM     ;4,3
        andi,r1 $C0          ;r4 &= %11000000;                        ;2,2
        cpsl    $10          ;PSL &= !!DrWOMC; // use main reg. bank  ;3,2
        rete,un              ;PSU &= ~PSU_II; return;                 ;3,1
;End of Interrupt Handler-------------------------------------------------
;Subroutine MAKENOISE-----------------------------------------------------
MAKENOISE:                                                           ;$5C6
;r3/r6 is passed as an argument.
;if (*($7AE + DERIVED) >= $80)
;{   NOISE = r3/r6 | %00,1,0,0,0,00;
;} else
;{   NOISE = r3/r6;
;}
        loda,r0 DERIVED      ;r0 = DERIVED; // motherboard RAM        ;4,3
        loda,r0 $07AE,r0     ;r0 = *($07AE + r0);                     ;4,3
        bcfr,lt L05D0        ;if >= goto L05D0;                       ;3,2
        iori,r3 $20          ;r3 |= %00100000;                        ;2,2
L05D0:
        stra,r3 NOISE        ;NOISE = r3; // noise generator          ;4,3
        retc,un              ;return;                                 ;3,1
;Data---------------------------------------------------------------------
X05D4:
        db      $80, $40
X05D6:
        db      $20, $10
X05D8:
        db      $08, $04 ;bit masks for sprites #0..#1
X05DA:
        db      $02, $01 ;bit masks for sprites #2..#3

        db      $5E, $59
        db      $54, $4F, $2F, $2E
        db      $2D
X05E3:
        db      $2C
X05E4:
        db      $00, $10 ;offsets to sprites #0 and #1 data areas
X05E6:
        db      $20, $40 ;offsets to sprites #2 and #3 data areas
X05E8:
        db      $00, $02, $04, $06
        db      $08, $06, $04, $02
X05F0:
        db      $00, $0A, $14, $1E
        db      $28, $1E, $14, $0A
X05F8:
        db      $00, $06, $01, $04
        db      $02, $04, $02, $02
        db      $03, $00
X0602:
        db      $01, $01, $01, $0D
        db      $00, $0D, $01, $01
        db      $00, $07, $0D, $0D
        db      $0D, $0D
X0610:
        db      $0D, $07, $00, $31
        db      $21, $11, $01, $02
        db      $00, $F1, $B1, $71
        db      $31, $11, $00, $71
        db      $51, $21, $11
X0623:
        db      $01, $20
X0625:
        db      $18, $10, $0B, $07
X0629:
        db      $05

        db      $10 ;...#.... $062A
        db      $38 ;..###... $062B
        db      $38 ;..###... $062C
        db      $38 ;..###... $062D
        db      $38 ;..###... $062E
        db      $10 ;...#.... $062F

X0630:
        db      $10 ;...#.... $0630
        db      $10 ;...#.... $0631
        db      $54 ;.#.#.#.. $0632
        db      $54 ;.#.#.#.. $0633
        db      $7C ;.#####.. $0634
        db      $7C ;.#####.. $0635
        db      $7C ;.#####.. $0636
        db      $7C ;.#####.. $0637
        db      $44 ;.#...#.. $0638
        db      $44 ;.#...#.. $0639

        db      $24, $28
        db      $38, $3A, $7E, $7E
        db      $5E, $0C, $04, $04
        db      $1A, $12, $3C, $3C
        db      $78, $18, $0E, $0E
        db      $04, $0C, $18, $30
        db      $72, $7E, $1C, $18
        db      $1C, $1E, $0C, $18
        db      $78, $78, $30, $30
        db      $3C, $3C, $30, $30
        db      $78, $78, $10, $10
        db      $7C, $7C, $10, $10
        db      $10, $10, $38, $38
        db      $28, $38, $18, $1C
        db      $16, $10, $50, $70
        db      $30, $10, $30, $14
        db      $1C, $08, $0C, $54
        db      $36, $20, $20, $10
        db      $08, $08, $08, $0E
        db      $4C, $7C, $34, $24
        db      $20, $00

        db      $08 ;....#... $068A
        db      $08 ;....#... $068B
        db      $48 ;.#..#... $068C
        db      $48 ;.#..#... $068D
        db      $7C ;.#####.. $068E
        db      $7C ;.#####.. $068F
        db      $48 ;.#..#... $0690
        db      $48 ;.#..#... $0691
        db      $08 ;....#... $0692
        db      $08 ;....#... $0693

        db      $00 ;........ $0694
        db      $10 ;...#.... $0695
        db      $10 ;...#.... $0696
        db      $38 ;..###... $0697
        db      $38 ;..###... $0698
        db      $7C ;.#####.. $0699
        db      $7C ;.#####.. $069A
        db      $10 ;...#.... $069B
        db      $10 ;...#.... $069C
        db      $00 ;........ $069D

        db      $18, $38
        db      $78, $38, $3C, $1C
        db      $14, $34, $20, $00
        db      $00, $3C, $3C, $1C
        db      $1C, $1C, $1C, $24
        db      $24, $00, $10, $18
        db      $1C, $1C, $1C, $7C
        db      $5C, $08, $08, $08
        db      $10, $10, $18, $18
        db      $3C, $3C, $18, $18
        db      $10, $10
X06C6:
        db      $39, $38, $00, $00
        db      $80, $01, $80, $01
        db      $80, $01, $80, $01
        db      $82, $41, $82, $41
        db      $02, $40, $02, $40
        db      $82, $41, $82, $41
        db      $80, $01, $80, $01
        db      $80, $01, $80, $01
        db      $00, $00, $00, $00
        db      $39, $38, $00, $00
        db      $41, $40, $40, $40
        db      $08, $E7, $CE, $80
        db      $01, $80, $01, $82
        db      $41, $30, $18, $22
        db      $44, $00, $00, $80
        db      $01, $03, $80, $03
        db      $80, $03, $80, $80
        db      $01, $20, $04, $22
        db      $44, $30, $18, $82
        db      $41, $80, $01, $80
        db      $01, $E7, $CE, $00
        db      $00, $41, $41, $4F
        db      $48, $48, $FF, $1E
        db      $00, $00, $80, $21
        db      $80, $21, $80, $20
        db      $80, $20, $80, $21
        db      $80, $21, $84, $21
        db      $84, $21, $84, $01
        db      $84, $01, $04, $01
        db      $04, $01, $84, $01
        db      $84, $01, $00, $00
        db      $00, $00, $F8, $FE
        db      $00, $00, $41, $40
        db      $40, $40, $48, $03
        db      $00, $07, $80, $0F
        db      $C0, $0F, $E0, $07
        db      $E0, $03, $C0, $01
        db      $80, $00, $80, $00
        db      $00, $00, $00, $00
        db      $00, $00, $00, $20
        db      $20, $60, $20, $E0
        db      $30, $F0, $78, $F8
        db      $78, $F8, $F0, $70
        db      $60, $60, $00, $FF
        db      $DF, $FF, $FE, $FF
        db      $40, $10, $60, $38
        db      $E0, $1C, $F0, $0E
        db      $70, $08, $10, $00
        db      $00, $00, $00, $00
        db      $03, $00, $03, $C0
        db      $07, $C0, $07, $E0
        db      $03, $C0, $01, $80
        db      $01, $00, $00, $04
        db      $40, $0E, $F0, $1F
        db      $60, $06, $40, $00
        db      $FF, $FB, $FF, $EF
X07A6:
        db      $DF, $2D, $5A, $87
        db      $B4, $E1
X07AC:

;for left column (*($7AC + DERIVED):
; bit  7   : 0 = tanks, 1 = planes
; bit  6   : 0 = tanks/biplanes, 1 = jets
; bits 5..3: colour of left  player
; bits 2..0: colour of right player
;for middle column (*($7AD + DERIVED):
; bit  7   : 0 = singles, 1 = twins
; bits 2..0: colour of ?
;for right column (*($7AE + DERIVED):
; bit  7   : 0 = day, 1 = night
; bit  6   : 0 = no minefields, 1 = minefields
; bit  5   : 0 = long range, 1 = short range
; bits 2..0: background scenery ($0..$5) ($0 for no scenery)
              ;$7AC $7AD $7AE
        db      $5E, $4E, $00 ;option  '1' tanks, day   , clear
        db      $4F, $5F, $01 ;option  '2' tanks, day   , absorbent barricades
        db      $41, $3D, $02 ;option  '3' tanks, day   , absorbent barricades
        db      $78, $4E, $03 ;option  '4' tanks, day   , absorbent barricades
        db      $5E, $7A, $44 ;option  '5' tanks, day   , minefields
        db      $71, $3D, $45 ;option  '6' tanks, day   , minefields
        db      $55, $CF, $01 ;option  '7' tanks, day   , rebounding barricades
        db      $70, $CA, $03 ;option  '8' tanks, day   , rebounding barricades
        db      $68, $6A, $80 ;option  '9' tanks, night , clear
        db      $75, $3F, $81 ;option '10' tanks, night , absorbent barricades
        db      $4E, $7A, $82 ;option '11' tanks, night , absorbent barricades
        db      $65, $1A, $83 ;option '12' tanks, night , absorbent barricades
        db      $68, $BE, $81 ;option '13' tanks, night , rebounding barricades
        db      $72, $D8, $83 ;option '14' tanks, night , rebounding barricades
        db      $50, $6B, $20 ;option '15' tanks, day   , short range
        db      $4C, $3E, $A0 ;option '16' tanks, night , short range
        db      $9D, $18, $04 ;option '17' sngl biplanes
        db      $8A, $9F, $04 ;option '18' twin biplanes
        db      $94, $18, $05 ;option '19' sngl biplanes
        db      $82, $9B, $05 ;option '20' twin biplanes
        db      $9D, $1F, $24 ;option '21' sngl biplanes, short range
        db      $EB, $18, $04 ;option '22' sngl jets
        db      $E9, $9F, $04 ;option '23' twin jets
        db      $E2, $18, $05 ;option '24' sngl jets
        db      $E2, $9F, $05 ;option '25' twin jets
        db      $EF, $1F, $25 ;option '26' sngl jets    , short range
;Junk?--------------------------------------------------------------------
;$FFA:
        db      $00, $00, $00, $00
        db      $00, $00

        end

$000..$3F5: mainline code?
$3F6..$5C5: interrupt handler
$5C6..$5D3: subroutine MAKENOISE
$5D4..$FF9: data
$FFA..$FFF: junk?

sprite #0: player(s) 1 vehicle
sprite #1: player(s) 2 vehicle
sprite #2: player(s) 1 bullet
sprite #3: player(s) 2 bullet

For game '18', on title screen:
 Y-positions of 'leader  ' planes are 106..115 (10 rastlines)
 Y-positions of inter-plane gaps  are 116..133 (18 rastlines)
 Y-positions of 'follower' planes are 134..143 (10 rastlines)

For WinArcadia 5.4, this is what happens (for sprite #0) on a good frame:

rast    0     : emulator reads SPRITE0AX/Y.
rasts 106..115: emulator draws sprite #0 (original).
rast  115     : emulator reads SPRITE0BY (as $11).
rast  115     : emulator generates original sprite #0 complete interrupt.
rast  122     : game reads SPRITE0BY (as $11).
rast  123     : game writes SPRITE0BY (to $FD).
rasts 134..143: emulator draws sprite #0 (duplicate).
rast  143     : emulator reads SPRITE0BY (as $FD).
rast  143     : emulator generates duplicate sprite #0 complete interrupt.
rast  150     : game reads SPRITE0BY (as $FD).
rast  150     : game writes SPRITE0BY (to $FE).
rast  271     : emulator generates vblank interrupt.
rast  289     : game reads SPRITE0BY (as $FE).
rast  290     : game writes SPRITE0BY (to $11).

...and this is what happens on a bad frame:

rast    0     : emulator reads SPRITE0AX/Y.
rasts   7.. 16: emulator draws sprite #0 (original).
rast   16     : emulator reads SPRITE0BY (as $11).
rast   16     : emulator suppresses original sprite #0 complete interrupt.
rasts  35.. 44: emulator draws sprite #0 (duplicate).
rast   44     : emulator reads SPRITE0BY (as $11).
                 (SPRITE0BY needs to change to $FD before this point.)
rast   44     : emulator suppresses duplicate sprite #0 complete interrupt.
rast   45     : game reads SPRITE0BY (as $11).
                 (why and how does it do that, since the interrupt was
                 suppressed?)
rast   46     : game writes SPRITE0BY (to $FD).
rasts  63.. 72: emulator draws sprite #0 (duplicate).
rast   72     : emulator reads SPRITE0BY (as $FD).
rast   72     : emulator suppresses duplicate sprite #0 complete interrupt.
rast  218     : game reads SPRITE0BY (as $FD).
rast  218     : game writes SPRITE0BY (to $FE).
rast  271     : emulator generates vblank interrupt.
rast  289     : game reads SPRITE0BY (as $FE).
rast  290     : game writes SPRITE0BY (to $11).

A quick and dirty emulator hack would be, if COMBATA/COMBATB is
 autosensed, to refuse to draw more than one of the same-numbered
 duplicate sprite in a given frame.

For night games, the scenery is always visible, but a given player's
 tank and bullet are only visible whilst that player's bullet is active.

$43E and $4AA are the instructions that write to SPRITE0BY. These
 instructions are marked with '@W'.
$43E writes $FD or $FE there (during scan).
$4AA writes $11 there (during vblank).

$42A and $49B are the instructions that read from SPRITE0BY. These
 instructions are marked with '@R'.
$42A reads from there (during scan).
$49B reads from there (during vblank).
