• Contact
  • Journal
  • Home
  • CoCo
  • Doubleback
  • Code
  • Site
  • Page
  • Amiga
    • Rainbow Islands
      • 1loader-dec
      • 1loader
      • boot
      • orig-boot
      • Journal
  • Arcade
    • Asteroids 80%
      • Hardware
      • RAMUse
      • Code

      • DVG
      • VectorROM

      • Journal
    • Crazy Climber 1%
      • BigSpriteGraphics.pdf
      • Buildings.pdf
      • cclimber.asm
      • CharEnc.inc
      • CrazyClimberMemoryMapInfo.pdf
      • GraphicsAndCharacterAssetInfo.pdf
      • MemoryMap.inc
    • Defender 75%
      • RAMUse
      • Hardware
      • Bank1
      • Bank2
      • Bank3
      • Bank7
      • BankFixed
      • Mapping.txt
      • SoundHardware
      • SoundRAMUse
      • SoundCode
      • Defender-Theory-Early.pdf
      • Defender-Theory-Later.pdf
      • Defender.CPU.jpg
      • Defender.ROM.B&W.jpg
      • Defender.Vid.B&W.jpg
      • SoundROM.txt
    • Frogger (Sound)
      • SoundHardware
      • SoundRAMUse
      • SoundCode

      • Hardware
      • RAMUse
      • Code

      • GFX

      • Journal
    • Galaga 5%
      • CPU1 (Main)
      • CPU2 (Secondary)
      • CPU3 (Sound)
      • GFX1 (Characters)
      • GFX2 (Sprites)
      • PROMcolors
      • PROMpaletteChar
      • PROMpaletteSprite

      • CPU1Fix

      • Journal
    • Moon Patrol 75%
      • Hardware
      • RAMUse
      • Code

      • GFX1 (Text)
      • GFX2 (Sprites)
      • GFX3 (Mountains)
      • GFX4 (Hills)
      • GFX5 (City)
      • ImageBackgroundColors
      • SpriteColors
      • SpriteColorSets
      • TextColors

      • MoonPatrolSound
      • SoundHardware
      • SoundRAMUse
      • SoundCode

      • Journal
    • Omega Race 10%
      • Hardware
      • RAMUse
      • MainBoard

      • SoundHardware
      • SoundRAMUse
      • SoundBoard

      • DVGPROM
      • VectorROM

      • Journal
    • Phoenix 35%
      • Hardware
      • RAMUse
      • Code

      • Background
      • Foreground

      • Journal

      • Scramble HHi
        • phoenixj-func-main2.pdf
        • phoenixj-func-main2.scap
        • phoenixj.asm-may2025.txt
        • phoenixj.asm-may2025.txt.pdf
    • Space Invaders
      • Hardware
      • RAMUse
      • Code

      • Journal
    • Time Pilot (Sound)
      • SoundHardware
      • SoundRAMUse
      • SoundCode

      • Hardware
      • RAMUse
      • Code

      • Journal
    • Sea Wolf 1%
      • Hardware
      • RAMUse
      • Code

      • Journal
    • Scramble 1%
      • SoundHardware
      • SoundRAMUse
      • SoundCode

      • Journal
  • Atari2600
    • Stella (Hardware Info)
    • Asteroids 5%
      • RAMUse
      • Code

      • Journal
    • Battle Zone 1%
      • RAMUse
      • Code

      • Journal
    • Chess 1%
      • RAMUse
      • Code

      • Journal
    • Combat 10%
      • RAMUse
      • Code
      • CodePAL

      • Journal
    • Double Gap
      • Code
      • DoubleGap.asm

      • Journal
    • Entombed 1%
      • RAMUse
      • Code

      • Journal
    • ET 1%
      • RAMUse
      • Code

      • Journal
    • Burger Time 1%
      • RAMUse
      • CodeBank0
      • CodeBank1
      • CodeBank2
      • CodeBank3
      • CodeBank4
      • CodeBank5
      • CodeBank6
      • CodeBank7

      • Journal
    • Missile Command 1%
      • RAMUse
      • Code

      • Journal
    • Space Invaders 1%
      • RAMUse
      • Code

      • Journal
  • CoCo
    • Hardware
    • Early Work
    • Pyramid
      • RAMUse
      • Code

      • Journal
    • Raaka Tu
      • RAMUse
      • Code

      • Journal
    • Bedlam
      • RAMUse
      • Code

      • Journal
    • Madness & Minotaur
      • Walk Through
        • after_start.txt
        • after_start.cas
        • after_1.txt
        • after_1.cas
        • after_2.txt
        • after_2.cas
        • after_3.txt
        • after_3.cas
        • after_4.txt
        • after_4.cas
        • after_5.txt
        • after_5.cas
        • after_6.txt
        • after_6.cas
        • after_7.txt
        • after_7.cas
        • after_8.txt
        • after_8.cas
        • after_9.txt
        • after_9.cas
        • after_10.txt
        • after_10.cas
        • after_11.txt
        • after_11.cas
        • after_12.txt
        • after_12.cas
        • after_13.txt
        • after_13.cas
        • after_14.txt
        • after_14.cas
        • after_15.txt
        • after_15.cas
        • after_16.txt
        • after_16.cas
        • after_17.txt
        • after_17.cas
        • after_18.txt
        • after_18.cas
        • after_19.txt
        • after_19.cas
        • after_20.txt
        • after_20.cas
        • after_21.txt
        • after_21.cas
        • after_22.txt
        • after_22.cas
        • after_23.txt
        • after_23.cas
        • after_24.txt
        • after_24.cas
        • after_25.txt
        • after_25.cas
      • RAMUse
      • Code

      • SaveGameViewer

      • Journal
    • Mega-Bug
      • RAMUse
      • Code

      • Journal
    • Daggorath
      • RAMUse
      • Code

      • Level Maps

      • Journal
    • Downland 5%
      • RAMUse
      • Code

      • Journal
    • Audio Analyzer 5%
      • RAMUse
      • Code

      • Journal
    • Doubleback
      • RAMUse
      • Code

      • Journal
  • NES
    • Zelda 5%
      • Hardware
      • RAMUse
      • Bank0
      • Bank1
      • Bank2
      • Bank3
      • Bank4
      • Bank5
      • Bank6
      • Bank7

      • Journal
    • Kid Icarus 1%
      • Hardware
      • RAMUse
      • Bank0
      • Bank1
      • Bank2
      • Bank3
      • Bank4
      • Bank5
      • Bank6
      • Bank7

      • Journal
  • Gameboy
    • Hardware
    • Link's Awakening 1%
      • RAMUse
      • Bank00
      • Bank01
      • Bank02
      • Bank03
      • Bank04
      • Bank05
      • Bank06
      • Bank07
      • Bank08
      • Bank09
      • Bank0A
      • Bank0B
      • Bank0C
      • Bank0D
      • Bank0E
      • Bank0F
      • Bank10
      • Bank11
      • Bank12
      • Bank13
      • Bank14
      • Bank15
      • Bank16
      • Bank17
      • Bank18
      • Bank19
      • Bank1A
      • Bank1B
      • Bank1C
      • Bank1D
      • Bank1E
      • Bank1F

      • Journal
    • Tetris 1%
      • RAMUse
      • Code

      • Journal
  • TRS80
    • Hardware
    • HauntedHouse
      • RAMUse1
      • Code1
      • RAMUse2
      • Code2

      • Journal
    • Pyramid
      • RAMUse
      • Code

      • RAMUse1
      • Code1

      • Journal
    • RaakaTu
      • RAMUse
      • Code

      • Journal
    • Bedlam
      • RAMUse
      • Code

      • Journal
  • Virus
    • Morris Worm 1%
      • Journal
    • Stoned
      • Journal

  • Tools
    • Blend
      • blend.zip

      • Journal
  • Doubleback
  • The Mask Table
  • Cursive Doubleback
  • Game Loop
  • Play One Round
  • One Cycle
    • Move Game Objects
    • Read the Player's Input
    • Looped Object Detection
    • Update the Player's Line
    • Make new Game Object
  • The Unexpected
  • Print Scores
  • Draw Number
  • Digit Graphics
  • Draw and Erase the Loop Score
  • Erase a Number
  • Draw and Erase an 8x8 Pixel Object
  • Print a Sequence of Characters
  • Set and Clear Pixel
  • Get Screen Pointer and Pixel Number
  • Move an Object by its DeltaX and DeltaY
  • Follow the Player
  • Play Song
  • Data From Here Down
    • Game Objects
    • Text Areas
    • The Cursive Doubleback Text
  • Songs

Doubleback

RAM Usage

Hardware Info

C000: 0F BB           CLR     highScore           ; First RESET comes here. Clear ...
C002: 0F BC           CLR     highScore+1         ; ... high-score
;
Reset:
; After the first boot, the RESET handler is modified to come here. This is also
; where the BREAK key jumps to. (Maybe BREAK should skip rebuilding the mask table
; and jump to C031).
C004: 12              NOP                         ; Required by BASIC ROM RESET handler
C005: 1A 50           ORCC    #$50                ; Disable IRQ
C007: 10 CE 01 50     LDS     #$0150              ; Stack
C00B: 30 8C F6        LEAX    Reset,PC            ; RESET button ...
C00E: 9F 72           STX     $72                 ; ... now comes to C004

The Mask Table

There are 4 pixels per memory byte: aa_bb_cc_dd

The value 00 is considered transparent. When an image is blitted to the screen, any pixels with value 00 are left unchanged at the destination. In order to set the non-zero bits, a mask is needed to zero-out the pixels at the destination. The pixel mask value is 11 for pixel value 00 and 00 for any other pixel value.

For instance: 00_01_10_00 has two visible pixels in the middle and two transparents on the ends

The mask: 11_00_00_11 this would AND out any 1s at the destination allowing the new value to be ORed into the destination

Building the mask on the fly is tedious (costly in time). Instead, the code builds a 256-value lookup table to get the mask from the pixel pattern. TABLE[$18] = $C3 for the example above.

; Build the bit mask table from 0380 to 0390
C010: 8E 03 80        LDX     #$0380              ; Start of mask table
C013: 5F              CLRB                        ; Start with ...
C014: 34 04           PSHS    B                   ; ... entry 0
C016: A6 E4           LDA     ,S                  ; Table entry index
C018: E6 E4           LDB     ,S                  ; Table entry value
C01A: C4 AA           ANDB    #$AA                ; Keep the upper bit of each pixel
C01C: 54              LSRB                        ; Copy to lower bit of each pixel
C01D: E7 86           STB     A,X                 ; Accumulate that
C01F: E6 E4           LDB     ,S                  ; Table entry value
C021: C4 55           ANDB    #$55                ; Keep the lower bit of each pixel
C023: 58              ASLB                        ; Copy to upper bit of each pixel
C024: EA 86           ORB     A,X                 ; Accumulate that
C026: EA E4           ORB     ,S                  ; OR in the original bits
C028: 53              COMB                        ; 1's to 0 for an AND mask
C029: E7 86           STB     A,X                 ; Store the entry
C02B: 6C E4           INC     ,S                  ; Do all ...
C02D: 26 E7           BNE     $C016               ; ... 256 entries
C02F: 35 04           PULS    B                   ; remove stack temporary
         
SplashScreen:
C031: 17 0A 1E        LBSR    ClearScreen         ; Clear the screen
C034: 17 0A 98        LBSR    SetVideoMode        ; Set the graphics mode
C037: CC 1C 46        LDD     #$1C46              ; Screen coordinates
C03A: 33 8D 0D 33     LEAU    StrCopyright1,PC    ; Print ...
C03E: 17 09 02        LBSR    PrintChars          ; ... copyright line 1
C041: CC 14 4E        LDD     #$144E              ; Screen coordinates
C044: 33 8D 0D 3A     LEAU    StrCopyright2,PC    ; Print ...
C048: 17 08 F8        LBSR    PrintChars          ; ... copyright line 2
C04B: CC 14 56        LDD     #$1456              ; Screen coordinates
C04E: 33 8D 0D D1     LEAU    StrCopyright3,PC    ; Print ...
C052: 17 08 EE        LBSR    PrintChars          ; ... copyright line 3

Cursive Doubleback

>> How is the cursive "doubleback" drawn on the screen?

The start screen has the word "doubleback" written in large cursive letters across the screen. The code also draws a reflected version (left/right and up/down) below the first.

The forward drawing begins at corrdinate (1F,18). The code uses a table of directions at CEC3 to move the drawing from pixel to pixel. Each entry in the table is a 3 bits specifying one of 8 directions (N,S,E,W,NE,SE,NW,SW).

There is an interactive demonstration of the cursive drawing below at CEC3.

; Cursive "doubleback"
C055: 8E 00 E4        LDX     #$00E4              ; Utility object structure
C058: 86 1F           LDA     #$1F                ; Set ...
C05A: A7 84           STA     ,X                  ; ... X coordinate
C05C: 86 18           LDA     #$18                ; Set ...
C05E: A7 02           STA     2,X                 ; ... Y coordinate
C060: 33 8D 0E 5F     LEAU    $CEC3,PC            ; Cursive "doubleback" data
C064: 34 04           PSHS    B                   ; Space on stack for counter
C066: C6 05           LDB     #$05                ; Each word has 3*5 = 15 data points
C068: E7 E4           STB     ,S                  ; Store the count
C06A: EC C1           LDD     ,U++                ; Get the next 5 data points
C06C: 27 42           BEQ     $C0B0               ; No more ... we are done
C06E: 34 06           PSHS    B,A                 ; Hold the data points
C070: C4 07           ANDB    #$07                ; Lower 3 bits
C072: 58              ASLB                        ; 2 bytes per
C073: 31 8D 0E B6     LEAY    DirTable,PC         ; Offset table
C077: EC A5           LDD     B,Y                 ; Get X and Y offsets
C079: AB 84           ADDA    ,X                  ; Add X offset
C07B: EB 02           ADDB    2,X                 ; Add Y offset
C07D: A7 84           STA     ,X                  ; Nex X position
C07F: E7 02           STB     2,X                 ; New Y position
C081: 40              NEGA                        ; Mirror ...
C082: 8B 80           ADDA    #$80                ; ... X ...
C084: A7 01           STA     1,X                 ; ... coordinate
C086: 50              NEGB                        ; Mirror ...
C087: CB 3C           ADDB    #$3C                ; ... Y ...
C089: E7 03           STB     3,X                 ; ... coordinate
C08B: 34 50           PSHS    U,X                 ; Hold data pointer and screen pointer
C08D: 17 08 CF        LBSR    SetPixel            ; Draw top pixel
C090: 30 01           LEAX    1,X                 ; Skip over to 2nd screen pointer
C092: 17 08 CA        LBSR    SetPixel            ; Draw bottom (reflected) pixel
C095: E6 84           LDB     ,X                  ; Is the X ...
C097: C4 01           ANDB    #$01                ; ... coordinate odd?
C099: 26 03           BNE     $C09E               ; No ... skip the pause
C09B: 17 0A 51        LBSR    WaitVBlank          ; Yes ... slight pause
C09E: 35 50           PULS    X,U                 ; Restore the data pointer and the screen pointer
C0A0: 35 06           PULS    A,B                 ; Pop the data points
C0A2: 6A E4           DEC     ,S                  ; All 5 datapoints done?
C0A4: 27 C0           BEQ     $C066               ; Yes ... reload next five
C0A6: 44              LSRA                        ; No ...
C0A7: 56              RORB                        ; ... shift ...
C0A8: 44              LSRA                        ; ... over ...
C0A9: 56              RORB                        ; ... next ...
C0AA: 44              LSRA                        ; ... data ...
C0AB: 56              RORB                        ; ... point
C0AC: 34 06           PSHS    B,A                 ; Hold current data
C0AE: 20 C0           BRA     $C070               ; Do next point
C0B0: 35 04           PULS    B                   ; Remove the stack counter

; Select 1 or 2 players
C0B2: CC 28 3A        LDD     #$283A              ; Print coordinates
C0B5: 33 8D 0C 57     LEAU    Str1or2Players,PC   ; Print ...
C0B9: 17 08 87        LBSR    PrintChars          ; ... "1 or 2 Players"
C0BC: AD 9F A0 0A     JSR     [JOYIN]             ; Read the joysticks
C0C0: 0F B4           CLR     numPlayers          ; Number of players = 1
C0C2: CE 0C 2A        LDU     #$0C2A              ; Screen coordinate for the underline for 1 or 2
C0C5: 6F C4           CLR     ,U                  ; Erase the 1 underline
C0C7: 6F 43           CLR     3,U                 ; Erase the 2 underline
C0C9: B6 01 5A        LDA     $015A               ; Player one X axis
C0CC: 81 1F           CMPA    #$1F                ; Left or right of middle?
C0CE: 2F 04           BLE     $C0D4               ; Left ...
C0D0: 0C B4           INC     numPlayers          ; Number of players = 1
C0D2: 33 43           LEAU    3,U                 ; U points to 2 underline
C0D4: 6A C4           DEC     ,U                  ; Underline the 1 or 2 with a white 4 pixels
C0D6: 17 0A 16        LBSR    WaitVBlank          ; Wait for VBLANKing
C0D9: F6 FF 00        LDB     PIA0_DA             ; Button ...
C0DC: C4 01           ANDB    #$01                ; ... pressed?
C0DE: 26 DC           BNE     $C0BC               ; No ... keep waiting

; Clear the scores and get ready for three rounds
C0E0: 0F B7           CLR     p1Score             ; Clear player ...
C0E2: 0F B8           CLR     p1Score+1           ; ... one score
C0E4: 0F B9           CLR     p2Score             ; Clear player ...
C0E6: 0F BA           CLR     p2Score+1           ; ... two score
C0E8: C6 03           LDB     #$03                ; Start with ...
C0EA: D7 B5           STB     numLives            ; ... three lives

Game Loop

This is the game's main loop. This code calls on the main game loop 3 times for each player. Once the game is over, this code updates the high score if needed. Finally, it prints "Game Over" and waits for a button before restarting way up at the splash screen code.

