back to project page

ABM Disassembly

                   ********************************************************************************
                   * ABM for the Apple II, by Silas Warner                                        *
                   * Copyright 1980 Muse Software                                                 *
                   *                                                                              *
                   * This is the main game code.  It was extracted from a .NIB image of the 13-   *
                   * sector original disk.                                                        *
                   ********************************************************************************
                   * Disassembly by Andy McFadden, using 6502bench SourceGen v1.7.1.              *
                   * Last updated 2020/08/13                                                      *
                   *                                                                              *
                   * This program makes heavy use of inline data following JSRs.  These are       *
                   * automatically formatted by an extension script based on the label prefix:    *
                   *                                                                              *
                   *   InA_* : JSR is followed by a two-byte address                              *
                   *   InXY_*: JSR is followed by a two-byte text screen position                 *
                   *   InS_* : JSR is followed by a null-terminated high-ASCII string             *
                   *                                                                              *
                   * If you rename one of these labels, do not change the prefix, or the inline   *
                   * formatting will vanish.                                                      *
                   ********************************************************************************
                   * The state of inbound missiles are recorded from $4200-4cff.  Each missile    *
                   * gets its own page, so there are a maximum of 11 inbound missiles.  Inline    *
                   * references to addresses at $42xx are transparently remapped to the           *
                   * appropriate page.                                                            *
                   *                                                                              *
                   * The first 150-ish bytes of each page record the column of the missile trail  *
                   * at the corresponding row, making it easy to erase the trail when the missile *
                   * is destroyed.  The last 30 bytes of each page holds the missile state        *
                   * (position, explosion progress, etc).                                         *
                   *                                                                              *
                   * $4d00-4dff holds the trail data and state for the ABM.  Only one ABM may be  *
                   * launched at a time.                                                          *
                   ********************************************************************************
                   * The Applesoft floating-point math routines are used heavily.  The basic      *
                   * format of a float is 40 bits:                                                *
                   *                                                                              *
                   *   EEEEEEEE SMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM                               *
                   *                                                                              *
                   * The exponent uses a bias of 129 (IEEE 754 uses 127).  For example, the       *
                   * number +25.0 would be:                                                       *
                   *                                                                              *
                   *   Applesoft: 0x8548000000: [10000101]  [0][1001000  00000000 ...]            *
                   *   IEEE 754 : 0x41c80000:   [0][1000001  1][1001000  00000000 ...]            *
                   ********************************************************************************
                   TOK_CALL        .eq     $8c    {const}
                   O_DET_SIZE      .eq     $f4    {const}    ;missile detonation size (96-176)
                   O_DET_STAGE1    .eq     $f5    {const}    ;tracks detonation progress (white)
                   O_DET_STAGE2    .eq     $f6    {const}    ;tracks detonation progress (black)
                   O_ROW           .eq     $fa    {const}    ;current row, starts at $00; $ff=inactive
                   O_DET_ROW       .eq     $fb    {const}    ;row at which missile detonates
                   O_TARGET_CITY   .eq     $fc    {const}    ;targeted city (0-5)
                   O_MIRV_ROW      .eq     $fd    {const}    ;row at which missile MIRVs ($00=never)
                   missile_ptr     .eq     $17    {addr/2}   ;points to page with missile state
                   BAS_HCOLOR1     .eq     $1c               ;hi-res color mask
                   MON_WNDTOP      .eq     $22               ;top of scroll window
                   MON_CH          .eq     $24               ;cursor horizontal displacement
                   MON_CV          .eq     $25               ;cursor vertical displacement
                   BAS_HBASL       .eq     $26               ;base address for hi-res drawing (lo part)
                   MON_BASL        .eq     $28               ;base address for text output (lo)
                   BAS_HMASK       .eq     $30               ;hi-res graphics on-the-fly bit mask
                   MON_INVFLAG     .eq     $32               ;text mask (255=normal, 127=flash, 63=inv)
                   sfx_counter     .eq     $4a    {addr/2}   ;speaker click delay
                   BAS_FAC         .eq     $9d    {addr/6}   ;floating point accumulator (6b)
                   strobe_thing?   .eq     $cb               ;not initialized, never used
                   BAS_SCALE       .eq     $e7               ;hi-res graphics scale factor
                   STACK           .eq     $0100  {addr/256} ;hardware stack
                   ReadPdlX        .eq     $0300             ;reads paddle for cursor X position
                   ReadPdlY        .eq     $0303             ;reads paddle for cursor Y position
                   GetOuterBtn     .eq     $0306             ;checks button that fires outer/center launchers
                   GetInnerBtn     .eq     $0309             ;checks button that fires inner launchers
                   missile_cur_xc  .eq     $42e2  {addr/5}   ;fp: current hi-res column of missile (0-139)
                   missile_target_xc .eq   $42e8  {addr/5}   ;fp: target hi-res column of missile (10-135)
                   missile_xmove   .eq     $42ee  {addr/5}   ;fp: per-frame horizontal movement
                   abm_trail       .eq     $4d00  {addr/160} ;pixel columns for ABM trail
                   abm_cur_xc      .eq     $4de2  {addr/5}   ;fp: current ABM column (0-139)
                   abm_target_xc   .eq     $4de8  {addr/5}   ;fp: temp storage for ABM target column (0-139)
                   abm_xmove       .eq     $4dee  {addr/5}   ;fp: ABM per-frame horizontal movement
                   abm_max_size    .eq     $4df4             ;max size of exploding ABM ($50/$70)
                   abm_det_size1   .eq     $4df5             ;current size of ABM explosion (white)
                   abm_det_size2   .eq     $4df6             ;current size of ABM explosion (black)
                   abm_row         .eq     $4dfa             ;current row of ABM, or $ff if none fired
                   abm_target_row  .eq     $4dfb             ;row at which ABM will detonate
                   RWTS_BUFFER     .eq     $73ef  {addr/256} ;RWTS sector buffer
                   HIGH_SCORE      .eq     $746f  {addr/5}   ;fp: high score
                   RWTS_PARM       .eq     $77e8  {addr/17}  ;RWTS parameter table
                   DOS_32K_RWTS    .eq     $7d00             ;RWTS entry point
                   KBD             .eq     $c000             ;R last key pressed + 128
                   KBDSTRB         .eq     $c010             ;RW keyboard strobe
                   SPKR            .eq     $c030             ;RW toggle speaker
                   STROBE          .eq     $c040             ;R game I/O strobe
                   TXTSET          .eq     $c051             ;RW display text
                   TXTPAGE1        .eq     $c054             ;RW display page 1
                   LORES           .eq     $c056             ;RW display lo-res graphics
                   BAS_GIVAYF      .eq     $e2f2             ;convert 16-bit (A,Y) to float, store in FAC
                   BAS_SNGFLT      .eq     $e301             ;convert 8-bit int (Y) to FLOAT
                   BAS_FSUB        .eq     $e7a7             ;FAC = (Y,A) - FAC
                   BAS_FADD        .eq     $e7be             ;FAC = (Y,A) + FAC
                   BAS_CON_ONE     .eq     $e913             ;constant value 1.0
                   BAS_FMULT       .eq     $e97f             ;FAC = (Y,A) * FAC
                   BAS_LOAD_ARG_FROM_YA .eq $e9e3            ;unpack 5-byte val at (Y,A) into ARG
                   BAS_MUL10       .eq     $ea39             ;multiply FAC by 10
                   BAS_CON_TEN     .eq     $ea50             ;constant value 10.0
                   BAS_FDIV        .eq     $ea66             ;FAC = (Y,A) / FAC
                   BAS_LOAD_FAC_FROM_YA .eq $eaf9            ;unpack 5-byte val at (Y,A) into FAC
                   BAS_STORE_FAC_AT_YX_ROUNDED .eq $eb2b     ;round FAC, store at (Y,X)
                   BAS_SIGN        .eq     $eb82             ;test FAC sign; <,=,> 0 -> A={-1,0,1}
                   BAS_FLOAT       .eq     $eb93             ;convert value in A to float in FAC
                   BAS_ABS         .eq     $ebaf             ;changes sign of FAC to +
                   BAS_FCOMP       .eq     $ebb2             ;cmp (Y,A) with FAC; <,=,> -> A={1,0,-1}
                   BAS_QINT        .eq     $ebf2             ;convert FAC to big-endian int in FAC+1..FAC+4
                   BAS_INT         .eq     $ec23             ;FAC = floor(FAC)
                   BAS_LINPRT      .eq     $ed24             ;print float at (A,X) as decimal integer
                   BAS_PRINT_FAC   .eq     $ed2e             ;print FAC to screen
                   BAS_CON_HALF    .eq     $ee64             ;constant value 0.5
                   BAS_FPWRT       .eq     $ee97             ;compute exponentiation
                   BAS_NEGOP       .eq     $eed0             ;negate value in FAC
                   BAS_RND         .eq     $efae             ;generate random number
                   BAS_CON_PI_HALF .eq     $f066             ;constant value PI/2
                   BAS_CON_PI_DOUB .eq     $f06b             ;constant value PI*2
                   BAS_QUARTER     .eq     $f070             ;constant value 0.25
                   BAS_HGR         .eq     $f3e2             ;switch to hi-res mixed-mode and clear
                   BAS_HPOSN       .eq     $f411             ;set hi-res position; horiz=(Y,X) vert=A
                   BAS_HPLOT0      .eq     $f457             ;plot point; horiz=(Y,X), vert=A
                   BAS_HGLIN       .eq     $f53a             ;draw line from last point to (A,X),Y
                   BAS_DRAW0       .eq     $f601             ;draw a shape from addr (Y,X)
                   BAS_HCOLOR      .eq     $f6e9  {addr/4}   ;set hi-res color to value in X
                   MON_SETTXT      .eq     $fb39             ;set screen to text mode
                   MON_VTAB        .eq     $fc22             ;tab to row specified in Acc
                   MON_HOME        .eq     $fc58             ;clear screen and reset text output to top-left
                   MON_WAIT        .eq     $fca8             ;delay for (26 + 27*Acc + 5*(Acc*Acc))/2 cycles
                   MON_CROUT       .eq     $fd8e             ;print a carriage return
                   MON_COUT        .eq     $fded             ;print Acc to output device via $36-37
                   MON_COUT1       .eq     $fdf0             ;print Acc to screen

                                   .org    $0801
                   ********************************************************************************
                   * Applesoft BASIC header.  When run, calls assembly-language program at $810.  *
                   ********************************************************************************
0801: 0b 08                        .dd2    $080b             ;pointer to start of next line
0803: 01 00                        .dd2    $0001             ;line 1
0805: 8c                           .dd1    TOK_CALL          ;"CALL 2064"
0806: 32 30 36 34                  .str    ‘2064’
080a: 00                           .dd1    $00
080b: 00 08                        .dd2    $0800             ;(garbage pointer)
080d: 02 00                        .dd2    $0002             ;line 2
080f: 8d                           .dd1    $8d               ;junk

                   ********************************************************************************
                   * Program entry point.                                                         *
                   ********************************************************************************
0810: 20 8c 09     Start           jsr     ReadHighScore     ;read high score from disk
0813: 8d 56 c0     Restart         sta     LORES             ;switch to lo-res graphics (why?)
0816: 8d 51 c0                     sta     TXTSET            ;text mode
0819: 8d 54 c0                     sta     TXTPAGE1          ;text page 1
                   ; Draw the scroll-up ABM logo.
081c: a9 05                        lda     #$05              ;draw the logo animation 5x
081e: 8d 44 08                     sta     :_count+1
0821: 20 39 fb     :LogoLoop       jsr     MON_SETTXT        ;text mode, full-screen window
0824: 20 58 fc                     jsr     MON_HOME          ;clear screen
0827: 20 42 15                     jsr     InXY_SetTextPos
082a: 17                           .dd1    23                ;row 23 (bottom of screen)
082b: 00                           .dd1    0                 ;col 0
082c: a2 ff                        ldx     #$ff
082e: e8           :LogoLineLoop   inx
082f: bd 05 09                     lda     abm_logo,x        ;get horizontal offset
0832: 10 06                        bpl     :DrawSpc          ;if not negative, draw a space
0834: 20 8e fd                     jsr     MON_CROUT         ;print CR to scroll text up one line
0837: 4c 2e 08                     jmp     :LogoLineLoop

083a: f0 07        :DrawSpc        beq     :_count           ;if zero, we're all done
083c: a8                           tay
083d: a9 20                        lda     #‘ ’              ;inverse space
083f: 91 28                        sta     (MON_BASL),y      ;store on screen
0841: d0 eb                        bne     :LogoLineLoop

0843: a9 00        :_count         lda     #$00              ;count is stored in self-mod operand
0845: f0 06                        beq     :LogoDone         ;we're done, branch
0847: ce 44 08                     dec     :_count+1
084a: 4c 21 08                     jmp     :LogoLoop

084d: 20 42 15     :LogoDone       jsr     InXY_SetTextPos
0850: 05                           .dd1    5                 ;row 5 (6th row)
0851: 0a                           .dd1    10                ;col 10 (11th position)
0852: 20 2b 15                     jsr     InS_PrintString   ;print high score notice
0855: c8 c9 c7 c8+                 .zstr   “HIGH SCORE IS ”
0864: 20 73 15                     jsr     InA_LoadFloat     ;copy high score into FAC
0867: 31 0c                        .dd2    high_score
0869: 20 2e ed                     jsr     BAS_PRINT_FAC     ;print FAC
086c: 20 42 15                     jsr     InXY_SetTextPos
086f: 17                           .dd1    23                ;row 23 (bottom of screen)
0870: 00                           .dd1    0
0871: 20 2b 15                     jsr     InS_PrintString   ;print multi-line string (scrolls 3x)
0874: a0 a0 a0 a0+                 .zstr   “      COPYRIGHT 1980, MUSE SOFTWARE”,$8d,“          ALL RIGHTS”
                                    +      “ RESERVED”,$8d,$8d,“         PRESS A KEY TO START.”
                   ; Wait for a key to be hit.  If enough time passes, go into attract mode.
08d6: 8d 10 c0                     sta     KBDSTRB           ;clear keyboard strobe
08d9: a2 f0                        ldx     #$f0
08db: 8e ef 0b                     stx     temp+1            ;init delay counter to $f0f0
08de: 8e ee 0b                     stx     temp
08e1: ee ee 0b     :WaitForStart   inc     temp
08e4: d0 09                        bne     :ChkStart
08e6: ee ef 0b                     inc     temp+1
08e9: d0 04                        bne     :ChkStart
08eb: a9 ff                        lda     #$ff              ;demo is playing
08ed: d0 10                        bne     :SetMode          ;(always)

08ef: ad 00 c0     :ChkStart       lda     KBD               ;key hit?
08f2: 30 06                        bmi     :KeyHit           ;yes, branch
08f4: ca                           dex
08f5: d0 f8                        bne     :ChkStart
08f7: 4c e1 08                     jmp     :WaitForStart

08fa: 8d 10 c0     :KeyHit         sta     KBDSTRB
08fd: a9 00                        lda     #$00              ;player is playing
08ff: 8d f0 0b     :SetMode        sta     auto_play_flag
0902: 4c d4 09                     jmp     StartGame

                   ; 
                   ; Text "ABM" logo.  Values are horizontal offsets where an inverse ' ' should be
                   ; drawn.  The result looks like this:
                   ; 
                   ;          ###     #####     ##   ##
                   ;         ## ##    ##  ##    ### ###
                   ;        ##   ##   ##   ##   #######
                   ;        ##   ##   ##  ##    ## # ##
                   ;        ##   ##   #####     ##   ##
                   ;        #######   ##  ##    ##   ##
                   ;        ##   ##   ##   ##   ##   ##
                   ;        ##   ##   ##  ##    ##   ##
                   ;        ##   ##   #####     ##   ##
0905: 09 0a 0b 11+ abm_logo        .bulk   $09,$0a,$0b,$11,$12,$13,$14,$15,$1b,$1c,$20,$21,$c8
0912: 08 09 0b 0c+                 .bulk   $08,$09,$0b,$0c,$11,$12,$15,$16,$1b,$1c,$1d,$1f,$20,$21,$c8
0921: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$16,$17,$1b,$1c,$1d,$1e,$1f,$20,$21,$c8
0931: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$15,$16,$1b,$1c,$1e,$20,$21,$c8
093f: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$13,$14,$15,$1b,$1c,$20,$21,$c8
094d: 07 08 09 0a+                 .bulk   $07,$08,$09,$0a,$0b,$0c,$0d,$11,$12,$15,$16,$1b,$1c,$20,$21,$c8
095d: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$16,$17,$1b,$1c,$20,$21,$c8
096a: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$15,$16,$1b,$1c,$20,$21,$c8
0977: 07 08 0c 0d+                 .bulk   $07,$08,$0c,$0d,$11,$12,$13,$14,$15,$1b,$1c,$20,$21,$c8
0985: c8 c8 c8 c8+                 .bulk   $c8,$c8,$c8,$c8,$c8,$c8
098b: 00                           .dd1    $00               ;zero indicates end of list

                   ; 
                   ; Reads the high score from disk.
                   ; 
