Difference between revisions of "Disassembly:Videocart 16"

From veswiki
Jump to: navigation, search
 
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Incomplete Disassembly}}
+
<pre>
 +
;-------------------------------------------------------------------------------
 +
; Dodge It - Videocart 16
 +
;  for the Fairchild Video Entertainment System
 +
; Original Code Copyright © 1978, Fairchild Semiconductor
 +
;
 +
; Disassembly Generated using Peter Trauner's f8tool
 +
;
 +
; Comments, Labels, Etc. added by
 +
;  Alex West
 +
;
 +
; Thanks to http://channelf.se/veswiki/ for making this possible
 +
;
 +
; A text file of the instruction manual can be found here:
 +
; http://channelf.se/gallery/txt/videocart16.txt
 +
;
 +
; Build Instructions
 +
;  dasm dodge_it.asm -f3 -ododge_it.bin
 +
 
 +
processor f8
 +
 
 +
include "ves.h"
 +
 
 +
;-------------------------------------------------------------------------------
 +
; Common register definitions
 +
;
 +
; Definitions for common registers, bitfields, and constants. Local registers
 +
;  and function arguments are generally not included here.
 +
 
 +
; -- Ball Properties -----------------------------------------------------------
 +
;
 +
;  The x and y positions are fairly straightforward. The xpos is 7 bits, and
 +
;  the ypos is 6 bits. Velocity is a bit more complicated.
 +
;
 +
;  The balls' velocity is stored in a sign-magnitude format. The sign, or
 +
;  direction, of the balls' x and y velocities is stored in the upper bits of
 +
;  the x and y positions, for those respective directions. The magnitudes are
 +
;  stored in a bitpacked array, with the information for two balls being stored
 +
;  in one byte like so:
 +
;
 +
;  /-- Ball 0's x speed
 +
;  |  /-- Ball 0's y speed
 +
;  XX YY xx yy
 +
;        |  \-- Ball 1's y speed
 +
;        \-- Ball 1's x speed
 +
;
 +
;  ...and so on and so forth for balls 2 and 3, 4 and 5, etc.
 +
;
 +
; Astute observers will note that bit 6 the in y position remains unused, and
 +
;  the last byte of the velocity array has an unused nybble. Such waste...
 +
 
 +
; Current ball being operated on
 +
main.curBall = $B
 +
PLAYER_1 = 0
 +
PLAYER_2 = 1
 +
 
 +
; Ball arrays
 +
balls.xpos = 020 ; Array
 +
balls.ypos = 033 ; Array
 +
balls.speed = 046 ; Bitpacked array
 +
 
 +
balls.count = 056 ; Number of balls currently in play including players
 +
delayIndex  = 057 ; Basically the same as balls.count
 +
 
 +
MASK_DIRECTION = %10000000
 +
MASK_POSITION  = %01111111
 +
MASK_YPOSITION = %00111111
 +
 
 +
MASK_SPEED  = %00001111
 +
MASK_XSPEED = %11001100
 +
MASK_YSPEED = %00110011
 +
 
 +
MAX_BALLS  = 11
 +
MAX_PLAYERS = 2
 +
MAX_ENEMIES = 9
 +
 
 +
; -- Arena Walls ---------------------------------------------------------------
 +
;
 +
; The left and top walls work how you'd expect. However, the right and bottom
 +
;  walls are weird. Not only do they have different values for player and enemy
 +
;  (to account for their different sizes), but they are also negative. In other
 +
;  words, they give distances for how far the walls are from some point 256
 +
;  pixels away from the origin. It's weird and inexplicable.
 +
 
 +
wall.rightEnemy = 060
 +
wall.rightPlayer = 061
 +
wall.left = 062
 +
wall.lowerEnemy = 063
 +
wall.lowerPlayer = 064
 +
wall.upper = 065
 +
 
 +
; Constants used to generate the positions of the walls
 +
WALL_MIN  = $10 ; Most upper-left point possible to generate a field
 +
; Note: These two constants, contrary to the values they help set, are just
 +
;  simply based off the distance from the origin.
 +
WALL_XMAX = $58
 +
WALL_YMAX = $38
 +
 
 +
WALL_X_OFFSET_MAX = $12
 +
WALL_Y_OFFSET_MAX = $0B
 +
 
 +
; Constants to render border at the start of the game
 +
FIELD_CORNER = WALL_MIN ; Top left corner of box, as rendered
 +
FIELD_WIDTH  = WALL_XMAX - WALL_MIN + 1 ; $49
 +
FIELD_HEIGHT = WALL_YMAX - WALL_MIN + 1 ; $29
 +
 
 +
; Constants to spawn the balls at the edges of the field
 +
SPAWN_XMIN = WALL_MIN
 +
SPAWN_XMAX = WALL_XMAX-1
 +
SPAWN_YMIN = WALL_MIN
 +
SPAWN_YMAX = WALL_YMAX-1
 +
 
 +
; -- Timers --------------------------------------------------------------------
 +
 
 +
; Each of these values is 2 bytes of binary-coded decimal.
 +
timer.hi = 066
 +
timer.lo = 067
 +
hiScore.p1.hi = 054
 +
hiScore.p1.lo = 055
 +
hiScore.p2.hi = 073
 +
hiScore.p2.lo = 074
 +
 
 +
; Used to get the lower nybble of a timer byte ("SR 4" can get the upper one)
 +
DIGIT_MASK = $0F
 +
 
 +
; Parameters for drawing the timers' positions
 +
TIMER_X_LEFT = $1F
 +
TIMER_X_CENTER = $39
 +
TIMER_X_RIGHT = $54
 +
TIMER_Y_OFFSET = $A
 +
 
 +
; -- Game mode -----------------------------------------------------------------
 +
 
 +
; The lower two bits represent what button was pressed on the console. The upper
 +
;  six bits of this are randomized in shuffleGame(), but of those bits only the
 +
;  top one matters.
 +
gameMode = 075
 +
MODE_2P_MASK    = %00000001 ; Unset: 1 player, set: 2 players
 +
MODE_SPEED_MASK  = %00000010 ; Set: fast, unset: slow
 +
MODE_CHOICE_MASK = %00000011 ; Used to check if the above two bits are set
 +
; Set: fiddle with speed upon collision, unset: don't fiddle with speed
 +
; Note: It appears that this can only be set in shuffleGame(), and that it is
 +
;  cleared in explode()
 +
MODE_BOUNCE_MASK = %10000000
 +
 
 +
; Set in shuffleGame()
 +
main.gameSettings = $A
 +
MASK_PLAYER_SIZE  = %11000000
 +
MASK_ENEMY_SIZE  = %00110000
 +
MASK_PLAYER_SPEED = %00001100
 +
MASK_ENEMY_SPEED  = %00000011
 +
 
 +
; -- Misc Registers ------------------------------------------------------------
 +
 
 +
; Yes, 070 and 071 have different semantics for different functions called from
 +
;  the main loop.
 +
 
 +
; Controller inputs. Written in readInput, and read in doPlayers and gameOver
 +
input.p1 = 070 ; Left controller
 +
input.p2 = 071 ; Right controller
 +
; Arguments for doBall
 +
doBall.size = 070
 +
doBall.speed = 071
 +
; Local register for collision()
 +
testBall = 071
 +
 
 +
; If set, execute explode() at the end of the main loop
 +
explosionFlag = 072
 +
MASK_EXPLODE = %10000000
 +
 
 +
; Randomly generated number
 +
RNG.seedHi = 076
 +
RNG.seedLo = 077
 +
 
 +
; -- Misc Constants ------------------------------------------------------------
 +
; Most of these should probably be added to ves.h
 +
 
 +
BCD_ADJUST = $66
 +
 
 +
; Sounds
 +
SOUND_NONE  = %00000000 ; Silence
 +
SOUND_1kHz  = %01000000 ; 1kHz tone
 +
SOUND_500Hz = %10000000 ; 500Hz tone
 +
SOUND_120Hz = %11000000 ; 120Hz tone
 +
 
 +
; Graphics
 +
BLUE  = $40
 +
RED  = $80
 +
GREEN = $C0
 +
 
 +
MASK_COLOR    = %11000000
 +
MASK_SOUND    = %11000000
 +
MASK_NO_SOUND  = %00111111
 +
 
 +
DRAW_ATTR_X = $7d
 +
DRAW_ATTR_W = 2
 +
DRAW_SCREEN_W = $80
 +
DRAW_SCREEN_H = $40
 +
 
 +
; end of common register definitions
 +
;-------------------------------------------------------------------------------
 +
 
 +
org $0800
 +
 
 +
CartridgeHeader: db $55, $2b
 +
CartridgeEntry:  JMP init
 +
 
 +
;-------------------------------------------------------------------------------
 +
; Graphics data
 +
;
 +
; Each character takes 5 nybbles of data, split across 5 bytes. Even numbered
 +
;  characters take the left nybble while odd numbered characters take the right.
 +
 
 +
CHAR_WIDTH  = 4
 +
CHAR_HEIGHT = 5
 +
CHAR_G    = $A
 +
CHAR_QMARK = $B
 +
 
 +
graphicsData:
 +
; 0805
 +
db %01110010 ;  ###  #
 +
db %01010110 ;  # # ##
 +
db %01010010 ;  # #  #
 +
db %01010010 ;  # #  #
 +
db %01110111 ;  ### ###
 +
; 080a
 +
db %01110111 ;  ### ###
 +
db %00010001 ;    #  #
 +
db %01110011 ;  ###  ##
 +
db %01000001 ;  #    #
 +
db %01110111 ;  ### ###
 +
; 080f
 +
db %01010111 ;  # # ###
 +
db %01010100 ;  # # # 
 +
db %01110111 ;  ### ###
 +
db %00010001 ;    #  #
 +
db %00010111 ;    # ###
 +
; 0814
 +
db %01000111 ;  #  ###
 +
db %01000001 ;  #    #
 +
db %01110001 ;  ###  #
 +
db %01010001 ;  # #  #
 +
db %01110001 ;  ###  #
 +
; 0819
 +
db %01110111 ;  ### ###
 +
db %01010101 ;  # # # #
 +
db %01110111 ;  ### ###
 +
db %01010001 ;  # #  #
 +
db %01110001 ;  ###  #
 +
; 081e
 +
db %11111111 ; ########
 +
db %10000001 ; #      #
 +
db %10110010 ; # ##  #
 +
db %10010000 ; #  #   
 +
db %11110010 ; ####  #
 +
; 0823
 +
db %01110111 ;  ### ###
 +
db %01000101 ;  #  # #
 +
db %01110111 ;  ### ###
 +
db %01000101 ;  #  # #
 +
db %01000101 ;  #  # #
 +
; 0828
 +
db %01110111 ;  ### ###
 +
db %01000010 ;  #    #
 +
db %01110010 ;  ###  #
 +
db %00010010 ;    #  #
 +
db %01110010 ;  ###  #
 +
 
 +
;-------------------------------------------------------------------------------
 +
; Data Tables
 +
 
 +
; Delay table A (easy)
 +
delayTableEasy: ; 082d
 +
db $19, $16, $13, $11, $0e, $0c, $0a, $08, $06, $03, $01
 +
 
 +
; Delay table B (pro)
 +
delayTableHard: ; 0838
 +
db $0b, $0a, $09, $08, $07, $06, $05, $04, $03, $02, $01
 +
 
 +
; Bitmasks used while randomizing the game mode
 +
gameModeMasks:  ; 0843
 +
db $C0, $30, $0C, $03, $FC
 +
 +
; This table is referenced but never read. Based on the code that references
 +
;  this table, it likely pertained to the enemy speeds. (Also, there is a chance
 +
;  that the endian-ness is wrong on these.)
 +
unusedSpeedTable: ; 0848 00 00 12 0b 0b 06 02 01
 +
dw $0000, $120B, $0B06, $0201
 +
 
 +
; Colors of P1, P2, and enemies
 +
ballColors: ; 0850 40 c0 80
 +
db BLUE, GREEN, RED
 +
 
 +
; Table helps translate the button press to the game mode number
 +
menuChoices: ; 0853
 +
db $00, $01, $02, $03, $03
 +
 
 +
;-------------------------------------------------------------------------------
 +
; draw(param, xpos, ypos, width, height)
 +
;  Leaf function
 +
;
 +
; This function plots pixels to screen. It has two different entry points, which
 +
;  make it act like two different functions.
 +
;
 +
; When entering via drawChar, draw.param should be set to the index of the
 +
;  character to be drawn. Although the charset only contains 16 characters, it
 +
;  could be expanded up to 64 without changing this function.
 +
;
 +
; When entering via drawBox, draw.param should be set to either DRAW_RECT or
 +
;  DRAW_ATTRIBUTE depending on whether you're drawing a box or the attribute
 +
;  column.
 +
;
 +
; The x and y coordinates are relative to the top-left corner of the screen.
 +
;
 +
; Despite the y position and color being mapped to different I/O ports, this
 +
;  function expects those values to be bitpacked together. The y position takes
 +
;  up the lower 6 bits, and the color takes up the upper 2 bits.
 +
;
 +
; Although this function modifies draw.xpos and draw.ypos, those variables are
 +
;  set back to their original values upon returning from the function.
 +
 
 +
; == Arguments ==
 +
draw.param  = 0 ; Drawing Parameter or Character Index
 +
draw.xpos  = 1 ; X Position
 +
draw.ypos  = 2 ; Y Position and Color
 +
draw.width  = 4 ; Width
 +
draw.height = 5 ; Width
 +
 
 +
; Valid values for draw.param
 +
DRAW_RECT      = %10000000 ; Draw a rectangle
 +
DRAW_ATTRIBUTE = %11000000 ; Draw the attribute column
 +
 
 +
; == Entry Point A == (for drawing a character)
 +
drawChar: subroutine
 +
 
 +
; == Local Variables ==
 +
.data  = 3 ; pixel data
 +
.xcount = 6 ; horizontal counter
 +
.ycount = 7 ; vertical counter
 +
.temp  = 8 ; helps calculate the data counter
 +
.color  = 8 ; color, as extracted from ypos
 +
 
 +
; Get the starting address of the desired character
 +
; DC = graphicsData + param/2 + (param/2)*4
 +
DCI  graphicsData        ; 0858 2a 08 05
 +
LR  A, draw.param      ; 085b 40
 +
SR  1                  ; 085c 12
 +
LR  .temp, A            ; 085d 58
 +
SL  1                  ; 085e 13
 +
SL  1                  ; 085f 13
 +
AS  .temp              ; 0860 c8
 +
ADC                      ; 0861 8e
 +
 
 +
; == Entry point B == (for drawing a box)
 +
drawBox:
 +
; (xcount,ycount) = (width,height)
 +
LR  A, draw.width      ; 0862 44
 +
LR  .xcount, A      ; 0863 56
 +
    LR  A, draw.height      ; 0864 45
 +
    LR  .ycount, A      ; 0865 57
 +
 
 +
.doRowLoop:
 +
; I/O write the ypos
 +
; Extract color bits from ypos
 +
LR  A, draw.ypos        ; 0866 42
 +
NI  MASK_COLOR          ; 0867 21 c0
 +
LR  .color, A          ; 0869 58
 +
 +
; Mask out sound, put the ypos in .data
 +
LR  A, draw.ypos        ; 086a 42
 +
COM                      ; 086b 18
 +
NI  MASK_NO_SOUND      ; 086c 21 3f
 +
LR  .data, A            ; 086e 53
 +
 +
; Write row to port 5, making sure to preserve the sound
 +
INS  5                  ; 086f a5
 +
NI  MASK_SOUND          ; 0870 21 c0
 +
AS  .data              ; 0872 c3
 +
OUTS 5                  ; 0873 b5
 +
 
 +
; Load the pixel data into .data
 +
; If either DRAW_RECT or DRAW_ATTRIBUTE is
 +
;  then set all of the pixels and jump ahead
 +
CLR                      ; 0874 70
 +
AS  draw.param          ; 0875 c0
 +
LI  %11111111          ; 0876 20 ff
 +
BM  .setPixelData      ; 0878 91 09
 +
 +
; Load .data from memory
 +
LM                      ; 087a 16
 +
LR  .data, A            ; 087b 53
 +
 
 +
; If character number is even, just use the left 4 bits
 +
LIS  $1                  ; 087c 71
 +
NS  draw.param          ; 087d f0
 +
BZ  .doPixelLoop        ; 087e 84 04
 +
 
 +
; If char is odd, use the right 4 bits by shifting them into place
 +
LR  A, .data            ; 0880 43
 +
SL  4                  ; 0881 15
 +
.setPixelData:
 +
LR  .data, A            ; 0882 53
 +
 
 +
; I/O write the xpos
 +
.doPixelLoop:
 +
LR  A, draw.xpos        ; 0883 41
 +
COM                      ; 0884 18
 +
OUTS 4                  ; 0885 b4
 +
 
 +
; I/O write the color
 +
; if MSB of .data is 1, draw that color
 +
; if MSB of .data is 0, draw the BG color
 +
CLR                      ; 0886 70
 +
AS  .data              ; 0887 c3
 +
LR  A, .color          ; 0888 48
 +
BM  .setColor          ; 0889 91 02
 +
LIS 0                    ; 088b 70
 +
.setColor:
 +
COM                      ; 088c 18
 +
NI  MASK_COLOR          ; 088d 21 c0
 +
OUTS 1                  ; 088f b1
 +
 +
; Iterate on to the next data bit, making sure to pad with 1
 +
; .data = (.data << 1) + 1
 +
LR  A, .data            ; 0890 43
 +
SL  1                  ; 0891 13
 +
INC                      ; 0892 1f
 +
LR  .data, A            ; 0893 53
 +
 +
; If DRAW_ATTRIBUTE is set, iterate to the color of the next column
 +
; Check if DRAW_ATTRIBUTE is set
 +
LR  A, draw.param      ; 0894 40
 +
SL  1                  ; 0895 13
 +
BP  .activateWrite      ; 0896 81 04
 +
; If so, .color = .color << 1
 +
LR  A, .color          ; 0898 48
 +
SL  1                  ; 0899 13
 +
LR  .color, A          ; 089a 58
 +
 
 +
; I/O write to push our color through
 +
.activateWrite:
 +
LI  $60                ; 089b 20 60
 +
OUTS 0                  ; 089d b0
 +
LI  $50                ; 089e 20 50
 +
OUTS 0                  ; 08a0 b0
 +
 
 +
; xpos++
 +
LR  A, draw.xpos        ; 08a1 41
 +
INC                      ; 08a2 1f
 +
LR  draw.xpos, A        ; 08a3 51
 +
 +
; Spin in place to make sure the write goes through
 +
LIS  4                  ; 08a4 74
 +
.delay:
 +
AI  $ff                ; 08a5 24 ff
 +
BNZ  .delay              ; 08a7 94 fd
 +
 +
; xcount--, loop on to next pixel if not zero
 +
DS  .xcount            ; 08a9 36
 +
BNZ  .doPixelLoop        ; 08aa 94 d8
 +
 +
; ypos++
 +
LR  A, draw.ypos        ; 08ac 42
 +
INC                      ; 08ad 1f
 +
LR  draw.ypos, A        ; 08ae 52
 +
 +
; Reset xcount and xpos
 +
; xcount = width
 +
LR  A, draw.width      ; 08af 44
 +
LR  .xcount,A      ; 08b0 56
 +
; xpos = xpos - width
 +
COM                      ; 08b1 18
 +
INC                      ; 08b2 1f
 +
AS  draw.xpos          ; 08b3 c1
 +
LR  draw.xpos, A        ; 08b4 51
 +
 
 +
; ycount--, loop on to next row if not zero
 +
DS  .ycount            ; 08b5 37
 +
BNZ  .doRowLoop          ; 08b6 94 af
 +
 +
; Reset ypos
 +
; ypos = ypos - height
 +
LR  A, draw.height      ; 08b8 45
 +
COM                      ; 08b9 18
 +
INC                      ; 08ba 1f
 +
AS  draw.ypos          ; 08bb c2
 +
LR  draw.ypos, A        ; 08bc 52
 +
 +
; Clear I/O ports
 +
CLR                      ; 08bd 70
 +
OUTS 1                  ; 08be b1
 +
OUTS 0                  ; 08bf b0
 +
 +
POP                      ; 08c0 1c
 +
 
 +
; end draw()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; rand()
 +
;  Leaf Function
 +
;
 +
; Random number generator. I am uncertain how random this is, or what the
 +
;  mathematical basis is behind it.
 +
 
 +
; == Arguments ==
 +
; None
 +
 
 +
; == Returns ==
 +
RNG.regHi = $6
 +
RNG.regLo = $7
 +
 
 +
; == Entry Point ==
 +
rand: subroutine
 +
 
 +
; == Local Variable ==
 +
.tempISAR = 8
 +
 
 +
; save ISAR to a temp register
 +
LR  A,IS                ; 08c1 0a
 +
LR  .tempISAR, A; 08c2 58
 +
 +
; r6 = o77*2 + o76
 +
SETISAR RNG.seedLo      ; 08c3 67 6f
 +
LR  A,(IS)-            ; 08c5 4e
 +
SL  1                  ; 08c6 13
 +
AS  (IS)+              ; 08c7 cd
 +
LR  RNG.regHi, A        ; 08c8 56
 +
 +
; r6,7 = (r6,77)*2
 +
;  do the lo byte
 +
LR  A,(IS)              ; 08c9 4c
 +
AS  (IS)                ; 08ca cc
 +
LR  RNG.regLo, A        ; 08cb 57
 +
 
 +
;  do the hi byte
 +
LR  J,W                ; 08cc 1e ; save status reg
 +
LR  A, RNG.regHi        ; 08cd 46
 +
SL  1                  ; 08ce 13
 +
LR  W,J                ; 08cf 1d ; reload status reg
 +
LNK                      ; 08d0 19
 +
LR  RNG.regHi, A        ; 08d1 56
 +
 +
; r6,7 = (r6,7)*2
 +
;  do the lo byte
 +
LR  A, RNG.regLo        ; 08d2 47
 +
AS  RNG.regLo          ; 08d3 c7
 +
LR  RNG.regLo, A        ; 08d4 57
 +
 
 +
;  do the hi byte
 +
LR  J,W                ; 08d5 1e
 +
LR  A, RNG.regHi        ; 08d6 46
 +
SL  1                  ; 08d7 13
 +
LR  W,J                ; 08d8 1d
 +
LNK                      ; 08d9 19
 +
LR  RNG.regHi, A        ; 08da 56
 +
 +
; r6,7 += r66,67
 +
;  do the lo byte
 +
LR  A, RNG.regLo        ; 08db 47
 +
AS  (IS)-              ; 08dc ce
 +
LR  RNG.regLo, A        ; 08dd 57
 +
 
 +
;  do the hi byte
 +
LR  A, RNG.regHi        ; 08de 46
 +
LNK                      ; 08df 19
 +
AS  (IS)+              ; 08e0 cd
 +
LR  RNG.regHi, A        ; 08e1 56
 +
 +
; r6,r7 += 0x3619
 +
; o76,77 = r6,r7
 +
;  do the lo byte
 +
LR  A, RNG.regLo        ; 08e2 47
 +
AI  $19                ; 08e3 24 19
 +
LR  RNG.regLo, A        ; 08e5 57
 +
LR  (IS)-,A            ; 08e6 5e
 +
 
 +
;  do the hi byte
 +
LR  A, RNG.regHi        ; 08e7 46
 +
LNK                      ; 08e8 19
 +
AI  $36                ; 08e9 24 36
 +
LR  RNG.regHi, A        ; 08eb 56
 +
LR  (IS)+,A            ; 08ec 5d
 +
 +
; Restore ISAR
 +
LR  A, .tempISAR        ; 08ed 48
 +
LR  IS,A                ; 08ee 0b
 +
 
 +
; Return
 +
POP                      ; 08ef 1c
 +
; end of rand()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; menu()
 +
;  Mid-Level Function
 +
;
 +
; Returns the menu button you pressed.
 +
;
 +
; Note that drawing "G?" is handled by main()
 +
 
 +
; == Return ==
 +
menu.buttons = 0
 +
 
 +
; == Entry Point ==
 +
menu: subroutine
 +
 
 +
; == Locals ==
 +
.waitTimerHi = 2
 +
.waitTimerLo = 1
 +
; Wait time is 10 seconds, according to the manual.
 +
.WAIT_TIME = $af00
 +
.DEFAULT_MODE = $1
 +
 
 +
LR  K,P                ; 08f0 08
 +
 
 +
; set lower byte of .waitTimer
 +
LIS  [<.WAIT_TIME]      ; 08f1 70
 +
LR  .waitTimerLo,A      ; 08f2 51
 +
 
 +
; clear console buttons, load default state
 +
OUTS 0                  ; 08f3 b0
 +
INS  0                  ; 08f4 a0
 +
LR  menu.buttons, A    ; 08f5 50
 +
 
 +
; set upper byte of .waitTimer
 +
LI  [>.WAIT_TIME]      ; 08f6 20 af
 +
LR  .waitTimerHi, A    ; 08f8 52
 +
 +
.pollInputLoop:
 +
PI  rand                ; 08f9 28 08 c1
 +
 +
; Set DC (to be used after this function in main)
 +
DCI  menuChoices        ; 08fc 2a 08 53
 +
 
 +
; Read console buttons
 +
CLR                      ; 08ff 70
 +
OUTS 0                  ; 0900 b0
 +
INS  0                  ; 0901 a0
 +
 
 +
; Check if different from last time they were read
 +
XS  menu.buttons        ; 0902 e0
 +
; if not, decrement .waitTimer
 +
BZ  .wait              ; 0903 84 03
 +
 
 +
; Return after 10 seconds or a choice is made
 +
.exit:
 +
LR  menu.buttons,A      ; 0905 50
 +
PK                      ; 0906 0c
 +
 
 +
; Wait for a choice for 10 seconds
 +
.wait:
 +
DS  .waitTimerLo        ; 0907 31
 +
BNZ  .pollInputLoop      ; 0908 94 f0
 +
DS  .waitTimerHi        ; 090a 32
 +
BNZ  .pollInputLoop      ; 090b 94 ed
 +
 
 +
; Default to game mode 1 (1 player, easy)
 +
LIS  .DEFAULT_MODE      ; 090d 71
 +
 
 +
; Return
 +
BR  .exit              ; 090e 90 f6
 +
; end menu()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; readInput()
 +
;  Leaf Function
 +
;
 +
; Reads input from the hand controllers, and twiddles the RNG a bit (if no
 +
;  inputs are detected (?)).
 +
;
 +
; Note: To enable data reads from the controllers, bit 6 of I/O port 0 needs to
 +
;  be set to 1. This is done in draw(), meaning that it doesn't need to be done
 +
;  here (although it might have been better practice to do so).
 +
;
 +
; == Arguments ==
 +
;  None
 +
; == Returns ==
 +
;  input.p1 = 070
 +
;  input.p2 = 071
 +
; == Locals ==
 +
;  None
 +
 
 +
; == Entry Point ==
 +
readInput: subroutine
 +
SETISAR input.p1        ; 0910 67 68
 +
 +
; Clear I/O ports
 +
CLR                      ; 0912 70
 +
OUTS 1                  ; 0913 b1
 +
OUTS 4                  ; 0914 b4
 +
 +
; Read left controller from I/O port 1
 +
INS  1                  ; 0915 a1
 +
LR  (IS)+,A            ; 0916 5d
 +
 +
; Read right controller from I/O port 2
 +
INS  4                  ; 0917 a4
 +
LR  (IS)-,A            ; 0918 5e
 +
 +
; if(-(input.p1 + input.p2) == 0) then exit
 +
AS  (IS)                ; 0919 cc
 +
INC                      ; 091a 1f
 +
COM                      ; 091b 18
 +
BZ  .exit              ; 091c 84 06
 +
 +
; else, twiddle with the RNG
 +
SETISARL RNG.seedLo    ; 091e 6f
 +
; RNG.lo = RNG.lo + 1
 +
LIS  $1                  ; 091f 71
 +
AS  (IS)                ; 0920 cc
 +
LR  (IS)-,A            ; 0921 5e
 +
; RNG.hi--
 +
DS  (IS)                ; 0922 3c
 +
 
 +
.exit:
 +
POP                      ; 0923 1c
 +
; end of readInput()
 +
;-------------------------------------------------------------------------------
 +
 +
;-------------------------------------------------------------------------------
 +
; doPlayers()
 +
;  Mid-Level Function
 +
;
 +
; This function takes the controller inputs sets the speed and direction of each
 +
;  player's ball accordingly. Player speed is taken from main.gameSettings. The
 +
;  results are then save to the xpos, ypos, and speed arrays in the scratchpad.
 +
;
 +
; The order in which the players are processed is done randomly.
 +
;
 +
; In the case of L/R or U/D conflicts, right takes precedence over left and down
 +
;  over up.
 +
;
 +
; This function does not handle drawing the players.
 +
 
 +
; == Entry Point ==
 +
doPlayers: subroutine
 +
 
 +
; == Locals ==
 +
.speed = $0
 +
.xpos = $1
 +
.ypos = $2
 +
.loopCount = $8
 +
 
 +
LR  K,P                ; 0924 08
 +
 +
; Read input from hand controllers
 +
PI  readInput          ; 0925 28 09 10
 +
 +
; Randomize which player is processed first
 +
; if LSB of RNG is set
 +
;  curBall = player 1
 +
; else
 +
;  curBall = player 2
 +
SETISAR RNG.seedLo      ; 0928 67 6f
 +
LIS  PLAYER_2            ; 092a 71
 +
NS  (IS)                ; 092b fc
 +
LIS  PLAYER_1            ; 092c 70
 +
BNZ  .setPlayer          ; 092d 94 02
 +
LIS  PLAYER_2            ; 092f 71
 +
.setPlayer:
 +
LR  main.curBall,A      ; 0930 5b
 +
 
 +
; .loopCount = 2
 +
LIS  MAX_PLAYERS        ; 0931 72
 +
LR  .loopCount,A        ; 0932 58
 +
 
 +
; start loop
 +
.playerLoop:
 +
; speed = 0 (so we don't move if nothing is pressed)
 +
CLR                      ; 0933 70
 +
LR  .speed,A            ; 0934 50
 +
 
 +
; .xpos = xpos[curBall]
 +
LR  A,main.curBall      ; 0935 4b
 +
AI  balls.xpos          ; 0936 24 10
 +
LR  IS,A                ; 0938 0b
 +
LR  A,(IS)              ; 0939 4c
 +
LR  .xpos,A            ; 093a 51
 +
 
 +
; .ypos = ypos[curBall]
 +
LR  A,IS                ; 093b 0a
 +
AI  MAX_BALLS          ; 093c 24 0b
 +
LR  IS,A                ; 093e 0b
 +
LR  A,(IS)              ; 093f 4c
 +
LR  $2,A                ; 0940 52
 +
 
 +
; set ISAR to match the current player's controller
 +
SETISARU RNG.seedLo      ; 0941 67
 +
LIS  PLAYER_2            ; 0942 71
 +
NS  main.curBall        ; 0943 fb
 +
SETISARL input.p2        ; 0944 69
 +
BNZ  .checkRight        ; 0945 94 02
 +
SETISARL input.p1        ; 0947 68
 +
 
 +
; Check if right is pressed
 +
.checkRight:
 +
LIS  CONTROL_RIGHT      ; 0948 71
 +
NS  (IS)                ; 0949 fc
 +
BNZ  .checkLeft          ; 094a 94 06
 +
 
 +
; If so, set x direction to right
 +
LR  A,.xpos            ; 094c 41
 +
NI  MASK_POSITION      ; 094d 21 7f
 +
BR  .setXspeed          ; 094f 90 08
 +
 
 +
; Check if left is pressed
 +
.checkLeft:
 +
LIS  CONTROL_LEFT        ; 0951 72
 +
NS  (IS)                ; 0952 fc
 +
BNZ  .checkDown          ; 0953 94 08
 +
 
 +
; If so, set x direction to left
 +
LR  A,.xpos            ; 0955 41
 +
OI  MASK_DIRECTION      ; 0956 22 80
 +
 
 +
.setXspeed:
 +
; Apply the direction to .xpos
 +
LR  .xpos,A            ; 0958 51
 +
; xspeed = gameSettings.playerSpeed
 +
LIS  MASK_PLAYER_SPEED  ; 0959 7c
 +
NS  main.gameSettings  ; 095a fa
 +
LR  .speed,A            ; 095b 50
 +
 
 +
; Check if down is pressed
 +
.checkDown:
 +
LIS  CONTROL_BACKWARD    ; 095c 74
 +
NS  (IS)                ; 095d fc
 +
BNZ  .checkUp            ; 095e 94 06
 +
 
 +
; If so, set y direction to down
 +
LR  A,.ypos            ; 0960 42
 +
NI  MASK_YPOSITION      ; 0961 21 3f
 +
BR  .setYspeed          ; 0963 90 08
 +
 +
; Check if up is pressed
 +
.checkUp:
 +
LIS  CONTROL_FORWARD    ; 0965 78
 +
NS  (IS)                ; 0966 fc
 +
BNZ  .prepSaveBall      ; 0967 94 0b
 +
 
 +
; If so, set y direction to up
 +
LR  A,.ypos            ; 0969 42
 +
OI  MASK_DIRECTION      ; 096a 22 80
 +
 
 +
.setYspeed:
 +
; Apply the direction to .ypos
 +
LR  .ypos,A            ; 096c 52
 +
; yspeed = gameSettings.playerSpeed
 +
LIS  MASK_PLAYER_SPEED  ; 096d 7c
 +
NS  main.gameSettings  ; 096e fa
 +
SR  1                  ; 096f 12
 +
SR  1                  ; 0970 12
 +
AS  .speed              ; 0971 c0
 +
LR  .speed,A            ; 0972 50
 +
 
 +
; Copy the speed to the other nybble
 +
.prepSaveBall:
 +
LR  A,.speed            ; 0973 40
 +
SL  4                  ; 0974 15
 +
AS  .speed              ; 0975 c0
 +
LR  .speed,A            ; 0976 50
 +
; saveBall will figure out which nybble to save
 +
 +
; Save the ball to the scratchpad arrays
 +
PI  saveBall            ; 0977 28 09 a2
 +
 +
; Set curBall to the other player's ball
 +
; (why not xor the register with a constant 1?)
 +
LIS  PLAYER_2            ; 097a 71
 +
NS  main.curBall        ; 097b fb
 +
LIS  PLAYER_1            ; 097c 70
 +
BNZ  .setNextPlayer      ; 097d 94 02
 +
LIS  PLAYER_2            ; 097f 71
 +
.setNextPlayer:
 +
LR  main.curBall,A      ; 0980 5b
 +
 +
; .loopCount--
 +
DS  .loopCount          ; 0981 38
 +
BNZ  .playerLoop        ; 0982 94 b0
 +
 +
; Return
 +
LR  P,K                ; 0984 09
 +
POP                      ; 0985 1c
 +
; end doPlayers()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; delayByTable(index)
 +
; delayVariable(count)
 +
;  Leaf Functions
 +
;
 +
; This procedure has two different entry points, so we can consider it two
 +
;  different functions. Alternatively, we can think of the first function as
 +
;  calling the second function by having just continuing on to its code.
 +
;  (Alternatively, this is just some spaghetti code.)
 +
;
 +
; The first sets the delay according to the game mode and the current number of
 +
;  balls. This function is necessary to make sure that the game runs at a
 +
;  consistent speed, since the Channel F does not have any means of
 +
;  synchronizing itself to vblank or anything like that.
 +
;
 +
; The second function sets a delay according to an a count provided by the
 +
;  callee. This is useful for providing short pauses, like during a game over.
 +
;
 +
; TODO: Find a rough conversion between delay.count and the amount of time this
 +
;  function actually delays.
 +
 
 +
; == Arguments ==
 +
; Same register, yes, but this is good syntactic sugar.
 +
delay.index = 0 ; when entering through delayByTable
 +
delay.count = 0 ; when entering through delayVariable
 +
 
 +
; == Entry Point A ==
 +
delayByTable: subroutine
 +
 
 +
; == Locals ==
 +
.tempISAR = 3
 +
 
 +
; if(gameMode & speedMask == 0)
 +
;  count = delayTableEasy[index]
 +
; else
 +
;  count = delayTableHard[index]
 +
; Set
 +
DCI  delayTableEasy      ; 0986 2a 08 2d
 +
 +
; Save the ISAR
 +
LR  A,IS                ; 0989 0a
 +
LR  .tempISAR,A        ; 098a 53
 +
 +
; Test to check the game speed
 +
SETISAR gameMode        ; 098b 67 6d
 +
LIS  MODE_SPEED_MASK    ; 098d 72
 +
NS  (IS)                ; 098e fc
 +
 +
; Restore the ISAR
 +
LR  A,.tempISAR        ; 098f 43
 +
LR  IS,A                ; 0990 0b
 +
 +
; Branch ahead if playing easy
 +
BZ  .loadData          ; 0991 84 04
 +
 +
; Else, set the table to hard
 +
DCI  delayTableHard      ; 0993 2a 08 38
 +
 
 +
; delay.count = delayTable[index]
 +
.loadData:
 +
LR  A, delay.index      ; 0996 40
 +
ADC                      ; 0997 8e
 +
LM                      ; 0998 16
 +
LR  delay.count, A      ; 0999 50
 +
 
 +
; == Entry Point B ==
 +
delayVariable:
 +
 
 +
; A = 0
 +
.outerLoop:
 +
LIS  0                  ; 099a 70
 +
; A++
 +
.innerLoop:
 +
INC                      ; 099b 1f
 +
BNZ  .innerLoop          ; 099c 94 fe
 +
; count--
 +
DS  delay.count        ; 099e 30
 +
BNZ  .outerLoop          ; 099f 94 fa
 +
 
 +
; Return
 +
POP                      ; 09a1 1c
 +
; end of delayByTable() and delayVariable()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; saveBall(ball, speed, xpos, ypos)
 +
;  Leaf Function
 +
;
 +
; Given the ball number, speed, x position, and y position in the input
 +
;  arguements, this function saves those ball parameters into the appropriate
 +
;  arrays in the scratchpad. This function is useful because the speed array is
 +
;  bitpacked.
 +
 
 +
; == Arguments ==
 +
saveBall.speed = $0
 +
saveBall.xpos = $1
 +
saveBall.ypos = $2
 +
; main.curBall = $B
 +
 
 +
saveBall: subroutine
 +
 
 +
; == Local ==
 +
.speedMask = $3
 +
 
 +
; xpos[curBall] = saveBall.xpos
 +
LI  balls.xpos          ; 09a2 20 10
 +
AS  main.curBall        ; 09a4 cb
 +
LR  IS,A                ; 09a5 0b
 +
LR  A,saveBall.xpos    ; 09a6 41
 +
LR  (IS),A              ; 09a7 5c
 +
 +
; ypos[curBall] = saveBall.xpos
 +
LR  A,IS                ; 09a8 0a
 +
AI  MAX_BALLS          ; 09a9 24 0b
 +
LR  IS,A                ; 09ab 0b
 +
LR  A,saveBall.ypos    ; 09ac 42
 +
LR  (IS),A              ; 09ad 5c
 +
 +
; Calculate index and bitmask for the bitpacked velocity array
 +
; ISAR = balls.speed + curBall/2
 +
LR  A, main.curBall    ; 09ae 4b
 +
SR  1                  ; 09af 12
 +
AI  balls.speed        ; 09b0 24 26
 +
LR  IS,A                ; 09b2 0b
 +
 +
; if curBall is even
 +
;  bitmask = %00001111
 +
; else
 +
;  bitmask = %11110000
 +
LIS  $1                  ; 09b3 71
 +
NS  main.curBall        ; 09b4 fb
 +
LIS  MASK_SPEED          ; 09b5 7f
 +
BNZ  .setSpeedMask      ; 09b6 94 02
 +
COM                      ; 09b8 18
 +
.setSpeedMask:         
 +
LR  .speedMask,A        ; 09b9 53
 +
 
 +
; Set curBall speed bitfield
 +
; Clear curBall's bitfield from the velocity[curBall/2]
 +
COM                      ; 09ba 18
 +
NS  (IS)                ; 09bb fc
 +
LR  (IS),A              ; 09bc 5c
 +
 
 +
; Extract the appropriate speed bitfield from the input argument
 +
LR  A,saveBall.speed    ; 09bd 40
 +
NS  .speedMask          ; 09be f3
 +
 
 +
; Merge the bitfields and save the result
 +
AS  (IS)                ; 09bf cc
 +
LR  (IS),A              ; 09c0 5c
 +
 
 +
; Return
 +
POP                      ; 09c1 1c
 +
; end saveBall()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; spawnBall(curBall)
 +
;  Mid-Level Function
 +
;
 +
; This function spawns a single enemy or player ball.
 +
;
 +
; Enemy balls are given a random position in the playfield and a random
 +
;  direction, and then clamped to one of the four walls, with their direction
 +
;  being set away from the wall. They are also given a non-random starting speed
 +
;  of 1 and 1 on each axis.
 +
;
 +
; Player balls are spawned in hardcoded positions in the middle of the court.
 +
 
 +
; == Arguments ==
 +
; main.curBall = $b
 +
 
 +
; == Returns ==
 +
; None
 +
 
 +
; == Entry Point ==
 +
spawnBall: subroutine
 +
LR  K,P                ; 09c2 08
 +
 
 +
; == Local Variables ==
 +
.speed = $0
 +
.xpos = $1
 +
.ypos = $2
 +
 
 +
; == Local Constants ==
 +
.SPEED = %01010101
 +
.PLAYER_Y = $23
 +
.PLAYER1_X = $33
 +
.PLAYER2_X = $3A
 +
 +
; keep rerolling RNG until it gets an inbounds x and y position
 +
.reroll:
 +
PI  rand                ; 09c3 28 08 c1
 +
 
 +
; xpos = rng.hi
 +
LR  A, RNG.regHi        ; 09c6 46
 +
CI  SPAWN_XMIN          ; 09c7 25 10
 +
BC  .reroll            ; 09c9 82 f9
 +
CI  SPAWN_XMAX          ; 09cb 25 57
 +
BNC  .reroll            ; 09cd 92 f5
 +
 
 +
LR  .xpos,A            ; 09cf 51
 +
 
 +
; ypos = rng.lo
 +
LR  A, RNG.regLo        ; 09d0 47
 +
CI  SPAWN_YMIN          ; 09d1 25 10
 +
BC  .reroll            ; 09d3 82 ef
 +
CI  SPAWN_YMAX          ; 09d5 25 37
 +
BNC  .reroll            ; 09d7 92 eb
 +
 
 +
LR  .ypos,A            ; 09d9 52
 +
 +
; speed = 0x55
 +
LI  .SPEED              ; 09da 20 55
 +
LR  .speed,A            ; 09dc 50
 +
 +
; Spawn the ball against one of the walls
 +
; use lower 2 bits of rng.hi as index to jump table
 +
; This is essentially a case statement
 +
LIS  %00000011          ; 09dd 73
 +
NS  RNG.regHi          ; 09de f6
 +
 +
; jump to (jump_table + 2*A)
 +
DCI  .jumpTable          ; 09df 2a 09 e6
 +
ADC                      ; 09e2 8e
 +
ADC                      ; 09e3 8e
 +
LR  Q,DC                ; 09e4 0e
 +
; Jump!
 +
LR  P0,Q                ; 09e5 0d
 +
 
 +
.jumpTable:
 +
BR  .north              ; 09e6 90 07
 +
BR  .east              ; 09e8 90 0a
 +
BR  .south              ; 09ea 90 13
 +
BR  .west              ; 09ec 90 1c
 +
 
 +
.north:
 +
; ypos = 0x11
 +
; ydir = sount
 +
LI  SPAWN_YMIN+1        ; 09ee 20 11
 +
LR  .ypos,A            ; 09f0 52
 +
BR  .spawnPlayers      ; 09f1 90 1a
 +
 +
.east:
 +
; xpos = $58 - enemy ball size
 +
; xdir = west
 +
LI  MASK_ENEMY_SIZE    ; 09f3 20 30
 +
NS  main.gameSettings  ; 09f5 fa
 +
SR  4                  ; 09f6 14
 +
COM                      ; 09f7 18
 +
INC                      ; 09f8 1f
 +
AI  MASK_DIRECTION|(SPAWN_XMAX+1) ; 09f9 24 d8
 +
LR  .xpos,A            ; 09fb 51
 +
BR  .spawnPlayers      ; 09fc 90 0f
 +
 
 +
.south:
 +
; ypos = $38 - enemy ball size
 +
; ydir = north
 +
LI  MASK_ENEMY_SIZE    ; 09fe 20 30
 +
NS  main.gameSettings  ; 0a00 fa
 +
SR  4                  ; 0a01 14
 +
COM                      ; 0a02 18
 +
INC                      ; 0a03 1f
 +
AI  MASK_DIRECTION|(SPAWN_YMAX+1) ; 0a04 24 b8
 +
LR  .ypos,A            ; 0a06 52
 +
BR  .spawnPlayers      ; 0a07 90 04
 +
 
 +
.west:
 +
; xpos = 0x11
 +
; xdir = east
 +
LI  SPAWN_XMIN+1        ; 0a09 20 11
 +
LR  .xpos,A            ; 0a0b 51
 +
 
 +
.spawnPlayers:
 +
; exit if current ball is not a player
 +
LR  A, main.curBall    ; 0a0c 4b
 +
CI  [MAX_PLAYERS-1]    ; 0a0d 25 01
 +
BNC  .exit              ; 0a0f 92 0b
 +
 +
; Ignore all the above calculations and spawn the players
 +
; ypos = 0x23
 +
LI  .PLAYER_Y          ; 0a11 20 23
 +
LR  .ypos,A            ; 0a13 52
 +
; if (curBall == Player 1)
 +
;  xpos = 0x33
 +
; else xpos = 0x33 + 0x07
 +
LI  .PLAYER1_X          ; 0a14 20 33
 +
BNZ  .setPlayerXPos      ; 0a16 94 03
 +
AI  .PLAYER2_X-.PLAYER1_X ; 0a18 24 07
 +
.setPlayerXPos:
 +
LR  .xpos,A            ; 0a1a 51
 +
 
 +
; Save xpos, ypos, and speed
 +
.exit:
 +
PI  saveBall            ; 0a1b 28 09 a2
 +
 
 +
LR  P,K                ; 0a1e 09
 +
POP                      ; 0a1f 1c
 +
; end spawnBall()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; drawTimer(int* timer, xpos, ypos)
 +
;  Mid-Level Function
 +
;
 +
; Draws a 4-digit number pointed to by the ISAR. The ISAR should point to the
 +
;  least significant byte of a big-endian word. The x and y positions specify
 +
;  the upper-left corner of the ones digit (not the thousands digit).
 +
 
 +
; == Arguments ==
 +
; *timer = ISAR
 +
drawTimer.xpos = 0
 +
drawTimer.ypos = 2 ; and color
 +
 
 +
drawTimer:         
 +
LR  K,P                ; 0a20 08
 +
 +
; == Local Constant ==
 +
.X_DELTA  = <[-5]
 +
 +
; Draw ones digit
 +
; Load xpos
 +
LR  A, drawTimer.xpos  ; 0a21 40
 +
LR  draw.xpos, A        ; 0a22 51
 +
; Adjust ypos
 +
LI  TIMER_Y_OFFSET      ; 0a23 20 0a
 +
AS  drawTimer.ypos      ; 0a25 c2
 +
LR  draw.ypos, A        ; 0a26 52
 +
; Set character
 +
LI  DIGIT_MASK          ; 0a27 20 0f
 +
NS  (IS)                ; 0a29 fc
 +
LR  draw.param, A      ; 0a2a 50
 +
; Width
 +
LIS  CHAR_WIDTH          ; 0a2b 74
 +
LR  draw.width, A      ; 0a2c 54
 +
; Height
 +
LIS  CHAR_HEIGHT        ; 0a2d 75
 +
LR  draw.height, A      ; 0a2e 55
 +
 
 +
PI  drawChar            ; 0a2f 28 08 58
 +
 +
; Draw tens digit
 +
; Set character
 +
LR  A,(IS)-            ; 0a32 4e
 +
SR  4                  ; 0a33 14
 +
LR  draw.param, A      ; 0a34 50
 +
; xpos -= xdelta
 +
LI  .X_DELTA            ; 0a35 20 fb
 +
AS  draw.xpos          ; 0a37 c1
 +
LR  draw.xpos, A        ; 0a38 51
 +
 +
PI  drawChar            ; 0a39 28 08 58
 +
 +
; Draw hundreds digit
 +
; Set character
 +
LR  A,(IS)              ; 0a3c 4c
 +
NI  DIGIT_MASK          ; 0a3d 21 0f
 +
LR  draw.param, A      ; 0a3f 50
 +
; xpos -= xdelta
 +
LI  .X_DELTA          ; 0a40 20 fb
 +
AS  draw.xpos          ; 0a42 c1
 +
LR  draw.xpos, A        ; 0a43 51
 +
 
 +
PI  drawChar            ; 0a44 28 08 58
 +
 +
; Draw thousands digit
 +
; Set character
 +
LR  A,(IS)              ; 0a47 4c
 +
SR  4                  ; 0a48 14
 +
LR  draw.param, A      ; 0a49 50
 +
; xpos -= xdelta
 +
LI  .X_DELTA            ; 0a4a 20 fb
 +
AS  draw.xpos          ; 0a4c c1
 +
LR  draw.xpos, A        ; 0a4d 51
 +
 
 +
PI  drawChar            ; 0a4e 28 08 58
 +
 
 +
; Exit
 +
LR  P,K                ; 0a51 09
 +
POP                      ; 0a52 1c
 +
; end of drawTimer()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; doBall()
 +
;  Mid-Level Function
 +
;
 +
; This function:
 +
; - Undraws the ball
 +
; - Moves the ball according its velocity
 +
; - Checks if the ball has collided with a wall
 +
; - Saves the changes the ball's velocity
 +
; - Redraws the ball (if the explosion flag is not set)
 +
;
 +
; Since this is such a long function (relative to the rest of the functions in
 +
;  this game), these parts of the function will be given nice, labeled dividers.
 +
;  Also, the local variables for each part of the function will be declared at
 +
;  the start of each part of the function.
 +
 
 +
; == Arguments ==
 +
; doBall.size = 070
 +
; doBall.speed = 071
 +
; main.curBall = $b
 +
 
 +
doBall: subroutine
 +
LR  K,P                ; 0a53 08
 +
 
 +
; -- Undraw the ball -----------------------------------------------------------
 +
.tempYpos = $9
 +
 
 +
; Load xpos
 +
LI  balls.xpos          ; 0a54 20 10
 +
AS  main.curBall        ; 0a56 cb
 +
LR  IS,A                ; 0a57 0b
 +
LR  A,(IS)              ; 0a58 4c
 +
LR  draw.xpos, A        ; 0a59 51
 +
 
 +
; Load ypos
 +
LR  A,IS                ; 0a5a 0a
 +
AI  MAX_BALLS          ; 0a5b 24 0b
 +
LR  IS,A                ; 0a5d 0b
 +
LR  A,(IS)              ; 0a5e 4c
 +
 
 +
; Store temp ypos
 +
LR  .tempYpos,A        ; 0a5f 59
 +
 
 +
; Mask out the color bits from ypos
 +
NI  MASK_YPOSITION      ; 0a60 21 3f
 +
LR  draw.ypos, A        ; 0a62 52
 +
 
 +
; Load ball size
 +
SETISAR doBall.size      ; 0a63 67 68
 +
LR  A,(IS)              ; 0a65 4c
 +
LR  draw.width, A      ; 0a66 54
 +
LR  draw.height, A      ; 0a67 55
 +
 
 +
; Set parameter
 +
LI  DRAW_RECT          ; 0a68 20 80
 +
LR  draw.param, A      ; 0a6a 50
 +
 
 +
; Undraw ball
 +
PI  drawBox            ; 0a6b 28 08 62
 +
 
 +
; Reload ypos from temp
 +
LR  A,.tempYpos        ; 0a6e 49
 +
LR  draw.ypos, A        ; 0a6f 52
 +
 
 +
; -- Apply x and y velocities to the ball --------------------------------------
 +
.xpos = $1
 +
.ypos = $2
 +
 
 +
.tempSpeed = $3
 +
.speedMask = $6
 +
 
 +
; Get bitpacked velocity
 +
; ISAR = balls.speed[curBall/2]
 +
LR  A, main.curBall    ; 0a70 4b
 +
SR  1                  ; 0a71 12
 +
AI  balls.speed        ; 0a72 24 26
 +
LR  IS,A                ; 0a74 0b
 +
 +
; if (index is odd)
 +
;  speedMask = $0F
 +
; else
 +
;  speedMask = $F0
 +
LIS  $1                  ; 0a75 71
 +
NS  main.curBall        ; 0a76 fb
 +
LIS  MASK_SPEED          ; 0a77 7f
 +
BNZ  .setSpeedMask      ; 0a78 94 02
 +
COM                      ; 0a7a 18
 +
.setSpeedMask:         
 +
LR  .speedMask,A        ; 0a7b 56
 +
 +
; Load the other ball's speed nybble
 +
; Note: This is never read.
 +
COM                      ; 0a7c 18
 +
NS  (IS)                ; 0a7d fc
 +
LR  $0,A                ; 0a7e 50
 +
 +
; Load this ball's speed nybble
 +
LR  A,.speedMask        ; 0a7f 46
 +
NS  (IS)                ; 0a80 fc
 +
LR  .tempSpeed,A        ; 0a81 53
 +
; Shift right by 4 and save the result if non-zero
 +
SR  4                  ; 0a82 14
 +
BZ  .applyVelocity      ; 0a83 84 02
 +
LR  .tempSpeed,A        ; 0a85 53
 +
 
 +
; Apply x velocity
 +
.applyVelocity:
 +
; Test if bit 7 of xpos is set
 +
CLR                      ; 0a86 70
 +
AS  .xpos              ; 0a87 c1
 +
; Save result of test
 +
LR  J,W                ; 0a88 1e
 +
 +
; Load xspeed to A
 +
LR  A,.tempSpeed        ; 0a89 43
 +
SR  1                  ; 0a8a 12
 +
SR  1                  ; 0a8b 12
 +
 +
; If bit 7 of xpos wasn't set, branch ahead
 +
LR  W,J                ; 0a8c 1d
 +
BP  .addXVelocity      ; 0a8d 81 03
 +
 +
; Else, negate the xspeed
 +
COM                      ; 0a8f 18
 +
INC                      ; 0a90 1f
 +
.addXVelocity:
 +
; xpos = xpos +/- xspeed
 +
AS  .xpos              ; 0a91 c1
 +
LR  .xpos,A            ; 0a92 51
 +
 
 +
; Apply y velocity
 +
; Test if bit 7 of ypos is set
 +
CLR                      ; 0a93 70
 +
AS  .ypos              ; 0a94 c2
 +
; Save result of test
 +
LR  J,W                ; 0a95 1e
 +
 +
; Load yspeed to A
 +
LIS  %00000011          ; 0a96 73
 +
NS  .tempSpeed          ; 0a97 f3
 +
 +
; If bit 7 of ypos wasn't set, branch ahead
 +
LR  W,J                ; 0a98 1d
 +
BP  .addYVelocity      ; 0a99 81 03
 +
 +
; Else, negate yspeed
 +
COM                      ; 0a9b 18
 +
INC                      ; 0a9c 1f
 +
.addYVelocity:
 +
; ypos = ypos +/- yspeed
 +
AS  .ypos              ; 0a9d c2
 +
LR  .ypos,A            ; 0a9e 52
 +
 
 +
; -- Ball/Wall collision detection ---------------------------------------------
 +
.bounceSpeed = $0 ; Speed imparted by bouncing off the walls
 +
.rightBound  = $4
 +
.lowerBound  = $5
 +
 
 +
; Get player or enemy right bound, depending on curBall
 +
SETISAR wall.rightEnemy  ; 0a9f 66 68
 +
LR  A, main.curBall    ; 0aa1 4b
 +
CI  [MAX_PLAYERS-1]    ; 0aa2 25 01
 +
BNC  .setRightBound    ; 0aa4 92 02
 +
SETISARL wall.rightPlayer; 0aa6 69
 +
.setRightBound:         
 +
LR  A,(IS)              ; 0aa7 4c
 +
LR  .rightBound,A      ; 0aa8 54
  
This is the complete disassembly of the [[Channel F]] [[Videocart 16]] made with Peter Trauner's [[f8tool]]. Original code is copyright &copy; 1978 Fairchild Semiconductor.
+
; Likewise, get lower bound
 +
; .lowerBound = (ISAR+3)
 +
LR  A,IS                ; 0aa9 0a
 +
AI  3                  ; 0aaa 24 03
 +
LR  IS,A                ; 0aac 0b
 +
LR  A,(IS)              ; 0aad 4c
 +
LR  .lowerBound,A      ; 0aae 55
  
 +
; -- Check collision with left and right walls --
 +
; Clear .bounceSpeed
 +
CLR                      ; 0aaf 70
 +
LR  .bounceSpeed,A      ; 0ab0 50
  
<pre>
+
; Check collision with right wall
Reset: equ $0000
+
; If ball is going leftward, branch ahead
 +
AS  .xpos              ; 0ab1 c1
 +
BM  .checkLeftWall      ; 0ab2 91 18
 +
; Branch if (xpos + rightBound < 256)
 +
AS  .rightBound        ; 0ab4 c4
 +
BNC  .checkBottomWall  ; 0ab5 92 29
 +
 +
; We have collided with the right wall
 +
; Clamp position to right wall and set direction to left
 +
LR  A,.rightBound      ; 0ab7 44
 +
COM                      ; 0ab8 18
 +
INC                      ; 0ab9 1f
 +
AI  MASK_DIRECTION      ; 0aba 24 80
 +
LR  .xpos,A            ; 0abc 51
 +
 +
; Play sound for hitting wall
 +
LI  SOUND_1kHz          ; 0abd 20 40
 +
LR  playSound.sound,A  ; 0abf 53
 +
PI  playSound          ; 0ac0 28 0c c8
 +
 
 +
.setXSpeed:
 +
; .bounceSpeed.x = doBall.speed
 +
SETISAR doBall.speed    ; 0ac3 67 69
 +
LR  A,(IS)              ; 0ac5 4c
 +
SL  1                  ; 0ac6 13
 +
SL  1                  ; 0ac7 13
 +
LR  .bounceSpeed,A      ; 0ac8 50
 +
BR  .checkBottomWall    ; 0ac9 90 15
 +
 
 +
; Check if colliding with left wall
 +
.checkLeftWall:
 +
; Mask out the directional bit
 +
LR  A,.xpos            ; 0acb 41
 +
NI  MASK_POSITION      ; 0acc 21 7f
 +
 +
; branch ahead if(leftBound < xpos)
 +
COM                      ; 0ace 18
 +
INC                      ; 0acf 1f
 +
SETISAR wall.left        ; 0ad0 66 6a
 +
AS  (IS)                ; 0ad2 cc
 +
BNC  .checkBottomWall    ; 0ad3 92 0b
 +
 +
; Clamp position to left wall and set direction to the right
 +
LR  A,(IS)              ; 0ad5 4c
 +
LR  .xpos,A            ; 0ad6 51
 +
 +
; Play sound for hitting wall
 +
LI  SOUND_1kHz          ; 0ad7 20 40
 +
LR  playSound.sound,A  ; 0ad9 53
 +
PI  playSound          ; 0ada 28 0c c8
 +
 +
BR  .setXSpeed          ; 0add 90 e5
 +
 
 +
; -- Check collision with top and bottom walls --
 +
.checkBottomWall:
 +
CLR                      ; 0adf 70
 +
; If ball is moving upwards, branch ahead
 +
AS  .ypos              ; 0ae0 c2
 +
BM  .checkTopWall      ; 0ae1 91 19
 +
; Apply bitmask
 +
NI  MASK_YPOSITION      ; 0ae3 21 3f
 +
; Branch if ypos + lowerBound < 256
 +
AS  .lowerBound        ; 0ae5 c5
 +
BNC  .applySpeedChanges  ; 0ae6 92 27
 +
 +
; We have collided with the lower wall
 +
; Clamp position to the lower wall and set the direction to up
 +
LR  A,.lowerBound      ; 0ae8 45
 +
COM                      ; 0ae9 18
 +
INC                      ; 0aea 1f
 +
AI  MASK_DIRECTION      ; 0aeb 24 80
 +
LR  draw.ypos,A        ; 0aed 52
 +
 +
; Play sound for hitting wall
 +
LI  SOUND_1kHz          ; 0aee 20 40
 +
LR  playSound.sound,A  ; 0af0 53
 +
PI  playSound          ; 0af1 28 0c c8
 +
 
 +
; Set y speed
 +
.setYSpeed:
 +
; yspeed = doBall.speed
 +
SETISAR doBall.speed    ; 0af4 67 69
 +
LR  A,(IS)              ; 0af6 4c
 +
AS  .bounceSpeed        ; 0af7 c0
 +
LR  .bounceSpeed,A      ; 0af8 50
 +
BR  .applySpeedChanges  ; 0af9 90 14
 +
 
 +
; Check if colliding with top wall
 +
.checkTopWall:
 +
SETISARU wall.upper      ; 0afb 66
 +
NI  MASK_YPOSITION      ; 0afc 21 3f
 +
; branch ahead if(topBound < ypos)
 +
COM                      ; 0afe 18
 +
INC                      ; 0aff 1f
 +
SETISARL wall.upper      ; 0b00 6d
 +
AS  (IS)                ; 0b01 cc
 +
BNC  .applySpeedChanges ; 0b02 92 0b
 +
 +
; We have collided with the top wall
 +
; Clamp position to top wall and set direction downwards
 +
LR  A,(IS)              ; 0b04 4c
 +
LR  draw.ypos,A        ; 0b05 52
 +
 
 +
; Play sound for hitting wall
 +
LI  SOUND_1kHz          ; 0b06 20 40
 +
LR  playSound.sound,A  ; 0b08 53
 +
PI  playSound          ; 0b09 28 0c c8
 +
 +
BR  .setYSpeed          ; 0b0c 90 e7
 +
 
 +
; -- Apply velocity changes from wall bounces ----------------------------------
 +
; Variables pertaining to curBall
 +
.thisSpeed    = $5
 +
.thisBitmask  = $7
 +
; Variables pertaining to the ball that shares curBall's speed byte
 +
.otherSpeed  = $4
 +
.otherBitmask = $6
 +
 
 +
.applySpeedChanges:
 +
; Copy lower nybble to upper nybble
 +
LR  A,.bounceSpeed      ; 0b0e 40
 +
SL  4                  ; 0b0f 15
 +
AS  .bounceSpeed        ; 0b10 c0
 +
LR  .bounceSpeed,A      ; 0b11 50
 +
 
 +
; ISAR = index of the speed byte
 +
LR  A,main.curBall      ; 0b12 4b
 +
SR  1                  ; 0b13 12
 +
AI  balls.speed        ; 0b14 24 26
 +
LR  IS,A                ; 0b16 0b
 +
 
 +
; Set the bitmask for the appropriate nybble
 +
LIS  $1                  ; 0b17 71
 +
NS  main.curBall        ; 0b18 fb
 +
LIS  MASK_SPEED          ; 0b19 7f
 +
BNZ  .setSpeedMaskAgain  ; 0b1a 94 02
 +
COM                      ; 0b1c 18
 +
.setSpeedMaskAgain:
 +
LR  .thisBitmask, A    ; 0b1d 57
 +
 
 +
; Set the bitmask for the other ball's speed nybble
 +
COM                      ; 0b1e 18
 +
LR  .otherBitmask,A    ; 0b1f 56
 +
; Save other ball's speed nybble
 +
NS  (IS)                ; 0b20 fc
 +
LR  .otherSpeed,A      ; 0b21 54
 +
 
 +
; Apply the bitmask to get our speed from memory
 +
LR  A,.thisBitmask      ; 0b22 47
 +
NS  (IS)                ; 0b23 fc
 +
LR  .thisSpeed,A        ; 0b24 55
 +
 
 +
; Apply y axis bounce
 +
; Branch ahead if .bounceSpeed.y == 0
 +
LI  MASK_YSPEED        ; 0b25 20 33
 +
NS  .bounceSpeed        ; 0b27 f0
 +
BZ  .saveXAxisBounce    ; 0b28 84 0c
 +
 
 +
; Mask out yspeed from thisSpeed
 +
LI  MASK_XSPEED        ; 0b2a 20 cc
 +
NS  .thisBitmask        ; 0b2c f7
 +
NS  .thisSpeed          ; 0b2d f5
 +
LR  .thisSpeed,A        ; 0b2e 55
 +
 +
; .thisSpeed.y = .bounceSpeed.y
 +
LI  MASK_YSPEED        ; 0b2f 20 33
 +
NS  .bounceSpeed        ; 0b31 f0
 +
AS  .thisSpeed          ; 0b32 c5
 +
NS  .thisBitmask        ; 0b33 f7
 +
LR  .thisSpeed,A        ; 0b34 55
 +
 
 +
; Apply x axis bounce
 +
.saveXAxisBounce:
 +
; Branch ahead if .bounceSpeed.x == 0
 +
LI  MASK_XSPEED        ; 0b35 20 cc
 +
NS  .bounceSpeed        ; 0b37 f0
 +
BZ  .prepSaveBall      ; 0b38 84 0c
 +
 +
; Mask out xspeed from thisSpeed
 +
LI  MASK_YSPEED        ; 0b3a 20 33
 +
NS  .thisBitmask        ; 0b3c f7
 +
NS  .thisSpeed          ; 0b3d f5
 +
LR  .thisSpeed,A        ; 0b3e 55
 +
 
 +
; .thisSpeed.x = .bounceSpeed.x
 +
LI  MASK_XSPEED        ; 0b3f 20 cc
 +
NS  .bounceSpeed        ; 0b41 f0
 +
AS  .thisSpeed          ; 0b42 c5
 +
NS  .thisBitmask        ; 0b43 f7
 +
LR  .thisSpeed,A        ; 0b44 55
 +
 
 +
; Prepare to save ball to array
 +
.prepSaveBall:
 +
; Merge the nybbles back together
 +
LR  A,.thisSpeed        ; 0b45 45
 +
AS  .otherSpeed        ; 0b46 c4
 +
 
 +
; Set speed for saveBall
 +
LR  saveBall.speed,A    ; 0b47 50
 +
 
 +
; It is finished... we can save the results
 +
PI  saveBall            ; 0b48 28 09 a2
 +
 +
; -- Redraw the ball -----------------------------------------------------------
 +
; if(curball <=1)
 +
;  color = ballColors[curBall]
 +
; else
 +
;  color = ballColors[2]
 +
DCI  ballColors          ; 0b4b 2a 08 50
 +
LR  A,main.curBall      ; 0b4e 4b
 +
CI  [MAX_PLAYERS-1]    ; 0b4f 25 01
 +
LIS  2                  ; 0b51 72
 +
BNC  .setColor          ; 0b52 92 02
 +
LR  A,main.curBall      ; 0b54 4b
 +
.setColor:
 +
ADC                      ; 0b55 8e
 +
LR  A, draw.ypos        ; 0b56 42
 +
 
 +
; Mask out the direction
 +
NI  MASK_POSITION      ; 0b57 21 7f
 +
 
 +
; OR in the color
 +
OM                      ; 0b59 8b
 +
LR  draw.ypos, A        ; 0b5a 52
 +
 
 +
; Set drawing parameters
 +
LI  DRAW_RECT          ; 0b5b 20 80
 +
LR  draw.param, A      ; 0b5d 50
 +
 
 +
; Set ball width/height
 +
SETISAR doBall.size      ; 0b5e 67 68
 +
LR  A,(IS)              ; 0b60 4c
 +
LR  draw.width, A      ; 0b61 54
 +
LR  draw.height, A      ; 0b62 55
 +
 
 +
; Do not redraw if explosion flag is set
 +
SETISAR explosionFlag    ; 0b63 67 6a
 +
CLR                      ; 0b65 70
 +
AS  (IS)                ; 0b66 cc
 +
BM  .return            ; 0b67 91 04
 +
 
 +
; Redraw ball
 +
PI  drawBox            ; 0b69 28 08 62
 +
 
 +
collision.return: ; The next function uses this to return as well
 +
.return:
 +
LR  P,K                ; 0b6c 09
 +
POP                      ; 0b6d 1c
 +
; end doBall()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; collision()
 +
;
 +
; Performs ball-ball collision detection against a single ball as specified by
 +
;  the input argument.
 +
;
 +
; The ball specified by the caller is tested against every other active ball to
 +
;  see if they overlap along the x and y axes. If so, and if the ball being
 +
;  tested against is the player's ball, this function jumps directly to
 +
;  gameOver(). Otherwise, the x and y directions and speeds are fiddled with to
 +
;  make them bounce off each other.
 +
 
 +
; == Arguments ==
 +
; main.curBall = $b
 +
 
 +
; == Locals ==
 +
; testBall = 071
 +
mainBall.xpos = $1
 +
mainBall.ypos = $2
 +
 
 +
; == Entry Point ==
 +
collision: subroutine
 +
LR  K,P                ; 0b6e 08
 +
 
 +
; setting up the collision loop counter
 +
; testBall = (delayIndex & 0x0F) + 1
 +
SETISAR delayIndex      ; 0b6f 65 6f
 +
LI  %00001111          ; 0b71 20 0f
 +
NS  (IS)                ; 0b73 fc
 +
SETISAR testBall        ; 0b74 67 69
 +
INC                      ; 0b76 1f
 +
LR  (IS),A              ; 0b77 5c
 +
 
 +
.testBallLoop:
 +
; loopCount--
 +
SETISAR testBall        ; 0b78 67 69
 +
DS  (IS)                ; 0b7a 3c
 +
 
 +
; if(testBall < 0), return
 +
BM  collision.return; 0b7b 91 f0
 +
 
 +
; if(testBall == curBall), skip and go to next ball
 +
LR  A,(IS)              ; 0b7d 4c
 +
XS  main.curBall        ; 0b7e eb
 +
BZ  .testBallLoop      ; 0b7f 84 f8
 +
 
 +
; Check if we're in 2-player mode
 +
SETISARL gameMode        ; 0b81 6d
 +
LIS  $1                  ; 0b82 71
 +
NS  (IS)                ; 0b83 fc
 +
; If so, skip ahead
 +
BNZ  .getBallPosition    ; 0b84 94 07
 +
 +
; If not, check if the loop counter is a player's ball
 +
SETISARL testBall        ; 0b86 69
 +
LR  A,(IS)              ; 0b87 4c
 +
CI  [MAX_PLAYERS-1]    ; 0b88 25 01
 +
; If so, skip the current ball
 +
BZ  .testBallLoop ; 0b8a 84 ed
 +
 
 +
.getBallPosition:
 +
; r1 = xpos[curBall]
 +
LI  balls.xpos          ; 0b8c 20 10
 +
AS  main.curBall        ; 0b8e cb
 +
LR  IS,A                ; 0b8f 0b
 +
LR  A,(IS)              ; 0b90 4c
 +
; Mask out the direction
 +
NI  MASK_POSITION      ; 0b91 21 7f
 +
LR  mainBall.xpos,A    ; 0b93 51
 +
 +
; r2 = ypos[curBall]
 +
LR  A,IS                ; 0b94 0a
 +
AI  MAX_BALLS          ; 0b95 24 0b
 +
LR  IS,A                ; 0b97 0b
 +
LR  A,(IS)              ; 0b98 4c
 +
; Mask out the direction
 +
NI  MASK_YPOSITION      ; 0b99 21 3f
 +
LR  mainBall.ypos,A    ; 0b9b 52
 +
 +
; -- Test collision along x axis -----------------------------------------------
 +
.xDelta = $1
 +
 
 +
; mainBall.xpos-testBall.xpos
 +
SETISAR testBall        ; 0b9c 67 69
 +
LI  balls.xpos          ; 0b9e 20 10
 +
AS  (IS)                ; 0ba0 cc
 +
LR  IS,A                ; 0ba1 0b
 +
LR  A,(IS)              ; 0ba2 4c
 +
NI  MASK_POSITION      ; 0ba3 21 7f
 +
COM                      ; 0ba5 18
 +
INC                      ; 0ba6 1f
 +
AS  mainBall.xpos      ; 0ba7 c1
 +
 +
; Save flags
 +
LR  J,W                ; 0ba8 1e
 +
; Keep results if (mainBall.xpos >= testBall.xpos)
 +
BP  .saveXdelta        ; 0ba9 81 03
 +
; Otherwise negate the results
 +
COM                      ; 0bab 18
 +
INC                      ; 0bac 1f
 +
 +
.saveXdelta:
 +
; abs(mainBall.x - testBall.x)
 +
LR  .xDelta,A          ; 0bad 51
 +
 +
; branch ahead if testBall is not a player ball
 +
LR  A,IS                ; 0bae 0a
 +
CI  [balls.xpos+MAX_PLAYERS-1] ; 0baf 25 11
 +
BNC  .useEnemySize      ; 0bb1 92 0b
 +
 
 +
; branch ahead if mainBall.xpos < testBall.xpos
 +
;  or: if mainBall is left of testBall
 +
LR  W,J                ; 0bb3 1d    ; Reuse flags from earlier
 +
BM  .useEnemySize      ; 0bb4 91 08
 +
 +
; Get player ball width
 +
LI  MASK_PLAYER_SIZE    ; 0bb6 20 c0
 +
NS  main.gameSettings  ; 0bb8 fa
 +
SR  1                  ; 0bb9 12
 +
SR  1                  ; 0bba 12
 +
BR  .testXaxis          ; 0bbb 90 04
 +
 
 +
; or get enemy ball width
 +
.useEnemySize:
 +
LI  MASK_ENEMY_SIZE    ; 0bbd 20 30
 +
NS  main.gameSettings  ; 0bbf fa
 +
 
 +
.testXaxis:
 +
SR  4                  ; 0bc0 14
 +
 
 +
; xDelta - testBall.width
 +
COM                      ; 0bc1 18
 +
INC                      ; 0bc2 1f
 +
AS  .xDelta            ; 0bc3 c1
 +
 
 +
; if (xDelta >= testBall.width)
 +
;  continue on to next ball
 +
BP  .testBallLoop            ; 0bc4 81 b3
 +
; else
 +
;  test the y axis collision
 +
 
 +
; -- Test collision on the y axis ----------------------------------------------
 +
.yDelta = $2
 +
 
 +
; mainBall.ypos-testBall.ypos
 +
LR  A,IS                ; 0bc6 0a
 +
AI  MAX_BALLS          ; 0bc7 24 0b
 +
LR  IS,A                ; 0bc9 0b
 +
LR  A,(IS)              ; 0bca 4c
 +
NI  MASK_YPOSITION      ; 0bcb 21 3f
 +
COM                      ; 0bcd 18
 +
INC                      ; 0bce 1f
 +
AS  mainBall.ypos      ; 0bcf c2
 +
 +
; Save flags
 +
LR  J,W                ; 0bd0 1e
 +
; Keep results if (mainBall.ypos >= testBall.ypos)
 +
BP  .saveYdelta        ; 0bd1 81 03
 +
; Otherwise negate the results
 +
COM                      ; 0bd3 18
 +
INC                      ; 0bd4 1f
 +
.saveYdelta:
 +
; abs(mainBall.ypos-testBall.ypos)
 +
LR  .yDelta,A          ; 0bd5 52
 +
 
 +
; branch ahead if testBall is not a player ball
 +
LR  A,IS                ; 0bd6 0a
 +
CI  [balls.ypos+MAX_PLAYERS-1]; 0bd7 25 1c
 +
BNC  .useEnemySize2    ; 0bd9 92 0b
 +
 
 +
; branch ahead if mainBall.ypos < testBall.ypos
 +
;  or: if mainBall is north of testBall
 +
LR  W,J                ; 0bdb 1d    ; Reuse flags from earlier
 +
BM  .useEnemySize2      ; 0bdc 91 08
 +
 +
; Get player ball width
 +
LI  MASK_PLAYER_SIZE    ; 0bde 20 c0
 +
NS  main.gameSettings  ; 0be0 fa
 +
SR  1                  ; 0be1 12
 +
SR  1                  ; 0be2 12
 +
BR  .testYaxis          ; 0be3 90 04
 +
; or get enemy ball width
 +
.useEnemySize2:
 +
LI  MASK_ENEMY_SIZE    ; 0be5 20 30
 +
NS  main.gameSettings  ; 0be7 fa
 +
.testYaxis:
 +
SR  4                  ; 0be8 14
 +
 +
; yDelta - tempWidth
 +
COM                      ; 0be9 18
 +
INC                      ; 0bea 1f
 +
AS  .yDelta            ; 0beb c2
 +
 
 +
; if (yDelta >= tempWidth)
 +
;  continue on to next ball
 +
BP  .testBallLoop      ; 0bec 81 8b
 +
; else
 +
;  handle the collision that just happened
 +
 
 +
; -- If we got to this point, a collision has happened -------------------------
 +
 +
; Check if the collision was with a player
 +
;  If so, game over
 +
;  Else, skip ahead
 +
SETISAR testBall        ; 0bee 67 69
 +
LR  A,(IS)              ; 0bf0 4c
 +
CI  [MAX_PLAYERS-1]    ; 0bf1 25 01
 +
BNC  .makeNoise        ; 0bf3 92 04
 +
; Game over
 +
JMP  gameOver            ; 0bf5 29 0e 44
 +
 
 +
.makeNoise:
 +
; Play sound
 +
LI  SOUND_500Hz        ; 0bf8 20 80
 +
LR  playSound.sound,A  ; 0bfa 53
 +
PI  playSound          ; 0bfb 28 0c c8
 +
 +
; RNG for random bounce trajectory
 +
PI  rand                ; 0bfe 28 08 c1
 +
 
 +
; branch ahead if(yDelta < 1)
 +
LR  A,.yDelta          ; 0c01 42
 +
CI  1                  ; 0c02 25 01
 +
BC  .randYdirection    ; 0c04 82 3c
 +
 
 +
; -- Fiddle with the x direction -----------------------------------------------
 +
.speedThing = $8
 +
.SPEED_ADJUST = $44
 +
.randBall = $0 ; TODO: Give this variable a better name (it's not random)
 +
 +
; Randomize x direction of mainBall
 +
; Set ISAR to xpos[curBall]
 +
LI  balls.xpos          ; 0c06 20 10
 +
AS  main.curBall        ; 0c08 cb
 +
LR  IS,A                ; 0c09 0b
 +
; XOR the direction with the RNG
 +
LI  MASK_DIRECTION      ; 0c0a 20 80
 +
NS  RNG.regHi          ; 0c0c f6
 +
XS  (IS)                ; 0c0d ec
 +
LR  (IS),A              ; 0c0e 5c
 +
; Save flags from (MASK_DIRECTION xor RNG)
 +
; Note: These flags do not appear to be used
 +
LR  J,W                ; 0c0f 1e
 +
 
 +
; Randomize x direction of testBall
 +
; ISAR = balls.xpos + testBall
 +
SETISAR testBall        ; 0c10 67 69
 +
LI  balls.xpos          ; 0c12 20 10
 +
AS  (IS)                ; 0c14 cc
 +
LR  IS,A                ; 0c15 0b
 +
; Add RNG.lo to the direction
 +
LI  MASK_DIRECTION      ; 0c16 20 80
 +
NS  RNG.regLo          ; 0c18 f7
 +
AS  (IS)                ; 0c19 cc
 +
LR  (IS),A              ; 0c1a 5c
 +
 +
; We'll be using this later to adjust the speed
 +
LI  .SPEED_ADJUST      ; 0c1b 20 44
 +
LR  .speedThing,A      ; 0c1d 58
 +
 
 +
; randBall = mainBall
 +
;  The branch that fiddles the y direction sets this to testBall
 +
LR  A, main.curBall    ; 0c1e 4b
 +
LR  .randBall,A        ; 0c1f 50
 +
 
 +
; -- Fiddle with the speed -----------------------------------------------------
 +
.thisBitmask = $3
 +
.otherSpeed = $4
 +
 
 +
.checkMode:
 +
; If MODE_BOUNCE_MASK is set, we mess with the speed
 +
;  Note: This bit is set in shuffleGame(), and is cleared in explode()
 +
SETISAR gameMode        ; 0c20 67 6d
 +
CLR                      ; 0c22 70
 +
AS  (IS)                ; 0c23 cc
 +
BP  .changeSpeed        ; 0c24 81 04
 +
; Else, test the next ball
 +
JMP  .testBallLoop      ; 0c26 29 0b 78
 +
 
 +
.changeSpeed:
 +
; ISAR = balls.speed + randBall/2
 +
LR  A,.randBall        ; 0c29 40
 +
SR  1                  ; 0c2a 12
 +
AI  balls.speed        ; 0c2b 24 26
 +
LR  IS,A                ; 0c2d 0b
 +
 
 +
; Conjure up the bitmask to extract randBall's speed
 +
LIS  $1                  ; 0c2e 71
 +
NS  .randBall          ; 0c2f f0
 +
LIS  MASK_SPEED          ; 0c30 7f
 +
BNZ  .getThisBitmask    ; 0c31 94 02
 +
COM                      ; 0c33 18
 +
.getThisBitmask:
 +
; Save randBall's speed bitmask
 +
LR  .thisBitmask,A      ; 0c34 53
 +
; Temp storage for the other speed bitfield
 +
COM                      ; 0c35 18
 +
NS  (IS)                ; 0c36 fc
 +
LR  .otherSpeed,A      ; 0c37 54
 +
 +
; Get the speed bitfield for randBall
 +
LR  A,.thisBitmask      ; 0c38 43
 +
NS  (IS)                ; 0c39 fc
 +
; Add .speedThing to it, and clean up with the bitmask
 +
AS  .speedThing        ; 0c3a c8
 +
NS  .thisBitmask        ; 0c3b f3
 +
; Merge the two speed bitfields and save the result
 +
AS  .otherSpeed        ; 0c3c c4
 +
LR  (IS),A              ; 0c3d 5c
 +
 +
; Return (don't process any more collisions for mainBall)
 +
JMP  collision.return            ; 0c3e 29 0b 6c
 +
 
 +
; -- Fiddle with y direction ---------------------------------------------------
 +
.randYdirection:
 +
; randBall = testBall
 +
; ISAR = balls.ypos + randBall
 +
SETISAR testBall        ; 0c41 67 69
 +
LR  A,(IS)              ; 0c43 4c
 +
LR  .randBall,A        ; 0c44 50
 +
AI  balls.ypos          ; 0c45 24 1b
 +
LR  IS,A                ; 0c47 0b
 +
 
 +
; Flip the y direction of testBall
 +
LI  MASK_DIRECTION      ; 0c48 20 80
 +
XS  (IS)                ; 0c4a ec
 +
LR  (IS),A              ; 0c4b 5c
 +
; Save flags for later
 +
LR  J,W                ; 0c4c 1e
 +
 
 +
; ISAR = balls.ypos + mainBall
 +
LI  balls.ypos          ; 0c4d 20 1b
 +
AS  main.curBall        ; 0c4f cb
 +
LR  IS,A                ; 0c50 0b
 +
 
 +
; Set mainBall's direction to down
 +
LR  A,(IS)              ; 0c51 4c
 +
OI  MASK_DIRECTION      ; 0c52 22 80
 +
 +
; Load flags from earlier
 +
;  if testBall went down, mainBall goes up
 +
;  if testBall went up, mainBall goes down
 +
LR  W,J                ; 0c54 1d
 +
BP  .setYdirection      ; 0c55 81 03
 +
NI  MASK_YPOSITION      ; 0c57 21 3f
 +
.setYdirection:
 +
LR  (IS),A              ; 0c59 5c
 +
 +
; We'll be using this later to adjust the velocity
 +
LI  .SPEED_ADJUST      ; 0c5a 20 44
 +
LR  .speedThing,A      ; 0c5c 58
 +
 +
; Go to the "fiddle with speed" section of this function
 +
BR  .checkMode          ; 0c5d 90 c2
 +
; end of collision()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; setWalls()
 +
;
 +
; Sets the positions of the walls along one axis given an input range.
 +
 
 +
; == Arguments ==
 +
; *walls = ISAR
 +
walls.max = $1
 +
walls.min = $2
 +
 
 +
; == Constants ==
 +
 
 +
 
 +
setWalls: subroutine
 +
LR  K,P                ; 0c5f 08
 +
 
 +
; == Local ==
 +
.tempWall = $4
 +
 
 +
.reroll:
 +
; Reroll RNG until r6 is non-zero
 +
PI  rand                ; 0c60 28 08 c1
 +
CLR                      ; 0c63 70
 +
AS  RNG.regHi          ; 0c64 c6
 +
BZ  .reroll            ; 0c65 84 fa
 +
 +
; Make sure the RNG is in range, depending on the axis being set
 +
; if(r1 == 0x58) ; x axis case
 +
;  if(RNG > 0x12)
 +
;  go back and reroll
 +
; else if(RNG > 0x0B) ; y axis case
 +
;  go back and reroll
 +
LR  A,walls.max        ; 0c67 41
 +
CI  WALL_XMAX          ; 0c68 25 58
 +
 
 +
LR  A, RNG.regHi        ; 0c6a 46
 +
BNZ  .clampY            ; 0c6b 94 05
 +
 
 +
CI  WALL_X_OFFSET_MAX  ; 0c6d 25 12
 +
BR  .clampX            ; 0c6f 90 03
 +
 
 +
.clampY:
 +
CI  WALL_Y_OFFSET_MAX  ; 0c71 25 0b
 +
.clampX:
 +
BNC  .reroll            ; 0c73 92 ec
 +
 
 +
; Get the base value for the right/lower wall
 +
;  Note: the greater this number is, the more to the left (or top) this wall
 +
;  is. (Unintuitive. Works opposite of how the upper and left walls work.)
 +
; .tempWall = -(max-rng+1)
 +
COM                      ; 0c75 18
 +
INC                      ; 0c76 1f
 +
INC                      ; 0c77 1f
 +
AS  walls.max          ; 0c78 c1
 +
COM                      ; 0c79 18
 +
INC                      ; 0c7a 1f
 +
LR  .tempWall,A        ; 0c7b 54
 +
 +
; Adjust the right/lower wall according to the enemy's size
 +
; wall.right(or lower)Enemy = playerSize + .tempWall
 +
LI  MASK_ENEMY_SIZE    ; 0c7c 20 30
 +
NS  main.gameSettings  ; 0c7e fa
 +
SR  4                  ; 0c7f 14
 +
AS  .tempWall          ; 0c80 c4
 +
LR  (IS)+,A            ; 0c81 5d
 +
 +
; Adjust the right/lower wall according to the player's size
 +
; wall.right(or lower)Player = playerSize + .tempWall
 +
LI  MASK_PLAYER_SIZE    ; 0c82 20 c0
 +
NS  main.gameSettings  ; 0c84 fa
 +
SR  4                  ; 0c85 14
 +
SR  1                  ; 0c86 12
 +
SR  1                  ; 0c87 12
 +
AS  .tempWall          ; 0c88 c4
 +
LR  (IS)+,A            ; 0c89 5d
 +
 +
; Set the left or top boundary
 +
; ISAR++ = walls.min + RNG
 +
LR  A,RNG.regHi        ; 0c8a 46
 +
AS  walls.min          ; 0c8b c2
 +
LR  (IS)+,A            ; 0c8c 5d
 +
 
 +
; Exit
 +
LR  P,K                ; 0c8d 09
 +
POP                      ; 0c8e 1c
 +
; end of setWalls()
 +
;-------------------------------------------------------------------------------
 +
 +
;-------------------------------------------------------------------------------
 +
; flash()
 +
;  Mid-Level Function
 +
;
 +
; UNUSED
 +
;
 +
; Makes the screen flash -- possibly an old form of the death animation. Working
 +
;  off of that assumption, we will assume that this function would have been
 +
;  called after a player collision in the ball-ball collision function.
 +
 
 +
; == Arguments ==
 +
; testBall = 071
 +
 
 +
; No Returns
 +
 
 +
flash: subroutine
 +
LR  K,P                ; 0c8f 08
 +
 
 +
; == Locals ==
 +
.loopCount = $9
 +
.NUM_LOOPS = $25
 +
 +
LI  .NUM_LOOPS          ; 0c90 20 25
 +
LR  .loopCount, A      ; 0c92 59
 +
 
 +
; Set flash color/sound value depending on value of o71 (who died?)
 +
SETISAR testBall        ; 0c93 67 69
 +
LIS  $1                  ; 0c95 71
 +
NS  (IS)-              ; 0c96 fe
 +
LI  SOUND_500Hz        ; 0c97 20 80
 +
BZ  .setSound          ; 0c99 84 03
 +
LI  SOUND_120Hz        ; 0c9b 20 c0
 +
.setSound:         
 +
LR  (IS), A            ; 0c9d 5c
 +
LR  draw.ypos, A        ; 0c9e 52
 +
 
 +
; Loop back here to reset the sound and row attribute color to the above value
 +
.loopResetColor:         
 +
LR  A,(IS)              ; 0c9f 4c
 +
 
 +
; Loop back here to keep the sound and row attribute color cleared
 +
.loopClearColor:         
 +
; Set ypos/color
 +
LR  draw.ypos, A        ; 0ca0 52
 +
 
 +
; Make sound
 +
; NOTE: sound is not played if curBall is one of the player balls
 +
LR  A,(IS)              ; 0ca1 4c
 +
LR  playSound.sound,A  ; 0ca2 53
 +
PI  playSound          ; 0ca3 28 0c c8
 +
 +
LISL 0                  ; 0ca6 68 ; ISAR = 070 ; Temp?
 +
; Set xpos to attribute column
 +
LI  DRAW_ATTR_X        ; 0ca7 20 7d
 +
LR  draw.xpos, A        ; 0ca9 51
 +
; Set width
 +
LIS  DRAW_ATTR_W        ; 0caa 72
 +
LR  draw.width, A      ; 0cab 54
 +
; Set height
 +
LI  DRAW_SCREEN_H      ; 0cac 20 40
 +
LR  draw.height, A      ; 0cae 55
 +
; Set rendering parameter
 +
LI  DRAW_ATTRIBUTE      ; 0caf 20 c0
 +
LR  draw.param, A      ; 0cb1 50
 +
PI  drawBox            ; 0cb2 28 08 62
 +
 +
; Clear sound
 +
CLR                      ; 0cb5 70
 +
OUTS 5                  ; 0cb6 b5
 +
 +
; Delay
 +
LIS  $b                  ; 0cb7 7b
 +
LR  delay.count, A      ; 0cb8 50
 +
PI  delayVariable      ; 0cb9 28 09 9a
 +
 
 +
; loopCount--
 +
;  exit it less than zero
 +
DS  .loopCount          ; 0cbc 39
 +
BM  .exit              ; 0cbd 91 08
 +
 +
; if (timer is even)
 +
;  ypos/color = (ISAR)
 +
LIS  $1                  ; 0cbf 71
 +
NS  .loopCount          ; 0cc0 f9
 +
CLR                      ; 0cc1 70
 +
BZ  .loopResetColor    ; 0cc2 84 dc
 +
; else
 +
;  ypos/color = 0
 +
BR  .loopClearColor    ; 0cc4 90 db
 +
 
 +
.exit:   
 +
LR  P,K                ; 0cc6 09
 +
POP                      ; 0cc7 1c
 +
; end flash()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; playSound(ball, sound)
 +
;  Leaf Function
 +
;
 +
; Make a ticking noise when the balls collide with something.
 +
 
 +
; == Arguments ==
 +
playSound.sound = 3
 +
; main.curBall = $b
 +
 
 +
; == Entry Point ==
 +
playSound: subroutine
 +
; if(curBall >= MAX_PLAYERS)
 +
LR  A, main.curBall    ; 0cc8 4b
 +
CI  [MAX_PLAYERS-1]    ; 0cc9 25 01
 +
BC  playSound.exit      ; 0ccb 82 03
 +
; then play the sound
 +
LR  A, playSound.sound  ; 0ccd 43
 +
OUTS 5                  ; 0cce b5
 +
 +
playSound.exit:         
 +
POP                      ; 0ccf 1c
 +
; end playSound()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; init()
 +
;  Top-Level Procedure
 +
;
 +
; For simplicity's sake, this disassembly will divide the top-level thread into
 +
;  separate "functions", even though they are not callable and the code just
 +
;  flows and jumps from one block to another.
 +
;
 +
; To initialize the game, this procedure does some initial bookkeeping with the
 +
;  scratchpad, I/O, and display, and then asks the player to select the game
 +
;  mode with the question "G?" The four selectable game types are:
 +
;
 +
; 1 - Slow, 1 player
 +
; 2 - Slow, 2 players
 +
; 3 - Fast, 1 player
 +
; 4 - Fast, 2 players
 +
 
 +
init: subroutine
 +
SETISAR RNG.seedLo      ; 0cd0 67 6f
 +
 
 +
; Enable data from controllers
 +
LI  $40                ; 0cd2 20 40
 +
OUTS 0                  ; 0cd4 b0
 +
 +
; Seed RNG from uninitialized ports
 +
INS  4                  ; 0cd5 a4
 +
LR  (IS)-,A            ; 0cd6 5e
 +
INS  5                  ; 0cd7 a5
 +
LR  (IS)-,A            ; 0cd8 5e
 +
 +
; Clear BIOS stack pointer at 073
 +
;  This game does not use the BIOS's stack functions
 +
LISL 3                  ; 0cd9 6b
 +
CLR                      ; 0cda 70
 +
LR  (IS),A              ; 0cdb 5c
 +
; The BIOS already intialized the rest of the scratchpad to zero
 +
 +
; Clear port
 +
OUTS 0                  ; 0cdc b0
 +
 
 +
; Clear screen
 +
; Set properties
 +
LI  DRAW_RECT          ; 0cdd 20 80
 +
LR  draw.param, A      ; 0cdf 50
 +
; Set x and y pos
 +
CLR                      ; 0ce0 70
 +
LR  draw.xpos, A        ; 0ce1 51
 +
LR  draw.ypos, A        ; 0ce2 52
 +
; Set width
 +
LI  DRAW_SCREEN_W      ; 0ce3 20 80
 +
LR  draw.width, A      ; 0ce5 54
 +
; Set height
 +
LI  DRAW_SCREEN_H      ; 0ce6 20 40
 +
LR  draw.height, A      ; 0ce8 55
 +
 
 +
PI  drawBox            ; 0ce9 28 08 62
 +
 
 +
; Set row attributes
 +
; Set rendering properties, ypos, and color
 +
LI  DRAW_ATTRIBUTE      ; 0cec 20 c0
 +
LR  draw.param, A      ; 0cee 50
 +
LR  draw.ypos, A        ; 0cef 52
 +
; Set width
 +
LIS  DRAW_ATTR_W        ; 0cf0 72
 +
LR  draw.width, A      ; 0cf1 54
 +
; xpos = attribute column
 +
LI  DRAW_ATTR_X        ; 0cf2 20 7d
 +
LR  draw.xpos, A        ; 0cf4 51
 +
; Height and ypos are retained from previous write
 +
PI  drawBox            ; 0cf5 28 08 62
 +
 
 +
; Draw the "G?" screen
 +
.G_X = $30
 +
.G_Y = $1B
 +
.Q_X = $35
 +
 
 +
; Set char
 +
LIS  CHAR_G              ; 0cf8 7a
 +
LR  draw.param, A      ; 0cf9 50
 +
; Set xpos
 +
LI  .G_X                ; 0cfa 20 30
 +
LR  draw.xpos, A        ; 0cfc 51
 +
; Set ypos and color
 +
LI  RED | .G_Y          ; 0cfd 20 9b
 +
LR  draw.ypos, A        ; 0cff 52
 +
; Set width
 +
LIS  CHAR_WIDTH          ; 0d00 74
 +
LR  draw.width, A      ; 0d01 54
 +
; Set height
 +
LIS  CHAR_HEIGHT        ; 0d02 75
 +
LR  draw.height, A      ; 0d03 55
 +
 
 +
PI  drawChar            ; 0d04 28 08 58
 +
 +
; Set char
 +
LIS  CHAR_QMARK          ; 0d07 7b
 +
LR  draw.param, A      ; 0d08 50
 +
; Set xpos
 +
LI  .Q_X                ; 0d09 20 35
 +
LR  draw.xpos, A        ; 0d0b 51
 +
 
 +
PI  drawChar            ; 0d0c 28 08 58
 +
 +
; Wait 10 seconds for input
 +
PI  menu                ; 0d0f 28 08 f0
 +
; The button press is returned in A (default is 1)
 +
 
 +
; Use a table to put the number of the button pressed into gameMode
 +
SETISAR gameMode        ; 0d12 67 6d
 +
SR  1                  ; 0d14 12
 +
; DC was set in the menu
 +
ADC                      ; 0d15 8e
 +
LM                      ; 0d16 16
 +
LR  (IS),A              ; 0d17 5c
 +
 
 +
; Continue on to next procedure
 +
 +
;-------------------------------------------------------------------------------
 +
; shuffleGame()
 +
;  Top-Level Procedure
 +
;
 +
; This function randomizes the game parameters such as player size, enemy size,
 +
;  player speed, enemy speed, the upper six bits of gameMode, and the walls.
 +
 
 +
shuffleGame: subroutine
 +
; Preserve the player and game speed bits of gameMode
 +
SETISAR gameMode        ; 0d18 67 6d
 +
LR  A,(IS)              ; 0d1a 4c
 +
NI  MODE_CHOICE_MASK    ; 0d1b 21 03
 +
LR  (IS),A              ; 0d1d 5c
 +
 
 +
.reroll:
 +
; Array of bitmaks to be used in the following series of tests
 +
DCI  gameModeMasks      ; 0d1e 2a 08 43
 +
 +
; Get a random number
 +
PI  rand                ; 0d21 28 08 c1
 +
 +
; Test to see if the number is a valid game setting
 +
.temp = $8
 +
 
 +
; Put bits 6 and 7 of RNG into .temp (for player ball size)
 +
LM                      ; 0d24 16
 +
NS  RNG.regHi          ; 0d25 f6
 +
LR  .temp,A            ; 0d26 58
 +
 +
; Add bits 4 and 5 of RNG to the previous result (for enemy ball size)
 +
LM                      ; 0d27 16
 +
NS  RNG.regHi          ; 0d28 f6
 +
SL  1                  ; 0d29 13
 +
SL  1                  ; 0d2a 13
 +
AS  .temp              ; 0d2b c8
 +
; if(playerSize + enemySize < 4), then reroll
 +
BNC  .reroll            ; 0d2c 92 f1
 +
 +
; Test if at least one of bits 2 and 3 of RNG are set
 +
LM                      ; 0d2e 16
 +
NS  RNG.regHi          ; 0d2f f6
 +
; if(playerSpeed == 0), then reroll
 +
BZ  .reroll            ; 0d30 84 ed
 +
 
 +
; Test if at least one of bits 0 and 1 of RNG are set
 +
LM                      ; 0d32 16
 +
NS  RNG.regHi          ; 0d33 f6
 +
; if(enemySpeed == 0), then reroll
 +
BZ  .reroll            ; 0d34 84 e9
 +
 
 +
; RNG.regHi contains a valid value, so we can use it
 +
LR  A, RNG.regHi        ; 0d36 46
 +
LR  main.gameSettings,A ; 0d37 5a
 +
 
 +
; Put the upper six bits of the RNG into gameMode
 +
LM                      ; 0d38 16
 +
NS  RNG.regLo          ; 0d39 f7
 +
AS  (IS)                ; 0d3a cc
 +
LR  (IS)-,A            ; 0d3b 5e
 +
; Note: This ISAR post-decrement puts the ISAR on player 2's high score.
 +
;  This is not utilized.
 +
 
 +
; DC = (enemySpeed)*2
 +
; Note: This array is never read from.
 +
DCI  unusedSpeedTable    ; 0d3c 2a 08 48
 +
LIS  MASK_ENEMY_SPEED    ; 0d3f 73
 +
NS  main.gameSettings  ; 0d40 fa
 +
SL  1                  ; 0d41 13
 +
ADC                      ; 0d42 8e
 +
; Note: Perhaps the 2 bytes from this table were meant to be loaded into the
 +
;  space that is now reserved for player 2's high score.
 +
 
 +
; Set playfield walls
 +
; Set playfield walls for x axis
 +
LI  WALL_XMAX          ; 0d43 20 58
 +
LR  walls.max,A        ; 0d45 51
 +
LI  WALL_MIN            ; 0d46 20 10
 +
LR  walls.min,A        ; 0d48 52
 +
SETISAR wall.rightEnemy  ; 0d49 66 68
 +
PI  setWalls            ; 0d4b 28 0c 5f
 +
 +
; Set playfield walls for y axis
 +
LI  WALL_YMAX          ; 0d4e 20 38
 +
LR  walls.max,A        ; 0d50 51
 +
PI  setWalls            ; 0d51 28 0c 5f
 +
 +
; Continue on to next procedure
 +
 
 +
;-------------------------------------------------------------------------------
 +
; restartGame()
 +
;  Top-Level Procedure
 +
;
 +
; Does prep work necessary to restart (or start the game), such as drawing the
 +
;  playfield, clearing the timer, spawning the players and the first ball, and
 +
;  making sure the explosion flag is clear.
 +
 
 +
restartGame: subroutine
 +
 
 +
; Draw playfield walls
 +
; Set rendering properties
 +
LI  DRAW_RECT          ; 0d54 20 80
 +
LR  draw.param, A      ; 0d56 50
 +
; Set x pos
 +
LI  FIELD_CORNER        ; 0d57 20 10
 +
LR  draw.xpos, A        ; 0d59 51
 +
; Set color (and ypos)
 +
AI  RED                ; 0d5a 24 80
 +
LR  draw.ypos, A        ; 0d5c 52
 +
; Set width
 +
LI  FIELD_WIDTH        ; 0d5d 20 49
 +
LR  draw.width, A      ; 0d5f 54
 +
; Set height
 +
LI  FIELD_HEIGHT        ; 0d60 20 29
 +
LR  draw.height, A      ; 0d62 55
 +
; Draw box
 +
PI  drawBox            ; 0d63 28 08 62
 +
 
 +
; Draw inner box of playfield
 +
.tempSize = $3
 +
 
 +
; xpos = wall.left
 +
SETISAR wall.left        ; 0d66 66 6a
 +
LR  A,(IS)              ; 0d68 4c
 +
LR  draw.xpos, A        ; 0d69 51
 +
 
 +
; width = -(wall.left + wall.rightEnemy) + enemySize
 +
SETISARL wall.rightEnemy ; 0d6a 68
 +
AS  (IS)                ; 0d6b cc
 +
COM                      ; 0d6c 18
 +
INC                      ; 0d6d 1f
 +
LR  draw.width, A      ; 0d6e 54
 +
 
 +
LI  MASK_ENEMY_SIZE    ; 0d6f 20 30
 +
NS  main.gameSettings  ; 0d71 fa
 +
SR  4                  ; 0d72 14
 +
LR  .tempSize,A        ; 0d73 53
 +
 
 +
AS  draw.width          ; 0d74 c4
 +
LR  draw.width, A      ; 0d75 54
 +
 +
; Set ypos (color is blank)
 +
SETISARL wall.upper      ; 0d76 6d
 +
LR  A,(IS)              ; 0d77 4c
 +
LR  draw.ypos, A        ; 0d78 52
 +
 +
; height = -(wall.top - wall.lowerEnemy) + enemySize
 +
SETISARL wall.lowerEnemy ; 0d79 6b
 +
AS  (IS)                ; 0d7a cc
 +
COM                      ; 0d7b 18
 +
INC                      ; 0d7c 1f
 +
AS  .tempSize          ; 0d7d c3
 +
LR  draw.height, A      ; 0d7e 55
 +
 +
; Set rendering properties
 +
LI  DRAW_RECT          ; 0d7f 20 80
 +
LR  draw.param, A      ; 0d81 50
 +
 
 +
; Draw
 +
PI  drawBox            ; 0d82 28 08 62
 +
 +
; Clear timer
 +
SETISAR timer.hi        ; 0d85 66 6e
 +
CLR                      ; 0d87 70
 +
LR  (IS)+,A            ; 0d88 5d
 +
LR  (IS)+,A            ; 0d89 5d
 +
 
 +
; Spawn the balls
 +
; Spawn the players
 +
CLR                      ; 0d8a 70
 +
.spawnLoop:         
 +
LR  main.curBall, A    ; 0d8b 5b
 +
PI  spawnBall          ; 0d8c 28 09 c2
 +
 +
LR  A, main.curBall    ; 0d8f 4b
 +
INC                      ; 0d90 1f
 +
CI  [MAX_PLAYERS-1]    ; 0d91 25 01
 +
BC  .spawnLoop          ; 0d93 82 f7
 +
 
 +
; Spawn the first enemy ball
 +
SETISAR balls.count      ; 0d95 65 6e
 +
LR  (IS),A              ; 0d97 5c
 +
LR  main.curBall, A    ; 0d98 5b
 +
PI  spawnBall          ; 0d99 28 09 c2
 +
 
 +
; Clear the the explosion flag
 +
SETISAR explosionFlag    ; 0d9c 67 6a
 +
CLR                      ; 0d9e 70
 +
LR  (IS),A              ; 0d9f 5c
 +
 
 +
; Continue on to next procedure
 +
 
 +
;-------------------------------------------------------------------------------
 +
; mainLoop()
 +
;  Top-Level Procedure
 +
;
 +
; Clears the sound, draws the timer, runs a delay function, processes the enemy
 +
;  balls, processes the player balls, and repeats until somebody loses.
 +
;
 +
; Note that since the Channel F lacks vsync or any sort of interval timer, that
 +
;  the game needs to use a delay function to keep the game running at a
 +
;  consistent and reasonable speed.
 +
 
 +
mainLoop: subroutine
 +
; Clear sound
 +
CLR                      ; 0da0 70
 +
OUTS 5                  ; 0da1 b5
 +
 +
; Change delay index according to the timer
 +
; if (timer.hi > 10)
 +
;  delay index = 10
 +
; else
 +
; delay index = timer.hi + 1
 +
SETISAR timer.hi        ; 0da2 66 6e
 +
LR  A,(IS)+            ; 0da4 4d
 +
INC                      ; 0da5 1f
 +
CI  [MAX_BALLS-1]      ; 0da6 25 0a
 +
BC  .setDelay          ; 0da8 82 02
 +
LIS  [MAX_BALLS-1]      ; 0daa 7a
 +
.setDelay:
 +
SETISARU delayIndex      ; 0dab 65
 +
LR  (IS),A              ; 0dac 5c
 +
SETISARU timer.lo        ; 0dad 66
 +
 
 +
; Increment 16-bit BCD timer
 +
; timer.lo++
 +
LI  $01 + BCD_ADJUST    ; 0dae 20 67
 +
ASD  (IS)                ; 0db0 dc
 +
LR  (IS)-,A            ; 0db1 5e
 +
BNC  .setTimerPos      ; 0db2 92 12
 +
; if carry, timer.hi++
 +
LI  $01 + BCD_ADJUST    ; 0db4 20 67
 +
ASD  (IS)                ; 0db6 dc
 +
LR  (IS)+,A            ; 0db7 5d
 +
 +
; Check if the explosion flag should be set
 +
; Check if hundreds digit is zero
 +
NI  DIGIT_MASK          ; 0db8 21 0f
 +
BNZ  .setTimerPos        ; 0dba 94 0a
 +
; If so, check if tens and ones digits are zero
 +
CLR                      ; 0dbc 70
 +
AS  (IS)                ; 0dbd cc
 +
BNZ  .setTimerPos        ; 0dbe 94 06
 +
; If so, set the explosion flag
 +
SETISAR explosionFlag    ; 0dc0 67 6a
 +
LI  MASK_EXPLODE        ; 0dc2 20 80
 +
LR  (IS),A              ; 0dc4 5c
 +
 
 +
; Handle Drawing of the timer
 +
.setTimerPos:
 +
; Check if 1 or 2 player
 +
SETISAR gameMode        ; 0dc5 67 6d
 +
LIS  MODE_2P_MASK        ; 0dc7 71
 +
NS  (IS)                ; 0dc8 fc
 +
; Display in middle if 2 player mode
 +
LI  TIMER_X_CENTER      ; 0dc9 20 39
 +
BNZ  .drawTimer          ; 0dcb 94 03
 +
; Display to left if 1 player mode
 +
LI  TIMER_X_LEFT        ; 0dcd 20 1f
 +
.drawTimer:         
 +
LR  drawTimer.xpos, A  ; 0dcf 50
 +
; Set color (drawTimer adds the ypos)
 +
LI  RED                ; 0dd0 20 80
 +
LR  drawTimer.ypos, A  ; 0dd2 52
 +
; Set ISAR to LSB of score
 +
SETISAR timer.lo        ; 0dd3 66 6f
 +
PI  drawTimer          ; 0dd5 28 0a 20
 +
 
 +
; Perform the delay (to keep the game speed consistent)
 +
; delayByTable(delayIndex)
 +
SETISAR delayIndex      ; 0dd8 65 6f
 +
LR  A,(IS)              ; 0dda 4c
 +
LR  delay.index, A      ; 0ddb 50
 +
PI  delayByTable        ; 0ddc 28 09 86
 +
 
 +
; Check if a new ball needs to be spawned
 +
; curBall = balls.count
 +
SETISAR balls.count      ; 0ddf 65 6e
 +
LI  %00001111          ; 0de1 20 0f
 +
NS  (IS)+              ; 0de3 fd
 +
LR  main.curBall, A    ; 0de4 5b
 +
 +
; ISAR is delayIndex here
 +
; Check if curBall >= delayIndex
 +
LR  A,(IS)              ; 0de5 4c
 +
COM                      ; 0de6 18
 +
INC                      ; 0de7 1f
 +
AS  main.curBall        ; 0de8 cb
 +
; if so, branch ahead
 +
BP  .ballLoopInit      ; 0de9 81 0d
 +
; if not, spawn a new ball
 +
 
 +
; curBall = delayIndex
 +
LR  A,(IS)              ; 0deb 4c
 +
LR  main.curBall, A    ; 0dec 5b
 +
 
 +
; Spawn new ball
 +
PI  spawnBall          ; 0ded 28 09 c2
 +
 +
; balls.count = delayIndex (preserve upper nybble of ball count)
 +
SETISAR balls.count      ; 0df0 65 6e
 +
LI  %11110000          ; 0df2 20 f0
 +
NS  (IS)+              ; 0df4 fd
 +
AS  (IS)-              ; 0df5 ce
 +
LR  (IS),A              ; 0df6 5c
 +
 
 +
; Handle enemy balls
 +
.ballLoopInit:
 +
SETISAR balls.count      ; 0df7 65 6e
 +
LI  %00001111          ; 0df9 20 0f
 +
NS  (IS)                ; 0dfb fc
 +
LR  main.curBall, A    ; 0dfc 5b
 +
 +
.ballLoop:         
 +
; doBall.size = enemy ball size
 +
SETISAR doBall.size      ; 0dfd 67 68
 +
LI  MASK_ENEMY_SIZE    ; 0dff 20 30
 +
NS  main.gameSettings  ; 0e01 fa
 +
SR  4                  ; 0e02 14
 +
LR  (IS)+,A            ; 0e03 5d
 +
 +
; doBall.speed = enemy speed
 +
LI  MASK_ENEMY_SPEED    ; 0e04 20 03
 +
NS  main.gameSettings  ; 0e06 fa
 +
LR  (IS),A              ; 0e07 5c
 +
 
 +
PI  doBall              ; 0e08 28 0a 53
 +
PI  collision          ; 0e0b 28 0b 6e
 +
 +
; if we're not dealing with a player ball, then move on to the next ball
 +
DS  main.curBall        ; 0e0e 3b
 +
LR  A,main.curBall      ; 0e0f 4b
 +
CI  [MAX_PLAYERS-1]    ; 0e10 25 01
 +
BNC  .ballLoop          ; 0e12 92 ea
 +
 
 +
; Handle player balls
 +
PI  doPlayers          ; 0e14 28 09 24
 +
 
 +
; doBall.size = player ball size
 +
SETISAR doBall.size      ; 0e17 67 68
 +
LI  MASK_PLAYER_SIZE    ; 0e19 20 c0
 +
NS  main.gameSettings  ; 0e1b fa
 +
SR  4                  ; 0e1c 14
 +
SR  1                  ; 0e1d 12
 +
SR  1                  ; 0e1e 12
 +
LR  (IS)+,A            ; 0e1f 5d
 +
 +
; doBall.size = player speed
 +
LI  MASK_PLAYER_SPEED  ; 0e20 20 0c
 +
NS  main.gameSettings  ; 0e22 fa
 +
SR  1                  ; 0e23 12
 +
SR  1                  ; 0e24 12
 +
LR  (IS),A              ; 0e25 5c
 +
 +
; Handle player 1
 +
LI  0                  ; 0e26 20 00
 +
LR  main.curBall,A      ; 0e28 5b
 +
PI  doBall              ; 0e29 28 0a 53
 +
 +
; Check if were doing 2 player mode
 +
SETISAR gameMode        ; 0e2c 67 6d
 +
LIS  1                  ; 0e2e 71
 +
NS  (IS)                ; 0e2f fc
 +
BZ  .checkExplosion    ; 0e30 84 05
 +
; If so handle player 2
 +
LR  main.curBall,A      ; 0e32 5b
 +
PI  doBall              ; 0e33 28 0a 53
 +
 
 +
; Deal with the explosion
 +
.checkExplosion:
 +
; Loop back to beginning if explosion flag isn't set
 +
SETISAR explosionFlag    ; 0e36 67 6a
 +
CLR                      ; 0e38 70
 +
AS  (IS)                ; 0e39 cc
 +
BP  .endMain            ; 0e3a 81 06
 +
 +
; Clear explosion flag, and then explode
 +
CLR                      ; 0e3c 70
 +
LR  (IS),A              ; 0e3d 5c
 +
JMP  explode            ; 0e3e 29 0f 6b
 +
 
 +
.endMain:
 +
JMP  mainLoop            ; 0e41 29 0d a0
 +
; end of mainLoop()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; gameOver()
 +
;  Top-Level Procedure
 +
;
 +
; collision() jumps to here if the player comes in contact with an enemy ball
 +
;
 +
; This procedure draws the fancy multicolored spiral effect, and then branches
 +
;  to two different paths depending whether we're in 1 or 2 player mode.
 +
;
 +
; In 1 player mode, the game checks the if the timer was better than the
 +
;  player's previous high score, and replaces the score if applicable.
 +
;
 +
; In 2 player mode, the game add's the value of the timer to the surviving
 +
;  player's high score (which makes it more of a running total, really).
 +
;
 +
; This procedure jumps back to either shuffleGame() or restartGame() depending
 +
;  on whether the controller is pushed in.
 +
 
 +
gameOver: subroutine
 +
; Make the multicolored spiral death effect
 +
.Y_CENTER = $24
 +
.MAX_RADIUS = $14
 +
 
 +
; ypos = $24, color = $80
 +
LI  RED | .Y_CENTER    ; 0e44 20 a4
 +
LR  draw.ypos, A        ; 0e46 52
 +
; spiralRadius = $14
 +
SETISAR spiral.radius    ; 0e47 64 6e
 +
LI  .MAX_RADIUS        ; 0e49 20 14
 +
LR  (IS),A              ; 0e4b 5c
 +
 
 +
.spiralLoop:
 +
PI  drawSpiral          ; 0e4c 28 0f 0a
 +
; spiralRadius--
 +
SETISAR spiral.radius ; 0e4f 64 6e
 +
DS  (IS)                ; 0e51 3c
 +
; save flags
 +
LR  J,W                ; 0e52 1e
 +
; color++
 +
; if(color == 0)
 +
;  color++
 +
; ypos = $24
 +
LR  A, draw.ypos        ; 0e53 42
 +
AI  $40                ; 0e54 24 40
 +
BNC  .setColor          ; 0e56 92 03
 +
AI  $40                ; 0e58 24 40
 +
.setColor:
 +
NI  MASK_COLOR          ; 0e5a 21 c0
 +
AI  .Y_CENTER          ; 0e5c 24 24
 +
LR  draw.ypos,A        ; 0e5e 52
 +
; restore flags
 +
; loop back if o46 != 0
 +
LR  W,J                ; 0e5f 1d
 +
BNZ  .spiralLoop        ; 0e60 94 eb
 +
 
 +
; Wait a bit before clearing the spiral effect
 +
; delayVariable($0)
 +
CLR                      ; 0e62 70
 +
LR  delay.count, A      ; 0e63 50
 +
PI  delayVariable      ; 0e64 28 09 9a
 +
 
 +
; Clear the spiral
 +
; Set color depending on who died
 +
; 1P mode - Red
 +
SETISAR gameMode        ; 0e67 67 6d
 +
LIS  MODE_2P_MASK        ; 0e69 71
 +
NS  (IS)                ; 0e6a fc
 +
LI  RED                ; 0e6b 20 80
 +
BZ  .clearSpiral        ; 0e6d 84 0a
 +
; 2P mode, P1 - Green
 +
SETISARL testBall        ; 0e6f 69
 +
LIS  $1                  ; 0e70 71
 +
NS  (IS)                ; 0e71 fc
 +
LI  GREEN              ; 0e72 20 c0
 +
BZ  .clearSpiral        ; 0e74 84 03
 +
; 2P mode, P2 - Blue
 +
LI  BLUE                ; 0e76 20 40
 +
.clearSpiral:
 +
; Set ypos
 +
AI  .Y_CENTER          ; 0e78 24 24
 +
LR  draw.ypos,A        ; 0e7a 52
 +
 
 +
; Draw spiral
 +
SETISAR spiral.radius    ; 0e7b 64 6e
 +
LI  .MAX_RADIUS        ; 0e7d 20 14
 +
LR  (IS),A              ; 0e7f 5c
 +
PI  drawSpiral          ; 0e80 28 0f 0a
 +
 
 +
; Delay a bit to allow the players time before input is polled later
 +
; Delay
 +
LI  $28                ; 0e83 20 28
 +
LR  delay.count,A      ; 0e85 50
 +
PI  delayVariable      ; 0e86 28 09 9a
 +
 
 +
; Branch depending on whether this is 1 or 2 player mode
 +
; Check if two players
 +
SETISAR gameMode        ; 0e89 67 6d
 +
LIS  MODE_2P_MASK        ; 0e8b 71
 +
NS  (IS)                ; 0e8c fc
 +
; If so, jump ahead
 +
BNZ  .2Pcleanup          ; 0e8d 94 38
 +
 
 +
; -- Game over cleanup - 1 player mode -----------------------------------------
 +
.tempTimerHi = $6
 +
.tempTimerLo = $7
 +
 
 +
; Check if a new high score was set
 +
; tempTimer = timer
 +
SETISAR timer.hi        ; 0e8f 66 6e
 +
LR  A,(IS)+            ; 0e91 4d
 +
LR  .tempTimerHi,A      ; 0e92 56
 +
LR  A,(IS)              ; 0e93 4c
 +
LR  .tempTimerLo,A      ; 0e94 57
 +
 
 +
; tempTimer.hi - hiScore.p1.hi
 +
SETISAR hiScore.p1.hi    ; 0e95 65 6c
 +
LR  A,(IS)+            ; 0e97 4d
 +
COM                      ; 0e98 18
 +
INC                      ; 0e99 1f
 +
AS  .tempTimerHi        ; 0e9a c6
 +
; if(tempTimer.hi < hiScore.p1.hi), we do not have a new high score
 +
BM  .delayP1            ; 0e9b 91 16
 +
; if(tempTimer.hi != hiScore.p1.hi), we have a new high score
 +
BNZ  .newHighScore      ; 0e9d 94 07
 +
 +
; tempTimer.lo - hiScore.lo
 +
LR  A,(IS)              ; 0e9f 4c
 +
COM                      ; 0ea0 18
 +
INC                      ; 0ea1 1f
 +
AS  .tempTimerLo        ; 0ea2 c7
 +
; if(tempTimer.lo < hiScore.p1.lo), we do not have a new high score
 +
BM  .delayP1            ; 0ea3 91 0e
 +
; else, we have a new high score
 +
 
 +
; Draw the new high score
 +
.newHighScore:
 +
; hiScore = tempTimer
 +
LR  A,.tempTimerLo      ; 0ea5 47
 +
LR  (IS)-,A            ; 0ea6 5e
 +
LR  A,.tempTimerHi      ; 0ea7 46
 +
LR  (IS)+,A            ; 0ea8 5d
 +
; Set color
 +
LI  BLUE                ; 0ea9 20 40
 +
LR  drawTimer.ypos, A  ; 0eab 52
 +
; Set xpos
 +
LI  TIMER_X_RIGHT      ; 0eac 20 54
 +
LR  drawTimer.xpos, A  ; 0eae 50
 +
 
 +
PI  drawTimer          ; 0eaf 28 0a 20
 +
 
 +
; Delay to give player time to push the controller
 +
.delayP1:
 +
LI  $40                ; 0eb2 20 40
 +
LR  delay.count, A      ; 0eb4 50
 +
PI  delayVariable      ; 0eb5 28 09 9a
 +
 
 +
; Read controllers
 +
PI  readInput          ; 0eb8 28 09 10
 +
 
 +
; If controller is not pushed in, shuffle the gametype
 +
SETISARL input.p1        ; 0ebb 68
 +
CLR                      ; 0ebc 70
 +
AS  (IS)                ; 0ebd cc
 +
BM  .gotoShuffle        ; 0ebe 91 04
 +
 
 +
; Else, keep the gametype and restart the game
 +
JMP  restartGame        ; 0ec0 29 0d 54
 +
; -- End of 1 player case ------------------------------------------------------
 +
 
 +
.gotoShuffle:
 +
JMP  shuffleGame        ; 0ec3 29 0d 18
 +
 
 +
; -- Game over cleanup - 2 player mode -----------------------------------------
 +
.2Pcleanup:
 +
; Check who gets the timer added to their score
 +
; tempTimer = timer
 +
SETISAR timer.hi        ; 0ec6 66 6e
 +
LR  A,(IS)+            ; 0ec8 4d
 +
LR  .tempTimerHi,A      ; 0ec9 56
 +
LR  A,(IS)              ; 0eca 4c
 +
LR  .tempTimerLo,A      ; 0ecb 57
 +
 +
; Check who died
 +
SETISAR testBall        ; 0ecc 67 69
 +
LIS  $1                  ; 0ece 71
 +
NS  (IS)                ; 0ecf fc
 +
BNZ  .P1survived        ; 0ed0 94 0b
 +
 
 +
; Set drawTimer parameters for player 2
 +
; Set color
 +
LI  GREEN              ; 0ed2 20 c0
 +
LR  drawTimer.ypos,A    ; 0ed4 52
 +
; set xpos
 +
LI  TIMER_X_RIGHT      ; 0ed5 20 54
 +
LR  drawTimer.xpos,A    ; 0ed7 50
 +
; Set ISAR
 +
SETISAR hiScore.p2.lo    ; 0ed8 67 6c
 +
BR  .addHiScore        ; 0eda 90 09
 +
 
 +
; Set drawTimer parameters for player 1
 +
.P1survived:
 +
; Set ISAR
 +
SETISAR hiScore.p1.lo    ; 0edc 65 6d
 +
; Set color
 +
LI  BLUE                ; 0ede 20 40
 +
LR  drawTimer.ypos,A    ; 0ee0 52
 +
; Set xpos
 +
LI  TIMER_X_LEFT        ; 0ee1 20 1f
 +
LR  drawTimer.xpos,A    ; 0ee3 50
 +
 
 +
; Add the current timer to the winning player's high score
 +
.addHiScore:
 +
; hiScore.lo += tempTimer.lo
 +
LR  A,.tempTimerLo      ; 0ee4 47
 +
AS  (IS)                ; 0ee5 cc
 +
LR  (IS),A              ; 0ee6 5c
 +
; Add zero in BCD to adjust score and check carry flag
 +
LI  0 + BCD_ADJUST      ; 0ee7 20 66
 +
ASD  (IS)                ; 0ee9 dc
 +
LR  (IS)-,A            ; 0eea 5e
 +
BNC  .addHiScoreHiByte  ; 0eeb 92 05
 +
; Carry
 +
LI  1 + BCD_ADJUST      ; 0eed 20 67
 +
ASD  (IS)                ; 0eef dc
 +
LR  (IS),A              ; 0ef0 5c
 +
 
 +
.addHiScoreHiByte:
 +
; hiScore.hi += tempTimer.hi
 +
LR  A,(IS)              ; 0ef1 4c
 +
AS  .tempTimerHi        ; 0ef2 c6
 +
LR  (IS),A              ; 0ef3 5c
 +
; Add zero in BCD to adjust score
 +
LI  0 + BCD_ADJUST      ; 0ef4 20 66
 +
ASD  (IS)                ; 0ef6 dc
 +
LR  (IS)+,A            ; 0ef7 5d
 +
 
 +
PI  drawTimer          ; 0ef8 28 0a 20
 +
 
 +
; There is no delay here, unlike in 1 player mode!
 +
 
 +
; Read controllers
 +
PI  readInput          ; 0efb 28 09 10
 +
 
 +
; If neither player is pushing the controller, shuffle gametype
 +
; Player 1
 +
SETISARL input.p1        ; 0efe 68
 +
CLR                      ; 0eff 70
 +
AS  (IS)+              ; 0f00 cd
 +
BM  .gotoShuffle        ; 0f01 91 c1
 +
 
 +
; Player 2
 +
CLR                      ; 0f03 70
 +
AS  (IS)                ; 0f04 cc
 +
BM  .gotoShuffle        ; 0f05 91 bd
 +
 
 +
; Else, just restart the current game
 +
JMP  restartGame        ; 0f07 29 0d 54
 +
; -- End of 2 player case ------------------------------------------------------
 +
 
 +
; end of gameOver()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; drawSpiral()
 +
;  Mid-Level Function
 +
;
 +
; Draws a single-colored square by going in a nice clockwise spiral pattern
 +
;  starting from the center, like so:
 +
;
 +
;  .-· · ·
 +
;  | .- - - - - -.
 +
;  | | .- - - -. |
 +
;  | | | .- -. | |
 +
;  | | | |.. | | |
 +
;  | | | | | | | |
 +
;  | | | '-' | | |
 +
;  | | '- - -' | |
 +
;  | '- - - - -' |
 +
;  '- - - - - - -'
 +
;
 +
; This function clobbers memory locations otherwise held by the ball arrays,
 +
;  meaning that it cannot be used during the main loop.
 +
 
 +
; == Arguments ==
 +
spiral.radius = 046
 +
;.ypos = 2
 +
 
 +
drawSpiral: subroutine
 +
LR  K,P                ; 0f0a 08
 +
 
 +
; == Locals ==
 +
; Note: These take the place of variables used while the game is being played!
 +
; Note 2: The reason these registers don't use the dot notation like other
 +
;  locals (eg. ".temp") is because that doesn't work with the SETISAR macros
 +
;  because of how DASM handles namespaces.
 +
spiral.hdiameter = 024 ; o24 - horizontal diameter
 +
spiral.hcount = 025    ; o25 - horizontal counter
 +
spiral.vcount = 026    ; o26 - vertical counter
 +
spiral.vdiameter = 027 ; o27 - vertical diameter
 +
spiral.lapCount = 036  ; o36 - spiral lap counter
 +
 
 +
.X_CENTER = $34
 +
 
 +
; Initialize things before the big loop
 +
; Set properties to draw a rect
 +
LI  DRAW_RECT          ; 0f0b 20 80
 +
LR  draw.param, A      ; 0f0d 50
 +
; Set xpos
 +
LI  .X_CENTER          ; 0f0e 20 34
 +
LR  draw.xpos, A        ; 0f10 51
 +
; Note: ypos is set before entering this function
 +
 
 +
SETISAR spiral.hdiameter ; 0f11 62 6c
 +
 
 +
; Set width/height to 1
 +
LIS  $1                  ; 0f13 71
 +
LR  draw.width, A      ; 0f14 54
 +
LR  draw.height, A      ; 0f15 55
 +
 
 +
; Set all spiral counters to 1
 +
; .hdiameter
 +
LR  (IS)+,A            ; 0f16 5d
 +
; .hcount
 +
LR  (IS)+,A            ; 0f17 5d
 +
; .vcount
 +
LR  (IS)+,A            ; 0f18 5d
 +
; .vdiameter
 +
LR  (IS)-,A            ; 0f19 5e
 +
 
 +
; spiral.lapCount = spiral.radius
 +
SETISARU spiral.radius  ; 0f1a 64
 +
LR  A,(IS)              ; 0f1b 4c
 +
SETISARU spiral.lapCount ; 0f1c 63
 +
LR  (IS),A              ; 0f1d 5c
 +
 
 +
; Set ISAR
 +
SETISARU spiral.vcount  ; 0f1e 62
 +
 
 +
; Dummy arithmetic operation
 +
LIS  $1                  ; 0f1f 71
 +
SL  1                  ; 0f20 13
 +
; Save the flags from that operation to prevent the "LR W,J" a few lines
 +
;  down from causing the function to erroneously return early
 +
LR  J,W                ; 0f21 1e
 +
 
 +
; Draw the center point
 +
PI  drawBox            ; 0f22 28 08 62
 +
 
 +
; Start of the big loop, which contains 4 small loops for each direction
 +
.startLap:
 +
.plotUp:
 +
; ypos--
 +
DS  draw.ypos          ; 0f25 32
 +
PI  drawBox            ; 0f26 28 08 62
 +
; .vcount--
 +
DS  (IS)                ; 0f29 3c
 +
; loop until .vcount reaches 0
 +
BNZ  .plotUp            ; 0f2a 94 fa
 +
 
 +
; if (.lapCount == 0) return
 +
LR  W,J                ; 0f2c 1d    ; restore flags
 +
BZ  .exit              ; 0f2d 84 3b
 +
 
 +
; Prep for .plotDown
 +
; .vdiameter++
 +
LR  A,(IS)+            ; 0f2f 4d
 +
LR  A,(IS)              ; 0f30 4c
 +
INC                      ; 0f31 1f
 +
LR  (IS)-,A            ; 0f32 5e
 +
; .vcount = .vdiameter
 +
LR  (IS)-,A            ; 0f33 5e
 +
 
 +
.plotRight:
 +
; xpos++
 +
LR  A, draw.xpos        ; 0f34 41
 +
INC                      ; 0f35 1f
 +
LR  draw.xpos, A        ; 0f36 51
 +
 +
PI  drawBox            ; 0f37 28 08 62
 +
; .hcount--
 +
DS  (IS)                ; 0f3a 3c
 +
; loop until hcount reaches 0
 +
BNZ  .plotRight          ; 0f3b 94 f8
 +
 +
; Clear sound
 +
CLR                      ; 0f3d 70
 +
OUTS 5                  ; 0f3e b5
 +
 
 +
; Prep for .plotLeft
 +
; .hdiameter++
 +
LR  A,(IS)-            ; 0f3f 4e
 +
LR  A,(IS)              ; 0f40 4c
 +
INC                      ; 0f41 1f
 +
LR  (IS)+,A            ; 0f42 5d
 +
; .hcount = .hdiameter
 +
LR  (IS)+,A            ; 0f43 5d
 +
 
 +
.plotDown:
 +
; ypos++
 +
LR  A, draw.ypos        ; 0f44 42
 +
INC                      ; 0f45 1f
 +
LR  draw.ypos, A        ; 0f46 52
 +
PI  drawBox            ; 0f47 28 08 62
 +
; vcount-- (o26)
 +
DS  (IS)                ; 0f4a 3c
 +
BNZ  .plotDown          ; 0f4b 94 f8
 +
 
 +
; Prep for .plotUp
 +
; .vdiameter++
 +
LR  A,(IS)+            ; 0f4d 4d
 +
LR  A,(IS)              ; 0f4e 4c
 +
INC                      ; 0f4f 1f
 +
LR  (IS)-,A            ; 0f50 5e
 +
; .vcount = .vdiameter
 +
LR  (IS)-,A            ; 0f51 5e
 +
 
 +
.plotLeft:
 +
; xpos--
 +
DS  draw.xpos          ; 0f52 31
 +
PI  drawBox            ; 0f53 28 08 62
 +
; .hcount--
 +
DS  (IS)                ; 0f56 3c
 +
BNZ  .plotLeft          ; 0f57 94 fa
 +
 
 +
; Prep for .plotRight
 +
; .hdiameter++
 +
LR  A,(IS)-            ; 0f59 4e
 +
LR  A,(IS)              ; 0f5a 4c
 +
INC                      ; 0f5b 1f
 +
LR  (IS)+,A            ; 0f5c 5d
 +
; .hcount = .hdiameter
 +
LR  (IS)+,A            ; 0f5d 5d
 +
 
 +
; Prep for next loop
 +
; .lapCount--
 +
SETISARU spiral.lapCount ; 0f5e 63
 +
DS  (IS)                ; 0f5f 3c
 +
; Reset ISAR
 +
SETISARU spiral.vcount  ; 0f60 62
 +
; save flags (to be used above shortly after .plotUp)
 +
LR  J,W                ; 0f61 1e
 +
 +
; Play sound
 +
LR  A,$2                ; 0f62 42
 +
OUTS 5                  ; 0f63 b5
 +
 +
; Start new lap if(.lapCount != 0)
 +
BNZ  .startLap          ; 0f64 94 c0
 +
 +
; Adjust .vcount for the last .plotUp so we make a clean sqaure
 +
; .vcount--
 +
DS  (IS)                ; 0f66 3c
 +
; Note: This lap will only do .plotUp before exiting
 +
BR  .startLap          ; 0f67 90 bd
 +
 
 +
.exit:
 +
LR  P,K                ; 0f69 09
 +
POP                      ; 0f6a 1c
 +
; end drawSpiral()
 +
;-------------------------------------------------------------------------------
 +
 
 +
;-------------------------------------------------------------------------------
 +
; explode()
 +
;  Top-level procedure
 +
;
 +
; Move the balls to the center to "explode". This procedure is executed
 +
;  every 1000 points.
 +
;
 +
; Accessed from the end of the main loop, and returns to the beginning of the
 +
;  main loop.
 +
;
 +
; No input arguments
 +
 
 +
; == Entry Point ==
 +
explode: subroutine
 +
 
 +
; == Local Regs ==
 +
.loopCount = $0
 +
 
 +
; == Local Constants ==
 +
.NUM_LOOPS = MAX_ENEMIES
 +
.X_CENTER = $30
 +
.Y_CENTER = $22
 +
 
 +
; == Start ==
 +
; Prepare for loop to set x positions
 +
; ISAR = balls.xpos + MAX_PLAYERS
 +
LIS  MAX_PLAYERS        ; 0f6b 72
 +
AI  balls.xpos          ; 0f6c 24 10
 +
LR  IS,A                ; 0f6e 0b
 +
; .loopCount = .NUM_LOOPS
 +
LIS  .NUM_LOOPS          ; 0f6f 79
 +
LR  .loopCount,A        ; 0f70 50
 +
; Set xpos of all enemy balls
 +
.xLoop:
 +
; Set xpos while preserving the x direction
 +
LI  MASK_DIRECTION      ; 0f71 20 80
 +
NS  (IS)                ; 0f73 fc
 +
AI  .X_CENTER          ; 0f74 24 30
 +
LR  (IS),A              ; 0f76 5c
 +
; ISAR++ (NOTE: ISAR post-increment would only affect the lower octal digit)
 +
LR  A,IS                ; 0f77 0a
 +
INC                      ; 0f78 1f
 +
LR  IS,A                ; 0f79 0b
 +
; .loopCount--, loop back if not zero
 +
DS  .loopCount          ; 0f7a 30
 +
BNZ  .xLoop              ; 0f7b 94 f5
 +
 
 +
; Prepare for loop to set y positions
 +
; ISAR = balls.ypos + MAX_PLAYERS
 +
LR  A,IS                ; 0f7d 0a
 +
AI  MAX_PLAYERS        ; 0f7e 24 02
 +
LR  IS,A                ; 0f80 0b
 +
; .loopCount = .NUM_LOOPS
 +
LIS  .NUM_LOOPS          ; 0f81 79
 +
LR  .loopCount,A        ; 0f82 50
 +
; Set ypos of all enemy balls
 +
.yLoop:
 +
; Set ypos while preserving the y direction
 +
LI  MASK_DIRECTION      ; 0f83 20 80
 +
NS  (IS)                ; 0f85 fc
 +
AI  .Y_CENTER          ; 0f86 24 22
 +
LR  (IS),A              ; 0f88 5c
 +
; ISAR++
 +
LR  A,IS                ; 0f89 0a
 +
INC                      ; 0f8a 1f
 +
LR  IS,A                ; 0f8b 0b
 +
; .loopCount, loop back if not
 +
DS  .loopCount          ; 0f8c 30
 +
BNZ  .yLoop              ; 0f8d 94 f5
 +
 
 +
; (ISAR) = gameSettings, ISAR++, (ISAR) = gameSettings
 +
; TODO: Why are we overwriting the speeds of the player balls and the first two enemies?
 +
LR  A,main.gameSettings ; 0f8f 4a ; is=046
 +
LR  (IS)+,A            ; 0f90 5d ; is=046
 +
LR  (IS)+,A            ; 0f91 5d ; is=047
 +
 
 +
; Clear MODE_BOUNCE_MASK from gameMode
 +
SETISAR gameMode        ; 0f92 67 6d
 +
LR  A,(IS)              ; 0f94 4c
 +
SL  1                  ; 0f95 13
 +
SR  1                  ; 0f96 12
 +
LR  (IS),A              ; 0f97 5c
  
org $0800
+
; Exit
 +
JMP  mainLoop              ; 0f98 29 0d a0
 +
; end explode()
 +
;-------------------------------------------------------------------------------
 +
 +
; Unused byte
 +
db $b2
 +
; This byte mirrors the $2b (NOP) in this cart's header.
 +
; Coincidence or creative whimsy?
  
CartridgeStart: LR  $5,A                ; 0800 55
+
; Free space - 94 bytes!
                NOP                      ; 0801 2b
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
CartridgeEntry: JMP  A0cd0              ; 0802 29 0c d0
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
A0805:          LIS  $2                  ; 0805 72
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
                LR  $6,A                ; 0806 56
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
                LR  $2,A                ; 0807 52
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
                LR  $2,A                ; 0808 52
+
db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
                LIS  $7                  ; 0809 77
 
                LIS  $7                  ; 080a 77
 
                LR  H,DC                ; 080b 11
 
                LIS  $3                  ; 080c 73
 
                LR  A,$1                ; 080d 41
 
                LIS  $7                  ; 080e 77
 
                LR  $7,A                ; 080f 57
 
                LR  $4,A                ; 0810 54
 
                LIS  $7                  ; 0811 77
 
                LR  H,DC                ; 0812 11
 
                ST                      ; 0813 17
 
A0814:          LR  A,$7                ; 0814 47
 
                LR  A,$1                ; 0815 41
 
                LIS  $1                  ; 0816 71
 
                LR  $1,A                ; 0817 51
 
                LIS  $1                  ; 0818 71
 
                LIS  $7                  ; 0819 77
 
                LR  $5,A                ; 081a 55
 
                LIS  $7                  ; 081b 77
 
                LR  $1,A                ; 081c 51
 
                LIS  $1                  ; 081d 71
 
                db   $ff                
 
                BT  1,-78              ; 081f 81 b2
 
                BF  $0,A0814            ; 0821 90 f2
 
                LIS  $7                  ; 0823 77
 
                LR  A,$5                ; 0824 45
 
                LIS  $7                  ; 0825 77
 
                LR  A,$5                ; 0826 45
 
                LR  A,$5                ; 0827 45
 
                LIS  $7                  ; 0828 77
 
                LR  A,$2                ; 0829 42
 
                LIS  $2                  ; 082a 72
 
                SR  1                  ; 082b 12
 
                LIS  $2                  ; 082c 72
 
A082d:          LNK                      ; 082d 19
 
                LM                      ; 082e 16
 
                SL  1                  ; 082f 13
 
                LR  H,DC                ; 0830 11
 
                LR  Q,DC                ; 0831 0e
 
                PK                      ; 0832 0c
 
                LR  A,IS                ; 0833 0a
 
                LR  K,P                ; 0834 08
 
                LR  QU,A                ; 0835 06
 
                LR  A,QL                ; 0836 03
 
                LR  A,KL                ; 0837 01
 
A0838:          LR  IS,A                ; 0838 0b
 
                LR  A,IS                ; 0839 0a
 
                LR  P,K                ; 083a 09
 
                LR  K,P                ; 083b 08
 
                LR  QL,A                ; 083c 07
 
                LR  QU,A                ; 083d 06
 
                LR  KL,A                ; 083e 05
 
                LR  KU,A                ; 083f 04
 
                LR  A,QL                ; 0840 03
 
                LR  A,QU                ; 0841 02
 
                LR  A,KL                ; 0842 01
 
A0843:          AS  $0                  ; 0843 c0
 
                DS  $0                  ; 0844 30
 
                PK                      ; 0845 0c
 
                LR  A,QL                ; 0846 03
 
                NS  (IS)                ; 0847 fc
 
A0848:          LR  A,KU                ; 0848 00
 
                LR  A,KU                ; 0849 00
 
                SR  1                  ; 084a 12
 
                LR  IS,A                ; 084b 0b
 
                LR  IS,A                ; 084c 0b
 
                LR  QU,A                ; 084d 06
 
                LR  A,QU                ; 084e 02
 
                LR  A,KL                ; 084f 01
 
A0850:          LR  A,$0                ; 0850 40
 
                AS  $0                  ; 0851 c0
 
                BT  0,0                ; 0852 80 00
 
                LR  A,KL                ; 0854 01
 
                LR  A,QU                ; 0855 02
 
                LR  A,QL                ; 0856 03
 
                LR  A,QL                ; 0857 03
 
A0858:          DCI  A0805              ; 0858 2a 08 05
 
                LR  A,$0                ; 085b 40
 
                SR  1                  ; 085c 12
 
                LR  $8,A                ; 085d 58
 
                SL  1                  ; 085e 13
 
                SL  1                  ; 085f 13
 
                AS  $8                  ; 0860 c8
 
                ADC                      ; 0861 8e
 
A0862:          LR  A,$4                ; 0862 44
 
                LR  $6,A                ; 0863 56
 
                LR  A,$5                ; 0864 45
 
                LR  $7,A                ; 0865 57
 
A0866:          LR  A,$2                ; 0866 42
 
                NI  $c0                ; 0867 21 c0
 
                LR  $8,A                ; 0869 58
 
                LR  A,$2                ; 086a 42
 
                COM                      ; 086b 18
 
                NI  $3f                ; 086c 21 3f
 
                LR  $3,A                ; 086e 53
 
                INS  5                  ; 086f a5
 
                NI  $c0                ; 0870 21 c0
 
                AS  $3                  ; 0872 c3
 
                OUTS 5                  ; 0873 b5
 
                LIS  $0                  ; 0874 70
 
                AS  $0                  ; 0875 c0
 
                LI  $ff                 ; 0876 20 ff
 
                BF  $1,A0882            ; 0878 91 09
 
                LM                      ; 087a 16
 
                LR  $3,A                ; 087b 53
 
                LIS  $1                  ; 087c 71
 
                NS  $0                  ; 087d f0
 
                BT  4,A0883            ; 087e 84 04
 
                LR  A,$3                ; 0880 43
 
                SL  4                  ; 0881 15
 
A0882:          LR  $3,A                ; 0882 53
 
A0883:          LR  A,$1                ; 0883 41
 
                COM                      ; 0884 18
 
                OUTS 4                  ; 0885 b4
 
                LIS  $0                  ; 0886 70
 
                AS  $3                  ; 0887 c3
 
                LR  A,$8                ; 0888 48
 
                BF  $1,A088c            ; 0889 91 02
 
                LIS  $0                  ; 088b 70
 
A088c:          COM                      ; 088c 18
 
                NI  $c0                ; 088d 21 c0
 
                OUTS 1                  ; 088f b1
 
                LR  A,$3                ; 0890 43
 
                SL  1                  ; 0891 13
 
                INC                      ; 0892 1f
 
                LR  $3,A                ; 0893 53
 
                LR  A,$0                ; 0894 40
 
                SL  1                  ; 0895 13
 
                BT  1,A089b            ; 0896 81 04
 
                LR  A,$8                ; 0898 48
 
                SL  1                  ; 0899 13
 
                LR  $8,A                ; 089a 58
 
A089b:          LI  $60                ; 089b 20 60
 
                OUTS 0                  ; 089d b0
 
                LI  $50                ; 089e 20 50
 
                OUTS 0                  ; 08a0 b0
 
                LR  A,$1                ; 08a1 41
 
                INC                      ; 08a2 1f
 
                LR  $1,A                ; 08a3 51
 
                LIS  $4                  ; 08a4 74
 
A08a5:          AI  $ff                ; 08a5 24 ff
 
                BF  $4,A08a5            ; 08a7 94 fd
 
                DS  $6                  ; 08a9 36
 
                BF  $4,A0883            ; 08aa 94 d8
 
                LR  A,$2                ; 08ac 42
 
                INC                      ; 08ad 1f
 
                LR  $2,A                ; 08ae 52
 
                LR  A,$4                ; 08af 44
 
                LR  $6,A                ; 08b0 56
 
                COM                      ; 08b1 18
 
                INC                      ; 08b2 1f
 
                AS  $1                  ; 08b3 c1
 
                LR  $1,A                ; 08b4 51
 
                DS  $7                  ; 08b5 37
 
                BF  $4,A0866            ; 08b6 94 af
 
                LR  A,$5                ; 08b8 45
 
                COM                      ; 08b9 18
 
                INC                      ; 08ba 1f
 
                AS  $2                  ; 08bb c2
 
                LR  $2,A                ; 08bc 52
 
                LIS  $0                  ; 08bd 70
 
                OUTS 1                  ; 08be b1
 
                OUTS 0                  ; 08bf b0
 
                POP                      ; 08c0 1c
 
A08c1:          LR  A,IS                ; 08c1 0a
 
                LR  $8,A                ; 08c2 58
 
                LISU 7                  ; 08c3 67
 
                LISL 7                  ; 08c4 6f
 
                LR  A,(IS)-            ; 08c5 4e
 
                SL  1                  ; 08c6 13
 
                AS  (IS)+              ; 08c7 cd
 
                LR  $6,A                ; 08c8 56
 
                LR  A,(IS)              ; 08c9 4c
 
                AS  (IS)                ; 08ca cc
 
                LR  $7,A                ; 08cb 57
 
                LR  J,W                ; 08cc 1e
 
                LR  A,$6                ; 08cd 46
 
                SL  1                  ; 08ce 13
 
                LR  W,J                ; 08cf 1d
 
                LNK                      ; 08d0 19
 
                LR  $6,A                ; 08d1 56
 
                LR  A,$7                ; 08d2 47
 
                AS  $7                  ; 08d3 c7
 
                LR  $7,A                ; 08d4 57
 
                LR  J,W                ; 08d5 1e
 
                LR  A,$6                ; 08d6 46
 
                SL  1                  ; 08d7 13
 
                LR  W,J                ; 08d8 1d
 
                LNK                      ; 08d9 19
 
                LR  $6,A                ; 08da 56
 
                LR  A,$7                ; 08db 47
 
                AS  (IS)-              ; 08dc ce
 
                LR  $7,A                ; 08dd 57
 
                LR  A,$6                ; 08de 46
 
                LNK                      ; 08df 19
 
                AS  (IS)+              ; 08e0 cd
 
                LR  $6,A                ; 08e1 56
 
                LR  A,$7                ; 08e2 47
 
                AI  $19                ; 08e3 24 19
 
                LR  $7,A                ; 08e5 57
 
                LR  (IS)-,A            ; 08e6 5e
 
                LR  A,$6                ; 08e7 46
 
                LNK                      ; 08e8 19
 
                AI  $36                ; 08e9 24 36
 
                LR  $6,A                ; 08eb 56
 
                LR  (IS)+,A            ; 08ec 5d
 
                LR  A,$8                ; 08ed 48
 
                LR  IS,A                ; 08ee 0b
 
                POP                      ; 08ef 1c
 
A08f0:          LR  K,P                ; 08f0 08
 
                LIS  $0                  ; 08f1 70
 
                LR  $1,A                ; 08f2 51
 
                OUTS 0                  ; 08f3 b0
 
                INS  0                  ; 08f4 a0
 
                LR  $0,A                ; 08f5 50
 
                LI  $af                ; 08f6 20 af
 
                LR  $2,A                ; 08f8 52
 
A08f9:          PI  A08c1              ; 08f9 28 08 c1
 
                DCI  $0853              ; 08fc 2a 08 53
 
                LIS  $0                  ; 08ff 70
 
                OUTS 0                  ; 0900 b0
 
                INS  0                  ; 0901 a0
 
                XS  $0                  ; 0902 e0
 
                BT  4,A0907            ; 0903 84 03
 
A0905:          LR  $0,A                ; 0905 50
 
                PK                      ; 0906 0c
 
A0907:          DS  $1                  ; 0907 31
 
                BF  $4,A08f9            ; 0908 94 f0
 
                DS  $2                  ; 090a 32
 
                BF  $4,A08f9            ; 090b 94 ed
 
                LIS  $1                  ; 090d 71
 
                BF  $0,A0905            ; 090e 90 f6
 
A0910:          LISU 7                  ; 0910 67
 
                LISL 0                  ; 0911 68
 
                LIS  $0                  ; 0912 70
 
                OUTS 1                  ; 0913 b1
 
                OUTS 4                  ; 0914 b4
 
                INS  1                  ; 0915 a1
 
                LR  (IS)+,A            ; 0916 5d
 
                INS  4                  ; 0917 a4
 
                LR  (IS)-,A            ; 0918 5e
 
                AS  (IS)                ; 0919 cc
 
                INC                      ; 091a 1f
 
                COM                      ; 091b 18
 
                BT  4,A0923            ; 091c 84 06
 
                LISL 7                  ; 091e 6f
 
                LIS  $1                  ; 091f 71
 
                AS  (IS)                ; 0920 cc
 
                LR  (IS)-,A            ; 0921 5e
 
                DS  (IS)                ; 0922 3c
 
A0923:          POP                      ; 0923 1c
 
A0924:          LR  K,P                ; 0924 08
 
                PI  A0910              ; 0925 28 09 10
 
                LISU 7                  ; 0928 67
 
                LISL 7                  ; 0929 6f
 
                LIS  $1                  ; 092a 71
 
                NS  (IS)                ; 092b fc
 
                LIS  $0                  ; 092c 70
 
                BF  $4,A0930            ; 092d 94 02
 
                LIS  $1                  ; 092f 71
 
A0930:          LR  $b,A                ; 0930 5b
 
                LIS  $2                  ; 0931 72
 
                LR  $8,A                ; 0932 58
 
A0933:          LIS  $0                  ; 0933 70
 
                LR  $0,A                ; 0934 50
 
                LR  A,$b                ; 0935 4b
 
                AI  $10                ; 0936 24 10
 
                LR  IS,A                ; 0938 0b
 
                LR  A,(IS)              ; 0939 4c
 
                LR  $1,A                ; 093a 51
 
                LR  A,IS                ; 093b 0a
 
                AI  $0b                ; 093c 24 0b
 
                LR  IS,A                ; 093e 0b
 
                LR  A,(IS)              ; 093f 4c
 
                LR  $2,A                ; 0940 52
 
                LISU 7                  ; 0941 67
 
                LIS  $1                  ; 0942 71
 
                NS  $b                  ; 0943 fb
 
                LISL 1                  ; 0944 69
 
                BF  $4,A0948            ; 0945 94 02
 
                LISL 0                  ; 0947 68
 
A0948:          LIS  $1                  ; 0948 71
 
                NS  (IS)                ; 0949 fc
 
                BF  $4,A0951            ; 094a 94 06
 
                LR  A,$1                ; 094c 41
 
                NI  $7f                ; 094d 21 7f
 
                BF  $0,A0958            ; 094f 90 08
 
A0951:          LIS  $2                  ; 0951 72
 
                NS  (IS)                ; 0952 fc
 
                BF  $4,A095c            ; 0953 94 08
 
                LR  A,$1                ; 0955 41
 
                OI  $80                ; 0956 22 80
 
A0958:          LR  $1,A                ; 0958 51
 
                LIS  $c                  ; 0959 7c
 
                NS  $a                  ; 095a fa
 
                LR  $0,A                ; 095b 50
 
A095c:          LIS  $4                  ; 095c 74
 
                NS  (IS)                ; 095d fc
 
                BF  $4,A0965            ; 095e 94 06
 
                LR  A,$2                ; 0960 42
 
                NI  $3f                ; 0961 21 3f
 
                BF  $0,A096c            ; 0963 90 08
 
A0965:          LIS  $8                  ; 0965 78
 
                NS  (IS)                ; 0966 fc
 
                BF  $4,A0973            ; 0967 94 0b
 
                LR  A,$2                ; 0969 42
 
                OI  $80                ; 096a 22 80
 
A096c:          LR  $2,A                ; 096c 52
 
                LIS  $c                  ; 096d 7c
 
                NS  $a                  ; 096e fa
 
                SR  1                  ; 096f 12
 
                SR  1                  ; 0970 12
 
                AS  $0                  ; 0971 c0
 
                LR  $0,A                ; 0972 50
 
A0973:          LR  A,$0                ; 0973 40
 
                SL  4                  ; 0974 15
 
                AS  $0                  ; 0975 c0
 
                LR  $0,A                ; 0976 50
 
                PI  A09a2              ; 0977 28 09 a2
 
                LIS  $1                  ; 097a 71
 
                NS  $b                  ; 097b fb
 
                LIS  $0                  ; 097c 70
 
                BF  $4,A0980            ; 097d 94 02
 
                LIS  $1                  ; 097f 71
 
A0980:          LR  $b,A                ; 0980 5b
 
                DS  $8                  ; 0981 38
 
                BF  $4,A0933            ; 0982 94 b0
 
                LR  P,K                ; 0984 09
 
                POP                      ; 0985 1c
 
A0986:          DCI  A082d              ; 0986 2a 08 2d
 
                LR  A,IS                ; 0989 0a
 
                LR  $3,A                ; 098a 53
 
                LISU 7                  ; 098b 67
 
                LISL 5                  ; 098c 6d
 
                LIS  $2                  ; 098d 72
 
                NS  (IS)                ; 098e fc
 
                LR  A,$3                ; 098f 43
 
                LR  IS,A                ; 0990 0b
 
                BT  4,A0996            ; 0991 84 04
 
                DCI  A0838              ; 0993 2a 08 38
 
A0996:          LR  A,$0                ; 0996 40
 
                ADC                      ; 0997 8e
 
                LM                      ; 0998 16
 
                LR  $0,A                ; 0999 50
 
A099a:          LIS  $0                  ; 099a 70
 
A099b:          INC                      ; 099b 1f
 
                BF  $4,A099b            ; 099c 94 fe
 
                DS  $0                  ; 099e 30
 
                BF  $4,A099a            ; 099f 94 fa
 
                POP                      ; 09a1 1c
 
A09a2:          LI  $10                ; 09a2 20 10
 
                AS  $b                  ; 09a4 cb
 
                LR  IS,A                ; 09a5 0b
 
                LR  A,$1                ; 09a6 41
 
                LR  (IS),A              ; 09a7 5c
 
                LR  A,IS                ; 09a8 0a
 
                AI  $0b                ; 09a9 24 0b
 
                LR  IS,A                ; 09ab 0b
 
                LR  A,$2                ; 09ac 42
 
                LR  (IS),A              ; 09ad 5c
 
                LR  A,$b                ; 09ae 4b
 
                SR  1                  ; 09af 12
 
                AI  $26                ; 09b0 24 26
 
                LR  IS,A                ; 09b2 0b
 
                LIS  $1                  ; 09b3 71
 
                NS  $b                  ; 09b4 fb
 
                LIS  $f                  ; 09b5 7f
 
                BF  $4,A09b9            ; 09b6 94 02
 
                COM                      ; 09b8 18
 
A09b9:          LR  $3,A                ; 09b9 53
 
                COM                      ; 09ba 18
 
                NS  (IS)                ; 09bb fc
 
                LR  (IS),A              ; 09bc 5c
 
                LR  A,$0                ; 09bd 40
 
                NS  $3                  ; 09be f3
 
                AS  (IS)                ; 09bf cc
 
                LR  (IS),A              ; 09c0 5c
 
                POP                      ; 09c1 1c
 
A09c2:          LR  K,P                ; 09c2 08
 
A09c3:          PI  A08c1              ; 09c3 28 08 c1
 
                LR  A,$6                ; 09c6 46
 
                CI  $10                ; 09c7 25 10
 
                BT  2,A09c3            ; 09c9 82 f9
 
                CI  $57                ; 09cb 25 57
 
                BF  $2,A09c3            ; 09cd 92 f5
 
                LR  $1,A                ; 09cf 51
 
                LR  A,$7                ; 09d0 47
 
                CI  $10                ; 09d1 25 10
 
                BT  2,A09c3            ; 09d3 82 ef
 
                CI  $37                ; 09d5 25 37
 
                BF  $2,A09c3            ; 09d7 92 eb
 
                LR  $2,A                ; 09d9 52
 
                LI  $55                ; 09da 20 55
 
                LR  $0,A                ; 09dc 50
 
                LIS  $3                  ; 09dd 73
 
                NS  $6                  ; 09de f6
 
                DCI  A09e6              ; 09df 2a 09 e6
 
                ADC                      ; 09e2 8e
 
                ADC                      ; 09e3 8e
 
                LR  Q,DC                ; 09e4 0e
 
                LR  P0,Q                ; 09e5 0d
 
A09e6:          BF  $0,A09ee            ; 09e6 90 07
 
                BF  $0,A09f3            ; 09e8 90 0a
 
                BF  $0,A09fe            ; 09ea 90 13
 
                BF  $0,A0a09            ; 09ec 90 1c
 
A09ee:          LI  $11                ; 09ee 20 11
 
                LR  $2,A                ; 09f0 52
 
                BF  $0,A0a0c            ; 09f1 90 1a
 
A09f3:          LI  $30                ; 09f3 20 30
 
                NS  $a                  ; 09f5 fa
 
                SR  4                  ; 09f6 14
 
                COM                      ; 09f7 18
 
                INC                      ; 09f8 1f
 
                AI  $d8                ; 09f9 24 d8
 
                LR  $1,A                ; 09fb 51
 
                BF  $0,A0a0c            ; 09fc 90 0f
 
A09fe:          LI  $30                ; 09fe 20 30
 
                NS  $a                  ; 0a00 fa
 
                SR  4                  ; 0a01 14
 
                COM                      ; 0a02 18
 
                INC                      ; 0a03 1f
 
                AI  $b8                ; 0a04 24 b8
 
                LR  $2,A                ; 0a06 52
 
                BF  $0,A0a0c            ; 0a07 90 04
 
A0a09:          LI  $11                ; 0a09 20 11
 
                LR  $1,A                ; 0a0b 51
 
A0a0c:          LR  A,$b                ; 0a0c 4b
 
                CI  $01                ; 0a0d 25 01
 
                BF  $2,A0a1b            ; 0a0f 92 0b
 
                LI  $23                ; 0a11 20 23
 
                LR  $2,A                ; 0a13 52
 
                LI  $33                ; 0a14 20 33
 
                BF  $4,A0a1a            ; 0a16 94 03
 
                AI  $07                ; 0a18 24 07
 
A0a1a:          LR  $1,A                ; 0a1a 51
 
A0a1b:          PI  A09a2              ; 0a1b 28 09 a2
 
                LR  P,K                ; 0a1e 09
 
                POP                      ; 0a1f 1c
 
A0a20:          LR  K,P                ; 0a20 08
 
                LR  A,$0                ; 0a21 40
 
                LR  $1,A                ; 0a22 51
 
                LI  $0a                ; 0a23 20 0a
 
                AS  $2                  ; 0a25 c2
 
                LR  $2,A                ; 0a26 52
 
                LI  $0f                ; 0a27 20 0f
 
                NS  (IS)                ; 0a29 fc
 
                LR  $0,A                ; 0a2a 50
 
                LIS  $4                  ; 0a2b 74
 
                LR  $4,A                ; 0a2c 54
 
                LIS  $5                  ; 0a2d 75
 
                LR  $5,A                ; 0a2e 55
 
                PI  A0858              ; 0a2f 28 08 58
 
                LR  A,(IS)-            ; 0a32 4e
 
                SR  4                  ; 0a33 14
 
                LR  $0,A                ; 0a34 50
 
                LI  $fb                ; 0a35 20 fb
 
                AS  $1                  ; 0a37 c1
 
                LR  $1,A                ; 0a38 51
 
                PI  A0858              ; 0a39 28 08 58
 
                LR  A,(IS)              ; 0a3c 4c
 
                NI  $0f                ; 0a3d 21 0f
 
                LR  $0,A                ; 0a3f 50
 
                LI  $fb                ; 0a40 20 fb
 
                AS  $1                  ; 0a42 c1
 
                LR  $1,A                ; 0a43 51
 
                PI  A0858              ; 0a44 28 08 58
 
                LR  A,(IS)              ; 0a47 4c
 
                SR  4                  ; 0a48 14
 
                LR  $0,A                ; 0a49 50
 
                LI  $fb                ; 0a4a 20 fb
 
                AS  $1                  ; 0a4c c1
 
                LR  $1,A                ; 0a4d 51
 
                PI  A0858              ; 0a4e 28 08 58
 
                LR  P,K                ; 0a51 09
 
                POP                      ; 0a52 1c
 
A0a53:          LR  K,P                ; 0a53 08
 
                LI  $10                ; 0a54 20 10
 
                AS  $b                  ; 0a56 cb
 
                LR  IS,A                ; 0a57 0b
 
                LR  A,(IS)              ; 0a58 4c
 
                LR  $1,A                ; 0a59 51
 
                LR  A,IS                ; 0a5a 0a
 
                AI  $0b                ; 0a5b 24 0b
 
                LR  IS,A                ; 0a5d 0b
 
                LR  A,(IS)              ; 0a5e 4c
 
                LR  $9,A                ; 0a5f 59
 
                NI  $3f                ; 0a60 21 3f
 
                LR  $2,A                ; 0a62 52
 
                LISU 7                  ; 0a63 67
 
                LISL 0                  ; 0a64 68
 
                LR  A,(IS)              ; 0a65 4c
 
                LR  $4,A                ; 0a66 54
 
                LR  $5,A                ; 0a67 55
 
                LI  $80                ; 0a68 20 80
 
                LR  $0,A                ; 0a6a 50
 
                PI  A0862              ; 0a6b 28 08 62
 
                LR  A,$9                ; 0a6e 49
 
                LR  $2,A                ; 0a6f 52
 
                LR  A,$b                ; 0a70 4b
 
                SR  1                  ; 0a71 12
 
                AI  $26                ; 0a72 24 26
 
                LR  IS,A                ; 0a74 0b
 
                LIS  $1                  ; 0a75 71
 
                NS  $b                  ; 0a76 fb
 
                LIS  $f                  ; 0a77 7f
 
                BF  $4,A0a7b            ; 0a78 94 02
 
                COM                      ; 0a7a 18
 
A0a7b:          LR  $6,A                ; 0a7b 56
 
                COM                      ; 0a7c 18
 
                NS  (IS)                ; 0a7d fc
 
                LR  $0,A                ; 0a7e 50
 
                LR  A,$6                ; 0a7f 46
 
                NS  (IS)                ; 0a80 fc
 
                LR  $3,A                ; 0a81 53
 
                SR  4                  ; 0a82 14
 
                BT  4,A0a86            ; 0a83 84 02
 
                LR  $3,A                ; 0a85 53
 
A0a86:          LIS  $0                  ; 0a86 70
 
                AS  $1                  ; 0a87 c1
 
                LR  J,W                ; 0a88 1e
 
                LR  A,$3                ; 0a89 43
 
                SR  1                  ; 0a8a 12
 
                SR  1                  ; 0a8b 12
 
                LR  W,J                ; 0a8c 1d
 
                BT  1,A0a91            ; 0a8d 81 03
 
                COM                      ; 0a8f 18
 
                INC                      ; 0a90 1f
 
A0a91:          AS  $1                  ; 0a91 c1
 
                LR  $1,A                ; 0a92 51
 
                LIS  $0                  ; 0a93 70
 
                AS  $2                  ; 0a94 c2
 
                LR  J,W                ; 0a95 1e
 
                LIS  $3                  ; 0a96 73
 
                NS  $3                  ; 0a97 f3
 
                LR  W,J                ; 0a98 1d
 
                BT  1,A0a9d            ; 0a99 81 03
 
                COM                      ; 0a9b 18
 
                INC                      ; 0a9c 1f
 
A0a9d:          AS  $2                  ; 0a9d c2
 
                LR  $2,A                ; 0a9e 52
 
                LISU 6                  ; 0a9f 66
 
                LISL 0                  ; 0aa0 68
 
                LR  A,$b                ; 0aa1 4b
 
                CI  $01                ; 0aa2 25 01
 
                BF  $2,A0aa7            ; 0aa4 92 02
 
                LISL 1                  ; 0aa6 69
 
A0aa7:          LR  A,(IS)              ; 0aa7 4c
 
                LR  $4,A                ; 0aa8 54
 
                LR  A,IS                ; 0aa9 0a
 
                AI  $03                ; 0aaa 24 03
 
                LR  IS,A                ; 0aac 0b
 
                LR  A,(IS)              ; 0aad 4c
 
                LR  $5,A                ; 0aae 55
 
                LIS  $0                  ; 0aaf 70
 
                LR  $0,A                ; 0ab0 50
 
                AS  $1                  ; 0ab1 c1
 
                BF  $1,A0acb            ; 0ab2 91 18
 
                AS  $4                  ; 0ab4 c4
 
                BF  $2,A0adf            ; 0ab5 92 29
 
                LR  A,$4                ; 0ab7 44
 
                COM                      ; 0ab8 18
 
                INC                      ; 0ab9 1f
 
                AI  $80                ; 0aba 24 80
 
                LR  $1,A                ; 0abc 51
 
                LI  $40                ; 0abd 20 40
 
                LR  $3,A                ; 0abf 53
 
                PI  A0cc8              ; 0ac0 28 0c c8
 
A0ac3:          LISU 7                  ; 0ac3 67
 
                LISL 1                  ; 0ac4 69
 
                LR  A,(IS)              ; 0ac5 4c
 
                SL  1                  ; 0ac6 13
 
                SL  1                  ; 0ac7 13
 
                LR  $0,A                ; 0ac8 50
 
                BF  $0,A0adf            ; 0ac9 90 15
 
A0acb:          LR  A,$1                ; 0acb 41
 
                NI  $7f                ; 0acc 21 7f
 
                COM                      ; 0ace 18
 
                INC                      ; 0acf 1f
 
                LISU 6                  ; 0ad0 66
 
                LISL 2                  ; 0ad1 6a
 
                AS  (IS)                ; 0ad2 cc
 
                BF  $2,A0adf            ; 0ad3 92 0b
 
                LR  A,(IS)              ; 0ad5 4c
 
                LR  $1,A                ; 0ad6 51
 
                LI  $40                ; 0ad7 20 40
 
                LR  $3,A                ; 0ad9 53
 
                PI  A0cc8              ; 0ada 28 0c c8
 
                BF  $0,A0ac3            ; 0add 90 e5
 
A0adf:          LIS  $0                  ; 0adf 70
 
                AS  $2                  ; 0ae0 c2
 
                BF  $1,A0afb            ; 0ae1 91 19
 
                NI  $3f                ; 0ae3 21 3f
 
                AS  $5                  ; 0ae5 c5
 
                BF  $2,A0b0e            ; 0ae6 92 27
 
                LR  A,$5                ; 0ae8 45
 
                COM                      ; 0ae9 18
 
                INC                      ; 0aea 1f
 
                AI  $80                ; 0aeb 24 80
 
                LR  $2,A                ; 0aed 52
 
                LI  $40                ; 0aee 20 40
 
                LR  $3,A                ; 0af0 53
 
                PI  A0cc8              ; 0af1 28 0c c8
 
A0af4:          LISU 7                  ; 0af4 67
 
                LISL 1                  ; 0af5 69
 
                LR  A,(IS)              ; 0af6 4c
 
                AS  $0                  ; 0af7 c0
 
                LR  $0,A                ; 0af8 50
 
                BF  $0,A0b0e            ; 0af9 90 14
 
A0afb:          LISU 6                  ; 0afb 66
 
                NI  $3f                ; 0afc 21 3f
 
                COM                      ; 0afe 18
 
                INC                      ; 0aff 1f
 
                LISL 5                  ; 0b00 6d
 
                AS  (IS)                ; 0b01 cc
 
                BF  $2,A0b0e            ; 0b02 92 0b
 
                LR  A,(IS)              ; 0b04 4c
 
                LR  $2,A                ; 0b05 52
 
                LI  $40                ; 0b06 20 40
 
                LR  $3,A                ; 0b08 53
 
                PI  A0cc8              ; 0b09 28 0c c8
 
                BF  $0,A0af4            ; 0b0c 90 e7
 
A0b0e:          LR  A,$0                ; 0b0e 40
 
                SL  4                  ; 0b0f 15
 
                AS  $0                  ; 0b10 c0
 
                LR  $0,A                ; 0b11 50
 
                LR  A,$b                ; 0b12 4b
 
                SR  1                  ; 0b13 12
 
                AI  $26                ; 0b14 24 26
 
                LR  IS,A                ; 0b16 0b
 
                LIS  $1                  ; 0b17 71
 
                NS  $b                  ; 0b18 fb
 
                LIS  $f                  ; 0b19 7f
 
                BF  $4,A0b1d            ; 0b1a 94 02
 
                COM                      ; 0b1c 18
 
A0b1d:          LR  $7,A                ; 0b1d 57
 
                COM                      ; 0b1e 18
 
                LR  $6,A                ; 0b1f 56
 
                NS  (IS)                ; 0b20 fc
 
                LR  $4,A                ; 0b21 54
 
                LR  A,$7                ; 0b22 47
 
                NS  (IS)                ; 0b23 fc
 
                LR  $5,A                ; 0b24 55
 
                LI  $33                ; 0b25 20 33
 
                NS  $0                  ; 0b27 f0
 
                BT  4,A0b35            ; 0b28 84 0c
 
                LI  $cc                ; 0b2a 20 cc
 
                NS  $7                  ; 0b2c f7
 
                NS  $5                  ; 0b2d f5
 
                LR  $5,A                ; 0b2e 55
 
                LI  $33                ; 0b2f 20 33
 
                NS  $0                  ; 0b31 f0
 
                AS  $5                  ; 0b32 c5
 
                NS  $7                  ; 0b33 f7
 
                LR  $5,A                ; 0b34 55
 
A0b35:          LI  $cc                ; 0b35 20 cc
 
                NS  $0                  ; 0b37 f0
 
                BT  4,A0b45            ; 0b38 84 0c
 
                LI  $33                ; 0b3a 20 33
 
                NS  $7                  ; 0b3c f7
 
                NS  $5                  ; 0b3d f5
 
                LR  $5,A                ; 0b3e 55
 
                LI  $cc                ; 0b3f 20 cc
 
                NS  $0                  ; 0b41 f0
 
                AS  $5                  ; 0b42 c5
 
                NS  $7                  ; 0b43 f7
 
                LR  $5,A                ; 0b44 55
 
A0b45:          LR  A,$5                ; 0b45 45
 
                AS  $4                  ; 0b46 c4
 
                LR  $0,A                ; 0b47 50
 
                PI  A09a2              ; 0b48 28 09 a2
 
                DCI  A0850              ; 0b4b 2a 08 50
 
                LR  A,$b                ; 0b4e 4b
 
                CI  $01                ; 0b4f 25 01
 
                LIS  $2                  ; 0b51 72
 
                BF  $2,A0b55            ; 0b52 92 02
 
                LR  A,$b                ; 0b54 4b
 
A0b55:          ADC                      ; 0b55 8e
 
                LR  A,$2                ; 0b56 42
 
                NI  $7f                ; 0b57 21 7f
 
                OM                      ; 0b59 8b
 
                LR  $2,A                ; 0b5a 52
 
                LI  $80                ; 0b5b 20 80
 
                LR  $0,A                ; 0b5d 50
 
                LISU 7                  ; 0b5e 67
 
                LISL 0                  ; 0b5f 68
 
                LR  A,(IS)              ; 0b60 4c
 
                LR  $4,A                ; 0b61 54
 
                LR  $5,A                ; 0b62 55
 
                LISU 7                  ; 0b63 67
 
                LISL 2                  ; 0b64 6a
 
                LIS  $0                  ; 0b65 70
 
                AS  (IS)                ; 0b66 cc
 
                BF  $1,A0b6c            ; 0b67 91 04
 
                PI  A0862              ; 0b69 28 08 62
 
A0b6c:          LR  P,K                ; 0b6c 09
 
                POP                      ; 0b6d 1c
 
A0b6e:          LR  K,P                ; 0b6e 08
 
                LISU 5                  ; 0b6f 65
 
                LISL 7                  ; 0b70 6f
 
                LI  $0f                ; 0b71 20 0f
 
                NS  (IS)                ; 0b73 fc
 
                LISU 7                  ; 0b74 67
 
                LISL 1                  ; 0b75 69
 
                INC                      ; 0b76 1f
 
                LR  (IS),A              ; 0b77 5c
 
A0b78:          LISU 7                  ; 0b78 67
 
                LISL 1                  ; 0b79 69
 
                DS  (IS)                ; 0b7a 3c
 
                BF  $1,A0b6c            ; 0b7b 91 f0
 
                LR  A,(IS)              ; 0b7d 4c
 
                XS  $b                  ; 0b7e eb
 
                BT  4,A0b78            ; 0b7f 84 f8
 
                LISL 5                  ; 0b81 6d
 
                LIS  $1                  ; 0b82 71
 
                NS  (IS)                ; 0b83 fc
 
                BF  $4,A0b8c            ; 0b84 94 07
 
                LISL 1                  ; 0b86 69
 
                LR  A,(IS)              ; 0b87 4c
 
                CI  $01                ; 0b88 25 01
 
                BT  4,A0b78            ; 0b8a 84 ed
 
A0b8c:          LI  $10                ; 0b8c 20 10
 
                AS  $b                  ; 0b8e cb
 
                LR  IS,A                ; 0b8f 0b
 
                LR  A,(IS)              ; 0b90 4c
 
                NI  $7f                ; 0b91 21 7f
 
                LR  $1,A                ; 0b93 51
 
                LR  A,IS                ; 0b94 0a
 
                AI  $0b                ; 0b95 24 0b
 
                LR  IS,A                ; 0b97 0b
 
                LR  A,(IS)              ; 0b98 4c
 
                NI  $3f                ; 0b99 21 3f
 
                LR  $2,A                ; 0b9b 52
 
                LISU 7                  ; 0b9c 67
 
                LISL 1                  ; 0b9d 69
 
                LI  $10                ; 0b9e 20 10
 
                AS  (IS)                ; 0ba0 cc
 
                LR  IS,A                ; 0ba1 0b
 
                LR  A,(IS)              ; 0ba2 4c
 
                NI  $7f                ; 0ba3 21 7f
 
                COM                      ; 0ba5 18
 
                INC                      ; 0ba6 1f
 
                AS  $1                  ; 0ba7 c1
 
                LR  J,W                ; 0ba8 1e
 
                BT  1,A0bad            ; 0ba9 81 03
 
                COM                      ; 0bab 18
 
                INC                      ; 0bac 1f
 
A0bad:          LR  $1,A                ; 0bad 51
 
                LR  A,IS                ; 0bae 0a
 
                CI  $11                ; 0baf 25 11
 
                BF  $2,A0bbd            ; 0bb1 92 0b
 
                LR  W,J                ; 0bb3 1d
 
                BF  $1,A0bbd            ; 0bb4 91 08
 
                LI  $c0                ; 0bb6 20 c0
 
                NS  $a                  ; 0bb8 fa
 
                SR  1                  ; 0bb9 12
 
                SR  1                  ; 0bba 12
 
                BF  $0,A0bc0            ; 0bbb 90 04
 
A0bbd:          LI  $30                ; 0bbd 20 30
 
                NS  $a                  ; 0bbf fa
 
A0bc0:          SR  4                  ; 0bc0 14
 
                COM                      ; 0bc1 18
 
                INC                      ; 0bc2 1f
 
                AS  $1                  ; 0bc3 c1
 
                BT  1,A0b78            ; 0bc4 81 b3
 
                LR  A,IS                ; 0bc6 0a
 
                AI  $0b                ; 0bc7 24 0b
 
                LR  IS,A                ; 0bc9 0b
 
                LR  A,(IS)              ; 0bca 4c
 
                NI  $3f                ; 0bcb 21 3f
 
                COM                      ; 0bcd 18
 
                INC                      ; 0bce 1f
 
                AS  $2                  ; 0bcf c2
 
                LR  J,W                ; 0bd0 1e
 
                BT  1,A0bd5            ; 0bd1 81 03
 
                COM                      ; 0bd3 18
 
                INC                      ; 0bd4 1f
 
A0bd5:          LR  $2,A                ; 0bd5 52
 
                LR  A,IS                ; 0bd6 0a
 
                CI  $1c                ; 0bd7 25 1c
 
                BF  $2,A0be5            ; 0bd9 92 0b
 
                LR  W,J                ; 0bdb 1d
 
                BF  $1,A0be5            ; 0bdc 91 08
 
                LI  $c0                ; 0bde 20 c0
 
                NS  $a                  ; 0be0 fa
 
                SR  1                  ; 0be1 12
 
                SR  1                  ; 0be2 12
 
                BF  $0,A0be8            ; 0be3 90 04
 
A0be5:          LI  $30                ; 0be5 20 30
 
                NS  $a                  ; 0be7 fa
 
A0be8:          SR  4                  ; 0be8 14
 
                COM                      ; 0be9 18
 
                INC                      ; 0bea 1f
 
                AS  $2                  ; 0beb c2
 
                BT  1,A0b78            ; 0bec 81 8b
 
                LISU 7                  ; 0bee 67
 
                LISL 1                  ; 0bef 69
 
                LR  A,(IS)              ; 0bf0 4c
 
                CI  $01                ; 0bf1 25 01
 
                BF  $2,A0bf8            ; 0bf3 92 04
 
                JMP  A0e44              ; 0bf5 29 0e 44
 
A0bf8:          LI  $80                ; 0bf8 20 80
 
                LR  $3,A                ; 0bfa 53
 
                PI  A0cc8              ; 0bfb 28 0c c8
 
                PI  A08c1              ; 0bfe 28 08 c1
 
                LR  A,$2                ; 0c01 42
 
                CI  $01                ; 0c02 25 01
 
                BT  2,A0c41            ; 0c04 82 3c
 
                LI  $10                ; 0c06 20 10
 
                AS  $b                  ; 0c08 cb
 
                LR  IS,A                ; 0c09 0b
 
                LI  $80                ; 0c0a 20 80
 
                NS  $6                  ; 0c0c f6
 
                XS  (IS)                ; 0c0d ec
 
                LR  (IS),A              ; 0c0e 5c
 
                LR  J,W                ; 0c0f 1e
 
                LISU 7                  ; 0c10 67
 
                LISL 1                  ; 0c11 69
 
                LI  $10                ; 0c12 20 10
 
                AS  (IS)                ; 0c14 cc
 
                LR  IS,A                ; 0c15 0b
 
                LI  $80                ; 0c16 20 80
 
                NS  $7                  ; 0c18 f7
 
                AS  (IS)                ; 0c19 cc
 
                LR  (IS),A              ; 0c1a 5c
 
                LI  $44                ; 0c1b 20 44
 
                LR  $8,A                ; 0c1d 58
 
                LR  A,$b                ; 0c1e 4b
 
                LR  $0,A                ; 0c1f 50
 
A0c20:          LISU 7                  ; 0c20 67
 
                LISL 5                  ; 0c21 6d
 
                LIS  $0                  ; 0c22 70
 
                AS  (IS)                ; 0c23 cc
 
                BT  1,A0c29            ; 0c24 81 04
 
                JMP  A0b78              ; 0c26 29 0b 78
 
A0c29:          LR  A,$0                ; 0c29 40
 
                SR  1                  ; 0c2a 12
 
                AI  $26                ; 0c2b 24 26
 
                LR  IS,A                ; 0c2d 0b
 
                LIS  $1                  ; 0c2e 71
 
                NS  $0                  ; 0c2f f0
 
                LIS  $f                  ; 0c30 7f
 
                BF  $4,A0c34            ; 0c31 94 02
 
                COM                      ; 0c33 18
 
A0c34:          LR  $3,A                ; 0c34 53
 
                COM                      ; 0c35 18
 
                NS  (IS)                ; 0c36 fc
 
                LR  $4,A                ; 0c37 54
 
                LR  A,$3                ; 0c38 43
 
                NS  (IS)                ; 0c39 fc
 
                AS  $8                  ; 0c3a c8
 
                NS  $3                  ; 0c3b f3
 
                AS  $4                  ; 0c3c c4
 
                LR  (IS),A              ; 0c3d 5c
 
                JMP  A0b6c              ; 0c3e 29 0b 6c
 
A0c41:          LISU 7                  ; 0c41 67
 
                LISL 1                  ; 0c42 69
 
                LR  A,(IS)              ; 0c43 4c
 
                LR  $0,A                ; 0c44 50
 
                AI  $1b                ; 0c45 24 1b
 
                LR  IS,A                ; 0c47 0b
 
                LI  $80                ; 0c48 20 80
 
                XS  (IS)                ; 0c4a ec
 
                LR  (IS),A              ; 0c4b 5c
 
                LR  J,W                ; 0c4c 1e
 
                LI  $1b                ; 0c4d 20 1b
 
                AS  $b                  ; 0c4f cb
 
                LR  IS,A                ; 0c50 0b
 
                LR  A,(IS)              ; 0c51 4c
 
                OI  $80                ; 0c52 22 80
 
                LR  W,J                ; 0c54 1d
 
                BT  1,A0c59            ; 0c55 81 03
 
                NI  $3f                ; 0c57 21 3f
 
A0c59:          LR  (IS),A              ; 0c59 5c
 
                LI  $44                ; 0c5a 20 44
 
                LR  $8,A                ; 0c5c 58
 
                BF  $0,A0c20            ; 0c5d 90 c2
 
A0c5f:          LR  K,P                ; 0c5f 08
 
A0c60:          PI  A08c1              ; 0c60 28 08 c1
 
                LIS  $0                  ; 0c63 70
 
                AS  $6                  ; 0c64 c6
 
                BT  4,A0c60            ; 0c65 84 fa
 
                LR  A,$1                ; 0c67 41
 
                CI  $58                ; 0c68 25 58
 
                LR  A,$6                ; 0c6a 46
 
                BF  $4,A0c71            ; 0c6b 94 05
 
                CI  $12                ; 0c6d 25 12
 
                BF  $0,A0c73            ; 0c6f 90 03
 
A0c71:          CI  $0b                ; 0c71 25 0b
 
A0c73:          BF  $2,A0c60            ; 0c73 92 ec
 
                COM                      ; 0c75 18
 
                INC                      ; 0c76 1f
 
                INC                      ; 0c77 1f
 
                AS  $1                  ; 0c78 c1
 
                COM                      ; 0c79 18
 
                INC                      ; 0c7a 1f
 
                LR  $4,A                ; 0c7b 54
 
                LI  $30                ; 0c7c 20 30
 
                NS  $a                  ; 0c7e fa
 
                SR  4                  ; 0c7f 14
 
                AS  $4                  ; 0c80 c4
 
                LR  (IS)+,A            ; 0c81 5d
 
                LI  $c0                ; 0c82 20 c0
 
                NS  $a                  ; 0c84 fa
 
                SR  4                  ; 0c85 14
 
                SR  1                  ; 0c86 12
 
                SR  1                  ; 0c87 12
 
                AS  $4                  ; 0c88 c4
 
                LR  (IS)+,A            ; 0c89 5d
 
                LR  A,$6                ; 0c8a 46
 
                AS  $2                  ; 0c8b c2
 
                LR  (IS)+,A            ; 0c8c 5d
 
                LR  P,K                ; 0c8d 09
 
                POP                      ; 0c8e 1c
 
                LR  K,P                ; 0c8f 08
 
                LI  $25                ; 0c90 20 25
 
                LR  $9,A                ; 0c92 59
 
                LISU 7                  ; 0c93 67
 
                LISL 1                  ; 0c94 69
 
                LIS  $1                  ; 0c95 71
 
                NS  (IS)-              ; 0c96 fe
 
                LI  $80                ; 0c97 20 80
 
                BT  4,A0c9d            ; 0c99 84 03
 
                LI  $c0                ; 0c9b 20 c0
 
A0c9d:          LR  (IS),A              ; 0c9d 5c
 
                LR  $2,A                ; 0c9e 52
 
A0c9f:          LR  A,(IS)              ; 0c9f 4c
 
A0ca0:          LR  $2,A                ; 0ca0 52
 
                LR  A,(IS)              ; 0ca1 4c
 
                LR  $3,A                ; 0ca2 53
 
                PI  A0cc8              ; 0ca3 28 0c c8
 
                LISL 0                  ; 0ca6 68
 
                LI  $7d                ; 0ca7 20 7d
 
                LR  $1,A                ; 0ca9 51
 
                LIS  $2                  ; 0caa 72
 
                LR  $4,A                ; 0cab 54
 
                LI  $40                ; 0cac 20 40
 
                LR  $5,A                ; 0cae 55
 
                LI  $c0                ; 0caf 20 c0
 
                LR  $0,A                ; 0cb1 50
 
                PI  A0862              ; 0cb2 28 08 62
 
                LIS  $0                  ; 0cb5 70
 
                OUTS 5                  ; 0cb6 b5
 
                LIS  $b                  ; 0cb7 7b
 
                LR  $0,A                ; 0cb8 50
 
                PI  A099a              ; 0cb9 28 09 9a
 
                DS  $9                  ; 0cbc 39
 
                BF  $1,A0cc6            ; 0cbd 91 08
 
                LIS  $1                  ; 0cbf 71
 
                NS  $9                  ; 0cc0 f9
 
                LIS  $0                  ; 0cc1 70
 
                BT  4,A0c9f            ; 0cc2 84 dc
 
                BF  $0,A0ca0            ; 0cc4 90 db
 
A0cc6:          LR  P,K                ; 0cc6 09
 
                POP                      ; 0cc7 1c
 
A0cc8:          LR  A,$b                ; 0cc8 4b
 
                CI  $01                ; 0cc9 25 01
 
                BT  2,A0ccf            ; 0ccb 82 03
 
                LR  A,$3                ; 0ccd 43
 
                OUTS 5                  ; 0cce b5
 
A0ccf:          POP                      ; 0ccf 1c
 
A0cd0:          LISU 7                  ; 0cd0 67
 
                LISL 7                  ; 0cd1 6f
 
                LI  $40                ; 0cd2 20 40
 
                OUTS 0                  ; 0cd4 b0
 
                INS  4                  ; 0cd5 a4
 
                LR  (IS)-,A            ; 0cd6 5e
 
                INS  5                  ; 0cd7 a5
 
                LR  (IS)-,A            ; 0cd8 5e
 
                LISL 3                  ; 0cd9 6b
 
                LIS  $0                  ; 0cda 70
 
                LR  (IS),A              ; 0cdb 5c
 
                OUTS 0                  ; 0cdc b0
 
                LI  $80                ; 0cdd 20 80
 
                LR  $0,A                ; 0cdf 50
 
                LIS  $0                  ; 0ce0 70
 
                LR  $1,A                ; 0ce1 51
 
                LR  $2,A                ; 0ce2 52
 
                LI  $80                ; 0ce3 20 80
 
                LR  $4,A                ; 0ce5 54
 
                LI  $40                ; 0ce6 20 40
 
                LR  $5,A                ; 0ce8 55
 
                PI  A0862              ; 0ce9 28 08 62
 
                LI  $c0                ; 0cec 20 c0
 
                LR  $0,A                ; 0cee 50
 
                LR  $2,A                ; 0cef 52
 
                LIS  $2                  ; 0cf0 72
 
                LR  $4,A                ; 0cf1 54
 
                LI  $7d                ; 0cf2 20 7d
 
                LR  $1,A                ; 0cf4 51
 
                PI  A0862              ; 0cf5 28 08 62
 
                LIS  $a                  ; 0cf8 7a
 
                LR  $0,A                ; 0cf9 50
 
                LI  $30                ; 0cfa 20 30
 
                LR  $1,A                ; 0cfc 51
 
                LI  $9b                ; 0cfd 20 9b
 
                LR  $2,A                ; 0cff 52
 
                LIS  $4                  ; 0d00 74
 
                LR  $4,A                ; 0d01 54
 
                LIS  $5                  ; 0d02 75
 
                LR  $5,A                ; 0d03 55
 
                PI  A0858              ; 0d04 28 08 58
 
                LIS  $b                  ; 0d07 7b
 
                LR  $0,A                ; 0d08 50
 
                LI  $35                ; 0d09 20 35
 
                LR  $1,A                ; 0d0b 51
 
                PI  A0858              ; 0d0c 28 08 58
 
                PI  A08f0              ; 0d0f 28 08 f0
 
                LISU 7                  ; 0d12 67
 
                LISL 5                  ; 0d13 6d
 
                SR  1                  ; 0d14 12
 
                ADC                      ; 0d15 8e
 
                LM                      ; 0d16 16
 
                LR  (IS),A              ; 0d17 5c
 
A0d18:          LISU 7                  ; 0d18 67
 
                LISL 5                  ; 0d19 6d
 
                LR  A,(IS)              ; 0d1a 4c
 
                NI  $03                ; 0d1b 21 03
 
                LR  (IS),A              ; 0d1d 5c
 
A0d1e:          DCI  A0843              ; 0d1e 2a 08 43
 
                PI  A08c1              ; 0d21 28 08 c1
 
                LM                      ; 0d24 16
 
                NS  $6                  ; 0d25 f6
 
                LR  $8,A                ; 0d26 58
 
                LM                      ; 0d27 16
 
                NS  $6                  ; 0d28 f6
 
                SL  1                  ; 0d29 13
 
                SL  1                  ; 0d2a 13
 
                AS  $8                  ; 0d2b c8
 
                BF  $2,A0d1e            ; 0d2c 92 f1
 
                LM                      ; 0d2e 16
 
                NS  $6                  ; 0d2f f6
 
                BT  4,A0d1e            ; 0d30 84 ed
 
                LM                      ; 0d32 16
 
                NS  $6                  ; 0d33 f6
 
                BT  4,A0d1e            ; 0d34 84 e9
 
                LR  A,$6                ; 0d36 46
 
                LR  $a,A                ; 0d37 5a
 
                LM                      ; 0d38 16
 
                NS  $7                  ; 0d39 f7
 
                AS  (IS)                ; 0d3a cc
 
                LR  (IS)-,A            ; 0d3b 5e
 
                DCI  A0848              ; 0d3c 2a 08 48
 
                LIS  $3                  ; 0d3f 73
 
                NS  $a                  ; 0d40 fa
 
                SL  1                  ; 0d41 13
 
                ADC                      ; 0d42 8e
 
                LI  $58                ; 0d43 20 58
 
                LR  $1,A                ; 0d45 51
 
                LI  $10                ; 0d46 20 10
 
                LR  $2,A                ; 0d48 52
 
                LISU 6                  ; 0d49 66
 
                LISL 0                  ; 0d4a 68
 
                PI  A0c5f              ; 0d4b 28 0c 5f
 
                LI  $38                ; 0d4e 20 38
 
                LR  $1,A                ; 0d50 51
 
                PI  A0c5f              ; 0d51 28 0c 5f
 
A0d54:          LI  $80                ; 0d54 20 80
 
                LR  $0,A                ; 0d56 50
 
                LI  $10                ; 0d57 20 10
 
                LR  $1,A                ; 0d59 51
 
                AI  $80                ; 0d5a 24 80
 
                LR  $2,A                ; 0d5c 52
 
                LI  $49                ; 0d5d 20 49
 
                LR  $4,A                ; 0d5f 54
 
                LI  $29                ; 0d60 20 29
 
                LR  $5,A                ; 0d62 55
 
                PI  A0862              ; 0d63 28 08 62
 
                LISU 6                  ; 0d66 66
 
                LISL 2                  ; 0d67 6a
 
                LR  A,(IS)              ; 0d68 4c
 
                LR  $1,A                ; 0d69 51
 
                LISL 0                  ; 0d6a 68
 
                AS  (IS)                ; 0d6b cc
 
                COM                      ; 0d6c 18
 
                INC                      ; 0d6d 1f
 
                LR  $4,A                ; 0d6e 54
 
                LI  $30                ; 0d6f 20 30
 
                NS  $a                  ; 0d71 fa
 
                SR  4                  ; 0d72 14
 
                LR  $3,A                ; 0d73 53
 
                AS  $4                  ; 0d74 c4
 
                LR  $4,A                ; 0d75 54
 
                LISL 5                  ; 0d76 6d
 
                LR  A,(IS)              ; 0d77 4c
 
                LR  $2,A                ; 0d78 52
 
                LISL 3                  ; 0d79 6b
 
                AS  (IS)                ; 0d7a cc
 
                COM                      ; 0d7b 18
 
                INC                      ; 0d7c 1f
 
                AS  $3                  ; 0d7d c3
 
                LR  $5,A                ; 0d7e 55
 
                LI  $80                ; 0d7f 20 80
 
                LR  $0,A                ; 0d81 50
 
                PI  A0862              ; 0d82 28 08 62
 
                LISU 6                  ; 0d85 66
 
                LISL 6                  ; 0d86 6e
 
                LIS  $0                  ; 0d87 70
 
                LR  (IS)+,A            ; 0d88 5d
 
                LR  (IS)+,A            ; 0d89 5d
 
                LIS  $0                  ; 0d8a 70
 
A0d8b:          LR  $b,A                ; 0d8b 5b
 
                PI  A09c2              ; 0d8c 28 09 c2
 
                LR  A,$b                ; 0d8f 4b
 
                INC                      ; 0d90 1f
 
                CI  $01                ; 0d91 25 01
 
                BT  2,A0d8b            ; 0d93 82 f7
 
                LISU 5                  ; 0d95 65
 
                LISL 6                  ; 0d96 6e
 
                LR  (IS),A              ; 0d97 5c
 
                LR  $b,A                ; 0d98 5b
 
                PI  A09c2              ; 0d99 28 09 c2
 
                LISU 7                  ; 0d9c 67
 
                LISL 2                  ; 0d9d 6a
 
                LIS  $0                  ; 0d9e 70
 
                LR  (IS),A              ; 0d9f 5c
 
A0da0:          LIS  $0                  ; 0da0 70
 
                OUTS 5                  ; 0da1 b5
 
                LISU 6                  ; 0da2 66
 
                LISL 6                  ; 0da3 6e
 
                LR  A,(IS)+            ; 0da4 4d
 
                INC                      ; 0da5 1f
 
                CI  $0a                ; 0da6 25 0a
 
                BT  2,A0dab            ; 0da8 82 02
 
                LIS  $a                  ; 0daa 7a
 
A0dab:          LISU 5                  ; 0dab 65
 
                LR  (IS),A              ; 0dac 5c
 
                LISU 6                  ; 0dad 66
 
                LI  $67                ; 0dae 20 67
 
                ASD  (IS)                ; 0db0 dc
 
                LR  (IS)-,A            ; 0db1 5e
 
                BF  $2,A0dc5            ; 0db2 92 12
 
                LI  $67                ; 0db4 20 67
 
                ASD  (IS)                ; 0db6 dc
 
                LR  (IS)+,A            ; 0db7 5d
 
                NI  $0f                ; 0db8 21 0f
 
                BF  $4,A0dc5            ; 0dba 94 0a
 
                LIS  $0                  ; 0dbc 70
 
                AS  (IS)                ; 0dbd cc
 
                BF  $4,A0dc5            ; 0dbe 94 06
 
                LISU 7                  ; 0dc0 67
 
                LISL 2                  ; 0dc1 6a
 
                LI  $80                ; 0dc2 20 80
 
                LR  (IS),A              ; 0dc4 5c
 
A0dc5:          LISU 7                  ; 0dc5 67
 
                LISL 5                  ; 0dc6 6d
 
                LIS  $1                  ; 0dc7 71
 
                NS  (IS)                ; 0dc8 fc
 
                LI  $39                ; 0dc9 20 39
 
                BF  $4,A0dcf            ; 0dcb 94 03
 
                LI  $1f                ; 0dcd 20 1f
 
A0dcf:          LR  $0,A                ; 0dcf 50
 
                LI  $80                ; 0dd0 20 80
 
                LR  $2,A                ; 0dd2 52
 
                LISU 6                  ; 0dd3 66
 
                LISL 7                  ; 0dd4 6f
 
                PI  A0a20              ; 0dd5 28 0a 20
 
                LISU 5                  ; 0dd8 65
 
                LISL 7                  ; 0dd9 6f
 
                LR  A,(IS)              ; 0dda 4c
 
                LR  $0,A                ; 0ddb 50
 
                PI  A0986              ; 0ddc 28 09 86
 
                LISU 5                  ; 0ddf 65
 
                LISL 6                  ; 0de0 6e
 
                LI  $0f                ; 0de1 20 0f
 
                NS  (IS)+              ; 0de3 fd
 
                LR  $b,A                ; 0de4 5b
 
                LR  A,(IS)              ; 0de5 4c
 
                COM                      ; 0de6 18
 
                INC                      ; 0de7 1f
 
                AS  $b                  ; 0de8 cb
 
                BT  1,A0df7            ; 0de9 81 0d
 
                LR  A,(IS)              ; 0deb 4c
 
                LR  $b,A                ; 0dec 5b
 
                PI  A09c2              ; 0ded 28 09 c2
 
                LISU 5                  ; 0df0 65
 
                LISL 6                  ; 0df1 6e
 
                LI  $f0                ; 0df2 20 f0
 
                NS  (IS)+              ; 0df4 fd
 
                AS  (IS)-              ; 0df5 ce
 
                LR  (IS),A              ; 0df6 5c
 
A0df7:          LISU 5                  ; 0df7 65
 
                LISL 6                  ; 0df8 6e
 
                LI  $0f                ; 0df9 20 0f
 
                NS  (IS)                ; 0dfb fc
 
                LR  $b,A                ; 0dfc 5b
 
A0dfd:          LISU 7                  ; 0dfd 67
 
                LISL 0                  ; 0dfe 68
 
                LI  $30                ; 0dff 20 30
 
                NS  $a                  ; 0e01 fa
 
                SR  4                  ; 0e02 14
 
                LR  (IS)+,A            ; 0e03 5d
 
                LI  $03                ; 0e04 20 03
 
                NS  $a                  ; 0e06 fa
 
                LR  (IS),A              ; 0e07 5c
 
                PI  A0a53              ; 0e08 28 0a 53
 
                PI  A0b6e              ; 0e0b 28 0b 6e
 
                DS  $b                  ; 0e0e 3b
 
                LR  A,$b                ; 0e0f 4b
 
                CI  $01                ; 0e10 25 01
 
                BF  $2,A0dfd            ; 0e12 92 ea
 
                PI  A0924              ; 0e14 28 09 24
 
                LISU 7                  ; 0e17 67
 
                LISL 0                  ; 0e18 68
 
                LI  $c0                ; 0e19 20 c0
 
                NS  $a                  ; 0e1b fa
 
                SR  4                  ; 0e1c 14
 
                SR  1                  ; 0e1d 12
 
                SR  1                  ; 0e1e 12
 
                LR  (IS)+,A            ; 0e1f 5d
 
                LI  $0c                ; 0e20 20 0c
 
                NS  $a                  ; 0e22 fa
 
                SR  1                  ; 0e23 12
 
                SR  1                  ; 0e24 12
 
                LR  (IS),A              ; 0e25 5c
 
                LI  $00                ; 0e26 20 00
 
                LR  $b,A                ; 0e28 5b
 
                PI  A0a53              ; 0e29 28 0a 53
 
                LISU 7                  ; 0e2c 67
 
                LISL 5                  ; 0e2d 6d
 
                LIS  $1                  ; 0e2e 71
 
                NS  (IS)                ; 0e2f fc
 
                BT  4,A0e36            ; 0e30 84 05
 
                LR  $b,A                ; 0e32 5b
 
                PI  A0a53              ; 0e33 28 0a 53
 
A0e36:          LISU 7                  ; 0e36 67
 
                LISL 2                  ; 0e37 6a
 
                LIS  $0                  ; 0e38 70
 
                AS  (IS)                ; 0e39 cc
 
                BT  1,A0e41            ; 0e3a 81 06
 
                LIS  $0                  ; 0e3c 70
 
                LR  (IS),A              ; 0e3d 5c
 
                JMP  A0f6b              ; 0e3e 29 0f 6b
 
A0e41:          JMP  A0da0              ; 0e41 29 0d a0
 
A0e44:          LI  $a4                ; 0e44 20 a4
 
                LR  $2,A                ; 0e46 52
 
                LISU 4                  ; 0e47 64
 
                LISL 6                  ; 0e48 6e
 
                LI  $14                ; 0e49 20 14
 
                LR  (IS),A              ; 0e4b 5c
 
A0e4c:          PI  A0f0a              ; 0e4c 28 0f 0a
 
                LISU 4                  ; 0e4f 64
 
                LISL 6                  ; 0e50 6e
 
                DS  (IS)                ; 0e51 3c
 
                LR  J,W                ; 0e52 1e
 
                LR  A,$2                ; 0e53 42
 
                AI  $40                ; 0e54 24 40
 
                BF  $2,A0e5a            ; 0e56 92 03
 
                AI  $40                ; 0e58 24 40
 
A0e5a:          NI  $c0                ; 0e5a 21 c0
 
                AI  $24                ; 0e5c 24 24
 
                LR  $2,A                ; 0e5e 52
 
                LR  W,J                ; 0e5f 1d
 
                BF  $4,A0e4c            ; 0e60 94 eb
 
                LIS  $0                  ; 0e62 70
 
                LR  $0,A                ; 0e63 50
 
                PI  A099a              ; 0e64 28 09 9a
 
                LISU 7                  ; 0e67 67
 
                LISL 5                  ; 0e68 6d
 
                LIS  $1                  ; 0e69 71
 
                NS  (IS)                ; 0e6a fc
 
                LI  $80                ; 0e6b 20 80
 
                BT  4,A0e78            ; 0e6d 84 0a
 
                LISL 1                  ; 0e6f 69
 
                LIS  $1                  ; 0e70 71
 
                NS  (IS)                ; 0e71 fc
 
                LI  $c0                ; 0e72 20 c0
 
                BT  4,A0e78            ; 0e74 84 03
 
                LI  $40                ; 0e76 20 40
 
A0e78:          AI  $24                ; 0e78 24 24
 
                LR  $2,A                ; 0e7a 52
 
                LISU 4                  ; 0e7b 64
 
                LISL 6                  ; 0e7c 6e
 
                LI  $14                ; 0e7d 20 14
 
                LR  (IS),A              ; 0e7f 5c
 
                PI  A0f0a              ; 0e80 28 0f 0a
 
                LI  $28                ; 0e83 20 28
 
                LR  $0,A                ; 0e85 50
 
                PI  A099a              ; 0e86 28 09 9a
 
                LISU 7                  ; 0e89 67
 
                LISL 5                  ; 0e8a 6d
 
                LIS  $1                  ; 0e8b 71
 
                NS  (IS)                ; 0e8c fc
 
                BF  $4,A0ec6            ; 0e8d 94 38
 
                LISU 6                  ; 0e8f 66
 
                LISL 6                  ; 0e90 6e
 
                LR  A,(IS)+            ; 0e91 4d
 
                LR  $6,A                ; 0e92 56
 
                LR  A,(IS)              ; 0e93 4c
 
                LR  $7,A                ; 0e94 57
 
                LISU 5                  ; 0e95 65
 
                LISL 4                  ; 0e96 6c
 
                LR  A,(IS)+            ; 0e97 4d
 
                COM                      ; 0e98 18
 
                INC                      ; 0e99 1f
 
                AS  $6                  ; 0e9a c6
 
                BF  $1,A0eb2            ; 0e9b 91 16
 
                BF  $4,A0ea5            ; 0e9d 94 07
 
                LR  A,(IS)              ; 0e9f 4c
 
                COM                      ; 0ea0 18
 
                INC                      ; 0ea1 1f
 
                AS  $7                  ; 0ea2 c7
 
                BF  $1,A0eb2            ; 0ea3 91 0e
 
A0ea5:          LR  A,$7                ; 0ea5 47
 
                LR  (IS)-,A            ; 0ea6 5e
 
                LR  A,$6                ; 0ea7 46
 
                LR  (IS)+,A            ; 0ea8 5d
 
                LI  $40                ; 0ea9 20 40
 
                LR  $2,A                ; 0eab 52
 
                LI  $54                ; 0eac 20 54
 
                LR  $0,A                ; 0eae 50
 
                PI  A0a20              ; 0eaf 28 0a 20
 
A0eb2:          LI  $40                ; 0eb2 20 40
 
                LR  $0,A                ; 0eb4 50
 
                PI  A099a              ; 0eb5 28 09 9a
 
                PI  A0910              ; 0eb8 28 09 10
 
                LISL 0                  ; 0ebb 68
 
                LIS  $0                  ; 0ebc 70
 
                AS  (IS)                ; 0ebd cc
 
                BF  $1,A0ec3            ; 0ebe 91 04
 
                JMP  A0d54              ; 0ec0 29 0d 54
 
A0ec3:          JMP  A0d18              ; 0ec3 29 0d 18
 
A0ec6:          LISU 6                  ; 0ec6 66
 
                LISL 6                  ; 0ec7 6e
 
                LR  A,(IS)+            ; 0ec8 4d
 
                LR  $6,A                ; 0ec9 56
 
                LR  A,(IS)              ; 0eca 4c
 
                LR  $7,A                ; 0ecb 57
 
                LISU 7                  ; 0ecc 67
 
                LISL 1                  ; 0ecd 69
 
                LIS  $1                  ; 0ece 71
 
                NS  (IS)                ; 0ecf fc
 
                BF  $4,A0edc            ; 0ed0 94 0b
 
                LI  $c0                ; 0ed2 20 c0
 
                LR  $2,A                ; 0ed4 52
 
                LI  $54                ; 0ed5 20 54
 
                LR  $0,A                ; 0ed7 50
 
                LISU 7                  ; 0ed8 67
 
                LISL 4                  ; 0ed9 6c
 
                BF  $0,A0ee4            ; 0eda 90 09
 
A0edc:          LISU 5                  ; 0edc 65
 
                LISL 5                  ; 0edd 6d
 
                LI  $40                ; 0ede 20 40
 
                LR  $2,A                ; 0ee0 52
 
                LI  $1f                ; 0ee1 20 1f
 
                LR  $0,A                ; 0ee3 50
 
A0ee4:          LR  A,$7                ; 0ee4 47
 
                AS  (IS)                ; 0ee5 cc
 
                LR  (IS),A              ; 0ee6 5c
 
                LI  $66                ; 0ee7 20 66
 
                ASD  (IS)                ; 0ee9 dc
 
                LR  (IS)-,A            ; 0eea 5e
 
                BF  $2,A0ef1            ; 0eeb 92 05
 
                LI  $67                ; 0eed 20 67
 
                ASD  (IS)                ; 0eef dc
 
                LR  (IS),A              ; 0ef0 5c
 
A0ef1:          LR  A,(IS)              ; 0ef1 4c
 
                AS  $6                  ; 0ef2 c6
 
                LR  (IS),A              ; 0ef3 5c
 
                LI  $66                ; 0ef4 20 66
 
                ASD  (IS)                ; 0ef6 dc
 
                LR  (IS)+,A            ; 0ef7 5d
 
                PI  A0a20              ; 0ef8 28 0a 20
 
                PI  A0910              ; 0efb 28 09 10
 
                LISL 0                  ; 0efe 68
 
                LIS  $0                  ; 0eff 70
 
                AS  (IS)+              ; 0f00 cd
 
                BF  $1,A0ec3            ; 0f01 91 c1
 
                LIS  $0                  ; 0f03 70
 
                AS  (IS)                ; 0f04 cc
 
                BF  $1,A0ec3            ; 0f05 91 bd
 
                JMP  A0d54              ; 0f07 29 0d 54
 
A0f0a:          LR  K,P                ; 0f0a 08
 
                LI  $80                ; 0f0b 20 80
 
                LR  $0,A                ; 0f0d 50
 
                LI  $34                ; 0f0e 20 34
 
                LR  $1,A                ; 0f10 51
 
                LISU 2                  ; 0f11 62
 
                LISL 4                  ; 0f12 6c
 
                LIS  $1                  ; 0f13 71
 
                LR  $4,A                ; 0f14 54
 
                LR  $5,A                ; 0f15 55
 
                LR  (IS)+,A            ; 0f16 5d
 
                LR  (IS)+,A            ; 0f17 5d
 
                LR  (IS)+,A            ; 0f18 5d
 
                LR  (IS)-,A            ; 0f19 5e
 
                LISU 4                  ; 0f1a 64
 
                LR  A,(IS)              ; 0f1b 4c
 
                LISU 3                  ; 0f1c 63
 
                LR  (IS),A              ; 0f1d 5c
 
                LISU 2                  ; 0f1e 62
 
                LIS  $1                  ; 0f1f 71
 
                SL  1                  ; 0f20 13
 
                LR  J,W                ; 0f21 1e
 
                PI  A0862              ; 0f22 28 08 62
 
A0f25:          DS  $2                  ; 0f25 32
 
                PI  A0862              ; 0f26 28 08 62
 
                DS  (IS)                ; 0f29 3c
 
                BF  $4,A0f25            ; 0f2a 94 fa
 
                LR  W,J                ; 0f2c 1d
 
                BT  4,A0f69            ; 0f2d 84 3b
 
                LR  A,(IS)+            ; 0f2f 4d
 
                LR  A,(IS)              ; 0f30 4c
 
                INC                      ; 0f31 1f
 
                LR  (IS)-,A            ; 0f32 5e
 
                LR  (IS)-,A            ; 0f33 5e
 
A0f34:          LR  A,$1                ; 0f34 41
 
                INC                      ; 0f35 1f
 
                LR  $1,A                ; 0f36 51
 
                PI  A0862              ; 0f37 28 08 62
 
                DS  (IS)                ; 0f3a 3c
 
                BF  $4,A0f34            ; 0f3b 94 f8
 
                LIS  $0                  ; 0f3d 70
 
                OUTS 5                  ; 0f3e b5
 
                LR  A,(IS)-            ; 0f3f 4e
 
                LR  A,(IS)              ; 0f40 4c
 
                INC                      ; 0f41 1f
 
                LR  (IS)+,A            ; 0f42 5d
 
                LR  (IS)+,A            ; 0f43 5d
 
A0f44:          LR  A,$2                ; 0f44 42
 
                INC                      ; 0f45 1f
 
                LR  $2,A                ; 0f46 52
 
                PI  A0862              ; 0f47 28 08 62
 
                DS  (IS)                ; 0f4a 3c
 
                BF  $4,A0f44            ; 0f4b 94 f8
 
                LR  A,(IS)+            ; 0f4d 4d
 
                LR  A,(IS)              ; 0f4e 4c
 
                INC                      ; 0f4f 1f
 
                LR  (IS)-,A            ; 0f50 5e
 
                LR  (IS)-,A            ; 0f51 5e
 
A0f52:          DS  $1                  ; 0f52 31
 
                PI  A0862              ; 0f53 28 08 62
 
                DS  (IS)                ; 0f56 3c
 
                BF  $4,A0f52            ; 0f57 94 fa
 
                LR  A,(IS)-            ; 0f59 4e
 
                LR  A,(IS)              ; 0f5a 4c
 
                INC                      ; 0f5b 1f
 
                LR  (IS)+,A            ; 0f5c 5d
 
                LR  (IS)+,A            ; 0f5d 5d
 
                LISU 3                  ; 0f5e 63
 
                DS  (IS)                ; 0f5f 3c
 
                LISU 2                  ; 0f60 62
 
                LR  J,W                ; 0f61 1e
 
                LR  A,$2                ; 0f62 42
 
                OUTS 5                  ; 0f63 b5
 
                BF  $4,A0f25            ; 0f64 94 c0
 
                DS  (IS)                ; 0f66 3c
 
                BF  $0,A0f25            ; 0f67 90 bd
 
A0f69:          LR  P,K                ; 0f69 09
 
                POP                      ; 0f6a 1c
 
A0f6b:          LIS  $2                  ; 0f6b 72
 
                AI  $10                ; 0f6c 24 10
 
                LR  IS,A                ; 0f6e 0b
 
                LIS  $9                  ; 0f6f 79
 
                LR  $0,A                ; 0f70 50
 
A0f71:          LI  $80                ; 0f71 20 80
 
                NS  (IS)                ; 0f73 fc
 
                AI  $30                ; 0f74 24 30
 
                LR  (IS),A              ; 0f76 5c
 
                LR  A,IS                ; 0f77 0a
 
                INC                      ; 0f78 1f
 
                LR  IS,A                ; 0f79 0b
 
                DS  $0                  ; 0f7a 30
 
                BF  $4,A0f71            ; 0f7b 94 f5
 
                LR  A,IS                ; 0f7d 0a
 
                AI  $02                ; 0f7e 24 02
 
                LR  IS,A                ; 0f80 0b
 
                LIS  $9                  ; 0f81 79
 
                LR  $0,A                ; 0f82 50
 
A0f83:          LI  $80                ; 0f83 20 80
 
                NS  (IS)                ; 0f85 fc
 
                AI  $22                ; 0f86 24 22
 
                LR  (IS),A              ; 0f88 5c
 
                LR  A,IS                ; 0f89 0a
 
                INC                      ; 0f8a 1f
 
                LR  IS,A                ; 0f8b 0b
 
                DS  $0                  ; 0f8c 30
 
                BF  $4,A0f83            ; 0f8d 94 f5
 
                LR  A,$a                ; 0f8f 4a
 
                LR  (IS)+,A            ; 0f90 5d
 
                LR  (IS)+,A            ; 0f91 5d
 
                LISU 7                  ; 0f92 67
 
                LISL 5                  ; 0f93 6d
 
                LR  A,(IS)              ; 0f94 4c
 
                SL  1                  ; 0f95 13
 
                SR  1                  ; 0f96 12
 
                LR  (IS),A              ; 0f97 5c
 
                JMP  A0da0              ; 0f98 29 0d a0
 
                db  $b2               
 
                db  $ff                
 
                db   $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db   $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db   $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db   $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db   $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff                
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff               
 
                db  $ff                
 
  
 +
; EoF
  
 
</pre>
 
</pre>

Latest revision as of 16:48, 1 March 2020

;-------------------------------------------------------------------------------
; Dodge It - Videocart 16
;  for the Fairchild Video Entertainment System
; Original Code Copyright © 1978, Fairchild Semiconductor
;
; Disassembly Generated using Peter Trauner's f8tool
; 
; Comments, Labels, Etc. added by
;  Alex West
;
; Thanks to http://channelf.se/veswiki/ for making this possible
;
; A text file of the instruction manual can be found here:
; http://channelf.se/gallery/txt/videocart16.txt
;
; Build Instructions
;  dasm dodge_it.asm -f3 -ododge_it.bin

	processor f8

	include "ves.h"

;-------------------------------------------------------------------------------
; Common register definitions
;
; Definitions for common registers, bitfields, and constants. Local registers
;  and function arguments are generally not included here.

; -- Ball Properties -----------------------------------------------------------
;
;  The x and y positions are fairly straightforward. The xpos is 7 bits, and 
;   the ypos is 6 bits. Velocity is a bit more complicated.
;
;  The balls' velocity is stored in a sign-magnitude format. The sign, or
;   direction, of the balls' x and y velocities is stored in the upper bits of 
;   the x and y positions, for those respective directions. The magnitudes are
;   stored in a bitpacked array, with the information for two balls being stored
;   in one byte like so:
;
;   /-- Ball 0's x speed
;   |  /-- Ball 0's y speed
;   XX YY xx yy
;         |  \-- Ball 1's y speed
;         \-- Ball 1's x speed
;
;  ...and so on and so forth for balls 2 and 3, 4 and 5, etc.
;
; Astute observers will note that bit 6 the in y position remains unused, and 
;  the last byte of the velocity array has an unused nybble. Such waste...

; Current ball being operated on
main.curBall = $B
PLAYER_1 = 0
PLAYER_2 = 1

; Ball arrays
balls.xpos = 020 ; Array
balls.ypos = 033 ; Array
balls.speed = 046 ; Bitpacked array

balls.count = 056 ; Number of balls currently in play including players
delayIndex  = 057 ; Basically the same as balls.count

MASK_DIRECTION = %10000000
MASK_POSITION  = %01111111
MASK_YPOSITION = %00111111

MASK_SPEED  = %00001111
MASK_XSPEED = %11001100
MASK_YSPEED = %00110011

MAX_BALLS   = 11
MAX_PLAYERS = 2
MAX_ENEMIES = 9

; -- Arena Walls ---------------------------------------------------------------
;
; The left and top walls work how you'd expect. However, the right and bottom
;  walls are weird. Not only do they have different values for player and enemy
;  (to account for their different sizes), but they are also negative. In other
;  words, they give distances for how far the walls are from some point 256
;  pixels away from the origin. It's weird and inexplicable.

wall.rightEnemy = 060
wall.rightPlayer = 061
wall.left = 062
wall.lowerEnemy = 063
wall.lowerPlayer = 064
wall.upper = 065

; Constants used to generate the positions of the walls
WALL_MIN  = $10 ; Most upper-left point possible to generate a field
; Note: These two constants, contrary to the values they help set, are just
;  simply based off the distance from the origin.
WALL_XMAX = $58
WALL_YMAX = $38

WALL_X_OFFSET_MAX = $12
WALL_Y_OFFSET_MAX = $0B

; Constants to render border at the start of the game
FIELD_CORNER = WALL_MIN ; Top left corner of box, as rendered
FIELD_WIDTH  = WALL_XMAX - WALL_MIN + 1 ; $49
FIELD_HEIGHT = WALL_YMAX - WALL_MIN + 1 ; $29

; Constants to spawn the balls at the edges of the field
SPAWN_XMIN = WALL_MIN
SPAWN_XMAX = WALL_XMAX-1
SPAWN_YMIN = WALL_MIN
SPAWN_YMAX = WALL_YMAX-1

; -- Timers --------------------------------------------------------------------

; Each of these values is 2 bytes of binary-coded decimal. 
timer.hi = 066
timer.lo = 067
hiScore.p1.hi = 054
hiScore.p1.lo = 055
hiScore.p2.hi = 073
hiScore.p2.lo = 074

; Used to get the lower nybble of a timer byte ("SR 4" can get the upper one)
DIGIT_MASK = $0F

; Parameters for drawing the timers' positions
TIMER_X_LEFT = $1F
TIMER_X_CENTER = $39
TIMER_X_RIGHT = $54
TIMER_Y_OFFSET = $A

; -- Game mode -----------------------------------------------------------------

; The lower two bits represent what button was pressed on the console. The upper
;  six bits of this are randomized in shuffleGame(), but of those bits only the
;  top one matters.
gameMode = 075
MODE_2P_MASK     = %00000001 ; Unset: 1 player, set: 2 players
MODE_SPEED_MASK  = %00000010 ; Set: fast, unset: slow
MODE_CHOICE_MASK = %00000011 ; Used to check if the above two bits are set
; Set: fiddle with speed upon collision, unset: don't fiddle with speed
; Note: It appears that this can only be set in shuffleGame(), and that it is
;  cleared in explode()
MODE_BOUNCE_MASK = %10000000

; Set in shuffleGame()
main.gameSettings = $A
MASK_PLAYER_SIZE  = %11000000
MASK_ENEMY_SIZE   = %00110000
MASK_PLAYER_SPEED = %00001100
MASK_ENEMY_SPEED  = %00000011

; -- Misc Registers ------------------------------------------------------------

; Yes, 070 and 071 have different semantics for different functions called from 
;  the main loop.

; Controller inputs. Written in readInput, and read in doPlayers and gameOver
input.p1 = 070 ; Left controller
input.p2 = 071 ; Right controller
; Arguments for doBall
doBall.size = 070
doBall.speed = 071
; Local register for collision()
testBall = 071

; If set, execute explode() at the end of the main loop
explosionFlag = 072
MASK_EXPLODE = %10000000

; Randomly generated number
RNG.seedHi = 076
RNG.seedLo = 077

; -- Misc Constants ------------------------------------------------------------
; Most of these should probably be added to ves.h

BCD_ADJUST = $66

; Sounds
SOUND_NONE  = %00000000 ; Silence
SOUND_1kHz  = %01000000 ; 1kHz tone
SOUND_500Hz = %10000000 ; 500Hz tone
SOUND_120Hz = %11000000 ; 120Hz tone

; Graphics
BLUE  = $40
RED   = $80
GREEN = $C0

MASK_COLOR     = %11000000
MASK_SOUND     = %11000000
MASK_NO_SOUND  = %00111111

DRAW_ATTR_X = $7d
DRAW_ATTR_W = 2
DRAW_SCREEN_W = $80
DRAW_SCREEN_H = $40

; end of common register definitions
;-------------------------------------------------------------------------------

	org $0800

CartridgeHeader: db $55, $2b
CartridgeEntry:  JMP init

;-------------------------------------------------------------------------------
; Graphics data
; 
; Each character takes 5 nybbles of data, split across 5 bytes. Even numbered
;  characters take the left nybble while odd numbered characters take the right.

CHAR_WIDTH  = 4
CHAR_HEIGHT = 5
CHAR_G     = $A
CHAR_QMARK = $B

graphicsData:
	; 0805 
	db %01110010 ;  ###  # 
	db %01010110 ;  # # ## 
	db %01010010 ;  # #  # 
	db %01010010 ;  # #  # 
	db %01110111 ;  ### ###
	; 080a
	db %01110111 ;  ### ###
	db %00010001 ;    #   #
	db %01110011 ;  ###  ##
	db %01000001 ;  #     #
	db %01110111 ;  ### ###
	; 080f
	db %01010111 ;  # # ###
	db %01010100 ;  # # #  
	db %01110111 ;  ### ###
	db %00010001 ;    #   #
	db %00010111 ;    # ###
	; 0814
	db %01000111 ;  #   ###
	db %01000001 ;  #     #
	db %01110001 ;  ###   #
	db %01010001 ;  # #   #
	db %01110001 ;  ###   #
	; 0819
	db %01110111 ;  ### ###
	db %01010101 ;  # # # #
	db %01110111 ;  ### ###
	db %01010001 ;  # #   #
	db %01110001 ;  ###   #
	; 081e
	db %11111111 ; ########
	db %10000001 ; #      #
	db %10110010 ; # ##  # 
	db %10010000 ; #  #    
	db %11110010 ; ####  # 
	; 0823
	db %01110111 ;  ### ###
	db %01000101 ;  #   # #
	db %01110111 ;  ### ###
	db %01000101 ;  #   # #
	db %01000101 ;  #   # #
	; 0828
	db %01110111 ;  ### ###
	db %01000010 ;  #    # 
	db %01110010 ;  ###  # 
	db %00010010 ;    #  # 
	db %01110010 ;  ###  # 

;-------------------------------------------------------------------------------
; Data Tables

; Delay table A (easy)
delayTableEasy: ; 082d
	db $19, $16, $13, $11, $0e, $0c, $0a, $08, $06, $03, $01

; Delay table B (pro)
delayTableHard: ; 0838
	db $0b, $0a, $09, $08, $07, $06, $05, $04, $03, $02, $01

; Bitmasks used while randomizing the game mode
gameModeMasks:  ; 0843
	db $C0, $30, $0C, $03, $FC
				
; This table is referenced but never read. Based on the code that references
;  this table, it likely pertained to the enemy speeds. (Also, there is a chance
;  that the endian-ness is wrong on these.)
unusedSpeedTable: ; 0848 00 00 12 0b 0b 06 02 01
	dw $0000, $120B, $0B06, $0201

; Colors of P1, P2, and enemies
ballColors: ; 0850 40 c0 80
	db BLUE, GREEN, RED

; Table helps translate the button press to the game mode number
menuChoices: ; 0853 
	db $00, $01, $02, $03, $03

;-------------------------------------------------------------------------------
; draw(param, xpos, ypos, width, height)
;  Leaf function
;
; This function plots pixels to screen. It has two different entry points, which
;  make it act like two different functions.
;
; When entering via drawChar, draw.param should be set to the index of the
;  character to be drawn. Although the charset only contains 16 characters, it
;  could be expanded up to 64 without changing this function.
;
; When entering via drawBox, draw.param should be set to either DRAW_RECT or
;  DRAW_ATTRIBUTE depending on whether you're drawing a box or the attribute
;  column.
;
; The x and y coordinates are relative to the top-left corner of the screen.
;
; Despite the y position and color being mapped to different I/O ports, this
;  function expects those values to be bitpacked together. The y position takes
;  up the lower 6 bits, and the color takes up the upper 2 bits.
;
; Although this function modifies draw.xpos and draw.ypos, those variables are
;  set back to their original values upon returning from the function.

; == Arguments ==
draw.param  = 0 ; Drawing Parameter or Character Index
draw.xpos   = 1 ; X Position
draw.ypos   = 2 ; Y Position and Color
draw.width  = 4 ; Width
draw.height = 5 ; Width

; Valid values for draw.param
DRAW_RECT      = %10000000 ; Draw a rectangle
DRAW_ATTRIBUTE = %11000000 ; Draw the attribute column

; == Entry Point A == (for drawing a character)
drawChar: subroutine

; == Local Variables ==
.data   = 3 ; pixel data
.xcount = 6 ; horizontal counter
.ycount = 7 ; vertical counter
.temp   = 8 ; helps calculate the data counter
.color  = 8 ; color, as extracted from ypos

; Get the starting address of the desired character
	; DC = graphicsData + param/2 + (param/2)*4
	DCI  graphicsData        ; 0858 2a 08 05
	LR   A, draw.param       ; 085b 40
	SR   1                   ; 085c 12
	LR   .temp, A            ; 085d 58
	SL   1                   ; 085e 13
	SL   1                   ; 085f 13
	AS   .temp               ; 0860 c8
	ADC                      ; 0861 8e

; == Entry point B == (for drawing a box)
drawBox:
	; (xcount,ycount) = (width,height)
	LR   A, draw.width       ; 0862 44
	LR   .xcount, A      ; 0863 56
    LR   A, draw.height      ; 0864 45
    LR   .ycount, A      ; 0865 57

.doRowLoop:
; I/O write the ypos
	; Extract color bits from ypos
	LR   A, draw.ypos        ; 0866 42
	NI   MASK_COLOR          ; 0867 21 c0
	LR   .color, A           ; 0869 58
	
	; Mask out sound, put the ypos in .data
	LR   A, draw.ypos        ; 086a 42
	COM                      ; 086b 18
	NI   MASK_NO_SOUND       ; 086c 21 3f
	LR   .data, A            ; 086e 53
	
	; Write row to port 5, making sure to preserve the sound
	INS  5                   ; 086f a5
	NI   MASK_SOUND          ; 0870 21 c0
	AS   .data               ; 0872 c3
	OUTS 5                   ; 0873 b5

; Load the pixel data into .data
	; If either DRAW_RECT or DRAW_ATTRIBUTE is
	;  then set all of the pixels and jump ahead
	CLR                      ; 0874 70
	AS   draw.param          ; 0875 c0
	LI   %11111111           ; 0876 20 ff
	BM   .setPixelData       ; 0878 91 09
	
	; Load .data from memory
	LM                       ; 087a 16
	LR   .data, A            ; 087b 53

	; If character number is even, just use the left 4 bits
	LIS  $1                  ; 087c 71
	NS   draw.param          ; 087d f0
	BZ   .doPixelLoop        ; 087e 84 04

	; If char is odd, use the right 4 bits by shifting them into place
	LR   A, .data            ; 0880 43
	SL   4                   ; 0881 15	
.setPixelData:
	LR   .data, A            ; 0882 53

; I/O write the xpos
.doPixelLoop:
	LR   A, draw.xpos        ; 0883 41
	COM                      ; 0884 18
	OUTS 4                   ; 0885 b4

; I/O write the color
	; if MSB of .data is 1, draw that color
	; if MSB of .data is 0, draw the BG color
	CLR                      ; 0886 70
	AS   .data               ; 0887 c3
	LR   A, .color           ; 0888 48
	BM   .setColor           ; 0889 91 02
	LIS 0                    ; 088b 70
.setColor:
	COM                      ; 088c 18
	NI   MASK_COLOR          ; 088d 21 c0
	OUTS 1                   ; 088f b1
	
; Iterate on to the next data bit, making sure to pad with 1
	; .data = (.data << 1) + 1
	LR   A, .data            ; 0890 43
	SL   1                   ; 0891 13
	INC                      ; 0892 1f
	LR   .data, A            ; 0893 53
	
; If DRAW_ATTRIBUTE is set, iterate to the color of the next column
	; Check if DRAW_ATTRIBUTE is set
	LR   A, draw.param       ; 0894 40
	SL   1                   ; 0895 13
	BP   .activateWrite      ; 0896 81 04
	; If so, .color = .color << 1
	LR   A, .color           ; 0898 48
	SL   1                   ; 0899 13
	LR   .color, A           ; 089a 58

; I/O write to push our color through
.activateWrite:
	LI   $60                 ; 089b 20 60
	OUTS 0                   ; 089d b0
	LI   $50                 ; 089e 20 50
	OUTS 0                   ; 08a0 b0

	; xpos++
	LR   A, draw.xpos        ; 08a1 41
	INC                      ; 08a2 1f
	LR   draw.xpos, A        ; 08a3 51
	
; Spin in place to make sure the write goes through
	LIS  4                   ; 08a4 74
.delay:
	AI   $ff                 ; 08a5 24 ff
	BNZ  .delay              ; 08a7 94 fd
	
	; xcount--, loop on to next pixel if not zero
	DS   .xcount             ; 08a9 36
	BNZ  .doPixelLoop        ; 08aa 94 d8
	
	; ypos++
	LR   A, draw.ypos        ; 08ac 42
	INC                      ; 08ad 1f
	LR   draw.ypos, A        ; 08ae 52
	
; Reset xcount and xpos
	; xcount = width
	LR   A, draw.width       ; 08af 44
	LR   .xcount,A       ; 08b0 56
	; xpos = xpos - width
	COM                      ; 08b1 18
	INC                      ; 08b2 1f
	AS   draw.xpos           ; 08b3 c1
	LR   draw.xpos, A        ; 08b4 51

	; ycount--, loop on to next row if not zero
	DS   .ycount             ; 08b5 37
	BNZ  .doRowLoop          ; 08b6 94 af
	
; Reset ypos
	; ypos = ypos - height
	LR   A, draw.height      ; 08b8 45
	COM                      ; 08b9 18
	INC                      ; 08ba 1f
	AS   draw.ypos           ; 08bb c2
	LR   draw.ypos, A        ; 08bc 52
	
; Clear I/O ports
	CLR                      ; 08bd 70
	OUTS 1                   ; 08be b1
	OUTS 0                   ; 08bf b0
	
	POP                      ; 08c0 1c

; end draw()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; rand()
;  Leaf Function
;
; Random number generator. I am uncertain how random this is, or what the
;  mathematical basis is behind it.

; == Arguments ==
; None

; == Returns ==
RNG.regHi = $6
RNG.regLo = $7

; == Entry Point ==
rand: subroutine

; == Local Variable ==
.tempISAR = 8

; save ISAR to a temp register
	LR   A,IS                ; 08c1 0a
	LR   .tempISAR, A; 08c2 58
	
; r6 = o77*2 + o76
	SETISAR RNG.seedLo      ; 08c3 67 6f
	LR   A,(IS)-             ; 08c5 4e
	SL   1                   ; 08c6 13
	AS   (IS)+               ; 08c7 cd
	LR   RNG.regHi, A        ; 08c8 56
	
; r6,7 = (r6,77)*2
	;  do the lo byte
	LR   A,(IS)              ; 08c9 4c
	AS   (IS)                ; 08ca cc
	LR   RNG.regLo, A        ; 08cb 57

	;  do the hi byte
	LR   J,W                 ; 08cc 1e ; save status reg
	LR   A, RNG.regHi        ; 08cd 46
	SL   1                   ; 08ce 13
	LR   W,J                 ; 08cf 1d ; reload status reg
	LNK                      ; 08d0 19
	LR   RNG.regHi, A        ; 08d1 56
	
; r6,7 = (r6,7)*2
	;  do the lo byte
	LR   A, RNG.regLo        ; 08d2 47
	AS   RNG.regLo           ; 08d3 c7
	LR   RNG.regLo, A        ; 08d4 57

	;  do the hi byte
	LR   J,W                 ; 08d5 1e
	LR   A, RNG.regHi        ; 08d6 46
	SL   1                   ; 08d7 13
	LR   W,J                 ; 08d8 1d
	LNK                      ; 08d9 19
	LR   RNG.regHi, A        ; 08da 56
	
; r6,7 += r66,67
	;  do the lo byte
	LR   A, RNG.regLo        ; 08db 47
	AS   (IS)-               ; 08dc ce
	LR   RNG.regLo, A        ; 08dd 57

	;  do the hi byte
	LR   A, RNG.regHi        ; 08de 46
	LNK                      ; 08df 19
	AS   (IS)+               ; 08e0 cd
	LR   RNG.regHi, A        ; 08e1 56
	
; r6,r7 += 0x3619	
; o76,77 = r6,r7
	;  do the lo byte
	LR   A, RNG.regLo        ; 08e2 47
	AI   $19                 ; 08e3 24 19
	LR   RNG.regLo, A        ; 08e5 57
	LR   (IS)-,A             ; 08e6 5e

	;  do the hi byte
	LR   A, RNG.regHi        ; 08e7 46
	LNK                      ; 08e8 19
	AI   $36                 ; 08e9 24 36
	LR   RNG.regHi, A        ; 08eb 56
	LR   (IS)+,A             ; 08ec 5d
	
	; Restore ISAR
	LR   A, .tempISAR        ; 08ed 48
	LR   IS,A                ; 08ee 0b

	; Return
	POP                      ; 08ef 1c
; end of rand()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; menu()
;  Mid-Level Function
;
; Returns the menu button you pressed.
;
; Note that drawing "G?" is handled by main()

; == Return ==
menu.buttons = 0

; == Entry Point ==
menu: subroutine

; == Locals ==
.waitTimerHi = 2
.waitTimerLo = 1
; Wait time is 10 seconds, according to the manual.
.WAIT_TIME = $af00
.DEFAULT_MODE = $1

	LR   K,P                 ; 08f0 08

	; set lower byte of .waitTimer
	LIS  [<.WAIT_TIME]       ; 08f1 70
	LR   .waitTimerLo,A      ; 08f2 51

	; clear console buttons, load default state
	OUTS 0                   ; 08f3 b0
	INS  0                   ; 08f4 a0
	LR   menu.buttons, A     ; 08f5 50

	; set upper byte of .waitTimer
	LI   [>.WAIT_TIME]       ; 08f6 20 af
	LR   .waitTimerHi, A     ; 08f8 52
	
.pollInputLoop:
	PI   rand                ; 08f9 28 08 c1
	
	; Set DC (to be used after this function in main)
	DCI  menuChoices         ; 08fc 2a 08 53

	; Read console buttons
	CLR                      ; 08ff 70
	OUTS 0                   ; 0900 b0
	INS  0                   ; 0901 a0

	; Check if different from last time they were read
	XS   menu.buttons        ; 0902 e0
	; if not, decrement .waitTimer
	BZ   .wait               ; 0903 84 03

	; Return after 10 seconds or a choice is made
.exit:
	LR   menu.buttons,A      ; 0905 50
	PK                       ; 0906 0c

	; Wait for a choice for 10 seconds
.wait:
	DS   .waitTimerLo        ; 0907 31
	BNZ  .pollInputLoop      ; 0908 94 f0
	DS   .waitTimerHi        ; 090a 32
	BNZ  .pollInputLoop      ; 090b 94 ed

	; Default to game mode 1 (1 player, easy)
	LIS  .DEFAULT_MODE       ; 090d 71

	; Return
	BR   .exit               ; 090e 90 f6
; end menu()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; readInput()
;  Leaf Function
;
; Reads input from the hand controllers, and twiddles the RNG a bit (if no
;  inputs are detected (?)).
;
; Note: To enable data reads from the controllers, bit 6 of I/O port 0 needs to
;  be set to 1. This is done in draw(), meaning that it doesn't need to be done
;  here (although it might have been better practice to do so).
;
; == Arguments ==
;  None
; == Returns ==
;  input.p1 = 070
;  input.p2 = 071
; == Locals ==
;  None

; == Entry Point ==
readInput: subroutine
	SETISAR input.p1         ; 0910 67 68
	
	; Clear I/O ports
	CLR                      ; 0912 70
	OUTS 1                   ; 0913 b1
	OUTS 4                   ; 0914 b4
		
	; Read left controller from I/O port 1
	INS  1                   ; 0915 a1
	LR   (IS)+,A             ; 0916 5d
	
	; Read right controller from I/O port 2
	INS  4                   ; 0917 a4
	LR   (IS)-,A             ; 0918 5e
	
	; if(-(input.p1 + input.p2) == 0) then exit
	AS   (IS)                ; 0919 cc
	INC                      ; 091a 1f
	COM                      ; 091b 18
	BZ   .exit               ; 091c 84 06
	
	; else, twiddle with the RNG
	SETISARL RNG.seedLo     ; 091e 6f
	; RNG.lo = RNG.lo + 1
	LIS  $1                  ; 091f 71
	AS   (IS)                ; 0920 cc
	LR   (IS)-,A             ; 0921 5e
	; RNG.hi--
	DS   (IS)                ; 0922 3c

.exit:
	POP                      ; 0923 1c
; end of readInput()
;-------------------------------------------------------------------------------
	
;-------------------------------------------------------------------------------
; doPlayers()
;  Mid-Level Function
;
; This function takes the controller inputs sets the speed and direction of each
;  player's ball accordingly. Player speed is taken from main.gameSettings. The 
;  results are then save to the xpos, ypos, and speed arrays in the scratchpad.
;
; The order in which the players are processed is done randomly.
;
; In the case of L/R or U/D conflicts, right takes precedence over left and down
;  over up.
;
; This function does not handle drawing the players.

; == Entry Point ==
doPlayers: subroutine

; == Locals ==
.speed = $0
.xpos = $1
.ypos = $2
.loopCount = $8

	LR   K,P                 ; 0924 08
	
	; Read input from hand controllers
	PI   readInput           ; 0925 28 09 10
	
; Randomize which player is processed first
	; if LSB of RNG is set
	;  curBall = player 1
	; else
	;  curBall = player 2
	SETISAR RNG.seedLo       ; 0928 67 6f
	LIS  PLAYER_2            ; 092a 71
	NS   (IS)                ; 092b fc
	LIS  PLAYER_1            ; 092c 70
	BNZ  .setPlayer          ; 092d 94 02
	LIS  PLAYER_2            ; 092f 71
.setPlayer:
	LR   main.curBall,A      ; 0930 5b

	; .loopCount = 2
	LIS  MAX_PLAYERS         ; 0931 72
	LR   .loopCount,A        ; 0932 58

; start loop
.playerLoop:
	; speed = 0 (so we don't move if nothing is pressed)
	CLR                      ; 0933 70
	LR   .speed,A            ; 0934 50

	; .xpos = xpos[curBall]
	LR   A,main.curBall      ; 0935 4b
	AI   balls.xpos          ; 0936 24 10
	LR   IS,A                ; 0938 0b
	LR   A,(IS)              ; 0939 4c
	LR   .xpos,A             ; 093a 51

	; .ypos = ypos[curBall]
	LR   A,IS                ; 093b 0a
	AI   MAX_BALLS           ; 093c 24 0b
	LR   IS,A                ; 093e 0b
	LR   A,(IS)              ; 093f 4c
	LR   $2,A                ; 0940 52

	; set ISAR to match the current player's controller
	SETISARU RNG.seedLo      ; 0941 67
	LIS  PLAYER_2            ; 0942 71
	NS   main.curBall        ; 0943 fb
	SETISARL input.p2        ; 0944 69
	BNZ  .checkRight         ; 0945 94 02
	SETISARL input.p1        ; 0947 68

; Check if right is pressed
.checkRight:
	LIS  CONTROL_RIGHT       ; 0948 71
	NS   (IS)                ; 0949 fc
	BNZ  .checkLeft          ; 094a 94 06

	; If so, set x direction to right
	LR   A,.xpos             ; 094c 41
	NI   MASK_POSITION      ; 094d 21 7f
	BR   .setXspeed          ; 094f 90 08

; Check if left is pressed
.checkLeft:
	LIS  CONTROL_LEFT        ; 0951 72
	NS   (IS)                ; 0952 fc
	BNZ  .checkDown          ; 0953 94 08

	; If so, set x direction to left
	LR   A,.xpos             ; 0955 41
	OI   MASK_DIRECTION      ; 0956 22 80

.setXspeed:
	; Apply the direction to .xpos
	LR   .xpos,A             ; 0958 51
	; xspeed = gameSettings.playerSpeed
	LIS  MASK_PLAYER_SPEED   ; 0959 7c
	NS   main.gameSettings   ; 095a fa
	LR   .speed,A            ; 095b 50

; Check if down is pressed
.checkDown:
	LIS  CONTROL_BACKWARD    ; 095c 74
	NS   (IS)                ; 095d fc
	BNZ  .checkUp            ; 095e 94 06

	; If so, set y direction to down
	LR   A,.ypos             ; 0960 42
	NI   MASK_YPOSITION      ; 0961 21 3f
	BR   .setYspeed          ; 0963 90 08
	
; Check if up is pressed
.checkUp:
	LIS  CONTROL_FORWARD     ; 0965 78
	NS   (IS)                ; 0966 fc
	BNZ  .prepSaveBall       ; 0967 94 0b

	; If so, set y direction to up
	LR   A,.ypos             ; 0969 42
	OI   MASK_DIRECTION      ; 096a 22 80

.setYspeed:
	; Apply the direction to .ypos
	LR   .ypos,A             ; 096c 52
	; yspeed = gameSettings.playerSpeed
	LIS  MASK_PLAYER_SPEED   ; 096d 7c
	NS   main.gameSettings   ; 096e fa
	SR   1                   ; 096f 12
	SR   1                   ; 0970 12
	AS   .speed              ; 0971 c0
	LR   .speed,A            ; 0972 50

; Copy the speed to the other nybble
.prepSaveBall:
	LR   A,.speed            ; 0973 40
	SL   4                   ; 0974 15
	AS   .speed              ; 0975 c0
	LR   .speed,A            ; 0976 50
	; saveBall will figure out which nybble to save
	
	; Save the ball to the scratchpad arrays
	PI   saveBall            ; 0977 28 09 a2
	
; Set curBall to the other player's ball
	; (why not xor the register with a constant 1?)
	LIS  PLAYER_2            ; 097a 71
	NS   main.curBall        ; 097b fb
	LIS  PLAYER_1            ; 097c 70
	BNZ  .setNextPlayer      ; 097d 94 02
	LIS  PLAYER_2            ; 097f 71
.setNextPlayer:
	LR   main.curBall,A      ; 0980 5b
	
	; .loopCount--
	DS   .loopCount          ; 0981 38
	BNZ  .playerLoop         ; 0982 94 b0
	
	; Return
	LR   P,K                 ; 0984 09
	POP                      ; 0985 1c
; end doPlayers()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; delayByTable(index)
; delayVariable(count)
;  Leaf Functions
;
; This procedure has two different entry points, so we can consider it two
;  different functions. Alternatively, we can think of the first function as
;  calling the second function by having just continuing on to its code.
;  (Alternatively, this is just some spaghetti code.)
;
; The first sets the delay according to the game mode and the current number of
;  balls. This function is necessary to make sure that the game runs at a
;  consistent speed, since the Channel F does not have any means of
;  synchronizing itself to vblank or anything like that.
;
; The second function sets a delay according to an a count provided by the
;  callee. This is useful for providing short pauses, like during a game over.
;
; TODO: Find a rough conversion between delay.count and the amount of time this
;  function actually delays.

; == Arguments ==
; Same register, yes, but this is good syntactic sugar.
delay.index = 0 ; when entering through delayByTable 
delay.count = 0 ; when entering through delayVariable

; == Entry Point A ==
delayByTable: subroutine

; == Locals ==
.tempISAR = 3

	; if(gameMode & speedMask == 0)
	;  count = delayTableEasy[index]
	; else
	;  count = delayTableHard[index]
	; Set 
	DCI  delayTableEasy      ; 0986 2a 08 2d
	
; Save the ISAR
	LR   A,IS                ; 0989 0a
	LR   .tempISAR,A         ; 098a 53
	
; Test to check the game speed
	SETISAR gameMode         ; 098b 67 6d
	LIS  MODE_SPEED_MASK     ; 098d 72
	NS   (IS)                ; 098e fc
	
; Restore the ISAR
	LR   A,.tempISAR         ; 098f 43
	LR   IS,A                ; 0990 0b
	
	; Branch ahead if playing easy
	BZ   .loadData           ; 0991 84 04
	
	; Else, set the table to hard
	DCI  delayTableHard      ; 0993 2a 08 38

; delay.count = delayTable[index]
.loadData:
	LR   A, delay.index      ; 0996 40
	ADC                      ; 0997 8e
	LM                       ; 0998 16
	LR   delay.count, A      ; 0999 50

; == Entry Point B ==
delayVariable:

; A = 0
.outerLoop:
	LIS  0                   ; 099a 70	
; A++
.innerLoop:
	INC                      ; 099b 1f
	BNZ  .innerLoop          ; 099c 94 fe
; count--
	DS   delay.count         ; 099e 30
	BNZ  .outerLoop          ; 099f 94 fa

	; Return
	POP                      ; 09a1 1c
; end of delayByTable() and delayVariable()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; saveBall(ball, speed, xpos, ypos)
;  Leaf Function
;
; Given the ball number, speed, x position, and y position in the input
;  arguements, this function saves those ball parameters into the appropriate
;  arrays in the scratchpad. This function is useful because the speed array is
;  bitpacked.

; == Arguments ==
saveBall.speed = $0
saveBall.xpos = $1
saveBall.ypos = $2
; main.curBall = $B

saveBall: subroutine

; == Local ==
.speedMask = $3

; xpos[curBall] = saveBall.xpos
	LI   balls.xpos          ; 09a2 20 10
	AS   main.curBall        ; 09a4 cb
	LR   IS,A                ; 09a5 0b
	LR   A,saveBall.xpos     ; 09a6 41
	LR   (IS),A              ; 09a7 5c
	
; ypos[curBall] = saveBall.xpos
	LR   A,IS                ; 09a8 0a
	AI   MAX_BALLS           ; 09a9 24 0b
	LR   IS,A                ; 09ab 0b
	LR   A,saveBall.ypos     ; 09ac 42
	LR   (IS),A              ; 09ad 5c
	
; Calculate index and bitmask for the bitpacked velocity array
	; ISAR = balls.speed + curBall/2
	LR   A, main.curBall     ; 09ae 4b
	SR   1                   ; 09af 12
	AI   balls.speed         ; 09b0 24 26
	LR   IS,A                ; 09b2 0b
	
	; if curBall is even
	;  bitmask = %00001111
	; else 
	;  bitmask = %11110000
	LIS  $1                  ; 09b3 71
	NS   main.curBall        ; 09b4 fb
	LIS  MASK_SPEED          ; 09b5 7f
	BNZ  .setSpeedMask       ; 09b6 94 02
	COM                      ; 09b8 18
.setSpeedMask:          
	LR   .speedMask,A        ; 09b9 53

; Set curBall speed bitfield
	; Clear curBall's bitfield from the velocity[curBall/2]
	COM                      ; 09ba 18
	NS   (IS)                ; 09bb fc
	LR   (IS),A              ; 09bc 5c

	; Extract the appropriate speed bitfield from the input argument
	LR   A,saveBall.speed    ; 09bd 40
	NS   .speedMask          ; 09be f3

	; Merge the bitfields and save the result
	AS   (IS)                ; 09bf cc
	LR   (IS),A              ; 09c0 5c

	; Return
	POP                      ; 09c1 1c
; end saveBall()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; spawnBall(curBall)
;  Mid-Level Function
;
; This function spawns a single enemy or player ball.
;
; Enemy balls are given a random position in the playfield and a random 
;  direction, and then clamped to one of the four walls, with their direction
;  being set away from the wall. They are also given a non-random starting speed
;  of 1 and 1 on each axis.
; 
; Player balls are spawned in hardcoded positions in the middle of the court.

; == Arguments ==
; main.curBall = $b

; == Returns ==
; None

; == Entry Point ==
spawnBall: subroutine
	LR   K,P                 ; 09c2 08

; == Local Variables ==
.speed = $0
.xpos = $1
.ypos = $2

; == Local Constants ==
.SPEED = %01010101
.PLAYER_Y = $23
.PLAYER1_X = $33
.PLAYER2_X = $3A
	
; keep rerolling RNG until it gets an inbounds x and y position
.reroll:
	PI   rand                ; 09c3 28 08 c1

; xpos = rng.hi
	LR   A, RNG.regHi        ; 09c6 46
	CI   SPAWN_XMIN          ; 09c7 25 10
	BC   .reroll             ; 09c9 82 f9
	CI   SPAWN_XMAX          ; 09cb 25 57
	BNC  .reroll             ; 09cd 92 f5

	LR   .xpos,A             ; 09cf 51

; ypos = rng.lo
	LR   A, RNG.regLo        ; 09d0 47
	CI   SPAWN_YMIN          ; 09d1 25 10
	BC   .reroll             ; 09d3 82 ef
	CI   SPAWN_YMAX          ; 09d5 25 37
	BNC  .reroll             ; 09d7 92 eb

	LR   .ypos,A             ; 09d9 52
	
; speed = 0x55
	LI   .SPEED              ; 09da 20 55
	LR   .speed,A            ; 09dc 50
	
; Spawn the ball against one of the walls
	; use lower 2 bits of rng.hi as index to jump table
	; This is essentially a case statement
	LIS  %00000011           ; 09dd 73
	NS   RNG.regHi           ; 09de f6
	
	; jump to (jump_table + 2*A)
	DCI  .jumpTable          ; 09df 2a 09 e6
	ADC                      ; 09e2 8e
	ADC                      ; 09e3 8e
	LR   Q,DC                ; 09e4 0e
	; Jump!
	LR   P0,Q                ; 09e5 0d

.jumpTable:
	BR   .north              ; 09e6 90 07
	BR   .east               ; 09e8 90 0a
	BR   .south              ; 09ea 90 13
	BR   .west               ; 09ec 90 1c

.north:
	; ypos = 0x11
	; ydir = sount
	LI   SPAWN_YMIN+1        ; 09ee 20 11
	LR   .ypos,A             ; 09f0 52
	BR   .spawnPlayers       ; 09f1 90 1a
	
.east:
	; xpos = $58 - enemy ball size
	; xdir = west
	LI   MASK_ENEMY_SIZE     ; 09f3 20 30
	NS   main.gameSettings   ; 09f5 fa
	SR   4                   ; 09f6 14
	COM                      ; 09f7 18
	INC                      ; 09f8 1f
	AI   MASK_DIRECTION|(SPAWN_XMAX+1) ; 09f9 24 d8
	LR   .xpos,A             ; 09fb 51
	BR   .spawnPlayers       ; 09fc 90 0f

.south:
	; ypos = $38 - enemy ball size
	; ydir = north
	LI   MASK_ENEMY_SIZE     ; 09fe 20 30
	NS   main.gameSettings   ; 0a00 fa
	SR   4                   ; 0a01 14
	COM                      ; 0a02 18
	INC                      ; 0a03 1f
	AI   MASK_DIRECTION|(SPAWN_YMAX+1) ; 0a04 24 b8
	LR   .ypos,A             ; 0a06 52
	BR   .spawnPlayers       ; 0a07 90 04

.west:
	; xpos = 0x11
	; xdir = east
	LI   SPAWN_XMIN+1        ; 0a09 20 11
	LR   .xpos,A             ; 0a0b 51

.spawnPlayers:
	; exit if current ball is not a player
	LR   A, main.curBall     ; 0a0c 4b
	CI   [MAX_PLAYERS-1]     ; 0a0d 25 01
	BNC   .exit              ; 0a0f 92 0b
	
; Ignore all the above calculations and spawn the players
	; ypos = 0x23
	LI   .PLAYER_Y           ; 0a11 20 23
	LR   .ypos,A             ; 0a13 52
	; if (curBall == Player 1)
	;  xpos = 0x33
	; else xpos = 0x33 + 0x07
	LI   .PLAYER1_X          ; 0a14 20 33
	BNZ  .setPlayerXPos      ; 0a16 94 03
	AI   .PLAYER2_X-.PLAYER1_X ; 0a18 24 07
.setPlayerXPos:
	LR   .xpos,A             ; 0a1a 51

; Save xpos, ypos, and speed
.exit:
	PI   saveBall            ; 0a1b 28 09 a2

	LR   P,K                 ; 0a1e 09
	POP                      ; 0a1f 1c
; end spawnBall()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; drawTimer(int* timer, xpos, ypos)
;  Mid-Level Function
;
; Draws a 4-digit number pointed to by the ISAR. The ISAR should point to the
;  least significant byte of a big-endian word. The x and y positions specify
;  the upper-left corner of the ones digit (not the thousands digit).

; == Arguments ==
; *timer = ISAR
drawTimer.xpos = 0
drawTimer.ypos = 2 ; and color

drawTimer:          
	LR   K,P                 ; 0a20 08
	
; == Local Constant ==
.X_DELTA  = <[-5]
	
; Draw ones digit
	; Load xpos
	LR   A, drawTimer.xpos   ; 0a21 40
	LR   draw.xpos, A        ; 0a22 51
	; Adjust ypos
	LI   TIMER_Y_OFFSET      ; 0a23 20 0a
	AS   drawTimer.ypos      ; 0a25 c2
	LR   draw.ypos, A        ; 0a26 52
	; Set character
	LI   DIGIT_MASK          ; 0a27 20 0f
	NS   (IS)                ; 0a29 fc
	LR   draw.param, A       ; 0a2a 50
	; Width
	LIS  CHAR_WIDTH          ; 0a2b 74
	LR   draw.width, A       ; 0a2c 54
	; Height
	LIS  CHAR_HEIGHT         ; 0a2d 75
	LR   draw.height, A      ; 0a2e 55

	PI   drawChar            ; 0a2f 28 08 58
	
; Draw tens digit
	; Set character
	LR   A,(IS)-             ; 0a32 4e
	SR   4                   ; 0a33 14
	LR   draw.param, A       ; 0a34 50
	; xpos -= xdelta
	LI   .X_DELTA            ; 0a35 20 fb
	AS   draw.xpos           ; 0a37 c1
	LR   draw.xpos, A        ; 0a38 51
	
	PI   drawChar            ; 0a39 28 08 58
	
; Draw hundreds digit
	; Set character
	LR   A,(IS)              ; 0a3c 4c
	NI   DIGIT_MASK          ; 0a3d 21 0f
	LR   draw.param, A       ; 0a3f 50
	; xpos -= xdelta
	LI   .X_DELTA           ; 0a40 20 fb
	AS   draw.xpos           ; 0a42 c1
	LR   draw.xpos, A        ; 0a43 51

	PI   drawChar            ; 0a44 28 08 58
	
; Draw thousands digit
	; Set character
	LR   A,(IS)              ; 0a47 4c
	SR   4                   ; 0a48 14
	LR   draw.param, A       ; 0a49 50
	; xpos -= xdelta
	LI   .X_DELTA            ; 0a4a 20 fb
	AS   draw.xpos           ; 0a4c c1
	LR   draw.xpos, A        ; 0a4d 51

	PI   drawChar            ; 0a4e 28 08 58

	; Exit
	LR   P,K                 ; 0a51 09
	POP                      ; 0a52 1c
; end of drawTimer()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; doBall()
;  Mid-Level Function
;
; This function:
; - Undraws the ball
; - Moves the ball according its velocity
; - Checks if the ball has collided with a wall
; - Saves the changes the ball's velocity
; - Redraws the ball (if the explosion flag is not set)
;
; Since this is such a long function (relative to the rest of the functions in 
;  this game), these parts of the function will be given nice, labeled dividers.
;  Also, the local variables for each part of the function will be declared at
;  the start of each part of the function.

; == Arguments ==
; doBall.size = 070
; doBall.speed = 071
; main.curBall = $b

doBall: subroutine
	LR   K,P                 ; 0a53 08

; -- Undraw the ball -----------------------------------------------------------
.tempYpos = $9

	; Load xpos
	LI   balls.xpos          ; 0a54 20 10
	AS   main.curBall        ; 0a56 cb
	LR   IS,A                ; 0a57 0b
	LR   A,(IS)              ; 0a58 4c
	LR   draw.xpos, A        ; 0a59 51

	; Load ypos
	LR   A,IS                ; 0a5a 0a
	AI   MAX_BALLS           ; 0a5b 24 0b
	LR   IS,A                ; 0a5d 0b
	LR   A,(IS)              ; 0a5e 4c

	; Store temp ypos
	LR   .tempYpos,A         ; 0a5f 59

	; Mask out the color bits from ypos
	NI   MASK_YPOSITION      ; 0a60 21 3f
	LR   draw.ypos, A        ; 0a62 52

	; Load ball size
	SETISAR doBall.size      ; 0a63 67 68
	LR   A,(IS)              ; 0a65 4c
	LR   draw.width, A       ; 0a66 54
	LR   draw.height, A      ; 0a67 55

	; Set parameter
	LI   DRAW_RECT           ; 0a68 20 80
	LR   draw.param, A       ; 0a6a 50

	; Undraw ball
	PI   drawBox             ; 0a6b 28 08 62

	; Reload ypos from temp
	LR   A,.tempYpos         ; 0a6e 49
	LR   draw.ypos, A        ; 0a6f 52

; -- Apply x and y velocities to the ball --------------------------------------
.xpos = $1
.ypos = $2

.tempSpeed = $3
.speedMask = $6

; Get bitpacked velocity
	; ISAR = balls.speed[curBall/2]
	LR   A, main.curBall     ; 0a70 4b
	SR   1                   ; 0a71 12
	AI   balls.speed         ; 0a72 24 26
	LR   IS,A                ; 0a74 0b
				
	; if (index is odd)
	;  speedMask = $0F
	; else
	;  speedMask = $F0
	LIS  $1                  ; 0a75 71
	NS   main.curBall        ; 0a76 fb
	LIS  MASK_SPEED          ; 0a77 7f
	BNZ  .setSpeedMask       ; 0a78 94 02
	COM                      ; 0a7a 18
.setSpeedMask:          
	LR   .speedMask,A        ; 0a7b 56
	
	; Load the other ball's speed nybble
	; Note: This is never read.
	COM                      ; 0a7c 18
	NS   (IS)                ; 0a7d fc
	LR   $0,A                ; 0a7e 50
	
	; Load this ball's speed nybble
	LR   A,.speedMask        ; 0a7f 46
	NS   (IS)                ; 0a80 fc
	LR   .tempSpeed,A        ; 0a81 53
	; Shift right by 4 and save the result if non-zero
	SR   4                   ; 0a82 14
	BZ   .applyVelocity      ; 0a83 84 02
	LR   .tempSpeed,A        ; 0a85 53

; Apply x velocity
.applyVelocity:
	; Test if bit 7 of xpos is set
	CLR                      ; 0a86 70
	AS   .xpos               ; 0a87 c1
	; Save result of test
	LR   J,W                 ; 0a88 1e
	
	; Load xspeed to A
	LR   A,.tempSpeed        ; 0a89 43
	SR   1                   ; 0a8a 12
	SR   1                   ; 0a8b 12
	
	; If bit 7 of xpos wasn't set, branch ahead
	LR   W,J                 ; 0a8c 1d
	BP   .addXVelocity       ; 0a8d 81 03
	
	; Else, negate the xspeed
	COM                      ; 0a8f 18
	INC                      ; 0a90 1f
.addXVelocity:
	; xpos = xpos +/- xspeed
	AS   .xpos               ; 0a91 c1
	LR   .xpos,A             ; 0a92 51

; Apply y velocity
	; Test if bit 7 of ypos is set
	CLR                      ; 0a93 70
	AS   .ypos               ; 0a94 c2
	; Save result of test
	LR   J,W                 ; 0a95 1e
	
	; Load yspeed to A
	LIS  %00000011           ; 0a96 73
	NS   .tempSpeed          ; 0a97 f3
	
	; If bit 7 of ypos wasn't set, branch ahead
	LR   W,J                 ; 0a98 1d
	BP   .addYVelocity       ; 0a99 81 03
	
	; Else, negate yspeed
	COM                      ; 0a9b 18
	INC                      ; 0a9c 1f
.addYVelocity:
	; ypos = ypos +/- yspeed
	AS   .ypos               ; 0a9d c2
	LR   .ypos,A             ; 0a9e 52

; -- Ball/Wall collision detection ---------------------------------------------
.bounceSpeed = $0 ; Speed imparted by bouncing off the walls
.rightBound  = $4
.lowerBound  = $5

; Get player or enemy right bound, depending on curBall
	SETISAR wall.rightEnemy  ; 0a9f 66 68
	LR   A, main.curBall     ; 0aa1 4b
	CI   [MAX_PLAYERS-1]     ; 0aa2 25 01
	BNC   .setRightBound     ; 0aa4 92 02
	SETISARL wall.rightPlayer; 0aa6 69
.setRightBound:          
	LR   A,(IS)              ; 0aa7 4c
	LR   .rightBound,A       ; 0aa8 54

; Likewise, get lower bound
	; .lowerBound = (ISAR+3)
	LR   A,IS                ; 0aa9 0a
	AI   3                   ; 0aaa 24 03
	LR   IS,A                ; 0aac 0b
	LR   A,(IS)              ; 0aad 4c
	LR   .lowerBound,A       ; 0aae 55

; -- Check collision with left and right walls --
	; Clear .bounceSpeed
	CLR                      ; 0aaf 70
	LR   .bounceSpeed,A      ; 0ab0 50

; Check collision with right wall
	; If ball is going leftward, branch ahead
	AS   .xpos               ; 0ab1 c1
	BM   .checkLeftWall      ; 0ab2 91 18
	; Branch if (xpos + rightBound < 256)
	AS   .rightBound         ; 0ab4 c4
	BNC   .checkBottomWall   ; 0ab5 92 29
	
; We have collided with the right wall
	; Clamp position to right wall and set direction to left
	LR   A,.rightBound       ; 0ab7 44
	COM                      ; 0ab8 18
	INC                      ; 0ab9 1f
	AI   MASK_DIRECTION      ; 0aba 24 80
	LR   .xpos,A             ; 0abc 51
	
	; Play sound for hitting wall
	LI   SOUND_1kHz          ; 0abd 20 40
	LR   playSound.sound,A   ; 0abf 53
	PI   playSound           ; 0ac0 28 0c c8

.setXSpeed:
	; .bounceSpeed.x = doBall.speed
	SETISAR doBall.speed     ; 0ac3 67 69
	LR   A,(IS)              ; 0ac5 4c
	SL   1                   ; 0ac6 13
	SL   1                   ; 0ac7 13
	LR   .bounceSpeed,A      ; 0ac8 50
	BR   .checkBottomWall    ; 0ac9 90 15

; Check if colliding with left wall
.checkLeftWall:
	; Mask out the directional bit
	LR   A,.xpos             ; 0acb 41
	NI   MASK_POSITION      ; 0acc 21 7f
	
	; branch ahead if(leftBound < xpos)
	COM                      ; 0ace 18
	INC                      ; 0acf 1f
	SETISAR wall.left        ; 0ad0 66 6a
	AS   (IS)                ; 0ad2 cc
	BNC  .checkBottomWall    ; 0ad3 92 0b
	
	; Clamp position to left wall and set direction to the right
	LR   A,(IS)              ; 0ad5 4c
	LR   .xpos,A             ; 0ad6 51
	
	; Play sound for hitting wall
	LI   SOUND_1kHz          ; 0ad7 20 40
	LR   playSound.sound,A   ; 0ad9 53
	PI   playSound           ; 0ada 28 0c c8
	
	BR   .setXSpeed          ; 0add 90 e5

; -- Check collision with top and bottom walls --
.checkBottomWall:
	CLR                      ; 0adf 70
	; If ball is moving upwards, branch ahead
	AS   .ypos               ; 0ae0 c2
	BM   .checkTopWall       ; 0ae1 91 19
	; Apply bitmask
	NI   MASK_YPOSITION      ; 0ae3 21 3f
	; Branch if ypos + lowerBound < 256
	AS   .lowerBound         ; 0ae5 c5
	BNC  .applySpeedChanges  ; 0ae6 92 27
	
; We have collided with the lower wall
	; Clamp position to the lower wall and set the direction to up
	LR   A,.lowerBound       ; 0ae8 45
	COM                      ; 0ae9 18
	INC                      ; 0aea 1f
	AI   MASK_DIRECTION      ; 0aeb 24 80
	LR   draw.ypos,A         ; 0aed 52
	
	; Play sound for hitting wall
	LI   SOUND_1kHz          ; 0aee 20 40
	LR   playSound.sound,A   ; 0af0 53
	PI   playSound           ; 0af1 28 0c c8

; Set y speed
.setYSpeed:
	; yspeed = doBall.speed
	SETISAR doBall.speed     ; 0af4 67 69
	LR   A,(IS)              ; 0af6 4c
	AS   .bounceSpeed        ; 0af7 c0
	LR   .bounceSpeed,A      ; 0af8 50
	BR   .applySpeedChanges  ; 0af9 90 14

; Check if colliding with top wall
.checkTopWall:
	SETISARU wall.upper      ; 0afb 66
	NI   MASK_YPOSITION      ; 0afc 21 3f
	; branch ahead if(topBound < ypos)
	COM                      ; 0afe 18
	INC                      ; 0aff 1f
	SETISARL wall.upper      ; 0b00 6d
	AS   (IS)                ; 0b01 cc
	BNC   .applySpeedChanges ; 0b02 92 0b
	
; We have collided with the top wall
	; Clamp position to top wall and set direction downwards
	LR   A,(IS)              ; 0b04 4c
	LR   draw.ypos,A         ; 0b05 52

	; Play sound for hitting wall	
	LI   SOUND_1kHz          ; 0b06 20 40
	LR   playSound.sound,A   ; 0b08 53
	PI   playSound           ; 0b09 28 0c c8
	
	BR   .setYSpeed          ; 0b0c 90 e7

; -- Apply velocity changes from wall bounces ----------------------------------
; Variables pertaining to curBall
.thisSpeed    = $5
.thisBitmask  = $7
; Variables pertaining to the ball that shares curBall's speed byte
.otherSpeed   = $4
.otherBitmask = $6

.applySpeedChanges:
	; Copy lower nybble to upper nybble
	LR   A,.bounceSpeed      ; 0b0e 40
	SL   4                   ; 0b0f 15
	AS   .bounceSpeed        ; 0b10 c0
	LR   .bounceSpeed,A      ; 0b11 50

	; ISAR = index of the speed byte
	LR   A,main.curBall      ; 0b12 4b
	SR   1                   ; 0b13 12
	AI   balls.speed         ; 0b14 24 26
	LR   IS,A                ; 0b16 0b

	; Set the bitmask for the appropriate nybble
	LIS  $1                  ; 0b17 71
	NS   main.curBall        ; 0b18 fb
	LIS  MASK_SPEED          ; 0b19 7f
	BNZ  .setSpeedMaskAgain  ; 0b1a 94 02
	COM                      ; 0b1c 18
.setSpeedMaskAgain:
	LR   .thisBitmask, A     ; 0b1d 57

	; Set the bitmask for the other ball's speed nybble 
	COM                      ; 0b1e 18
	LR   .otherBitmask,A     ; 0b1f 56
	; Save other ball's speed nybble
	NS   (IS)                ; 0b20 fc
	LR   .otherSpeed,A       ; 0b21 54

	; Apply the bitmask to get our speed from memory
	LR   A,.thisBitmask      ; 0b22 47
	NS   (IS)                ; 0b23 fc
	LR   .thisSpeed,A        ; 0b24 55

; Apply y axis bounce
	; Branch ahead if .bounceSpeed.y == 0
	LI   MASK_YSPEED         ; 0b25 20 33
	NS   .bounceSpeed        ; 0b27 f0
	BZ   .saveXAxisBounce    ; 0b28 84 0c

	; Mask out yspeed from thisSpeed
	LI   MASK_XSPEED         ; 0b2a 20 cc
	NS   .thisBitmask        ; 0b2c f7
	NS   .thisSpeed          ; 0b2d f5
	LR   .thisSpeed,A        ; 0b2e 55
	
	; .thisSpeed.y = .bounceSpeed.y
	LI   MASK_YSPEED         ; 0b2f 20 33
	NS   .bounceSpeed        ; 0b31 f0
	AS   .thisSpeed          ; 0b32 c5
	NS   .thisBitmask        ; 0b33 f7
	LR   .thisSpeed,A        ; 0b34 55

; Apply x axis bounce
.saveXAxisBounce:
	; Branch ahead if .bounceSpeed.x == 0
	LI   MASK_XSPEED         ; 0b35 20 cc
	NS   .bounceSpeed        ; 0b37 f0
	BZ   .prepSaveBall       ; 0b38 84 0c
				
	; Mask out xspeed from thisSpeed
 	LI   MASK_YSPEED         ; 0b3a 20 33
	NS   .thisBitmask        ; 0b3c f7
	NS   .thisSpeed          ; 0b3d f5
	LR   .thisSpeed,A        ; 0b3e 55

	; .thisSpeed.x = .bounceSpeed.x
	LI   MASK_XSPEED         ; 0b3f 20 cc
	NS   .bounceSpeed        ; 0b41 f0
	AS   .thisSpeed          ; 0b42 c5
	NS   .thisBitmask        ; 0b43 f7
	LR   .thisSpeed,A        ; 0b44 55

; Prepare to save ball to array
.prepSaveBall:
	; Merge the nybbles back together
	LR   A,.thisSpeed        ; 0b45 45
	AS   .otherSpeed         ; 0b46 c4

	; Set speed for saveBall
	LR   saveBall.speed,A    ; 0b47 50

	; It is finished... we can save the results
	PI   saveBall            ; 0b48 28 09 a2
	
; -- Redraw the ball -----------------------------------------------------------
	; if(curball <=1)
	;  color = ballColors[curBall]
	; else
	;  color = ballColors[2]
	DCI  ballColors          ; 0b4b 2a 08 50
	LR   A,main.curBall      ; 0b4e 4b
	CI   [MAX_PLAYERS-1]     ; 0b4f 25 01
	LIS  2                   ; 0b51 72
	BNC   .setColor          ; 0b52 92 02
	LR   A,main.curBall      ; 0b54 4b
.setColor:
	ADC                      ; 0b55 8e
	LR   A, draw.ypos        ; 0b56 42

	; Mask out the direction
	NI   MASK_POSITION      ; 0b57 21 7f

	; OR in the color
	OM                       ; 0b59 8b
	LR   draw.ypos, A        ; 0b5a 52

	; Set drawing parameters
	LI   DRAW_RECT           ; 0b5b 20 80
	LR   draw.param, A       ; 0b5d 50

	; Set ball width/height
	SETISAR doBall.size      ; 0b5e 67 68
	LR   A,(IS)              ; 0b60 4c
	LR   draw.width, A       ; 0b61 54
	LR   draw.height, A      ; 0b62 55

	; Do not redraw if explosion flag is set
	SETISAR explosionFlag    ; 0b63 67 6a
	CLR                      ; 0b65 70
	AS   (IS)                ; 0b66 cc
	BM   .return             ; 0b67 91 04

	; Redraw ball
	PI   drawBox             ; 0b69 28 08 62

collision.return: ; The next function uses this to return as well
.return:
	LR   P,K                 ; 0b6c 09
	POP                      ; 0b6d 1c
; end doBall()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; collision()
;
; Performs ball-ball collision detection against a single ball as specified by
;  the input argument.
;
; The ball specified by the caller is tested against every other active ball to
;  see if they overlap along the x and y axes. If so, and if the ball being
;  tested against is the player's ball, this function jumps directly to
;  gameOver(). Otherwise, the x and y directions and speeds are fiddled with to 
;  make them bounce off each other.

; == Arguments ==
; main.curBall = $b

; == Locals ==
; testBall = 071
mainBall.xpos = $1
mainBall.ypos = $2

; == Entry Point ==
collision: subroutine
	LR   K,P                 ; 0b6e 08

	; setting up the collision loop counter
	; testBall = (delayIndex & 0x0F) + 1
	SETISAR delayIndex       ; 0b6f 65 6f
	LI   %00001111           ; 0b71 20 0f
	NS   (IS)                ; 0b73 fc
	SETISAR testBall         ; 0b74 67 69
	INC                      ; 0b76 1f
	LR   (IS),A              ; 0b77 5c

.testBallLoop:
	; loopCount--
	SETISAR testBall         ; 0b78 67 69
	DS   (IS)                ; 0b7a 3c

	; if(testBall < 0), return
	BM   collision.return; 0b7b 91 f0

	; if(testBall == curBall), skip and go to next ball
	LR   A,(IS)              ; 0b7d 4c
	XS   main.curBall        ; 0b7e eb
	BZ   .testBallLoop       ; 0b7f 84 f8

	; Check if we're in 2-player mode
	SETISARL gameMode        ; 0b81 6d
	LIS  $1                  ; 0b82 71
	NS   (IS)                ; 0b83 fc
	; If so, skip ahead
	BNZ  .getBallPosition    ; 0b84 94 07
	
	; If not, check if the loop counter is a player's ball
	SETISARL testBall        ; 0b86 69
	LR   A,(IS)              ; 0b87 4c
	CI   [MAX_PLAYERS-1]     ; 0b88 25 01
	; If so, skip the current ball
	BZ   .testBallLoop ; 0b8a 84 ed

.getBallPosition:
	; r1 = xpos[curBall]
	LI   balls.xpos          ; 0b8c 20 10
	AS   main.curBall        ; 0b8e cb
	LR   IS,A                ; 0b8f 0b
	LR   A,(IS)              ; 0b90 4c
	; Mask out the direction
	NI   MASK_POSITION       ; 0b91 21 7f
	LR   mainBall.xpos,A     ; 0b93 51
	
	; r2 = ypos[curBall]
	LR   A,IS                ; 0b94 0a
	AI   MAX_BALLS           ; 0b95 24 0b
	LR   IS,A                ; 0b97 0b
	LR   A,(IS)              ; 0b98 4c
	; Mask out the direction
	NI   MASK_YPOSITION      ; 0b99 21 3f
	LR   mainBall.ypos,A     ; 0b9b 52
	
; -- Test collision along x axis -----------------------------------------------
.xDelta = $1

	; mainBall.xpos-testBall.xpos
	SETISAR testBall         ; 0b9c 67 69
	LI   balls.xpos          ; 0b9e 20 10
	AS   (IS)                ; 0ba0 cc
	LR   IS,A                ; 0ba1 0b
	LR   A,(IS)              ; 0ba2 4c
	NI   MASK_POSITION       ; 0ba3 21 7f
	COM                      ; 0ba5 18
	INC                      ; 0ba6 1f
	AS   mainBall.xpos       ; 0ba7 c1
	
	; Save flags
	LR   J,W                 ; 0ba8 1e
	; Keep results if (mainBall.xpos >= testBall.xpos)
	BP   .saveXdelta         ; 0ba9 81 03	
	; Otherwise negate the results
	COM                      ; 0bab 18
	INC                      ; 0bac 1f
	
.saveXdelta:
	; abs(mainBall.x - testBall.x)
	LR   .xDelta,A           ; 0bad 51
	
	; branch ahead if testBall is not a player ball
	LR   A,IS                ; 0bae 0a
	CI   [balls.xpos+MAX_PLAYERS-1] ; 0baf 25 11
	BNC  .useEnemySize       ; 0bb1 92 0b

	; branch ahead if mainBall.xpos < testBall.xpos
	;  or: if mainBall is left of testBall
	LR   W,J                 ; 0bb3 1d    ; Reuse flags from earlier
	BM   .useEnemySize       ; 0bb4 91 08
				
	; Get player ball width
	LI   MASK_PLAYER_SIZE    ; 0bb6 20 c0
	NS   main.gameSettings   ; 0bb8 fa
	SR   1                   ; 0bb9 12
	SR   1                   ; 0bba 12
	BR   .testXaxis          ; 0bbb 90 04

	; or get enemy ball width
.useEnemySize:
	LI   MASK_ENEMY_SIZE     ; 0bbd 20 30
	NS   main.gameSettings   ; 0bbf fa

.testXaxis:
	SR   4                   ; 0bc0 14

	; xDelta - testBall.width
	COM                      ; 0bc1 18
	INC                      ; 0bc2 1f
	AS   .xDelta             ; 0bc3 c1

	; if (xDelta >= testBall.width)
	;  continue on to next ball
	BP   .testBallLoop             ; 0bc4 81 b3
	; else
	;  test the y axis collision

; -- Test collision on the y axis ----------------------------------------------
.yDelta = $2

	; mainBall.ypos-testBall.ypos
	LR   A,IS                ; 0bc6 0a
	AI   MAX_BALLS           ; 0bc7 24 0b
	LR   IS,A                ; 0bc9 0b
	LR   A,(IS)              ; 0bca 4c
	NI   MASK_YPOSITION      ; 0bcb 21 3f
	COM                      ; 0bcd 18
	INC                      ; 0bce 1f
	AS   mainBall.ypos       ; 0bcf c2
	
	; Save flags
	LR   J,W                 ; 0bd0 1e
	; Keep results if (mainBall.ypos >= testBall.ypos)
	BP   .saveYdelta         ; 0bd1 81 03
	; Otherwise negate the results
	COM                      ; 0bd3 18
	INC                      ; 0bd4 1f
.saveYdelta:
	; abs(mainBall.ypos-testBall.ypos)
	LR   .yDelta,A           ; 0bd5 52

	; branch ahead if testBall is not a player ball
	LR   A,IS                ; 0bd6 0a
	CI   [balls.ypos+MAX_PLAYERS-1]; 0bd7 25 1c
	BNC   .useEnemySize2     ; 0bd9 92 0b

	; branch ahead if mainBall.ypos < testBall.ypos
	;  or: if mainBall is north of testBall
	LR   W,J                 ; 0bdb 1d    ; Reuse flags from earlier
	BM   .useEnemySize2      ; 0bdc 91 08
	
	; Get player ball width
	LI   MASK_PLAYER_SIZE    ; 0bde 20 c0
	NS   main.gameSettings   ; 0be0 fa
	SR   1                   ; 0be1 12
	SR   1                   ; 0be2 12
	BR   .testYaxis          ; 0be3 90 04
	; or get enemy ball width
.useEnemySize2:
	LI   MASK_ENEMY_SIZE     ; 0be5 20 30
	NS   main.gameSettings   ; 0be7 fa
.testYaxis:
	SR   4                   ; 0be8 14
	
	; yDelta - tempWidth
	COM                      ; 0be9 18
	INC                      ; 0bea 1f
	AS   .yDelta             ; 0beb c2

	; if (yDelta >= tempWidth)
	;  continue on to next ball
	BP   .testBallLoop       ; 0bec 81 8b
	; else
	;  handle the collision that just happened

; -- If we got to this point, a collision has happened -------------------------
	
	; Check if the collision was with a player
	;  If so, game over
	;  Else, skip ahead
	SETISAR testBall         ; 0bee 67 69
	LR   A,(IS)              ; 0bf0 4c
	CI   [MAX_PLAYERS-1]     ; 0bf1 25 01
	BNC   .makeNoise         ; 0bf3 92 04
	; Game over
	JMP  gameOver            ; 0bf5 29 0e 44

.makeNoise:
	; Play sound
	LI   SOUND_500Hz         ; 0bf8 20 80
	LR   playSound.sound,A   ; 0bfa 53
	PI   playSound           ; 0bfb 28 0c c8
	
	; RNG for random bounce trajectory
	PI   rand                ; 0bfe 28 08 c1

	; branch ahead if(yDelta < 1)
	LR   A,.yDelta           ; 0c01 42
	CI   1                   ; 0c02 25 01
	BC   .randYdirection     ; 0c04 82 3c

; -- Fiddle with the x direction -----------------------------------------------
.speedThing = $8
.SPEED_ADJUST = $44
.randBall = $0 ; TODO: Give this variable a better name (it's not random)
	
; Randomize x direction of mainBall
	; Set ISAR to xpos[curBall]
	LI   balls.xpos          ; 0c06 20 10
	AS   main.curBall        ; 0c08 cb
	LR   IS,A                ; 0c09 0b
	; XOR the direction with the RNG
	LI   MASK_DIRECTION      ; 0c0a 20 80
	NS   RNG.regHi           ; 0c0c f6
	XS   (IS)                ; 0c0d ec
	LR   (IS),A              ; 0c0e 5c
	; Save flags from (MASK_DIRECTION xor RNG)
	; Note: These flags do not appear to be used
	LR   J,W                 ; 0c0f 1e

; Randomize x direction of testBall
	; ISAR = balls.xpos + testBall
	SETISAR testBall         ; 0c10 67 69
	LI   balls.xpos          ; 0c12 20 10
	AS   (IS)                ; 0c14 cc
	LR   IS,A                ; 0c15 0b
	; Add RNG.lo to the direction
	LI   MASK_DIRECTION      ; 0c16 20 80
	NS   RNG.regLo           ; 0c18 f7
	AS   (IS)                ; 0c19 cc
	LR   (IS),A              ; 0c1a 5c
				
	; We'll be using this later to adjust the speed
	LI   .SPEED_ADJUST       ; 0c1b 20 44
	LR   .speedThing,A       ; 0c1d 58

	; randBall = mainBall
	;  The branch that fiddles the y direction sets this to testBall
	LR   A, main.curBall     ; 0c1e 4b
	LR   .randBall,A         ; 0c1f 50

; -- Fiddle with the speed -----------------------------------------------------
.thisBitmask = $3
.otherSpeed = $4

.checkMode:
	; If MODE_BOUNCE_MASK is set, we mess with the speed
	;  Note: This bit is set in shuffleGame(), and is cleared in explode()
	SETISAR gameMode         ; 0c20 67 6d
	CLR                      ; 0c22 70
	AS   (IS)                ; 0c23 cc
	BP   .changeSpeed        ; 0c24 81 04
	; Else, test the next ball
	JMP  .testBallLoop       ; 0c26 29 0b 78

.changeSpeed:
	; ISAR = balls.speed + randBall/2
	LR   A,.randBall         ; 0c29 40
	SR   1                   ; 0c2a 12
	AI   balls.speed         ; 0c2b 24 26
	LR   IS,A                ; 0c2d 0b

	; Conjure up the bitmask to extract randBall's speed
	LIS  $1                  ; 0c2e 71
	NS   .randBall           ; 0c2f f0
	LIS  MASK_SPEED          ; 0c30 7f
	BNZ  .getThisBitmask     ; 0c31 94 02
	COM                      ; 0c33 18
.getThisBitmask:
	; Save randBall's speed bitmask
	LR   .thisBitmask,A      ; 0c34 53
	; Temp storage for the other speed bitfield
	COM                      ; 0c35 18
	NS   (IS)                ; 0c36 fc
	LR   .otherSpeed,A       ; 0c37 54
	
	; Get the speed bitfield for randBall
	LR   A,.thisBitmask      ; 0c38 43
	NS   (IS)                ; 0c39 fc
	; Add .speedThing to it, and clean up with the bitmask
	AS   .speedThing         ; 0c3a c8
	NS   .thisBitmask        ; 0c3b f3
	; Merge the two speed bitfields and save the result
	AS   .otherSpeed         ; 0c3c c4
	LR   (IS),A              ; 0c3d 5c
	
	; Return (don't process any more collisions for mainBall)
	JMP  collision.return            ; 0c3e 29 0b 6c

; -- Fiddle with y direction ---------------------------------------------------
.randYdirection:
	; randBall = testBall
	; ISAR = balls.ypos + randBall
	SETISAR testBall         ; 0c41 67 69
	LR   A,(IS)              ; 0c43 4c
	LR   .randBall,A         ; 0c44 50
	AI   balls.ypos          ; 0c45 24 1b
	LR   IS,A                ; 0c47 0b

	; Flip the y direction of testBall
	LI   MASK_DIRECTION      ; 0c48 20 80
	XS   (IS)                ; 0c4a ec
	LR   (IS),A              ; 0c4b 5c
	; Save flags for later
	LR   J,W                 ; 0c4c 1e

	; ISAR = balls.ypos + mainBall
	LI   balls.ypos          ; 0c4d 20 1b
	AS   main.curBall        ; 0c4f cb
	LR   IS,A                ; 0c50 0b

	; Set mainBall's direction to down
	LR   A,(IS)              ; 0c51 4c
	OI   MASK_DIRECTION      ; 0c52 22 80
	
	; Load flags from earlier
	;  if testBall went down, mainBall goes up
	;  if testBall went up, mainBall goes down
	LR   W,J                 ; 0c54 1d
	BP   .setYdirection      ; 0c55 81 03
	NI   MASK_YPOSITION      ; 0c57 21 3f
.setYdirection:
	LR   (IS),A              ; 0c59 5c
	
	; We'll be using this later to adjust the velocity
	LI   .SPEED_ADJUST       ; 0c5a 20 44
	LR   .speedThing,A       ; 0c5c 58
	
	; Go to the "fiddle with speed" section of this function
	BR   .checkMode          ; 0c5d 90 c2
; end of collision()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; setWalls()
;
; Sets the positions of the walls along one axis given an input range.
  
; == Arguments ==
; *walls = ISAR
walls.max = $1
walls.min = $2

; == Constants ==


setWalls: subroutine 
	LR   K,P                 ; 0c5f 08

; == Local ==
.tempWall = $4

.reroll:
	; Reroll RNG until r6 is non-zero
	PI   rand                ; 0c60 28 08 c1
	CLR                      ; 0c63 70
	AS   RNG.regHi           ; 0c64 c6
	BZ   .reroll             ; 0c65 84 fa
	
; Make sure the RNG is in range, depending on the axis being set
	; if(r1 == 0x58) ; x axis case
	;  if(RNG > 0x12)
	;   go back and reroll
	; else if(RNG > 0x0B) ; y axis case
	;   go back and reroll
	LR   A,walls.max         ; 0c67 41
	CI   WALL_XMAX           ; 0c68 25 58

	LR   A, RNG.regHi        ; 0c6a 46
	BNZ  .clampY             ; 0c6b 94 05

	CI   WALL_X_OFFSET_MAX   ; 0c6d 25 12
	BR   .clampX             ; 0c6f 90 03

.clampY:
	CI   WALL_Y_OFFSET_MAX   ; 0c71 25 0b
.clampX:
	BNC  .reroll             ; 0c73 92 ec

; Get the base value for the right/lower wall
	;  Note: the greater this number is, the more to the left (or top) this wall
	;   is. (Unintuitive. Works opposite of how the upper and left walls work.)
	; .tempWall = -(max-rng+1)
	COM                      ; 0c75 18
	INC                      ; 0c76 1f
	INC                      ; 0c77 1f
	AS   walls.max           ; 0c78 c1
	COM                      ; 0c79 18
	INC                      ; 0c7a 1f
	LR   .tempWall,A         ; 0c7b 54
	
; Adjust the right/lower wall according to the enemy's size
	; wall.right(or lower)Enemy = playerSize + .tempWall
	LI   MASK_ENEMY_SIZE     ; 0c7c 20 30
	NS   main.gameSettings   ; 0c7e fa
	SR   4                   ; 0c7f 14
	AS   .tempWall           ; 0c80 c4
	LR   (IS)+,A             ; 0c81 5d
	
; Adjust the right/lower wall according to the player's size
	; wall.right(or lower)Player = playerSize + .tempWall
	LI   MASK_PLAYER_SIZE    ; 0c82 20 c0
	NS   main.gameSettings   ; 0c84 fa
	SR   4                   ; 0c85 14
	SR   1                   ; 0c86 12
	SR   1                   ; 0c87 12
	AS   .tempWall           ; 0c88 c4
	LR   (IS)+,A             ; 0c89 5d
	
; Set the left or top boundary
	; ISAR++ = walls.min + RNG
	LR   A,RNG.regHi         ; 0c8a 46
	AS   walls.min           ; 0c8b c2
	LR   (IS)+,A             ; 0c8c 5d

	; Exit
	LR   P,K                 ; 0c8d 09
	POP                      ; 0c8e 1c
; end of setWalls()
;-------------------------------------------------------------------------------
	
;-------------------------------------------------------------------------------
; flash()
;  Mid-Level Function
;
; UNUSED
;
; Makes the screen flash -- possibly an old form of the death animation. Working
;  off of that assumption, we will assume that this function would have been
;  called after a player collision in the ball-ball collision function.

; == Arguments ==
; testBall = 071

; No Returns

flash: subroutine
	LR   K,P                 ; 0c8f 08

; == Locals ==
.loopCount = $9
.NUM_LOOPS = $25
	
	LI   .NUM_LOOPS          ; 0c90 20 25
	LR   .loopCount, A       ; 0c92 59

	; Set flash color/sound value depending on value of o71 (who died?)
	SETISAR testBall         ; 0c93 67 69
	LIS  $1                  ; 0c95 71
	NS   (IS)-               ; 0c96 fe
	LI   SOUND_500Hz         ; 0c97 20 80
	BZ   .setSound           ; 0c99 84 03
	LI   SOUND_120Hz         ; 0c9b 20 c0
.setSound:          
	LR   (IS), A             ; 0c9d 5c
	LR   draw.ypos, A        ; 0c9e 52

; Loop back here to reset the sound and row attribute color to the above value
.loopResetColor:          
	LR   A,(IS)              ; 0c9f 4c

; Loop back here to keep the sound and row attribute color cleared
.loopClearColor:          
	; Set ypos/color
	LR   draw.ypos, A        ; 0ca0 52

	; Make sound
	; NOTE: sound is not played if curBall is one of the player balls
	LR   A,(IS)              ; 0ca1 4c
	LR   playSound.sound,A   ; 0ca2 53
	PI   playSound           ; 0ca3 28 0c c8
	
	LISL 0                   ; 0ca6 68 ; ISAR = 070 ; Temp?
	; Set xpos to attribute column
	LI   DRAW_ATTR_X         ; 0ca7 20 7d
	LR   draw.xpos, A        ; 0ca9 51
	; Set width
	LIS  DRAW_ATTR_W         ; 0caa 72
	LR   draw.width, A       ; 0cab 54
	; Set height
	LI   DRAW_SCREEN_H       ; 0cac 20 40
	LR   draw.height, A      ; 0cae 55
	; Set rendering parameter
	LI   DRAW_ATTRIBUTE      ; 0caf 20 c0
	LR   draw.param, A       ; 0cb1 50
	PI   drawBox             ; 0cb2 28 08 62
	
	; Clear sound
	CLR                      ; 0cb5 70
	OUTS 5                   ; 0cb6 b5
	
	; Delay
	LIS  $b                  ; 0cb7 7b
	LR   delay.count, A      ; 0cb8 50
	PI   delayVariable       ; 0cb9 28 09 9a

	; loopCount--
	;  exit it less than zero
	DS   .loopCount          ; 0cbc 39
	BM   .exit               ; 0cbd 91 08
	
	; if (timer is even)
	;  ypos/color = (ISAR)
	LIS  $1                  ; 0cbf 71
	NS   .loopCount          ; 0cc0 f9
	CLR                      ; 0cc1 70
	BZ   .loopResetColor     ; 0cc2 84 dc
	; else
	;  ypos/color = 0
	BR   .loopClearColor     ; 0cc4 90 db

.exit:     
	LR   P,K                 ; 0cc6 09
	POP                      ; 0cc7 1c
; end flash()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; playSound(ball, sound)
;  Leaf Function
;
; Make a ticking noise when the balls collide with something.

; == Arguments ==
playSound.sound = 3
; main.curBall = $b

; == Entry Point ==
playSound: subroutine
	; if(curBall >= MAX_PLAYERS)
	LR   A, main.curBall     ; 0cc8 4b
	CI   [MAX_PLAYERS-1]     ; 0cc9 25 01
	BC   playSound.exit      ; 0ccb 82 03
	; then play the sound
	LR   A, playSound.sound  ; 0ccd 43
	OUTS 5                   ; 0cce b5
	
playSound.exit:          
	POP                      ; 0ccf 1c
; end playSound()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; init()
;  Top-Level Procedure
;
; For simplicity's sake, this disassembly will divide the top-level thread into
;  separate "functions", even though they are not callable and the code just
;  flows and jumps from one block to another.
;
; To initialize the game, this procedure does some initial bookkeeping with the
;  scratchpad, I/O, and display, and then asks the player to select the game
;  mode with the question "G?" The four selectable game types are:
;
; 1 - Slow, 1 player
; 2 - Slow, 2 players
; 3 - Fast, 1 player
; 4 - Fast, 2 players

init: subroutine
	SETISAR RNG.seedLo       ; 0cd0 67 6f

	; Enable data from controllers
	LI   $40                 ; 0cd2 20 40
	OUTS 0                   ; 0cd4 b0
	
	; Seed RNG from uninitialized ports
	INS  4                   ; 0cd5 a4
	LR   (IS)-,A             ; 0cd6 5e
	INS  5                   ; 0cd7 a5
	LR   (IS)-,A             ; 0cd8 5e
	
	; Clear BIOS stack pointer at 073
	;  This game does not use the BIOS's stack functions
	LISL 3                   ; 0cd9 6b
	CLR                      ; 0cda 70
	LR   (IS),A              ; 0cdb 5c
	; The BIOS already intialized the rest of the scratchpad to zero
	
	; Clear port
	OUTS 0                   ; 0cdc b0

; Clear screen
	; Set properties
	LI   DRAW_RECT           ; 0cdd 20 80
	LR   draw.param, A       ; 0cdf 50
	; Set x and y pos
	CLR                      ; 0ce0 70
	LR   draw.xpos, A        ; 0ce1 51
	LR   draw.ypos, A        ; 0ce2 52
	; Set width
	LI   DRAW_SCREEN_W       ; 0ce3 20 80
	LR   draw.width, A       ; 0ce5 54
	; Set height
	LI   DRAW_SCREEN_H       ; 0ce6 20 40
	LR   draw.height, A      ; 0ce8 55

	PI   drawBox             ; 0ce9 28 08 62

; Set row attributes
	; Set rendering properties, ypos, and color
	LI   DRAW_ATTRIBUTE      ; 0cec 20 c0
	LR   draw.param, A       ; 0cee 50
	LR   draw.ypos, A        ; 0cef 52
	; Set width
	LIS  DRAW_ATTR_W         ; 0cf0 72
	LR   draw.width, A       ; 0cf1 54
	; xpos = attribute column
	LI   DRAW_ATTR_X         ; 0cf2 20 7d
	LR   draw.xpos, A        ; 0cf4 51
	; Height and ypos are retained from previous write
	PI   drawBox             ; 0cf5 28 08 62

; Draw the "G?" screen
.G_X = $30
.G_Y = $1B
.Q_X = $35

	; Set char
	LIS  CHAR_G              ; 0cf8 7a
	LR   draw.param, A       ; 0cf9 50
	; Set xpos
	LI   .G_X                ; 0cfa 20 30
	LR   draw.xpos, A        ; 0cfc 51
	; Set ypos and color
	LI   RED | .G_Y          ; 0cfd 20 9b
	LR   draw.ypos, A        ; 0cff 52
	; Set width
	LIS  CHAR_WIDTH          ; 0d00 74
	LR   draw.width, A       ; 0d01 54
	; Set height
	LIS  CHAR_HEIGHT         ; 0d02 75
	LR   draw.height, A      ; 0d03 55

	PI   drawChar            ; 0d04 28 08 58
	
	; Set char
	LIS  CHAR_QMARK          ; 0d07 7b
	LR   draw.param, A       ; 0d08 50
	; Set xpos
	LI   .Q_X                ; 0d09 20 35
	LR   draw.xpos, A        ; 0d0b 51

	PI   drawChar            ; 0d0c 28 08 58
	
; Wait 10 seconds for input
	PI   menu                ; 0d0f 28 08 f0
	; The button press is returned in A (default is 1)

; Use a table to put the number of the button pressed into gameMode
	SETISAR gameMode         ; 0d12 67 6d
	SR   1                   ; 0d14 12
	; DC was set in the menu
	ADC                      ; 0d15 8e
	LM                       ; 0d16 16
	LR   (IS),A              ; 0d17 5c

	; Continue on to next procedure
	
;-------------------------------------------------------------------------------
; shuffleGame()
;  Top-Level Procedure
;
; This function randomizes the game parameters such as player size, enemy size,
;  player speed, enemy speed, the upper six bits of gameMode, and the walls.

shuffleGame: subroutine
	; Preserve the player and game speed bits of gameMode
	SETISAR gameMode         ; 0d18 67 6d
	LR   A,(IS)              ; 0d1a 4c
	NI   MODE_CHOICE_MASK    ; 0d1b 21 03
	LR   (IS),A              ; 0d1d 5c

.reroll:
	; Array of bitmaks to be used in the following series of tests
	DCI  gameModeMasks       ; 0d1e 2a 08 43
	
	; Get a random number
	PI   rand                ; 0d21 28 08 c1
	
; Test to see if the number is a valid game setting
.temp = $8

	; Put bits 6 and 7 of RNG into .temp (for player ball size)
	LM                       ; 0d24 16
	NS   RNG.regHi           ; 0d25 f6
	LR   .temp,A             ; 0d26 58
	
	; Add bits 4 and 5 of RNG to the previous result (for enemy ball size)
	LM                       ; 0d27 16
	NS   RNG.regHi           ; 0d28 f6
	SL   1                   ; 0d29 13
	SL   1                   ; 0d2a 13
	AS   .temp               ; 0d2b c8
	; if(playerSize + enemySize < 4), then reroll
	BNC  .reroll             ; 0d2c 92 f1
	
	; Test if at least one of bits 2 and 3 of RNG are set
	LM                       ; 0d2e 16
	NS   RNG.regHi           ; 0d2f f6
	; if(playerSpeed == 0), then reroll
	BZ   .reroll             ; 0d30 84 ed

	; Test if at least one of bits 0 and 1 of RNG are set
	LM                       ; 0d32 16
	NS   RNG.regHi           ; 0d33 f6
	; if(enemySpeed == 0), then reroll
	BZ   .reroll             ; 0d34 84 e9

	; RNG.regHi contains a valid value, so we can use it
	LR   A, RNG.regHi        ; 0d36 46
	LR   main.gameSettings,A ; 0d37 5a

; Put the upper six bits of the RNG into gameMode
	LM                       ; 0d38 16
	NS   RNG.regLo           ; 0d39 f7
	AS   (IS)                ; 0d3a cc
	LR   (IS)-,A             ; 0d3b 5e
	; Note: This ISAR post-decrement puts the ISAR on player 2's high score.
	;  This is not utilized.

	; DC = (enemySpeed)*2
	; Note: This array is never read from.
	DCI  unusedSpeedTable    ; 0d3c 2a 08 48
	LIS  MASK_ENEMY_SPEED    ; 0d3f 73
	NS   main.gameSettings   ; 0d40 fa
	SL   1                   ; 0d41 13
	ADC                      ; 0d42 8e
	; Note: Perhaps the 2 bytes from this table were meant to be loaded into the
	;  space that is now reserved for player 2's high score.

; Set playfield walls
	; Set playfield walls for x axis
	LI   WALL_XMAX           ; 0d43 20 58
	LR   walls.max,A         ; 0d45 51
	LI   WALL_MIN            ; 0d46 20 10
	LR   walls.min,A         ; 0d48 52
	SETISAR wall.rightEnemy  ; 0d49 66 68
	PI   setWalls            ; 0d4b 28 0c 5f
	
	; Set playfield walls for y axis
	LI   WALL_YMAX           ; 0d4e 20 38
	LR   walls.max,A         ; 0d50 51
	PI   setWalls            ; 0d51 28 0c 5f
	
	; Continue on to next procedure

;-------------------------------------------------------------------------------
; restartGame()
;  Top-Level Procedure
;
; Does prep work necessary to restart (or start the game), such as drawing the
;  playfield, clearing the timer, spawning the players and the first ball, and
;  making sure the explosion flag is clear.

restartGame: subroutine

; Draw playfield walls
	; Set rendering properties
	LI   DRAW_RECT           ; 0d54 20 80
	LR   draw.param, A       ; 0d56 50
	; Set x pos
	LI   FIELD_CORNER        ; 0d57 20 10
	LR   draw.xpos, A        ; 0d59 51
	; Set color (and ypos)
	AI   RED                 ; 0d5a 24 80
	LR   draw.ypos, A        ; 0d5c 52
	; Set width
	LI   FIELD_WIDTH         ; 0d5d 20 49
	LR   draw.width, A       ; 0d5f 54
	; Set height
	LI   FIELD_HEIGHT        ; 0d60 20 29
	LR   draw.height, A      ; 0d62 55
	; Draw box
	PI   drawBox             ; 0d63 28 08 62

; Draw inner box of playfield
.tempSize = $3

	; xpos = wall.left
	SETISAR wall.left        ; 0d66 66 6a
	LR   A,(IS)              ; 0d68 4c
	LR   draw.xpos, A        ; 0d69 51

	; width = -(wall.left + wall.rightEnemy) + enemySize
	SETISARL wall.rightEnemy ; 0d6a 68
	AS   (IS)                ; 0d6b cc
	COM                      ; 0d6c 18
	INC                      ; 0d6d 1f
	LR   draw.width, A       ; 0d6e 54

	LI   MASK_ENEMY_SIZE     ; 0d6f 20 30
	NS   main.gameSettings   ; 0d71 fa
	SR   4                   ; 0d72 14
	LR   .tempSize,A         ; 0d73 53

	AS   draw.width          ; 0d74 c4
	LR   draw.width, A       ; 0d75 54
	
	; Set ypos (color is blank)
	SETISARL wall.upper      ; 0d76 6d
	LR   A,(IS)              ; 0d77 4c
	LR   draw.ypos, A        ; 0d78 52
	
	; height = -(wall.top - wall.lowerEnemy) + enemySize
	SETISARL wall.lowerEnemy ; 0d79 6b
	AS   (IS)                ; 0d7a cc
	COM                      ; 0d7b 18
	INC                      ; 0d7c 1f
	AS   .tempSize           ; 0d7d c3
	LR   draw.height, A      ; 0d7e 55
	
	; Set rendering properties
	LI   DRAW_RECT           ; 0d7f 20 80
	LR   draw.param, A       ; 0d81 50

	; Draw
	PI   drawBox             ; 0d82 28 08 62
	
; Clear timer
	SETISAR timer.hi         ; 0d85 66 6e
	CLR                      ; 0d87 70
	LR   (IS)+,A             ; 0d88 5d
	LR   (IS)+,A             ; 0d89 5d

; Spawn the balls
	; Spawn the players
	CLR                      ; 0d8a 70
.spawnLoop:          
	LR   main.curBall, A     ; 0d8b 5b
	PI   spawnBall           ; 0d8c 28 09 c2
	
	LR   A, main.curBall     ; 0d8f 4b
	INC                      ; 0d90 1f
	CI   [MAX_PLAYERS-1]     ; 0d91 25 01
	BC   .spawnLoop          ; 0d93 82 f7

	; Spawn the first enemy ball
	SETISAR balls.count      ; 0d95 65 6e
	LR   (IS),A              ; 0d97 5c
	LR   main.curBall, A     ; 0d98 5b
	PI   spawnBall           ; 0d99 28 09 c2

; Clear the the explosion flag
	SETISAR explosionFlag    ; 0d9c 67 6a
	CLR                      ; 0d9e 70
	LR   (IS),A              ; 0d9f 5c

	; Continue on to next procedure

;-------------------------------------------------------------------------------
; mainLoop()
;  Top-Level Procedure
;
; Clears the sound, draws the timer, runs a delay function, processes the enemy
;  balls, processes the player balls, and repeats until somebody loses.
;
; Note that since the Channel F lacks vsync or any sort of interval timer, that
;  the game needs to use a delay function to keep the game running at a
;  consistent and reasonable speed.

mainLoop: subroutine
	; Clear sound
	CLR                      ; 0da0 70
	OUTS 5                   ; 0da1 b5
				
; Change delay index according to the timer
	; if (timer.hi > 10)
	;   delay index = 10
	; else
	;	delay index = timer.hi + 1
	SETISAR timer.hi         ; 0da2 66 6e
	LR   A,(IS)+             ; 0da4 4d
	INC                      ; 0da5 1f
	CI   [MAX_BALLS-1]       ; 0da6 25 0a
	BC   .setDelay           ; 0da8 82 02
	LIS  [MAX_BALLS-1]       ; 0daa 7a
.setDelay:
	SETISARU delayIndex      ; 0dab 65
	LR   (IS),A              ; 0dac 5c
	SETISARU timer.lo        ; 0dad 66

; Increment 16-bit BCD timer
	; timer.lo++
	LI   $01 + BCD_ADJUST    ; 0dae 20 67
	ASD  (IS)                ; 0db0 dc
	LR   (IS)-,A             ; 0db1 5e
	BNC   .setTimerPos       ; 0db2 92 12
	; if carry, timer.hi++
	LI   $01 + BCD_ADJUST    ; 0db4 20 67
	ASD  (IS)                ; 0db6 dc
	LR   (IS)+,A             ; 0db7 5d
	
; Check if the explosion flag should be set
	; Check if hundreds digit is zero
	NI   DIGIT_MASK          ; 0db8 21 0f
	BNZ  .setTimerPos        ; 0dba 94 0a
	; If so, check if tens and ones digits are zero
	CLR                      ; 0dbc 70
	AS   (IS)                ; 0dbd cc
	BNZ  .setTimerPos        ; 0dbe 94 06
	; If so, set the explosion flag
	SETISAR explosionFlag    ; 0dc0 67 6a
	LI   MASK_EXPLODE        ; 0dc2 20 80
	LR   (IS),A              ; 0dc4 5c

; Handle Drawing of the timer
.setTimerPos:
	; Check if 1 or 2 player
	SETISAR gameMode         ; 0dc5 67 6d
	LIS  MODE_2P_MASK        ; 0dc7 71
	NS   (IS)                ; 0dc8 fc
	; Display in middle if 2 player mode
	LI   TIMER_X_CENTER      ; 0dc9 20 39
	BNZ  .drawTimer          ; 0dcb 94 03
	; Display to left if 1 player mode
	LI   TIMER_X_LEFT        ; 0dcd 20 1f
.drawTimer:          
	LR   drawTimer.xpos, A   ; 0dcf 50
	; Set color (drawTimer adds the ypos)
	LI   RED                 ; 0dd0 20 80
	LR   drawTimer.ypos, A   ; 0dd2 52
	; Set ISAR to LSB of score
	SETISAR timer.lo         ; 0dd3 66 6f
	PI   drawTimer           ; 0dd5 28 0a 20

; Perform the delay (to keep the game speed consistent)
	; delayByTable(delayIndex)
	SETISAR delayIndex       ; 0dd8 65 6f
	LR   A,(IS)              ; 0dda 4c
	LR   delay.index, A      ; 0ddb 50
	PI   delayByTable        ; 0ddc 28 09 86

; Check if a new ball needs to be spawned
	; curBall = balls.count
	SETISAR balls.count      ; 0ddf 65 6e
	LI   %00001111           ; 0de1 20 0f
	NS   (IS)+               ; 0de3 fd
	LR   main.curBall, A     ; 0de4 5b
	
	; ISAR is delayIndex here
	; Check if curBall >= delayIndex
	LR   A,(IS)              ; 0de5 4c
	COM                      ; 0de6 18
	INC                      ; 0de7 1f
	AS   main.curBall        ; 0de8 cb
	; if so, branch ahead
	BP   .ballLoopInit       ; 0de9 81 0d
	; if not, spawn a new ball

	; curBall = delayIndex
	LR   A,(IS)              ; 0deb 4c
	LR   main.curBall, A     ; 0dec 5b

	; Spawn new ball
	PI   spawnBall           ; 0ded 28 09 c2
	
	; balls.count = delayIndex (preserve upper nybble of ball count)
	SETISAR balls.count      ; 0df0 65 6e
	LI   %11110000           ; 0df2 20 f0
	NS   (IS)+               ; 0df4 fd
	AS   (IS)-               ; 0df5 ce
	LR   (IS),A              ; 0df6 5c

; Handle enemy balls
.ballLoopInit:
	SETISAR balls.count      ; 0df7 65 6e
	LI   %00001111           ; 0df9 20 0f
	NS   (IS)                ; 0dfb fc
	LR   main.curBall, A     ; 0dfc 5b
				
.ballLoop:          
	; doBall.size = enemy ball size
	SETISAR doBall.size      ; 0dfd 67 68
	LI   MASK_ENEMY_SIZE     ; 0dff 20 30
	NS   main.gameSettings   ; 0e01 fa
	SR   4                   ; 0e02 14
	LR   (IS)+,A             ; 0e03 5d
	
	; doBall.speed = enemy speed 
	LI   MASK_ENEMY_SPEED    ; 0e04 20 03
	NS   main.gameSettings   ; 0e06 fa
	LR   (IS),A              ; 0e07 5c

	PI   doBall              ; 0e08 28 0a 53
	PI   collision           ; 0e0b 28 0b 6e
	
	; if we're not dealing with a player ball, then move on to the next ball
	DS   main.curBall        ; 0e0e 3b
	LR   A,main.curBall      ; 0e0f 4b
	CI   [MAX_PLAYERS-1]     ; 0e10 25 01
	BNC   .ballLoop          ; 0e12 92 ea

; Handle player balls
	PI   doPlayers           ; 0e14 28 09 24

	; doBall.size = player ball size
	SETISAR doBall.size      ; 0e17 67 68
	LI   MASK_PLAYER_SIZE    ; 0e19 20 c0
	NS   main.gameSettings   ; 0e1b fa
	SR   4                   ; 0e1c 14
	SR   1                   ; 0e1d 12
	SR   1                   ; 0e1e 12
	LR   (IS)+,A             ; 0e1f 5d
	
	; doBall.size = player speed
	LI   MASK_PLAYER_SPEED   ; 0e20 20 0c
	NS   main.gameSettings   ; 0e22 fa
	SR   1                   ; 0e23 12
	SR   1                   ; 0e24 12
	LR   (IS),A              ; 0e25 5c
	
	; Handle player 1
	LI   0                   ; 0e26 20 00
	LR   main.curBall,A      ; 0e28 5b
	PI   doBall              ; 0e29 28 0a 53
	
	; Check if were doing 2 player mode
	SETISAR gameMode         ; 0e2c 67 6d
	LIS  1                   ; 0e2e 71
	NS   (IS)                ; 0e2f fc
	BZ   .checkExplosion     ; 0e30 84 05	
	; If so handle player 2
	LR   main.curBall,A      ; 0e32 5b
	PI   doBall              ; 0e33 28 0a 53

; Deal with the explosion
.checkExplosion:
	; Loop back to beginning if explosion flag isn't set
	SETISAR explosionFlag    ; 0e36 67 6a
	CLR                      ; 0e38 70
	AS   (IS)                ; 0e39 cc
	BP   .endMain            ; 0e3a 81 06
	
	; Clear explosion flag, and then explode
	CLR                      ; 0e3c 70
	LR   (IS),A              ; 0e3d 5c
	JMP  explode             ; 0e3e 29 0f 6b

.endMain:
	JMP  mainLoop            ; 0e41 29 0d a0
; end of mainLoop()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; gameOver()
;  Top-Level Procedure
;
; collision() jumps to here if the player comes in contact with an enemy ball
;
; This procedure draws the fancy multicolored spiral effect, and then branches
;  to two different paths depending whether we're in 1 or 2 player mode.
;
; In 1 player mode, the game checks the if the timer was better than the
;  player's previous high score, and replaces the score if applicable.
;
; In 2 player mode, the game add's the value of the timer to the surviving
;  player's high score (which makes it more of a running total, really).
;
; This procedure jumps back to either shuffleGame() or restartGame() depending
;  on whether the controller is pushed in.

gameOver: subroutine
; Make the multicolored spiral death effect
.Y_CENTER = $24
.MAX_RADIUS = $14

	; ypos = $24, color = $80
	LI   RED | .Y_CENTER     ; 0e44 20 a4
	LR   draw.ypos, A        ; 0e46 52
	; spiralRadius = $14
	SETISAR spiral.radius    ; 0e47 64 6e
	LI   .MAX_RADIUS         ; 0e49 20 14
	LR   (IS),A              ; 0e4b 5c

.spiralLoop:
	PI   drawSpiral          ; 0e4c 28 0f 0a
	; spiralRadius--
	SETISAR spiral.radius ; 0e4f 64 6e
	DS   (IS)                ; 0e51 3c
	; save flags
	LR   J,W                 ; 0e52 1e
	; color++
	; if(color == 0)
	;  color++
	; ypos = $24
	LR   A, draw.ypos        ; 0e53 42
	AI   $40                 ; 0e54 24 40
	BNC  .setColor           ; 0e56 92 03
	AI   $40                 ; 0e58 24 40
.setColor:
	NI   MASK_COLOR          ; 0e5a 21 c0
	AI   .Y_CENTER           ; 0e5c 24 24
	LR   draw.ypos,A         ; 0e5e 52
	; restore flags
	; loop back if o46 != 0
	LR   W,J                 ; 0e5f 1d
	BNZ  .spiralLoop         ; 0e60 94 eb

; Wait a bit before clearing the spiral effect
	; delayVariable($0)
	CLR                      ; 0e62 70
	LR   delay.count, A      ; 0e63 50
	PI   delayVariable       ; 0e64 28 09 9a

; Clear the spiral
	; Set color depending on who died
	; 1P mode - Red
	SETISAR gameMode         ; 0e67 67 6d
	LIS  MODE_2P_MASK        ; 0e69 71
	NS   (IS)                ; 0e6a fc
	LI   RED                 ; 0e6b 20 80
	BZ   .clearSpiral        ; 0e6d 84 0a
	; 2P mode, P1 - Green
	SETISARL testBall        ; 0e6f 69
	LIS  $1                  ; 0e70 71
	NS   (IS)                ; 0e71 fc
	LI   GREEN               ; 0e72 20 c0
	BZ   .clearSpiral        ; 0e74 84 03
	; 2P mode, P2 - Blue
	LI   BLUE                ; 0e76 20 40
.clearSpiral:
	; Set ypos
	AI   .Y_CENTER           ; 0e78 24 24
	LR   draw.ypos,A         ; 0e7a 52

	; Draw spiral
	SETISAR spiral.radius    ; 0e7b 64 6e
	LI   .MAX_RADIUS         ; 0e7d 20 14
	LR   (IS),A              ; 0e7f 5c
	PI   drawSpiral          ; 0e80 28 0f 0a

; Delay a bit to allow the players time before input is polled later
	; Delay
	LI   $28                 ; 0e83 20 28
	LR   delay.count,A       ; 0e85 50
	PI   delayVariable       ; 0e86 28 09 9a

; Branch depending on whether this is 1 or 2 player mode
	; Check if two players
	SETISAR gameMode         ; 0e89 67 6d
	LIS  MODE_2P_MASK        ; 0e8b 71
	NS   (IS)                ; 0e8c fc
	; If so, jump ahead
	BNZ  .2Pcleanup          ; 0e8d 94 38

; -- Game over cleanup - 1 player mode -----------------------------------------
.tempTimerHi = $6
.tempTimerLo = $7

; Check if a new high score was set
	; tempTimer = timer
	SETISAR timer.hi         ; 0e8f 66 6e
	LR   A,(IS)+             ; 0e91 4d
	LR   .tempTimerHi,A      ; 0e92 56
	LR   A,(IS)              ; 0e93 4c
	LR   .tempTimerLo,A      ; 0e94 57

	; tempTimer.hi - hiScore.p1.hi
	SETISAR hiScore.p1.hi    ; 0e95 65 6c
	LR   A,(IS)+             ; 0e97 4d
	COM                      ; 0e98 18
	INC                      ; 0e99 1f
	AS   .tempTimerHi        ; 0e9a c6
	; if(tempTimer.hi < hiScore.p1.hi), we do not have a new high score
	BM   .delayP1            ; 0e9b 91 16
	; if(tempTimer.hi != hiScore.p1.hi), we have a new high score
	BNZ  .newHighScore       ; 0e9d 94 07
	
	; tempTimer.lo - hiScore.lo
	LR   A,(IS)              ; 0e9f 4c
	COM                      ; 0ea0 18
	INC                      ; 0ea1 1f
	AS   .tempTimerLo        ; 0ea2 c7
	; if(tempTimer.lo < hiScore.p1.lo), we do not have a new high score
	BM   .delayP1            ; 0ea3 91 0e
	; else, we have a new high score

; Draw the new high score
.newHighScore:
	; hiScore = tempTimer
	LR   A,.tempTimerLo      ; 0ea5 47
	LR   (IS)-,A             ; 0ea6 5e
	LR   A,.tempTimerHi      ; 0ea7 46
	LR   (IS)+,A             ; 0ea8 5d
	; Set color
	LI   BLUE                ; 0ea9 20 40
	LR   drawTimer.ypos, A   ; 0eab 52
	; Set xpos
	LI   TIMER_X_RIGHT       ; 0eac 20 54
	LR   drawTimer.xpos, A   ; 0eae 50

	PI   drawTimer           ; 0eaf 28 0a 20

; Delay to give player time to push the controller
.delayP1:
	LI   $40                 ; 0eb2 20 40
	LR   delay.count, A      ; 0eb4 50
	PI   delayVariable       ; 0eb5 28 09 9a

	; Read controllers
	PI   readInput           ; 0eb8 28 09 10

	; If controller is not pushed in, shuffle the gametype
	SETISARL input.p1        ; 0ebb 68
	CLR                      ; 0ebc 70
	AS   (IS)                ; 0ebd cc
	BM   .gotoShuffle        ; 0ebe 91 04

	; Else, keep the gametype and restart the game
	JMP  restartGame         ; 0ec0 29 0d 54
; -- End of 1 player case ------------------------------------------------------

.gotoShuffle:
	JMP  shuffleGame         ; 0ec3 29 0d 18

; -- Game over cleanup - 2 player mode -----------------------------------------
.2Pcleanup:
; Check who gets the timer added to their score
	; tempTimer = timer
	SETISAR timer.hi         ; 0ec6 66 6e
	LR   A,(IS)+             ; 0ec8 4d
	LR   .tempTimerHi,A      ; 0ec9 56
	LR   A,(IS)              ; 0eca 4c
	LR   .tempTimerLo,A      ; 0ecb 57
	
	; Check who died
	SETISAR testBall         ; 0ecc 67 69
	LIS  $1                  ; 0ece 71
	NS   (IS)                ; 0ecf fc
	BNZ  .P1survived         ; 0ed0 94 0b

; Set drawTimer parameters for player 2
	; Set color
	LI   GREEN               ; 0ed2 20 c0
	LR   drawTimer.ypos,A    ; 0ed4 52
	; set xpos
	LI   TIMER_X_RIGHT       ; 0ed5 20 54
	LR   drawTimer.xpos,A    ; 0ed7 50
	; Set ISAR
	SETISAR hiScore.p2.lo    ; 0ed8 67 6c
	BR   .addHiScore         ; 0eda 90 09

; Set drawTimer parameters for player 1
.P1survived:
	; Set ISAR
	SETISAR hiScore.p1.lo    ; 0edc 65 6d
	; Set color
	LI   BLUE                ; 0ede 20 40
	LR   drawTimer.ypos,A    ; 0ee0 52
	; Set xpos
	LI   TIMER_X_LEFT        ; 0ee1 20 1f
	LR   drawTimer.xpos,A    ; 0ee3 50

; Add the current timer to the winning player's high score
.addHiScore:
	; hiScore.lo += tempTimer.lo
	LR   A,.tempTimerLo      ; 0ee4 47
	AS   (IS)                ; 0ee5 cc
	LR   (IS),A              ; 0ee6 5c
	; Add zero in BCD to adjust score and check carry flag
	LI   0 + BCD_ADJUST      ; 0ee7 20 66
	ASD  (IS)                ; 0ee9 dc
	LR   (IS)-,A             ; 0eea 5e
	BNC   .addHiScoreHiByte  ; 0eeb 92 05
	; Carry
	LI   1 + BCD_ADJUST      ; 0eed 20 67
	ASD  (IS)                ; 0eef dc
	LR   (IS),A              ; 0ef0 5c

.addHiScoreHiByte:
	; hiScore.hi += tempTimer.hi
	LR   A,(IS)              ; 0ef1 4c
	AS   .tempTimerHi        ; 0ef2 c6
	LR   (IS),A              ; 0ef3 5c
	; Add zero in BCD to adjust score
	LI   0 + BCD_ADJUST      ; 0ef4 20 66
	ASD  (IS)                ; 0ef6 dc
	LR   (IS)+,A             ; 0ef7 5d

	PI   drawTimer           ; 0ef8 28 0a 20

; There is no delay here, unlike in 1 player mode!

	; Read controllers
	PI   readInput           ; 0efb 28 09 10

	; If neither player is pushing the controller, shuffle gametype
	; Player 1
	SETISARL input.p1        ; 0efe 68
	CLR                      ; 0eff 70
	AS   (IS)+               ; 0f00 cd
	BM   .gotoShuffle        ; 0f01 91 c1

	; Player 2
	CLR                      ; 0f03 70
	AS   (IS)                ; 0f04 cc
	BM   .gotoShuffle        ; 0f05 91 bd

	; Else, just restart the current game
	JMP  restartGame         ; 0f07 29 0d 54
; -- End of 2 player case ------------------------------------------------------

; end of gameOver()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; drawSpiral()
;  Mid-Level Function
; 
; Draws a single-colored square by going in a nice clockwise spiral pattern 
;  starting from the center, like so:
;
;   .-· · ·
;   | .- - - - - -.
;   | | .- - - -. |
;   | | | .- -. | |
;   | | | |.. | | |
;   | | | | | | | |
;   | | | '-' | | |
;   | | '- - -' | |
;   | '- - - - -' |
;   '- - - - - - -'
;
; This function clobbers memory locations otherwise held by the ball arrays,
;  meaning that it cannot be used during the main loop.

; == Arguments ==
spiral.radius = 046
;.ypos = 2

drawSpiral: subroutine
	LR   K,P                 ; 0f0a 08

; == Locals ==
; Note: These take the place of variables used while the game is being played!
; Note 2: The reason these registers don't use the dot notation like other
;  locals (eg. ".temp") is because that doesn't work with the SETISAR macros
;  because of how DASM handles namespaces.
spiral.hdiameter = 024 ; o24 - horizontal diameter
spiral.hcount = 025    ; o25 - horizontal counter
spiral.vcount = 026    ; o26 - vertical counter
spiral.vdiameter = 027 ; o27 - vertical diameter
spiral.lapCount = 036  ; o36 - spiral lap counter

.X_CENTER = $34

; Initialize things before the big loop
	; Set properties to draw a rect
	LI   DRAW_RECT           ; 0f0b 20 80
	LR   draw.param, A       ; 0f0d 50
	; Set xpos
	LI   .X_CENTER           ; 0f0e 20 34
	LR   draw.xpos, A        ; 0f10 51
	; Note: ypos is set before entering this function

	SETISAR spiral.hdiameter ; 0f11 62 6c

	; Set width/height to 1
	LIS  $1                  ; 0f13 71
	LR   draw.width, A       ; 0f14 54
	LR   draw.height, A      ; 0f15 55

	; Set all spiral counters to 1
	; .hdiameter
	LR   (IS)+,A             ; 0f16 5d
	; .hcount
	LR   (IS)+,A             ; 0f17 5d
	; .vcount
	LR   (IS)+,A             ; 0f18 5d
	; .vdiameter
	LR   (IS)-,A             ; 0f19 5e

	; spiral.lapCount = spiral.radius
	SETISARU spiral.radius   ; 0f1a 64
	LR   A,(IS)              ; 0f1b 4c
	SETISARU spiral.lapCount ; 0f1c 63
	LR   (IS),A              ; 0f1d 5c

	; Set ISAR
	SETISARU spiral.vcount   ; 0f1e 62

; Dummy arithmetic operation
	LIS  $1                  ; 0f1f 71
	SL   1                   ; 0f20 13
	; Save the flags from that operation to prevent the "LR W,J" a few lines
	;  down from causing the function to erroneously return early
	LR   J,W                 ; 0f21 1e

	; Draw the center point
	PI   drawBox             ; 0f22 28 08 62

; Start of the big loop, which contains 4 small loops for each direction
.startLap:
.plotUp:
	; ypos--
	DS   draw.ypos           ; 0f25 32
	PI   drawBox             ; 0f26 28 08 62
	; .vcount--
	DS   (IS)                ; 0f29 3c
	; loop until .vcount reaches 0
	BNZ  .plotUp             ; 0f2a 94 fa

	; if (.lapCount == 0) return
	LR   W,J                 ; 0f2c 1d    ; restore flags
	BZ   .exit               ; 0f2d 84 3b

; Prep for .plotDown
	; .vdiameter++
	LR   A,(IS)+             ; 0f2f 4d
	LR   A,(IS)              ; 0f30 4c
	INC                      ; 0f31 1f
	LR   (IS)-,A             ; 0f32 5e
	; .vcount = .vdiameter
	LR   (IS)-,A             ; 0f33 5e

.plotRight:
	; xpos++
	LR   A, draw.xpos        ; 0f34 41
	INC                      ; 0f35 1f
	LR   draw.xpos, A        ; 0f36 51
	
	PI   drawBox             ; 0f37 28 08 62
	; .hcount--
	DS   (IS)                ; 0f3a 3c
	; loop until hcount reaches 0
	BNZ  .plotRight          ; 0f3b 94 f8
	
; Clear sound
	CLR                      ; 0f3d 70
	OUTS 5                   ; 0f3e b5

; Prep for .plotLeft
	; .hdiameter++
	LR   A,(IS)-             ; 0f3f 4e
	LR   A,(IS)              ; 0f40 4c
	INC                      ; 0f41 1f
	LR   (IS)+,A             ; 0f42 5d
	; .hcount = .hdiameter
	LR   (IS)+,A             ; 0f43 5d

.plotDown:
	; ypos++
	LR   A, draw.ypos        ; 0f44 42
	INC                      ; 0f45 1f
	LR   draw.ypos, A        ; 0f46 52
	PI   drawBox             ; 0f47 28 08 62
	; vcount-- (o26)
	DS   (IS)                ; 0f4a 3c
	BNZ  .plotDown           ; 0f4b 94 f8

; Prep for .plotUp
	; .vdiameter++
	LR   A,(IS)+             ; 0f4d 4d
	LR   A,(IS)              ; 0f4e 4c
	INC                      ; 0f4f 1f
	LR   (IS)-,A             ; 0f50 5e
	; .vcount = .vdiameter
	LR   (IS)-,A             ; 0f51 5e

.plotLeft:
	; xpos--
	DS   draw.xpos           ; 0f52 31
	PI   drawBox             ; 0f53 28 08 62
	; .hcount--
	DS   (IS)                ; 0f56 3c
	BNZ  .plotLeft           ; 0f57 94 fa

; Prep for .plotRight
	; .hdiameter++
	LR   A,(IS)-             ; 0f59 4e
	LR   A,(IS)              ; 0f5a 4c
	INC                      ; 0f5b 1f
	LR   (IS)+,A             ; 0f5c 5d
	; .hcount = .hdiameter
	LR   (IS)+,A             ; 0f5d 5d

; Prep for next loop
	; .lapCount--
	SETISARU spiral.lapCount ; 0f5e 63
	DS   (IS)                ; 0f5f 3c
	; Reset ISAR
	SETISARU spiral.vcount   ; 0f60 62
	; save flags (to be used above shortly after .plotUp)
	LR   J,W                 ; 0f61 1e
				
; Play sound
	LR   A,$2                ; 0f62 42
	OUTS 5                   ; 0f63 b5
	
	; Start new lap if(.lapCount != 0)
	BNZ  .startLap           ; 0f64 94 c0
	
; Adjust .vcount for the last .plotUp so we make a clean sqaure
	; .vcount--
	DS   (IS)                ; 0f66 3c
	; Note: This lap will only do .plotUp before exiting
	BR   .startLap           ; 0f67 90 bd

.exit:
	LR   P,K                 ; 0f69 09
	POP                      ; 0f6a 1c
; end drawSpiral()
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; explode()
;  Top-level procedure
;
; Move the balls to the center to "explode". This procedure is executed
;  every 1000 points.
;
; Accessed from the end of the main loop, and returns to the beginning of the
;  main loop.
;
; No input arguments

; == Entry Point ==
explode: subroutine

; == Local Regs ==
.loopCount = $0

; == Local Constants ==
.NUM_LOOPS = MAX_ENEMIES
.X_CENTER = $30
.Y_CENTER = $22

; == Start ==
; Prepare for loop to set x positions
	; ISAR = balls.xpos + MAX_PLAYERS
	LIS  MAX_PLAYERS         ; 0f6b 72
	AI   balls.xpos          ; 0f6c 24 10
	LR   IS,A                ; 0f6e 0b
	; .loopCount = .NUM_LOOPS
	LIS  .NUM_LOOPS          ; 0f6f 79
	LR   .loopCount,A        ; 0f70 50
; Set xpos of all enemy balls
.xLoop:
	; Set xpos while preserving the x direction
	LI   MASK_DIRECTION      ; 0f71 20 80
	NS   (IS)                ; 0f73 fc
	AI   .X_CENTER           ; 0f74 24 30
	LR   (IS),A              ; 0f76 5c
	; ISAR++ (NOTE: ISAR post-increment would only affect the lower octal digit)
	LR   A,IS                ; 0f77 0a
	INC                      ; 0f78 1f
	LR   IS,A                ; 0f79 0b
	; .loopCount--, loop back if not zero
	DS   .loopCount          ; 0f7a 30
	BNZ  .xLoop              ; 0f7b 94 f5

; Prepare for loop to set y positions
	; ISAR = balls.ypos + MAX_PLAYERS
	LR   A,IS                ; 0f7d 0a
	AI   MAX_PLAYERS         ; 0f7e 24 02
	LR   IS,A                ; 0f80 0b
	; .loopCount = .NUM_LOOPS
	LIS  .NUM_LOOPS          ; 0f81 79
	LR   .loopCount,A        ; 0f82 50
; Set ypos of all enemy balls
.yLoop:
	; Set ypos while preserving the y direction
	LI   MASK_DIRECTION      ; 0f83 20 80
	NS   (IS)                ; 0f85 fc
	AI   .Y_CENTER           ; 0f86 24 22
	LR   (IS),A              ; 0f88 5c
	; ISAR++
	LR   A,IS                ; 0f89 0a
	INC                      ; 0f8a 1f
	LR   IS,A                ; 0f8b 0b
	; .loopCount, loop back if not
	DS   .loopCount          ; 0f8c 30
	BNZ  .yLoop              ; 0f8d 94 f5

	; (ISAR) = gameSettings, ISAR++, (ISAR) = gameSettings
	; TODO: Why are we overwriting the speeds of the player balls and the first two enemies?
	LR   A,main.gameSettings ; 0f8f 4a ; is=046
	LR   (IS)+,A             ; 0f90 5d ; is=046
	LR   (IS)+,A             ; 0f91 5d ; is=047

	; Clear MODE_BOUNCE_MASK from gameMode
	SETISAR gameMode         ; 0f92 67 6d
	LR   A,(IS)              ; 0f94 4c
	SL   1                   ; 0f95 13
	SR   1                   ; 0f96 12
	LR   (IS),A              ; 0f97 5c

	; Exit
	JMP  mainLoop               ; 0f98 29 0d a0
; end explode()
;-------------------------------------------------------------------------------
	
	; Unused byte
	db $b2
	; This byte mirrors the $2b (NOP) in this cart's header.
	; Coincidence or creative whimsy?

	; Free space - 94 bytes!
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
	db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff

; EoF