; All lives -- both players
C0EC: 0F B6           CLR     player              ; Player 0
C0EE: 17 00 3E        LBSR    PlayRound           ; Play one round for player 0
C0F1: 0D B4           TST     numPlayers          ; Two player game?
C0F3: 27 05           BEQ     $C0FA               ; No ... skip second player
C0F5: 0C B6           INC     player              ; Player 1
C0F7: 17 00 35        LBSR    PlayRound           ; Play one round for player 1
C0FA: 0A B5           DEC     numLives            ; Subtract one from lives
C0FC: 26 EE           BNE     $C0EC               ; Go back for all lives
;
; Update high scores
C0FE: DC B7           LDD     p1Score             ; Player 1 score
C100: 10 93 BB        CMPD    highScore           ; Beat the high score?
C103: 23 02           BLS     $C107               ; No ... move on
C105: DD BB           STD     highScore           ; Change the high score
C107: DC B9           LDD     p2Score             ; Player 2 score
C109: 10 93 BB        CMPD    highScore           ; Beat the high score?
C10C: 23 02           BLS     $C110               ; No ... move on
C10E: DD BB           STD     highScore           ; Change the high score
C110: DC BB           LDD     highScore           ; Print ...
C112: CE 04 EE        LDU     #$04EE              ; ... high score at top ...
C115: 17 05 13        LBSR    DrawNumber          ; ... of screen
;
; Print "Game Over" and wait for a button
C118: CC 2C 28        LDD     #$2C28              ; Print coordinates
C11B: 33 8D 0B A0     LEAU    StrGameOver,PC      ; Print ...
C11F: 17 08 21        LBSR    PrintChars          ; ... "Game Over"
C122: 17 09 9B        LBSR    CheckForBreak       ; Check for break
C125: F6 FF 00        LDB     PIA0_DA             ; Wait for ...
C128: C4 01           ANDB    #$01                ; ... button ...
C12A: 26 F6           BNE     $C122               ; ... press ...
C12C: 16 FF 02        LBRA    SplashScreen        ; Start a new game

Play One Round

This code plays one round for either of the players. The round ends when the player runs into a game object.

PlayRound:
;
; Clear the screen and init the round variables
C12F: C6 FF           LDB     #$FF                ; Fill screen ...
C131: 17 09 1F        LBSR    FillScreen          ; ... with white {}
C134: 0F BE           CLR     endOfPlayer         ; Offset in player's line buffer (0x200)
C136: 0F D1           CLR     nextObjTime         ; 
C138: 0F CE           CLR     liveObjCnt          ; 
C13A: 0F D0           CLR     totalLoops          ; 
C13C: 0F C7           CLR     hasLoopScore        ; Not showing a loop score
C13E: 0F D6           CLR     flashType           ; Flash player "word" is off
C140: 0F CF           CLR     skullCount          ; 
C142: C6 28           LDB     #$28                ; Reload counter for ...
C144: D7 D5           STB     flashCount          ; ... flashing player "word"
;
; Print the player number so they both know whose turn it is
C146: CC 2C 28        LDD     #$2C28              ; Screen coordinates
C149: 33 8D 0A FF     LEAU    StrPlayer,PC        ; Graphics for "Player"
C14D: 17 07 F3        LBSR    PrintChars          ; Print "player"
C150: CC 44 28        LDD     #$4428              ; Screen coordinates
C153: 33 8D 0B 26     LEAU    StrOne,PC           ; Graphics for "one"
C157: 0D B6           TST     player              ; Player 0 or 1?
C159: 27 06           BEQ     $C161               ; Player 0 ... keep the "one"
C15B: 86 46           LDA     #$46                ; Move "two" over a hair
C15D: 33 8D 0B 3D     LEAU    StrTwo,PC           ; Graphics for "two"
C161: 17 07 DF        LBSR    PrintChars          ; Print the player (one or two)
;
; Play the song that goes with the life number (1, 2, or 3)
C164: D6 B5           LDB     numLives            ; What life-number are we on?
C166: 33 8D 0E 1B     LEAU    MusicThirdLife,PC   ; Song for "3rd life"
C16A: 5A              DECB                        ; Is this the last life?
C16B: 27 0B           BEQ     $C178               ; Yes ... play this song
C16D: 33 8D 0D F0     LEAU    MusicSecondLife,PC  ; Song for "2nd life"
C171: 5A              DECB                        ; Is this the second life?
C172: 27 04           BEQ     $C178               ; Yes ... play this song
C174: 33 8D 0D C5     LEAU    MusicFirstLife,PC   ; Song for 1st life
C178: 17 09 03        LBSR    PlaySong            ; Play the song
;
; Now that the song is done, clear the playfied and draw its border
C17B: 17 08 E5        LBSR    DrawPlayfiled       ; 
C17E: C6 02           LDB     #$02                ; X/Y coordinate ...
C180: 34 04           PSHS    B                   ; ... temporary
C182: 8E 00 E4        LDX     #$00E4              ; Utility object to draw border
C185: C1 56           CMPB    #$56                ; Left/Right side is shorter
C187: 2E 12           BGT     $C19B               ; Beyond the bounds of up/down ... skip up/down lines
C189: E7 02           STB     2,X                 ; Set the Y coordinate
C18B: C6 02           LDB     #$02                ; X coordinate ...
C18D: E7 84           STB     ,X                  ; ... is 2
C18F: 17 07 CD        LBSR    SetPixel            ; Draw the line down left side
C192: C6 7E           LDB     #$7E                ; X cooridante ...
C194: E7 84           STB     ,X                  ; ... is right side
C196: 17 07 C6        LBSR    SetPixel            ; Draw the line down right side
C199: E6 02           LDB     2,X                 ; Counter now ...
C19B: E7 84           STB     ,X                  ; ... in the X coordinate
C19D: C6 02           LDB     #$02                ; Top Y ...
C19F: E7 02           STB     2,X                 ; coordinate
C1A1: 17 07 BB        LBSR    SetPixel            ; Draw the line across the top
C1A4: C6 56           LDB     #$56                ; Bottom ...
C1A6: E7 02           STB     2,X                 ; ... Y coordinate
C1A8: 17 07 B4        LBSR    SetPixel            ; Draw the line across the bottom
C1AB: 6C E4           INC     ,S                  ; Increment the counter
C1AD: E6 E4           LDB     ,S                  ; New counter value
C1AF: C1 7E           CMPB    #$7E                ; All edge pixels drawn?
C1B1: 23 CF           BLS     $C182               ; No ... go do them all
C1B3: 35 04           PULS    B                   ; Pop the counter
;
; Print the player scores below the playfield
C1B5: 4F              CLRA                        ; X coordinate
C1B6: C6 58           LDB     #$58                ; Y coordinate
C1B8: 33 8D 0A 90     LEAU    StrPlayer,PC        ; Print "player" at bottom ...
C1BC: 17 07 84        LBSR    PrintChars          ; ... of screen
C1BF: CC 18 58        LDD     #$1858              ; Coordinates for "one"
C1C2: 33 8D 0A B7     LEAU    StrOne,PC           ; Graphics for "one"
C1C6: 17 07 7A        LBSR    PrintChars          ; Print "one" after "player"
C1C9: 0D B4           TST     numPlayers          ; One are two players?
C1CB: 27 0A           BEQ     $C1D7               ; Just one ... skip the "two"
C1CD: CC 52 58        LDD     #$5258              ; Coordinates for "two"
C1D0: 33 8D 0A CA     LEAU    StrTwo,PC           ; Print "two" farther ...
C1D4: 17 07 6C        LBSR    PrintChars          ; ... farther right
C1D7: 17 04 36        LBSR    PrintScores         ; Print the player scores (both if two player)
;
; Show the life number indicators (3 bars -- the current life is active)
C1DA: 8E 00 E4        LDX     #$00E4              ; Utility object
C1DD: 6F 02           CLR     2,X                 ; Y = 0
C1DF: C6 33           LDB     #$33                ; 1st slot X ...
C1E1: E7 84           STB     ,X                  ; ... coordinate
; First slot (active if 3 lives)
C1E3: 33 8D 0A 33     LEAU    $CC1A,PC            ; Life inidcator ACTIVE
C1E7: D6 B5           LDB     numLives            ; Number of lives
C1E9: C1 03           CMPB    #$03                ; All 3?
C1EB: 27 04           BEQ     $C1F1               ; Yes ... 1st bar is CURRENT
C1ED: 33 8D 0A 19     LEAU    LifeIndicator,PC    ; Life indicator INACTIVE
C1F1: 17 05 69        LBSR    Draw8x8             ; Draw the indicator
C1F4: C6 3D           LDB     #$3D                ; 2nd slot X ...
C1F6: E7 84           STB     ,X                  ; ... cooridinate
; Second slot (active if 2 lives)
C1F8: 33 8D 0A 1E     LEAU    $CC1A,PC            ; Life inidcator ACTIVE
C1FC: D6 B5           LDB     numLives            ; Number of lives
C1FE: C1 02           CMPB    #$02                ; 2 remaining?
C200: 27 04           BEQ     $C206               ; Yes ... 2nd bar is CURRENT
C202: 33 8D 0A 04     LEAU    LifeIndicator,PC    ; Life indicator INACTIVE
C206: 17 05 54        LBSR    Draw8x8             ; Draw the indicator
C209: C6 47           LDB     #$47                ; 3rd slot X ...
C20B: E7 84           STB     ,X                  ; ... coordinate
; Third slot (active if 1 life)
C20D: 33 8D 0A 09     LEAU    $CC1A,PC            ; Life inidcator ACTIVE
C211: D6 B5           LDB     numLives            ; Number of lives
C213: C1 01           CMPB    #$01                ; 1 remaining?
C215: 27 04           BEQ     $C21B               ; Yes ... 3rd bar is CURRENT
C217: 33 8D 09 EF     LEAU    LifeIndicator,PC    ; Life indicator INACTIVE
C21B: 17 05 3F        LBSR    Draw8x8             ; Draw the indicator
;
; Clear the player's line (all points to 64,64)
C21E: 8E 00 D8        LDX     #$00D8              ; Player-point object
C221: 86 40           LDA     #$40                ; Set X ...
C223: A7 84           STA     ,X                  ; ... to 64 ...
C225: A7 02           STA     2,X                 ; ... and Y to 64
C227: 8E 02 00        LDX     #$0200              ; Clear ...
C22A: 5F              CLRB                        ; ... the ...
C22B: A7 80           STA     ,X+                 ; ... player ...
C22D: 5A              DECB                        ; ... line
C22E: 26 FB           BNE     $C22B               ; ... points
;
; Clear all game objects
C230: 8E 01 60        LDX     #$0160              ; Start of game objects
C233: C6 A0           LDB     #$A0                ; 160 / 8 = 20 possible objects
C235: 6F 80           CLR     ,X+                 ; Clear ...
C237: 5A              DECB                        ; ... all ...
C238: 26 FB           BNE     $C235               ; ... game objects
C23A: 0F BD           CLR     collision           ; Clear the collision flag
;
; Loop through one cycle of play -- over and over until done
C23C: 17 00 16        LBSR    OneCycle            ; Move the player and the objects
C23F: 0D BD           TST     collision           ; Was there a collision?
C241: 27 F9           BEQ     $C23C               ; No ... keep playing
;
; Dull the screen, play the tone, and return from the round
C243: C6 F0           LDB     #$F0                ; Dull screen ...
C245: F7 FF 22        STB     PIA1_DB             ; ... color mode
C248: 33 8D 0D 59     LEAU    MusicEndOfLife,PC   ; Play the ...
C24C: 17 08 2F        LBSR    PlaySong            ; ... end of life song
C24F: C6 F8           LDB     #$F8                ; Bright screen ...
C251: F7 FF 22        STB     PIA1_DB             ; ... color mode
C254: 39              RTS                         ; Done

One Cycle

This code is one pass through the game loop. It ends way down at C60F. There is a wait on VBLANK at the end of this loop. - Check for break and restart the program if pressed - Erase the tail of the player - Handle a small set game objects (not every object is processed every cycle) - Read sticks and move player's head - Check for looped objects (score and remove them) - Create a new object if it is time - Wait for the next VBLANK - Time down and remove any showing "loop score" - Flash the player word "one" or "two"

OneCycle:
C255: 17 08 68        LBSR    CheckForBreak       ; Check for BREAK (reset if so)
C258: 8E 02 00        LDX     #$0200              ; Player's drawn coordinates
C25B: D6 BE           LDB     endOfPlayer         ; End of the list
C25D: 3A              ABX                         ; Offset to last point
C25E: EC 84           LDD     ,X                  ; X,Y of last point
C260: 8E 00 DE        LDX     #$00DE              ; Descriptor for erasing points
C263: A7 84           STA     ,X                  ; Set X ...
C265: E7 02           STB     2,X                 ; ... and Y coordinate
C267: 17 07 48        LBSR    GetScreenAndShift   ; Pointer and pixel number
C26A: 17 07 29        LBSR    ErasePixel          ; Erase the tail of the player
C26D: 0C D4           INC     cycleCount          ; Cycle count used to pace the objects

Move Game Objects

The game manages a list of 8-byte objects in memory at 0160. The array has 20 slots, but there is always a null slot (object type = 0) at the end to mark the end. Thus there can be only 19 objects on the screen at once.

Object structure (offset in the 8 bytes):

  • 00 X coordinate
  • 01 X residue (if used)
  • 02 Y coordinate
  • 03 Y residue (if used)
  • 04 delta X (if used) and looped flag
  • 05 delta Y (if used) and looped flag
  • 06 object type (0 means end of list)
  • 07 image number (if used) for flipping images

Every object has an object-type (1-9), and X coordinate, and a Y coordinate.

Animated objects us an "image number" value they can use to flip images, though some of the objects use the X coordinate odd/even instead.

Animated objects use a delta-X and delta-Y value to make their movements. The move-routine extends the X coordinate and Y coordinate to two-bytes each (the residue values in the structure). This allows for finer-grain movement speeds.

The delta-X and delta-Y fields are also used during the process of figuring out if an object has been looped or not. More on that with the looping-detection algorithm below.

C26F: 8E 01 60        LDX     #$0160              ; List of objects
;
ObjectLoop:
C272: 6D 06           TST     6,X                 ; Object type 0 (end of list)?
C274: 10 27 01 17     LBEQ    $C38F               ; Yes ... done with list
C278: 30 08           LEAX    8,X                 ; Next slot
C27A: 1F 10           TFR     X,D                 ; 8 bytes per slot ...
C27C: 54              LSRB                        ; ... get the ...
C27D: 54              LSRB                        ; ... slot number ...
C27E: 54              LSRB                        ; ... to B
C27F: DB D4           ADDB    cycleCount          ; Add in cycle count
C281: C4 07           ANDB    #$07                ; Time for this slot to update?
C283: 26 ED           BNE     ObjectLoop          ; No ... skip this object
C285: 30 18           LEAX    -8,X                ; Back up to start of this object

C287: E6 06           LDB     6,X                 ; Object type
C289: 5A              DECB                        ; 1=APPLE (fixed position)
C28A: 26 0A           BNE     $C296               ; No ... check other types
C28C: 33 8D 08 6A     LEAU    ImageApple,PC       ; Apple graphic
C290: 17 04 CA        LBSR    Draw8x8             ; Draw apple
C293: 16 00 F0        LBRA    NextObject          ; Next object

C296: 5A              DECB                        ; 2=CHERRY (fixed position)
C297: 26 0A           BNE     $C2A3               ; No ... check other types
C299: 33 8D 08 6D     LEAU    ImageCherry,PC      ; Cherry graphic
C29D: 17 04 BD        LBSR    Draw8x8             ; Draw cherry
C2A0: 16 00 E3        LBRA    NextObject          ; Next object

C2A3: 5A              DECB                        ; 3=MAGNET (slow moving X/Y)
C2A4: 26 17           BNE     $C2BD               ; No ... check other types
C2A6: 33 8D 08 70     LEAU    ImageMagnet,PC      ; Erase current ...
C2AA: 17 05 AE        LBSR    Erase8x8            ; ... magnet
C2AD: CC 10 10        LDD     #$1010              ; DeltaX,DeltaY = 16,16
C2B0: 17 07 4C        LBSR    FollowPlayer        ; 
C2B3: 33 8D 08 63     LEAU    ImageMagnet,PC      ; Draw the ...
C2B7: 17 04 A3        LBSR    Draw8x8             ; ... magnet
C2BA: 16 00 C9        LBRA    NextObject          ; Next object

C2BD: 5A              DECB                        ; 4=SKATE (moves along X only)
C2BE: 26 24           BNE     $C2E4               ; No ... check other types
C2C0: 8D 13           BSR     $C2D5               ; Get skate image
C2C2: 17 05 96        LBSR    Erase8x8            ; Erase the current skate
C2C5: 6C 07           INC     7,X                 ; Next skate image
C2C7: 86 10           LDA     #$10                ; DeltaX,DeltaY = ...
C2C9: 5F              CLRB                        ; ... 16,0
C2CA: 17 07 32        LBSR    FollowPlayer        ; 
C2CD: 8D 06           BSR     $C2D5               ; Get the skate image
C2CF: 17 04 8B        LBSR    Draw8x8             ; Draw the skate
C2D2: 16 00 B1        LBRA    NextObject          ; Next object
;
C2D5: 33 8D 08 51     LEAU    ImageSkate,PC       ; Skate graphic 1
C2D9: E6 07           LDB     7,X                 ; Image number
C2DB: C4 01           ANDB    #$01                ; Either 0 or 1
C2DD: 26 04           BNE     $C2E3               ; Not 1 ... use this graphic
C2DF: 33 8D 08 57     LEAU    $CB3A,PC            ; Use skate graphic 2
C2E3: 39              RTS                         ; Done