098c: a9 01        ReadHighScore   lda     #$01              ;cmd=read
098e: 20 b1 09                     jsr     AccessHighScore   ;read high score sector
0991: a0 74                        ldy     #>HIGH_SCORE
0993: a9 6f                        lda     #<HIGH_SCORE
0995: 20 f9 ea                     jsr     BAS_LOAD_FAC_FROM_YA ;copy score from sector buffer to FAC
0998: 20 ac 15                     jsr     InA_StoreFloat    ;store rounded FAC at address below
099b: 31 0c                        .dd2    high_score
099d: 60                           rts

                   ; 
                   ; Writes the high score to disk.
                   ; 
099e: a9 01        WriteHighScore  lda     #$01              ;cmd=read
09a0: 20 b1 09                     jsr     AccessHighScore   ;read high score sector
09a3: 20 73 15                     jsr     InA_LoadFloat     ;copy score into FAC
09a6: 31 0c                        .dd2    high_score
09a8: a0 74                        ldy     #>HIGH_SCORE
09aa: a2 6f                        ldx     #<HIGH_SCORE
09ac: 20 2b eb                     jsr     BAS_STORE_FAC_AT_YX_ROUNDED ;copy score from FAC to sector buffer
09af: a9 02                        lda     #$02              ;cmd=write; fall through
                   ; 
                   ; Common code for high score I/O.
                   ; 
09b1: 8d f4 77     AccessHighScore sta     RWTS_PARM+12
09b4: a9 02                        lda     #$02              ;track 2
09b6: 8d ec 77                     sta     RWTS_PARM+4
09b9: a9 09                        lda     #$09              ;sector 9
09bb: 8d ed 77                     sta     RWTS_PARM+5
09be: a9 00                        lda     #$00              ;volume 0 (matches any)
09c0: 8d eb 77                     sta     RWTS_PARM+3
09c3: a9 ef                        lda     #<RWTS_BUFFER     ;set buffer address
09c5: 8d f0 77                     sta     RWTS_PARM+8
09c8: a9 73                        lda     #>RWTS_BUFFER
09ca: 8d f1 77                     sta     RWTS_PARM+9
09cd: a0 e8                        ldy     #<RWTS_PARM       ;use DOS RWTS parameter list
09cf: a9 77                        lda     #>RWTS_PARM
09d1: 4c 00 7d                     jmp     DOS_32K_RWTS      ;write the sector

                   ********************************************************************************
                   * Initializes state for a new game.                                            *
                   ********************************************************************************
09d4: 20 39 fb     StartGame       jsr     MON_SETTXT        ;set text mode, reset window
09d7: 20 58 fc                     jsr     MON_HOME          ;clear the screen
09da: 20 e2 f3                     jsr     BAS_HGR           ;switch to HGR w/window, and clear graphics
09dd: 8d 10 c0                     sta     KBDSTRB           ;clear keyboard strobe
09e0: a2 03                        ldx     #$03
09e2: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
                   ; Init game state.
09e5: a9 46                        lda     #70
09e7: 8d 79 13                     sta     cursor_x          ;init cursor position
09ea: 8d 7a 13                     sta     cursor_y          ;roughly middle of screen (X gets doubled)
09ed: 8d 81 12                     sta     auto_curs_x
09f0: 8d 82 12                     sta     auto_curs_y
09f3: a2 01                        ldx     #$01
09f5: 86 e7                        stx     BAS_SCALE         ;set scale for shape drawing
09f7: a9 00                        lda     #$00
09f9: 8d ee 0b                     sta     temp
09fc: 85 17                        sta     missile_ptr
09fe: 8d f3 0b                     sta     abm_fired_cnt     ;init score counters
0a01: 8d f4 0b                     sta     abm_fired_cnt+1
0a04: 8d f1 0b                     sta     mssl_destroy_cnt
0a07: 8d f2 0b                     sta     mssl_destroy_cnt+1
0a0a: 8d 43 18                     sta     sound_fx_mod      ;init sound effects
                   ; Draw cities and launchers.
0a0d: ae ee 0b     :DrawLoop       ldx     temp              ;get start position
0a10: a0 00                        ldy     #$00
0a12: a9 9f                        lda     #159              ;row 159 (just above text area)
0a14: 20 57 f4                     jsr     BAS_HPLOT0        ;plot a point
0a17: 20 7d 13                     jsr     InA_DrawShape     ;draw a city at that position
0a1a: 4e 14                        .dd2    shape_city
0a1c: ad ee 0b                     lda     temp
0a1f: c9 fa                        cmp     #250              ;did we draw the rightmost city?
0a21: b0 31                        bcs     :DrawText         ;yes, done drawing
0a23: 69 1e                        adc     #30               ;move right 30 pixels
0a25: 8d ee 0b                     sta     temp
0a28: aa                           tax
0a29: a0 00                        ldy     #$00
0a2b: a9 9d                        lda     #157
0a2d: 20 57 f4                     jsr     BAS_HPLOT0        ;plot a point
0a30: 20 7d 13                     jsr     InA_DrawShape     ;draw the bottom of the launcher
0a33: b9 14                        .dd2    shape_laun_bot
0a35: ad ee 0b                     lda     temp
0a38: 18                           clc
0a39: 69 06                        adc     #6                ;move right six pixels
0a3b: aa                           tax
0a3c: a0 00                        ldy     #$00
0a3e: a9 98                        lda     #152              ;come up 7 lines
0a40: 20 57 f4                     jsr     BAS_HPLOT0
0a43: 20 7d 13                     jsr     InA_DrawShape     ;draw the top of the launcher
0a46: dd 14                        .dd2    shape_laun_top
0a48: ad ee 0b                     lda     temp
0a4b: 18                           clc
0a4c: 69 14                        adc     #20               ;move right 20 pixels
0a4e: 8d ee 0b                     sta     temp
0a51: 4c 0d 0a                     jmp     :DrawLoop         ;draw the next set

                   ; Draw text area: city names, missile ratings, score.
0a54: 20 42 15     :DrawText       jsr     InXY_SetTextPos
0a57: 14                           .dd1    20
0a58: 00                           .dd1    0
0a59: 20 2b 15                     jsr     InS_PrintString
0a5c: a0 c2 cf d3+                 .zstr   “ BOS    NYC    PHL    BAL    WSH    RCH”,$8d,“      1      5  ”
                                    +      “   1      5      1”,$8d,“         ENEMY 0    0 ABM'S”
0ac3: a9 16                        lda     #22               ;set top of text window
0ac5: 85 22                        sta     MON_WNDTOP
0ac7: ad f0 0b                     lda     auto_play_flag    ;are we in attract mode?
0aca: f0 09                        beq     :NotAuto          ;no, branch
0acc: a9 64                        lda     #$64              ;replace speaker click with harmless store
0ace: 8d 76 13                     sta     _Click+1          ; (attract mode is silent)
0ad1: a0 14                        ldy     #20               ;start with high spawn probability
0ad3: d0 07                        bne     :SetProb          ;(always)

0ad5: a9 30        :NotAuto        lda     #$30
0ad7: 8d 76 13                     sta     _Click+1
0ada: a0 78                        ldy     #120              ;start with low spawn probability
0adc: 20 01 e3     :SetProb        jsr     BAS_SNGFLT        ;convert Y-reg to float
0adf: 20 ac 15                     jsr     InA_StoreFloat    ;save it
0ae2: f5 0b                        .dd2    spawn_prob
0ae4: a2 02                        ldx     #$02
0ae6: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=purple
0ae9: a2 00                        ldx     #$00
0aeb: a0 00                        ldy     #$00
0aed: a9 9f                        lda     #159
0aef: 20 57 f4                     jsr     BAS_HPLOT0        ;plot at (0,159)
0af2: a2 01                        ldx     #1
0af4: a9 16                        lda     #22
0af6: a0 9f                        ldy     #159
0af8: 20 3a f5                     jsr     BAS_HGLIN         ;draw line to (278,159)
0afb: a2 03                        ldx     #$03
0afd: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
                   ; Make a copy of the original row 155, so that as the game goes on we can
                   ; compare the screen contents to the original state to evaluate damage.
0b00: a2 00                        ldx     #$00
0b02: a0 00                        ldy     #$00
0b04: a9 9b                        lda     #155
0b06: 20 11 f4                     jsr     BAS_HPOSN         ;get address of (0,155)
0b09: a0 00                        ldy     #$00
0b0b: b1 26        :Copy155Loop    lda     (BAS_HBASL),y
0b0d: 99 52 0b                     sta     orig_row_155,y
0b10: c8                           iny
0b11: c0 28                        cpy     #40               ;copy full 40-byte line
0b13: 90 f6                        bcc     :Copy155Loop
                   ; Init launcher status to undamaged.
0b15: a0 00                        ldy     #$00
0b17: a9 98                        lda     #152
0b19: 99 7a 0b     :InitLauLoop    sta     launcher_status,y
0b1c: c8                           iny
0b1d: c0 05                        cpy     #$05              ;done with all five?
0b1f: d0 f8                        bne     :InitLauLoop
                   ; Init city status to undamaged.
0b21: a9 ff                        lda     #$ff
0b23: a0 00                        ldy     #$00
0b25: 99 4a 18     :InitCitLoop    sta     city_status,y
0b28: c8                           iny
0b29: c0 06                        cpy     #$06              ;done with all six?
0b2b: d0 f8                        bne     :InitCitLoop
                   ; Initialize missile data area from $4100-4dff.  This is (mostly) zeroed out.
0b2d: a9 41                        lda     #$41
0b2f: 85 18                        sta     missile_ptr+1
0b31: e6 18        :InitMslLoop    inc     missile_ptr+1
0b33: a5 18                        lda     missile_ptr+1
0b35: c9 4e                        cmp     #$4e              ;reached last page?
0b37: 90 03                        bcc     :NotDone          ;not yet, keep going
0b39: 4c 38 0c                     jmp     GameLoop          ;start the game

0b3c: 20 41 0b     :NotDone        jsr     :InitPage
0b3f: d0 f0                        bne     :InitMslLoop      ;(always)

                   ; Zero the page pointed to by $17-18 to zeroes, then store $FF at +$FA.
0b41: a9 00        :InitPage       lda     #$00
0b43: a8                           tay
0b44: 85 17                        sta     missile_ptr       ;set low byte of pointer to zero
0b46: 91 17        :ZeroLoop       sta     (missile_ptr),y   ;set 256 bytes to zero
0b48: c8                           iny
0b49: d0 fb                        bne     :ZeroLoop
0b4b: a0 fa                        ldy     #O_ROW            ;set missile status to inactive
0b4d: a9 ff                        lda     #$ff
0b4f: 91 17                        sta     (missile_ptr),y
0b51: 60                           rts

                   ; 
                   ; Contents of hi-res row 155, which is 4 lines above the text window.  The
                   ; values here are compared against the current state to determine whether a city
                   ; has been damaged.  (When the on-screen value of the city center is zero, the
                   ; city is considered destroyed.)
0b52: 00 00 00 00+ orig_row_155    .fill   40,$00
                   ; 
                   ; Launcher status.
                   ; 
                   ; All values are initialized to 152, possibly to indicate the hi-res row from
                   ; which ABMs launch, but in practice this is treated as a bool (zero/nonzero)
                   ; indicating whether the launcher is alive.  It's also set to zero when the
                   ; launcher fires.
0b7a: 00 00 00 00+ launcher_status .bulk   $00,$00,$00,$00,$00
                   ; 
                   ; Appears to be hi-res pixel column (0-255 of 279) from which ABMs launch from
                   ; the five launchers.
0b7f: 24 56 88 ba+ launcher_posns  .bulk   $24,$56,$88,$ba,$ec

                   ; 
                   ; After an ABM has finished exploding, check the state of all launchers of the
                   ; same class (inner vs. outer).  Redraw it if necessary, or mark it as disabled
                   ; if it has been destroyed.  The state of the launcher we just used will be $00
                   ; (inactive), so the goal here is to decide if we want to re-enable it.
                   ; 
                   ; We do this *after* the ABM has exploded, which means a "dead" launcher can
                   ; fire one last missile before it's marked as inactive.  (BUG?)
                   ; 
0b84: a0 fe        CheckOuterLau   ldy     #$fe              ;start with even-numbered launchers
0b86: d0 02                        bne     :ChkLauLoop       ;(always)

0b88: a0 ff        CheckInnerLau   ldy     #$ff              ;start with odd-numbered launchers
0b8a: c8           :ChkLauLoop     iny                       ;increment twice so we only check odds or evens
0b8b: c8                           iny
0b8c: 8c e7 0b                     sty     :_NextLauncher+1  ;save index
0b8f: b9 7a 0b                     lda     launcher_status,y ;check status
0b92: d0 52                        bne     :_NextLauncher    ;launcher is enabled, skip
0b94: a2 03                        ldx     #$03
0b96: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
0b99: ae e7 0b                     ldx     :_NextLauncher+1  ;get index
0b9c: bd 7f 0b                     lda     launcher_posns,x  ;get pixel column
0b9f: aa                           tax
0ba0: a0 00                        ldy     #$00
0ba2: a9 9b                        lda     #155
0ba4: 20 11 f4                     jsr     BAS_HPOSN         ;get address for (xc,155)
0ba7: b1 26                        lda     (BAS_HBASL),y     ;grab a byte at that address
0ba9: d0 0a                        bne     :StillAlive       ;nonzero, launcher is still alive
0bab: ac e7 0b                     ldy     :_NextLauncher+1  ;get index
0bae: a9 00                        lda     #$00
0bb0: 99 7a 0b                     sta     launcher_status,y ;mark launcher as dead (redundant)
0bb3: f0 31                        beq     :_NextLauncher    ;(always)

0bb5: d9 52 0b     :StillAlive     cmp     orig_row_155,y    ;is launcher mid-line undamaged?
0bb8: f0 16                        beq     :NoDamage         ;yes, no need to redraw bottom
0bba: ac e7 0b                     ldy     :_NextLauncher+1
0bbd: b9 7f 0b                     lda     launcher_posns,y  ;get the horizontal offset
0bc0: 38                           sec
0bc1: e9 06                        sbc     #$06              ;slide back 6 pixels
0bc3: aa                           tax
0bc4: a0 00                        ldy     #$00
0bc6: a9 9d                        lda     #157
0bc8: 20 57 f4                     jsr     BAS_HPLOT0        ;plot a point at xc,157
0bcb: 20 7d 13                     jsr     InA_DrawShape     ;draw the launcher bottom
0bce: b9 14                        .dd2    shape_laun_bot
0bd0: ae e7 0b     :NoDamage       ldx     :_NextLauncher+1
0bd3: bd 7f 0b                     lda     launcher_posns,x  ;get horizontal position
0bd6: 9d 7a 0b                     sta     launcher_status,x ;mark launcher as alive (posn is always nonzer)
0bd9: aa                           tax                       ;copy horiz position to X-reg
0bda: a0 00                        ldy     #$00
0bdc: a9 98                        lda     #152
0bde: 20 57 f4                     jsr     BAS_HPLOT0        ;plot a point at xc,152
0be1: 20 7d 13                     jsr     InA_DrawShape     ;draw the launcher top
0be4: dd 14                        .dd2    shape_laun_top
0be6: a0 00        :_NextLauncher  ldy     #$00              ;get current value of counter (self-mod)
0be8: c0 05                        cpy     #$05              ;processed all appropriate launchers?
0bea: 90 9e                        bcc     :ChkLauLoop       ;not yet, branch
0bec: 60                           rts

0bed: 00           page_counter    .dd1    $00               ;game loop counts 0-10 for $4200-4c00
0bee: 00 00        temp            .dd2    $0000             ;general-purpose temporary storage
0bf0: 00           auto_play_flag  .dd1    $00               ;bool 00/ff: are we in auto-play (attract) mode?
                   mssl_destroy_cnt
0bf1: 00 00                        .dd2    $0000             ;number of missiles destroyed
0bf3: 00 00        abm_fired_cnt   .dd2    $0000             ;number of ABMs fired
0bf5: 88 48 00 00+ spawn_prob      .bulk   $88,$48,$00,$00,$00 ;fp: probability of missile spawn (lower=more likely)
0bfa: 88 00 00 00+ const_128       .bulk   $88,$00,$00,$00,$00 ;fp: 128.0
0bff: 85 48 00 00+ const_25        .bulk   $85,$48,$00,$00,$00 ;fp: 25.0
0c04: 87 48 00 00+ const_100       .bulk   $87,$48,$00,$00,$00 ;fp: 100.0
0c09: 83 40 00 00+ const_6         .bulk   $83,$40,$00,$00,$00 ;fp: 6.0
0c0e: 00 00 00 00+                 .junk   10
0c18: 00 00 00 00+ xc_delta_temp   .fill   5,$00             ;fp: temp storage for missile/abm delta X
0c1d: 00 00 00 00+ score_m_temp    .fill   5,$00             ;fp: temporary storage while computing score
0c22: 00 00 00 00+                 .junk   10
0c2c: 00 00 00 00+ score_temp      .fill   5,$00             ;fp: temporary storage while computing score
0c31: 00 00 00 00+ high_score      .fill   5,$00             ;fp: high score
0c36: 00 00                        .junk   2

                   ********************************************************************************
                   * Main game loop.                                                              *
                   *                                                                              *
                   * Each iteration, the page counter is incremented, cycling through 0-10.  On   *
                   * cycles 0 through 5 we check to see if we want to spawn a missile.  6 through *
                   * 10 are reserved for MIRV spawns.  (When a missile splits, the initial slot   *
                   * plus 5 additional slots means all 6 cities can be targeted if no other MIRVs *
                   * are active.)                                                                 *
                   *                                                                              *
                   * Missiles are only updated when it's their turn, so each missile is advanced  *
                   * once every 11 frames.                                                        *
                   ********************************************************************************
0c38: a5 cb        GameLoop        lda     strobe_thing?     ;(no idea what the point of this is)
0c3a: 4d 40 c0                     eor     STROBE
0c3d: 85 cb                        sta     strobe_thing?
0c3f: ee ed 0b                     inc     page_counter
0c42: ad ed 0b                     lda     page_counter
0c45: c9 0b                        cmp     #11               ;did counter hit 11?
0c47: 90 09                        bcc     :SkipSound        ;not yet, branch
0c49: 20 5c 13                     jsr     PlaySounds        ;update sound effects
0c4c: a9 00                        lda     #$00              ;reset counter
0c4e: 8d ed 0b                     sta     page_counter
0c51: 18                           clc
0c52: 69 42        :SkipSound      adc     #$42              ;set pointer to $4200, $4300, ... $4C00
0c54: 85 18                        sta     missile_ptr+1
0c56: a9 00                        lda     #$00              ;set pointer low byte
0c58: 85 17                        sta     missile_ptr
0c5a: a0 fa                        ldy     #O_ROW
0c5c: b1 17                        lda     (missile_ptr),y   ;check current row
0c5e: c9 ff                        cmp     #$ff              ;is it $FF?
0c60: f0 03                        beq     :SkipUpdate       ;yes, missile is inactive; branch
0c62: 4c fe 0c                     jmp     :UpdateMissile    ;go update this missile

0c65: ad ed 0b     :SkipUpdate     lda     page_counter
0c68: c9 06                        cmp     #$06              ;are we on page 0-5?
0c6a: b0 0f                        bcs     :NoSpawn          ;no, don't spawn new missile here
0c6c: 20 ae ef                     jsr     BAS_RND           ;generate random [0,1)
0c6f: 20 91 15                     jsr     InA_MulFloat      ;multiply by spawn probability
0c72: f5 0b                        .dd2    spawn_prob
0c74: 20 f2 eb                     jsr     BAS_QINT          ;convert to int in FAC1..FAC4
0c77: a5 a1                        lda     BAS_FAC+4         ;check least-significant byte
0c79: f0 03                        beq     :DoSpawn          ;if it's zero, spawn a new missile
0c7b: 4c 56 13     :NoSpawn        jmp     JmpUpdateAbm

                   ; Create a new missile in this slot.  Start by increasing the probably of
                   ; missile and MIRV spawns.  This reaches its maximum after 110 missiles.
0c7e: 20 73 15     :DoSpawn        jsr     InA_LoadFloat     ;get spawn probability in FAC
0c81: f5 0b                        .dd2    spawn_prob
0c83: 20 a6 15                     jsr     InA_CmpFloat      ;compare to 10.0
0c86: 50 ea                        .dd2    BAS_CON_TEN
0c88: 30 0d                        bmi     :NoDec            ;FAC < 10, don't reduce further; branch
0c8a: 20 8b 15                     jsr     InA_SubFloat      ;FAC = 1 - FAC
0c8d: 13 e9                        .dd2    BAS_CON_ONE
0c8f: 20 d0 ee                     jsr     BAS_NEGOP         ;negate value
0c92: 20 ac 15                     jsr     InA_StoreFloat    ;store it (essentially "FAC = FAC - 1")
0c95: f5 0b                        .dd2    spawn_prob
0c97: 20 ae ef     :NoDec          jsr     BAS_RND           ;random number [0,1)
0c9a: 20 91 15                     jsr     InA_MulFloat      ;multiply by 128.0 [0,128)
0c9d: fa 0b                        .dd2    const_128
0c9f: 20 85 15                     jsr     InA_AddFloat      ;add 6.0 (6,134)
0ca2: 09 0c                        .dd2    const_6
0ca4: 20 ac 15                     jsr     InA_StoreFloat    ;save it as the horizontal start position
0ca7: e2 42                        .dd2    missile_cur_xc
0ca9: 20 ae ef                     jsr     BAS_RND           ;random number [0,1)
0cac: 20 91 15                     jsr     InA_MulFloat      ;multiply by spawn probability
0caf: f5 0b                        .dd2    spawn_prob
0cb1: 20 91 15                     jsr     InA_MulFloat      ;multiply by 0.25
0cb4: 70 f0                        .dd2    BAS_QUARTER
0cb6: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0cb9: a4 a1                        ldy     BAS_FAC+4         ;get value as int (yields 3.3% - 33% chance)
0cbb: d0 16                        bne     :SkipMirv         ;not zero, don't make it a MIRV
                   ; This missile is a MIRV.  Determine the height at which it will split.
0cbd: 20 ae ef                     jsr     BAS_RND           ;random number [0,1)
0cc0: 20 91 15                     jsr     InA_MulFloat      ;multiply by 100.0 [0,100)
0cc3: 04 0c                        .dd2    const_100
0cc5: 20 91 15                     jsr     InA_MulFloat      ;multiply by 0.5 [0,50)
0cc8: 64 ee                        .dd2    BAS_CON_HALF
0cca: 20 f2 eb                     jsr     BAS_QINT          ;convert to int [0,49]
0ccd: a5 a1                        lda     BAS_FAC+4         ;get least-significant byte
0ccf: 69 19                        adc     #25               ;add 25 [25,74]
0cd1: d0 02                        bne     :SkipLoad         ;(always)
                   ; Set MIRV row and missile status.
0cd3: a9 00        :SkipMirv       lda     #$00
0cd5: a0 fd        :SkipLoad       ldy     #O_MIRV_ROW
0cd7: 91 17                        sta     (missile_ptr),y
0cd9: a9 00                        lda     #$00
0cdb: a0 fa                        ldy     #O_ROW
0cdd: 91 17                        sta     (missile_ptr),y   ;mark missile as alive
                   ; Target a city.  The game ends when all cities are dead, so we shouldn't be
                   ; here unless there's something to target.
0cdf: 20 ae ef                     jsr     BAS_RND           ;random number [0,1)
0ce2: 20 91 15                     jsr     InA_MulFloat      ;multiply by 6.0 [0,6)
0ce5: 09 0c                        .dd2    const_6
0ce7: 20 f2 eb                     jsr     BAS_QINT          ;convert to int [0,5]
0cea: a4 a1                        ldy     BAS_FAC+4         ;start with this city
0cec: b9 4a 18     :ScanCities     lda     city_status,y     ;is city alive?
0cef: d0 09                        bne     :CityPicked       ;yes, branch
0cf1: c8                           iny
0cf2: c0 06                        cpy     #$06              ;end of list?
0cf4: d0 f6                        bne     :ScanCities       ;not yet, loop
0cf6: a0 00                        ldy     #$00              ;start over at start of list
0cf8: f0 f2                        beq     :ScanCities       ;loop (always)

0cfa: 98           :CityPicked     tya
0cfb: 20 a0 0e                     jsr     TargetCity        ;configure missile to fly toward city
                   ; 
                   ; Update the missile.  Start by seeing if we've reached terminal height.
                   ; 
0cfe: a0 fa        :UpdateMissile  ldy     #O_ROW
0d00: b1 17                        lda     (missile_ptr),y   ;get current row
0d02: 8d ee 0b                     sta     temp              ;save for later
0d05: a0 fb                        ldy     #O_DET_ROW
0d07: b1 17                        lda     (missile_ptr),y   ;get detonation row (why not CMP here?)
0d09: cd ee 0b                     cmp     temp              ;have we reached it?
0d0c: f0 02                        beq     :Explode          ;yes, explode
0d0e: b0 03                        bcs     :MoveDown         ;no, keep moving
0d10: 4c c4 0d     :Explode        jmp     MissileExploding  ;update explosion animation

                   ; Advance the missile.  We move twice each frame.
0d13: ee ee 0b     :MoveDown       inc     temp              ;move to next row
0d16: 20 5c 13                     jsr     PlaySounds
                   ; Start by overwriting the white missile head with green trail.
0d19: a2 01                        ldx     #$01
0d1b: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=green
0d1e: 20 73 15                     jsr     InA_LoadFloat     ;get current column
0d21: e2 42                        .dd2    missile_cur_xc
0d23: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0d26: ac ee 0b                     ldy     temp              ;get row
0d29: 88                           dey                       ;move up so we're at current row
0d2a: 98                           tya
0d2b: a6 a1                        ldx     BAS_FAC+4         ;get current column as int
0d2d: 20 07 14                     jsr     DrawPixel         ;overwrite white head with green
0d30: 20 73 15                     jsr     InA_LoadFloat     ;get current column
0d33: e2 42                        .dd2    missile_cur_xc
0d35: 20 85 15                     jsr     InA_AddFloat      ;add movement delta
0d38: ee 42                        .dd2    missile_xmove
0d3a: 20 ac 15                     jsr     InA_StoreFloat    ;save it
0d3d: e2 42                        .dd2    missile_cur_xc
0d3f: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0d42: ac ee 0b                     ldy     temp              ;get next row
0d45: a5 a1                        lda     BAS_FAC+4         ;get next column
0d47: 91 17                        sta     (missile_ptr),y   ;save in pixel list
0d49: 98                           tya
0d4a: a0 fa                        ldy     #O_ROW
0d4c: 91 17                        sta     (missile_ptr),y   ;update current row
0d4e: a6 a1                        ldx     BAS_FAC+4         ;get column
0d50: a8                           tay
0d51: 20 07 14                     jsr     DrawPixel         ;draw green pixel
0d54: c9 03                        cmp     #$03              ;was screen previously white?
0d56: f0 45                        beq     :Collision        ;yes, ran into something
0d58: ee ee 0b                     inc     temp              ;move to next row (+2)
0d5b: ad ee 0b                     lda     temp
0d5e: a0 fa                        ldy     #O_ROW
0d60: 91 17                        sta     (missile_ptr),y   ;update current row (again)
0d62: a2 03                        ldx     #$03
0d64: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
0d67: 20 73 15                     jsr     InA_LoadFloat     ;get current column
0d6a: e2 42                        .dd2    missile_cur_xc
0d6c: 20 85 15                     jsr     InA_AddFloat      ;add movement delta
0d6f: ee 42                        .dd2    missile_xmove
0d71: 20 ac 15                     jsr     InA_StoreFloat    ;save it
0d74: e2 42                        .dd2    missile_cur_xc
0d76: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0d79: ac ee 0b                     ldy     temp              ;get row
0d7c: a5 a1                        lda     BAS_FAC+4         ;get column
0d7e: 91 17                        sta     (missile_ptr),y   ;save in pixel list
0d80: a6 a1                        ldx     BAS_FAC+4         ;get column (TAX?)
0d82: ad ee 0b                     lda     temp              ;get row (TYA?)
0d85: 20 07 14                     jsr     DrawPixel         ;draw white pixel
0d88: c9 03                        cmp     #$03              ;was screen previously white?
0d8a: f0 11                        beq     :Collision        ;yes, ran into something
0d8c: a0 fd                        ldy     #O_MIRV_ROW
0d8e: b1 17                        lda     (missile_ptr),y   ;get MIRV row
0d90: f0 05                        beq     :NotMirv          ;zero, not a MIRV
0d92: cd ee 0b                     cmp     temp              ;have we reached the split point?
0d95: 90 03                        bcc     :SplitMirv        ;yes, handle that
0d97: 4c 56 13     :NotMirv        jmp     JmpUpdateAbm

0d9a: 4c c5 11     :SplitMirv      jmp     SplitMirv

                   ; Missile has collided with something.  Disable or detonate.
0d9d: ad ee 0b     :Collision      lda     temp              ;get current row
0da0: a0 fb                        ldy     #O_DET_ROW
0da2: 91 17                        sta     (missile_ptr),y   ;set this as the detonation row
0da4: a0 fa                        ldy     #O_ROW
0da6: 91 17                        sta     (missile_ptr),y   ;and the current row
0da8: 20 ae ef                     jsr     BAS_RND           ;get randon number [0,1)
0dab: 20 91 15                     jsr     InA_MulFloat      ;multiply by 10.0 [0,10)
0dae: 50 ea                        .dd2    BAS_CON_TEN
0db0: 20 f2 eb                     jsr     BAS_QINT          ;convert to int [0,9]
0db3: a5 a1                        lda     BAS_FAC+4         ;get least significant byte
0db5: f0 0d                        beq     MissileExploding  ;if zero, detonate (10% chance)
0db7: a0 f4                        ldy     #O_DET_SIZE       ;otherwise, mark as exploded for recycling
0db9: b1 17                        lda     (missile_ptr),y   ;get detonation size
0dbb: c8                           iny                       ;O_DET_STAGE1
0dbc: 91 17                        sta     (missile_ptr),y   ;init stage 1 size to "done"
0dbe: c8                           iny                       ;O_DET_STAGE2
0dbf: 91 17                        sta     (missile_ptr),y   ;init stage 2 size to "done"
0dc1: 4c 56 13                     jmp     JmpUpdateAbm      ;done with missile

                   ; 
                   ; Update missile explosion.
                   ; 
                   MissileExploding
0dc4: a0 f4                        ldy     #O_DET_SIZE
0dc6: b1 17                        lda     (missile_ptr),y   ;get detonation size
0dc8: 8d ee 0b                     sta     temp
0dcb: a0 f5                        ldy     #O_DET_STAGE1
0dcd: b1 17                        lda     (missile_ptr),y   ;get stage 1 progress
0dcf: 8d c5 15                     sta     _DrawCircIndex+1
0dd2: cd ee 0b                     cmp     temp              ;are we finished?
0dd5: f0 37                        beq     :Stage2           ;yes, check stage 2
0dd7: c9 00                        cmp     #$00              ;have we started yet?
0dd9: d0 0c                        bne     :InProgress1      ;yes, branch
0ddb: ad ee 0b                     lda     temp              ;no, tweak sound effects with det size
0dde: 4a                           lsr     A                 ;divide by 8
0ddf: 4a                           lsr     A
0de0: 4a                           lsr     A
0de1: 6d 43 18                     adc     sound_fx_mod      ;note carry set with last shifted bit
0de4: 8d 43 18                     sta     sound_fx_mod
0de7: a2 03        :InProgress1    ldx     #$03
0de9: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
0dec: 20 73 15                     jsr     InA_LoadFloat     ;get missile's horizontal position
0def: e2 42                        .dd2    missile_cur_xc
0df1: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0df4: a0 fa                        ldy     #O_ROW
0df6: b1 17                        lda     (missile_ptr),y   ;get current row
0df8: a8                           tay                       ;use as index
0df9: a5 a1                        lda     BAS_FAC+4         ;get column as int
0dfb: 91 17                        sta     (missile_ptr),y   ;store in missile trail pixel list
0dfd: aa                           tax                       ;center column in X-reg
0dfe: 98                           tya                       ;center row in A-reg
0dff: a0 10                        ldy     #$10              ;draw 16 more pixels
0e01: 20 b8 15                     jsr     DrawExplosion
0e04: a0 f5                        ldy     #O_DET_STAGE1
0e06: ad c5 15                     lda     _DrawCircIndex+1  ;get updated count
0e09: 91 17                        sta     (missile_ptr),y   ;save it
0e0b: 4c 56 13                     jmp     JmpUpdateAbm      ;done with missile