C2E4: 5A              DECB                        ; 5=YOYO (moves up and down and leaves a string)
C2E5: 26 3C           BNE     $C323               ; No ... check other types
C2E7: 33 8D 08 9F     LEAU    $CB8A,PC            ; Erase the current yoyo but ...
C2EB: 17 05 6D        LBSR    Erase8x8            ; ... leave the string piece of the image
C2EE: 4F              CLRA                        ; Set deltaX ...
C2EF: A7 04           STA     4,X                 ; ... to zero
C2F1: C6 20           LDB     #$20                ; Downward deltaY
C2F3: 6D 07           TST     7,X                 ; Moving down?
C2F5: 27 01           BEQ     $C2F8               ; Yes ... keep this
C2F7: 50              NEGB                        ; No ... moving UP. Negate it
C2F8: E7 05           STB     5,X                 ; Store deltaY
C2FA: 17 06 CB        LBSR    MoveObject          ; 
C2FD: E6 02           LDB     2,X                 ; Y coordinate
C2FF: C1 0C           CMPB    #$0C                ; At the top-most allowed?
C301: 24 04           BHS     $C307               ; No ... keep moving in current direction
C303: 6F 07           CLR     7,X                 ; Yes ... now moving down
C305: C6 0C           LDB     #$0C                ; Set to the top-most allowed
C307: C1 42           CMPB    #$42                ; At the bottom-most allowed?
C309: 25 04           BLO     $C30F               ; No ... keep moving in current direction
C30B: 6C 07           INC     7,X                 ; Yes ... now moving up
C30D: C6 42           LDB     #$42                ; Set to the bottom-most allowed
C30F: E7 02           STB     2,X                 ; New Y coordinate
C311: 33 8D 08 35     LEAU    ImageYoYo,PC        ; YoYo images
C315: C4 03           ANDB    #$03                ; 4 of them based on Y coordinate
C317: 58              ASLB                        ; 16 ...
C318: 58              ASLB                        ; ... bytes ...
C319: 58              ASLB                        ; ... each ...
C31A: 58              ASLB                        ; ... image
C31B: 33 C5           LEAU    B,U                 ; Point to current image
C31D: 17 04 3D        LBSR    Draw8x8             ; 
C320: 16 00 63        LBRA    NextObject          ; Next object

C323: 5A              DECB                        ; 6=PEAR (fixed position)
C324: 26 09           BNE     $C32F               ; No ... check other types
C326: 33 8D 08 90     LEAU    ImagePear,PC        ; 
C32A: 17 04 30        LBSR    Draw8x8             ; 
C32D: 20 57           BRA     NextObject          ; Next object

C32F: 5A              DECB                        ; 7=SPIDER (fast moving X/Y)
C330: 26 21           BNE     $C353               ; No ... check other types
C332: 8D 10           BSR     $C344               ; Get spider image
C334: 17 05 24        LBSR    Erase8x8            ; Erase current spider image
C337: CC 30 30        LDD     #$3030              ; DeltaX,DeltaY = 48,48
C33A: 17 06 C2        LBSR    FollowPlayer        ; Move towards player
C33D: 8D 05           BSR     $C344               ; Get spider image
C33F: 17 04 1B        LBSR    Draw8x8             ; Draw the spider
C342: 20 42           BRA     NextObject          ; Next object
;
C344: 33 8D 08 82     LEAU    ImageSpider,PC      ; First spider image
C348: E6 02           LDB     2,X                 ; Y coordinate
C34A: C4 01           ANDB    #$01                ; Is the Y coordinate odd?
C34C: 26 04           BNE     $C352               ; Yes ... use first image
C34E: 33 8D 08 88     LEAU    $CBDA,PC            ; No ... use 2nd image
C352: 39              RTS                         ; Done

C353: 5A              DECB                        ; 8=SKULL (fixed position)
C354: 26 09           BNE     $C35F               ; No ... check other types
C356: 33 8D 08 50     LEAU    ImageSkull,PC       ; 
C35A: 17 04 00        LBSR    Draw8x8             ; 
C35D: 20 27           BRA     NextObject          ; Next object

C35F: 5A              DECB                        ; 9=X (very fast moving X/Y)
C360: 26 24           BNE     NextObject          ; No. Anything but 0-9 ... skip.
C362: 8D 13           BSR     $C377               ; Get the current image
C364: 17 04 F4        LBSR    Erase8x8            ; Erase the current image
C367: 6C 07           INC     7,X                 ; Next image index
C369: CC 7F 7F        LDD     #$7F7F              ; DeltaX,DeltaY = 127,127 ! Very fast!
C36C: 17 06 90        LBSR    FollowPlayer        ; Move towards player
C36F: 8D 06           BSR     $C377               ; Get the image
C371: 17 03 E9        LBSR    Draw8x8             ; Draw the image
C374: 16 00 0F        LBRA    NextObject          ; Next object
;
C377: 33 8D 08 6F     LEAU    ImageX,PC           ; X picture small
C37B: E6 07           LDB     7,X                 ; The image number
C37D: C4 01           ANDB    #$01                ; Is image number odd?
C37F: 26 04           BNE     $C385               ; Yes ... keep small picture
C381: 33 8D 08 75     LEAU    $CBFA,PC            ; No ... use large picture
C385: 39              RTS                         ; Done

NextObject:
C386: 6F 04           CLR     4,X                 ; Clear any ...
C388: 6F 05           CLR     5,X                 ; ... deltas (used as flags later)
C38A: 30 08           LEAX    8,X                 ; Next object
C38C: 16 FE E3        LBRA    ObjectLoop          ; continue with next

Read the Player's Input

Any "loop score" that is showing is erased before the player is drawn. Collision detection is noted as the player is drawn. Then any "loop score" is immediately drawn back.

Joystick axises are read as 6-bit values from 0 (left/up) to 63 (right/down). The code subtracts 32 to make 6-bit signed values for the delta-X and delta-Y.

; Read the player's input
C38F: 9F D2           STX     nextFreeObj         ; 
C391: AD 9F A0 0A     JSR     [JOYIN]             ; JOYIN reads all 4 joysticks (15A,15B,15C,15D)
C395: 8E 00 D8        LDX     #$00D8              ; Object for drawing player point
C398: 10 8E 01 5A     LDY     #$015A              ; Memory for analog inputs
C39C: D6 B6           LDB     player              ; Player number
C39E: 58              ASLB                        ; 2 axis per joystick
C39F: 31 A5           LEAY    B,Y                 ; Point to 15A, 15B (player 0) or 15C, 15D (player 1)
C3A1: E6 A4           LDB     ,Y                  ; Get the X stick value
C3A3: A6 A4           LDA     ,Y                  ; Add in ...
C3A5: 9B D7           ADDA    random              ; ... some ...
C3A7: 97 D7           STA     random              ; ... randomness to RNG
C3A9: C0 20           SUBB    #$20                ; 0 to 64 now -32 to 32
C3AB: E7 04           STB     4,X                 ; Hold as delta X
C3AD: E6 21           LDB     1,Y                 ; Next axis
C3AF: C0 20           SUBB    #$20                ; 0 to 64 now -32 to 32
C3B1: E7 05           STB     5,X                 ; Hold as delta Y
C3B3: 17 06 12        LBSR    MoveObject          ; Move ...
C3B6: 17 03 66        LBSR    EraseLoopScore      ; ... player's dot
;
; Draw the new player head
C3B9: 8E 00 D8        LDX     #$00D8              ; Player point structure
C3BC: 17 05 A0        LBSR    SetPixel            ; Draw the new player dot
C3BF: D7 BF           STB     origPixel           ; Hold the original pixel (for collision detection)
C3C1: 17 03 4F        LBSR    DrawLoopScore       ; Redraw the loop score (after we drew the head and checked collision)
;
; Check for a loop
C3C4: 0F C3           CLR     nontouch            ; So far, no non-touching point
C3C6: D6 BE           LDB     endOfPlayer         ; End of the player ...
C3C8: D7 C0           STB     objCounter          ; ... line (ring buffer)
;
C3CA: D6 C0           LDB     objCounter          ; Move up ...
C3CC: C0 02           SUBB    #$02                ; ... one point (this wraps around from FF)
C3CE: D7 C0           STB     objCounter          ; Hold the new pointer
C3D0: D1 BE           CMPB    endOfPlayer         ; Caught up to head?
C3D2: 10 27 01 24     LBEQ    $C4FA               ; Yes ... we are done
C3D6: 8E 02 00        LDX     #$0200              ; Player's points
C3D9: 3A              ABX                         ; Offset into the points
C3DA: EC 84           LDD     ,X                  ; Get X,Y of point
C3DC: 8E 00 D8        LDX     #$00D8              ; Player's X,Y
C3DF: A0 84           SUBA    ,X                  ; This point ...
C3E1: 4C              INCA                        ; ... X next to the ...
C3E2: 81 02           CMPA    #$02                ; ... start X?
C3E4: 22 07           BHI     $C3ED               ; No ... skip
C3E6: E0 02           SUBB    2,X                 ; This point ...
C3E8: 5C              INCB                        ; ... Y next to the ...
C3E9: C1 02           CMPB    #$02                ; Start Y?
C3EB: 23 04           BLS     $C3F1               ; Yes ... we need to check for looped objects
C3ED: 0C C3           INC     nontouch            ; 
C3EF: 20 D9           BRA     $C3CA               ; Keep looking for a crossing
;
C3F1: 10 83 01 01     CMPD    #$0101              ; Did we cross ourselves (as opposed to just touching next to the head)
C3F5: 26 02           BNE     $C3F9               ; No ... keep the point under the player
C3F7: 0F BF           CLR     origPixel           ; Clear the pixel under the player (no collision)
C3F9: 0D C3           TST     nontouch            ; Were there any points that didn't touch the head?
C3FB: 27 CD           BEQ     $C3CA               ; No ... we are on top of ourselves ... keep looking for a crossing
C3FD: 0F BF           CLR     origPixel           ; No collision detection
;
C3FF: D6 C0           LDB     objCounter          ; Note where we ...
C401: D7 C1           STB     loopStart           ; ... formed a loop
C403: D6 BE           LDB     endOfPlayer         ; Reset ...
C405: D7 C0           STB     objCounter          ; ... the end pointer
;
C407: D6 C0           LDB     objCounter          ; Move up ...
C409: C0 02           SUBB    #$02                ; a point
C40B: D7 C0           STB     objCounter          ; New pointer
C40D: 8E 02 00        LDX     #$0200              ; Player line points
C410: 3A              ABX                         ; Get the ...
C411: EC 84           LDD     ,X                  ; ... X,Y coordinates
C413: C0 03           SUBB    #$03                ; Translate to top of objects (compare player point to center of object)
C415: D7 C2           STB     transY              ; Hold the Y
C417: 80 03           SUBA    #$03                ; Translate the left side of objects ... X in A
C419: 8E 01 60        LDX     #$0160              ; Start of objects

Looped Object Detection

We look at all points in the player's loop. For each point, we run the list of objects. If the Y coordinate of the player point matches the object's center Y coordinate (or one beyond) then we note the object as having a point on either the left or right side by comparing the X coordinates. These notes are kept in the object structure at OBJ[4] for left side or OBJ[5] for right side.

After we have run all points, we look at the notes. If an object has a point noted on the left AND on the right side, we consider it looped.

Most of the time, this is a good (and fast) check. But you can "loop" and object by making a "U" around it either up or down without actually going around it. In fact, the sides of the U can be half the height of the object.

For instance, this object "O" is considered looped by the player line "*":

******************
*                *
* ************** *
* *            * *
* *  OOOOOOOO  * *
* *  OOOOOOOO  * *
* *  OOOOOOOO  * *
***  OOOOOOOO  ***
     OOOOOOOO
     OOOOOOOO
     OOOOOOOO
     OOOOOOOO
C41C: 6D 06           TST     6,X                 ; Reached the end of the list?
C41E: 27 15           BEQ     $C435               ; yes ... done
C420: D6 C2           LDB     transY              ; The Y coordinate
C422: E0 02           SUBB    2,X                 ; Compare Y coordinates
C424: 54              LSRB                        ; (Also match the next Y coordinate)
C425: 26 0A           BNE     $C431               ; This Y coordinate is not the center of the object .. skip
C427: A1 84           CMPA    ,X                  ; The X coordinate is ...
C429: 22 04           BHI     $C42F               ; ... above. Mark that.
C42B: 6C 04           INC     4,X                 ; Mark the X coordinate is below
C42D: 20 02           BRA     $C431               ; Check other points
C42F: 6C 05           INC     5,X                 ; There was a Y coordinate close
C431: 30 08           LEAX    8,X                 ; Check all ...
C433: 20 E7           BRA     $C41C               ; ... objects
;
C435: D6 C0           LDB     objCounter          ; Check ...
C437: D1 C1           CMPB    loopStart           ; ... all points ...
C439: 26 CC           BNE     $C407               ; ... in the loop
;
C43B: 8E 01 60        LDX     #$0160              ; Start of objects
C43E: 0F C4           CLR     numLooped           ; Number of objects looped
C440: 0F C8           CLR     loopScoreTmp        ; Sum of ...
C442: 0F C9           CLR     loopScoreTmp+1      ; ... looped objects score
;
C444: E6 06           LDB     6,X                 ; End of the object list?
C446: 27 5D           BEQ     $C4A5               ; Yes ... done
C448: 6D 04           TST     4,X                 ; Close-Y points on the left?
C44A: 27 55           BEQ     $C4A1               ; No ... wasn't looped
C44C: 6D 05           TST     5,X                 ; And close-Y points on the right?
C44E: 27 51           BEQ     $C4A1               ; No ... wasn't looped
C450: C1 08           CMPB    #$08                ; This object a skull?
C452: 27 4D           BEQ     $C4A1               ; Yes ... it doesn't count ... next object
C454: 0C C4           INC     numLooped           ; number of objects looped
C456: 0C D0           INC     totalLoops          ; 
C458: 0A CE           DEC     liveObjCnt          ; 
;
; Score the looped object
C45A: 33 8D 0B 4B     LEAU    ScoreTable,PC       ; The table of object scores
C45E: E6 C5           LDB     B,U                 ; Get the score for this object
C460: 1D              SEX                         ; No score is greater than 127 ... this is a quick way to clear A
C461: D3 C8           ADDD    loopScoreTmp        ; Add the score ...
C463: DD C8           STD     loopScoreTmp        ; ... to the accumulated loop score
C465: CE 00 EA        LDU     #$00EA              ; Descriptor for erasing
C468: E6 84           LDB     ,X                  ; Copy ...
C46A: E7 C4           STB     ,U                  ; ... X coordinate
C46C: E6 02           LDB     2,X                 ; Copy ...
C46E: E7 42           STB     2,U                 ; ... Y coordinate
C470: 33 8D 07 B7     LEAU    GenericEraser,PC    ; Erase the ...
C474: 17 03 E4        LBSR    Erase8x8            ; ... object
C477: E6 06           LDB     6,X                 ; Is this ...
C479: C1 05           CMPB    #$05                ; ... a yoyo?
C47B: 26 11           BNE     $C48E               ; No ... skip the string
C47D: 33 8D 07 19     LEAU    StringEraser,PC     ; Line erase graphic
C481: 17 03 D7        LBSR    Erase8x8            ; Erase the string
C484: E6 02           LDB     2,X                 ; Move ...
C486: C0 04           SUBB    #$04                ; ... up by ...
C488: E7 02           STB     2,X                 ; ... 4 pixels
C48A: C1 03           CMPB    #$03                ; At the top of the screen?
C48C: 2E F3           BGT     $C481               ; No ... keep erasing possible string
C48E: 1F 13           TFR     X,U                 ; For memory copy
C490: C6 08           LDB     #$08                ; 8 bytes per object
C492: DF D2           STU     nextFreeObj         ; end of the object list (where we add new objects)
C494: A6 48           LDA     8,U                 ; Close ...
C496: A7 C0           STA     ,U+                 ; ... up ...
C498: 5A              DECB                        ; ... list ...
C499: 26 F9           BNE     $C494               ; ... over ...
C49B: 6D 46           TST     6,U                 ; ... removed ...
C49D: 26 F1           BNE     $C490               ; ... object
C49F: 20 A3           BRA     $C444               ; Next object
;
C4A1: 30 08           LEAX    8,X                 ; Next object
C4A3: 20 9F           BRA     $C444               ; Continue checking

C4A5: 0D C4           TST     numLooped           ; Were any objects looped?
C4A7: 27 51           BEQ     $C4FA               ; No ... skip score update
C4A9: 17 02 73        LBSR    EraseLoopScore      ; Erase any loop score being shown
C4AC: 4F              CLRA                        ; Score for all ...
C4AD: 5F              CLRB                        ; Looped ...
C4AE: D3 C8           ADDD    loopScoreTmp        ; Sum of looped objects score
C4B0: 0A C4           DEC     numLooped           ; Multiply score of summed by ...
C4B2: 26 FA           BNE     $C4AE               ; ... number of objects looped
C4B4: DD CA           STD     loopScoreShown      ; The value of the loop score to show
C4B6: 0D B6           TST     player              ; Player 0 or 1
C4B8: 26 06           BNE     $C4C0               ; ... player 1
C4BA: D3 B7           ADDD    p1Score             ; Player 1 score
C4BC: DD B7           STD     p1Score             ; Update player 1 score
C4BE: 20 04           BRA     $C4C4               ; Continue
C4C0: D3 B9           ADDD    p2Score             ; Player 2 score
C4C2: DD B9           STD     p2Score             ; Update player 2 score
C4C4: C6 3C           LDB     #$3C                ; Counter for showing ...
C4C6: D7 C6           STB     loopScoreCnt        ; ... loop score
C4C8: 8E 00 EA        LDX     #$00EA              ; Current game object
C4CB: E6 84           LDB     ,X                  ; X coordinate
C4CD: C1 60           CMPB    #$60                ; Too far to the right to print score?
C4CF: 2F 02           BLE     $C4D3               ; No ... keep it
C4D1: C6 60           LDB     #$60                ; Keep loop score on the screen
C4D3: E7 84           STB     ,X                  ; Constrained X coordinate
C4D5: 17 04 DA        LBSR    GetScreenAndShift   ; Store the screen ...
C4D8: DF CC           STU     loopScoreLoc        ; ... location of the loop score
C4DA: 0C C7           INC     hasLoopScore        ; We now have a loop score to show
C4DC: 17 01 31        LBSR    PrintScores         ; Print the scores (both if 2 player)
;
; Make popping sound after scoring object
C4DF: 7F FF 20        CLR     PIA1_DA             ; DAC to zero
C4E2: BD A9 76        JSR     $A976               ; Enable the sound
C4E5: C6 80           LDB     #$80                ; Outer loop
C4E7: 1F 98           TFR     B,A                 ; Outter to inner
C4E9: 4A              DECA                        ; Slight ...
C4EA: 26 FD           BNE     $C4E9               ; ... delay
C4EC: F7 FF 20        STB     PIA1_DA             ; Store samples
C4EF: 1F 98           TFR     B,A                 ; Another ...
C4F1: 4A              DECA                        ; ... slight ...
C4F2: 26 FD           BNE     $C4F1               ; ... delay
C4F4: 7F FF 20        CLR     PIA1_DA             ; DAC to 0
C4F7: 5A              DECB                        ; All loops made?
C4F8: 26 ED           BNE     $C4E7               ; No ... continue popping sound

Update the Player's Line

The new "head" coordinate overwrites the tail coordinate, and the dividing line moves around the ring.