0e0e: a0 f6        :Stage2         ldy     #O_DET_STAGE2
0e10: b1 17                        lda     (missile_ptr),y   ;get stage 2 progress
0e12: 8d c5 15                     sta     _DrawCircIndex+1
0e15: cd ee 0b                     cmp     temp              ;are we finished?
0e18: f0 28                        beq     :DetComplete      ;yes, go evaluate damage
0e1a: a2 00                        ldx     #$00
0e1c: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=black
0e1f: 20 73 15                     jsr     InA_LoadFloat     ;get missile's horizontal position
0e22: e2 42                        .dd2    missile_cur_xc
0e24: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0e27: a0 fa                        ldy     #O_ROW
0e29: b1 17                        lda     (missile_ptr),y   ;get current row
0e2b: a6 a1                        ldx     BAS_FAC+4         ;get column as int
0e2d: a0 10                        ldy     #$10              ;draw 16 more pixels
0e2f: 20 b8 15                     jsr     DrawExplosion
0e32: ce 43 18                     dec     sound_fx_mod      ;update sound FX
0e35: ce 43 18                     dec     sound_fx_mod
0e38: a0 f6                        ldy     #O_DET_STAGE2
0e3a: ad c5 15                     lda     _DrawCircIndex+1  ;get updated count
0e3d: 91 17                        sta     (missile_ptr),y   ;save it
0e3f: 4c 56 13                     jmp     JmpUpdateAbm      ;done with missile

                   ; Detonation complete.  Redraw base line, update stats, and check effects.
0e42: a2 02        :DetComplete    ldx     #$02
0e44: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=purple
0e47: a2 00                        ldx     #$00
0e49: a0 00                        ldy     #$00
0e4b: a9 9f                        lda     #159
0e4d: 20 57 f4                     jsr     BAS_HPLOT0        ;plot point at 0,159
0e50: a2 01                        ldx     #1
0e52: a9 16                        lda     #22
0e54: a0 9f                        ldy     #159
0e56: 20 3a f5                     jsr     BAS_HGLIN         ;draw line to 278,159
0e59: a2 00                        ldx     #$00
0e5b: 20 ec f6                     jsr     BAS_HCOLOR+3      ;set color to black
0e5e: ee f1 0b                     inc     mssl_destroy_cnt  ;increment the number of missiles destroyed
0e61: d0 03                        bne     :NoInc
0e63: ee f2 0b                     inc     mssl_destroy_cnt+1
0e66: 20 5c 13     :NoInc          jsr     PlaySounds        ;update sounds
0e69: 20 42 15                     jsr     InXY_SetTextPos   ;set text position to score area
0e6c: 16                           .dd1    22
0e6d: 0f                           .dd1    15
0e6e: ad f2 0b                     lda     mssl_destroy_cnt+1 ;get destroyed count
0e71: ae f1 0b                     ldx     mssl_destroy_cnt
0e74: 20 24 ed                     jsr     BAS_LINPRT        ;print it
0e77: 20 56 18                     jsr     EvalCityDamage
                   ; Erase the missile trail.
0e7a: a0 fa                        ldy     #O_ROW
0e7c: b1 17                        lda     (missile_ptr),y   ;get final row
0e7e: 8d ef 0b                     sta     temp+1            ;save it
0e81: a9 ff                        lda     #$ff
0e83: 91 17                        sta     (missile_ptr),y   ;mark missile slot as inactive
0e85: 8d ee 0b                     sta     temp              ;init counter to $ff so first inc makes it zero
0e88: ee ee 0b     :EraseLoop      inc     temp
0e8b: ac ee 0b                     ldy     temp              ;get row
0e8e: cc ef 0b                     cpy     temp+1            ;reached the bottom?
0e91: d0 03                        bne     :ErasePixel       ;not yet
0e93: 4c 50 13                     jmp     GameLoopBottom    ;yes, we're done

0e96: b1 17        :ErasePixel     lda     (missile_ptr),y   ;get column we drew on for this row
0e98: aa                           tax
0e99: 98                           tya
0e9a: 20 07 14                     jsr     DrawPixel         ;draw black pixel here
0e9d: 4c 88 0e                     jmp     :EraseLoop

                   ; 
                   ; Configures a missile to target a specific city.
                   ; 
                   ; On entry:
                   ;   A-reg: city to target (0-5)
                   ; 
0ea0: a0 fc        TargetCity      ldy     #O_TARGET_CITY
0ea2: 91 17                        sta     (missile_ptr),y   ;record the city being targeted
                   ; Compute column of target city.
0ea4: 20 93 eb                     jsr     BAS_FLOAT         ;convert A-reg to float in FAC
0ea7: 20 91 15                     jsr     InA_MulFloat      ;multiply by 25 (0-125)
0eaa: ff 0b                        .dd2    const_25
0eac: 20 85 15                     jsr     InA_AddFloat      ;add 10 (10-135)
0eaf: 50 ea                        .dd2    BAS_CON_TEN
0eb1: 20 ac 15                     jsr     InA_StoreFloat
0eb4: e8 42                        .dd2    missile_target_xc
                   ; Compute size of missile explosion.
0eb6: 20 ae ef                     jsr     BAS_RND           ;generate random number [0,1)
0eb9: 20 91 15                     jsr     InA_MulFloat      ;multiply by 6 [0,6)
0ebc: 09 0c                        .dd2    const_6
0ebe: 20 85 15                     jsr     InA_AddFloat      ;add 6 [6,12)
0ec1: 09 0c                        .dd2    const_6
0ec3: 20 f2 eb                     jsr     BAS_QINT          ;convert to int [6,11]
0ec6: a5 a1                        lda     BAS_FAC+4         ;get least significant byte
0ec8: 18                           clc
0ec9: 0a                           asl     A                 ;multiply by 16 [96,176]
0eca: 0a                           asl     A
0ecb: 0a                           asl     A
0ecc: 0a                           asl     A
0ecd: a0 f4                        ldy     #O_DET_SIZE
0ecf: 91 17                        sta     (missile_ptr),y
                   ; Pick the detonation height.  We must detonate above the level of the city, or
                   ; the collision with a lit pixel will kill the missile.
                   ; 
                   ; Note we pick our numbers in such a way that deltaX is < 1.0, so we're never in
                   ; a position where we have to draw two pixels on the same row.
0ed1: 20 ae ef                     jsr     BAS_RND           ;generate random number [0,1)
0ed4: 20 91 15                     jsr     InA_MulFloat      ;multiply by 10 [0,10)
0ed7: 50 ea                        .dd2    BAS_CON_TEN
0ed9: 20 f2 eb                     jsr     BAS_QINT          ;convert to int [0,9]
0edc: a5 a1                        lda     BAS_FAC+4         ;get least significant byte
0ede: 49 ff                        eor     #$ff              ;invert [$f6,$ff]
0ee0: 69 96                        adc     #150              ;add 150 [140,149]
0ee2: a0 fb                        ldy     #O_DET_ROW
0ee4: 91 17                        sta     (missile_ptr),y
                   ; Init explosion trackers.
0ee6: a9 00                        lda     #$00
0ee8: a0 f5                        ldy     #O_DET_STAGE1
0eea: 91 17                        sta     (missile_ptr),y
0eec: c8                           iny
0eed: 91 17                        sta     (missile_ptr),y
                   ; Compute how far the missile moves horizontally each frame.
0eef: 20 73 15                     jsr     InA_LoadFloat     ;get starting X coordinate
0ef2: e2 42                        .dd2    missile_cur_xc
0ef4: 20 8b 15                     jsr     InA_SubFloat      ;subtract target X coordinate
0ef7: e8 42                        .dd2    missile_target_xc
0ef9: 20 ac 15                     jsr     InA_StoreFloat    ;save delta X
0efc: 18 0c                        .dd2    xc_delta_temp
0efe: a0 fa                        ldy     #O_ROW
0f00: b1 17                        lda     (missile_ptr),y   ;get missile's row (will be nonzero for MIRV)
0f02: 49 ff                        eor     #$ff              ;invert
0f04: 18                           clc
0f05: 69 a0                        adc     #160              ;add 160 to get approximate delta Y
0f07: a8                           tay
0f08: 20 01 e3                     jsr     BAS_SNGFLT        ;convert to float in FAC
0f0b: 20 97 15                     jsr     InA_DivFloat      ;FAC = deltaX / deltaY
0f0e: 18 0c                        .dd2    xc_delta_temp
0f10: 20 ac 15                     jsr     InA_StoreFloat    ;save as per-frame horizontal movement
0f13: ee 42                        .dd2    missile_xmove
                   ; Record initial position.
0f15: 20 73 15                     jsr     InA_LoadFloat
0f18: e2 42                        .dd2    missile_cur_xc    ;get start column
0f1a: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
0f1d: a0 fa                        ldy     #O_ROW
0f1f: b1 17                        lda     (missile_ptr),y   ;get missile's row
0f21: a8                           tay                       ;use as index
0f22: a5 a1                        lda     BAS_FAC+4         ;get column as int
0f24: 91 17                        sta     (missile_ptr),y   ;save it so we can erase it later
0f26: 60                           rts

                   ; 
                   ; Update the ABM, or check user input if none is in flight.
                   ; 
0f27: ad fa 4d     UpdateAbmMaybe  lda     abm_row           ;is an ABM in flight?
0f2a: c9 ff                        cmp     #$ff
0f2c: f0 03                        beq     :GetInput         ;no, get user input
0f2e: 4c 6f 10                     jmp     UpdateAbm         ;yes, update it

0f31: ad f0 0b     :GetInput       lda     auto_play_flag    ;are we in attract mode?
0f34: f0 03                        beq     ReadUserInput     ;no, get user input
0f36: 4c 85 12                     jmp     AutoPlay          ;yes, auto-play

                   ; 
                   ; Reads paddles and buttons.
                   ; 
                   ; To avoid slowing the game down with excessive controller reads, and also to
                   ; mitigate paddle cross-talk, the paddle reads are distributed across frames. 
                   ; We do two frames with no reads, one frame for paddle X, and one frame for
                   ; paddle Y.
                   ; 
                   ; The cursor is only on-screen while we are reading the paddles, which is why
                   ; it's a flickery mess.
                   ; 
                   ; This is not called while an ABM is in flight.
                   ; 
0f39: ee 3d 0f     ReadUserInput   inc     :_IgnorePaddle+1
0f3c: a2 00        :_IgnorePaddle  ldx     #$00              ;do we want to check the paddles this time?
0f3e: 30 2d                        bmi     :SkipPaddles      ;no, skip it
0f40: d0 11                        bne     :ReadY            ;if it's #$01, read the Y axis
0f42: 20 86 13                     jsr     DrawCursor        ;draw the cursor
0f45: 20 5c 13                     jsr     PlaySounds        ;play sound effects
0f48: 20 00 03                     jsr     ReadPdlX          ;read X-axis paddle
0f4b: 4a                           lsr     A                 ;halve it; note LSB is now in carry
0f4c: 69 06                        adc     #$06              ;add 6 to get [6,134]
0f4e: 8d 79 13                     sta     cursor_x
0f51: d0 14                        bne     :Cont             ;(always)

0f53: 20 86 13     :ReadY          jsr     DrawCursor        ;draw the cursor
0f56: 20 5c 13                     jsr     PlaySounds        ;play sound effects
0f59: 20 03 03                     jsr     ReadPdlY          ;read Y-axis paddle
0f5c: 4a                           lsr     A                 ;halve it; note LSB is now in carry
0f5d: 69 03                        adc     #$03              ;add 3 to get [3,131]
0f5f: 8d 7a 13                     sta     cursor_y
0f62: a9 fd                        lda     #$fd              ;reset counter to -3
0f64: 8d 3d 0f                     sta     :_IgnorePaddle+1
0f67: 20 5c 13     :Cont           jsr     PlaySounds        ;play sound effects
0f6a: 20 be 13                     jsr     EraseCursor       ;erase the cursor
0f6d: 20 06 03     :SkipPaddles    jsr     GetOuterBtn       ;button for outer/center launchers pressed?
0f70: 90 09                        bcc     :NotOuter         ;no, branch
0f72: a9 50        FireOuter       lda     #$50              ;explosion with 80 pixels
0f74: 8d f4 4d                     sta     abm_max_size
0f77: a0 fe                        ldy     #$fe              ;check even-numbered launchers
0f79: d0 0f                        bne     :FireCommon       ;(always)

0f7b: 20 09 03     :NotOuter       jsr     GetInnerBtn       ;button for inner launchers pressed?
0f7e: b0 03                        bcs     FireInner         ;yes, fire
0f80: 4c 50 13                     jmp     GameLoopBottom

0f83: a9 70        FireInner       lda     #$70              ;explosion with 112 pixels
0f85: 8d f4 4d                     sta     abm_max_size
0f88: a0 ff                        ldy     #$ff              ;check odd-numbered launchers
0f8a: 8c bc 0f     :FireCommon     sty     :_Closest+1
0f8d: a9 64                        lda     #100              ;max horizontal delta for launcher
0f8f: 8d af 0f                     sta     :_Val+1           ; (can't fire farther away than that)
0f92: c8           :NextLauncher   iny                       ;incr twice so we check odd or even
0f93: c8                           iny
0f94: c0 05                        cpy     #$05
0f96: b0 23                        bcs     :_Closest
0f98: b9 7a 0b                     lda     launcher_status,y ;get launcher status
0f9b: f0 f5                        beq     :NextLauncher     ;not available, branch
0f9d: b9 7f 0b                     lda     launcher_posns,y  ;get launcher position
0fa0: 4a                           lsr     A                 ;halve it to get color coordinates (0-139)
0fa1: 38                           sec
0fa2: ed 79 13                     sbc     cursor_x          ;subtract cursor X position
0fa5: c9 00                        cmp     #$00              ;(?)
0fa7: 10 05                        bpl     :_Val             ;positive, branch
0fa9: 49 ff                        eor     #$ff              ;negative, invert to get absolute value
0fab: 38                           sec
0fac: 69 00                        adc     #$00              ;add 1
0fae: c9 00        :_Val           cmp     #$00              ;is it closer than previous value?
0fb0: b0 e0                        bcs     :NextLauncher     ;no, check next
0fb2: 8d af 0f                     sta     :_Val+1           ;yes, this is closest; update
0fb5: 8c bc 0f                     sty     :_Closest+1       ;save launcher index
0fb8: 4c 92 0f                     jmp     :NextLauncher     ;check next

0fbb: a0 00        :_Closest       ldy     #$00              ;did we find a launcher?
0fbd: 10 03                        bpl     :FireAbm          ;yes, fire ABM
0fbf: 4c 50 13                     jmp     GameLoopBottom    ;no, nothing was in range

0fc2: a9 00        :FireAbm        lda     #$00
0fc4: 99 7a 0b                     sta     launcher_status,y ;mark launcher as unavailable
0fc7: b9 7f 0b                     lda     launcher_posns,y  ;get launcher position
0fca: 8d f0 0f                     sta     :_LaunchCol+1     ;set as horizontal coordinate for HPOSN
0fcd: 4a                           lsr     A                 ;divide by two
0fce: a8                           tay
0fcf: c8                           iny                       ;add two
0fd0: c8                           iny
0fd1: 20 01 e3                     jsr     BAS_SNGFLT        ;convert to float
0fd4: 20 ac 15                     jsr     InA_StoreFloat
0fd7: e2 4d                        .dd2    abm_cur_xc
0fd9: ad 7a 13                     lda     cursor_y          ;get target row
0fdc: 8d fb 4d                     sta     abm_target_row    ;save it
0fdf: ac 79 13                     ldy     cursor_x          ;get target column
0fe2: 20 01 e3                     jsr     BAS_SNGFLT        ;convert to float
0fe5: 20 ac 15                     jsr     InA_StoreFloat    ;save it
0fe8: e8 4d                        .dd2    abm_target_xc
0fea: a2 00                        ldx     #$00
0fec: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=black
0fef: a2 00        :_LaunchCol     ldx     #$00              ;starting pixel column
0ff1: a9 98                        lda     #152              ;starting row
0ff3: 8d fa 4d                     sta     abm_row           ;save it
0ff6: ce fa 4d                     dec     abm_row           ;move up one row
0ff9: a0 00                        ldy     #$00
0ffb: 20 11 f4                     jsr     BAS_HPOSN         ;get address of position
0ffe: 20 7d 13                     jsr     InA_DrawShape     ;erase launcher top
1001: dd 14                        .dd2    shape_laun_top
1003: a9 00                        lda     #$00
1005: 8d f5 4d                     sta     abm_det_size1     ;init detonation counters
1008: 8d f6 4d                     sta     abm_det_size2
100b: 20 73 15                     jsr     InA_LoadFloat     ;get start column
100e: e2 4d                        .dd2    abm_cur_xc
1010: 20 8b 15                     jsr     InA_SubFloat      ;subtract from target column
1013: e8 4d                        .dd2    abm_target_xc
1015: 20 ac 15                     jsr     InA_StoreFloat    ;save delta X
1018: 18 0c                        .dd2    xc_delta_temp
101a: ad fa 4d                     lda     abm_row           ;get start row
101d: 38                           sec
101e: ed fb 4d                     sbc     abm_target_row    ;subtract target row (delta Y)
1021: a8                           tay
1022: 20 01 e3                     jsr     BAS_SNGFLT        ;convert to float in FAC
1025: 20 97 15                     jsr     InA_DivFloat      ;FAC = deltaX / deltaY
1028: 18 0c                        .dd2    xc_delta_temp
102a: 20 ac 15                     jsr     InA_StoreFloat    ;save X movement
102d: ee 4d                        .dd2    abm_xmove
102f: 20 af eb                     jsr     BAS_ABS           ;compute absolute value
1032: 20 a6 15                     jsr     InA_CmpFloat      ;compare to 1.0
1035: 13 e9                        .dd2    BAS_CON_ONE
1037: 30 03                        bmi     :GoodAngle        ;less than 1.0, keep going
1039: 4c a1 11                     jmp     StopAbm           ;angle too shallow, won't draw right, disallow

103c: 20 73 15     :GoodAngle      jsr     InA_LoadFloat     ;get initial column
103f: e2 4d                        .dd2    abm_cur_xc
1041: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
1044: ac fa 4d                     ldy     abm_row           ;get current row
1047: a5 a1                        lda     BAS_FAC+4         ;get initial column as int
1049: 99 00 4d                     sta     abm_trail,y       ;record position in trail record
104c: ee f3 0b                     inc     abm_fired_cnt     ;increment number of ABMs fired
104f: d0 03                        bne     :NoInc
1051: ee f4 0b                     inc     abm_fired_cnt+1
1054: 20 42 15     :NoInc          jsr     InXY_SetTextPos
1057: 16                           .dd1    22                ;status row
1058: 14                           .dd1    20
1059: ae f3 0b                     ldx     abm_fired_cnt     ;get number of ABMs fired
105c: ad f4 0b                     lda     abm_fired_cnt+1
105f: 20 24 ed                     jsr     BAS_LINPRT        ;print value
1062: 20 2b 15                     jsr     InS_PrintString
1065: a0 c1 c2 cd+                 .zstr   “ ABM'S”
106c: 4c 50 13                     jmp     GameLoopBottom

                   ; 
                   ; Updates ABM movement.
                   ; 
106f: 20 5c 13     UpdateAbm       jsr     PlaySounds
1072: ad fb 4d                     lda     abm_target_row    ;get target row
1075: cd fa 4d                     cmp     abm_row           ;compare to current row
1078: 90 03                        bcc     :StillFlying      ;not there yet, branch
107a: 4c ef 10                     jmp     AbmExploding      ;detonate!

                   ; Move the ABM up two rows.
107d: ce fa 4d     :StillFlying    dec     abm_row           ;reduce row (move toward top of screen)
1080: a2 02                        ldx     #$02
1082: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=purple
1085: ac fa 4d                     ldy     abm_row           ;get next row
1088: c8                           iny                       ;inc to get current row
1089: 98                           tya
108a: be 00 4d                     ldx     abm_trail,y       ;get pixel position
108d: 20 07 14                     jsr     DrawPixel         ;draw purple pixel on top of white head
1090: 20 73 15                     jsr     InA_LoadFloat     ;get current column
1093: e2 4d                        .dd2    abm_cur_xc
1095: 20 85 15                     jsr     InA_AddFloat      ;add movement delta
1098: ee 4d                        .dd2    abm_xmove
109a: 20 ac 15                     jsr     InA_StoreFloat    ;save updated position
109d: e2 4d                        .dd2    abm_cur_xc
109f: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer
10a2: ac fa 4d                     ldy     abm_row           ;get current row
10a5: a5 a1                        lda     BAS_FAC+4         ;get column as integer
10a7: 99 00 4d                     sta     abm_trail,y       ;save in ABM trail list
10aa: aa                           tax
10ab: 98                           tya
10ac: 20 07 14                     jsr     DrawPixel         ;draw trail
10af: c9 03                        cmp     #$03              ;did we hit something?
10b1: f0 36                        beq     :AbmCollision     ;yes, branch
10b3: ce fa 4d                     dec     abm_row           ;move down a row
10b6: a2 03                        ldx     #$03
10b8: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
10bb: 20 73 15                     jsr     InA_LoadFloat     ;get current column
10be: e2 4d                        .dd2    abm_cur_xc
10c0: 20 85 15                     jsr     InA_AddFloat      ;add movement delta
10c3: ee 4d                        .dd2    abm_xmove
10c5: 20 ac 15                     jsr     InA_StoreFloat    ;save updated position
10c8: e2 4d                        .dd2    abm_cur_xc
10ca: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer
10cd: ac fa 4d                     ldy     abm_row           ;get current row
10d0: a5 a1                        lda     BAS_FAC+4         ;get column as integer
10d2: 99 00 4d                     sta     abm_trail,y       ;save in ABM trail list
10d5: aa                           tax
10d6: 98                           tya
10d7: 20 07 14                     jsr     DrawPixel         ;draw missile head
10da: c9 03                        cmp     #$03              ;did we hit something?
10dc: f0 0b                        beq     :AbmCollision     ;yes, branch
10de: 20 5c 13                     jsr     PlaySounds
10e1: a9 28                        lda     #$28              ;sleep for ~4.5 msec (feels a little smoother
10e3: 20 a8 fc                     jsr     MON_WAIT          ; when things aren't too busy)
10e6: 4c 50 13                     jmp     GameLoopBottom

10e9: ad fa 4d     :AbmCollision   lda     abm_row           ;set current = target so we know ABM is exploding
10ec: 8d fb 4d                     sta     abm_target_row
10ef: 20 5c 13     AbmExploding    jsr     PlaySounds
10f2: ad f5 4d                     lda     abm_det_size1     ;check stage 1 detonation size
10f5: 8d c5 15                     sta     _DrawCircIndex+1
10f8: cd f4 4d                     cmp     abm_max_size      ;done yet?
10fb: f0 34                        beq     :Stage2           ;yes, branch
10fd: c9 00                        cmp     #$00              ;initial detonation?
10ff: d0 0b                        bne     :NotFirst         ;no, skip sound adjust
1101: ad f4 4d                     lda     abm_max_size      ;get max size
1104: 4a                           lsr     A                 ;divide by 2
1105: 18                           clc
1106: 6d 43 18                     adc     sound_fx_mod      ;tweak sound effects
1109: 8d 43 18                     sta     sound_fx_mod
110c: a2 03        :NotFirst       ldx     #$03
110e: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
1111: 20 73 15                     jsr     InA_LoadFloat     ;get current column
1114: e2 4d                        .dd2    abm_cur_xc
1116: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
1119: ac fa 4d                     ldy     abm_row           ;get current row
111c: a5 a1                        lda     BAS_FAC+4         ;get current col as int
111e: 99 00 4d                     sta     abm_trail,y       ;save in trail list
1121: aa                           tax
1122: 98                           tya
1123: a0 08                        ldy     #$08              ;expand circle by 8 pixels
1125: 20 b8 15                     jsr     DrawExplosion     ;draw it
1128: ad c5 15                     lda     _DrawCircIndex+1  ;get updated count
112b: 8d f5 4d                     sta     abm_det_size1     ;save it
112e: 4c 50 13                     jmp     GameLoopBottom

1131: ad f6 4d     :Stage2         lda     abm_det_size2     ;get stage 2 detonation size
1134: 8d c5 15                     sta     _DrawCircIndex+1
1137: cd f4 4d                     cmp     abm_max_size      ;done yet?
113a: f0 2c                        beq     :ExplodeDone      ;yes, go clean up
113c: a2 00                        ldx     #$00
113e: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=black
1141: 20 73 15                     jsr     InA_LoadFloat     ;get current column
1144: e2 4d                        .dd2    abm_cur_xc
1146: 20 f2 eb                     jsr     BAS_QINT          ;convert to int
1149: ad fa 4d                     lda     abm_row           ;get current row
114c: a6 a1                        ldx     BAS_FAC+4         ;get current col as int
114e: a0 08                        ldy     #$08              ;expand circle by 8 pixels
1150: 20 b8 15                     jsr     DrawExplosion     ;draw it
1153: ce 43 18                     dec     sound_fx_mod      ;update sound effects
1156: ce 43 18                     dec     sound_fx_mod
1159: ce 43 18                     dec     sound_fx_mod
115c: ce 43 18                     dec     sound_fx_mod
115f: ad c5 15                     lda     _DrawCircIndex+1  ;get updated count
1162: 8d f6 4d                     sta     abm_det_size2     ;save it
1165: 4c 50 13                     jmp     GameLoopBottom

1168: 20 5c 13     :ExplodeDone    jsr     PlaySounds
                   ; Redraw base line, then erase trail.
116b: a2 02                        ldx     #$02
116d: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=purple
1170: a2 00                        ldx     #$00
1172: a0 00                        ldy     #$00
1174: a9 9f                        lda     #159
1176: 20 57 f4                     jsr     BAS_HPLOT0        ;plot point at 0,159
1179: a2 01                        ldx     #1
117b: a9 16                        lda     #22
117d: a0 9f                        ldy     #159
117f: 20 3a f5                     jsr     BAS_HGLIN         ;draw line to 278,159
1182: a2 00                        ldx     #$00
1184: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=black
1187: a9 99                        lda     #153              ;start row is 152, add 1 to compensate for
1189: 8d ee 0b                     sta     temp              ; initial DEC
118c: ce ee 0b     :Loop           dec     temp
118f: ac ee 0b                     ldy     temp              ;get row
1192: cc fa 4d                     cpy     abm_row           ;reached end of trail?
1195: 90 0a                        bcc     StopAbm           ;yes, branch
1197: be 00 4d                     ldx     abm_trail,y       ;get pixel column
119a: 98                           tya
119b: 20 07 14                     jsr     DrawPixel         ;draw black pixel
119e: 4c 8c 11                     jmp     :Loop

                   ; ABM is done exploding, reset state and check launcher.
11a1: a9 ff        StopAbm         lda     #$ff
11a3: 8d fa 4d                     sta     abm_row           ;mark ABM as inactive
11a6: a2 03                        ldx     #$03
11a8: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=white
11ab: ad f4 4d                     lda     abm_max_size      ;get size of ABM we just fired
11ae: c9 50                        cmp     #$50              ;from outer/center launcher?
11b0: d0 06                        bne     :InnerLauncher    ;no, branch
11b2: 20 84 0b                     jsr     CheckOuterLau
11b5: 4c 50 13                     jmp     GameLoopBottom

11b8: 20 88 0b     :InnerLauncher  jsr     CheckInnerLau
11bb: 4c 50 13                     jmp     GameLoopBottom

                   temp_missile_col
11be: 00 00 00 00+                 .fill   5,$00             ;fp: temp storage for missile column
                   temp_missile_row
11c3: 00                           .dd1    $00
11c4: 00           temp_city_off   .dd1    $00

                   ; 
                   ; Split one missile into up to six, one per city.
                   ; 
                   ; Note this does NOT zero out the MIRV split row, so the original missile will
                   ; try to split continuously, limited only by slot availability.  (Bug?)
                   ; 
11c5: 20 73 15     SplitMirv       jsr     InA_LoadFloat     ;get missile's column
11c8: e2 42                        .dd2    missile_cur_xc
11ca: 20 ac 15                     jsr     InA_StoreFloat    ;save in temp
11cd: be 11                        .dd2    temp_missile_col
11cf: a0 fa                        ldy     #O_ROW
11d1: b1 17                        lda     (missile_ptr),y   ;get missile's row
11d3: 18                           clc
11d4: e9 00                        sbc     #$00              ;subtract 1
11d6: 8d c3 11                     sta     temp_missile_row  ;save in temp
11d9: a9 02                        lda     #$02
11db: a0 fc                        ldy     #O_TARGET_CITY    ;set target city (redundant; target city
11dd: 91 17                        sta     (missile_ptr),y   ; subroutine does this too)
11df: 20 a0 0e                     jsr     TargetCity        ;configure original missile to target city #2
11e2: a5 17                        lda     missile_ptr       ;get current page pointer
11e4: 8d 7b 12                     sta     :_RestorePtr+1    ;save it off
11e7: a9 fd                        lda     #$fd              ;init city offset to -3
11e9: 8d c4 11                     sta     temp_city_off
11ec: a9 47                        lda     #$47              ;start at first page reserved for MIRVs ($48xx)
11ee: 85 18                        sta     missile_ptr+1
11f0: e6 18        :MirvLoop       inc     missile_ptr+1     ;advance to next page
11f2: a5 18                        lda     missile_ptr+1
11f4: c9 4d                        cmp     #$4d              ;did we reach end of slots?
11f6: 90 03                        bcc     :Cont             ;no, branch
11f8: 4c 7a 12                     jmp     :_RestorePtr      ;yes, jump to end

11fb: ee c4 11     :Cont           inc     temp_city_off     ;increment the count
11fe: ad c4 11                     lda     temp_city_off
1201: d0 05                        bne     :NotZero          ;not zero, branch
1203: a9 01                        lda     #$01              ;skip zero, go straight to +1
1205: 8d c4 11                     sta     temp_city_off
1208: 20 93 eb     :NotZero        jsr     BAS_FLOAT         ;convert to float in FAC
120b: 20 85 15                     jsr     InA_AddFloat      ;add to missile column
120e: be 11                        .dd2    temp_missile_col
1210: a0 fa                        ldy     #O_ROW
1212: b1 17                        lda     (missile_ptr),y   ;get row for this missile
1214: c9 ff                        cmp     #$ff              ;is it available?
1216: d0 d8                        bne     :MirvLoop         ;no, move to next slot
1218: 20 ac 15                     jsr     InA_StoreFloat    ;set column for this missile
121b: e2 42                        .dd2    missile_cur_xc
121d: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer
1220: a0 fa                        ldy     #O_ROW
1222: ad c3 11                     lda     temp_missile_row  ;get row - 1
1225: 91 17                        sta     (missile_ptr),y   ;set missile's row
1227: a8                           tay                       ;use row as index
1228: a5 a1                        lda     BAS_FAC+4         ;get column as int
122a: 91 17                        sta     (missile_ptr),y   ;save column in trail list
122c: a6 a1                        ldx     BAS_FAC+4         ;get column as int (TAX?)
122e: ad c3 11                     lda     temp_missile_row  ;get row - 1
1231: 8e 59 12                     stx     _Column+1         ;set column
1234: 20 07 14                     jsr     DrawPixel         ;draw white pixel
1237: ad c4 11                     lda     temp_city_off     ;get offset
123a: 18                           clc
123b: 69 02                        adc     #$02              ;add 2
123d: a0 fc                        ldy     #O_TARGET_CITY
123f: 91 17                        sta     (missile_ptr),y   ;set as target city
1241: 20 a0 0e                     jsr     TargetCity        ;configure missile to hit city
1244: 20 73 15                     jsr     InA_LoadFloat     ;get X movement delta
1247: ee 42                        .dd2    missile_xmove
1249: 20 af eb                     jsr     BAS_ABS           ;compute absolute value
124c: 20 a6 15                     jsr     InA_CmpFloat      ;compare to 1.0
124f: 13 e9                        .dd2    BAS_CON_ONE
1251: 30 21                        bmi     :PathGood         ;it's less, keep it
                   ; MIRV path is too shallow, kill it, and give up.