C4FA: 8E 02 00        LDX     #$0200              ; The player's line points
C4FD: D6 BE           LDB     endOfPlayer         ; the end of the player line
C4FF: 3A              ABX                         ; The tail and head separator
C500: CE 00 D8        LDU     #$00D8              ; Player's head
C503: A6 C4           LDA     ,U                  ; Player's head ...
C505: E6 42           LDB     2,U                 ; ... X and Y
C507: ED 84           STD     ,X                  ; Add it to the start of the list (will be start after we increment below)
;
C509: D6 BF           LDB     origPixel           ; The pixel the player over-drew
C50B: DB BD           ADDB    collision           ; Mark ...
C50D: D7 BD           STB     collision           ; ... collision
C50F: 0C BE           INC     endOfPlayer         ; Next point ...
C511: 0C BE           INC     endOfPlayer         ; ... slot in player line

Make new Game Object

We only allow 19 game object on the screen at once. The type of the object made depends on the player's score and the number of completed loops the player has made. Higher values result in more advanced objects.

When the code tries to make a new skull, it looks to see if there are already 10 skulls on the screen. If there are, the new object becomes the fast moving "X" shape instead.

C513: 0C D1           INC     nextObjTime         ; Time to make a new object?
C515: 10 26 00 B3     LBNE    $C5CC               ; No ... skip making one
C519: D6 CE           LDB     liveObjCnt          ; Do we already have ...
C51B: C1 13           CMPB    #$13                ; ... 19 objects?
C51D: 10 2C 00 AB     LBGE    $C5CC               ; Yes ... skip making one
C521: 0C CE           INC     liveObjCnt          ; Bump the object count
C523: 33 8D 0A 7A     LEAU    $CFA1,PC            ; Make the popping sound ...
C527: 17 05 54        LBSR    PlaySong            ; ... of a new object appearing
;
; We are making a new object now, but we'll make the timer until the next one.
; Next object's appearence is based on the total number of loops made so far and the player's
; score. The more loops and the higher the score, the sooner the next object can appear.
C52A: 96 D0           LDA     totalLoops          ; Total number of loops made
C52C: 48              ASLA                        ; Times ...
C52D: 48              ASLA                        ; ... 4
C52E: 8E 00 B7        LDX     #$00B7              ; Player 1 score
C531: D6 B6           LDB     player              ; Which player is playing?
C533: 58              ASLB                        ; Point to current player score
C534: AB 85           ADDA    B,X                 ; Add in the player's score upper byte
C536: 94 D7           ANDA    random              ; Some randomness
C538: 97 D1           STA     nextObjTime         ; Timer for next object to appear
;
; The type of the next object is random but based on the player's score. The higher the score, the
; more advanced the object can be.
; (SCORE[0]+4) * random(256) / 256
; For a score of 0: 4*255/256 = 0,1,2,3 (apple, cherry, magnet, skate)
; Upper digit of 4 is 4*256 = 1024. Add the extra zero (all scores have it): 10,000 is where skulls start.
; TODO break them all down
; For a score of (4+4)*255/256 = 0,1,2,3,4,5,6,7 (everything ... skulls begin)
C53A: A6 85           LDA     B,X                 ; Upper byte of score
C53C: 8B 04           ADDA    #$04                ; Add 4 (even with no score you can get an object)
C53E: D6 D7           LDB     random              ; Multiply ...
C540: 3D              MUL                         ; ... by random number 0 to 255
C541: 84 07           ANDA    #$07                ; Divide by 256 and random object type ...
C543: 4C              INCA                        ; ... from 1 to 8
C544: 81 08           CMPA    #$08                ; Is this a skull?
C546: 26 09           BNE     $C551               ; No ... keep whatever it is

The Unexpected

This is the code that creates the fast-moving "X" after 10 skulls.