1253: a2 00                        ldx     #$00
1255: 20 ec f6                     jsr     BAS_HCOLOR+3      ;color=black
1258: a2 00        _Column         ldx     #$00              ;missile column
125a: ad c3 11                     lda     temp_missile_row  ;missile row
125d: 20 07 14                     jsr     DrawPixel         ;erase head
1260: a9 ff                        lda     #$ff
1262: a0 fa                        ldy     #O_ROW
1264: 91 17                        sta     (missile_ptr),y   ;mark missile as inactive
1266: ad 7b 12                     lda     :_RestorePtr+1    ;restore previous pointer value
1269: 85 18                        sta     missile_ptr+1     ;(redundant with code below)
126b: a9 00                        lda     #$00
126d: a0 fd                        ldy     #O_MIRV_ROW
126f: 91 17                        sta     (missile_ptr),y   ;set MIRV row to zero
1271: 4c 7a 12                     jmp     :_RestorePtr

1274: 20 5c 13     :PathGood       jsr     PlaySounds
1277: 4c f0 11                     jmp     :MirvLoop         ;go make another

127a: a9 00        :_RestorePtr    lda     #$00              ;get previous pointer value
127c: 85 18                        sta     missile_ptr+1     ;restore
127e: 4c 38 0c                     jmp     GameLoop

1281: 00           auto_curs_x     .dd1    $00               ;random value, from 6 to 133
1282: 00           auto_curs_y     .dd1    $00               ;random value, from 6 to 133
1283: 00 00                        .junk   2

                   ; 
                   ; Controls the player in "attract mode", moving the cursor and firing ABMs.
                   ; 
1285: ad 00 c0     AutoPlay        lda     KBD               ;check keyboard
1288: 10 03                        bpl     :DoPlay           ;no key hit, keep going
128a: 4c 13 08                     jmp     Restart           ;key hit, jump back to title screen

128d: 20 86 13     :DoPlay         jsr     DrawCursor        ;draw cursor
1290: 20 ae ef                     jsr     BAS_RND           ;get random [0,1)
1293: 20 91 15                     jsr     InA_MulFloat      ;multiply by 128 [0,128)
1296: fa 0b                        .dd2    const_128
1298: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer [0,127]
129b: a5 a1                        lda     BAS_FAC+4         ;get value as int
129d: f0 7a                        beq     :MoveFireOuter    ;if zero, fire outer, move to new position
129f: c9 01                        cmp     #$01
12a1: f0 7f                        beq     :MoveFireInner    ;if 1, fire inner, move to new position
12a3: c9 08                        cmp     #$08
12a5: 90 32                        bcc     :AddWobble        ;if 2-7, ?
12a7: 29 01                        and     #$01              ;odd or even?
12a9: f0 14                        beq     :MoveY            ;even, move Y only
12ab: ad 79 13                     lda     cursor_x          ;get current cursor X position
12ae: 38                           sec
12af: ed 81 12                     sbc     auto_curs_x       ;subtract desired position
12b2: f0 1f                        beq     :MoveDone         ;already there, bail
12b4: 30 06                        bmi     :MoveRight        ;which way do we need to go?
12b6: ce 79 13                     dec     cursor_x          ;move left
12b9: 4c bf 12                     jmp     :MoveY

12bc: ee 79 13     :MoveRight      inc     cursor_x          ;move right
12bf: ad 7a 13     :MoveY          lda     cursor_y          ;get current cursor Y position
12c2: 38                           sec
12c3: ed 82 12                     sbc     auto_curs_y       ;subtract desired position
12c6: f0 0b                        beq     :MoveDone         ;already there, bail
12c8: 30 06                        bmi     :MoveDown
12ca: ce 7a 13                     dec     cursor_y          ;move up
12cd: 4c d3 12                     jmp     :MoveDone

12d0: ee 7a 13     :MoveDown       inc     cursor_y
12d3: 20 be 13     :MoveDone       jsr     EraseCursor       ;erase the cursor
12d6: 4c 38 0c                     jmp     GameLoop

                   ; 
                   ; Add a bit of wobble to the cursor position.
                   ; 
                   ; The computation seems wrong.  It's calculating:
                   ;   (PI/2) - (PI/2) - (2*PI*random)
                   ; which is equivalent to:
                   ;   -2*PI*random
                   ; 
                   ; I think the author probably wanted PI - (2*PI*random), to get an integer value
                   ; in the range [-3,3].  But he only had 2*PI and 0.5*PI, and tried to double-up
                   ; the latter.
                   ; 
                   ; There doesn't seem to be a point in using PI other than as a convenient
                   ; constant.
                   ; 
12d9: 20 ae ef     :AddWobble      jsr     BAS_RND           ;get random number [0,1)
12dc: 20 91 15                     jsr     InA_MulFloat      ;multiply by PI*2 [0,~6.28)
12df: 6b f0                        .dd2    BAS_CON_PI_DOUB
12e1: 20 8b 15                     jsr     InA_SubFloat      ;subtract from PI/2
12e4: 66 f0                        .dd2    BAS_CON_PI_HALF
12e6: 20 8b 15                     jsr     InA_SubFloat      ;again
12e9: 66 f0                        .dd2    BAS_CON_PI_HALF
12eb: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer [0,6]
12ee: a5 a1                        lda     BAS_FAC+4         ;get value as int
12f0: 6d 79 13                     adc     cursor_x          ;add to cursor X position
12f3: 8d 79 13                     sta     cursor_x
12f6: 20 ae ef                     jsr     BAS_RND           ;repeat for Y position
12f9: 20 91 15                     jsr     InA_MulFloat      ; ...
12fc: 6b f0                        .dd2    BAS_CON_PI_DOUB
12fe: 20 8b 15                     jsr     InA_SubFloat
1301: 66 f0                        .dd2    BAS_CON_PI_HALF
1303: 20 85 15                     jsr     InA_AddFloat
1306: 66 f0                        .dd2    BAS_CON_PI_HALF
1308: 20 d0 ee                     jsr     BAS_NEGOP
130b: 20 f2 eb                     jsr     BAS_QINT
130e: a5 a1                        lda     BAS_FAC+4
1310: 6d 7a 13                     adc     cursor_y
1313: 8d 7a 13                     sta     cursor_y
1316: 4c d3 12                     jmp     :MoveDone

1319: 20 2b 13     :MoveFireOuter  jsr     RandomCursorPos   ;pick new position
131c: 20 be 13                     jsr     EraseCursor       ;erase cursor
131f: 4c 72 0f                     jmp     FireOuter         ;fire ABM from outer/center silo

1322: 20 2b 13     :MoveFireInner  jsr     RandomCursorPos   ;pick new position
1325: 20 be 13                     jsr     EraseCursor       ;erase cursor
1328: 4c 83 0f                     jmp     FireInner         ;fire ABM from inner silo

                   ; Pick a random X,Y position for the cursor.
132b: 20 ae ef     RandomCursorPos jsr     BAS_RND           ;get random [0,1)
132e: 20 91 15                     jsr     InA_MulFloat      ;multiply by 128.0 [0,128)
1331: fa 0b                        .dd2    const_128
1333: 20 f2 eb                     jsr     BAS_QINT          ;convert to integer [0,127]
1336: a5 a1                        lda     BAS_FAC+4
1338: 69 06                        adc     #$06              ;add 6 [6,133]
133a: 8d 81 12                     sta     auto_curs_x       ;save it
133d: 20 ae ef                     jsr     BAS_RND           ;do it again
1340: 20 91 15                     jsr     InA_MulFloat
1343: fa 0b                        .dd2    const_128
1345: 20 f2 eb                     jsr     BAS_QINT
1348: a5 a1                        lda     BAS_FAC+4
134a: 69 06                        adc     #$06              ;(should be 3?)
134c: 8d 82 12                     sta     auto_curs_y       ;save that too
134f: 60                           rts

                   ; 
                   ; Play sounds, jump to top of game loop.
                   ; 
1350: 20 5c 13     GameLoopBottom  jsr     PlaySounds
1353: 4c 38 0c                     jmp     GameLoop

                   ; 
                   ; Play sounds, jump to ABM/player update.
                   ; 
1356: 20 5c 13     JmpUpdateAbm    jsr     PlaySounds
1359: 4c 27 0f                     jmp     UpdateAbmMaybe

                   ; 
                   ; Plays sound effects.
                   ; 
135c: a5 4a        PlaySounds      lda     sfx_counter
135e: 26 4b                        rol     sfx_counter+1
1360: 2a                           rol     A
1361: 90 02                        bcc     :NoInc
1363: e6 4b                        inc     sfx_counter+1
1365: 45 4b        :NoInc          eor     sfx_counter+1
1367: 4d 40 c0                     eor     STROBE            ;(?)
136a: 85 4a                        sta     sfx_counter
136c: 29 7f                        and     #$7f
136e: cd 43 18                     cmp     sound_fx_mod
1371: f0 05                        beq     :Return
1373: b0 03                        bcs     :Return
1375: 8d 30 c0     _Click          sta     SPKR              ;$c030 or (for attract mode) $c064
1378: 60           :Return         rts

1379: 00           cursor_x        .dd1    $00               ;ranges from 6 to 134 ($86)
137a: 00           cursor_y        .dd1    $00               ;ranges from 3 to 131 ($83)
137b: 00           prev_cursor_x   .dd1    $00               ;X posn where cursor was last drawn
137c: 00           prev_cursor_y   .dd1    $00               ;Y posn where cursor was last drawn

                   ; 
                   ; Draws an Applesoft shape, from an inline data pointer, at the position
                   ; determined by the last HPOSN or HPLOT.
                   ; 
137d: 20 4c 15     InA_DrawShape   jsr     GetInlineWord
1380: aa                           tax                       ;get address in (Y,X)
1381: a9 00                        lda     #$00              ;rotation=0
1383: 4c 01 f6                     jmp     BAS_DRAW0         ;draw shape

                   ; 
                   ; Draws the cursor, one pixel at a time.  The previous screen contents are
                   ; saved.
                   ; 
1386: a0 ff        DrawCursor      ldy     #$ff              ;init index (first inc will make it zero)
1388: 8c 94 13                     sty     :_Index+1
138b: a2 03                        ldx     #$03              ;color=3 (white)
138d: 20 ec f6                     jsr     BAS_HCOLOR+3
1390: ee 94 13     :Loop           inc     :_Index+1
1393: a0 00        :_Index         ldy     #$00
1395: ad 79 13                     lda     cursor_x          ;get cursor X position
1398: 18                           clc
1399: 79 e9 13                     adc     cursor_xoff,y     ;add the X offset
139c: aa                           tax
139d: ad 7a 13                     lda     cursor_y          ;get cursor Y position
13a0: 18                           clc
13a1: 79 f3 13                     adc     cursor_yoff,y     ;add the Y offset
13a4: 20 07 14                     jsr     DrawPixel         ;draw the pixel
13a7: ac 94 13                     ldy     :_Index+1
13aa: 99 fd 13                     sta     saved_curs_pix,y  ;save previous value
13ad: c0 09                        cpy     #$09              ;did we finish entry #9?
13af: 90 df                        bcc     :Loop             ;not yet, loop
13b1: ad 79 13                     lda     cursor_x          ;remember where we drew it
13b4: 8d 7b 13                     sta     prev_cursor_x
13b7: ad 7a 13                     lda     cursor_y
13ba: 8d 7c 13                     sta     prev_cursor_y
13bd: 60                           rts

                   ; 
                   ; Erases the cursor, one pixel at a time.  The previous screen contents are
                   ; restored.
                   ; 
13be: a0 ff        EraseCursor     ldy     #$ff              ;init index (first inc will make it zero)
13c0: 8c c7 13                     sty     :_Index+1
13c3: ee c7 13     :Loop           inc     :_Index+1
13c6: a0 00        :_Index         ldy     #$00
13c8: b9 fd 13                     lda     saved_curs_pix,y  ;get old color
13cb: aa                           tax
13cc: 20 ec f6                     jsr     BAS_HCOLOR+3      ;set color
13cf: ad 7b 13                     lda     prev_cursor_x     ;get cursor's previous X position
13d2: 18                           clc
13d3: 79 e9 13                     adc     cursor_xoff,y     ;add the X offset
13d6: aa                           tax
13d7: ad 7c 13                     lda     prev_cursor_y     ;get cursor's previous Y position
13da: 18                           clc
13db: 79 f3 13                     adc     cursor_yoff,y     ;add the Y offset
13de: 20 07 14                     jsr     DrawPixel         ;draw the pixel
13e1: ac c7 13                     ldy     :_Index+1
13e4: c0 09                        cpy     #$09              ;did we finish entry #9?
13e6: 90 db                        bcc     :Loop             ;not yet, loop
13e8: 60                           rts

                   ; 
                   ; X/Y offsets for drawing cursor pixels.  These are 8-bit signed values.
                   ; 
                   ;          (0,-2)
                   ;          (0,-1)
                   ; (-1, 0)  (0, 0)  (1, 0)
                   ; (-1, 1)  (0, 1)  (1, 1)
                   ;          (0, 2)
                   ;          (0, 3)
13e9: 00 00 ff ff+ cursor_xoff     .bulk   $00,$00,$ff,$ff,$00,$00,$01,$01,$00,$00
13f3: fe ff 00 01+ cursor_yoff     .bulk   $fe,$ff,$00,$01,$00,$01,$00,$01,$02,$03
                   ; 
                   ; Saved pixel colors.  These hold the color value (0-3) of the pixel under the
                   ; cursor pixel.  Note these are color pixels (two basic pixels).
13fd: 00 00 00 00+ saved_curs_pix  .bulk   $00,$00,$00,$00,$00,$00,$00,$00,$00,$00

                   ; 
                   ; Draws a color pixel (two B&W pixels) at the specified position.  The previous
                   ; color value is returned.
                   ; 
                   ; On entry:
                   ;   X-reg: X offset (0-139)
                   ;   A-reg: Y offset (0-191)
                   ; 
                   ; On exit:
                   ;   A-reg: previous color pixel value (0-3)
                   ; 
1407: 48           DrawPixel       pha                       ;preserve Y offset
1408: a9 00                        lda     #$00
140a: 8d 4c 14                     sta     :_ScreenColor+1   ;init return value
140d: 8a                           txa                       ;get X offset
140e: 0a                           asl     A                 ;double it
140f: aa                           tax                       ;save low part in X-reg
1410: a9 00                        lda     #$00
1412: 69 00                        adc     #$00
1414: a8                           tay                       ;save high part in Y-reg
1415: 68                           pla                       ;restore Y offset (why?)
1416: 48                           pha                       ;save it some more
1417: 8a                           txa                       ;get low part
1418: 29 fe                        and     #%11111110        ;ensure it's even
141a: aa                           tax                       ;put that back in X-reg
141b: 49 01                        eor     #$01              ;ensure it's odd
141d: 8d 2e 14                     sta     :_XCoordLo+1      ;store odd X coord for second pass
1420: 68                           pla                       ;restore Y offset
1421: 8d 30 14                     sta     :_YCoord+1        ;set as Y coord
1424: 8c 32 14                     sty     :_XCoordHi+1      ;set X coord (high)
1427: 20 33 14                     jsr     :DoDraw           ;draw one pixel
142a: 0e 4c 14                     asl     :_ScreenColor+1   ;shift previous screen value
142d: a2 00        :_XCoordLo      ldx     #$00              ;now set up for the even pixel
142f: a9 00        :_YCoord        lda     #$00
1431: a0 00        :_XCoordHi      ldy     #$00
1433: 20 11 f4     :DoDraw         jsr     BAS_HPOSN         ;set up DP for hi-res X/Y position
1436: b1 26                        lda     (BAS_HBASL),y     ;get current value
1438: 25 30                        and     BAS_HMASK         ;apply masks
143a: 29 7f                        and     #$7f              ;(probably not needed, nothing draws with hi set)
143c: f0 03                        beq     L1441             ;pixel not set, branch
143e: ee 4c 14                     inc     :_ScreenColor+1   ;bump return value
1441: a5 1c        L1441           lda     BAS_HCOLOR1       ;merge color pixels into hi-res screen
1443: 51 26                        eor     (BAS_HBASL),y
1445: 25 30                        and     BAS_HMASK         ;don't touch the adjacent pixels
1447: 51 26                        eor     (BAS_HBASL),y
1449: 91 26                        sta     (BAS_HBASL),y
144b: a9 00        :_ScreenColor   lda     #$00              ;return previous color
144d: 60                           rts

                   ; 
                   ; Shapes for the cities and missile launchers.
                   ; 
                   vis
144e: 24 24 24 35+ shape_city      .bulk   $24,$24,$24,$35,$36,$2e,$25,$24,$24,$2c,$2c,$24,$36,$35,$35,$36
                                    +      $36,$26,$24,$25,$24,$24,$25,$24,$2c,$24,$24,$2d,$36,$36,$35,$36
                                    +      $2e,$36,$36,$36,$3f,$37,$2e,$2d,$2d,$25,$3c,$3f,$24,$24,$2c,$2d
                                    +      $36,$36,$26,$24,$24,$24,$24,$24,$2c,$2d,$35,$36,$36,$36,$36,$36
                                    +      $36,$26,$24,$24,$2d,$24,$24,$36,$36,$2d,$35,$36,$36,$3e,$3f,$3f
                                    +      $3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$3f,$2d,$2d,$2d,$2d,$2d
                                    +      $2d,$2d,$2d,$2d,$2d,$2d,$2d,$2d,$2d,$05,$00

                   vis
14b9: 1b 2e 21 24+ shape_laun_bot  .bulk   $1b,$2e,$21,$24,$09,$36,$2e,$21,$24,$24,$09,$36,$36,$2d,$24,$24
                                    +      $0d,$36,$36,$2f,$2e,$21,$24,$2c,$11,$36,$2e,$21,$2c,$11,$36,$1b
                                    +      $1b,$08,$20,$00

                   vis
14dd: 2d 2d 3f 27+ shape_laun_top  .bulk   $2d,$2d,$3f,$27,$24,$2c,$24,$34,$36,$35,$36,$06,$00

                   ; 
                   ; Returns a pointer stored as inline data following the caller's caller's JSR.
                   ; 
                   ; On exit:
                   ;   $10-11: pointer
                   ;   A-reg/X-reg/Y-reg preserved
                   ; 
                   ]ptr            .var    $10    {addr/2}

14ea: 48           GetInlinePtr    pha                       ;preserve A-reg
14eb: 8a                           txa
14ec: 48                           pha                       ;preserve X-reg
14ed: ba                           tsx
14ee: bd 05 01                     lda     STACK+5,x         ;extract the pointer
14f1: 85 10                        sta     ]ptr
14f3: bd 06 01                     lda     STACK+6,x
14f6: 85 11                        sta     ]ptr+1
14f8: 68                           pla
14f9: aa                           tax                       ;restore X-reg
14fa: 68                           pla                       ;restore A-reg
14fb: 60                           rts

                   ; 
                   ; Adjusts the return address on the stack to move past the inline string.  The
                   ; caller must jump here, not JSR.
                   ; 
                   ; On entry:
                   ;   Y-reg: string length
                   ; 
                   ]tmp            .var    $10    {addr/1}

14fc: 98           AdjustRetAddr   tya                       ;move length to A-reg (why?)
14fd: 85 10                        sta     ]tmp              ;store in DP
14ff: 68                           pla                       ;pull low byte of return addr
1500: 18                           clc
1501: 65 10                        adc     ]tmp              ;add the length
1503: 85 10                        sta     ]tmp              ;store result in DP
1505: 90 04                        bcc     :NoInc            ;if we didn't cross a page, branch
1507: 68                           pla                       ;need to update high byte, so pull that
1508: 69 00                        adc     #$00
150a: 48                           pha
150b: a5 10        :NoInc          lda     ]tmp              ;get low byte
150d: 48                           pha                       ;push it back on
150e: 60                           rts                       ;return to updated address

                   ; 
                   ; Unused function, probably used for issuing DOS commands.
                   ; 
                   ]ptr            .var    $10    {addr/2}

150f: a9 84        InS_unref_150f? lda     #$84              ;Ctrl+D
1511: 20 ed fd                     jsr     MON_COUT
1514: 20 ea 14                     jsr     GetInlinePtr      ;get pointer to string
1517: a0 00                        ldy     #$00
1519: 8c 20 15                     sty     :_Index+1
151c: ee 20 15     :Loop           inc     :_Index+1
151f: a0 00        :_Index         ldy     #$00              ;track index with self-mod code
1521: b1 10                        lda     (]ptr),y
1523: f0 d7                        beq     AdjustRetAddr     ;done, move return addr to end of string
1525: 20 ed fd                     jsr     MON_COUT          ;use COUT to allow interception
1528: 4c 1c 15                     jmp     :Loop

                   ; 
                   ; Prints a high-ASCII string that immediately follows the JSR to this function.
                   ; 
152b: 20 ea 14     InS_PrintString jsr     GetInlinePtr      ;get pointer to string
152e: a0 00                        ldy     #$00
1530: 8c 37 15                     sty     :_Index+1
1533: ee 37 15     :Loop           inc     :_Index+1
1536: a0 00        :_Index         ldy     #$00              ;track index with self-mod code
1538: b1 10                        lda     (]ptr),y
153a: f0 c0                        beq     AdjustRetAddr     ;done, move return addr to end of string
153c: 20 f0 fd                     jsr     MON_COUT1         ;use COUT1 to bypass I/O hooks
153f: 4c 33 15                     jmp     :Loop

                   ; 
                   ; Sets the text position to a row and column specified by inline data following
                   ; the call to this function.  First byte is row (0-23), second byte is column
                   ; (0-39).
                   ; 
1542: 20 4c 15     InXY_SetTextPos jsr     GetInlineWord
1545: 85 25                        sta     MON_CV            ;set text vertical position
1547: 84 24                        sty     MON_CH            ;set text horizontal position
1549: 4c 22 fc                     jmp     MON_VTAB          ;update pointer

                   ; 
                   ; Gets an inline word from the caller's caller.  Update's the return address
                   ; from the calling function to walk past it.
                   ; 
                   ; If the retrieved value is $42xx, the high byte is replaced with the value at
                   ; $18 (high byte of pointer at $17-18).
                   ; 
                   ; On exit:
                   ;   A-reg: low byte
                   ;   Y-reg: high byte
                   ; 
154c: ba           GetInlineWord   tsx                       ;get stack pointer
154d: bd 03 01                     lda     STACK+3,x         ;read from stack+3 to get caller's caller
1550: 85 10                        sta     ]ptr              ;(address is last byte of JSR, e.g. $0829)
1552: bd 04 01                     lda     STACK+4,x
1555: 85 11                        sta     ]ptr+1
1557: a0 01                        ldy     #$01              ;add one to get byte following JSR
1559: b1 10                        lda     (]ptr),y          ;get first (low) byte
155b: 48                           pha                       ;save it
155c: c8                           iny
155d: b1 10                        lda     (]ptr),y          ;get second (high) byte
155f: c9 42                        cmp     #$42              ;$42xx?
1561: d0 02                        bne     :Not42
1563: a5 18                        lda     missile_ptr+1     ;substitute value in $18
1565: a8           :Not42          tay                       ;put high byte in Y-reg
1566: 68                           pla                       ;put low byte in A-reg
1567: 20 6a 15                     jsr     :IncVal           ;increment twice to get past value
156a: fe 03 01     :IncVal         inc     STACK+3,x
156d: d0 03                        bne     :NoInc
156f: fe 04 01                     inc     STACK+4,x
1572: 60           :NoInc          rts

                   ; 
                   ; Gets a 5-byte "packed" floating-point value, and loads it into Applesoft's
                   ; FAC.  The address is specified by inline data following the JSR to this
                   ; function.
                   ; 
                   ; On entry:
                   ;   A-reg: destination address (low)
                   ;   Y-reg: destination address (high)
                   ; 
1573: 20 4c 15     InA_LoadFloat   jsr     GetInlineWord     ;get word from caller's caller
1576: 4c f9 ea                     jmp     BAS_LOAD_FAC_FROM_YA ;load it into Applesoft FP register

                   ; 
                   ; Converts an inline integer value to a float in FAC.
                   ; 
1579: 20 4c 15     unref_1579?     jsr     GetInlineWord
157c: 8c 81 15                     sty     :_Aval+1          ;Y-reg has high byte, but func wants it as low
157f: a8                           tay                       ;move low byte to Y-reg
1580: a9 00        :_Aval          lda     #$00              ;high byte in A-reg
1582: 4c f2 e2                     jmp     BAS_GIVAYF        ;convert value to float

                   ; 
                   ; Computes FAC = (inline_ref) + FAC.
                   ; 
1585: 20 4c 15     InA_AddFloat    jsr     GetInlineWord
1588: 4c be e7                     jmp     BAS_FADD

                   ; 
                   ; Computes FAC = (inline_ref) - FAC.
                   ; 
158b: 20 4c 15     InA_SubFloat    jsr     GetInlineWord
158e: 4c a7 e7                     jmp     BAS_FSUB

                   ; 
                   ; Computes FAC = (inline_ref) * FAC.
                   ; 
1591: 20 4c 15     InA_MulFloat    jsr     GetInlineWord
1594: 4c 7f e9                     jmp     BAS_FMULT

                   ; 
                   ; Computes FAC = (inline_ref) / FAC.
                   ; 
1597: 20 4c 15     InA_DivFloat    jsr     GetInlineWord
159a: 4c 66 ea                     jmp     BAS_FDIV

                   ; 
                   ; Computes FAC = (inline_ref) ^ FAC.
                   ; 
                   InA_unref_ExpFloat
159d: 20 4c 15                     jsr     GetInlineWord
15a0: 20 e3 e9                     jsr     BAS_LOAD_ARG_FROM_YA
15a3: 4c 97 ee                     jmp     BAS_FPWRT

                   ; 
                   ; Compares float referenced by inline value to FAC.
                   ; 
                   ; On exit:
                   ;   A-reg: {1,0,-1} as (Y,A) <,=,> FAC
                   ;   Status flags set according to A-reg
                   ; 
15a6: 20 4c 15     InA_CmpFloat    jsr     GetInlineWord
15a9: 4c b2 eb                     jmp     BAS_FCOMP

                   ; 
                   ; Rounds the floating point value in FAC, then stores the value at the address
                   ; specified inline after the caller's JSR.
                   ; 
                   ; On entry:
                   ;   X-reg: destination address (low)
                   ;   Y-reg: destination address (high)
                   ; 
15ac: 20 4c 15     InA_StoreFloat  jsr     GetInlineWord     ;get address in (Y,A)
15af: aa                           tax
15b0: 4c 2b eb                     jmp     BAS_STORE_FAC_AT_YX_ROUNDED ;round FAC, and store at (Y,X)

                   ; 
                   ; Unused: print a float as an integer.
                   ; 
                   unref_PrintFloat
15b3: aa                           tax
15b4: 98                           tya
15b5: 4c 24 ed                     jmp     BAS_LINPRT        ;print float at (A,X) as integer

                   ; 
                   ; Draws expanding circle for explosions.
                   ; 
                   ; The tables define a circle as a series of pixels drawn from the center
                   ; outward, sort of like drawing a spiral.  The code starts at index M and stops
                   ; at index N, drawing part of the circle on each call, expanding outward.  By
                   ; remembering the stop index and passing it in on subsequent iterations, the
                   ; circle can be drawn incrementally.
                   ; 
                   ; The number of iterations we do per visit determines how quickly the circle
                   ; expands per frame.  The total pixel count determines the radius.  Each entry
                   ; in the table determines 4 pixels, one per quadrant, and we're drawing "color
                   ; pixels" which are twice as wide as they are high.  So a 256-entry table covers
                   ; 2048 pixels, which math says is enough for a circle of radius 25.  The largest
                   ; displacement in the table is 24, to which we add 1 for the center pixel.
                   ; 
                   ; At max radius we offset +/- 24 pixels, so the maximum Y coordinate value
                   ; (assuming a valid center point) is [-24,215], which we can check with a simple
                   ; test.  There's no risk of wrapping around the screen.
                   ; 
                   ; ABMs use radius $50 (80) for outer/center, $70 (112) for inner.  Missiles use
                   ; a randomized radius between 96 and 176.
                   ; 
                   ; Note to hackers: don't use a size larger than ($100 - iterations), or the code
                   ; can get stuck.  If you're using an iteration count of 8, don't exceed $f8. 
                   ; The integer rolls over and the game doesn't realize the explosion should stop.
                   ; Make the size a multiple of the count.
                   ; 
                   ; Set the HCOLOR before calling.
                   ; 
                   ; On entry:
                   ;   X-reg: center X position (0-139)
                   ;   A-reg: center Y position (0-191)
                   ;   Y-reg: iterations (8 or 16)
                   ;   (set the initial index directly, starting from zero)
                   ; 
                   ; On exit:
                   ;   Index updated (+= iteration count)
                   ; 
15b8: 8d d2 15     DrawExplosion   sta     :_DrawCircY+1     ;set center Y
15bb: 8e c7 15                     stx     :_DrawCircX+1     ;set center X
15be: 8c 3c 16                     sty     :_CircleCount+1   ;init iterations
                   ; Note the DrawPixel function takes the column (0-139) in X-reg, and the row (0-
                   ; 191) in A-reg.  Y-reg doesn't matter.
15c1: ce 3c 16     :DrawCircLoop   dec     :_CircleCount+1   ;count down interations
                   ; Start with bottom-right quadrant.
15c4: a0 00        _DrawCircIndex  ldy     #$00
15c6: a9 00        :_DrawCircX     lda     #$00              ;get center X
15c8: 18                           clc
15c9: 79 43 16                     adc     circle_x_data,y   ;add horizontal offset
15cc: aa                           tax                       ;copy to X-reg
15cd: c9 8c                        cmp     #140              ;range check 0 <= X <= 140
15cf: b0 0b                        bcs     :SkipBR           ;went past, don't draw pixel
15d1: a9 00        :_DrawCircY     lda     #$00              ;get center Y
15d3: 18                           clc
15d4: 79 43 17                     adc     circle_y_data,y   ;add vertical offset
15d7: a0 00                        ldy     #$00              ;(?)
15d9: 20 07 14                     jsr     DrawPixel         ;draw bottom-right pixel
                   ; Bottom-Left quadrant.
15dc: ac c5 15     :SkipBR         ldy     _DrawCircIndex+1
15df: ad c7 15                     lda     :_DrawCircX+1
15e2: 38                           sec
15e3: f9 43 16                     sbc     circle_x_data,y
15e6: aa                           tax
15e7: c9 8c                        cmp     #140              ;check vs. left edge (negative)
15e9: b0 0c                        bcs     :SkipBL
15eb: ad d2 15                     lda     :_DrawCircY+1
15ee: 18                           clc
15ef: 79 43 17                     adc     circle_y_data,y   ;not range-checked: we don't draw circles that low
15f2: a0 00                        ldy     #$00              ;(?)
15f4: 20 07 14                     jsr     DrawPixel         ;draw bottom-left pixel
                   ; Upper-right quadrant.
15f7: ac c5 15     :SkipBL         ldy     _DrawCircIndex+1
15fa: ad c7 15                     lda     :_DrawCircX+1
15fd: 18                           clc
15fe: 79 43 16                     adc     circle_x_data,y
1601: aa                           tax
1602: c9 8c                        cmp     #140              ;check vs. right edge
1604: b0 10                        bcs     :SkipUR
1606: ad d2 15                     lda     :_DrawCircY+1
1609: 38                           sec
160a: f9 43 17                     sbc     circle_y_data,y
160d: c9 be                        cmp     #190              ;check vs. top (negative)
160f: b0 05                        bcs     :SkipUR
1611: a0 00                        ldy     #$00              ;(?)
1613: 20 07 14                     jsr     DrawPixel         ;draw upper-right pixel
                   ; Upper-left quadrant.
1616: ac c5 15     :SkipUR         ldy     _DrawCircIndex+1
1619: ad c7 15                     lda     :_DrawCircX+1
161c: 38                           sec
161d: f9 43 16                     sbc     circle_x_data,y
1620: aa                           tax
1621: c9 8c                        cmp     #140              ;check vs. left edge (negative)
1623: b0 10                        bcs     :SkipUL
1625: ad d2 15                     lda     :_DrawCircY+1
1628: 38                           sec
1629: f9 43 17                     sbc     circle_y_data,y
162c: c9 be                        cmp     #190              ;check vs. top (negative)
162e: b0 05                        bcs     :SkipUL
1630: a0 00                        ldy     #$00              ;(?)
1632: 20 07 14                     jsr     DrawPixel         ;draw upper-left pixel
                   ; All pixels are drawn; update state.
1635: ee c5 15     :SkipUL         inc     _DrawCircIndex+1
1638: 20 5c 13                     jsr     PlaySounds        ;update sound effects once per iteration
163b: a2 00        :_CircleCount   ldx     #$00              ;done yet?
163d: f0 03                        beq     :Return           ;yes, bail
163f: 4c c1 15                     jmp     :DrawCircLoop

1642: 60           :Return         rts

                   ; 
                   ; Pixel offsets for incrementally-drawn circle.  The X offsets are for double-
                   ; wide color pixels, so represent twice the distance of the Y offsets.
                   ; 
                   ; The values are all +X/+Y, representing the first quadrant.
                   ; 
                   vis