C548: 0C CF           INC     skullCount          ; Bump the skull count
C54A: D6 CF           LDB     skullCount          ; Do we have ...
C54C: C1 0A           CMPB    #$0A                ; ... 10 skulls on the screen?
C54E: 23 01           BLS     $C551               ; No ... this is a new skull
C550: 4C              INCA                        ; Yes ... promote this to a moving "X"
C551: 9E D2           LDX     nextFreeObj         ; Next object slot
C553: A7 06           STA     6,X                 ; New object's type
C555: 6F 07           CLR     7,X                 ; Any image flipping starts at 0
;
; Pick a candidate X,Y coordinate (we'll check it later)
C557: 96 D7           LDA     random              ; Mix ...
C559: 1F 89           TFR     A,B                 ; ... up ...
C55B: 54              LSRB                        ; ... the ...
C55C: 46              RORA                        ; ...
C55D: 54              LSRB                        ; ...
C55E: 46              RORA                        ; ...
C55F: 97 D7           STA     random              ; ... random a bit
C561: 54              LSRB                        ; Mix ...
C562: 46              RORA                        ; ...
C563: 54              LSRB                        ; ...
C564: 46              RORA                        ; ... even more
C565: C6 44           LDB     #$44                ; Y coordinate = ...
C567: 3D              MUL                         ; ... random(68) ...
C568: 8B 08           ADDA    #$08                ; ... + 8
C56A: A7 02           STA     2,X                 ; New random Y coordinate
C56C: 96 D7           LDA     random              ; Random value
C56E: C6 60           LDB     #$60                ; X coordinate = ...
C570: 3D              MUL                         ; ... random(96)
; TODO simulate this algorithm and see what's going on exactly
C571: 84 FC           ANDA    #$FC                ; Drop lower 2 bits
C573: 8B 0C           ADDA    #$0C                ; Now between 12 and 119
C575: 8B 04           ADDA    #$04                ; Move right 4 bits
C577: 81 6C           CMPA    #$6C                ; Too close to the right side (X=108)?
C579: 24 FA           BHS     $C575               ; Yes ... keep moving right 4 (and wrap)
C57B: 81 10           CMPA    #$10                ; Too close to the left sice (X=16)?
C57D: 23 F6           BLS     $C575               ; Yes ... keep moving right 4 (and wrap)
C57F: A7 84           STA     ,X                  ; X coordinate
;
; Don't drop a new object near the player
C581: E6 02           LDB     2,X                 ; Y coordinate
C583: CE 00 D8        LDU     #$00D8              ; Player's X,y
C586: E0 42           SUBB    2,U                 ; Are we far ...
C588: CB 14           ADDB    #$14                ; ... enough from ...
C58A: C1 28           CMPB    #$28                ; ... the player?
C58C: 24 0C           BHS     $C59A               ; Yes ... keep this location
C58E: A0 C4           SUBA    ,U                  ; No ... compare X too
C590: 8B 14           ADDA    #$14                ; Are we far ...
C592: 81 28           CMPA    #$28                ; ... enough from the player?
C594: 24 04           BHS     $C59A               ; Yes ... keep this location
C596: A6 84           LDA     ,X                  ; No ... go back for ...
C598: 20 DB           BRA     $C575               ; ... another random X coordinate
;
; Try not to drop similar objects near each other
C59A: 1F 13           TFR     X,U                 ; Is this the ...
C59C: 11 83 01 60     CMPU    #$0160              ; ... first slot?
C5A0: 27 2A           BEQ     $C5CC               ; Yes ... good to go
C5A2: 33 58           LEAU    -8,U                ; Is one of this ...
C5A4: E6 46           LDB     6,U                 ; ... new object ...
C5A6: E1 06           CMPB    6,X                 ; ... alread on the screen?
C5A8: 26 F2           BNE     $C59C               ; Keep checking
C5AA: E6 84           LDB     ,X                  ; Compare ...
C5AC: E0 C4           SUBB    ,U                  ; ... X coordinate
C5AE: CB 08           ADDB    #$08                ; +8
C5B0: C1 10           CMPB    #$10                ; Are these close in X?
C5B2: 22 E8           BHI     $C59C               ; No ... keep checking
C5B4: E6 02           LDB     2,X                 ; Compare ...
C5B6: E0 42           SUBB    2,U                 ; ... Y coordinate
C5B8: CB 08           ADDB    #$08                ; +8
C5BA: C1 10           CMPB    #$10                ; Are these close in Y?
C5BC: 22 DE           BHI     $C59C               ; No ... keep checking
C5BE: E6 02           LDB     2,X                 ; Y coordinate
C5C0: CB 15           ADDB    #$15                ; Move Y coordinate down 21
C5C2: C1 4C           CMPB    #$4C                ; too close to the bottom?
C5C4: 2D 02           BLT     $C5C8               ; No keep it
C5C6: C0 44           SUBB    #$44                ; Yes ... back it up to the top
C5C8: E7 02           STB     2,X                 ; New Y coordinate
C5CA: 20 CA           BRA     $C596               ; Go all the way back for another random X coordinate
;
; Sync up to VBLANK for timing and tearing
C5CC: 17 05 20        LBSR    WaitVBlank          ; Sync the gameloop to VBLANK
;
; Time down and remove loop score indicator
C5CF: 0D C7           TST     hasLoopScore        ; Is there a loop score showing?
C5D1: 27 09           BEQ     $C5DC               ; No ... skip timing it out
C5D3: 0A C6           DEC     loopScoreCnt        ; Time to erase it?
C5D5: 26 05           BNE     $C5DC               ; No ... leave it alone
C5D7: 17 01 45        LBSR    EraseLoopScore      ; Erase the loop score
C5DA: 0F C7           CLR     hasLoopScore        ; No longer showing the loop score
C5DC: 0A D5           DEC     flashCount          ; Time to flash the player word?
;
; Flash the player's word on and off with a counter
C5DE: 26 2F           BNE     $C60F               ; No ... skip it
C5E0: C6 28           LDB     #$28                ; Reload the ...
C5E2: D7 D5           STB     flashCount          ; ... player word flash counter
C5E4: C6 58           LDB     #$58                ; Y coordinate of player word
C5E6: 0D B6           TST     player              ; Player one?
C5E8: 26 12           BNE     $C5FC               ; No ... go to player one
C5EA: 86 18           LDA     #$18                ; X coordinate of player "one"
C5EC: 03 D6           COM     flashType           ; Value was zero?
C5EE: 26 06           BNE     $C5F6               ; Yes ... erase the word
C5F0: 33 8D 06 89     LEAU    StrOne,PC           ; No ... print the word
C5F4: 20 16           BRA     $C60C               ; Go print and out
C5F6: 33 8D 06 31     LEAU    GenericEraser,PC    ; Erase the word
C5FA: 20 10           BRA     $C60C               ; Go erase and out
;
C5FC: 86 52           LDA     #$52                ; X coordinate for "two"
C5FE: 03 D6           COM     flashType           ; Value was zero?
C600: 26 06           BNE     $C608               ; Yes ... erase the word
C602: 33 8D 06 98     LEAU    StrTwo,PC           ; No ... print the word
C606: 20 04           BRA     $C60C               ; Go print and out
C608: 33 8D 06 1F     LEAU    GenericEraser,PC    ; Erase graphics
C60C: 17 03 34        LBSR    PrintChars          ; Draw whatever graphics
C60F: 39              RTS                         ; Done

Print Scores

Number are drawn with 4x5 pixel patterns (see the images below). The right most column is always blank for spacing.

Both scores are printed at the same time (or just one for 1-player game).

PrintScores:
C610: C6 FF           LDB     #$FF                ; White background chars ...
C612: D7 C5           STB     digitColor          ; ... for score digits
C614: DC B7           LDD     p1Score             ; Player one score
C616: CE 0F 2B        LDU     #$0F2B              ; Location of player one score on screen
C619: 17 00 0F        LBSR    DrawNumber          ; Print player one score
C61C: 0D B4           TST     numPlayers          ; Is there a second player?
C61E: 27 08           BEQ     $C628               ; No ... skip player two score
C620: DC B9           LDD     p2Score             ; Player two score
C622: CE 0F 3A        LDU     #$0F3A              ; Location of player two score on screen
C625: 17 00 03        LBSR    DrawNumber          ; Print the player two score
C628: 0F C5           CLR     digitColor          ; Default back to black background chars
C62A: 39              RTS                         ; Done

Draw Number

This code breaks a 2-byte word into 5 printed digits. Much of the work is brute-force. Numbers are always drawn with a trailing 0; every value is shown multiplied by 10. Space invaders did this too to make the scores look bigger.

The maximum printed number is thus 655360 with the trailing zero.

The code drops leading 0s at it prints. The code does not preserve the screen bits around the digits.

DrawNumber:
; Numbers are kept in words ... max value 65_536. Max 5 digits.
; An extra "0" is always added to the end of the number (multiply by 10)
C62B: 10 83 27 10     CMPD    #$2710              ; Decimal 10_000
C62F: 24 14           BHS     $C645               ; Handle digits
C631: 10 83 03 E8     CMPD    #$03E8              ; Decimal 1_000
C635: 24 13           BHS     $C64A               ; Handle 4 digits
C637: 10 83 00 64     CMPD    #$0064              ; Decimal 100
C63B: 24 12           BHS     $C64F               ; Handle 3 digits
C63D: 10 83 00 0A     CMPD    #$000A              ; Decimal 10
C641: 24 11           BHS     $C654               ; Handle 2 digit
C643: 20 14           BRA     $C659               ; Just one digit
;
C645: 8E 27 10        LDX     #$2710              ; Base amount 10000
C648: 8D 19           BSR     $C663               ; Draw digit picture
C64A: 8E 03 E8        LDX     #$03E8              ; Base amount 1000
C64D: 8D 14           BSR     $C663               ; Draw digit picture
C64F: 8E 00 64        LDX     #$0064              ; Base amount 100
C652: 8D 0F           BSR     $C663               ; Draw digit picture
C654: 8E 00 0A        LDX     #$000A              ; Base amount 10
C657: 8D 0A           BSR     $C663               ; Draw digit picture
C659: 8E 00 01        LDX     #$0001              ; Base amount 1
C65C: 8D 05           BSR     $C663               ; Draw digit picture
C65E: 4F              CLRA                        ; Add a ...
C65F: 5F              CLRB                        ; ... zero to everything
C660: 8D 01           BSR     $C663               ; Print 0
C662: 39              RTS                         ; Done
;
C663: 34 10           PSHS    X                   ; Hold the value
C665: 30 8D 00 78     LEAX    Digit0,PC           ; Graphics for "0"
C669: A3 E4           SUBD    ,S                  ; Subtract off base amount
C66B: 25 46           BLO     $C6B3               ; This is the digit
C66D: 30 8D 00 75     LEAX    Digit1,PC           ; Graphics for "1"
C671: A3 E4           SUBD    ,S                  ; Subtract off base amount
C673: 25 3E           BLO     $C6B3               ; This is the digit
C675: 30 8D 00 72     LEAX    Digit2,PC           ; Graphics for "2"
C679: A3 E4           SUBD    ,S                  ; Subtract off base amount
C67B: 25 36           BLO     $C6B3               ; This is the digit
C67D: 30 8D 00 6F     LEAX    Digit3,PC           ; Graphics for "3"
C681: A3 E4           SUBD    ,S                  ; Subtract off base amount
C683: 25 2E           BLO     $C6B3               ; This is the digit
C685: 30 8D 00 6C     LEAX    Digit4,PC           ; Graphics for "4"
C689: A3 E4           SUBD    ,S                  ; Subtract off base amount
C68B: 25 26           BLO     $C6B3               ; This is the digit
C68D: 30 8D 00 69     LEAX    Digit5,PC           ; Graphics for "5"
C691: A3 E4           SUBD    ,S                  ; Subtract off base amount
C693: 25 1E           BLO     $C6B3               ; This is the digit
C695: 30 8D 00 66     LEAX    Digit6,PC           ; Graphics for "6"
C699: A3 E4           SUBD    ,S                  ; Subtract off base amount
C69B: 25 16           BLO     $C6B3               ; This is the digit
C69D: 30 8D 00 63     LEAX    Digit7,PC           ; Graphics for "7"
C6A1: A3 E4           SUBD    ,S                  ; Subtract off base amount
C6A3: 25 0E           BLO     $C6B3               ; This is the digit
C6A5: 30 8D 00 60     LEAX    Digit8,PC           ; Graphics for "8"
C6A9: A3 E4           SUBD    ,S                  ; Subtract off base amount
C6AB: 25 06           BLO     $C6B3               ; This is the digit
C6AD: 30 8D 00 5D     LEAX    Digit9,PC           ; Graphics for "9"
C6B1: A3 E4           SUBD    ,S                  ; Subtract off base amount
C6B3: E3 E4           ADDD    ,S                  ; Add one base amount back (we overshot above)
C6B5: 34 06           PSHS    B,A                 ; Hold the value
C6B7: E6 84           LDB     ,X                  ; Get first row data
C6B9: 54              LSRB                        ; Everything drawn in color "01" (not sure why it wasn't defined that way to begin with)
C6BA: D8 C5           EORB    digitColor          ; Flip the color if needed
C6BC: E7 C0           STB     ,U+                 ; Store to screen
C6BE: E6 01           LDB     1,X                 ; Repeat ...
C6C0: 54              LSRB                        ; ... with ...
C6C1: D8 C5           EORB    digitColor          ; ... next ...
C6C3: E7 C8 1F        STB     $1F,U               ; ... row
C6C6: E6 02           LDB     2,X                 ; Repeat ...
C6C8: 54              LSRB                        ; ... with ...
C6C9: D8 C5           EORB    digitColor          ; ... next ...
C6CB: E7 C8 3F        STB     $3F,U               ; ... row
C6CE: E6 03           LDB     3,X                 ; Repeat ...
C6D0: 54              LSRB                        ; ... with ...
C6D1: D8 C5           EORB    digitColor          ; ... next ...
C6D3: E7 C8 5F        STB     $5F,U               ; ... row
C6D6: E6 04           LDB     4,X                 ; Repeat ...
C6D8: 54              LSRB                        ; ... with ...
C6D9: D8 C5           EORB    digitColor          ; ... next ...
C6DB: E7 C8 7F        STB     $7F,U               ; ... row
C6DE: 35 16           PULS    A,B,X               ; Restore
C6E0: 39              RTS                         ; Done

Digit Graphics

Digit0:
; ..#.....
; #...#...
; #...#...
; #...#...
; ..#.....
C6E1: 20 88 88 88 20 

Digit1:
; ..#.....
; #.#.....
; ..#.....
; ..#.....
; #.#.#...
C6E6: 20 A0 20 20 A8

Digit2:
; ..#.....
; #...#...
; ....#...
; ..#.....
; #.#.#...
C6EB: 20 88 08 20 A8 

Digit3:
; #.#.#...
; ....#...
; ..#.#...
; ....#...
; #.#.#...
C6F0: A8 08 28 08 A8 

Digit4:
; #.......
; #...#...
; #...#...
; #.#.#...
; ....#...
C6F5: 80 88 88 A8 08            

Digit5:
; #.#.#...
; #.......
; ..#.....
; ....#...
; #.#.....
C6FA: A8 80 20 08 A0 

Digit6:
; #.#.#...
; #.......
; #.#.#...
; #...#...
; #.#.#...
C6FF: A8 80 A8 88 A8 

Digit7:
; #.#.#...
; ....#...
; ....#...
; ..#.....
; ..#.....
C704: A8 08 08 20 20 

Digit8:
; #.#.#...
; #...#...
; #.#.#...
; #...#...
; #.#.#...
C709: A8 88 A8 88 A8 

Digit9:
; ..#.....
; #...#...
; ..#.#...
; ....#...
; #.#.....
C70E: 20 88 28 08 A0 

Draw and Erase the Loop Score

This code checks to see if there is a loop-score showing before taking action.

DrawLoopScore:
; If there is a loop score, draw it
C713: 0D C7           TST     hasLoopScore        ; Is there a value?
C715: 27 07           BEQ     $C71E               ; No ... skip drawing it
C717: DE CC           LDU     loopScoreLoc        ; Screen coordinate
C719: DC CA           LDD     loopScoreShown      ; Value
C71B: 17 FF 0D        LBSR    DrawNumber          ; Draw number
C71E: 39              RTS                         ; Done

EraseLoopScore:
C71F: 0D C7           TST     hasLoopScore        ; Is there a value?
C721: 27 2A           BEQ     $C74D               ; No ... skip erasing it
C723: DE CC           LDU     loopScoreLoc        ; Screen coordinate
C725: DC CA           LDD     loopScoreShown      ; Value
C727: 10 83 27 10     CMPD    #$2710              ; Decimal 10_000
C72B: 24 14           BHS     $C741               ; Erase 6 digits
C72D: 10 83 03 E8     CMPD    #$03E8              ; Decimal 1_000
C731: 24 10           BHS     $C743               ; Erase 5 digits
C733: 10 83 00 64     CMPD    #$0064              ; Decimal 100
C737: 24 0C           BHS     $C745               ; Erase 4 digits
C739: 10 83 00 0A     CMPD    #$000A              ; Decimal 10
C73D: 24 08           BHS     $C747               ; Erase 3 digits
C73F: 20 08           BRA     $C749               ; Erase 2 digits

Erase a Number

This is very similar brute-force logic as drawing a number, except here the screen area is erased.

Note this is only ever called when erasing the loop score. The only other numbers on the screen are the scores, and they are just overwritten without being erased first.

; Erase number of digits
C741: 8D 0B           BSR     EraseDigit          ; Erase 1 digit and advance
C743: 8D 09           BSR     EraseDigit          ; Erase 1 digit and advance
C745: 8D 07           BSR     EraseDigit          ; Erase 1 digit and advance
C747: 8D 05           BSR     EraseDigit          ; Erase 1 digit and advance
C749: 8D 03           BSR     EraseDigit          ; Erase 1 digit and advance
C74B: 8D 01           BSR     EraseDigit          ; Erase 1 digit and advance
C74D: 39              RTS                         ; Done

EraseDigit:
; Erase the digit and advance U to next digit start
C74E: 6F C0           CLR     ,U+                 ; Erase 1st line and advance U
C750: 6F C8 1F        CLR     $1F,U               ; Erase 2nd line
C753: 6F C8 3F        CLR     $3F,U               ; Erase 3rd line
C756: 6F C8 5F        CLR     $5F,U               ; Erase 4th line
C759: 6F C8 7F        CLR     $7F,U               ; Erase 5th line
C75C: 39              RTS                         ; Done

Draw and Erase an 8x8 Pixel Object

This code ORs an 8x8 pixel object onto the screen. A pixel value of 00 in the object is considered transparent, and the existing screen pixels are left alone.

There is a lot of screen-math and shifting here since there are 4 pixels per byte.

Draw8x8:
; X = object pointer (has X,Y coordinate)
; U = pointer to data (8x8 pixels = 16 bytes)
C75D: C6 08           LDB     #$08                ; 8 Rows
C75F: 34 54           PSHS    U,X,B               ; Hold these
C761: 17 02 4E        LBSR    GetScreenAndShift   ; Get pointer to screen memory
C764: 10 8E 03 80     LDY     #$0380              ; Mask table
C768: AE 63           LDX     3,S                 ; Incoming U (data pointer) to X
C76A: 5D              TSTB                        ; 0 means ...
C76B: 10 27 00 CA     LBEQ    $C839               ; ... draw with no shift
C76F: 5A              DECB                        ; 1 means ...
C770: 10 27 00 88     LBEQ    $C7FC               ; ... one pixel shift right
C774: 5A              DECB                        ; 2 means ...
C775: 10 27 00 3E     LBEQ    $C7B7               ; ... two pixel shift right
;
; One pixel shift left (three pixel shift right)
C779: E6 80           LDB     ,X+                 ; First byte of pixel data
C77B: 4F              CLRA                        ; Make it a word with leading 0s
C77C: 58              ASLB                        ; Shift ...
C77D: 49              ROLA                        ; ... left ...
C77E: 58              ASLB                        ; ... one ...
C77F: 49              ROLA                        ; ... pixel
C780: 34 06           PSHS    B,A                 ; Hold this
C782: E6 80           LDB     ,X+                 ; Second byte of pixel data
C784: 4F              CLRA                        ; Make it a word with leading 0s
C785: 58              ASLB                        ; Shift ...
C786: 49              ROLA                        ; ... left ...
C787: 58              ASLB                        ; ... one ...
C788: 49              ROLA                        ; ... pixel
C789: AB 61           ADDA    1,S                 ; Combine pixels ...
C78B: A7 61           STA     1,S                 ; ... in middle byte
C78D: 34 04           PSHS    B                   ; Third byte
C78F: A6 A5           LDA     B,Y                 ; Mask ...
C791: A4 42           ANDA    2,U                 ; ... screen ...
C793: AB E4           ADDA    ,S                  ; ... add pixels ...
C795: A7 42           STA     2,U                 ; ... to screen
C797: E6 62           LDB     2,S                 ; 2nd byte
C799: A6 A5           LDA     B,Y                 ; Mask ...
C79B: A4 41           ANDA    1,U                 ; ... screen ...
C79D: AB 62           ADDA    2,S                 ; ... add pixels ...
C79F: A7 41           STA     1,U                 ; ... to screen
C7A1: E6 61           LDB     1,S                 ; First byte
C7A3: A6 A5           LDA     B,Y                 ; Mask ...
C7A5: A4 C4           ANDA    ,U                  ; ... screen ...
C7A7: AB 61           ADDA    1,S                 ; ... add pixels ...
C7A9: A7 C4           STA     ,U                  ; ... to screen
C7AB: 32 63           LEAS    3,S                 ; Pull the 3-byte temporary
C7AD: 33 C8 20        LEAU    $20,U               ; Next row
C7B0: 6A E4           DEC     ,S                  ; All rows done?
C7B2: 26 C5           BNE     $C779               ; No ... keep going
C7B4: 16 00 A1        LBRA    $C858               ; Yes ... done
;
; Two pixel shift right
C7B7: E6 80           LDB     ,X+                 ; First byte of pixel data
C7B9: 4F              CLRA                        ; Make it a word with leading 0s
C7BA: 54              LSRB                        ; Shift ...
C7BB: 46              RORA                        ; ... right ...
C7BC: 54              LSRB                        ; ... two ...
C7BD: 46              RORA                        ; ...
C7BE: 54              LSRB                        ; ...
C7BF: 46              RORA                        ; ...
C7C0: 54              LSRB                        ; ...
C7C1: 46              RORA                        ; ... pixels
C7C2: 34 06           PSHS    B,A                 ; Hold this
C7C4: E6 80           LDB     ,X+                 ; Second byte of pixel data
C7C6: 4F              CLRA                        ; Make it a word with leading 0s
C7C7: 54              LSRB                        ; Shift ...
C7C8: 46              RORA                        ; ... right ...
C7C9: 54              LSRB                        ; ... two ...
C7CA: 46              RORA                        ; ...
C7CB: 54              LSRB                        ; ...
C7CC: 46              RORA                        ; ...
C7CD: 54              LSRB                        ; ...
C7CE: 46              RORA                        ; ... pixels
C7CF: EB E4           ADDB    ,S                  ; Combine pixels ...
C7D1: E7 E4           STB     ,S                  ; ... in middle byte
C7D3: 34 02           PSHS    A                   ; Third byte
C7D5: A6 A6           LDA     A,Y                 ; Mask ...
C7D7: A4 42           ANDA    2,U                 ; ... screen ...
C7D9: AB E4           ADDA    ,S                  ; ... add pixels ...
C7DB: A7 42           STA     2,U                 ; ... to screen
C7DD: E6 61           LDB     1,S                 ; 2nd byte
C7DF: A6 A5           LDA     B,Y                 ; Mask ...
C7E1: A4 41           ANDA    1,U                 ; ... screen ...
C7E3: AB 61           ADDA    1,S                 ; ... add pixels ...
C7E5: A7 41           STA     1,U                 ; ... to screen
C7E7: E6 62           LDB     2,S                 ; 3rd byte
C7E9: A6 A5           LDA     B,Y                 ; Mask ...
C7EB: A4 C4           ANDA    ,U                  ; ... screen ...
C7ED: AB 62           ADDA    2,S                 ; ... add pixels ...
C7EF: A7 C4           STA     ,U                  ; ... to screen
C7F1: 32 63           LEAS    3,S                 ; Pull the 3-byte temporary
C7F3: 33 C8 20        LEAU    $20,U               ; Next row
C7F6: 6A E4           DEC     ,S                  ; All rows done?
C7F8: 26 BD           BNE     $C7B7               ; No ... keep going
C7FA: 20 5C           BRA     $C858               ; Yes ... done
;
; One pixel shift right
C7FC: E6 80           LDB     ,X+                 ; First byte of pixel data
C7FE: 4F              CLRA                        ; Make it a word with leading 0s
C7FF: 54              LSRB                        ; Shift ...
C800: 46              RORA                        ; ... right ...
C801: 54              LSRB                        ; ... one ...
C802: 46              RORA                        ; ... pixel
C803: 34 06           PSHS    B,A                 ; Hold this
C805: E6 80           LDB     ,X+                 ; Second byte of pixel data
C807: 4F              CLRA                        ; Make it a word with leading 0s
C808: 54              LSRB                        ; Shift ...
C809: 46              RORA                        ; ... right ...
C80A: 54              LSRB                        ; ... one ...
C80B: 46              RORA                        ; ... pixel
C80C: EB E4           ADDB    ,S                  ; Combine pixels ...
C80E: E7 E4           STB     ,S                  ; ... in middle byte
C810: 34 02           PSHS    A                   ; Third byte
C812: A6 A6           LDA     A,Y                 ; Mask ...
C814: A4 42           ANDA    2,U                 ; ... screen ...
C816: AB E4           ADDA    ,S                  ; ... add pixels ...
C818: A7 42           STA     2,U                 ; ... to screen
C81A: E6 61           LDB     1,S                 ; 2nd byte
C81C: A6 A5           LDA     B,Y                 ; Mask ...
C81E: A4 41           ANDA    1,U                 ; ... screen ...
C820: AB 61           ADDA    1,S                 ; ... add pixels ...
C822: A7 41           STA     1,U                 ; ... to screen
C824: E6 62           LDB     2,S                 ; 3rd byte
C826: A6 A5           LDA     B,Y                 ; Mask ...
C828: A4 C4           ANDA    ,U                  ; ... screen ...
C82A: AB 62           ADDA    2,S                 ; ... add pixels ...
C82C: A7 C4           STA     ,U                  ; ... to screen
C82E: 32 63           LEAS    3,S                 ; Pull the 3-byte temporary
C830: 33 C8 20        LEAU    $20,U               ; Next row
C833: 6A E4           DEC     ,S                  ; All rows done?
C835: 26 C5           BNE     $C7FC               ; No ... keep going
C837: 20 1F           BRA     $C858               ; All done
;
; Draw with no shift
C839: EC 81           LDD     ,X++                ; Pixel data
C83B: 34 06           PSHS    B,A                 ; Hold it
C83D: A6 A6           LDA     A,Y                 ; Look up mask for value
C83F: A4 C4           ANDA    ,U                  ; Get pixels from screen
C841: AB E4           ADDA    ,S                  ; Add in the image pixels
C843: A7 C4           STA     ,U                  ; To the screen
C845: E6 61           LDB     1,S                 ; 2nd byte
C847: A6 A5           LDA     B,Y                 ; Look up mask for value
C849: A4 41           ANDA    1,U                 ; Get pixels from screen
C84B: AB 61           ADDA    1,S                 ; Add in the image pixels
C84D: A7 41           STA     1,U                 ; To the screen
C84F: 32 62           LEAS    2,S                 ; Pop the temporaries
C851: 33 C8 20        LEAU    $20,U               ; Next row
C854: 6A E4           DEC     ,S                  ; All rows done?
C856: 26 E1           BNE     $C839               ; No ... keep going
C858: 35 54           PULS    B,X,U               ; Restore
C85A: 39              RTS                         ; Done

Erase8x8:
; X = object pointer (has X,Y coordinate)
; U = pointer to data (8x8 pixels = 16 bytes)
C85B: C6 08           LDB     #$08                ; 8 rows
C85D: 34 54           PSHS    U,X,B               ; Hold these
C85F: 17 01 50        LBSR    GetScreenAndShift   ; Get pointer to screen memory
C862: 10 8E 03 80     LDY     #$0380              ; Mask table
C866: AE 63           LDX     3,S                 ; Incoming U (data pointer) to X
C868: 5D              TSTB                        ; 0 means ...
C869: 10 27 00 B8     LBEQ    $C925               ; ... erase with no shift
C86D: 5A              DECB                        ; 1 means ...
C86E: 10 27 00 7C     LBEQ    $C8EE               ; ... one pixel shift right
C872: 5A              DECB                        ; 2 means ...
C873: 10 27 00 38     LBEQ    $C8AF               ; ... two pixel shift right
;
; One pixel shift left (three pixel shift right)
C877: E6 80           LDB     ,X+                 ; First byte of pixel data
C879: 4F              CLRA                        ; Make it a word with leading 0s
C87A: 58              ASLB                        ; Shift ...
C87B: 49              ROLA                        ; ... left ...
C87C: 58              ASLB                        ; ... one ...
C87D: 49              ROLA                        ; ... pixel
C87E: 34 06           PSHS    B,A                 ; Hold this
C880: E6 80           LDB     ,X+                 ; Second byte of pixel data
C882: 4F              CLRA                        ; Make it a word with leading 0s
C883: 58              ASLB                        ; Shift ...
C884: 49              ROLA                        ; ... left ...
C885: 58              ASLB                        ; ... one ...
C886: 49              ROLA                        ; ... pixel
C887: AB 61           ADDA    1,S                 ; Combine pixels ...
C889: A7 61           STA     1,S                 ; ... in middle byte
C88B: 34 04           PSHS    B                   ; Third byte
C88D: A6 A5           LDA     B,Y                 ; Mask ...
C88F: A4 42           ANDA    2,U                 ; ... screen ...
C891: A7 42           STA     2,U                 ; ... to screen
C893: E6 62           LDB     2,S                 ; 2nd byte
C895: A6 A5           LDA     B,Y                 ; Mask ...
C897: A4 41           ANDA    1,U                 ; ... screen ...
C899: A7 41           STA     1,U                 ; ... to screen
C89B: E6 61           LDB     1,S                 ; 3rd byte
C89D: A6 A5           LDA     B,Y                 ; Mask ...
C89F: A4 C4           ANDA    ,U                  ; ... screen ...
C8A1: A7 C4           STA     ,U                  ; ... to screen
C8A3: 32 63           LEAS    3,S                 ; Pull the 3-byte temporary
C8A5: 33 C8 20        LEAU    $20,U               ; Next row
C8A8: 6A E4           DEC     ,S                  ; All rows done?
C8AA: 26 CB           BNE     $C877               ; No ... keep going
C8AC: 16 00 91        LBRA    $C940               ; yest ... done
;
; Two pixel shift right
C8AF: E6 80           LDB     ,X+                 ; First byte of pixel data
C8B1: 4F              CLRA                        ; Make it a word with leading 0s
C8B2: 54              LSRB                        ; Shift ...
C8B3: 46              RORA                        ; ... right ...
C8B4: 54              LSRB                        ; ... two ...
C8B5: 46              RORA                        ; ...
C8B6: 54              LSRB                        ; ...
C8B7: 46              RORA                        ; ...
C8B8: 54              LSRB                        ; ...
C8B9: 46              RORA                        ; ... pixels
C8BA: 34 06           PSHS    B,A                 ; Hold this
C8BC: E6 80           LDB     ,X+                 ; Second byte of pixel data
C8BE: 4F              CLRA                        ; Shift ...
C8BF: 54              LSRB                        ; ... right ...
C8C0: 46              RORA                        ; ... two
C8C1: 54              LSRB                        ; ...
C8C2: 46              RORA                        ; ...
C8C3: 54              LSRB                        ; ...
C8C4: 46              RORA                        ; ...
C8C5: 54              LSRB                        ; ...
C8C6: 46              RORA                        ; ... pixels
C8C7: EB E4           ADDB    ,S                  ; Combine pixels ...
C8C9: E7 E4           STB     ,S                  ; ... in middle byte
C8CB: 34 02           PSHS    A                   ; Third byte
C8CD: A6 A6           LDA     A,Y                 ; Mask ...
C8CF: A4 42           ANDA    2,U                 ; ... screen ...
C8D1: A7 42           STA     2,U                 ; ... to screen
C8D3: E6 61           LDB     1,S                 ; Second byte
C8D5: A6 A5           LDA     B,Y                 ; Mask ...
C8D7: A4 41           ANDA    1,U                 ; ... screen ...
C8D9: A7 41           STA     1,U                 ; ... to screen
C8DB: E6 62           LDB     2,S                 ; Third byte
C8DD: A6 A5           LDA     B,Y                 ; Mask ...
C8DF: A4 C4           ANDA    ,U                  ; ... screen ...
C8E1: A7 C4           STA     ,U                  ; ... to screen
C8E3: 32 63           LEAS    3,S                 ; Pull the 3-byte temporary
C8E5: 33 C8 20        LEAU    $20,U               ; Next row
C8E8: 6A E4           DEC     ,S                  ; All rows done?
C8EA: 26 C3           BNE     $C8AF               ; No ... keep going
C8EC: 20 52           BRA     $C940               ; Yes ... done
;
; One pixel shift right
C8EE: E6 80           LDB     ,X+                 ; First byte of pixel data
C8F0: 4F              CLRA                        ; Make it a word with leading 0s
C8F1: 54              LSRB                        ; Shift ...
C8F2: 46              RORA                        ; ... right ...
C8F3: 54              LSRB                        ; ... one ...
C8F4: 46              RORA                        ; ... pixel
C8F5: 34 06           PSHS    B,A                 ; Hold this
C8F7: E6 80           LDB     ,X+                 ; Second byte of pixel data
C8F9: 4F              CLRA                        ; Make it a word with leading 0s
C8FA: 54              LSRB                        ; Shift ...
C8FB: 46              RORA                        ; ... right ...
C8FC: 54              LSRB                        ; ... one ...
C8FD: 46              RORA                        ; ... pixel
C8FE: EB E4           ADDB    ,S                  ; Combine pixels ...
C900: E7 E4           STB     ,S                  ; ... in middle byte
C902: 34 02           PSHS    A                   ; Third byte
C904: A6 A6           LDA     A,Y                 ; Mask ...
C906: A4 42           ANDA    2,U                 ; ... screen ...
C908: A7 42           STA     2,U                 ; ... to screen
C90A: E6 61           LDB     1,S                 ; 2nd byte
C90C: A6 A5           LDA     B,Y                 ; Mask ...
C90E: A4 41           ANDA    1,U                 ; ... screen ...
C910: A7 41           STA     1,U                 ; ... to screen
C912: E6 62           LDB     2,S                 ; Third byte
C914: A6 A5           LDA     B,Y                 ; Mask ...
C916: A4 C4           ANDA    ,U                  ; ... screen ...
C918: A7 C4           STA     ,U                  ; ... to screen
C91A: 32 63           LEAS    3,S                 ; Pull the 3 byte temporary
C91C: 33 C8 20        LEAU    $20,U               ; Next row
C91F: 6A E4           DEC     ,S                  ; All rows done?
C921: 26 CB           BNE     $C8EE               ; No ... keep going
C923: 20 1B           BRA     $C940               ; All done
;
; Erase with no shift
C925: EC 81           LDD     ,X++                ; Pixel data
C927: 34 06           PSHS    B,A                 ; Hold it
C929: A6 A6           LDA     A,Y                 ; Look up mask for value
C92B: A4 C4           ANDA    ,U                  ; Mask screen
C92D: A7 C4           STA     ,U                  ; Back to screen
C92F: E6 61           LDB     1,S                 ; 2nd byte
C931: A6 A5           LDA     B,Y                 ; Look up mask for value
C933: A4 41           ANDA    1,U                 ; Mas screen
C935: A7 41           STA     1,U                 ; Back to screen
C937: 32 62           LEAS    2,S                 ; Pop the temporaries
C939: 33 C8 20        LEAU    $20,U               ; Next row
C93C: 6A E4           DEC     ,S                  ; All rows done?
C93E: 26 E5           BNE     $C925               ; No ... keep going
C940: 35 54           PULS    B,X,U               ; Restore
C942: 39              RTS                         ; Done

Print a Sequence of Characters

Characters here are 8x8 tiles that form images on the screen. This is only ever used for printing text areas, but there are no patterns for individual letters. See the actual graphics patterns decoded below.

PrintChars:
; A = X coordinate
; B = Y coordinate
; U = text string
C943: 8E 00 E4        LDX     #$00E4              ; Utility descriptor
C946: A7 84           STA     ,X                  ; Set the X coordinate
C948: E7 02           STB     2,X                 ; Set the Y coordinate
C94A: E6 5F           LDB     -1,U                ; Characters ...
C94C: E7 04           STB     4,X                 ; ... to print
C94E: 17 FE 0C        LBSR    Draw8x8             ; 
C951: 33 C8 10        LEAU    $10,U               ; Next image
C954: A6 84           LDA     ,X                  ; X coordinate
C956: 8B 08           ADDA    #$08                ; Next character ...
C958: A7 84           STA     ,X                  ; ... over
C95A: 6A 04           DEC     4,X                 ; All done?
C95C: 26 F0           BNE     $C94E               ; No ... do all
C95E: 39              RTS                         ; Done

Set and Clear Pixel

These functions manipulate individual pixels by X,Y coordinate. This is used to draw the cursive "doubleback" on the splash screen. And it is used to draw the player's head pixel.

This code captures the pixel value from the screen before overwriting it. This value is used for collision detection for the player.

SetPixel:
C95F: 17 00 50        LBSR    GetScreenAndShift   ; 
C962: A6 C4           LDA     ,U                  ; Value from screen
C964: 5D              TSTB                        ; Shift 0 means ...
C965: 26 0A           BNE     $C971               ; ... upper pixel
C967: 84 3F           ANDA    #$3F                ; Mask off upper pixel ..111111
C969: 1F 89           TFR     A,B                 ; Return the bits ... (used by collision detection))
C96B: E0 C4           SUBB    ,U                  ; ... we removed
C96D: 8A 80           ORA     #$80                ; OR in the upper pixel
C96F: 20 22           BRA     $C993               ; Set and done
;
C971: 5A              DECB                        ; Shift 1 means ...
C972: 26 0A           BNE     $C97E               ; ... 2nd pixel
C974: 84 CF           ANDA    #$CF                ; Mask off the 2nd pixel 11..1111
C976: 1F 89           TFR     A,B                 ; Return the bits ...
C978: E0 C4           SUBB    ,U                  ; ... we removed
C97A: 8A 20           ORA     #$20                ; OR in the 2nd pixel
C97C: 20 15           BRA     $C993               ; Set and done
;
C97E: 5A              DECB                        ; Shift 2 means ...
C97F: 26 0A           BNE     $C98B               ; ... 3rd pixel
C981: 84 F3           ANDA    #$F3                ; Mask off the 3rd pixel 1111..11
C983: 1F 89           TFR     A,B                 ; Return the bits ...
C985: E0 C4           SUBB    ,U                  ; ... we removed
C987: 8A 08           ORA     #$08                ; OR in the 3rd pixel
C989: 20 08           BRA     $C993               ; Set and done
;
C98B: 84 FC           ANDA    #$FC                ; Mask off the last pixel 111111..
C98D: 1F 89           TFR     A,B                 ; Return the bits ...
C98F: E0 C4           SUBB    ,U                  ; ... we removed
C991: 8A 02           ORA     #$02                ; OR in the last pixel
;
C993: A7 C4           STA     ,U                  ; Store pixel to screen
C995: 39              RTS                         ; Done

ErasePixel:
; U = pointer to screen memory
C996: A6 C4           LDA     ,U                  ; Value from the screen
C998: 5D              TSTB                        ; Pixel shift value
C999: 26 04           BNE     $C99F               ; Not 0 (left most pixel) ... try others
C99B: 84 3F           ANDA    #$3F                ; Mask off the left most pixel ..111111
C99D: 20 10           BRA     $C9AF               ; Clear the pixel
C99F: 5A              DECB                        ; Is this the 2nd pixel?
C9A0: 26 04           BNE     $C9A6               ; No ... try the 3rd
C9A2: 84 CF           ANDA    #$CF                ; Mask off the 2nd pixel 11..1111
C9A4: 20 09           BRA     $C9AF               ; Clear the pixel
C9A6: 5A              DECB                        ; Is this the 3rd pixel?
C9A7: 26 04           BNE     $C9AD               ; No ... must be the 4th
C9A9: 84 F3           ANDA    #$F3                ; Mask off the 3rd pixel 1111..11
C9AB: 20 02           BRA     $C9AF               ; Clear the pixel
C9AD: 84 FC           ANDA    #$FC                ; Mask off the 4th pixel 111111..
C9AF: A7 C4           STA     ,U                  ; Clear the pixel on the screen
C9B1: 39              RTS                         ; Done

Get Screen Pointer and Pixel Number

This decodes an X,Y coordinate to a pointer to screen memory. Since each byte of memory holds 4 pixels, this routine also returns the pixel number within that byte.

GetScreenAndShift:
; Ultimately, the equation for screen pointer is: Y*32 + X/4.
; This code cleverly does:
;     (Y*256 + X*2) / 8 =
;     (Y*128 + X) / 4 =
;     Y*32 + X/4
; Input: X pointer to object structure
; Mangle: A, Y
; Return: U screen pointer
; Return: B shift amount
C9B2: E6 84           LDB     ,X                  ; The object's X coordinate
C9B4: A6 02           LDA     2,X                 ; The object's Y coordinate
C9B6: 58              ASLB                        ; D = Y*256 + X*2
C9B7: 47              ASRA                        ; Divide ...
C9B8: 56              RORB                        ; ...
C9B9: 47              ASRA                        ; ...
C9BA: 56              RORB                        ; ...
C9BB: 47              ASRA                        ; ...
C9BC: 56              RORB                        ; ... eight
C9BD: 10 8E 04 00     LDY     #$0400              ; Start of screen memory
C9C1: 33 AB           LEAU    D,Y                 ; Point into screen memory
C9C3: E6 84           LDB     ,X                  ; X coordinate
C9C5: C4 03           ANDB    #$03                ; 4 pixels per byte ... 4 possible shifts
C9C7: 39              RTS                         ; Done

Move an Object by its DeltaX and DeltaY

This function works on the bytes within a single object structure. The X and Y coordinate are considered to be words in the object structure, but the deltas are single bytes.

MoveObject:
; coordinates = coordinates + 8 * delta (with limits)
C9C8: E6 04           LDB     4,X                 ; Word ...
C9CA: 1D              SEX                         ; ... deltaX
C9CB: 58              ASLB                        ; Multiply ...
C9CC: 49              ROLA                        ; ...
C9CD: 58              ASLB                        ; ...
C9CE: 49              ROLA                        ; ... deltaX ...
C9CF: 58              ASLB                        ; ...
C9D0: 49              ROLA                        ; ... by 8
C9D1: E3 84           ADDD    ,X                  ; Add to the 2-byte X coordiante
C9D3: 80 03           SUBA    #$03                ; Temporarily translate for contraining
C9D5: 81 7B           CMPA    #$7B                ; X coordinate too high?
C9D7: 25 07           BLO     $C9E0               ; No ... keep it
C9D9: 86 7A           LDA     #$7A                ; Yes ... constrain it
C9DB: 6D 04           TST     4,X                 ; X coordinate too low?
C9DD: 2A 01           BPL     $C9E0               ; No ... keep it
C9DF: 4F              CLRA                        ; Yes ... constrain it
C9E0: 8B 03           ADDA    #$03                ; Translate back to the right
C9E2: ED 84           STD     ,X                  ; Store X coordinate (integer and fractional)
C9E4: E6 05           LDB     5,X                 ; Word ...
C9E6: 1D              SEX                         ; ... deltaY
C9E7: 58              ASLB                        ; Multiply ...
C9E8: 58              ASLB                        ; ...
C9E9: 58              ASLB                        ; ... ?? why no ROLA
C9EA: 49              ROLA                        ; ... by 8
C9EB: E3 02           ADDD    2,X                 ; Add to the 2-byte Y coordinate
C9ED: 80 03           SUBA    #$03                ; Temporarily translate for constraining
C9EF: 81 53           CMPA    #$53                ; Y coordinate too high?
C9F1: 25 07           BLO     $C9FA               ; No ... keep it
C9F3: 86 52           LDA     #$52                ; Yes ... constrain it
C9F5: 6D 05           TST     5,X                 ; Y coordinate too low?
C9F7: 2A 01           BPL     $C9FA               ; No ... keep it
C9F9: 4F              CLRA                        ; Yes ... constrain it
C9FA: 8B 03           ADDA    #$03                ; Translate back down
C9FC: ED 02           STD     2,X                 ; Store Y coordinate (integer and fractional)
C9FE: 39              RTS                         ; Done

Follow the Player

This code moves the given object towards the player's head point. The absolute delta speeds are given in A and B. The code changes the sign as needed.

FollowPlayer:
; X = object to move
C9FF: A7 04           STA     4,X                 ; Store the deltaX ...
CA01: E7 05           STB     5,X                 ; ... and deltaY
CA03: CE 00 D8        LDU     #$00D8              ; Player object to U
CA06: A6 84           LDA     ,X                  ; Objects are 8 pixels wide. Get ...
CA08: 8B 04           ADDA    #$04                ; ... the center X of the object
CA0A: A7 84           STA     ,X                  ; Update coordinate
CA0C: A0 C4           SUBA    ,U                  ; Compare object X to player X
CA0E: 2B 07           BMI     $CA17               ; Object X is less ... keep deltaX
CA10: 60 04           NEG     4,X                 ; Reverse direction on deltaX
CA12: 4D              TSTA                        ; Are the coordinates the same?
CA13: 26 02           BNE     $CA17               ; No ... keep this
CA15: 6F 04           CLR     4,X                 ; Yes ... no movement on X axis
;
CA17: E6 04           LDB     4,X                 ; DeltaX to B
CA19: A6 02           LDA     2,X                 ; Objects are 8 pixels tall. Get ...
CA1B: 8B 04           ADDA    #$04                ; ... the center Y of the object
CA1D: A7 02           STA     2,X                 ; Update coordinate
CA1F: A0 42           SUBA    2,U                 ; Compare object Y to player Y
CA21: 2B 07           BMI     $CA2A               ; Object Y is less ... keep deltaY
CA23: 60 05           NEG     5,X                 ; Reverse direction on deltaY
CA25: 4D              TSTA                        ; Are the coordinates the same?
CA26: 26 02           BNE     $CA2A               ; No ... keep this
CA28: 6F 05           CLR     5,X                 ; Yes ... no movement on Y axis
;
CA2A: 17 FF 9B        LBSR    MoveObject          ; Move the object towards the player
CA2D: A6 84           LDA     ,X                  ; X coordinate
CA2F: 80 04           SUBA    #$04                ; Translate back to upper left corner
CA31: 81 03           CMPA    #$03                ; Is coordinate too small?
CA33: 2C 02           BGE     $CA37               ; No ... keep it.
CA35: 86 03           LDA     #$03                ; Yes ... constrain to X>=3
CA37: 81 76           CMPA    #$76                ; Is coordinate too big?
CA39: 2F 02           BLE     $CA3D               ; No ... keep it
CA3B: 86 76           LDA     #$76                ; Yes ... constrain to X<=118
CA3D: A7 84           STA     ,X                  ; Update the object's X coordiante
CA3F: A6 02           LDA     2,X                 ; Get the Y coordinate
CA41: 80 04           SUBA    #$04                ; Translate back to the upper left corner
CA43: 81 03           CMPA    #$03                ; Is coordinate too small?
CA45: 2C 02           BGE     $CA49               ; No ... keep it.
CA47: 86 03           LDA     #$03                ; Yes ... constrain to Y>=3
CA49: 81 4E           CMPA    #$4E                ; Is coordinate too big?
CA4B: 2F 02           BLE     $CA4F               ; No ... keep it
CA4D: 86 4E           LDA     #$4E                ; Yes ... constrain to Y<=78
CA4F: A7 02           STA     2,X                 ; Update the object's Y coordinate
CA51: 39              RTS                         ; Done

ClearScreen:
CA52: 5F              CLRB                        ; Clear value is black
FillScreen:
CA53: CE 04 00        LDU     #$0400              ; Start of screen
CA56: 33 C9 0C 00     LEAU    $0C00,U             ; Now to the end of screen
CA5A: E7 C2           STB     ,-U                 ; Store value ...
CA5C: 11 83 04 00     CMPU    #$0400              ; ... to the ...
CA60: 22 F8           BHI     $CA5A               ; ... screen
CA62: 39              RTS                         ; Done

DrawPlayfiled:
CA63: CE 04 00        LDU     #$0400              ; Start of screen
CA66: 33 C8 60        LEAU    $60,U               ; 3rd row down
CA69: 86 53           LDA     #$53                ; 83 rows in the playfield
CA6B: C6 F0           LDB     #$F0                ; 2 pixels on the left ...
CA6D: E7 C0           STB     ,U+                 ; ... are white
CA6F: C6 1E           LDB     #$1E                ; Clear ...
CA71: 6F C0           CLR     ,U+                 ; ... 30 columns ...
CA73: 5A              DECB                        ; ... on each ...
CA74: 26 FB           BNE     $CA71               ; ... row
CA76: C6 0F           LDB     #$0F                ; 2 pixels on the right ...
CA78: E7 C0           STB     ,U+                 ; ... are white
CA7A: 4A              DECA                        ; Do ...
CA7B: 26 EE           BNE     $CA6B               ; ... all rows
CA7D: 39              RTS                         ; Done

Play Song

PlaySong:
CA7E: 7F FF 20        CLR     PIA1_DA             ; D/A to 0
CA81: BD A9 76        JSR     $A976               ; Enable analog mux
CA84: 17 00 39        LBSR    CheckForBreak       ; 
CA87: EC C1           LDD     ,U++                ; Get next data
CA89: 27 34           BEQ     $CABF               ; No more ... done
CA8B: 34 06           PSHS    B,A                 ; Audio timing magic
CA8D: 1F 98           TFR     B,A                 ; Audio timing magic
CA8F: 4A              DECA                        ; Delay amount
CA90: 1E 11           EXG     X,X                 ; Small ...
CA92: 1E 11           EXG     X,X                 ; ...
CA94: 1E 11           EXG     X,X                 ; ...
CA96: 1E 11           EXG     X,X                 ; ... delay
CA98: 26 F5           BNE     $CA8F               ; Finish the delay
CA9A: 86 3C           LDA     #$3C                ; 6 bit D/A to ...
CA9C: B7 FF 20        STA     PIA1_DA             ; ... 111100
CA9F: 1F 98           TFR     B,A                 ; Audio timing magic
CAA1: A0 61           SUBA    1,S                 ; Audio timing magic
CAA3: 43              COMA                        ; Audio timing magic
CAA4: 4A              DECA                        ; Delay amount
CAA5: 1E 11           EXG     X,X                 ; Small ...
CAA7: 1E 11           EXG     X,X                 ; ...
CAA9: 1E 11           EXG     X,X                 ; ...
CAAB: 1E 11           EXG     X,X                 ; ... delay
CAAD: 26 F5           BNE     $CAA4               ; Finish the delay
CAAF: 7F FF 20        CLR     PIA1_DA             ; D/A to 0
CAB2: 5A              DECB                        ; Audio timing magic
CAB3: 26 02           BNE     $CAB7               ; Audio timing magic
CAB5: E6 61           LDB     1,S                 ; Audio timing magic
CAB7: 6A E4           DEC     ,S                  ; Audio timing magic
CAB9: 26 D2           BNE     $CA8D               ; Audio timing magic
CABB: 35 06           PULS    A,B                 ; Audio timing magic
CABD: 20 BF           BRA     PlaySong            ; Play until end
CABF: 39              RTS                         ; Done

CheckForBreak:
CAC0: C6 FB           LDB     #$FB                ; All high but ...
CAC2: F7 FF 02        STB     PIA0_DB             ; ... BREAK column
CAC5: F6 FF 00        LDB     PIA0_DA             ; Read keyboard rows
CAC8: C4 40           ANDB    #$40                ; Is BREAK row low?
CACA: 10 27 F5 36     LBEQ    Reset               ; Yes ...break is pressed ... restart
CACE: 39              RTS                         ; Break not pressed ... continue

SetVideoMode:
; Set mode 128x96 Color Graphics
; Set display offset to $400
; V2 V1 V0 7 6 5 4 3 2 1 0
;  1  0  0 1 1 1 1 1 x x x
CACF: 8D 1E           BSR     WaitVBlank          ; Wait for VBLANK
CAD1: 8E FF C6        LDX     #$FFC6              ; Set ...
CAD4: E7 84           STB     ,X                  ; ... display ... 000010
CAD6: E7 03           STB     3,X                 ; ... offset to ...
CAD8: E7 04           STB     4,X                 ; ... 00010 ...
CADA: E7 06           STB     6,X                 ; ... 0.5K * 2 = 1K ...
CADC: E7 08           STB     8,X                 ; ... ...
CADE: E7 0A           STB     10,X                ; ... address=$400
CAE0: F7 FF C0        STB     dispMode            ; V0=0
CAE3: F7 FF C2        STB     dispMode+2          ; V1=0
CAE6: F7 FF C5        STB     dispMode+5          ; V2=1 (Mode 100 = G3C)
CAE9: C6 F8           LDB     #$F8                ; Bright screen ...
CAEB: F7 FF 22        STB     PIA1_DB             ; ... color mode
CAEE: 39              RTS                         ; Cone

WaitVBlank:
CAEF: 7D FF 02        TST     PIA0_DB             ; ??? why read the keyboard register? It doesn't clear anything
CAF2: 0C D7           INC     random              ; ?? randomness?
CAF4: 7D FF 03        TST     PIA0_CB             ; Wait for ...
CAF7: 2A F9           BPL     $CAF2               ; ... vertical blank
CAF9: 39              RTS                         ; Cone

Data From Here Down

Game Objects

ImageApple:
; Object type 1
CAFA: 00 80 ; ....2...
CAFC: 16 50 ; .11211..
CAFE: 55 54 ; 1111111.
CB00: 55 D4 ; 1111311.
CB02: 55 D4 ; 1111311.
CB04: 15 50 ; .11111..
CB06: 05 40 ; ..111...
CB08: 00 00 ; ........

ImageCherry:
; Object type 2
CB0A: 00 20 ; .....2..
CB0C: 00 80 ; ....2...
CB0E: 02 20 ; ...2.2..
CB10: 08 14 ; ..2..11.
CB12: 14 5D ; .11.1131
CB14: 5D 55 ; 11311111
CB16: 55 14 ; 1111.11.
CB18: 14 00 ; .11.....

ImageMagnet:
; Object type 3
CB1A: 0A A0 ; ..2222..
CB1C: 2A A8 ; .222222.
CB1E: A8 2A ; 222..222
CB20: A0 0A ; 22....22
CB22: A0 0A ; 22....22
CB24: A0 0A ; 22....22
CB26: 28 28 ; .22..22.
CB28: 28 28 ; .22..22.

ImageSkate: 
; Object type 4
; 2 images
CB2A: FC 00 ; 333.....
CB2C: F7 00 ; 3313....
CB2E: FF 74 ; 3333131.
CB30: FF FF ; 33333333
CB32: 55 55 ; 11111111
CB34: 10 04 ; .1....1.
CB36: 54 15 ; 111..111
CB38: 10 04 ; .1....1.
;
CB3A: FC 00 ; 333.....
CB3C: F7 00 ; 3313....
CB3E: FF 74 ; 3333131.
CB40: FF FF ; 33333333
CB42: 55 55 ; 11111111
CB44: 44 11 ; 1.1..1.1
CB46: 10 04 ; .1....1.
CB48: 44 11 ; 1.1..1.1

ImageYoYo:
; Object type 5
; 5 images
CB4A: 00 10 ; .....1..
CB4C: 0A 90 ; ..2221..
CB4E: 2A A0 ; .22222..
CB50: AA A8 ; 2222222.
CB52: FF FC ; 3333333.
CB54: AA A8 ; 2222222.
CB56: 2A A0 ; .22222..
CB58: 0A 80 ; ..222...
;
CB5A: 00 10 ; .....1..
CB5C: 0A 90 ; ..2221..
CB5E: 2A B0 ; .22223..
CB60: AA E8 ; 2222322.
CB62: AB A8 ; 2223222.
CB64: AE A8 ; 2232222.
CB66: 3A A0 ; .32222..
CB68: 0A 80 ; ..222...
;
CB6A: 00 10 ; .....1..
CB6C: 0B 90 ; ..2321..
CB6E: 2B A0 ; .22322..
CB70: AB A8 ; 2223222.
CB72: AB A8 ; 2223222.
CB74: AB A8 ; 2223222.
CB76: 2B A0 ; .22322..
CB78: 0B 80 ; ..232...
;
CB7A: 00 10 ; .....1..
CB7C: 0A 90 ; ..2221..
CB7E: 3A A0 ; .32222..
CB80: AE A8 ; 2232222.
CB82: AB A8 ; 2223222.
CB84: AA E8 ; 2222322.
CB86: 2A B0 ; .22223..
CB88: 0A 80 ; ..222...
;
CB8A: 00 00 ; ........
CB8C: 0A 80 ; ..222...
CB8E: 2A A0 ; .22222..
CB90: AA A8 ; 2222222.
CB92: AA A8 ; 2222222.
CB94: AA A8 ; 2222222.
CB96: 2A A0 ; .22222..
CB98: 0A 80 ; ..222...

StringEraser:
CB9A: 00 30 ; .....3..
CB9C: 00 30 ; .....3..
CB9E: 00 30 ; .....3..
CBA0: 00 30 ; .....3..
CBA2: 00 30 ; .....3..
CBA4: 00 30 ; .....3..
CBA6: 00 30 ; .....3..
CBA8: 00 30 ; .....3..

ImageSkull:
; Object type 8
CBAA: 0F C0 ; ..333...
CBAC: 3F F0 ; .33333..
CBAE: 37 70 ; .31313..
CBB0: 3F F0 ; .33333..
CBB2: 0F C0 ; ..333...
CBB4: CF CC ; 3.333.3.
CBB6: 30 30 ; .3...3..
CBB8: C0 0C ; 3.....3.

ImagePear:
; Object type 6
CBBA: 00 10 ; .....1..
CBBC: 00 40 ; ....1...
CBBE: 00 C0 ; ....3...
CBC0: 03 C0 ; ...33...
CBC2: 0F F0 ; ..3333..
CBC4: 3F F0 ; .33333..
CBC6: 3F F0 ; .33333..
CBC8: 0F C0 ; ..333...

ImageSpider:
; Object type 7
; 2 images
CBCA: 04 10 ; ..1..1..
CBCC: 44 11 ; 1.1..1.1
CBCE: 12 84 ; .1.22.1.
CBD0: 06 90 ; ..1221..
CBD2: 06 90 ; ..1221..
CBD4: 12 84 ; .1.22.1.
CBD6: 42 81 ; 1..22..1
CBD8: 40 01 ; 1......1
;
CBDA: 04 10 ; ..1..1..
CBDC: 04 10 ; ..1..1..
CBDE: 02 80 ; ...22...
CBE0: 56 95 ; 11122111
CBE2: 02 80 ; ...22...
CBE4: 16 94 ; .112211.
CBE6: 42 81 ; 1..22..1
CBE8: 00 00 ; ........

ImageX:
; Object type 9
; 2 images
CBEA: 00 00 ; ........
CBEC: 00 00 ; ........
CBEE: 08 20 ; ..2..2..
CBF0: 02 80 ; ...22...
CBF2: 02 80 ; ...22...
CBF4: 08 20 ; ..2..2..
CBF6: 00 00 ; ........
CBF8: 00 00 ; ........
;
CBFA: 80 02 ; 2......2
CBFC: 20 08 ; .2....2.
CBFE: 08 20 ; ..2..2..
CC00: 02 80 ; ...22...
CC02: 02 80 ; ...22...
CC04: 08 20 ; ..2..2..
CC06: 20 08 ; .2....2.
CC08: 80 02 ; 2......2

LifeIndicator:
; Inactive
CC0A: AA 80 ; 22222...
CC0C: 00 00 ; ........
CC0E: 00 00 ; ........
CC10: 00 00 ; ........
CC12: 00 00 ; ........
CC14: 00 00 ; ........
CC16: 00 00 ; ........
CC18: 00 00 ; ........
; Active
CC1A: 55 40 ; 11111...
CC1C: 00 00 ; ........
CC1E: 00 00 ; ........
CC20: 00 00 ; ........
CC22: 00 00 ; ........
CC24: 00 00 ; ........
CC26: 00 00 ; ........
CC28: 00 00 ; ........

CC2A: 02 ; 2 tiles
GenericEraser:
; 3333333333333333
; 3333333333333333
; 3333333333333333
; 3333333333333333
; 3333333333333333
; 3333333333333333
; 3333333333333333
; 3333333333333333
;
CC2B: FF FF ; 33333333
CC2D: FF FF ; 33333333
CC2F: FF FF ; 33333333
CC31: FF FF ; 33333333
CC33: FF FF ; 33333333
CC35: FF FF ; 33333333
CC37: FF FF ; 33333333
CC39: FF FF ; 33333333
;
CC3B: FF FF ; 33333333
CC3D: FF FF ; 33333333
CC3F: FF FF ; 33333333
CC41: FF FF ; 33333333
CC43: FF FF ; 33333333
CC45: FF FF ; 33333333
CC47: FF FF ; 33333333
CC49: FF FF ; 33333333

Text Areas

CC4B: 03 ; 3 tiles
StrPlayer:
; .....1..................
; .....1..................
; 111..1..11.......11..111
; 1..1.1...1.1..1.1111.1..
; 1..1.1.111.1..1.1....1..
; 111..1.111..111..11..1..
; 1.............1.........
; 1..........111..........
;
CC4C: 00 10 ; .....1..
CC4E: 00 10 ; .....1..
CC50: 54 10 ; 111..1..
CC52: 41 10 ; 1..1.1..
CC54: 41 11 ; 1..1.1.1
CC56: 54 11 ; 111..1.1
CC58: 40 00 ; 1.......
CC5A: 40 00 ; 1.......
;
CC5C: 00 00 ; ........
CC5E: 00 00 ; ........
CC60: 50 00 ; 11......
CC62: 11 04 ; .1.1..1.
CC64: 51 04 ; 11.1..1.
CC66: 50 54 ; 11..111.
CC68: 00 04 ; ......1.
CC6A: 01 50 ; ...111..
;
CC6C: 00 00 ; ........
CC6E: 00 00 ; ........
CC70: 14 15 ; .11..111
CC72: 55 10 ; 1111.1..
CC74: 40 10 ; 1....1..
CC76: 14 10 ; .11..1..
CC78: 00 00 ; ........
CC7A: 00 00 ; ........
CC7C: 02 ; 2 tiles
StrOne:
; ................
; ................
; ...11..111...11.
; ..1..1.1..1.1111
; ..1..1.1..1.1...
; ...11..1..1..11.
; ................
; ................
;
CC7D: 00 00 ; ........
CC7F: 00 00 ; ........
CC81: 01 41 ; ...11..1
CC83: 04 11 ; ..1..1.1
CC85: 04 11 ; ..1..1.1
CC87: 01 41 ; ...11..1
CC89: 00 00 ; ........
CC8B: 00 00 ; ........
;
CC8D: 00 00 ; ........
CC8F: 00 00 ; ........
CC91: 50 14 ; 11...11.
CC93: 04 55 ; ..1.1111
CC95: 04 40 ; ..1.1...
CC97: 04 14 ; ..1..11.
CC99: 00 00 ; ........
CC9B: 00 00 ; ........
CC9D: 02 ; 2 tiles
StrTwo:
; ................
; .1..............
; 111..1..1..11...
; .1...1..1.1..1..
; .1.1.1111.1..1..
; ..1..1111..11...
; ................
; ................
;
CC9E: 00 00 ; ........
CCA0: 10 00 ; .1......
CCA2: 54 10 ; 111..1..
CCA4: 10 10 ; .1...1..
CCA6: 11 15 ; .1.1.111
CCA8: 04 15 ; ..1..111
CCAA: 00 00 ; ........
CCAC: 00 00 ; ........
;
CCAE: 00 00 ; ........
CCB0: 00 00 ; ........
CCB2: 41 40 ; 1..11...
CCB4: 44 10 ; 1.1..1..
CCB6: 44 10 ; 1.1..1..
CCB8: 41 40 ; 1..11...
CCBA: 00 00 ; ........
CCBC: 00 00 ; ........
CCBE: 05 ; 5 tiles
StrGameOver:
; ..33333333333333333333333333333333333...
; .3333333333333333333333333333333333333..
; 332233322322223322333332233232332233222.
; 323323332322223222233323323232322223233.
; 323323222323323233333323323323323333233.
; 332223222323323322333332233323332233233.
; .3332333333333333333333333333333333333..
; .222333333333333333333333333333333333...
;
CCBF: 0F FF ; ..333333
CCC1: 3F FF ; .3333333
CCC3: FA FE ; 33223332
CCC5: EF BF ; 32332333
CCC7: EF BA ; 32332322
CCC9: FA BA ; 33222322
CCCB: 3F BF ; .3332333
CCCD: 2A FF ; .2223333
;
CCCF: FF FF ; 33333333
CCD1: FF FF ; 33333333
CCD3: BA AF ; 23222233
CCD5: BA AE ; 23222232
CCD7: BB EE ; 23233232
CCD9: BB EF ; 23233233
CCDB: FF FF ; 33333333
CCDD: FF FF ; 33333333
;
CCDF: FF FF ; 33333333
CCE1: FF FF ; 33333333
CCE3: AF FE ; 22333332
CCE5: AB FB ; 22233323
CCE7: FF FB ; 33333323
CCE9: AF FE ; 22333332
CCEB: FF FF ; 33333333
CCED: FF FF ; 33333333
;
CCEF: FF FF ; 33333333
CCF1: FF FF ; 33333333
CCF3: BE EF ; 23323233
CCF5: EE EE ; 32323232
CCF7: EF BE ; 32332332
CCF9: BF BF ; 23332333
CCFB: FF FF ; 33333333
CCFD: FF FF ; 33333333
;
CCFF: FF C0 ; 33333...
CD01: FF F0 ; 333333..
CD03: AF A8 ; 2233222.
CD05: AB BC ; 2223233.
CD07: FF BC ; 3333233.
CD09: AF BC ; 2233233.
CD0B: FF F0 ; 333333..
CD0D: FF C0 ; 33333...
CD0F: 06 ; Six tiles
Str1or2Players:
;. 3...........33.........1.......................
; 33..111.11..3..3...111..1.......................
; .3..1.1.1.....3....1..1.1..11.1..1..11..111..11.
; .3..1.1.1....3.....1..1.1...1.1..1.1111.1...1...
; .3..111.1...3......1..1.1.111.1..1.1....1....11.
; 333.........3333...111..1.111..111..11..1...11..
; ...................1.............1..............
; ...................1...........111..............
;
CD10: 30 00 ; .3......
CD12: F0 54 ; 33..111.
CD14: 30 44 ; .3..1.1.
CD16: 30 44 ; .3..1.1.
CD18: 30 54 ; .3..111.
CD1A: FC 00 ; 333.....
CD1C: 00 00 ; ........
CD1E: 00 00 ; ........
;
CD20: 00 3C ; .....33.
CD22: 50 C3 ; 11..3..3
CD24: 40 0C ; 1.....3.
CD26: 40 30 ; 1....3..
CD28: 40 C0 ; 1...3...
CD2A: 00 FF ; ....3333
CD2C: 00 00 ; ........
CD2E: 00 00 ; ........
;
CD30: 00 00 ; ........
CD32: 01 50 ; ...111..
CD34: 01 04 ; ...1..1.
CD36: 01 04 ; ...1..1.
CD38: 01 04 ; ...1..1.
CD3A: 01 50 ; ...111..
CD3C: 01 00 ; ...1....
CD3E: 01 00 ; ...1....
;
CD40: 40 00 ; 1.......
CD42: 40 00 ; 1.......
CD44: 41 44 ; 1..11.1.
CD46: 40 44 ; 1...1.1.
CD48: 45 44 ; 1.111.1.
CD4A: 45 41 ; 1.111..1
CD4C: 00 00 ; ........
CD4E: 00 01 ; .......1
;
CD50: 00 00 ; ........
CD52: 00 00 ; ........
CD54: 10 50 ; .1..11..
CD56: 11 54 ; .1.1111.
CD58: 11 00 ; .1.1....
CD5A: 50 50 ; 11..11..
CD5C: 10 00 ; .1......
CD5E: 50 00 ; 11......
;
CD60: 00 00 ; ........
CD62: 00 00 ; ........
CD64: 54 14 ; 111..11.
CD66: 40 40 ; 1...1...
CD68: 40 14 ; 1....11.
CD6A: 40 50 ; 1...11..
CD6C: 00 00 ; ........
CD6E: 00 00 ; ........
; Copyright message in 3 lines of tiles
;         ........
;         ........
;         ........
;         ........
;         ........
;         ........
;         .2222...
;         2....2..
; .......2..22..2..2..22...22...22................................................
; .......2.2....2.22.2..2.2..2.2..2......22...2..2...222...2...222..2..22.........
; .......2.2....2..2..222..22....2.......2.2.2.2.2...2.....2...2...2.2.2.2........
; .......2..22..2..2....2.2..2..2........2.2.222.2...22....2...22..222.22.........
; ........2....2..222.22...22..2222......22..2.2.222.222...222.222.2.2.2.2........
; .........2222...................................................................
; ........................................22222.22..2..2.222..2.2.................
; 2...2..22.222.2..2..22.222.22...222..2....2..2..2.22.2.2..2.2.2...22..2..22..22.
; 2...2.2...2...22.2.2...2...2.2...2..2.2...2..2..2.22.2.2..2.222..2...2.2.2.2.2.2
; 2...2.2...22..2.22..22.22..2.2...2..2.2...2..2222.2.22.2..2..2...2...2.2.22..22.
; 222.2..22.222.2..2.22..222.22....2...2....2..2..2.2.22.222...2....22..2..2.2.2..
; ................................................................................
; .......2..2...2.....22..2..22.2.2.222..22...22..222..22.222.22..2.2.222.22......
; ......2.2.2...2.....2.2.2.2...2.2..2..2.....2.2.2...2...2...2.2.2.2.2...2.2.....
; ......222.2...2.....22..2.2.2.222..2...22...22..22...22.22..22..2.2.22..2.2.....
; ......2.2.222.222...2.2.2..22.2.2..2..22....2.2.222.22..222.2.2..2..222.22......

CD70: 01 ; 1 tile
StrCopyright1: 
CD71: 00 00 ; ........
CD73: 00 00 ; ........
CD75: 00 00 ; ........
CD77: 00 00 ; ........
CD79: 00 00 ; ........
CD7B: 00 00 ; ........
CD7D: 2A 80 ; .2222...
CD7F: 80 20 ; 2....2..

CD81: 0A ; 10 tiles
StrCopyright2: 
; .......2..22..2..2..22...22...22................................................
; .......2.2....2.22.2..2.2..2.2..2......22...2..2...222...2...222..2..22.........
; .......2.2....2..2..222..22....2.......2.2.2.2.2...2.....2...2...2.2.2.2........
; .......2..22..2..2....2.2..2..2........2.2.222.2...22....2...22..222.22.........
; ........2....2..222.22...22..2222......22..2.2.222.222...222.222.2.2.2.2........
; .........2222...................................................................
; ........................................22222.22..2..2.222..2.2.................
; 2...2..22.222.2..2..22.222.22...222..2....2..2..2.22.2.2..2.2.2...22..2..22..22.
;
CD82: 00 02 ; .......2
CD84: 00 02 ; .......2
CD86: 00 02 ; .......2
CD88: 00 02 ; .......2
CD8A: 00 00 ; ........
CD8C: 00 00 ; ........
CD8E: 00 00 ; ........
CD90: 80 82 ; 2...2..2
;
CD92: 0A 08 ; ..22..2.
CD94: 20 08 ; .2....2.
CD96: 20 08 ; .2....2.
CD98: 0A 08 ; ..22..2.
CD9A: 80 20 ; 2....2..
CD9C: 2A 80 ; .2222...
CD9E: 00 00 ; ........
CDA0: 8A 88 ; 2.222.2.
;
CDA2: 20 A0 ; .2..22..
CDA4: A2 08 ; 22.2..2.
CDA6: 20 A8 ; .2..222.
CDA8: 20 08 ; .2....2.
CDAA: A8 A0 ; 222.22..
CDAC: 00 00 ; ........
CDAE: 00 00 ; ........
CDB0: 20 A2 ; .2..22.2
;
CDB2: 28 0A ; .22...22
CDB4: 82 20 ; 2..2.2..
CDB6: 28 02 ; .22....2
CDB8: 82 08 ; 2..2..2.
CDBA: 28 2A ; .22..222
CDBC: 00 00 ; ........
CDBE: 00 00 ; ........
CDC0: A2 80 ; 22.22...
;
CDC2: 00 00 ; ........
CDC4: 80 02 ; 2......2
CDC6: 00 02 ; .......2
CDC8: 00 02 ; .......2
CDCA: 80 02 ; 2......2
CDCC: 00 00 ; ........
CDCE: 00 00 ; ........
CDD0: A8 20 ; 222..2..
;
CDD2: 00 00 ; ........
CDD4: 80 82 ; 2...2..2
CDD6: 22 22 ; .2.2.2.2
CDD8: 22 A2 ; .2.222.2
CDDA: 82 22 ; 2..2.2.2
CDDC: 00 00 ; ........
CDDE: AA 8A ; 22222.22
CDE0: 08 20 ; ..2..2..
;
CDE2: 00 00 ; ........
CDE4: 02 A0 ; ...222..
CDE6: 02 00 ; ...2....
CDE8: 02 80 ; ...22...
CDEA: A2 A0 ; 22.222..
CDEC: 00 00 ; ........
CDEE: 08 22 ; ..2..2.2
CDF0: 8A 22 ; 2.22.2.2
;
CDF2: 00 00 ; ........
CDF4: 20 2A ; .2...222
CDF6: 20 20 ; .2...2..
CDF8: 20 28 ; .2...22.
CDFA: 2A 2A ; .222.222
CDFC: 00 00 ; ........
CDFE: A0 88 ; 22..2.2.
CE00: 08 88 ; ..2.2.2.
;
CE02: 00 00 ; ........
CE04: 08 28 ; ..2..22.
CE06: 22 22 ; .2.2.2.2
CE08: 2A 28 ; .222.22.
CE0A: 22 22 ; .2.2.2.2
CE0C: 00 00 ; ........
CE0E: 00 00 ; ........
CE10: 0A 08 ; ..22..2.
;
CE12: 00 00 ; ........
CE14: 00 00 ; ........
CE16: 00 00 ; ........
CE18: 00 00 ; ........
CE1A: 00 00 ; ........
CE1C: 00 00 ; ........
CE1E: 00 00 ; ........
CE20: 28 28 ; .22..22.

CE22: 0A
StrCopyright3:
; 2...2.2...2...22.2.2...2...2.2...2..2.2...2..2..2.22.2.2..2.222..2...2.2.2.2.2.2
; 2...2.2...22..2.22..22.22..2.2...2..2.2...2..2222.2.22.2..2..2...2...2.2.22..22.
; 222.2..22.222.2..2.22..222.22....2...2....2..2..2.2.22.222...2....22..2..2.2.2..
; ................................................................................
; .......2..2...2.....22..2..22.2.2.222..22...22..222..22.222.22..2.2.222.22......
; ......2.2.2...2.....2.2.2.2...2.2..2..2.....2.2.2...2...2...2.2.2.2.2...2.2.....
; ......222.2...2.....22..2.2.2.222..2...22...22..22...22.22..22..2.2.22..2.2.....
; ......2.2.222.222...2.2.2..22.2.2..2..22....2.2.222.22..222.2.2..2..222.22......
;
CE23: 80 88 ; 2...2.2.
CE25: 80 88 ; 2...2.2.
CE27: A8 82 ; 222.2..2
CE29: 00 00 ; ........
CE2B: 00 02 ; .......2
CE2D: 00 08 ; ......2.
CE2F: 00 0A ; ......22
CE31: 00 08 ; ......2.
;
CE33: 08 0A ; ..2...22
CE35: 0A 08 ; ..22..2.
CE37: 8A 88 ; 2.222.2.
CE39: 00 00 ; ........
CE3B: 08 08 ; ..2...2.
CE3D: 88 08 ; 2.2...2.
CE3F: 88 08 ; 2.2...2.
CE41: 8A 8A ; 2.222.22
;
CE43: 22 02 ; .2.2...2
CE45: A0 A2 ; 22..22.2
CE47: 22 82 ; .2.22..2
CE49: 00 00 ; ........
CE4B: 00 A0 ; ....22..
CE4D: 00 88 ; ....2.2.
CE4F: 00 A0 ; ....22..
CE51: 80 88 ; 2...2.2.
;
CE53: 02 20 ; ...2.2..
CE55: 82 20 ; 2..2.2..
CE57: A2 80 ; 22.22...
CE59: 00 00 ; ........
CE5B: 82 88 ; 2..22.2.
CE5D: 88 08 ; 2.2...2.
CE5F: 88 8A ; 2.2.2.22
CE61: 82 88 ; 2..22.2.
;
CE63: 20 88 ; .2..2.2.
CE65: 20 88 ; .2..2.2.
CE67: 20 20 ; .2...2..
CE69: 00 00 ; ........
CE6B: 8A 82 ; 2.222..2
CE6D: 82 08 ; 2..2..2.
CE6F: 82 02 ; 2..2...2
CE71: 82 0A ; 2..2..22
;
CE73: 08 20 ; ..2..2..
CE75: 08 2A ; ..2..222
CE77: 08 20 ; ..2..2..
CE79: 00 00 ; ........
CE7B: 80 A0 ; 2...22..
CE7D: 00 88 ; ....2.2.
CE7F: 80 A0 ; 2...22..
CE81: 00 88 ; ....2.2.
;
CE83: 8A 22 ; 2.22.2.2
CE85: 88 A2 ; 2.2.22.2
CE87: 88 A2 ; 2.2.22.2
CE89: 00 00 ; ........
CE8B: A8 28 ; 222..22.
CE8D: 80 80 ; 2...2...
CE8F: A0 28 ; 22...22.
CE91: A8 A0 ; 222.22..
;
CE93: 08 A8 ; ..2.222.
CE95: 08 20 ; ..2..2..
CE97: A0 20 ; 22...2..
CE99: 00 00 ; ........
CE9B: A8 A0 ; 222.22..
CE9D: 80 88 ; 2...2.2.
CE9F: A0 A0 ; 22..22..
CEA1: A8 88 ; 222.2.2.
;
CEA3: 20 22 ; .2...2.2
CEA5: 20 22 ; .2...2.2
CEA7: 0A 08 ; ..22..2.
CEA9: 00 00 ; ........
CEAB: 88 A8 ; 2.2.222.
CEAD: 88 80 ; 2.2.2...
CEAF: 88 A0 ; 2.2.22..
CEB1: 20 A8 ; .2..222.
;
CEB3: 22 22 ; .2.2.2.2
CEB5: 28 28 ; .22..22.
CEB7: 22 20 ; .2.2.2..
CEB9: 00 00 ; ........
CEBB: A0 00 ; 22......
CEBD: 88 00 ; 2.2.....
CEBF: 88 00 ; 2.2.....
CEC1: A0 00 ; 22......

The Cursive Doubleback Text


; Cursive "doubleback" data. Each 2 bytes holds 5 directional data points.
; The upper bit is unused.
CEC3: 6D B6   ; 0 110 110 110 110 110    W  W  W  W  W
CEC5: 27 6D   ; 0 010 011 101 101 101   SW SW SW SE  E
CEC7: 12 52   ; 0 001 001 001 010 010    E  E NE NE NE
CEC9: 12 49   ; 0 001 001 001 001 001   NE NE NE NE NE
CECB: 5A 49   ; 0 101 101 001 001 001   NE NE NE SW SW
CECD: 5B 6D   ; 0 101 101 101 101 101   SW SW SW SW SW
CECF: 29 25   ; 0 010 100 100 100 101   SW  S  S  S  E
CED1: 12 4A   ; 0 001 001 001 001 010    E NE NE NE NE
CED3: 5D 92   ; 0 101 110 110 010 010    E  E  W  W SW
CED5: 24 E5   ; 0 010 010 011 100 101   SW  S SE  E  E
CED7: 30 09   ; 0 011 000 000 001 001   NE NE  N  N SE
CED9: 52 53   ; 0 101 001 001 010 011   SE  E NE NE SW
CEDB: 24 E5   ; 0 010 010 011 100 101   SW  S SE  E  E
CEDD: 52 49   ; 0 101 001 001 001 001   NE NE NE NE SW
CEDF: 24 ED   ; 0 010 010 011 101 101   SW SW SE  E  E
CEE1: 12 52   ; 0 001 001 001 010 010    E  E NE NE NE
CEE3: 10 49   ; 0 001 000 001 001 001   NE NE NE  N NE
CEE5: 5C 00   ; 0 101 110 000 000 000    N  N  N  W SW
CEE7: 4B 2D   ; 0 100 101 100 101 101   SW SW  S SW  S
CEE9: 39 25   ; 0 011 100 100 100 101   SW  S  S  S SE
CEEB: 70 52   ; 0 111 000 001 010 010    E  E NE  N NW
CEED: 24 93   ; 0 010 010 010 010 011   SE  E  E  E  E
CEEF: 02 49   ; 0 000 001 001 001 001   NE NE NE NE  N
CEF1: 60 01   ; 0 110 000 000 000 001   NE  N  N  N  W
CEF3: 59 6D   ; 0 101 100 101 101 101   SW SW SW  S SW
CEF5: 49 2C   ; 0 100 100 100 101 100    S SW  S  S  S
CEF7: 24 93   ; 0 010 010 010 010 011   SE  E  E  E  E
CEF9: 02 4A   ; 0 000 001 001 001 010    E NE NE NE  N
CEFB: 49 76   ; 0 100 100 101 110 110    W  W SW  S  S
CEFD: 24 93   ; 0 010 010 010 010 011   SE  E  E  E  E
CEFF: 12 92   ; 0 001 001 010 010 010    E  E  E NE NE
CF01: 02 49   ; 0 000 001 001 001 001   NE NE NE NE  N
CF03: 60 01   ; 0 110 000 000 000 001   NE  N  N  N  W
CF05: 59 6D   ; 0 101 100 101 101 101   SW SW SW  S SW
CF07: 49 2C   ; 0 100 100 100 101 100    S SW  S  S  S
CF09: 02 93   ; 0 000 001 010 010 011   SE  E  E NE  N
CF0B: 14 9F   ; 0 001 010 010 011 111   NW SE  E  E NE
CF0D: 64 8A   ; 0 110 010 010 001 010    E NE  E  E  W
CF0F: 39 6E   ; 0 011 100 101 101 110    W SW SW  S SE
CF11: 40 4A   ; 0 100 000 001 001 010    E NE NE  N  S
CF13: 14 9D   ; 0 001 010 010 011 101   SW SE  E  E NE
CF15: 24 49   ; 0 010 010 001 001 001   NE NE NE  E  E
CF17: 6D DA   ; 0 110 110 111 011 010    E SE NW  W  W
CF19: 39 2E   ; 0 011 100 100 101 110    W SW  S  S SE
CF1B: 24 92   ; 0 010 010 010 010 010    E  E  E  E  E
CF1D: 12 49   ; 0 001 001 001 001 001   NE NE NE NE NE
CF1F: 00 41   ; 0 000 000 001 000 001   NE  N NE  N  N
CF21: 5B 70   ; 0 101 101 101 110 000    N  W SW SW SW
CF23: 4B 2C   ; 0 100 101 100 101 100    S SW  S SW  S
CF25: 24 4C   ; 0 010 010 001 001 100    S NE NE  E  E
CF27: 37 AB   ; 0 011 011 110 101 011   SE SW  W SE SE
CF29: 12 52   ; 0 001 001 001 010 010    E  E NE NE NE
CF2B: 00 00   ; END

DirTable:
; These are X/Y offsets for each 8 directions
CF2D: 00 FF  ; 0 N
CF2F: 01 FF  ; 1 NE
CF31: 01 00  ; 2 E
CF33: 01 01  ; 3 SE
CF35: 00 01  ; 4 S
CF37: FF 01  ; 5 SW
CF39: FF 00  ; 6 W
CF3B: FF FF  ; 7 NW

Songs

MusicFirstLife:
CF3D: 28 80                
CF3F: 40 40                              
CF41: 28 80          
CF43: 40 40                                  
CF45: 28 80          
CF47: 40 40                               
CF49: 28 80          
CF4B: 40 40                                   
CF4D: 19 5F                                 
CF4F: 19 64 
CF51: 19 5F                                  
CF53: 1A 55                        
CF55: 1C 4B                        
CF57: 1C 55                         
CF59: 1C 4B                        
CF5B: 1C 43                       
CF5D: 40 40                                 
CF5F: 00 00          

MusicSecondLife:
CF61: 28 80 
CF63: 40 40   
CF65: 40 43
CF67: 40 40
CF69: 37 5F
CF6B: 37 4B
CF6D: 37 55
CF6F: 37 4B
CF71: 19 5F
CF73: 19 64
CF75: 19 5F
CF77: 1A 55
CF79: 1C 4B
CF7B: 1C 55
CF7D: 1C 4B
CF7F: 1C 43
CF81: 40 40
CF83: 00 00

MusicThirdLife:
CF85: 28 80
CF87: 40 40
CF89: 40 43
CF8B: 3C 4B
CF8D: 39 55
CF8F: 37 5F
CF91: 37 64
CF93: 37 5F
CF95: 39 55
CF97: 3C 4B
CF99: 40 43
CF9B: 39 55
CF9D: 40 40
CF9F: 00 00

CFA1: 14 1E
CFA3: 00 00 

MusicEndOfLife:
; Just one long note
CFA5: FF FF 
CFA7: 00 00              

ScoreTable:
; A zero is added to the end of all scores
CFA9: 00     ; End marker
CFAA: 07     ; Type 1: Apple     70
CFAB: 0A     ; Type 2: Cherry   100
CFAC: 0F     ; Type 3: Magnet   150
CFAD: 14     ; Type 4: Skate    200
CFAE: 19     ; Type 5: YoYo     250
CFAF: 1E     ; Type 6: Pear     300
CFB0: 32     ; Type 7: Spider   500
CFB1: 00     ; Type 8: Skull   (no score)
CFB2: 64     ; Type 9: X       1000

; ASCII version of the copyright (never used by the code)

; "COPYRIGHT 1982 DALE A. LEAR ALL RIGHTS RESERVED LICENSED TO TANDY COPRPORATION"
CFB3: 43 4F 50 59 52 49 47 48 54 20 31 39 38 32 20 44 41 4C 45 20 41 2E 20 4C 45 41 52 20 41 4C 4C 20 
CFD3: 52 49 47 48 54 53 20 52 45 53 45 52 56 45 44 20 4C 49 43 45 4E 53 45 44 20 54 4F 20 54 41 4E 44 
CFF3: 59 20 43 4F 52 50 4F 52 41 54 49 4F 4E