1643: 00 00 00 01+ circle_x_data   .bulk   $00,$00,$00,$01,$01,$01,$00,$01,$00,$02,$02,$01,$02,$00,$02,$01
                                    +      $02,$00,$03,$03,$01,$03,$02,$03,$00,$02,$03,$01,$03,$00,$04,$02
                                    +      $04,$01,$04,$03,$04,$02,$00,$04,$01,$02,$03,$04,$02,$00,$03,$04
                                    +      $05,$05,$01,$05,$05,$04,$02,$05,$03,$00,$01,$05,$04,$03,$05,$02
                                    +      $00,$06,$04,$06,$01,$06,$05,$06,$03,$02,$06,$04,$05,$00,$06,$01
                                    +      $03,$06,$05,$02,$04,$06,$00,$07,$07,$01,$05,$07,$03,$07,$04,$06
                                    +      $02,$07,$05,$07,$00,$06,$01,$03,$07,$04,$02,$05,$06,$07,$00,$08
                                    +      $08,$01,$04,$07,$08,$03,$06,$08,$05,$02,$08,$07,$08,$06,$00,$04
                                    +      $03,$08,$01,$05,$07,$02,$08,$06,$07,$04,$08,$00,$09,$03,$05,$09
                                    +      $01,$09,$09,$08,$02,$06,$07,$09,$09,$04,$05,$08,$03,$09,$00,$01
                                    +      $07,$06,$09,$02,$08,$04,$09,$05,$07,$03,$00,$06,$08,$0a,$0a,$01
                                    +      $0a,$09,$0a,$02,$0a,$07,$05,$09,$04,$08,$0a,$06,$03,$0a,$00,$01
                                    +      $09,$0a,$07,$08,$02,$05,$04,$0a,$06,$09,$03,$08,$0a,$00,$0b,$07
                                    +      $0b,$01,$0b,$09,$0b,$02,$05,$0a,$0b,$04,$06,$0b,$08,$03,$07,$09
                                    +      $0b,$0a,$00,$01,$0b,$05,$06,$0a,$02,$08,$04,$0b,$09,$07,$03,$0b
                                    +      $0a,$00,$0c,$0c,$01,$08,$09,$0c,$05,$0b,$06,$0c,$02,$0c,$04,$07
1743: 00 01 02 00+ circle_y_data   .bulk   $00,$01,$02,$00,$01,$02,$03,$03,$04,$00,$01,$04,$02,$05,$03,$05
                                    +      $04,$06,$00,$01,$06,$02,$05,$03,$07,$06,$04,$07,$05,$08,$00,$07
                                    +      $01,$08,$02,$06,$03,$08,$09,$04,$09,$09,$07,$05,$09,$0a,$08,$06
                                    +      $00,$01,$0a,$02,$03,$07,$0a,$04,$09,$0b,$0b,$05,$08,$0a,$06,$0b
                                    +      $0c,$00,$09,$01,$0c,$02,$07,$03,$0b,$0c,$04,$0a,$08,$0d,$05,$0d
                                    +      $0c,$06,$09,$0d,$0b,$07,$0e,$00,$01,$0e,$0a,$02,$0d,$03,$0c,$08
                                    +      $0e,$04,$0b,$05,$0f,$09,$0f,$0e,$06,$0d,$0f,$0c,$0a,$07,$10,$00
                                    +      $01,$10,$0e,$08,$02,$0f,$0b,$03,$0d,$10,$04,$09,$05,$0c,$11,$0f
                                    +      $10,$06,$11,$0e,$0a,$11,$07,$0d,$0b,$10,$08,$12,$00,$11,$0f,$01
                                    +      $12,$02,$03,$09,$12,$0e,$0c,$04,$05,$11,$10,$0a,$12,$06,$13,$13
                                    +      $0d,$0f,$07,$13,$0b,$12,$08,$11,$0e,$13,$14,$10,$0c,$00,$01,$14
                                    +      $02,$09,$03,$14,$04,$0f,$12,$0a,$13,$0d,$05,$11,$14,$06,$15,$15
                                    +      $0b,$07,$10,$0e,$15,$13,$14,$08,$12,$0c,$15,$0f,$09,$16,$00,$11
                                    +      $01,$16,$02,$0d,$03,$16,$14,$0a,$04,$15,$13,$05,$10,$16,$12,$0e
                                    +      $06,$0b,$17,$17,$07,$15,$14,$0c,$17,$11,$16,$08,$0f,$13,$17,$09
                                    +      $0d,$18,$00,$01,$18,$12,$10,$02,$16,$0a,$15,$03,$18,$04,$17,$14
                   ; 
                   ; Sound effect modifier.
1843: 00           sound_fx_mod    .dd1    $00
1844: 00 00 00 00+                 .junk   6
                   ; 
                   ; Status of the six cities:
                   ;   $ff - undamaged
                   ;   $80 - damaged
                   ;   $00 - destroyed
184a: ff ff ff ff+ city_status     .bulk   $ff,$ff,$ff,$ff,$ff,$ff
                   ; 
                   ; Horizontal column of city center (0-39).
1850: 02 09 10 17+ city_cols       .bulk   $02,$09,$10,$17,$1e,$25

                   ; 
                   ; Evaluate damage done to cities.
                   ; 
1856: a2 ff        EvalCityDamage  ldx     #$ff
1858: 8e 6c 18                     stx     :_Loop+1
185b: e8                           inx                       ;X-reg=0
185c: a0 00                        ldy     #$00              ;init surviving city count to zero
185e: 8e be 18                     stx     :_CityLoopDone+1
1861: a9 9b                        lda     #155              ;line 155 (five above text window), left column
1863: 20 11 f4                     jsr     BAS_HPOSN
1866: 20 42 15                     jsr     InXY_SetTextPos
1869: 14                           .dd1    20                ;top row of text window
186a: 00                           .dd1    0                 ;left edge
                   ; Loop over all six cities, checking for damage.
186b: a2 00        :_Loop          ldx     #$00
186d: e8                           inx
186e: 8e 6c 18                     stx     :_Loop+1
1871: e0 06                        cpx     #$06              ;done yet?
1873: f0 48                        beq     :_CityLoopDone    ;yes, branch
1875: bd 50 18                     lda     city_cols,x       ;get horizontal offset of city center (0-39)
1878: a8                           tay                       ;use as index into hi-res page
1879: b1 26                        lda     (BAS_HBASL),y     ;read hi-res byte at (offset*7, 155)
187b: d0 1a                        bne     :CityNotDead      ;still some pixels here, city not destroyed
187d: bd 4a 18                     lda     city_status,x     ;check status
1880: f0 e9                        beq     :_Loop            ;already destroyed, nothing to do
                   ; Destroy city.
1882: a9 00                        lda     #$00
1884: 9d 4a 18                     sta     city_status,x     ;set status to destroyed
1887: 88                           dey                       ;back up one space
1888: a2 00                        ldx     #$00
188a: a9 ad                        lda     #“-”
188c: 91 28        :DashLoop       sta     (MON_BASL),y      ;ovewrite city initials with hyphens
188e: c8                           iny
188f: e8                           inx
1890: e0 03                        cpx     #$03
1892: 90 f8                        bcc     :DashLoop
1894: 4c 6b 18                     jmp     :_Loop            ;check next

1897: ee be 18     :CityNotDead    inc     :_CityLoopDone+1  ;increment number of surviving cities
189a: d9 52 0b                     cmp     orig_row_155,y    ;check for damage
189d: f0 cc                        beq     :_Loop            ;no damage, move on to next
189f: bd 4a 18                     lda     city_status,x     ;check city status
18a2: c9 80                        cmp     #$80              ;already marked as damaged?
18a4: f0 c5                        beq     :_Loop            ;yes, move on to next
18a6: a9 80                        lda     #$80
18a8: 9d 4a 18                     sta     city_status,x     ;set status to damaged
18ab: 88                           dey                       ;back up one space from center
18ac: a2 00                        ldx     #$00
18ae: b1 28        :InvertLoop     lda     (MON_BASL),y      ;invert the city abbrev (or whatever is there)
18b0: 29 3f                        and     #$3f
18b2: 91 28                        sta     (MON_BASL),y
18b4: c8                           iny
18b5: e8                           inx
18b6: e0 03                        cpx     #$03
18b8: 90 f4                        bcc     :InvertLoop
18ba: 4c 6b 18                     jmp     :_Loop

18bd: a9 00        :_CityLoopDone  lda     #$00              ;check surviving city count
18bf: f0 01                        beq     :NoCitiesLeft     ;all destroyed, game is over
18c1: 60                           rts

18c2: 68           :NoCitiesLeft   pla                       ;pop return address
18c3: 68                           pla
18c4: ad f0 0b                     lda     auto_play_flag    ;attract mode?
18c7: f0 03                        beq     ShowFinalScore    ;no, show player their score
18c9: 4c 13 08                     jmp     Restart           ;yes, just go back to title screen

                   ; 
                   ; Shows the final score after the game ends.
                   ; 
                   ; base_score = ((missiles_destroyed - 6) * 10) / (ABMs_fired + 100)
                   ; score = floor(base_score * 100) * 10
                   ; 
18cc: 8d 56 c0     ShowFinalScore  sta     LORES             ;lo-res graphics (why?)
18cf: 8d 51 c0                     sta     TXTSET            ;text mode (redundant with next call)
18d2: 20 39 fb                     jsr     MON_SETTXT        ;text mode, reset window
18d5: ad f2 0b                     lda     mssl_destroy_cnt+1 ;get number of missiles destroyed
18d8: ac f1 0b                     ldy     mssl_destroy_cnt
18db: 20 f2 e2                     jsr     BAS_GIVAYF        ;convert to float
18de: 20 42 15                     jsr     InXY_SetTextPos
18e1: 0a                           .dd1    10
18e2: 0a                           .dd1    10
18e3: 20 2b 15                     jsr     InS_PrintString
18e6: d9 cf d5 a0+                 .zstr   “YOU SCORED ”
18f2: 20 8b 15                     jsr     InA_SubFloat      ;subtract 6, because missiles "destroyed" by blowing
18f5: 09 0c                        .dd2    const_6           ; up a city don't count toward your score
18f7: 20 d0 ee                     jsr     BAS_NEGOP
18fa: 20 82 eb                     jsr     BAS_SIGN          ;did it go negative?
18fd: 10 0c                        bpl     :NotNeg           ;no, branch
18ff: a9 00                        lda     #$00              ;yes, set it to zero
1901: 85 9d                        sta     BAS_FAC
1903: 85 9e                        sta     BAS_FAC+1
1905: 85 9f                        sta     BAS_FAC+2
1907: 85 a0                        sta     BAS_FAC+3
1909: 85 a1                        sta     BAS_FAC+4
190b: 20 39 ea     :NotNeg         jsr     BAS_MUL10         ;multiply by 10
190e: 20 ac 15                     jsr     InA_StoreFloat    ;save it
1911: 1d 0c                        .dd2    score_m_temp
1913: ad f4 0b                     lda     abm_fired_cnt+1   ;get number of ABMs launched
1916: ac f3 0b                     ldy     abm_fired_cnt
1919: 20 f2 e2                     jsr     BAS_GIVAYF        ;convert to float
191c: 20 85 15                     jsr     InA_AddFloat      ;add 100
191f: 04 0c                        .dd2    const_100
1921: 20 97 15                     jsr     InA_DivFloat      ;divide (missiles-6) by (ABM+100)
1924: 1d 0c                        .dd2    score_m_temp
1926: 20 39 ea                     jsr     BAS_MUL10         ;multiply by 10
1929: 20 39 ea                     jsr     BAS_MUL10         ;again (* 100)
192c: 20 23 ec                     jsr     BAS_INT           ;truncate fractional portion
192f: 20 39 ea                     jsr     BAS_MUL10         ;multiply by 10 (* 1000)
1932: 20 ac 15                     jsr     InA_StoreFloat    ;save it
1935: 2c 0c                        .dd2    score_temp
1937: 20 2e ed                     jsr     BAS_PRINT_FAC     ;print score
193a: 20 42 15                     jsr     InXY_SetTextPos   ;move down a line
193d: 0b                           .dd1    11
193e: 0a                           .dd1    10
193f: 20 2b 15                     jsr     InS_PrintString
1942: c6 cf d2 a0+                 .zstr   “FOR DOWNING ”
194f: ad f2 0b                     lda     mssl_destroy_cnt+1 ;get count of missiles destroyed
1952: ae f1 0b                     ldx     mssl_destroy_cnt
1955: 20 24 ed                     jsr     BAS_LINPRT        ;print it
1958: 20 42 15                     jsr     InXY_SetTextPos   ;move down a line
195b: 0c                           .dd1    12
195c: 0a                           .dd1    10
195d: 20 2b 15                     jsr     InS_PrintString
1960: cd c9 d3 d3+                 .zstr   “MISSILES WITH ”
196f: ad f4 0b                     lda     abm_fired_cnt+1   ;get count of ABMs fired
1972: ae f3 0b                     ldx     abm_fired_cnt
1975: 20 24 ed                     jsr     BAS_LINPRT        ;print it
1978: 20 42 15                     jsr     InXY_SetTextPos   ;move down a line
197b: 0d                           .dd1    13
197c: 0a                           .dd1    10
197d: 20 2b 15                     jsr     InS_PrintString
1980: c1 c2 cd a7+                 .zstr   “ABM'S.”
1987: 20 42 15                     jsr     InXY_SetTextPos   ;move up several rows
198a: 05                           .dd1    5
198b: 0a                           .dd1    10
198c: 20 2b 15                     jsr     InS_PrintString
198f: c8 c9 c7 c8+                 .zstr   “HIGH SCORE IS ”
199e: 20 73 15                     jsr     InA_LoadFloat     ;get high score
19a1: 31 0c                        .dd2    high_score
19a3: 20 2e ed                     jsr     BAS_PRINT_FAC     ;print it
19a6: 20 73 15                     jsr     InA_LoadFloat     ;get current score in FAC
19a9: 2c 0c                        .dd2    score_temp
19ab: 20 a6 15                     jsr     InA_CmpFloat      ;compare to high score
19ae: 31 0c                        .dd2    high_score
19b0: 30 2a                        bmi     :NotHigh          ;not new high score, branch
19b2: 20 ac 15                     jsr     InA_StoreFloat    ;store new high score
19b5: 31 0c                        .dd2    high_score
19b7: a9 3f                        lda     #$3f
19b9: 85 32                        sta     MON_INVFLAG       ;inverse text
19bb: 20 42 15                     jsr     InXY_SetTextPos   ;move down one row
19be: 06                           .dd1    6
19bf: 0c                           .dd1    12
19c0: 20 2b 15                     jsr     InS_PrintString
19c3: c2 c5 c6 cf+                 .zstr   “BEFORE THIS GAME!”
19d5: a9 ff                        lda     #$ff
19d7: 85 32                        sta     MON_INVFLAG       ;normal text
19d9: 20 9e 09                     jsr     WriteHighScore    ;save score to disk
19dc: 20 42 15     :NotHigh        jsr     InXY_SetTextPos   ;move to bottom of screen
19df: 17                           .dd1    23
19e0: 05                           .dd1    5
19e1: 20 2b 15                     jsr     InS_PrintString
19e4: d0 d2 c5 d3+                 .zstr   “PRESS RETURN TO PLAY AGAIN.”
                   ; Wait until key hit or timer expires.
1a00: 8d 10 c0                     sta     KBDSTRB           ;clear keyboard strobe
1a03: a2 d0                        ldx     #$d0
1a05: 8e ef 0b                     stx     temp+1            ;set timer
1a08: 8e ee 0b                     stx     temp
1a0b: ee ee 0b     :WaitLoop       inc     temp
1a0e: d0 08                        bne     :NotExp
1a10: ee ef 0b                     inc     temp+1
1a13: d0 03                        bne     :NotExp
1a15: 4c 13 08                     jmp     Restart           ;timer expired, restart at title

1a18: ad 00 c0     :NotExp         lda     KBD               ;key hit?
1a1b: 30 06                        bmi     :KeyHit
1a1d: ca                           dex
1a1e: d0 f8                        bne     :NotExp
1a20: 4c 0b 1a                     jmp     :WaitLoop

1a23: 8d 10 c0     :KeyHit         sta     KBDSTRB
1a26: a9 00                        lda     #$00
1a28: 8d f0 0b                     sta     auto_play_flag    ;clear auto-play flag (unnecessary?)
1a2b: 4c d4 09                     jmp     StartGame         ;start a new game

                   ; 
                   ; Unused junk saved with file.
                   ; 
1a2e: d2 d3 cf d2+                 .junk   1489

Symbol Table

No exported symbols found.