Home Journal Contact Me Tools Comments

Game Info
RAM usage Hardware/machine info
Code
Bug in the code Hidden message Easter egg Program Entry
ISR called at mid-screen update ISR called at end-screen update Run all game objects
Move/draw the player Move/draw the player shot Allien rolling-shot (targets player)
Alien plunger-shot Flying Saucer OR squiggly shot Start of a new game
Draw a shifted sprite Erase a shifted sprite Check/handle TILT
Data
Demo movement commands Alien shot rate map values
Alien shot rate map keys 'Column Firing' table
Saucer score table Saucer score strings
Alien score per type Alien starting coordinate table
Printing info for alien score Printing info for credits
Images
Player shot (1 image) 'Squiggly' alien shot
'Plunger' alien shot 'Rolling' alien shot
Player shot exploding (1 image) Player Shield
Aliens (2 images each) 1st picture Aliens (2 images each) 2nd picture
Player sprite (2 images) Flying saucer (1 image)
Player exploding (2 images) Alien shot exploding (1 image)
Alien exploding (1 image) Saucer exploding (1 image)
Alien pulling upside down Y (1st of 2) Alien pulling upside down Y (2nd of 2)
Alien pushing Y (1st of 2) Alien pushing Y (2nd of 2)
Character font (8x8 * 64 characters)
Messages
'SPACE INVADERS' 'INSERT COIN'
'PUSH ' 'PLAy' with upside down Y
'PLAY' with normal Y 'ONLY 1PLAYER BUTTON '
'1 OR 2PLAYERS BUTTON' '<1 OR 2 PLAYERS> '
'*SCORE ADVANCE TABLE*' '=? MYSTERY'
'=10 POINTS' '=20 POINTS'
'=30 POINTS' 'CREDIT '
'*1 PLAYER 1 COIN ' '*2 PLAYERS 2 COINS'
'TILT' 'PLAY PLAYER<1>'
'GAME OVER PLAYER< >' ' SCORE<1> HI-SCORE SCORE<2>'
'*TAITO CORPORATION*' '*TAITO COP*'
; Space Invaders
; Disassembly comments by Chris Cantrell 2010
; See http://www.computerarcheology.com for discussion.

; It is never completely finished!
;   TODO Look at the various versions of the ROMs and see what's different
;   TODO Check all X/Y references and make Xr/Yr or Xn/Yn

; A word on coordinates. Sometimes the code is easier to understand in the context of the screen
; in standard (no rotated) position. The comments will refer to Xn (X not-rotated) and Yn. Sometimes
; the code is easier to understand in the context of the rotated screen. The comments will
; refer to Xr (X rotated) and Yr.
;
; Some of the early comments in this dig may switch back and forth without the "r/n" notation. Be suspect
; of those.

; RAM

; #+2000    waitOnDraw          (1B00:01) Cleared by alien-draw and set by next-alien. This ensures no alien gets missed while drawing. @ >0137 <0146 >0176  
;  +2001    unused2001          (1B01:00)        
; #+2002    alienIsExploding    (1B02:00) Not-0 if an alien is exploding, 0 if not exploting @ <0103 >0426 <14EA >154B  
; #+2003    expAlienTimer       (1B03:10) Time (ISR ticks) left in alien-explosion @ >152C <153B >153B  
; #+2004    alienRow            (1B04:00) Row number of current alien (cursor) @ <0119 >0171  
; #+2005    alienFrame          (1B05:00) Animation frame number (0 or 1) for current alien (cursor) @ <011B <01B4 >01B8  
; #+2006    alienCurIndex       (1B06:00) Alien cursor index (from 0 to 54) @ <0109 <014F >0160 >01A8  
; #+2007    refAlienDYr         (1B07:00) Reference alien delta Yr @ <01AB >01AC >15B3  
; #+2008    refAlienDXr         (1B08:02) Reference alien deltaXr @ >00C8 <01DA <0878 >15AD  
; #+2009    refAlienYr          (1B09:78) Reference alien Yr coordinate @ >00B9 <0180 <01DD >01DE <087C <0913 <14F8 <1562  
; #+200A    refAlienXr          (1B0A:38) Reference alien Xr coordinate @ >00B9 <0182 <01E1 >01E2 <087C <156F  
; #+200B    alienPosLSB         (1B0B:78) Alien cursor bit pos (LSB) @ >00BC <012E >0167  
; #+200C    alienPosMSB         (1B0C:38) Alien cursor bit pos (MSB) @ >00BC <012E >0167  
; #+200D    rackDirection       (1B0D:00) Value 0 if rack is moving right or 1 if rack is moving left @ >00D3 <1597 >15A9  
; #+200E    rackDownDelta       (1B0E:F8) Constant value of alien rack dropping after bumping screen edge @ <15B0  
;  +200F    unused200F          (1B0F:00)        

; GameObject0 (Move/draw the player)
;
; #+2010    obj0TimerMSB        (1B10:00)      @ <024B >0280 <1621  
; #+2011    obj0TimerLSB        (1B11:80) Wait 128 interrupts (about 2 secs) before player task starts @ <0255 >027E >0319 <1623  
; #+2012    obj0TimerExtra      (1B12:00)      @ <025D >037D  
; #+2013    obj0HanlderLSB      (1B13:8E)      @ <0263  
; #+2014    oBJ0HanlderMSB      (1B14:02) Player handler code at 028E @ <0265  
;
; #+2015    playerAlive         (1B15:FF) Player is alive (FF=alive). Toggles between 0 and 1 for blow-up images. @ <0290 >039E >060F <0A59 <1618 *16EB  
; #+2016    expAnimateTimer     (1B16:05) Time till next blow-up sprite change (reloaded to 5) @ <0297 >0297 >02A7  
; #+2017    expAnimateCnt       (1B17:0C) Number of changes left in blow-up sequence @ <02AA >02AA  
; #+2018    plyrSprPicL         (1B18:60) Player sprite descriptor ... picture LSB @ >03AA  <1A3B 
; #+2019    plyrSprPicM         (1B19:1C) Player sprite descriptor ... picture MSB @ >03AA  <1A3D 
; #+201A    playerYr            (1B1A:20) Player sprite descriptor ... location LSB @ <02AE  <1A3F 
; #+201B    playerXr            (1B1B:30) Player sprite descriptor ... location MSB @ <02AE <034A >0388 >0395 <03FC <061B  <1A41 
; #+201C    plyrSprSiz          (1B1C:10) Player sprite descriptor ... size of sprite @  <1A43 
; #+201D    nextDemoCmd         (1B1D:01) Next movement command for demo @ <0355 >1667  
; #+201E    hidMessSeq          (1B1E:00) Set to 1 after 1st of 2 sequences are entered for hidden-message display @ <199A *19A9  
;  +201F    unused201F          (1B1F:00) Appears to be unused   

; GameObject1 (Move/draw the player shot)
;
; #+2020    obj1TimerMSB        (1B20:00)      @ <024B  
; #+2021    obj1TimerLSB        (1B21:00)      @ <0255  
; #+2022    obj1TimerExtra      (1B22:00) All 0's ... run immediately @ <025D  
; #+2023    obj1HandlerLSB      (1B23:BB)      @ <0263  
; #+2024    obj1HandlerMSB      (1B24:03) Shot handler code at 03BB @ <0265  
;
; #+2025    plyrShotStatus      (1B25:00) 0 if available, 1 if just initiated, 2 moving normally, 3 hit something besides alien, 5 if alien explosion is in progress, 4 if alien has exploded (remove from active duty) @ <03C4 >03FB >0B80 <14D8 >1514 >1532 >1547 <1626 >1641 >1655 <172C  
; #+2026    blowUpTimer         (1B26:10) Sprite blow-up timer @ <03D7 >03D7 <03DB  
; #+2027    obj1ImageLSB        (1B27:90)      @ <03E8 >03E8  <1A3B 
; #+2028    obj1ImageMSB        (1B28:1C) Sprite image at 1C90 (just one byte) @  <1A3D 
; #+2029    obj1CoorYr          (1B29:28) Player shot Y coordinate @ <03EB >03EB <03EC >03EC >041B <14E1  <1A3F 
; #+202A    obj1CoorXr          (1B2A:30) Player shot X coordinate @ <03EE >03EE <03EF >03EF <03F0 >03F0 >0401 <1508 <1A0A  <1A41 
; #+202B    obj1ImageSize       (1B2B:01) Size of shot image (just one byte) @ >03F2  <1A43 
; #+202C    shotDeltaX          (1B2C:04) Shot's delta X @ <0416  
; #+202D    fireBounce          (1B2D:00) 1 if button has been handled but remains down @ <1632 >1644 >164E  
;  +202E    unused202E          (1B2E:FF)        
;  +202F    unused202F          (1B2F:FF)        

; GameObject2 (Alien rolling-shot)
;
; #+2030    obj2TimerMSB        (1B30:00)      @ <024B  
; #+2031    obj2TimerLSB        (1B31:00)      @ <0255  
; #+2032    obj2TimerExtra      (1B32:02)  GO-3 runs when this is 1. GO-4 runs when this is 2. (copied to 2080 in game loop)@ <0072 <025D <0288 >0288 >047A  
; #+2033    obj2HandlerLSB      (1B33:76)      @ <0263  
; #+2034    obj2HandlerMSB      (1B34:04)  Handler code at 0476 @ <0265  

;Rolling-alien-shot data structure
; #+2035    rolShotStatus       (1B35:00)         
; #+2036    rolShotStepCnt      (1B36:00)      @ <04CA <051D   
; #+2037    rolShotTrack        (1B37:00)  A 0 means this shot tracks the player       
; #+2038    rolShotCFirLSB      (1B38:00)  Pointer to column-firing table LSB (not used for targeting) @ <047D >0486   
; #+2039    rolShotCFirMSB      (1B39:00)  Pointer to column-firing table MSB (not used for MSB counter @ <047D >0486   
; #+203A    rolShotBlowCnt      (1B3A:04)         
; #+203B    rolShotImageLSB     (1B3B:EE)         
; #+203C    rolShotImageMSB     (1B3C:1C)         
; #+203D    rolShotYr           (1B3D:00)         
; #+203E    rolShotXr           (1B3E:00)         
; #+203F    rolShotSize         (1B3F:03)   


; GameObject3 (Alien plunger-shot)
;
; #+2040    obj3TimerMSB        (1B40:00)      @ <024B  
; #+2041    obj3TimerLSB        (1B41:00)      @ <0255  
; #+2042    obj3TimerExtra      (1B42:00)      @ <025D  
; #+2043    obj3HandlerLSB      (1B43:B6)      @ <0263  
; #+2044    obj3HandlerMSB      (1B44:04) Handler code at 04B6 @ <0265  

;Plunger-alien-shot data structure
; #+2045    pluShotStatus       (1B45:00)         
; #+2046    pluShotStepCnt      (1B46:00)      @ <0492 <0517   
; #+2047    pluShotTrack        (1B47:01) A 1 means this shot does not track the player        
; #+2048    pluShotCFirLSB      (1B48:00) Pointer to column-firing table LSB @ >067E   
; #+2049    pluShotCFirMSB      (1B49:1D) Pointer to column-firing table MSB @ >067E   
; #+204A    pluShotBlowCnt      (1B4A:04)         
; #+204B    pluShotImageLSB     (1B4B:E2)         
; #+204C    pluShotImageMSB     (1B4C:1C)         
; #+204D    pluShotYr           (1B4D:00)         
; #+204E    pluSHotXr           (1B4E:00)         
; #+204F    pluShotSize         (1B4F:03)         


; GameObject4 (Flying saucer OR alien squiggly shot)
; #+2050    obj4TimerMSB        (1B50:00)      @ <024B >0280  
; #+2051    obj4TimerLSB        (1B51:00)      @ <0255 >027E  
; #+2052    obj4TimerExtra      (1B52:00)      @ <025D  
; #+2053    obj4HandlerLSB      (1B53:82)      @ <0263  
; #+2054    obj4HandlerMSB      (1B54:06) Handler code at 0682 @ <0265  

;Squiggly-alien-shot data structure
; #+2055    squShotStatus       (1B55:00)      @ <18B8 <18C0   
; #+2056    squShotStepCnt      (1B56:00)      @ <0498 <04D0 <0691   
; #+2057    squShotTrack        (1B57:01) A 1 means this shot does not track the player        
; #+2058    squShotCFirLSB      (1B58:06) Pointer to column-firing table LSB @ >054C   
; #+2059    squShotCFirMSB      (1B59:1D) Pointer to column-firing table MSB @ >054C   
; #+205A    squSHotBlowCnt      (1B5A:04)         
; #+205B    squShotImageLSB     (1B5B:D0)         
; #+205C    squShotImageMSB     (1B5C:1C)         
; #+205D    squShotYr           (1B5D:00)         
; #+205E    squShotXr           (1B5E:00)         
; #+205F    squShotSize         (1B5F:03)         

; #+2060    endOfTasks          (1B60:FF) FF marks the end of the tasks list @ <024B  


; #+2061    collision           (1B61:00) Set to 1 if sprite-draw detects collision @ <0421 <05FB >1495 >14A6 >14BA  
; #+2062    expAlienLSB         (1B62:C0)      @  <1A3B 
; #+2063    expAlienMSB         (1B63:1C) Exploding alien picture 1CC0 @  <1A3D 
; #+2064    expAlienYr          (1B64:00) Y coordinate of exploding alien @ >150F <153D  <1A3F 
; #+2065    expAlienXr          (1B65:00) X coordinate of exploding alien @ >150F <153D  <1A41 
; #+2066    expAlienSize        (1B66:10) Size of exploding alien sprite (16 bytes) @  <1A43 
; #+2067    playerDataMSB       (1B67:21) Current player's data-pointer MSB (21xx or 22xx) @ <010D <014B <01BD <02ED >0312 <0630 <0807 <0886 <0898 <08C1 <09CA *09F9 *0A01 *0A04 <158B <1613 <16AE <17C0 <18E7 <1913  
; #+2068    playerOK            (1B68:01) 1 means OK, 0 means blowing up @ <0141 >029B >033E <1747  
; #+2069    enableAlienFire     (1B69:00) 1 means aliens can fire, 0 means not @ >029E <0341 >0348 <0571  
; #+206A    alienFireDelay      (1B6A:30) Count down till aliens can fire (2069 flag is then set) @ >02A3 <03B4 >03B4  
; #+206B    oneAlien            (1B6B:00) 1 when only one alien is on screen  
; #+206C    temp206C            (1B6C:12) Holds the value ten ... number of characters in each "=xx POINTS" string but gets set to 18 in mem copy before game. @ >1822 <184D  
; #+206D    invaded             (1B6D:00) Set to 1 when player blows up because rack has reached bottom @ <02C6 >1973  
; #+206E    skipPlunger         (1B6E:00) When there is only one alien left this goes to 1 to disable the plunger-shot when it ends @ <04B7 >0505  
;  +206F    unused206F          (1B6F:00)        
; #+2070    otherShot1          (1B70:0F) When processing a shot, this holds one of the other shot's info @ >0495 >04CD >051A <057C  
; #+2071    otherShot2          (1B71:0B) When processing a shot, this holds one of the other shot's info @ >049B >04D3 >0520 <0589  
; #+2072    vblankStatus        (1B72:00) 80=screen is being drawn (don't touch), 0=blanking in progress (ok to change) @ >0016 >008D <1A09  

; Alien shot information (copied from the 3 actual structures when processed)
; #+2073    aShotStatus         (1B73:18) Bit 0 set if shot is blowing up, bit 7 set if active @ <0566 <05BA >05BD <05C9 <0612 >0617   
; #+2074    aShotStepCnt        (1B74:26) Count of steps made by shot (used for fire reload rate) @ >057A <05BF >05BF <05D0 >05D0   
; #+2075    aShotTrack          (1B75:0F) 0 if shot tracks player or 1 if it uses the column-fire table  @ <0597   
; #+2076    aShotCFirLSB        (1B76:0B) Pointer to column-firing table LSB @ <04D9 >04E4 <0508 <0526 >0531 <0549 <059C >05A2   
; #+2077    aShotCFirMSB        (1B77:00) Pointer to column-firing table MSB @ <0508 <0549 <059C >05A2   
; #+2078    aShotBlowCnt        (1B78:18) Alen shot blow up counter. At 3 the explosion is drawn. At 0 it is done. @ <04A1 <04E7 <0534 <0647 >0647 <0648   
; #+2079    aShotImageLSB       (1B79:04) Alien shot image LSB @ <05D4 >05E2 >0654   <1A3B 
; #+207A    aShotImageMSB       (1B7A:11) Alien shot image MSB @ >0654   <1A3D 
; #+207B    alienShotYr         (1B7B:24) Alien shot delta Y @ >05B4 <05E5 >05ED <05F3 <0600 <065D >065D <065E >065E   <1A3F 
; #+207C    alienShotXr         (1B7C:1B) Alien shot delta X @ >05B4 <065A >065A <065B >065B <1A0A   <1A41 
; #+207D    alienShotSize       (1B7D:25) Alien shot size  @ >0661   <1A43 
; #+207E    alienShotDelta      (1B7E:FC) Alien shot speed. Normally -1 but set to -4 with less than 9 aliens @ <05E9 *08E0 >18B0  
; #+207F    shotPicEnd          (1B7F:00) the last picture in the current alien shot animation @ >0550 <05DC  
; #+2080    shotSync            (1B80:01) All 3 shots are synchronized to the GO-2 timer. This is copied from timer in the game loop @ >0075 <04BC <0683 >18AB  
; #+2081    tmp2081             (1B81:FF) Used to hold the remember/restore flag in shield-copy routine @ >021E <022B  
; #+2082    numAliens           (1B82:FF) Number of aliens on screen @ <04FC <069E <082B <08D8 >1605 <1759 <1782 <18F3  
; #+2083    saucerStart         (1B83:00) Flag to start saucer (set to 1 when 2091:2092 counts down to 0) @ <068C >0926  
; #+2084    saucerActive        (1B84:00) Saucer is on screen (1 means yes) @ <045D <0699 >06A6 <1807  
; #+2085    saucerHit           (1B85:00) Saucer has been hit (1 means draw it but don't move it) @ <06B5 *157B <180D  
; #+2086    saucerHitTime       (1B86:20) Hit-sequence timer (explosion drawn at 1F, score drawn at 18) @  
; #+2087    saucerPriLocLSB     (1B87:64) Mystery ship print descriptor ... coordinate LSB @ *0729 *0759  <1A3B 
; #+2088    saucerPriLocMSB     (1B88:1D) Mystery ship print descriptor ... coordinate MSB @  <1A3D 
; #+2089    saucerPriPicLSB     (1B89:D0) Mystery ship print descriptor ... message LSB @  <1A3F 
; #+208A    saucerPriPicMSB     (1B8A:29) Mystery ship print descriptor ... message MSB @ >0471 <06BD >06C1 <06CA <1A0A  <1A41 
; #+208B    saucerPriSize       (1B8B:18) Mystery ship print descriptor ... number of characters @  <1A43 
; #+208C    saucerDeltaY        (1B8C:02) Mystery ship delta Y @ >0474 <06C0  
; #+208D    sauScoreLSB         (1B8D:54) Pointer into mystery-ship score table (MSB) @ <0447 >0453 *0711  
; #+208E    sauScoreMSB         (1B8E:1D) Pointer into mystery-ship score table (LSB) @ <0447 >0453  
; #+208F    shotCountLSB        (1B8F:00) Bumped every shot-removal. Saucer's direction is bit 0. (0=2/29, 1=-2/E0) @ <0456 >045A  
; #+2090    shotCountMSB        (1B90:08) Read as two-bytes with 208F, but never used as such. @ <0456 >045A  
; #+2091    tillSaucerLSB       (1B91:00)      @ <0919 >092A  
; #+2092    tillSaucerMSB       (1B92:06) Count down every game loop. When it reaches 0 saucer is triggerd. Reset to 600. @ <0919 >092A  
; #+2093    waitStartLoop       (1B93:00) 1=in wait-for-start loop, 0=in splash screens @ <005D >0767 *17FE  
; #+2094    soundPort3          (1B94:00) Current status of sound port (out $03) @ <18FA >18FE <19DC >19E0  
; #+2095    changeFleetSnd      (1B95:01) Set to 1 in ISR if time to change the fleet sound @ >1765 <1775 >17A7  
; #+2096    fleetSndCnt         (1B96:40) Delay until next fleet movement tone @ <1751 >1751 >1763  
; #+2097    fleetSndReload      (1B97:00) Reload value for fleet sound counter @ <1761 >178F  
; #+2098    soundPort5          (1B98:01) Current status of sound port (out $05) @ >0320 *0A27 <1756 <176D <1795 <1799 >17A5  
; #+2099    extraHold           (1B99:00) Duration counter for extra-ship sound @ *0974 <17AD >17AD  
; #+209A    tilt                (1B9A:00) 1 if tilt handling is in progress @ *17D2 *17E5 *17FB  
; #+209B    fleetSndHold        (1B9B:10) Time to hold fleet-sound at each change @ <1743 >1743 >1769  
;  +209C    unused209C          (1B9C:9E)        
;  +209D    unused209D          (1B9D:00)        
;  +209E    unused209E          (1B9E:20)        
;  +209F    unused209F          (1B9F:1C)        


; This is the image of the alien sprite pulling the upside down Y. The code expects it to be 0030 below the
; second animation picture at 1BD0. This must be unused. The copy to RAM isn't used.
;
;  +20A0    unused20A0          (1BA0:00)        
;  +20A1    unused20A1          (1BA1:03)        
;  +20A2    unused20A2          (1BA2:04)        
;  +20A3    unused20A3          (1BA3:78)        
;  +20A4    unused20A4          (1BA4:14)        
;  +20A5    unused20A5          (1BA5:13)        
;  +20A6    unused20A6          (1BA6:08)        
;  +20A7    unused20A7          (1BA7:1A)        
;  +20A8    unused20A8          (1BA8:3D)        
;  +20A9    unused20A9          (1BA9:68)        
;  +20AA    unused20AA          (1BAA:FC)        
;  +20AB    unused20AB          (1BAB:FC)     
;  +20AC    unused20AC          (1BAC:68)        
;  +20AD    unused20AD          (1BAD:3D)        
;  +20AE    unused20AE          (1BAE:1A)        
;  +20AF    unused20AF          (1BAF:00)        
;  +20B0    unused20B0          (1BB0:00) 
;  +20B1    unused20B1          (1BB1:00)
;  +20B2    unused20B2          (1BB2:01)
;  +20B3    unused20B3          (1BB3:B8)
;  +20B4    unused20B4          (1BB4:98)
;  +20B5    unused20B5          (1BB5:A0)
;  +20B6    unused20B6          (1BB6:1B) 
;  +20B7    unused20B7          (1BB7:10)
;  +20B8    unused20B8          (1BB8:FF)
;  +20B9    unused20B9          (1BB9:00)
;  +20BA    unused20BA          (1BBA:A0)
;  +20BB    unused20BB          (1BBB:1B)
;  +20BC    unused20BC          (1BBC:00)
;  +20BD    unused20BD          (1BBD:00)
;  +20BE    unused20BE          (1BBE:00)
;  +20BF    unused20BF          (1BBF:00)

;--- End of inialization copy from ROM mirror

; These are copied once from ROM at startup (01E6).

; Splash screen animation structure
;
; #+20C0    isrDelay            Delay counter decremented in ISR @ <001C >001C >08A6 <08A9 *0A44 *0A47 >0A9B <0A9E >0AD7 <0ADA  
; #+20C1    isrSplashTask       1=In demo, 2=Little-alien and Y, 4=shooting extra 'C' @ <009E <056C >0801 >0A82 >0A8F <0ABF >0B6B >0B8A >18B5 >1982  
; #+20C2    splashAnForm        Image form (increments each draw) @ <186B >186B <1879   
; #+20C3    splashDeltaX        Delta X @ <186D  
; #+20C4    splashDeltaY        Delta Y @ <01DA   
; #+20C5    splashYr            Y coordinate @ <01DD >01DE  <1A3B 
; #+20C6    splashXr            X coordinate @ <01E1 >01E2  <1A3D  
; #+20C7    splashImageLSB      @ >1888  <1A3F       
; #+20C8    splashImageMSB      Base image 1BA0 (small alien with upside down Y) @ >1888  <1A41   
; #+20C9    splashImageSize     Size of image (16 bytes) @ <1A43  
; #+20CA    splashTargetY       Target Y coordinate @ <1872  
; #+20CB    splashReached       Reached target Y flag (1 when reached) @ <0A87 >189A  
; #+20CC    splashImRestLSB     Base image for restore 1BA0 is small alien with upside down Y @ <187E  
; #+20CD    splashImRestMSB     @ <187E       
; #+20CE    twoPlayers          1 for yes, 0 means 1 player @ <02E6 >079B <08E4 <1698  
; #+20CF    aShotReloadRate     Based on the MSB of the player's score ... how fast the aliens reload their shots @ <0584 <0591 >1728 >18E1  

;  +20D0    unused20D0          ; This is where the alien-sprite-carying-the-Y ...            
;  +20D1    unused20D1          ; ... lives in ROM            
;  +20D2    unused20D2                      
;  +20D3    unused20D3                    
;  +20D4    unused20D4              
;  +20D5    unused20D5              
;  +20D6    unused20D6              
;  +20D7    unused20D7              
;  +20D8    unused20D8             
;  +20D9    unused20D9              
;  +20DA    unused20DA              
;  +20DB    unused20DB              
;  +20DC    unused20DC              
;  +20DD    unused20DD                  
;  +20DE    unused20DE                      
;  +20DF    unused20DF                     
;  +20E0    unused20E0                      
;  +20E1    unused20E1                     
;  +20E2    unused20E2                      
;  +20E3    unused20E3                  
;  +20E4    unused20E4                  

; #+20E5    player1Ex           Extra ship has been awarded = 0 @ >07C5 <093A  
; #+20E6    player2Ex           Extra ship has been awarded = 0 @ >07C5 <093A  
; #+20E7    player1Alive        1 if player is alive, 0 if dead (after last man) @ <02E1 >07C2 >1674 <16C1  
; #+20E8    player2Alive        1 if player is alive, 0 if dead (after last man) @ <02E1 >07C2 >1674 <16C1  

; #+20E9    suspendPlay         (1BE9:01) 1=game things are moving, 0=game things are suspended @ <0042 <0090 *09F3 >19D3  
; #+20EA    coinSwitch          (1BEA:00) 1=switch down, 0=switch up (used to debounce coin switch) @ <0026 >003F >0069  
; #+20EB    numCoins            (1BEB:00) number of coin credits in BCD format (99 max) @ <002D >0038 <0050 <077F <079E >07A3 <1947  
; #+20EC    splashAnimate       (1BEC:01) 0 for animation during splash and 1 for not. This alternates after every cycle. @ <0AF6 <0B17 <0B9E <0BC6 <0BDD >0BE1  
; #+20ED    demoCmdPtrLSB       (1BED:74) pointer to demo commands LSB 1663 @ <1657 >1663  
; #+20EE    demoCmdPtrMSB       (1BEE:1F) pointer to demo commands MSB @ <1657 >1663  
; #+20EF    gameMode            (1BEF:00) 1=game running, 0=demo or splash screens @ <0049 <0097 <02CB <034E >07BF <0A5F <162B >16DB  
;  +20F0    unused20F0          (1BF0:80)        
; #+20F1    adjustScore         (1BF1:00) Set to 1 if score needs adjusting @ *070E <098B >0991 >0A7A  
; #+20F2    scoreDeltaLSB       (1BF2:00) Score adjustment (LSB) @ *0733 <0995 >0A78  
; #+20F3    scoreDeltaMSB       (1BF3:00) Score adjustment (MSB) @ <0995 >0A75  
; #+20F4    HiScorL             (1BF4:00) Hi-score descriptor ... value LSB @ <1681 >1690 <1931  
; #+20F5    HiScorM             (1BF5:00) Hi-score descriptor ... value MSB @ <167D >1694 <1933  
; #+20F6    HiScorLoL           (1BF6:1C) Hi-score descriptor ... location LSB @ <1935  
; #+20F7    HiScorLoM           (1BF7:2F) Hi-score descriptor ... location MSB @ <1937  
; #+20F8    P1ScorL             (1BF8:00) Hi-score descriptor ... value LSB @ >07AC <099A >099D <168B <168F <1931  
; #+20F9    P1ScorM             (1BF9:00) Hi-score descriptor ... value MSB @ >07AC <094C <09A0 >09A3 <167E <1693 <1712 <1933  
; #+20FA    P1ScorLoL           (1BFA:1C) Hi-score descriptor ... location LSB @ <09A6 <1935  
; #+20FB    P1ScorLoM           (1BFB:27) Hi-score descriptor ... location MSB @ <09A8 <1937  
; #+20FC    P2ScorL             (1BFC:00) Hi-score descriptor ... value LSB @ >07AF <168B <1931  
; #+20FD    P2ScorM             (1BFD:00) Hi-score descriptor ... value MSB @ >07AF <094C <167E <1712 <1933  
; #+20FE    P2ScorLoL           (1BFE:1C) Hi-score descriptor ... location LSB @ <1935  
; #+20FF    P2ScorLoM           (1BFF:39) Hi-score descriptor ... location MSB @ <1937  


; Player 1 specific data
;2100 - 2136                    Player 1 alien ship indicators (0=dead) 11*5 = 55
;2137 - 2141                    Unused 11 bytes (room for another row of aliens?)
;2142 - 21F1                    Player 1 shields remembered between rounds 44 bytes * 4 shields ($B0 bytes)
;21F2 - 21FA                    Unused 9 bytes
;  +21FB    p1RefAlienDX        Player 1 reference-alien delta X  
;  +21FC    p1RefAlienY         Player 1 reference-alien Y coordinate  
;  +21FD    p1RefAlienX         Player 1 reference-alien X coordiante
;  +21FE    p1RackCnt           Player 1 rack-count (starts at 0 but get incremented to 1-8)               
;  +21FF    p1ShipsRem          Ships remaining after current dies  

; Player 2 specific data
;2200 - 2236                    Player 2 alien ship indicators (0=dead) 11*5 = 55
;2237 - 2241                    Unused 11 bytes (room for another row of aliens?)
;2242 - 22F1                    Player 2 shields remembered between rounds 44 bytes * 4 shields ($B0 bytes)
;22F2 - 22FA                    Unused 9 bytes
;  +22FB    p2RefAlienDX        Player 2 reference-alien delta X   
;  +22FC    p2RefAlienYr        Player 2 reference-alien Y coordinate  
;  +22FD    p2RefAlienXr        Player 2 reference-alien X coordiante
;  +22FE    p2RackCnt           Player 2 rack-count (starts at 0 but get incremented to 1-8)
;  +22FF    p2ShipsRem          Ships remiaing after current dies@ 07D7 

; In the emulator run the stack builds down through 23DE (23FF - 23DE). Roughly 16 levels.

; Hardware
; Much of this comes from the comments in the MAME emulator.
;
; invaders.h 0000-07FF
; invaders.g 0800-0FFF
; invaders.f 1000-17FF
; invaders.e 1800-1FFF

; The mame/drivers/mw8080bw.c comments have the following information about the interrupts:

;        The CPU's INT line is asserted via a D flip-flop at E3.
;        The flip-flop is clocked by the expression (!(64V | !128V) | VBLANK).
;        According to this, the LO to HI transition happens when the vertical
;        sync chain is 0x80 and 0xda and VBLANK is 0 and 1, respectively.
;        These correspond to lines 96 and 224 as displayed.
;        The interrupt vector is provided by the expression:
;        0xc7 | (64V << 4) | (!64V << 3), giving 0xcf and 0xd7 for the vectors.
;        The flip-flop, thus the INT line, is later cleared by the CPU via
;        one of its memory access control signals.
;
; The value CF is RST 8 and D7 is RST 10.
; If I understand this right then the system gets RST 8 when the beam is *near* the 
; middle of the screen and RST 10 when it is at the end (start of VBLANK).

; Video = 256x * 224y @60Hz vertical
; Video hardware 7168 bytes lbpp bitmap (32 bytes per scanline)

;0000-1FFF   8K ROM
;2000-23FF   1K RAM
;2400-3FFF   7K Video RAM
;4000- RAM mirror

;I/O ports:
;read:
;00        INPUTS (Mapped in hardware but never used by the code)
;01        INPUTS
;02        INPUTS
;03        bit shift register read
;write:
;02        shift amount (3 bits)
;03        sound bits
;04        shift data
;05        sound bits
;06        watch-dog
;07        * See below

; Dedicated shift hardware goes like this:
; Write LSB of 16bit value to port 4
; Write MSB of 16bit value to port 4
; Write left-shift-amount to port 2
; Read port 3 returns the upper byte of the 16bit value
; after it has been shifted left N bits

;Space Invaders
;--------------
;Input:
;Port 0
;   bit 0 DIP4 (Cocktail request?)
;   bit 1 Always 1
;   bit 2 Always 1
;   bit 3 Always 1
;   bit 4 Fire
;   bit 5 Left
;   bit 6 Right
;   bit 7 * See below
;Port 1
;   bit 0 = CREDIT (1 if deposit)
;   bit 1 = 2P start (1 if pressed)
;   bit 2 = 1P start (1 if pressed)
;   bit 3 = Always 1
;   bit 4 = 1P shot (1 if pressed)
;   bit 5 = 1P left (1 if pressed)
;   bit 6 = 1P right (1 if pressed)
;   bit 7 = Not connected
;Port 2
;   bit 0 = DIP3 00 = 3 ships  10 = 5 ships
;   bit 1 = DIP5 01 = 4 ships  11 = 6 ships
;   bit 2 = Tilt
;   bit 3 = DIP6 0 = extra ship at 1500, 1 = extra ship at 1000
;   bit 4 = P2 shot (1 if pressed)
;   bit 5 = P2 left (1 if pressed)
;   bit 6 = P2 right (1 if pressed)
;   bit 7 = DIP7 Coin info displayed in demo screen 0=ON
; Port 3
;   bit 0-7 Shift register data
;
; Output
;Port 2:
;  bit 0,1,2 Shift amount
;Port 3:
;  bit 0=UFO (repeats)        SX0 0.raw
;  bit 1=Shot                 SX1 1.raw
;  bit 2=Flash (player die)   SX2 2.raw
;  bit 3=Invader die          SX3 3.raw
;  bit 4=Extended play        SX4
;  bit 5= AMP enable          SX5
;  bit 6= NC (not wired)
;  bit 7= NC (not wired)
;Port 4:
;  bit 0-7 shift data (LSB on 1st write, MSB on 2nd)
;Port 5:
;  bit 0=Fleet movement 1     SX6 4.raw
;  bit 1=Fleet movement 2     SX7 5.raw
;  bit 2=Fleet movement 3     SX8 6.raw
;  bit 3=Fleet movement 4     SX9 7.raw
;  bit 4=UFO Hit              SX10 8.raw
;  bit 5= NC (Cocktail mode control ... to flip screen)
;  bit 6= NC (not wired)
;  bit 7= NC (not wired)
;
;Port 6:
;  Watchdog ... read or write to reset


;16 bit shift register:
;	f              0	bit
;	xxxxxxxxyyyyyyyy
;	
;	Writing to port 4 shifts x into y, and the new value into x, eg.
;	$0000,
;	write $aa -> $aa00,
;	write $ff -> $ffaa,
;	write $12 -> $12ff, ..
;	
;	Writing to port 2 (bits 0,1,2) sets the offset for the 8 bit result, eg.
;	offset 0:
;	rrrrrrrr		result=xxxxxxxx
;	xxxxxxxxyyyyyyyy
;	
;	offset 2:
;	  rrrrrrrr	result=xxxxxxyy
;	xxxxxxxxyyyyyyyy
;	
;	offset 7:
;	       rrrrrrrr	result=xyyyyyyy
;	xxxxxxxxyyyyyyyy
;	
;	Reading from port 3 returns said result.


; Screen Geometry
; 2400 - 3FFF (1C00 bytes = 256 * 28) 28*8=224. Screen is 256x224 pixels.
; Screen layout. Take this map and rotate it counter clockwise once. Thus the first
; byte is lower left. First "row" ends upper left. Last byte is upper right.
;  
; 
;     2400     2401     2402        ....   241F
;     01234567 01234567 01234567    ....   01234567
; 
;     2420     2421     2422        ....   243F
;     01234567 01234567 01234567    ....   01234567
;    
;     .                                    .
;     .                                    .
;     .                                    .
;     .                                    .
; 
;     3FE0     3FE1     3FE2        ....   3FFF
;     01234567 01234567 01234567    ....   01234567

 
; Reset
0000: 00          NOP                      ; %% Interesting. Why waste the ...
0001: 00          NOP                      ; ... CPU cycles with NOPs ? ...
0002: 00          NOP                      ; ... Slot for jump in development?
0003: C3 D4 18    JMP   $18D4              ; Continue startup at 18D4
0006: 00 00  ; Padding before fixed ISR address

; ScanLine96
; Interrupt brings us here when the beam is *near* the middle of the screen. The real middle
; would be 224/2 = 112. The code pretends this interrupt happesn at line 128.
;
0008: F5          PUSH  PSW                ; Save ...
0009: C5          PUSH  B                  ; ...
000A: D5          PUSH  D                  ; ...
000B: E5          PUSH  H                  ; ... everything
000C: C3 8C 00    JMP   $008C              ; Continue ISR at 8C
000F: 00     ; Padding before fixed ISR address

; ScanLine224
; Interrupt brings us here when the beam is at the end of the screen (line 224) when
; the VBLANK begins.
;
0010: F5          PUSH  PSW                ; Save ...
0011: C5          PUSH  B                  ; ...
0012: D5          PUSH  D                  ; ...
0013: E5          PUSH  H                  ; ... everything
0014: 3E 80       MVI   A,$80              ; Flag that tells objects ...
0016: 32 72 20    STA   #vblankStatus       ; ... on the lower half of the screen to draw/move
0019: 21 C0 20    LXI   H,$20C0            ; Decrement ...
001C: 35          DCR   M                  ; ... the general countdown (used for pauses)
001D: CD CD 17    CALL  CheckHandleTilt    ; Check and handle TILT
0020: DB 01       IN    $01                ; Read coin switch
0022: 0F          RRC                      ; Has a coin been deposited (bit 0)?
0023: DA 67 00    JC    $0067              ; Yes ... note that switch is closed and continue at 3F with A=1
0026: 3A EA 20    LDA   #coinSwitch         ; Switch is now open. Was it ...
0029: A7          ANA   A                  ; ... closed last time?
002A: CA 42 00    JZ    $0042              ; No ... skip registering the credit
;
; Handle bumping credit count
002D: 3A EB 20    LDA   #numCoins           ; Number of credits in BCD
0030: FE 99       CPI   $99                ; 99 credits already?
0032: CA 3E 00    JZ    $003E              ; Yes ... ignore this (better than rolling over to 00)
0035: C6 01       ADI   $01                ; Bump number of credits
0037: 27          DAA                      ; Make it binary coded decimal
0038: 32 EB 20    STA   #numCoins           ; New number of credits
003B: CD 47 19    CALL  DrawNumCredits     ; Draw credits on screen
003E: AF          XRA   A                  ; Credit switch ...
003F: 32 EA 20    STA   #coinSwitch         ; ... has opened
;
0042: 3A E9 20    LDA   #suspendPlay        ; Are we moving ...
0045: A7          ANA   A                  ; ... game objects?
0046: CA 82 00    JZ    $0082              ; No ... restore registers and out
0049: 3A EF 20    LDA   #gameMode           ; Are we in ...
004C: A7          ANA   A                  ; ... game mode?
004D: C2 6F 00    JNZ   $006F              ; Yes ... go process game-play things and out
0050: 3A EB 20    LDA   #numCoins           ; Number of credits
0053: A7          ANA   A                  ; Are there any credits (player standing there)?
0054: C2 5D 00    JNZ   $005D              ; Yes ... skip any ISR animations for the splash screens
0057: CD BF 0A    CALL  ISRSplTasks        ; Process ISR tasks for splash screens
005A: C3 82 00    JMP   $0082              ; Restore registers and out
;
; At this point no game is going and there are credits
005D: 3A 93 20    LDA   #waitStartLoop      ; Are we in the ...
0060: A7          ANA   A                  ; ... "press start" loop?
0061: C2 82 00    JNZ   $0082              ; Yes ... restore registers and out
0064: C3 65 07    JMP   WaitForStart       ; Start the "press start" loop
;
; Mark credit as needing registering
0067: 3E 01       MVI   A,$01              ; Remember switch ...
0069: 32 EA 20    STA   #coinSwitch         ; ... state for debounce
006C: C3 3F 00    JMP   $003F              ; Continue
;
; Main game-play timing loop
006F: CD 40 17    CALL  TimeFleetSound     ; Time down fleet sound and sets flag if needs new delay value
0072: 3A 32 20    LDA   #obj2TimerExtra     ; Use rolling shot's timer to sync ...
0075: 32 80 20    STA   #shotSync           ; ... other two shots
0078: CD 00 01    CALL  DrawAlien          ; Draw the current alien (or exploding alien)
007B: CD 48 02    CALL  RunGameObjs        ; Process game objects (including player object)
007E: CD 13 09    CALL  TimeToSaucer       ; Count down time to saucer
0081: 00          NOP                      ; %% Why are we waiting?
;
0082: E1          POP   H                  ; Restore ...
0083: D1          POP   D                  ; ...
0084: C1          POP   B                  ; ...
0085: F1          POP   PSW                ; ... everything
0086: FB          EI                       ; Enable interrupts
0087: C9          RET                      ; Return from interrupt

0088: 00 00 00 00 ; %% Why waste the space?       

; Continues here at scanline 96
;
008C: AF          XRA   A                  ; Flag that tells ...
008D: 32 72 20    STA   #vblankStatus       ; ... objects on the upper half of screen to draw/move
0090: 3A E9 20    LDA   #suspendPlay        ; Are we moving ...
0093: A7          ANA   A                  ; ... game objects?
0094: CA 82 00    JZ    $0082              ; No ... restore and return
0097: 3A EF 20    LDA   #gameMode           ; Are we in ...
009A: A7          ANA   A                  ; ... game mode?
009B: C2 A5 00    JNZ   $00A5              ; Yes .... process game objects and out
009E: 3A C1 20    LDA   #isrSplashTask      ; Splash-animation tasks
00A1: 0F          RRC                      ; If we are in demo-mode then we'll process the tasks anyway
00A2: D2 82 00    JNC   $0082              ; Not in demo mode ... done
;
00A5: 21 20 20    LXI   H,$2020            ; Game object table (skip player-object at 2010)
00A8: CD 4B 02    CALL  $024B              ; Process all game objects (except player object)
00AB: CD 41 01    CALL  CursorNextAlien    ; Advance cursor to next alien (move the alien if it is last one)
00AE: C3 82 00    JMP   $0082              ; Restore and return

; InitRack
; Initialize the player's rack of aliens. Copy the reference-location and deltas from the
; player's data bank.
;
00B1: CD 86 08    CALL  GetAlRefPtr        ; 2xFC Get current player's ref-alien position pointer
00B4: E5          PUSH  H                  ; Hold pointer
00B5: 7E          MOV   A,M                ; Get player's ...
00B6: 23          INX   H                  ; ... ref-alien ...
00B7: 66          MOV   H,M                ; ...
00B8: 6F          MOV   L,A                ; ... coordinates
00B9: 22 09 20    SHLD  #refAlienYr         ; Set game's reference alien's X,Y
00BC: 22 0B 20    SHLD  #alienPosLSB        ; Set game's alien cursor bit position
00BF: E1          POP   H                  ; Restore pointer
00C0: 2B          DCX   H                  ; 21FB or 22FB ref alien's delta (left or right)
00C1: 7E          MOV   A,M                ; Get ref alien's delta X
00C2: FE 03       CPI   $03                ; If there is one alien it will move right at 3
00C4: C2 C8 00    JNZ   $00C8              ; Not 3 ... keep it
00C7: 3D          DCR   A                  ; If it is 3, back it down to 2 until it switches again
00C8: 32 08 20    STA   #refAlienDXr        ; Store alien deltaY
00CB: FE FE       CPI   $FE                ; Moving left?
00CD: 3E 00       MVI   A,$00              ; Value of 0 for rack-moving-right (not XOR so flags are unaffected)
00CF: C2 D3 00    JNZ   $00D3              ; Not FE ... keep the value 0 for right
00D2: 3C          INR   A                  ; It IS FE ... use 1 for left
00D3: 32 0D 20    STA   #rackDirection      ; Store rack direction
00D6: C9          RET                      ; Done

00D7: 3E 02       MVI   A,$02              ; Set ...
00D9: 32 FB 21    STA   $21FB              ; ... player 1 and 2 ...
00DC: 32 FB 22    STA   $22FB              ; ... alien delta to 2 (right 2 pixels)
00DF: C3 E4 08    JMP   $08E4              

00E2: 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
;
; %% Lots of wasted space here. Seems to be padding the next routine to 0100 

; DrawAlien
; 2006 holds the index into the alien flag data grid. 2067 holds the MSB of the pointer (21xx or 22xx).
; If there is an alien exploding time it down. Otherwise draw the alien if it alive (or skip if
; it isn't). If an alien is drawn (or blank) then the 2000 alien-drawing flag is cleared.
;
0100: 21 02 20    LXI   H,$2002            ; Is there an ...
0103: 7E          MOV   A,M                ; ... alien ...
0104: A7          ANA   A                  ; ... exploding?
0105: C2 38 15    JNZ   AExplodeTime       ; Yes ... go time it down and out
;
0108: E5          PUSH  H                  ; 2002 on the stack
0109: 3A 06 20    LDA   #alienCurIndex      ; Get alien index ...
010C: 6F          MOV   L,A                ; ... for the 21xx or 22xx pointer
010D: 3A 67 20    LDA   #playerDataMSB      ; Get MSB ...
0110: 67          MOV   H,A                ; ... of data area (21xx or 22xx)
0111: 7E          MOV   A,M                ; Get alien status flag
0112: A7          ANA   A                  ; Is the alien alive?
0113: E1          POP   H                  ; HL=2002
0114: CA 36 01    JZ    $0136              ; No alien ... skip drawing alien sprite (but flag done)
0117: 23          INX   H                  ; HL=2003 Bump descriptor
0118: 23          INX   H                  ; HL=2004 Point to alien's row
0119: 7E          MOV   A,M                ; Get alien type
011A: 23          INX   H                  ; HL=2005 Bump descriptor
011B: 46          MOV   B,M                ; Get animation number
011C: E6 FE       ANI   $FE                ; Translate row to type offset as follows: ...
011E: 07          RLC                      ; ... 0,1 -> 32 (type 1) ...
011F: 07          RLC                      ; ... 2,3 -> 16 (type 2) ...
0120: 07          RLC                      ; ...   4 -> 32 (type 3) on top row
0121: 5F          MOV   E,A                ; Sprite offset LSB
0122: 16 00       MVI   D,$00              ; MSB is 0
0124: 21 00 1C    LXI   H,$1C00            ; Position 0 alien sprites
0127: 19          DAD   D                  ; Offset to sprite type
0128: EB          XCHG                     ; Sprite offset to DE
0129: 78          MOV   A,B                ; Animation frame number
012A: A7          ANA   A                  ; Is it position 0?
012B: C4 3B 01    CNZ   $013B              ; No ... add 30 and use position 1 alien sprites
012E: 2A 0B 20    LHLD  #alienPosLSB        ; Pixel position
0131: 06 10       MVI   B,$10              ; 16 rows in alien sprites
0133: CD D3 15    CALL  DrawSprite         ; Draw shifted sprite
;
0136: AF          XRA   A                  ; Let the ISR routine ...
0137: 32 00 20    STA   #waitOnDraw         ; ... advance the cursor to the next alien
013A: C9          RET                      ; Out
;
013B: 21 30 00    LXI   H,$0030            ; Offset sprite pointer ...
013E: 19          DAD   D                  ; ... to animation frame 1 sprites
013F: EB          XCHG                     ; Back to DE
0140: C9          RET                      ; Out

; CursorNextAlien
; This is called from the mid-screen ISR to set the cursor for the next alien to draw. 
; When the cursor moves over all aliens then it is reset to the beginning and the reference 
; alien is moved to its next position.
;
; The flag at 2000 keeps this in sync with the alien-draw routine called from the end-screen ISR. 
; When the cursor is moved here then the flag at 2000 is set to 1. This routine will not change 
; the cursor until the alien-draw routine at 100 clears the flag. Thus no alien is skipped.
;
0141: 3A 68 20    LDA   #playerOK           ; Is the player ...
0144: A7          ANA   A                  ; ... blowing up?
0145: C8          RZ                       ; Yes ... ignore the aliens
0146: 3A 00 20    LDA   #waitOnDraw         ; Still waiting on ...
0149: A7          ANA   A                  ; ... this alien to be drawn?
014A: C0          RNZ                      ; Yes ... leave cursor in place
014B: 3A 67 20    LDA   #playerDataMSB      ; Load alien-data ...
014E: 67          MOV   H,A                ; ... MSB (either 21xx or 22xx)
014F: 3A 06 20    LDA   #alienCurIndex      ; Load the xx part of the alien flag pointer
0152: 16 02       MVI   D,$02              ; When all are gone this triggers 1A1 to return from this stack frame
0154: 3C          INR   A                  ; Have we drawn all aliens ...
0155: FE 37       CPI   $37                ; ... at last position?
0157: CC A1 01    CZ    MoveRefAlien       ; Yes ... move the bottom/right alien and reset index to 0
015A: 6F          MOV   L,A                ; HL now points to alien flag
015B: 46          MOV   B,M                ; Is alien ...
015C: 05          DCR   B                  ; ... alive?
015D: C2 54 01    JNZ   $0154              ; No ... skip to next alien
0160: 32 06 20    STA   #alienCurIndex      ; New alien index
0163: CD 7A 01    CALL  GetAlienCoords     ; Calculate bit position and type for index
0166: 61          MOV   H,C                ; The calculation returns the MSB in C
0167: 22 0B 20    SHLD  #alienPosLSB        ; Store new bit position
016A: 7D          MOV   A,L                ; Has this alien ...
016B: FE 28       CPI   $28                ; ... reached the end of screen?
016D: DA 71 19    JC    $1971              ; Yes ... kill the player
0170: 7A          MOV   A,D                ; This alien's ...
0171: 32 04 20    STA   #alienRow           ; ... row index
0174: 3E 01       MVI   A,$01              ; Set the wait-flag for the ...
0176: 32 00 20    STA   #waitOnDraw         ; ... draw-alien routine to clear
0179: C9          RET                      ; Done

; GetAlienCoords
; Convert alien index in L to screen bit position in C,L.
; Return alien row index (converts to type) in D.
; 
017A: 16 00       MVI   D,$00              ; Row 0
017C: 7D          MOV   A,L                ; Hold onto alien index
017D: 21 09 20    LXI   H,$2009            ; Get alien X ...
0180: 46          MOV   B,M                ; ... to B
0181: 23          INX   H                  ; Get alien y ...
0182: 4E          MOV   C,M                ; ... to C
0183: FE 0B       CPI   $0B                ; Can we take a full row off of index?
0185: FA 94 01    JM    $0194              ; No ... we have the row
0188: DE 0B       SBI   $0B                ; Subtract off 11 (one whole row)
018A: 5F          MOV   E,A                ; Hold the new index
018B: 78          MOV   A,B                ; Add ...
018C: C6 10       ADI   $10                ; ... 16 to bit ...
018E: 47          MOV   B,A                ; ... position Y (1 row in rack)
018F: 7B          MOV   A,E                ; Restore tallied index
0190: 14          INR   D                  ; Next row
0191: C3 83 01    JMP   $0183              ; Keep skipping whole rows
;
0194: 68          MOV   L,B                ; We have the LSB (the row)
0195: A7          ANA   A                  ; Are we in the right column?
0196: C8          RZ                       ; Yes ... X and Y are right
0197: 5F          MOV   E,A                ; Hold index
0198: 79          MOV   A,C                ; Add ...
0199: C6 10       ADI   $10                ; ... 16 to bit ...
019B: 4F          MOV   C,A                ; ... position X (1 column in rack)
019C: 7B          MOV   A,E                ; Restore index
019D: 3D          DCR   A                  ; We adjusted for 1 column
019E: C3 95 01    JMP   $0195              ; Keep moving over column


; MoveRefAlien
; The "reference alien" is the bottom left. All other aliens are drawn relative to this
; reference. This routine moves the reference alien (the delta is set elsewhere) and toggles
; the animation frame number between 0 and 1.
;
01A1: 15          DCR   D                  ; This decrements with each call to move
01A2: CA CD 01    JZ    ReturnTwo          ; Return out of TWO call frames (only used if no aliens left)
01A5: 21 06 20    LXI   H,$2006            ; Set current alien ...
01A8: 36 00       MVI   M,$00              ; ... index to 0
01AA: 23          INX   H                  ; Point to DeltaX
01AB: 4E          MOV   C,M                ; Load DX into C
01AC: 36 00       MVI   M,$00              ; Set DX to 0
01AE: CD D9 01    CALL  AddDelta           ; Move alien
01B1: 21 05 20    LXI   H,$2005            ; Alien animation frame number
01B4: 7E          MOV   A,M                ; Toggle ...
01B5: 3C          INR   A                  ; ... animation ...
01B6: E6 01       ANI   $01                ; ... number between ...
01B8: 77          MOV   M,A                ; ... 0 and 1
01B9: AF          XRA   A                  ; Alien index in A is now 0
01BA: 21 67 20    LXI   H,$2067            ; Restore H ...
01BD: 66          MOV   H,M                ; ... to player data MSB (21 or 22)
01BE: C9          RET                      ; Done

01BF: 00 ; %% Why?

; InitAliens
; Initialize the 55 aliens from last to 1st. 1 means alive.
;
01C0: 21 00 21    LXI   H,$2100            ; Start of alien structures (this is the last alien)
01C3: 06 37       MVI   B,$37              ; Count to 55 (that's five rows of 11 aliens)
01C5: 36 01       MVI   M,$01              ; Bring alien to live
01C7: 23          INX   H                  ; Next alien
01C8: 05          DCR   B                  ; All done?
01C9: C2 C5 01    JNZ   $01C5              ; No ... keep looping
01CC: C9          RET                      ; Done

; ReturnTwo
; If there are no aliens left on the screen then MoveDrawAlien comes here which returns from the
; caller's stack frame.
;
01CD: E1          POP   H                  ; Drop return to caller
01CE: C9          RET                      ; Return to caller's caller

; DrawBottomLine
; Draw a 1px line across the player's stash at the bottom of the screen.
;
01CF: 3E 01       MVI   A,$01              ; Bit 1 set ... going to draw a 1-pixel stripe down left side
01D1: 06 E0       MVI   B,$E0              ; All the way down the screen
01D3: 21 02 24    LXI   H,$2402            ; Screen coordinates (3rd byte from upper left)
01D6: C3 CC 14    JMP   $14CC              ; Draw line down left side

; AddDelta
; HL points to descriptor: DX DY XX YY except DX is already loaded in C
; %% Why the "already loaded" part? Why not just load it here?
;
01D9: 23          INX   H                  ; We loaded delta-x already ... skip over it
01DA: 46          MOV   B,M                ; Get delta-y
01DB: 23          INX   H                  ; Skip over it
01DC: 79          MOV   A,C                ; Add delta-x ...
01DD: 86          ADD   M                  ; ... to x
01DE: 77          MOV   M,A                ; Store new x
01DF: 23          INX   H                  ; Skip to y
01E0: 78          MOV   A,B                ; Add delta-y ...
01E1: 86          ADD   M                  ; ... to y
01E2: 77          MOV   M,A                ; Store new y
01E3: C9          RET                      ; Done

; CopyRAMMirror
; Block copy ROM mirror 1B00-1BBF to initialize RAM at 2000-20BF.
; 
01E4: 06 C0       MVI   B,$C0              ; Number of bytes
01E6: 11 00 1B    LXI   D,$1B00            ; RAM mirror in ROM
01E9: 21 00 20    LXI   H,$2000            ; Start of RAM
01EC: C3 32 1A    JMP   BlockCopy          ; Copy [DE]->[HL] and return



; DrawShieldPl1
; Draw the shields for player 1 (draws it in the buffer in the player's data area).
;
01EF: 21 42 21    LXI   H,$2142            ; Player 1 shield buffer (remember between games in multi-player)
01F2: C3 F8 01    JMP   $01F8              ; Common draw point
;
; DrawShieldPl2
; Draw the shields for player 1 (draws it in the buffer in the player's data area).
;
01F5: 21 42 22    LXI   H,$2242            ; Player 2 shield buffer (remember between games in multi-player)
;
01F8: 0E 04       MVI   C,$04              ; Going to draw 4 shields
01FA: 11 20 1D    LXI   D,$1D20            ; Shield pixel pattern
01FD: D5          PUSH  D                  ; Hold the start for the next shield
01FE: 06 2C       MVI   B,$2C              ; 44 bytes to copy
0200: CD 32 1A    CALL  BlockCopy          ; Block copy DE to HL (B bytes)
0203: D1          POP   D                  ; Restore start of shield pattern
0204: 0D          DCR   C                  ; Drawn all shields?
0205: C2 FD 01    JNZ   $01FD              ; No ... go draw them all
0208: C9          RET                      ; Done

; RememberShields1
; Copy shields on the screen to player 1's data area.
;
0209: 3E 01       MVI   A,$01              ; Not zero means remember
020B: C3 1B 02    JMP   $021B              ; Shuffle-shields player 1

; RememberShields2
; Copy shields on the screen to player 2's data area.
;
020E: 3E 01       MVI   A,$01              ; Not zero means remember
0210: C3 14 02    JMP   $0214              ; Shuffle-shields player 2

; RestoreShields2
; Copy shields from player 2's data area to screen.
;
0213: AF          XRA   A                  ; Zero means restore
0214: 11 42 22    LXI   D,$2242            ; Player 2 shield buffer (remember between games in multi-player)
0217: C3 1E 02    JMP   CopyShields        ; Shuffle-shields player 2

; RestoreShields1
; Copy shields from player 1's data area to screen.
;
021A: AF          XRA   A                  ; Zero means restore
021B: 11 42 21    LXI   D,$2142            ; Player 1 shield buffer (remember between games in multi-player)

; CopyShields
; A is 1 for screen-to-buffer, 0 for to buffer-to-screen
; HL is screen coordinates of first shield. There are 23 rows between shields.
; DE is sprite buffer in memory.
;
021E: 32 81 20    STA   #tmp2081            ; Remember copy/restore flag
0221: 01 02 16    LXI   B,$1602            ; 22 rows, 2 bytes/row (for 1 shield pattern)
0224: 21 06 28    LXI   H,$2806            ; Screen coordinates
0227: 3E 04       MVI   A,$04              ; Four shields to move
0229: F5          PUSH  PSW                ; Hold shield count
022A: C5          PUSH  B                  ; Hold sprite-size
022B: 3A 81 20    LDA   #tmp2081            ; Get back copy/restore flag
022E: A7          ANA   A                  ; Not zero ...
022F: C2 42 02    JNZ   $0242              ; ... means remember shidles
0232: CD 69 1A    CALL  RestoreShields     ; Restore player's shields
0235: C1          POP   B                  ; Get back sprite-size
0236: F1          POP   PSW                ; Get back shield count
0237: 3D          DCR   A                  ; Have we moved all shields?
0238: C8          RZ                       ; Yes ... out
0239: D5          PUSH  D                  ; Hold sprite buffer
023A: 11 E0 02    LXI   D,$02E0            ; Add 2E0 (23 rows) to get to ...
023D: 19          DAD   D                  ; ... next shield on screen
023E: D1          POP   D                  ; restore sprite buffer
023F: C3 29 02    JMP   $0229              ; Go back and do all
;
0242: CD 7C 14    CALL  RememberShields    ; Remember player's shields
0245: C3 35 02    JMP   $0235              ; Continue with next shield


; RunGameObjs
; Process game objects. Each game object has a 16 byte structure. The handler routine for the object
; is at xx03 and xx04 of the structure. The pointer to xx04 is pushed onto the stack before calling
; the handler.
;
; All game objects (except task 0 ... the player) are called at the mid-screen and end-screen renderings.
; Each object decides when to run based on its Y (not rotated) coordinate. If an object is on the lower
; half of the screen then it does its work when the beam is at the top of the screen. If an object is
; on the top of the screen then it does its work when the beam is at the bottom. This keeps the
; object from updating while it is being drawn which would result in an ugly flicker.
;
;
; The player is only processed at the mid-screen interrupt. I am not sure why.
;
; The first three bytes of the structure are used for status and timers.
; 
; If the first byte is FF then the end of the game-task list has been reached.
; If the first byte is FE then the object is skipped.
;
; If the first-two bytes are non-zero then they are treated like a two-byte counter
; and decremented as such. The 2nd byte is the LSB (moves the fastest).
;
; If the first-two bytes are zero then the third byte is treated as an additional counter. It
; is decremented as such.
;
; When all three bytes reach zero the task is executed.
;
; The third-byte-counter was used as a speed-governor for the player's object, but evidently even the slowest
; setting was too slow. It got changed to 0 (fastest possible).
; 
0248: 21 10 20    LXI   H,$2010            ; First game object (active player)
024B: 7E          MOV   A,M                ; Have we reached the ...
024C: FE FF       CPI   $FF                ; ... end of the object list?
024E: C8          RZ                       ; Yes ... done
024F: FE FE       CPI   $FE                ; Is object active?
0251: CA 81 02    JZ    $0281              ; No ... skip it
0254: 23          INX   H                  ; xx01
0255: 46          MOV   B,M                ; First byte to B
0256: 4F          MOV   C,A                ; Hold 1st byte
0257: B0          ORA   B                  ; OR 1st and 2nd byte
0258: 79          MOV   A,C                ; Restore 1st byte
0259: C2 77 02    JNZ   $0277              ; If word at xx00,xx02 is non zero then decrement it
;
025C: 23          INX   H                  ; xx02
025D: 7E          MOV   A,M                ; Get byte counter
025E: A7          ANA   A                  ; Is it 0?
025F: C2 88 02    JNZ   $0288              ; No ... decrement byte counter at xx02
0262: 23          INX   H                  ; xx03
0263: 5E          MOV   E,M                ; Get handler address LSB
0264: 23          INX   H                  ; xx04
0265: 56          MOV   D,M                ; Get handler address MSB
0266: E5          PUSH  H                  ; Remember pointer to MSB
0267: EB          XCHG                     ; Handler address to HL
0268: E5          PUSH  H                  ; Now to stack (making room for indirect call)
0269: 21 6F 02    LXI   H,$026F            ; Return address to 026F
026C: E3          XTHL                     ; Return address (026F) now on stack. Handler in HL.
026D: D5          PUSH  D                  ; Push pointer to data struct (xx04) for handler to use
026E: E9          PCHL                     ; Run object's code (will return to next line)
026F: E1          POP   H                  ; Restore pointer to xx04
0270: 11 0C 00    LXI   D,$000C            ; Offset to next ...
0273: 19          DAD   D                  ; ... game task (C+4=10)
0274: C3 4B 02    JMP   $024B              ; Do next game task
; 
; Word at xx00 and xx01 is non-zero. Decrement it and move to next task. 
0277: 05          DCR   B                  ; Decrement ...
0278: 04          INR   B                  ; ... two ...
0279: C2 7D 02    JNZ   $027D              ; ... byte ...
027C: 3D          DCR   A                  ; ... value ...
027D: 05          DCR   B                  ; ... at ...
027E: 70          MOV   M,B                ; ... xx00 ...
027F: 2B          DCX   H                  ; ... and ...
0280: 77          MOV   M,A                ; ... xx01
;
0281: 11 10 00    LXI   D,$0010            ; Next ...
0284: 19          DAD   D                  ; ... object descriptor
0285: C3 4B 02    JMP   $024B              ; Keep processing game objects
;
; Word at xx00 and xx01 is zero and byte at xx02 is non-zero. Decrement xx02 and 
; move to next task.
0288: 35          DCR   M                  ; Decrement the xx02 counter
0289: 2B          DCX   H                  ; Back up to ...
028A: 2B          DCX   H                  ; ... start of game task
028B: C3 81 02    JMP   $0281              ; Next game task



; GameObj0
; Game object 0: Move/draw the player
;
; This task is only called at the mid-screen ISR. It ALWAYS does its work here, even though
; the player can be on the top or bottom of the screen (not rotated). 
;
028E: E1          POP   H                  ; Get player object structure 2014
028F: 23          INX   H                  ; Point to blow-up status
0290: 7E          MOV   A,M                ; Get player blow-up status
0291: FE FF       CPI   $FF                ; Player is blowing up?
0293: CA 3B 03    JZ    $033B              ; No ... go do normal movement
;
; Handle blowing up player
0296: 23          INX   H                  ; Point to blow-up delay count
0297: 35          DCR   M                  ; Decrement the blow-up delay
0298: C0          RNZ                      ; Not time for a new blow-up sprite ... out
0299: 47          MOV   B,A                ; Hold sprite image number
029A: AF          XRA   A                  ; 0
029B: 32 68 20    STA   #playerOK           ; Player is NOT OK ... player is blowing up
029E: 32 69 20    STA   #enableAlienFire    ; Alien fire is disabled
02A1: 3E 30       MVI   A,$30              ; Reset count ...
02A3: 32 6A 20    STA   #alienFireDelay     ; ... till alien shots are enabled
02A6: 78          MOV   A,B                ; Restore sprite image number (used if we go to 39B)
02A7: 36 05       MVI   M,$05              ; Reload time between blow-up changes
02A9: 23          INX   H                  ; Point to number of blow-up changes
02AA: 35          DCR   M                  ; Count down blow-up changes
02AB: C2 9B 03    JNZ   DrawPlayerDie      ; Still blowing up ... go draw next sprite
;
; Blow up finished
02AE: 2A 1A 20    LHLD  #playerYr           ; Player's coordinates
02B1: 06 10       MVI   B,$10              ; 16 Bytes
02B3: CD 24 14    CALL  EraseSimpleSprite  ; Erase simple sprite (the player)
02B6: 21 10 20    LXI   H,$2010            ; Restore player ...
02B9: 11 10 1B    LXI   D,$1B10            ; ... structure ...
02BC: 06 10       MVI   B,$10              ; ... from ...
02BE: CD 32 1A    CALL  BlockCopy          ; ... ROM mirror
02C1: 06 00       MVI   B,$00              ; Turn off ...
02C3: CD DC 19    CALL  SoundBits3Off      ; ... all sounds
02C6: 3A 6D 20    LDA   #invaded            ; Has rack reached ...
02C9: A7          ANA   A                  ; ... the bottom of the screen?
02CA: C0          RNZ                      ; Yes ... done here
02CB: 3A EF 20    LDA   #gameMode           ; Are we in ...
02CE: A7          ANA   A                  ; ... game mode?
02CF: C8          RZ                       ; No ... return to splash screens
02D0: 31 00 24    LXI   SP,$2400           ; We aren't going to return
02D3: FB          EI                       ; Enable interrupts (we just dropped the ISR context)
02D4: CD D7 19    CALL  DsableGameTasks    ; Disable game tasks
02D7: CD 2E 09    CALL  $092E              ; Get number of ships for active player
02DA: A7          ANA   A                  ; Any left?
02DB: CA 6D 16    JZ    $166D              ; No ... handle game over for player
02DE: CD E7 18    CALL  $18E7              ; Get player-alive status pointer
02E1: 7E          MOV   A,M                ; Is player ...
02E2: A7          ANA   A                  ; ... alive?
02E3: CA 2C 03    JZ    $032C              ; Yes ... remove a ship from player's stash and reenter game loop
02E6: 3A CE 20    LDA   #twoPlayers         ; Multi-player game
02E9: A7          ANA   A                  ; Only one player?
02EA: CA 2C 03    JZ    $032C              ; Yes ... remove a ship from player's stash and reenter game loop
02ED: 3A 67 20    LDA   #playerDataMSB      ; Player data MSB
02F0: F5          PUSH  PSW                ; Hold the MSB
02F1: 0F          RRC                      ; Player 1 is active player?
02F2: DA 32 03    JC    $0332              ; Yes ... go store player 1 shields and come back to 02F8
02F5: CD 0E 02    CALL  RememberShields2   ; No ... go store player 2 shields
02F8: CD 78 08    CALL  $0878              ; Get ref-alien info and pointer to storage
02FB: 73          MOV   M,E                ; Hold the ...
02FC: 23          INX   H                  ; ... ref-alien ...
02FD: 72          MOV   M,D                ; ... screen coordinates
02FE: 2B          DCX   H                  ; Back up ...
02FF: 2B          DCX   H                  ; .. to delta storage
0300: 70          MOV   M,B                ; Store ref-alien's delta (direction)
0301: 00          NOP                      ; %% Why?
0302: CD E4 01    CALL  CopyRAMMirror      ; Copy RAM mirror (getting ready to switch players)
0305: F1          POP   PSW                ; Restore active player MSB
0306: 0F          RRC                      ; Player 1?
0307: 3E 21       MVI   A,$21              ; Player 1 data pointer
0309: 06 00       MVI   B,$00              ; Cocktail bit=0 (player 1)
030B: D2 12 03    JNC   $0312              ; It was player one ... keep data for player 2
030E: 06 20       MVI   B,$20              ; Cocktail bit=1 (player 2)
0310: 3E 22       MVI   A,$22              ; Player 2 data pointer
0312: 32 67 20    STA   #playerDataMSB      ; Change players
0315: CD B6 0A    CALL  TwoSecDelay        ; Two second delay
0318: AF          XRA   A                  ; Clear the player-object ...
0319: 32 11 20    STA   #obj0TimerLSB       ; ... timer (player can move instantly after switching players)
031C: 78          MOV   A,B                ; Cocktail bit to A
031D: D3 05       OUT   $05                ; Set the cocktail mode
031F: 3C          INR   A                  ; Fleet sound 1 (first tone)
0320: 32 98 20    STA   #soundPort5         ; Set the port 5 hold
0323: CD D6 09    CALL  ClearPlayField     ; Clear center window
0326: CD 7F 1A    CALL  RemoveShip         ; Remove a ship and update indicators
0329: C3 F9 07    JMP   $07F9              ; Tell the players that the switch has been made
;
032C: CD 7F 1A    CALL  RemoveShip         ; Remove a ship and update indicators
032F: C3 17 08    JMP   $0817              ; Continue into game loop
;
0332: CD 09 02    CALL  RememberShields1   ; Remember the shields for player 1
0335: C3 F8 02    JMP   $02F8              ; Back to switching-players above

0338: 00 00 00 ; %% Why
           
; Player not blowing up ... handle inputs
033B: 21 68 20    LXI   H,$2068            ; Player OK flag
033E: 36 01       MVI   M,$01              ; Flag 1 ... player is OK
0340: 23          INX   H                  ; 2069
0341: 7E          MOV   A,M                ; Alien shots enabled?
0342: A7          ANA   A                  ; Set flags
0343: C3 B0 03    JMP   $03B0              ; Continue

0346: 00          NOP                      ; %% Why?
0347: 2B          DCX   H                  ; 2069
0348: 36 01       MVI   M,$01              ; Enable alien fire

034A: 3A 1B 20    LDA   #playerXr           ; Current player coordinates
034D: 47          MOV   B,A                ; Hold it
034E: 3A EF 20    LDA   #gameMode           ; Are we in ...
0351: A7          ANA   A                  ; ... game mode?
0352: C2 63 03    JNZ   $0363              ; Yes ... use switches as player controls
; 
0355: 3A 1D 20    LDA   #nextDemoCmd        ; Get demo command
0358: 0F          RRC                      ; Is it right?
0359: DA 81 03    JC    MovePlayerRight    ; Yes ... do right
035C: 0F          RRC                      ; Is it left?
035D: DA 8E 03    JC    MovePlayerLeft     ; Yes ... do left
0360: C3 6F 03    JMP   $036F              ; Skip over movement (draw player and out)
; Player is in control
0363: CD C0 17    CALL  ReadInputs         ; Read active player controls
0366: 07          RLC                      ; Test for ...
0367: 07          RLC                      ; ... right button
0368: DA 81 03    JC    MovePlayerRight    ; Yes ... handle move right
036B: 07          RLC                      ; Test for left button
036C: DA 8E 03    JC    MovePlayerLeft     ; Yes ... handle move left
; Draw player sprite
036F: 21 18 20    LXI   H,$2018            ; Active player descriptor
0372: CD 3B 1A    CALL  ReadDesc           ; Load 5 byte sprite descriptor in order: EDLHB
0375: CD 47 1A    CALL  ConvToScr          ; Convert HL to screen coordinates
0378: CD 39 14    CALL  DrawSimpSprite     ; Draw player
037B: 3E 00       MVI   A,$00              ; Clear the task timer. Nobody changes this but it could have ...
037D: 32 12 20    STA   #obj0TimerExtra     ; ... been speed set for the player with a value other than 0 (not XORA)
0380: C9          RET                      ; Out

; MovePlayerRight
; Handle player moving right
0381: 78          MOV   A,B                ; Player coordinate
0382: FE D9       CPI   $D9                ; At right edge?
0384: CA 6F 03    JZ    $036F              ; Yes ... ignore this
0387: 3C          INR   A                  ; Bump X coordinate
0388: 32 1B 20    STA   #playerXr           ; New X coordinate
038B: C3 6F 03    JMP   $036F              ; Draw player and out

; MovePlayerLeft
; Handle player moving left
038E: 78          MOV   A,B                ; Player coordinate
038F: FE 30       CPI   $30                ; At left edge
0391: CA 6F 03    JZ    $036F              ; Yes ... ignore this
0394: 3D          DCR   A                  ; Bump X coordinate
0395: 32 1B 20    STA   #playerXr           ; New X coordinate
0398: C3 6F 03    JMP   $036F              ; Draw player and out

; DrawPlayerDie
; Toggle the player's blowing-up sprite between two pictures and draw it
039B: 3C          INR   A                  ; Toggle blowing-up ...
039C: E6 01       ANI   $01                ; ... player sprite (0,1,0,1)
039E: 32 15 20    STA   #playerAlive        ; Hold current state
03A1: 07          RLC                      ; *2
03A2: 07          RLC                      ; *4
03A3: 07          RLC                      ; *8
03A4: 07          RLC                      ; *16
03A5: 21 70 1C    LXI   H,$1C70            ; Base blow-up sprite location
03A8: 85          ADD   L                  ; Offset sprite ...
03A9: 6F          MOV   L,A                ; ... pointer
03AA: 22 18 20    SHLD  #plyrSprPicL        ; New blow-up sprite picture
03AD: C3 6F 03    JMP   $036F              ; Draw new blow-up sprite and out

03B0: C2 4A 03    JNZ   $034A              ; Alien shots enabled ... move player's ship, draw it, and out
03B3: 23          INX   H                  ; To 206A
03B4: 35          DCR   M                  ; Time until aliens can fire
03B5: C2 4A 03    JNZ   $034A              ; Not time to enable ... move player's ship, draw it, and out
03B8: C3 46 03    JMP   $0346              ; Enable alien fire ... move player's ship, draw it, and out


; GameObj1
; Game object 1: Move/draw the player shot
;
; This task executes at either mid-screen ISR (if it is on the top half of the non-rotated screen) or
; at the end-screen ISR (if it is on the bottom half of the screen).
;
03BB: 11 2A 20    LXI   D,$202A            ; Object's Yn coordiante
03BE: CD 06 1A    CALL  CompYToBeam        ; Compare to screen-update location
03C1: E1          POP   H                  ; Pointer to task data
03C2: D0          RNC                      ; Make sure we are in the right ISR

03C3: 23          INX   H                  ; Point to 2025 ... the shot status
03C4: 7E          MOV   A,M                ; Get shot status
03C5: A7          ANA   A                  ; Return if ...
03C6: C8          RZ                       ; ... no shot is active
;
03C7: FE 01       CPI   $01                ; Shot just starting (requested elsewhere)?
03C9: CA FA 03    JZ    InitPlyShot        ; Yes ... go initiate shot
;
03CC: FE 02       CPI   $02                ; Progressing normally?
03CE: CA 0A 04    JZ    MovePlyShot        ; Yes ... go move it
;
03D1: 23          INX   H                  ; 2026
03D2: FE 03       CPI   $03                ; Shot blowing up (not because of alien)?
03D4: C2 2A 04    JNZ   $042A              ; No ... try other options
;
; Shot blowing up because it left the playfield, hit a shield, or hit another bullet
03D7: 35          DCR   M                  ; Decrement the timer
03D8: CA 36 04    JZ    EndOfBlowup        ; If done then
03DB: 7E          MOV   A,M                ; Get timer value
03DC: FE 0F       CPI   $0F                ; Starts at 10 ... first decrement brings us here
03DE: C0          RNZ                      ; Not the first time ... explosion has been drawn
; Draw explosion first pass through timer loop
03DF: E5          PUSH  H                  ; Hold pointer to data
03E0: CD 30 04    CALL  ReadPlyShot        ; Read shot descriptor
03E3: CD 52 14    CALL  EraseShifted       ; Erase the sprite
03E6: E1          POP   H                  ; 2026 (timer flag)
03E7: 23          INX   H                  ; 2027 point to sprite LSB
03E8: 34          INR   M                  ; Change 1C90 to 1C91
03E9: 23          INX   H                  ; 2028
03EA: 23          INX   H                  ; 2029
03EB: 35          DCR   M                  ; Drop X coordinate ...
03EC: 35          DCR   M                  ; ... by 2
03ED: 23          INX   H                  ; 202A
03EE: 35          DCR   M                  ; Drop Y ...
03EF: 35          DCR   M                  ; ... coordinate ...
03F0: 35          DCR   M                  ; ... by ...
03F1: 23          INX   H                  ; ... 3
03F2: 36 08       MVI   M,$08              ; 202B 8 bytes in size of sprite
03F4: CD 30 04    CALL  ReadPlyShot        ; Read player shot structure
03F7: C3 00 14    JMP   DrawShiftedSprite  ; Draw sprite and out
;
; InitPlyShot
03FA: 3C          INR   A                  ; Type is now ...
03FB: 77          MOV   M,A                ; ... 2 (in progress)
03FC: 3A 1B 20    LDA   #playerXr           ; Players Y coordinate
03FF: C6 08       ADI   $08                ; To center of player
0401: 32 2A 20    STA   #obj1CoorXr         ; Shot's Y coordinate
0404: CD 30 04    CALL  ReadPlyShot        ; Read 5 byte structure
0407: C3 00 14    JMP   DrawShiftedSprite  ; Draw sprite and out
;
; MovePlyShot
040A: CD 30 04    CALL  ReadPlyShot        ; Read the shot structure
040D: D5          PUSH  D                  ; Hold pointer to sprite image
040E: E5          PUSH  H                  ; Hold sprite coordinates
040F: C5          PUSH  B                  ; Hold sprite size (in B)
0410: CD 52 14    CALL  EraseShifted       ; Erase the sprite from the screen
0413: C1          POP   B                  ; Restore size
0414: E1          POP   H                  ; Restore coords
0415: D1          POP   D                  ; Restore pointer to sprite image
0416: 3A 2C 20    LDA   #shotDeltaX         ; DeltaX for shot
0419: 85          ADD   L                  ; Move the shot ...
041A: 6F          MOV   L,A                ; ... up the screen
041B: 32 29 20    STA   #obj1CoorYr         ; Store shot's new X coordinate
041E: CD 91 14    CALL  DrawSprCollision   ; Draw sprite with collision detection
0421: 3A 61 20    LDA   #collision          ; Test for ...
0424: A7          ANA   A                  ; ... collision
0425: C8          RZ                       ; No collision ... out
;
; Collision with alien detected
0426: 32 02 20    STA   #alienIsExploding   ; Set to not-0 indicating ...
0429: C9          RET                      ; ... an alien is blowing up
;
; Other shot-status options
042A: FE 05       CPI   $05                ; Alien explosion in progress?
042C: C8          RZ                       ; Yes ... nothing to do
042D: C3 36 04    JMP   EndOfBlowup        ; Anything else erases the shot and removes it from duty

; ReadPlyShot
0430: 21 27 20    LXI   H,$2027            ; Read 5 byte sprite structure for ...
0433: C3 3B 1A    JMP   ReadDesc           ; ... player shot

; EndOfBlowup
0436: CD 30 04    CALL  ReadPlyShot        ; Read the shot structure
0439: CD 52 14    CALL  EraseShifted       ; Erase the player's shot
043C: 21 25 20    LXI   H,$2025            ; Reinit ...
043F: 11 25 1B    LXI   D,$1B25            ; ... shot structure ...
0442: 06 07       MVI   B,$07              ; ... from ...
0444: CD 32 1A    CALL  BlockCopy          ; ... ROM mirror
0447: 2A 8D 20    LHLD  #sauScoreLSB        ; Get pointer to saucer-score table
044A: 2C          INR   L                  ; Every shot explosion advances it one
044B: 7D          MOV   A,L                ; Have we passed ...
044C: FE 63       CPI   $63                ; ... the end at 1D63
044E: DA 53 04    JC    $0453              ; No .... keep it
0451: 2E 54       MVI   L,$54              ; Wrap back around to 1D54
0453: 22 8D 20    SHLD  #sauScoreLSB        ; New score pointer
0456: 2A 8F 20    LHLD  #shotCountLSB       ; Increments with every shot ...
0459: 2C          INR   L                  ; ... but only LSB %% ...
045A: 22 8F 20    SHLD  #shotCountLSB       ; ... used for saucer direction
;
045D: 3A 84 20    LDA   #saucerActive       ; Is saucer ...
0460: A7          ANA   A                  ; ... on screen?
0461: C0          RNZ                      ; Yes ... don't reset it
;
; Setup saucer direction for next trip
0462: 7E          MOV   A,M                ; Shot counter
0463: E6 01       ANI   $01                ; Lowest bit set?
0465: 01 29 02    LXI   B,$0229            ; Xr delta of 2 starting at Xr=29
0468: C2 6E 04    JNZ   $046E              ; Yes ... use 2/29
046B: 01 E0 FE    LXI   B,$FEE0            ; No ... Xr delta of -2 starting at Xr=E0
046E: 21 8A 20    LXI   H,$208A            ; Saucer descriptor
0471: 71          MOV   M,C                ; Store Xr coordinate
0472: 23          INX   H                  ; Point to ...
0473: 23          INX   H                  ; ... delta Xr
0474: 70          MOV   M,B                ; Store delta Xr
0475: C9          RET                      ; Done


; GameObj2
; Game object 2: Allien rolling-shot (targets player specifically)
;
; The 2-byte value at 2038 is where the firing-column-table-pointer would be (see other
; shots ... next game objects). This shot doesn't use that table. It targets the player
; specifically. Instead the value is used as a flag to have the shot skip its first
; attempt at firing every time it is reinitialized (when it blows up).
;
; The task-timer at 2032 is copied to 2080 in the game loop. The flag is used as a
; synchronization flag to keep all the shots processed on separate interrupt ticks. This
; has the main effect of slowing the shots down.
;
; When the timer is 2 the squiggly-shot/saucer (object 4 ) runs.
; When the timer is 1 the plunger-shot (object 3) runs.
; Whne the timer is 0 this object, the rolling-shot, runs.
;
0476: E1          POP   H                  ; Game object data
0477: 3A 32 1B    LDA   $1B32              ; Restore delay from ...
047A: 32 32 20    STA   #obj2TimerExtra     ; ... ROM mirror (value 2)
047D: 2A 38 20    LHLD  #rolShotCFirLSB     ; Get pointer to ...
0480: 7D          MOV   A,L                ; ... column-firing table.
0481: B4          ORA   H                  ; All zeros?
0482: C2 8A 04    JNZ   $048A              ; No ... must be a valid column. Go fire.
0485: 2B          DCX   H                  ; Decrement the counter
0486: 22 38 20    SHLD  #rolShotCFirLSB     ; Store new counter value (run the shot next time)
0489: C9          RET                      ; And out

048A: 11 35 20    LXI   D,$2035            ; Rolling-shot data structure
048D: 3E F9       MVI   A,$F9              ; Last picture of "rolling" alien shot
048F: CD 50 05    CALL  ToShotStruct       ; Set code to handle rolling-shot
0492: 3A 46 20    LDA   #pluShotStepCnt     ; Get the plunger-shot step count
0495: 32 70 20    STA   #otherShot1         ; Hold it
0498: 3A 56 20    LDA   #squShotStepCnt     ; Get the squiggly-shot step count
049B: 32 71 20    STA   #otherShot2         ; Hold it
049E: CD 63 05    CALL  HandleAlienShot    ; Handle active shot structure
04A1: 3A 78 20    LDA   #aShotBlowCnt       ; Blow up counter
04A4: A7          ANA   A                  ; Test if shot has cycled through blowing up
04A5: 21 35 20    LXI   H,$2035            ; Rolling-shot data structure
04A8: C2 5B 05    JNZ   FromShotStruct     ; If shot is still running, copy the updated data and out

; ResetShot
; The rolling-shot has blown up. Reset the data structure.
04AB: 11 30 1B    LXI   D,$1B30            ; Reload ...
04AE: 21 30 20    LXI   H,$2030            ; ... object ...
04B1: 06 10       MVI   B,$10              ; ... structure ...
04B3: C3 32 1A    JMP   BlockCopy          ; ... from ROM mirror and out


; GameObj3
; Game object 3: Alien plunger-shot
; This is skipped if there is only one alien left on the screen.
;
04B6: E1          POP   H                  ; Game object data
04B7: 3A 6E 20    LDA   #skipPlunger        ; One alien left? Skip plunger shot?
04BA: A7          ANA   A                  ; Check
04BB: C0          RNZ                      ; Yes. Only one alien. Skip this shot.
04BC: 3A 80 20    LDA   #shotSync           ; Sync flag (copied from GO-2's timer value)
04BF: FE 01       CPI   $01                ; GO-2 and GO-4 are idle?
04C1: C0          RNZ                      ; No ... only one shot at a time

04C2: 11 45 20    LXI   D,$2045            ; Plunger alien shot data structure
04C5: 3E ED       MVI   A,$ED              ; Last picture of "plunger" alien shot
04C7: CD 50 05    CALL  ToShotStruct       ; Copy the plunger alien to the active structure
04CA: 3A 36 20    LDA   #rolShotStepCnt     ; Step count from rolling-shot
04CD: 32 70 20    STA   #otherShot1         ; Hold it
04D0: 3A 56 20    LDA   #squShotStepCnt     ; Step count from squiggly shot
04D3: 32 71 20    STA   #otherShot2         ; Hold it
04D6: CD 63 05    CALL  HandleAlienShot    ; Handle active shot structure
04D9: 3A 76 20    LDA   #aShotCFirLSB       ; LSB of column-firing table
04DC: FE 10       CPI   $10                ; Been through all entries in the table?
04DE: DA E7 04    JC    $04E7              ; Not yet ... table is OK
04E1: 3A 48 1B    LDA   $1B48              ; Been through all ..
04E4: 32 76 20    STA   #aShotCFirLSB       ; ... so reset pointer into firing-column table
04E7: 3A 78 20    LDA   #aShotBlowCnt       ; Get the blow up timer
04EA: A7          ANA   A                  ; Zero means shot is done
04EB: 21 45 20    LXI   H,$2045            ; Plunger shot data
04EE: C2 5B 05    JNZ   FromShotStruct     ; If shot is still running, go copy the updated data and out
;
04F1: 11 40 1B    LXI   D,$1B40            ; Reload ...
04F4: 21 40 20    LXI   H,$2040            ; ... object ...
04F7: 06 10       MVI   B,$10              ; ... structure ...
04F9: CD 32 1A    CALL  BlockCopy          ; ... from mirror
;
04FC: 3A 82 20    LDA   #numAliens          ; Number of aliens on screen
04FF: 3D          DCR   A                  ; Is there only one left?
0500: C2 08 05    JNZ   $0508              ; No ... move on
0503: 3E 01       MVI   A,$01              ; Disable plunger shot ...
0505: 32 6E 20    STA   #skipPlunger        ; ... when only one alien remains
0508: 2A 76 20    LHLD  #aShotCFirLSB       ; Set the plunger shot's ...
050B: C3 7E 06    JMP   $067E              ; ... column-firing pointer data

; Game task 4 when splash screen alien is shooting extra "C" with a squiggly shot
050E: E1          POP   H                  ; Ignore the task data pointer passed on stack
;
; GameObject 4 comes here if processing a squiggly shot
050F: 11 55 20    LXI   D,$2055            ; Squiggly shot data structure
0512: 3E DB       MVI   A,$DB              ; LSB of last byte of picture
0514: CD 50 05    CALL  ToShotStruct       ; Copy squiggly shot to
0517: 3A 46 20    LDA   #pluShotStepCnt     ; Get plunger ...
051A: 32 70 20    STA   #otherShot1         ; ... step count
051D: 3A 36 20    LDA   #rolShotStepCnt     ; Get rolling ...
0520: 32 71 20    STA   #otherShot2         ; ... step count
0523: CD 63 05    CALL  HandleAlienShot    ; Handle active shot structure
0526: 3A 76 20    LDA   #aShotCFirLSB       ; LSB of column-firing table pointer
0529: FE 15       CPI   $15                ; Have we processed all entries?
052B: DA 34 05    JC    $0534              ; No ... don't reset it
052E: 3A 58 1B    LDA   $1B58              ; Reset the pointer ...
0531: 32 76 20    STA   #aShotCFirLSB       ; ... back to the start of the table
0534: 3A 78 20    LDA   #aShotBlowCnt       ; Check to see if squiggly shot is done
0537: A7          ANA   A                  ; 0 means blow-up timer expired
0538: 21 55 20    LXI   H,$2055            ; Squiggly shot data structure
053B: C2 5B 05    JNZ   FromShotStruct     ; If shot is still running, go copy the updated data and out

; Shot explosion is over. Remove the shot.
053E: 11 50 1B    LXI   D,$1B50            ; Reload
0541: 21 50 20    LXI   H,$2050            ; ... object ...
0544: 06 10       MVI   B,$10              ; ... structure ...
0546: CD 32 1A    CALL  BlockCopy          ; ... from mirror
0549: 2A 76 20    LHLD  #aShotCFirLSB       ; Copy pointer to column-firing table ...
054C: 22 58 20    SHLD  #squShotCFirLSB     ; ... back to data structure (for next shot)
054F: C9          RET                      ; Done

; ToShotStruct
0550: 32 7F 20    STA   #shotPicEnd         ; LSB of last byte of last picture in sprite
0553: 21 73 20    LXI   H,$2073            ; Destination is the shot-structure
0556: 06 0B       MVI   B,$0B              ; 11 bytes
0558: C3 32 1A    JMP   BlockCopy          ; Block copy and out

; FromShotStruct
055B: 11 73 20    LXI   D,$2073            ; Source is the shot-structure
055E: 06 0B       MVI   B,$0B              ; 11 bytes
0560: C3 32 1A    JMP   BlockCopy          ; Block copy and out

; HandleAlienShot
; Each of the 3 shots copy their data to the 2073 structure (0B bytes) and call this.
; Then they copy back if the shot is still active. Otherwise they copy from the mirror.
;
; The alien "fire rate" is based on the number of steps the other two shots on the screen 
; have made. The smallest number-of-steps is compared to the reload-rate. If it is too
; soon then no shot is made. The reload-rate is based on the player's score. The MSB
; is looked up in a table to get the reload-rate. The smaller the rate the faster the
; aliens fire. Setting rate this way keeps shots from walking on each other.
; 
0563: 21 73 20    LXI   H,$2073            ; Start of active shot structure
0566: 7E          MOV   A,M                ; Get the shot status
0567: E6 80       ANI   $80                ; Is the shot active?
0569: C2 C1 05    JNZ   $05C1              ; Yes ... go move it

056C: 3A C1 20    LDA   #isrSplashTask      ; ISR splash task
056F: FE 04       CPI   $04                ; Shooting the "C" ?
0571: 3A 69 20    LDA   #enableAlienFire    ; Alien fire enabled flag
0574: CA B7 05    JZ    $05B7              ; We are shooting the extra "C" ... just flag it active and out
0577: A7          ANA   A                  ; Is alien fire enabled?
0578: C8          RZ                       ; No ... don't start a new shot

0579: 23          INX   H                  ; 2074 step count of current shot
057A: 36 00       MVI   M,$00              ; clear the step count

; Make sure it isn't too soon to fire another shot
057C: 3A 70 20    LDA   #otherShot1         ; Get the step count of the 1st "other shot"
057F: A7          ANA   A                  ; Any steps made?
0580: CA 89 05    JZ    $0589              ; No ... ignore this count
0583: 47          MOV   B,A                ; Shuffle off step count
0584: 3A CF 20    LDA   #aShotReloadRate    ; Get the reload rate (based on MSB of score)
0587: B8          CMP   B                  ; Too soon to fire again?
0588: D0          RNC                      ; Yes ... don't fire
0589: 3A 71 20    LDA   #otherShot2         ; Get the step count of the 2nd "other shot"
058C: A7          ANA   A                  ; Any steps made?
058D: CA 96 05    JZ    $0596              ; No steps on any shot ... we are clear to fire
0590: 47          MOV   B,A                ; Shuffle off step count
0591: 3A CF 20    LDA   #aShotReloadRate    ; Get the reload rate (based on MSB of score)
0594: B8          CMP   B                  ; Too soon to fire again?
0595: D0          RNC                      ; Yes ... don't fire
0596: 23          INX   H                  ; 2075
0597: 7E          MOV   A,M                ; Get tracking flag
0598: A7          ANA   A                  ; Does this shot track the player?
0599: CA 1B 06    JZ    $061B              ; Yes ... go make a tracking shot;
059C: 2A 76 20    LHLD  #aShotCFirLSB       ; Column-firing table
059F: 4E          MOV   C,M                ; Get next column to fire from
05A0: 23          INX   H                  ; Bump the ...
05A1: 00          NOP                      ; % WHY?
05A2: 22 76 20    SHLD  #aShotCFirLSB       ; ... pointer into column table
05A5: CD 2F 06    CALL  FindInColumn       ; Find alien in target column
05A8: D0          RNC                      ; No alien is alive in target column ... out
;
05A9: CD 7A 01    CALL  GetAlienCoords     ; Get coordinates of alien (lowest alien in firing column)
05AC: 79          MOV   A,C                ; Offset ...
05AD: C6 07       ADI   $07                ; ... Y by 7
05AF: 67          MOV   H,A                ; To H
05B0: 7D          MOV   A,L                ; Offset ...
05B1: D6 0A       SUI   $0A                ; ... X down 10
05B3: 6F          MOV   L,A                ; To L
05B4: 22 7B 20    SHLD  #alienShotYr        ; Set shot coordinates below alien
;
05B7: 21 73 20    LXI   H,$2073            ; Alien shot status
05BA: 7E          MOV   A,M                ; Get the status
05BB: F6 80       ORI   $80                ; Mark this shot ...
05BD: 77          MOV   M,A                ; ... as actively running
05BE: 23          INX   H                  ; 2074 step count
05BF: 34          INR   M                  ; Give this shot 1 step (it just started)
05C0: C9          RET                      ; Out
;
; Move the alien shot
05C1: 11 7C 20    LXI   D,$207C            ; Alien-shot Y coordinate
05C4: CD 06 1A    CALL  CompYToBeam        ; Compare to beam position
05C7: D0          RNC                      ; Not the right ISR for this shot
;
05C8: 23          INX   H                  ; 2073 status
05C9: 7E          MOV   A,M                ; Get shot status
05CA: E6 01       ANI   $01                ; Bit 0 is 1 if blowing up
05CC: C2 44 06    JNZ   ShotBlowingUp      ; Go do shot-is-blowing-up sequence
05CF: 23          INX   H                  ; 2074 step count
05D0: 34          INR   M                  ; Count the steps (used for fire rate)
05D1: CD 75 06    CALL  $0675              ; Erase shot
05D4: 3A 79 20    LDA   #aShotImageLSB      ; Get LSB of the image pointer
05D7: C6 03       ADI   $03                ; Next set of images
05D9: 21 7F 20    LXI   H,$207F            ; End of image
05DC: BE          CMP   M                  ; Have we reached the end of the set?
05DD: DA E2 05    JC    $05E2              ; No ... keep it
05E0: D6 0C       SUI   $0C                ; Back up to the 1st image in the set
05E2: 32 79 20    STA   #aShotImageLSB      ; New LSB image pointer
05E5: 3A 7B 20    LDA   #alienShotYr        ; Get shot's Y coordinate
05E8: 47          MOV   B,A                ; Hold it
05E9: 3A 7E 20    LDA   #alienShotDelta     ; Get alien shot delta
05EC: 80          ADD   B                  ; Add to shots coordinate
05ED: 32 7B 20    STA   #alienShotYr        ; New shot Y coordinate
05F0: CD 6C 06    CALL  $066C              ; Draw the alien shot
05F3: 3A 7B 20    LDA   #alienShotYr        ; Shot's Y coordinate
05F6: FE 15       CPI   $15                ; Still in the active playfield?
05F8: DA 12 06    JC    $0612              ; No ... end it
05FB: 3A 61 20    LDA   #collision          ; Did shot collide ...
05FE: A7          ANA   A                  ; ... with something?
05FF: C8          RZ                       ; No ... we are done here
0600: 3A 7B 20    LDA   #alienShotYr        ; Shot's Y coordinate
0603: FE 1E       CPI   $1E                ; Is it below player's area?
0605: DA 12 06    JC    $0612              ; Yes ... end it
0608: FE 27       CPI   $27                ; Is it above player's area?
060A: 00          NOP                      ; %% WHY?
060B: D2 12 06    JNC   $0612              ; Yes ... end it
060E: 97          SUB   A                  ; Flag that player ...
060F: 32 15 20    STA   #playerAlive        ; ... has been struck
;
0612: 3A 73 20    LDA   #aShotStatus        ; Flag to ...
0615: F6 01       ORI   $01                ; ... start shot ...
0617: 32 73 20    STA   #aShotStatus        ; ... blowing up
061A: C9          RET                      ; Out
;
; Start a shot right over the player
061B: 3A 1B 20    LDA   #playerXr           ; Player's X coordinate
061E: C6 08       ADI   $08                ; Center of player
0620: 67          MOV   H,A                ; To H for routine
0621: CD 6F 15    CALL  FindColumn         ; Find the column
0624: 79          MOV   A,C                ; Get the column right over player
0625: FE 0C       CPI   $0C                ; Is it a valid column?
0627: DA A5 05    JC    $05A5              ; Yes ... use what we found
062A: 0E 0B       MVI   C,$0B              ; Else use ...
062C: C3 A5 05    JMP   $05A5              ; ... as far over as we can

; FindInColumn
; C contains the target column. Look for a live alien in the column starting with
; the lowest position. Return C=1 if found ... HL points to found slot.
062F: 0D          DCR   C                  ; Column that is firing
0630: 3A 67 20    LDA   #playerDataMSB      ; Player's MSB (21xx or 22xx)
0633: 67          MOV   H,A                ; To MSB of HL
0634: 69          MOV   L,C                ; Column to L
0635: 16 05       MVI   D,$05              ; 5 rows of aliens
0637: 7E          MOV   A,M                ; Get alien's status
0638: A7          ANA   A                  ; 0 means dead
0639: 37          STC                      ; In case not 0
063A: C0          RNZ                      ; Alien is alive? Yes ... return
063B: 7D          MOV   A,L                ; Get the flag pointer LSB
063C: C6 0B       ADI   $0B                ; Jump to same column on next row of rack (+11 aliens per row)
063E: 6F          MOV   L,A                ; New alien index
063F: 15          DCR   D                  ; Tested all rows?
0640: C2 37 06    JNZ   $0637              ; No ... keep looking for a live alien up the rack
0643: C9          RET                      ; Didn't find a live alien. Return with C=0.

; ShotBlowingUp
; Alien shot is blowing up
0644: 21 78 20    LXI   H,$2078            ; Blow up timer
0647: 35          DCR   M                  ; Decrement the value
0648: 7E          MOV   A,M                ; Get the value
0649: FE 03       CPI   $03                ; First tick, 4, we draw the explosion
064B: C2 67 06    JNZ   $0667              ; After that just wait
064E: CD 75 06    CALL  $0675              ; Erase the shot
0651: 21 DC 1C    LXI   H,$1CDC            ; Alien shot ...
0654: 22 79 20    SHLD  #aShotImageLSB      ; ... explosion sprite
0657: 21 7C 20    LXI   H,$207C            ; Alien shot Y
065A: 35          DCR   M                  ; Left two for ...
065B: 35          DCR   M                  ; ... explosion
065C: 2B          DCX   H                  ; Point slien shot X
065D: 35          DCR   M                  ; Up two for ...
065E: 35          DCR   M                  ; ... explosion
065F: 3E 06       MVI   A,$06              ; Alien shot descriptor ...
0661: 32 7D 20    STA   #alienShotSize      ; ... size 6
0664: C3 6C 06    JMP   $066C              ; Draw alien shot explosion

0667: A7          ANA   A                  ; Have we reached 0?
0668: C0          RNZ                      ; No ... keep waiting
0669: C3 75 06    JMP   $0675              ; Erase the explosion and out
;
066C: 21 79 20    LXI   H,$2079            ; Alien shot descriptor
066F: CD 3B 1A    CALL  ReadDesc           ; Read 5 byte structure
0672: C3 91 14    JMP   DrawSprCollision   ; Draw shot and out
;
0675: 21 79 20    LXI   H,$2079            ; Alien shot descriptor
0678: CD 3B 1A    CALL  ReadDesc           ; Read 5 byte structure
067B: C3 52 14    JMP   EraseShifted       ; Erase the shot and out

067E: 22 48 20    SHLD  #pluShotCFirLSB     ; From 50B, update ...
0681: C9          RET                      ; ... column-firing table pointer and out

       

; GameObj4
; Game object 4: Flying Saucer OR squiggly shot
;
; This task is shared by the squiggly-shot and the flying saucer. The saucer waits until the 
; squiggly-shot is over before it begins.
;
0682: E1          POP   H                  ; Pull data pointer from the stack (not going to use it)
0683: 3A 80 20    LDA   #shotSync           ; Sync flag (copied from GO-2's timer value)
0686: FE 02       CPI   $02                ; Are GO-2 and GO-3 idle?
0688: C0          RNZ                      ; No ... only one at a time
0689: 21 83 20    LXI   H,$2083            ; Time-till-saucer flag
068C: 7E          MOV   A,M                ; Is it time ...
068D: A7          ANA   A                  ; ... for a saucer?
068E: CA 0F 05    JZ    $050F              ; No ... go process squiggly shot
0691: 3A 56 20    LDA   #squShotStepCnt     ; Is there a ...
0694: A7          ANA   A                  ; ... squiggly shot going?
0695: C2 0F 05    JNZ   $050F              ; Yes ... go handle squiggly shot

0698: 23          INX   H                  ; Saucer on screen flag
0699: 7E          MOV   A,M                ; (2084) Is the saucer ...
069A: A7          ANA   A                  ; ... already on the screen?
069B: C2 AB 06    JNZ   $06AB              ; Yes ... go handle it
069E: 3A 82 20    LDA   #numAliens          ; Number of aliens remaining
06A1: FE 08       CPI   $08                ; Less than ...
06A3: DA 0F 05    JC    $050F              ; ... 8 ... no saucer
06A6: 36 01       MVI   M,$01              ; (2084) The saucer is on the screen
06A8: CD 3C 07    CALL  $073C              ; Draw the flying saucer

06AB: 11 8A 20    LXI   D,$208A            ; Saucer's Y coordinate
06AE: CD 06 1A    CALL  CompYToBeam        ; Compare to beam position
06B1: D0          RNC                      ; Not the right ISR for moving saucer

06B2: 21 85 20    LXI   H,$2085            ; Saucer hit flag
06B5: 7E          MOV   A,M                ; Has saucer ...
06B6: A7          ANA   A                  ; ... been hit?
06B7: C2 D6 06    JNZ   $06D6              ; Yes ... don't move it

06BA: 21 8A 20    LXI   H,$208A            ; Saucer's structure
06BD: 7E          MOV   A,M                ; Get saucer's Y coordinate
06BE: 23          INX   H                  ; Bump to ...
06BF: 23          INX   H                  ; ... delta Y
06C0: 86          ADD   M                  ; Move saucer
06C1: 32 8A 20    STA   #saucerPriPicMSB    ; New coordinate
06C4: CD 3C 07    CALL  $073C              ; Draw the flying saucer
06C7: 21 8A 20    LXI   H,$208A            ; Saucer's structure
06CA: 7E          MOV   A,M                ; Y coordinate
06CB: FE 28       CPI   $28                ; Too low? End of screen?
06CD: DA F9 06    JC    $06F9              ; Yes ... remove from play
06D0: FE E1       CPI   $E1                ; Too high? End of screen?
06D2: D2 F9 06    JNC   $06F9              ; Yes ... remove from play
06D5: C9          RET                      ; Done

06D6: 06 FE       MVI   B,$FE              ; Turn off ...
06D8: CD DC 19    CALL  SoundBits3Off      ; ... flying saucer sound
06DB: 23          INX   H                  ; (2086) show-hit timer
06DC: 35          DCR   M                  ; Count down show-hit timer
06DD: 7E          MOV   A,M                ; Get current value
06DE: FE 1F       CPI   $1F                ; Starts at 20 ... is this the first tick of show-hit timer?
06E0: CA 4B 07    JZ    $074B              ; Yes ... go show the explosion
06E3: FE 18       CPI   $18                ; A little later ...
06E5: CA 0C 07    JZ    $070C              ; ... show the score besides the saucer and add it
06E8: A7          ANA   A                  ; Has timer expired?
06E9: C0          RNZ                      ; No ... let it run
06EA: 06 EF       MVI   B,$EF              ; 1110_1111 (mask off saucer hit sound)
06EC: 21 98 20    LXI   H,$2098            ; Get current ...
06EF: 7E          MOV   A,M                ; ... value of port 5 sound
06F0: A0          ANA   B                  ; Mask off the saucer-hit sound
06F1: 77          MOV   M,A                ; Set the new value
06F2: E6 20       ANI   $20                ; All sound off but ...
06F4: D3 05       OUT   $05                ; ... cocktail cabinet bit
06F6: 00          NOP                      ; %% Why
06F7: 00          NOP                      ; %%
06F8: 00          NOP                      ; %%
;
06F9: CD 42 07    CALL  $0742              ; Covert pixel pos from descriptor to HL screen and shift
06FC: CD CB 14    CALL  ClearSmallSprite   ; Clear a one byte sprite at HL
06FF: 21 83 20    LXI   H,$2083            ; Saucer structure
0702: 06 0A       MVI   B,$0A              ; 10 bytes in saucer structure
0704: CD 5F 07    CALL  $075F              ; Re-initialize saucer structure

0707: 06 FE       MVI   B,$FE              ; Turn off UFO ...
0709: C3 DC 19    JMP   SoundBits3Off      ; ... sound and out

070C: 3E 01       MVI   A,$01              ; Flag the score ...
070E: 32 F1 20    STA   #adjustScore        ; ... needs updating
0711: 2A 8D 20    LHLD  #sauScoreLSB        ; Saucer score table
0714: 46          MOV   B,M                ; Get score for this saucer
0715: 0E 04       MVI   C,$04              ; There are only 4 possibilities
0717: 21 50 1D    LXI   H,$1D50            ; Possible scores table
071A: 11 4C 1D    LXI   D,$1D4C            ; Print strings for each score
071D: 1A          LDAX  D                  ; Find ...
071E: B8          CMP   B                  ; ... the ...
071F: CA 28 07    JZ    $0728              ; ... print ...
0722: 23          INX   H                  ; ... string ...
0723: 13          INX   D                  ; ... for ...
0724: 0D          DCR   C                  ; ... the ...
0725: C2 1D 07    JNZ   $071D              ; ... score
0728: 7E          MOV   A,M                ; Get LSB of message (MSB is 2088 which is 1D)
0729: 32 87 20    STA   #saucerPriLocLSB    ; Message's LSB (_50=1D94 100=1D97 150=1D9A 300=1D9D)
072C: 26 00       MVI   H,$00              ; MSB = 0 ...
072E: 68          MOV   L,B                ; HL = B
072F: 29          DAD   H                  ; *2
0730: 29          DAD   H                  ; *4
0731: 29          DAD   H                  ; *8
0732: 29          DAD   H                  ; *16
0733: 22 F2 20    SHLD  #scoreDeltaLSB      ; Add score for hitting saucer (015 becomes 150 in BCD).
0736: CD 42 07    CALL  $0742              ; Get the flying saucer score descriptor
0739: C3 F1 08    JMP   $08F1              ; Print the three-byte score and out

073C: CD 42 07    CALL  $0742              ; Draw the ...
073F: C3 39 14    JMP   DrawSimpSprite     ; ... flying saucer

0742: 21 87 20    LXI   H,$2087            ; Read flying saucer ...
0745: CD 3B 1A    CALL  ReadDesc           ; ... structure
0748: C3 47 1A    JMP   ConvToScr          ; Convert pixel number to screen and shift and out
;
074B: 06 10       MVI   B,$10              ; Saucer hit sound bit
074D: 21 98 20    LXI   H,$2098            ; Current state of sounds
0750: 7E          MOV   A,M                ; OR ...
0751: B0          ORA   B                  ; ... in ...
0752: 77          MOV   M,A                ; ... saucer-hit sound
0753: CD 70 17    CALL  $1770              ; Turn off fleet sound and start saucer-hit
0756: 21 7C 1D    LXI   H,$1D7C            ; Sprite for saucer blowing up
0759: 22 87 20    SHLD  #saucerPriLocLSB    ; Store it in structure
075C: C3 3C 07    JMP   $073C              ; Draw the flying saucer
;
075F: 11 83 1B    LXI   D,$1B83            ; Data for saucer (702 sets count to 0A)
0762: C3 32 1A    JMP   BlockCopy          ; Reset saucer object data


; WaitForStart
; Wait for player 1 start button press
0765: 3E 01       MVI   A,$01              ; Tell ISR that we ...
0767: 32 93 20    STA   #waitStartLoop      ; ... have started to wait
076A: 31 00 24    LXI   SP,$2400           ; Reset stack
076D: FB          EI                       ; Enable interrupts
076E: CD 79 19    CALL  $1979              ; Suspend game tasks
0771: CD D6 09    CALL  ClearPlayField     ; Clear center window
0774: 21 13 30    LXI   H,$3013            ; Screen coordinates
0777: 11 F3 1F    LXI   D,$1FF3            ; "PRESS"
077A: 0E 04       MVI   C,$04              ; Message length
077C: CD F3 08    CALL  PrintMessage       ; Print it
077F: 3A EB 20    LDA   #numCoins           ; Number of credits
0782: 3D          DCR   A                  ; Set flags
0783: 21 10 28    LXI   H,$2810            ; Screen coordinates
0786: 0E 14       MVI   C,$14              ; Message length
0788: C2 57 08    JNZ   $0857              ; Take 1 or 2 player start
078B: 11 CF 1A    LXI   D,$1ACF            ; "ONLY 1PLAYER BUTTON "
078E: CD F3 08    CALL  PrintMessage       ; Print message
0791: DB 01       IN    $01                ; Read player controls
0793: E6 04       ANI   $04                ; 1Player start button?
0795: CA 7F 07    JZ    $077F              ; No ... wait for button or credit

;=============================================================
; NewGame
; START NEW GAME
;
; 1 Player start
0798: 06 99       MVI   B,$99              ; Essentially a -1 for DAA
079A: AF          XRA   A                  ; Clear two player flag
;
; 2 player start sequence enters here with a=1 and B=98 (-2)
079B: 32 CE 20    STA   #twoPlayers         ; Set flag for 1 or 2 players
079E: 3A EB 20    LDA   #numCoins           ; Number of credits
07A1: 80          ADD   B                  ; Take away credits
07A2: 27          DAA                      ; Convert back to DAA
07A3: 32 EB 20    STA   #numCoins           ; New credit count
07A6: CD 47 19    CALL  DrawNumCredits     ; Display number of credits
07A9: 21 00 00    LXI   H,$0000            ; Score of 0000
07AC: 22 F8 20    SHLD  #P1ScorL            ; Clear player-1 score
07AF: 22 FC 20    SHLD  #P2ScorL            ; CLear player-2 score
07B2: CD 25 19    CALL  $1925              ; Print player-1 score
07B5: CD 2B 19    CALL  $192B              ; Print player-2 score
07B8: CD D7 19    CALL  DsableGameTasks    ; Disable game tasks
07BB: 21 01 01    LXI   H,$0101            ; Two bytes 1, 1
07BE: 7C          MOV   A,H                ; 1 to A
07BF: 32 EF 20    STA   #gameMode           ; 20EF=1 ... game mode
07C2: 22 E7 20    SHLD  #player1Alive       ; 20E7 and 20E8 both one ... players 1 and 2 are alive
07C5: 22 E5 20    SHLD  #player1Ex          ; Extra-ship is available for player-1 and player-2
07C8: CD 56 19    CALL  DrawStatus         ; Print scores and credits
07CB: CD EF 01    CALL  DrawShieldPl1      ; Draw shields for player-1
07CE: CD F5 01    CALL  DrawShieldPl2      ; Draw shields for player-2
07D1: CD D1 08    CALL  GetShipsPerCred    ; Get number of ships from DIP settings
07D4: 32 FF 21    STA   $21FF              ; Player-1 ships
07D7: 32 FF 22    STA   $22FF              ; Player-2 ships
07DA: CD D7 00    CALL  $00D7              ; Set player-1 and player-2 alien racks going right
07DD: AF          XRA   A                  ; Make a 0
07DE: 32 FE 21    STA   $21FE              ; Player 1 is on first rack of aliens
07E1: 32 FE 22    STA   $22FE              ; Player 2 is on first rack of aliens
07E4: CD C0 01    CALL  InitAliens         ; Initialize 55 aliens for player 1
07E7: CD 04 19    CALL  InitAliensP2       ; Initialize 55 aliens for player 2
07EA: 21 78 38    LXI   H,$3878            ; Screen coordinates for lower-left alien
07ED: 22 FC 21    SHLD  $21FC              ; Initialize reference alien for player 1
07F0: 22 FC 22    SHLD  $22FC              ; Initialize reference alien for player 2
07F3: CD E4 01    CALL  CopyRAMMirror      ; Copy ROM mirror to RAM (2000 - 20C0)
07F6: CD 7F 1A    CALL  RemoveShip         ; Initialize ship hold indicator
;
07F9: CD 8D 08    CALL  PromptPlayer       ; Prompt with "PLAY PLAYER "
07FC: CD D6 09    CALL  ClearPlayField     ; Clear the playfield
07FF: 00          NOP                      ; % Why?
0800: AF          XRA   A                  ; Make a 0
0801: 32 C1 20    STA   #isrSplashTask      ; Disable isr splash-task animation
0804: CD CF 01    CALL  DrawBottomLine     ; Draw line across screen under player
0807: 3A 67 20    LDA   #playerDataMSB      ; Current player
080A: 0F          RRC                      ; Right bit tells all
080B: DA 72 08    JC    $0872              ; Go do player 1
;
080E: CD 13 02    CALL  RestoreShields2    ; Restore shields for player 2
0811: CD CF 01    CALL  DrawBottomLine     ; Draw line across screen under player
0814: CD B1 00    CALL  InitRack           ; Initialize alien rack for current player
0817: CD D1 19    CALL  EnableGameTasks    ; Enable game tasks in ISR
081A: 06 20       MVI   B,$20              ; Enable ...
081C: CD FA 18    CALL  SoundBits3On       ; ... sound amplifier
;
; GAME LOOP
;
081F: CD 18 16    CALL  PlrFireOrDemo      ; Initiate player shot if button pressed
0822: CD 0A 19    CALL  PlyrShotAndBump    ; Collision detect player's shot and rack-bump
0825: CD F3 15    CALL  CountAliens        ; Count aliens (count to 2082)
0828: CD 88 09    CALL  AdjustScore        ; Adjust score (and print) if there is an adjustment
082B: 3A 82 20    LDA   #numAliens          ; Number of live aliens
082E: A7          ANA   A                  ; All aliens gone?
082F: CA EF 09    JZ    $09EF              ; Yes ... end of turn
0832: CD 0E 17    CALL  $170E              ; Update alien-shot-rate based on player's score
0835: CD 35 09    CALL  $0935              ; Check (and handle) extra ship award
0838: CD D8 08    CALL  SpeedShots         ; Adjust alien shot speed
083B: CD 2C 17    CALL  ShotSound          ; Shot sound on or off with 2025
083E: CD 59 0A    CALL  $0A59              ; Check if player is hit
0841: CA 49 08    JZ    $0849              ; No hit ... jump handler
0844: 06 04       MVI   B,$04              ; Player hit sound
0846: CD FA 18    CALL  SoundBits3On       ; Make explosion sound
0849: CD 75 17    CALL  FleetDelayExShip   ; Extra-ship sound timer, set fleet-delay, play fleet movement sound
084C: D3 06       OUT   $06                ; Feed the watchdog
084E: CD 04 18    CALL  CtrlSaucerSound    ; Control saucer sound
0851: C3 1F 08    JMP   $081F              ; Continue game loop

0854: 00 00 00                                    ; %% Why?

; Test for 1 or 2 player start button press
0857: 11 BA 1A    LXI   D,$1ABA            ; "1 OR 2PLAYERS BUTTON"
085A: CD F3 08    CALL  PrintMessage       ; Print message
085D: 06 98       MVI   B,$98              ; -2 (take away 2 credits)
085F: DB 01       IN    $01                ; Read player controls
0861: 0F          RRC                      ; Test ...
0862: 0F          RRC                      ; ... bit 2
0863: DA 6D 08    JC    $086D              ; 2 player button pressed ... do it
0866: 0F          RRC                      ; Test bit 3
0867: DA 98 07    JC    NewGame            ; One player start ... do it
086A: C3 7F 07    JMP   $077F              ; Keep waiting on credit or button
; 2 PLAYER START
086D: 3E 01       MVI   A,$01              ; Flag 2 player game
086F: C3 9B 07    JMP   $079B              ; Continue normal startup

0872: CD 1A 02    CALL  RestoreShields1    ; Restore shields for player 1
0875: C3 14 08    JMP   $0814              ; Continue in game loop

0878: 3A 08 20    LDA   #refAlienDXr        ; Alien deltaY
087B: 47          MOV   B,A                ; Hold it
087C: 2A 09 20    LHLD  #refAlienYr         ; Alien coordinates
087F: EB          XCHG                     ; Coordinates to DE
0880: C3 86 08    JMP   GetAlRefPtr        ; HL is 21FC or 22FC and out
            
0883: 00 00 00                                    ; %% Why?

; GetAlRefPtr
; Get pointer to player's alien ref coordiantes
0886: 3A 67 20    LDA   #playerDataMSB      ; Player data MSB (21 or 22)
0889: 67          MOV   H,A                ; To H
088A: 2E FC       MVI   L,$FC              ; 21FC or 22FC ... alien coordinates
088C: C9          RET                      ; Done

; PromptPlayer
; Print "PLAY PLAYER " and blink score for 2 seconds.
;
088D: 21 11 2B    LXI   H,$2B11            ; Screen coordinates
0890: 11 70 1B    LXI   D,$1B70            ; Message "PLAY PLAYER<1>"
0893: 0E 0E       MVI   C,$0E              ; 14 bytes in message
0895: CD F3 08    CALL  PrintMessage       ; Print the message
0898: 3A 67 20    LDA   #playerDataMSB      ; Get the player number
089B: 0F          RRC                      ; C will be set for player 1
089C: 3E 1C       MVI   A,$1C              ; The "2" character
089E: 21 11 37    LXI   H,$3711            ; Replace the "<1>" with "<2">
08A1: D4 FF 08    CNC   DrawChar           ; If player 2 ... change the message
08A4: 3E B0       MVI   A,$B0              ; Delay of 176 (roughly 2 seconds)
08A6: 32 C0 20    STA   #isrDelay           ; Set the ISR delay value
;
08A9: 3A C0 20    LDA   #isrDelay           ; Get the ISR delay value
08AC: A7          ANA   A                  ; Has the 2 second delay expired?
08AD: C8          RZ                       ; Yes ... done
08AE: E6 04       ANI   $04                ; Every 4 ISRs ...
08B0: C2 BC 08    JNZ   $08BC              ; ... flash the player's score
08B3: CD CA 09    CALL  $09CA              ; Get the score descriptor for the active player
08B6: CD 31 19    CALL  DrawScore          ; Draw the score
08B9: C3 A9 08    JMP   $08A9              ; Back to the top of the wait loop
;
08BC: 06 20       MVI   B,$20              ; 32 rows (4 characters * 8 bytes each)
08BE: 21 1C 27    LXI   H,$271C            ; Player-1 score on the screen
08C1: 3A 67 20    LDA   #playerDataMSB      ; Get the player number
08C4: 0F          RRC                      ; C will be set for player 1
08C5: DA CB 08    JC    $08CB              ; We have the right score coordinates
08C8: 21 1C 39    LXI   H,$391C            ; Use coordinates for player-2's score
08CB: CD CB 14    CALL  ClearSmallSprite   ; Clear a one byte sprite at HL
08CE: C3 A9 08    JMP   $08A9              ; Back to the top of the wait loop


; GetShipsPerCred
; Get number of ships from DIP settings
08D1: DB 02       IN    $02                ; DIP settings
08D3: E6 03       ANI   $03                ; Get number of ships
08D5: C6 03       ADI   $03                ; From 3-6
08D7: C9          RET                      ; Out

; SpeedShots
; With less than 9 aliens on the screen the alien shots get a tad bit faster. Probably
; because the advancing rack can catch them.
;
08D8: 3A 82 20    LDA   #numAliens          ; Number of aliens on screen
08DB: FE 09       CPI   $09                ; More than 8?
08DD: D0          RNC                      ; Yes ... leave shot speed alone
08DE: 3E FB       MVI   A,$FB              ; Normally FF (-1) ... now FB (-4)
08E0: 32 7E 20    STA   #alienShotDelta     ; Speed up alien shots
08E3: C9          RET                      ; Done

08E4: 3A CE 20    LDA   #twoPlayers         ; Number of players
08E7: A7          ANA   A                  ; Skip if ...
08E8: C0          RNZ                      ; ... two player
08E9: 21 1C 39    LXI   H,$391C            ; Player 2's score
08EC: 06 20       MVI   B,$20              ; 32 rows is 4 digits * 8 rows each
08EE: C3 CB 14    JMP   ClearSmallSprite   ; Clear a one byte sprite (32 rows long) at HL

08F1: 0E 03       MVI   C,$03              ; Length of saucer-score message ... fall into print

; PrintMessage
; Print a message on the screen
; HL = coordinates
; DE = message buffer
; C = length
08F3: 1A          LDAX  D                  ; Get character
08F4: D5          PUSH  D                  ; Preserve
08F5: CD FF 08    CALL  DrawChar           ; Print character
08F8: D1          POP   D                  ; Restore
08F9: 13          INX   D                  ; Next character
08FA: 0D          DCR   C                  ; All done?
08FB: C2 F3 08    JNZ   PrintMessage       ; Print all of message
08FE: C9          RET                      ; Out

;=============================================================
; DrawChar
; Get pointer to 8 byte sprite number in A and
; draw sprite on screen at HL
08FF: 11 00 1E    LXI   D,$1E00            ; Character set
0902: E5          PUSH  H                  ; Preserve
0903: 26 00       MVI   H,$00              ; MSB=0
0905: 6F          MOV   L,A                ; Character number to L
0906: 29          DAD   H                  ; HL = HL *2
0907: 29          DAD   H                  ; *4
0908: 29          DAD   H                  ; *8 (8 bytes each)
0909: 19          DAD   D                  ; Get pointer to sprite
090A: EB          XCHG                     ; Now into DE
090B: E1          POP   H                  ; Restore HL
090C: 06 08       MVI   B,$08              ; 8 bytes each
090E: D3 06       OUT   $06                ; Feed watchdog
0910: C3 39 14    JMP   DrawSimpSprite     ; To screen

; TimeToSaucer
0913: 3A 09 20    LDA   #refAlienYr         ; Reference alien's X coordinate
0916: FE 78       CPI   $78                ; Don't process saucer timer ... ($78 is 1st rack Yr)
0918: D0          RNC                      ; ... unless aliens are closer to bottom
0919: 2A 91 20    LHLD  #tillSaucerLSB      ; Time to saucer
091C: 7D          MOV   A,L                ; Is it time ...
091D: B4          ORA   H                  ; ... for a saucer
091E: C2 29 09    JNZ   $0929              ; No ... skip flagging
0921: 21 00 06    LXI   H,$0600            ; Reset timer to 600 game loops
0924: 3E 01       MVI   A,$01              ; Flag a ...
0926: 32 83 20    STA   #saucerStart        ; ... saucer sequence
0929: 2B          DCX   H                  ; Decrement the ...
092A: 22 91 20    SHLD  #tillSaucerLSB      ; ... time-to-saucer
092D: C9          RET                      ; Done

;=============================================================
; Get number of ships for acive player
092E: CD 11 16    CALL  GetPlayerDataPtr   ; HL points to player data
0931: 2E FF       MVI   L,$FF              ; Last byte = numbe of ships
0933: 7E          MOV   A,M                ; Get number of ships
0934: C9          RET                      ; Done

;=============================================================
; Award extra ship if score has reached ceiling
0935: CD 10 19    CALL  CurPlyAlive        ; Get descriptor of sorts
0938: 2B          DCX   H                  ; Back up ...
0939: 2B          DCX   H                  ; ... two bytes
093A: 7E          MOV   A,M                ; Has extra ship ...
093B: A7          ANA   A                  ; already been awarded?
093C: C8          RZ                       ; Yes ... ignore
093D: 06 15       MVI   B,$15              ; Default 1500
093F: DB 02       IN    $02                ; Read DIP settings
0941: E6 08       ANI   $08                ; Extra ship at 1000 or 1500
0943: CA 48 09    JZ    $0948              ; 0=1500
0946: 06 10       MVI   B,$10              ; Awarded at 1000
0948: CD CA 09    CALL  $09CA              ; Get score descriptor for active player
094B: 23          INX   H                  ; MSB of score ...
094C: 7E          MOV   A,M                ; ... to accumulator
094D: B8          CMP   B                  ; Time for an extra ship?
094E: D8          RC                       ; No ... out
094F: CD 2E 09    CALL  $092E              ; Get pointer to number of ships
0952: 34          INR   M                  ; Bump number of ships
0953: 7E          MOV   A,M                ; Get the new total
0954: F5          PUSH  PSW                ; Hang onto it for a bit
0955: 21 01 25    LXI   H,$2501            ; Screen coords for ship hold
0958: 24          INR   H                  ; Bump to ...
0959: 24          INR   H                  ; ... next
095A: 3D          DCR   A                  ; ... spot
095B: C2 58 09    JNZ   $0958              ; Find spot for new ship
095E: 06 10       MVI   B,$10              ; 16 byte sprite
0960: 11 60 1C    LXI   D,$1C60            ; Player sprite
0963: CD 39 14    CALL  DrawSimpSprite     ; Draw the sprite
0966: F1          POP   PSW                ; Restore the count
0967: 3C          INR   A                  ; +1
0968: CD 8B 1A    CALL  $1A8B              ; Print the number of ships
096B: CD 10 19    CALL  CurPlyAlive        ; Get descriptor for active player of some sort
096E: 2B          DCX   H                  ; Back up ...
096F: 2B          DCX   H                  ; ... two bytes
0970: 36 00       MVI   M,$00              ; Flag extra ship has been awarded
0972: 3E FF       MVI   A,$FF              ; Set timer ...
0974: 32 99 20    STA   #extraHold          ; ... for extra-ship sound
0977: 06 10       MVI   B,$10              ; Make sound ...
0979: C3 FA 18    JMP   SoundBits3On       ; ... for extra man

; AlienScoreValue
097C: 21 A0 1D    LXI   H,$1DA0            ; Table for scores for hitting alien
097F: FE 02       CPI   $02                ; 0 or 1 (lower two rows) ...
0981: D8          RC                       ; ... return HL points to value 10
0982: 23          INX   H                  ; next value
0983: FE 04       CPI   $04                ; 2 or 3 (middle two rows) ...
0985: D8          RC                       ; ... return HL points to value 20
0986: 23          INX   H                  ; Top row ...
0987: C9          RET                      ; ... return HL points to value 30

; AdjustScore
; Adjust the score for the active player. 20F1 is 1 if there is a new value to add.
; The adjustment is in 20F2,20F3. Then print the score.
0988: CD CA 09    CALL  $09CA              ; Get score structure for active player
098B: 3A F1 20    LDA   #adjustScore        ; Does the score ...
098E: A7          ANA   A                  ; ... need increasing?
098F: C8          RZ                       ; No ... done
0990: AF          XRA   A                  ; Mark score ...
0991: 32 F1 20    STA   #adjustScore        ; ... as adjusted
0994: E5          PUSH  H                  ; Hold the pointer to the structure
0995: 2A F2 20    LHLD  #scoreDeltaLSB      ; Get requested adjustment
0998: EB          XCHG                     ; Adjustment to DE
0999: E1          POP   H                  ; Get back pointer to structure
099A: 7E          MOV   A,M                ; Add adjustment ...
099B: 83          ADD   E                  ; ... first byte
099C: 27          DAA                      ; Adjust it for BCD
099D: 77          MOV   M,A                ; Store new LSB
099E: 5F          MOV   E,A                ; Add adjustment ...
099F: 23          INX   H                  ; ... to ...
09A0: 7E          MOV   A,M                ; ... second ...
09A1: 8A          ADC   D                  ; ... byte
09A2: 27          DAA                      ; Adjust for BCD (cary gets dropped)
09A3: 77          MOV   M,A                ; Store second byte
09A4: 57          MOV   D,A                ; Second byte to D (first byte still in E)
09A5: 23          INX   H                  ; Load ...
09A6: 7E          MOV   A,M                ; ... the ...
09A7: 23          INX   H                  ; ... screen ...
09A8: 66          MOV   H,M                ; ... coordinates ...
09A9: 6F          MOV   L,A                ; ... to HL
09AA: C3 AD 09    JMP   Print4Digits       ; %% Usually a good idea, but wasted here

; Print4Digits
; Print 4 digits in DE
09AD: 7A          MOV   A,D                ; Get first 2 digits of BCD or hex
09AE: CD B2 09    CALL  DrawHexByte        ; Print them
09B1: 7B          MOV   A,E                ; Get second 2 digits of BCD or hex (fall into print)

; DrawHexByte
; Display 2 digits in A to screen at HL
09B2: D5          PUSH  D                  ; Preserve
09B3: F5          PUSH  PSW                ; Save for later
09B4: 0F          RRC                      ; Get ...
09B5: 0F          RRC                      ; ...
09B6: 0F          RRC                      ; ...
09B7: 0F          RRC                      ; ... left digit
09B8: E6 0F       ANI   $0F                ; Mask out lower digit's bits
09BA: CD C5 09    CALL  $09C5              ; To screen at HL
09BD: F1          POP   PSW                ; Restore digit
09BE: E6 0F       ANI   $0F                ; Mask out upper digit
09C0: CD C5 09    CALL  $09C5              ; To screen
09C3: D1          POP   D                  ; Restore
09C4: C9          RET                      ; Done
;
09C5: C6 1A       ADI   $1A                ; Bump to number characters
09C7: C3 FF 08    JMP   DrawChar           ; Continue ...

; Get score descriptor for active player
09CA: 3A 67 20    LDA   #playerDataMSB      ; Get active player
09CD: 0F          RRC                      ; Test for player
09CE: 21 F8 20    LXI   H,$20F8            ; Player 1 score descriptor
09D1: D8          RC                       ; Keep it if player 1 is active
09D2: 21 FC 20    LXI   H,$20FC            ; Else get player 2 descriptor
09D5: C9          RET                      ; Out

; ClearPlayField
; Clear center window of screen
09D6: 21 02 24    LXI   H,$2402            ; Thrid from left, top of screen
09D9: 36 00       MVI   M,$00              ; Clear screen byte
09DB: 23          INX   H                  ; Next in row
09DC: 7D          MOV   A,L                ; Get X ...
09DD: E6 1F       ANI   $1F                ; ... coordinate
09DF: FE 1C       CPI   $1C                ; Edge minus a buffer?
09E1: DA E8 09    JC    $09E8              ; No ... keep going
09E4: 11 06 00    LXI   D,$0006            ; Else ... bump to
09E7: 19          DAD   D                  ; ... next edge + buffer
09E8: 7C          MOV   A,H                ; Get Y coordinate
09E9: FE 40       CPI   $40                ; Reached bottom?
09EB: DA D9 09    JC    $09D9              ; No ... keep going
09EE: C9          RET                      ; Done

09EF: CD 3C 0A    CALL  $0A3C              
09F2: AF          XRA   A                  ; Suspend ...
09F3: 32 E9 20    STA   #suspendPlay        ; ... ISR game tasks
09F6: CD D6 09    CALL  ClearPlayField     ; Clear playfield
09F9: 3A 67 20    LDA   #playerDataMSB      ; Hold current player number ...
09FC: F5          PUSH  PSW                ; ... on stack
09FD: CD E4 01    CALL  CopyRAMMirror      ; Block copy RAM mirror from ROM
0A00: F1          POP   PSW                ; Restore ...
0A01: 32 67 20    STA   #playerDataMSB      ; ... current player number
0A04: 3A 67 20    LDA   #playerDataMSB      ; %% Why load this again? Nobody ever jumps to 0A04?
0A07: 67          MOV   H,A                ; To H
0A08: E5          PUSH  H                  ; Hold player-data pointer
0A09: 2E FE       MVI   L,$FE              ; 2xFE ... rack count
0A0B: 7E          MOV   A,M                ; Get the number of racks the player has beaten
0A0C: E6 07       ANI   $07                ; 0-7
0A0E: 3C          INR   A                  ; Now 1-8
0A0F: 77          MOV   M,A                ; Update count since player just beat a rack
0A10: 21 A2 1D    LXI   H,$1DA2            ; Starting coordinate of alien table
0A13: 23          INX   H                  ; Find the ...
0A14: 3D          DCR   A                  ; ... right entry ...
0A15: C2 13 0A    JNZ   $0A13              ; ... in the table
0A18: 7E          MOV   A,M                ; Get the starting Y coordiante
0A19: E1          POP   H                  ; Restore player's pointer
0A1A: 2E FC       MVI   L,$FC              ; 2xFC ...
0A1C: 77          MOV   M,A                ; Set rack's starting Y coordinate
0A1D: 23          INX   H                  ; Point to X
0A1E: 36 38       MVI   M,$38              ; Set rack's starting X coordinate to 38
0A20: 7C          MOV   A,H                ; Player ...
0A21: 0F          RRC                      ; ... number to carry
0A22: DA 33 0A    JC    $0A33              ; 2nd player stuff
0A25: 3E 21       MVI   A,$21              ; Start fleet with ...
0A27: 32 98 20    STA   #soundPort5         ; ... first sound
0A2A: CD F5 01    CALL  DrawShieldPl2      ; Draw shields for player 2
0A2D: CD 04 19    CALL  InitAliensP2       ; Initalize aliens for player 2
0A30: C3 04 08    JMP   $0804              ; Continue at top of game loop
;
0A33: CD EF 01    CALL  DrawShieldPl1      ; Draw shields for player 1
0A36: CD C0 01    CALL  InitAliens         ; Initialize aliens for player 1
0A39: C3 04 08    JMP   $0804              ; Continue at top of game loop
;
0A3C: CD 59 0A    CALL  $0A59              ; Check player collision
0A3F: C2 52 0A    JNZ   $0A52              ; Player is not alive ... skip delay
0A42: 3E 30       MVI   A,$30              ; Half second delay
0A44: 32 C0 20    STA   #isrDelay           ; Set ISR timer
0A47: 3A C0 20    LDA   #isrDelay           ; Has timer expired?
0A4A: A7          ANA   A                  ; Check exipre
0A4B: C8          RZ                       ; Out if done
0A4C: CD 59 0A    CALL  $0A59              ; Check player collision
0A4F: CA 47 0A    JZ    $0A47              ; No collision ... wait on timer
0A52: CD 59 0A    CALL  $0A59              ; Wait for ...
0A55: C2 52 0A    JNZ   $0A52              ; ... collision to end
0A58: C9          RET                      ; Done

; Check to see if player is hit
0A59: 3A 15 20    LDA   #playerAlive        ; Active player hit flag
0A5C: FE FF       CPI   $FF                ; All FFs means player is OK
0A5E: C9          RET                      ; Out

; ScoreForAlien
; Start the hit-alien sound and flag the adjustment for the score.
; B contains the row, which determines the score value.
0A5F: 3A EF 20    LDA   #gameMode           ; Are we in ...
0A62: A7          ANA   A                  ; ... game mode?
0A63: CA 7C 0A    JZ    $0A7C              ; No ... skip scoring in demo
0A66: 48          MOV   C,B                ; Hold row number
0A67: 06 08       MVI   B,$08              ; Alien hit sound
0A69: CD FA 18    CALL  SoundBits3On       ; Enable sound
0A6C: 41          MOV   B,C                ; Restore row number
0A6D: 78          MOV   A,B                ; Into A
0A6E: CD 7C 09    CALL  AlienScoreValue    ; Look up the score for the alien
0A71: 7E          MOV   A,M                ; Get the score value
0A72: 21 F3 20    LXI   H,$20F3            ; Pointer to score delta
0A75: 36 00       MVI   M,$00              ; Upper byte of score delta is "00"
0A77: 2B          DCX   H                  ; Point to score delta LSB
0A78: 77          MOV   M,A                ; Set score for hitting alien
0A79: 2B          DCX   H                  ; Point to adjust-score-flag
0A7A: 36 01       MVI   M,$01              ; The score will get changed elsewhere
0A7C: 21 62 20    LXI   H,$2062            ; Return exploding-alien descriptor
0A7F: C9          RET                      ; Out

; Animate
; Start the ISR moving the sprite. Return when done.
0A80: 3E 02       MVI   A,$02              ; Start simple linear ...
0A82: 32 C1 20    STA   #isrSplashTask      ; ... sprite animation (splash)
0A85: D3 06       OUT   $06                ; Feed watchdog
0A87: 3A CB 20    LDA   #splashReached      ; Has the ...
0A8A: A7          ANA   A                  ; ... sprite reached target?
0A8B: CA 85 0A    JZ    $0A85              ; No ... wait
0A8E: AF          XRA   A                  ; Stop ...
0A8F: 32 C1 20    STA   #isrSplashTask      ; ... ISR animation
0A92: C9          RET                      ; Done

; PrintMessageDel
; Print message from DE to screen at HL (length in B) with a
; delay between letters.
0A93: D5          PUSH  D                  ; Preserve
0A94: 1A          LDAX  D                  ; Get character
0A95: CD FF 08    CALL  DrawChar           ; Draw character on screen
0A98: D1          POP   D                  ; Preserve
0A99: 3E 07       MVI   A,$07              ; Delay between letters
0A9B: 32 C0 20    STA   #isrDelay           ; Set counter
0A9E: 3A C0 20    LDA   #isrDelay           ; Get counter
0AA1: 3D          DCR   A                  ; Is it 1?
0AA2: C2 9E 0A    JNZ   $0A9E              ; No ... wait on it
0AA5: 13          INX   D                  ; Next in message
0AA6: 0D          DCR   C                  ; All done?
0AA7: C2 93 0A    JNZ   PrintMessageDel    ; No ... do all
0AAA: C9          RET                      ; Out

; SplashSquiggly
0AAB: 21 50 20    LXI   H,$2050            ; Pointer to game-object 4 timer
0AAE: C3 4B 02    JMP   $024B              ; Process squiggly-shot in demo mode

; OneSecDelay
; Delay 64 interrupts
0AB1: 3E 40       MVI   A,$40              ; Delay of 64 (tad over 1 sec)
0AB3: C3 D7 0A    JMP   WaitOnDelay        ; Do delay

; TwoSecDelay
; Delay 128 interrupts
0AB6: 3E 80       MVI   A,$80              ; Delay of 80 (tad over 2 sec)
0AB8: C3 D7 0A    JMP   WaitOnDelay        ; Do delay

; SplashDemo
0ABB: E1          POP   H                  ; Drop the call to ABF and ...
0ABC: C3 72 00    JMP   $0072              ; ... do a demo game loop without sound

; ISRSplTasks
; Different types of splash tasks managed by ISR in splash screens. The ISR
; calls this if in splash-mode. These may have been bit flags to allow all 3 
; at the same time. Maybe it is just easier to do a switch with a rotate-to-carry.
;
0ABF: 3A C1 20    LDA   #isrSplashTask      ; Get the ISR task number
0AC2: 0F          RRC                      ; In demo play mode?
0AC3: DA BB 0A    JC    SplashDemo         ; 1: Yes ... go do game play (without sound)
0AC6: 0F          RRC                      ; Moving little alien from point A to B?
0AC7: DA 68 18    JC    SplashSprite       ; 2: Yes ... go move little alien from point A to B
0ACA: 0F          RRC                      ; Shooting extra "C" with squiggly shot?
0ACB: DA AB 0A    JC    SplashSquiggly     ; 4: Yes ... go shoot extra "C" in splash
0ACE: C9          RET                      ; No task to do

; Message to center of screen.
; Only used in one place for "SPACE  INVADERS"
0ACF: 21 14 2B    LXI   H,$2B14            ; Near center of screen
0AD2: 0E 0F       MVI   C,$0F              ; 15 bytes in message
0AD4: C3 93 0A    JMP   PrintMessageDel    ; Print and out

; WaitOnDelay
; Wait on ISR counter to reach 0
0AD7: 32 C0 20    STA   #isrDelay           ; Delay counter
0ADA: 3A C0 20    LDA   #isrDelay           ; Get current delay
0ADD: A7          ANA   A                  ; Zero yet?
0ADE: C2 DA 0A    JNZ   $0ADA              ; No ... wait on it
0AE1: C9          RET                      ; Out

; IniSplashAni
; Init the splash-animation block
0AE2: 21 C2 20    LXI   H,$20C2            ; The splash-animation descriptor
0AE5: 06 0C       MVI   B,$0C              ; C bytes
0AE7: C3 32 1A    JMP   BlockCopy          ; Block copy DE to descriptor

;=============================================================
; After initialization ... splash screens
0AEA: AF          XRA   A                  ; Make a 0
0AEB: D3 03       OUT   $03                ; Turn off sound
0AED: D3 05       OUT   $05                ; Turn off sound
0AEF: CD 82 19    CALL  $1982              ; Turn off ISR splash-task
0AF2: FB          EI                       ; Enable interrupts (using them for delays)
0AF3: CD B1 0A    CALL  OneSecDelay        ; One second delay
0AF6: 3A EC 20    LDA   #splashAnimate      ; Splash screen type
0AF9: A7          ANA   A                  ; Set flags based on type
0AFA: 21 17 30    LXI   H,$3017            ; Screen coordinates (middle near top)
0AFD: 0E 04       MVI   C,$04              ; 4 characters in "PLAY"
0AFF: C2 E8 0B    JNZ   $0BE8              ; Not 0 ... do "normal" PLAY
0B02: 11 FA 1C    LXI   D,$1CFA            ; The "PLAy" with an upside down 'Y'
0B05: CD 93 0A    CALL  PrintMessageDel    ; Print the "PLAy"
0B08: 11 AF 1D    LXI   D,$1DAF            ; "SPACE  INVADERS" message
0B0B: CD CF 0A    CALL  $0ACF              ; Print to middle-ish of screen
0B0E: CD B1 0A    CALL  OneSecDelay        ; One second delay
0B11: CD 15 18    CALL  DrawAdvTable       ; Draw "SCORE ADVANCE TABLE" with print delay
0B14: CD B6 0A    CALL  TwoSecDelay        ; Two second delay
0B17: 3A EC 20    LDA   #splashAnimate      ; Do splash ...
0B1A: A7          ANA   A                  ; ... animations?
0B1B: C2 4A 0B    JNZ   $0B4A              ; Not 0 ... no animations
;
; Animate small alien replacing upside-down Y with correct Y
0B1E: 11 95 1A    LXI   D,$1A95            ; Animate sprite from Y=FE to Y=9E step -1
0B21: CD E2 0A    CALL  IniSplashAni       ; Copy to splash-animate structure
0B24: CD 80 0A    CALL  Animate            ; Wait for ISR to move sprite (small alien)
0B27: 11 B0 1B    LXI   D,$1BB0            ; Animate sprite from Y=98 to Y=FF step 1
0B2A: CD E2 0A    CALL  IniSplashAni       ; Copy to splash-animate structure
0B2D: CD 80 0A    CALL  Animate            ; Wait for ISR to move sprite (alien pulling upside down Y)
0B30: CD B1 0A    CALL  OneSecDelay        ; One second delay
0B33: 11 C9 1F    LXI   D,$1FC9            ; Animate sprite from Y=FF to Y=97 step 1
0B36: CD E2 0A    CALL  IniSplashAni       ; Copy to splash-animate structure
0B39: CD 80 0A    CALL  Animate            ; Wait for ISR to move sprite (alien pushing Y)
0B3C: CD B1 0A    CALL  OneSecDelay        ; One second delay
0B3F: 21 B7 33    LXI   H,$33B7            ; Where the splash alien ends up
0B42: 06 0A       MVI   B,$0A              ; 10 rows
0B44: CD CB 14    CALL  ClearSmallSprite   ; Clear a one byte sprite at HL
0B47: CD B6 0A    CALL  TwoSecDelay        ; Two second delay
;
; Play demo
0B4A: CD D6 09    CALL  ClearPlayField     ; Clear playfield
0B4D: 3A FF 21    LDA   $21FF              ; Number of ships for player-1
0B50: A7          ANA   A                  ; If non zero ...
0B51: C2 5D 0B    JNZ   $0B5D              ; ... keep it (counts down between demos)
0B54: CD D1 08    CALL  GetShipsPerCred    ; Get number of ships from DIP settings
0B57: 32 FF 21    STA   $21FF              ; Reset number of ships for player-1
0B5A: CD 7F 1A    CALL  RemoveShip         ; Remove a ship from stash and update indicators
;
0B5D: CD E4 01    CALL  CopyRAMMirror      ; Block copy ROM mirror to initialize RAM
0B60: CD C0 01    CALL  InitAliens         ; Initialize all player 1 aliens
0B63: CD EF 01    CALL  DrawShieldPl1      ; Draw shields for player 1 (to buffer)
0B66: CD 1A 02    CALL  RestoreShields1    ; Restore shields for player 1 (to screen)
0B69: 3E 01       MVI   A,$01              ; ISR splash-task ...
0B6B: 32 C1 20    STA   #isrSplashTask      ; ... playing demo
0B6E: CD CF 01    CALL  DrawBottomLine     ; Draw playfield line
;
0B71: CD 18 16    CALL  PlrFireOrDemo      ; In demo ... process demo movement and always fire
0B74: CD F1 0B    CALL  $0BF1              ; Check player shot and aliens bumping edges of screen and hidden message
0B77: D3 06       OUT   $06                ; Feed watchdog
0B79: CD 59 0A    CALL  $0A59              ; Has demo player been hit?
0B7C: CA 71 0B    JZ    $0B71              ; No ... continue game
0B7F: AF          XRA   A                  ; Remove player shot ...
0B80: 32 25 20    STA   #plyrShotStatus     ; ... from activity
0B83: CD 59 0A    CALL  $0A59              ; Wait for demo player ...
0B86: C2 83 0B    JNZ   $0B83              ; ... to stop exploding
;
; Credit information
0B89: AF          XRA   A                  ; Turn off ...
0B8A: 32 C1 20    STA   #isrSplashTask      ; ... splash animation
0B8D: CD B1 0A    CALL  OneSecDelay        ; One second delay
0B90: CD 88 19    CALL  $1988              ; %%Something else at one time? Jump straight to clear-play-field
0B93: 0E 0C       MVI   C,$0C              ; Message size
0B95: 21 11 2C    LXI   H,$2C11            ; Screen coordinates
0B98: 11 90 1F    LXI   D,$1F90            ; "INSERT  COIN"
0B9B: CD F3 08    CALL  PrintMessage       ; Print message
0B9E: 3A EC 20    LDA   #splashAnimate      ; Do splash ...
0BA1: FE 00       CPI   $00                ; ... animations?
0BA3: C2 AE 0B    JNZ   $0BAE              ; Not 0 ... not on this screen
0BA6: 21 11 33    LXI   H,$3311            ; Screen coordinates
0BA9: 3E 02       MVI   A,$02              ; Character "C"
0BAB: CD FF 08    CALL  DrawChar           ; Put an extra "C" for "CCOIN" on the screen
0BAE: 01 9C 1F    LXI   B,$1F9C            ; "<1 OR 2 PLAYERS>  "
0BB1: CD 56 18    CALL  ReadPriStruct      ; Load the screen,pointer
0BB4: CD 4C 18    CALL  $184C              ; Print the message
0BB7: DB 02       IN    $02                ; Display coin info (bit 7) ...
0BB9: 07          RLC                      ; ... on demo screen?
0BBA: DA C3 0B    JC    $0BC3              ; 1 means no ... skip it
0BBD: 01 A0 1F    LXI   B,$1FA0            ; "*1 PLAYER  1 COIN "
0BC0: CD 3A 18    CALL  $183A              ; Load the descriptor
0BC3: CD B6 0A    CALL  TwoSecDelay        ; Print TWO descriptors worth
0BC6: 3A EC 20    LDA   #splashAnimate      ; Doing splash ...
0BC9: FE 00       CPI   $00                ; ... animation?
0BCB: C2 DA 0B    JNZ   $0BDA              ; Not 0 ... not on this screen
0BCE: 11 D5 1F    LXI   D,$1FD5            ; Animation for small alien to line up with extra "C"
0BD1: CD E2 0A    CALL  IniSplashAni       ; Copy the animation block
0BD4: CD 80 0A    CALL  Animate            ; Wait for the animation to complete
0BD7: CD 9E 18    CALL  $189E              ; Animate alien shot to extra "C"
0BDA: 21 EC 20    LXI   H,$20EC            ; Toggle ...
0BDD: 7E          MOV   A,M                ; ... the ...
0BDE: 3C          INR   A                  ; ... splash screen ...
0BDF: E6 01       ANI   $01                ; ... animation for ...
0BE1: 77          MOV   M,A                ; ... next time
0BE2: CD D6 09    CALL  ClearPlayField     ; Clear play field
0BE5: C3 DF 18    JMP   $18DF              ; Keep splashing

0BE8: 11 AB 1D    LXI   D,$1DAB            ;"PLAY" with normal 'Y'
0BEB: CD 93 0A    CALL  PrintMessageDel    ; Print it
0BEE: C3 0B 0B    JMP   $0B0B              ; Continue with splash (HL will be pointing to next message)

0BF1: CD 0A 19    CALL  PlyrShotAndBump    ; Check if player is shot and aliens bumping the edge of screen
0BF4: C3 9A 19    JMP   CheckHiddenMes     ; Check for hidden-message display sequence

; MessageCorp
; "TAITO COP"
0BF7: 13 00 08 13 0E 26 02 0E 0F

; %% Why all the space?
0C00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0C20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0C40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0C60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0C80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0CA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0CC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0CE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0D00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0D20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0D40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0D60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0D80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0DA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0DC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0DE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0E00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0E20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0E40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0E60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0E80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0EA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0EC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0EE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0F00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0FA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0FC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

1000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

1300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
13A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
13C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
13E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

; DrawShiftedSprite
; The only differences between this and EraseSimpleSprite is two CPL instructions in the latter and
; the use of AND instead of OR. NOP takes the same amount of time/space as CPL. So the two NOPs
; here make these two parallel routines the same size and speed.
;
1400: 00          NOP                      ; Time/size pad to match CPL in EraseShiftedSprite
1401: CD 74 14    CALL  CnvtPixNumber      ; Convert pixel number to coord and shift
1404: 00          NOP                      ; Time/size pad to match CPL in EraseShiftedSprite
1405: C5          PUSH  B                  ; Hold count
1406: E5          PUSH  H                  ; Hold start coordinate
1407: 1A          LDAX  D                  ; Get the picture bits
1408: D3 04       OUT   $04                ; Store in shift register
140A: DB 03       IN    $03                ; Read the shifted pixels
140C: B6          ORA   M                  ; OR them onto the screen
140D: 77          MOV   M,A                ; Store them back to screen
140E: 23          INX   H                  ; Next colummn on screen
140F: 13          INX   D                  ; Next in picture
1410: AF          XRA   A                  ; Shift over ...
1411: D3 04       OUT   $04                ; ... to next byte in register (shift in 0)
1413: DB 03       IN    $03                ; Read the shifted pixels
1415: B6          ORA   M                  ; OR them onto the screen
1416: 77          MOV   M,A                ; Store them back to screen
1417: E1          POP   H                  ; Restore starting coordinate
1418: 01 20 00    LXI   B,$0020            ; Add 32 ...
141B: 09          DAD   B                  ; ... to coordinate (move to next row)
141C: C1          POP   B                  ; Restore count
141D: 05          DCR   B                  ; All done?
141E: C2 05 14    JNZ   $1405              ; No ... go do all rows
1421: C9          RET                      ; Done

1422: 00 00 ; %% Why?

; EraseSimpleSprite
; Clear a sprite from the screen (standard pixel number descriptor).
; %% We clear 2 bytes even though the draw-simple only draws one.
1424: CD 74 14    CALL  CnvtPixNumber      ; Convert pixel number in HL
1427: C5          PUSH  B                  ; Hold
1428: E5          PUSH  H                  ; Hold
1429: AF          XRA   A                  ; 0
142A: 77          MOV   M,A                ; Clear screen byte
142B: 23          INX   H                  ; Next byte
142C: 77          MOV   M,A                ; Clear byte
142D: 23          INX   H                  ; %% Is this to mimic timing? We increment then pop
142E: E1          POP   H                  ; Restore screen coordinate
142F: 01 20 00    LXI   B,$0020            ; Add 1 row ...
1432: 09          DAD   B                  ; ... to screen coordinate
1433: C1          POP   B                  ; Restore counter
1434: 05          DCR   B                  ; All rows done?
1435: C2 27 14    JNZ   $1427              ; Do all rows
1438: C9          RET                      ; out

; DrawSimpSprite
; Display character to screen
; HL = screen coordinates
; DE = character data
; B = number of rows
1439: C5          PUSH  B                  ; Preserve counter
143A: 1A          LDAX  D                  ; From character set ...
143B: 77          MOV   M,A                ; ... to screen
143C: 13          INX   D                  ; Next in character set
143D: 01 20 00    LXI   B,$0020            ; Next row ...
1440: 09          DAD   B                  ; ... on screen
1441: C1          POP   B                  ; Restore counter
1442: 05          DCR   B                  ; Decrement counter
1443: C2 39 14    JNZ   DrawSimpSprite     ; Do all
1446: C9          RET                      ; Out

1447: 00 00 00 00 00 00 00 00 00 00 00 ; %% Why?
                        
; EraseShifted
; Erases a shifted sprite from screen (like for player's explosion)
1452: CD 74 14    CALL  CnvtPixNumber      ; Convert pixel number in HL to coorinates with shift
1455: C5          PUSH  B                  ; Hold BC
1456: E5          PUSH  H                  ; Hold coordinate
1457: 1A          LDAX  D                  ; Get picture value
1458: D3 04       OUT   $04                ; Value into shift register
145A: DB 03       IN    $03                ; Read shifted sprite picture
145C: 2F          CMA                      ; Reverse it (erasing bits)
145D: A6          ANA   M                  ; Erase the bits from the screen
145E: 77          MOV   M,A                ; Store the erased pattern back
145F: 23          INX   H                  ; Next column on screen
1460: 13          INX   D                  ; Next in image
1461: AF          XRA   A                  ; Shift register over ...
1462: D3 04       OUT   $04                ; ... 8 bits (shift in 0)
1464: DB 03       IN    $03                ; Read 2nd byte of image
1466: 2F          CMA                      ; Reverse it (erasing bits)
1467: A6          ANA   M                  ; Erase the bits from the screen
1468: 77          MOV   M,A                ; Store the erased pattern back
1469: E1          POP   H                  ; Restore starting coordinate
146A: 01 20 00    LXI   B,$0020            ; Add 32 ...
146D: 09          DAD   B                  ; ... to next row
146E: C1          POP   B                  ; Restore BC (count)
146F: 05          DCR   B                  ; All rows done?
1470: C2 55 14    JNZ   $1455              ; No ... erase all
1473: C9          RET                      ; Done

; CnvtPixNumber
; Convert pixel number in HL to screen coordinate and shift amount.
; HL gets screen coordinate.
; Hardware shift-register gets amount.
1474: 7D          MOV   A,L                ; Get X coordinate
1475: E6 07       ANI   $07                ; Shift by pixel position
1477: D3 02       OUT   $02                ; Write shift amount to hardware
1479: C3 47 1A    JMP   ConvToScr          ; HL = HL/8 + 2000 (screen coordinate)

; RememberShields
; In a multi-player game the player's shields are block-copied to and from RAM between turns.
; HL = screen pointer
; DE = memory buffer
; B = number of rows
; C = number of columns
147C: C5          PUSH  B                  ; Hold counter
147D: E5          PUSH  H                  ; Hold start
147E: 7E          MOV   A,M                ; From sprite ... (should be DE)
147F: 12          STAX  D                  ; ... to screen ... (should be HL)
1480: 13          INX   D                  ; Next in sprite
1481: 23          INX   H                  ; Next on screen
1482: 0D          DCR   C                  ; All columns done?
1483: C2 7E 14    JNZ   $147E              ; No ... do multi columns
1486: E1          POP   H                  ; Restore screen start
1487: 01 20 00    LXI   B,$0020            ; Add 32 ...
148A: 09          DAD   B                  ; ... to get to next row
148B: C1          POP   B                  ; Pop the counters
148C: 05          DCR   B                  ; All rows done?
148D: C2 7C 14    JNZ   RememberShields    ; No ... do multi rows
1490: C9          RET                      ; Done

; DrawSprCollision
1491: CD 74 14    CALL  CnvtPixNumber      ; Convert pixel number to coord and shift
1494: AF          XRA   A                  ; Clear the ...
1495: 32 61 20    STA   #collision          ; ... collision-detection flag
1498: C5          PUSH  B                  ; Hold count
1499: E5          PUSH  H                  ; Hold screen
149A: 1A          LDAX  D                  ; Get byte
149B: D3 04       OUT   $04                ; Write first byte to shift register
149D: DB 03       IN    $03                ; Read shifted pattern
149F: F5          PUSH  PSW                ; Hold the pattern
14A0: A6          ANA   M                  ; Any bits from pixel collide with bits on screen?
14A1: CA A9 14    JZ    $14A9              ; No ... leave flag alone
14A4: 3E 01       MVI   A,$01              ; Yes ... set ...
14A6: 32 61 20    STA   #collision          ; ... collision flag
14A9: F1          POP   PSW                ; Restore the pixel pattern
14AA: B6          ORA   M                  ; OR it onto the screen
14AB: 77          MOV   M,A                ; Store new screen value
14AC: 23          INX   H                  ; Next byte on screen
14AD: 13          INX   D                  ; Next in pixel pattern
14AE: AF          XRA   A                  ; Write zero ...
14AF: D3 04       OUT   $04                ; ... to shift register
14B1: DB 03       IN    $03                ; Read 2nd half of shifted sprite
14B3: F5          PUSH  PSW                ; Hold pattern
14B4: A6          ANA   M                  ; Any bits from pixel collide with bits on screen?
14B5: CA BD 14    JZ    $14BD              ; No ... leave flag alone
14B8: 3E 01       MVI   A,$01              ; Yes ... set ...
14BA: 32 61 20    STA   #collision          ; ... collision flag
14BD: F1          POP   PSW                ; Restore the pixel pattern
14BE: B6          ORA   M                  ; OR it onto the screen
14BF: 77          MOV   M,A                ; Store new screen pattern
14C0: E1          POP   H                  ; Starting screen coordinate
14C1: 01 20 00    LXI   B,$0020            ; Add 32 ...
14C4: 09          DAD   B                  ; ... to get to next row
14C5: C1          POP   B                  ; Restore count
14C6: 05          DCR   B                  ; All done?
14C7: C2 98 14    JNZ   $1498              ; No ... do all rows
14CA: C9          RET                      ; Done

; ClearSmallSprite
; Clear a one byte sprite at HL. B=number of rows.
14CB: AF          XRA   A                  ; 0
14CC: C5          PUSH  B                  ; Preserve BC
14CD: 77          MOV   M,A                ; Clear screen byte
14CE: 01 20 00    LXI   B,$0020            ; Bump HL ...
14D1: 09          DAD   B                  ; ... one screen row
14D2: C1          POP   B                  ; Restore
14D3: 05          DCR   B                  ; All done?
14D4: C2 CC 14    JNZ   $14CC              ; No ... clear all
14D7: C9          RET                      

; PlayerShotHit
; The player's shot hit something (or is being removed from play) 
;
14D8: 3A 25 20    LDA   #plyrShotStatus     ; Player shot flag
14DB: FE 05       CPI   $05                ; Alien explosion in progress?
14DD: C8          RZ                       ; Yes ... ignore this function
14DE: FE 02       CPI   $02                ; Normal movement?
14E0: C0          RNZ                      ; No ... out
;
14E1: 3A 29 20    LDA   #obj1CoorYr         ; Get Yr coordinate of player shot
14E4: FE D8       CPI   $D8                ; Compare to 216 (40 from Top-rotated)
14E6: 47          MOV   B,A                ; Hold value for later
14E7: D2 30 15    JNC   $1530              ; Yr is within 40 from top initiate miss-explosion (shot flag 3)
14EA: 3A 02 20    LDA   #alienIsExploding   ; Is an alien ...
14ED: A7          ANA   A                  ; ... blowing up?
14EE: C8          RZ                       ; No ... out
;
14EF: 78          MOV   A,B                ; Get original Yr coordinate back to A
14F0: FE CE       CPI   $CE                ; Compare to 206 (50 from rotated top)
14F2: D2 79 15    JNC   $1579              ; Yr is within 50 from top? Yes ... saucer must be hit
14F5: C6 06       ADI   $06                ; Offset to coordinate for wider "explosion" picture
14F7: 47          MOV   B,A                ; Hold that
14F8: 3A 09 20    LDA   #refAlienYr         ; Ref alien Y coordianate

; If the lower 4 rows are all empty then the reference alien's Y coordinate will wrap around from 0 to F8.
; At this point the top row of aliens is in the shields and we will assume that everything is within
; the rack.

14FB: FE 90       CPI   $90                ; This is true if ...
14FD: D2 04 15    JNC   $1504              ; ... aliens are down in the shields
1500: B8          CMP   B                  ; Compare to shot's coordinate
1501: D2 30 15    JNC   $1530              ; Outside the rack-square ... do miss explosion

; CodeBug1
;
; We get here if the player's shot hit something within the rack area (a shot or an alien).
; Find the alien that is (or would be) where the shot hit. If there is no alien alive at the row/column
; thn the player hit an alien missile. If there is an alien then explode the alien.
;
; There is a code bug here, but it is extremely subtle. The algorithm for finding the row/column in the
; rack works by adding 16 to the reference coordinates (X for column, Y for row) until it passes or equals
; the target coordinates. This works great as long as the target point is within the alien's rack area.
; If the reference point is far to the right, the column number will be greater than 11, which messes
; up the column/row-to-pointer math.
;
; The entire rack of aliens is based on the lower left alien. Imagine all aliens are dead except the
; upper left. It wiggles down the screen and enters the players shields on the lower left where it begins
; to eat them. Imagine the player is under his own shields on the right side of the screen and fires a
; shot into his own shield.
;
; The alien is in the rack on row 4 (rows are numbered from bottom up starting with 0). The shot hits
; the shields below the alien's Y coordinate and gets correctly assigned to row 3. The alien is in the rack
; at column 0 (columns are numbered from left to right starting with 0). The shot hits the shields far to
; the right of the alien's X coordinate. The algorithm says it is in column 11. But 0-10 are the only
; correct values.
;
; The column/row-to-pointer math works by multiplying the row by 11 and adding the column. For the alien 
; that is 11*4 + 0 = 44. For the shot that is 11*3 +11 = 44. The game thinks the shot hit the alien.
;
1504: 68          MOV   L,B                ; L now holds the shot coordinate (adjusted)
1505: CD 62 15    CALL  FindRow            ; Look up row number to B
1508: 3A 2A 20    LDA   #obj1CoorXr         ; Player's shot's Xr coordinate ...
150B: 67          MOV   H,A                ; ... to H
150C: CD 6F 15    CALL  FindColumn         ; Get alien's coordinate
150F: 22 64 20    SHLD  #expAlienYr         ; Put it in the exploding-alien descriptor
1512: 3E 05       MVI   A,$05              ; Flag alien explosion ...
1514: 32 25 20    STA   #plyrShotStatus     ; ... in progress
1517: CD 81 15    CALL  GetAlienStatPtr    ; Get descriptor for alien
151A: 7E          MOV   A,M                ; Is alien ...
151B: A7          ANA   A                  ; ... alive
151C: CA 30 15    JZ    $1530              ; No ... must have been an alien shot
;
151F: 36 00       MVI   M,$00              ; Make alien invader dead
1521: CD 5F 0A    CALL  ScoreForAlien      ; Makes alien explosion sound and adjust score
1524: CD 3B 1A    CALL  ReadDesc           ; Load 5 byte sprite descriptor
1527: CD D3 15    CALL  DrawSprite         ; Draw explosion sprite on screen
152A: 3E 10       MVI   A,$10              ; Initiate alien-explosion
152C: 32 03 20    STA   #expAlienTimer      ; ... timer to 16
152F: C9          RET                      ; Out
;
; Player shot leaving playfield, hitting shield, or hitting an alien shot
1530: 3E 03       MVI   A,$03              ; Mark ...
1532: 32 25 20    STA   #plyrShotStatus     ; ... player shot hit something other than alien
1535: C3 4A 15    JMP   $154A              ; Finish up
;
; AExplodeTime
; Time down the alien explosion. Remove when done.
1538: 21 03 20    LXI   H,$2003            ; Decrement alien explosion ...
153B: 35          DCR   M                  ; ... timer
153C: C0          RNZ                      ; Not done  ... out
153D: 2A 64 20    LHLD  #expAlienYr         ; Pixel pointer for exploding alien
1540: 06 10       MVI   B,$10              ; 16 row pixel
1542: CD 24 14    CALL  EraseSimpleSprite  ; Clear the explosion sprite from the screen
1545: 3E 04       MVI   A,$04              ; 4 means that ...
1547: 32 25 20    STA   #plyrShotStatus     ; ... alien has exploded (remove from active duty)
;
154A: AF          XRA   A                  ; Turn off ...
154B: 32 02 20    STA   #alienIsExploding   ; ... alien-is-blowing-up flag
154E: 06 F7       MVI   B,$F7              ; Turn off ...
1550: C3 DC 19    JMP   SoundBits3Off      ; ... alien exploding sound

1553: 00                          
    
; Cnt16s
; Count number of 16s needed to bring reference (in A) up to target (in H).
; If the reference starts out beyond the target then we add 16s as long as
; the reference has a signed bit. But these aren't signed quantities. This
; doesn't make any sense. This counting algorithm produces questionable 
; results if the reference is beyond the target.
;
1554: 0E 00       MVI   C,$00              ; Count of 16s
1556: BC          CMP   H                  ; Compare reference coordinate to target
1557: D4 90 15    CNC   WrapRef            ; If reference is greater or equal then do something questionable ... see below
155A: BC          CMP   H                  ; Compare reference coordinate to target
155B: D0          RNC                      ; If reference is greater or equal then done
155C: C6 10       ADI   $10                ; Add 16 to reference
155E: 0C          INR   C                  ; Bump 16s count
155F: C3 5A 15    JMP   $155A              ; Keep testing

; FindRow
; L contains a Yr coordinate. Find the row number within the rack that corresponds
; to the Yr coordinate. Return the row coordinate in L and the row number in C.
;
1562: 3A 09 20    LDA   #refAlienYr         ; Reference alien Yr coordinate
1565: 65          MOV   H,L                ; Target Yr coordinate to H
1566: CD 54 15    CALL  Cnt16s             ; Count 16s needed to bring ref alien to target
1569: 41          MOV   B,C                ; Count to B
156A: 05          DCR   B                  ; Base 0
156B: DE 10       SBI   $10                ; The counting also adds 16 no matter what
156D: 6F          MOV   L,A                ; To coordinate
156E: C9          RET                      ; Done

; FindColumn
; H contains a Xr coordinate. Find the column number within the rack that corresponds
; to the Xr coordinate. Return the column coordinate in H and the column number in C.
;
156F: 3A 0A 20    LDA   #refAlienXr         ; Reference alien Yn coordinate
1572: CD 54 15    CALL  Cnt16s             ; Count 16s to bring Y to target Y
1575: DE 10       SBI   $10                ; Subtract off extra 16
1577: 67          MOV   H,A                ; To H
1578: C9          RET                      ; Done

1579: 3E 01       MVI   A,$01              ; Mark flying ...
157B: 32 85 20    STA   #saucerHit          ; ... saucer has been hit
157E: C3 45 15    JMP   $1545              ; Remove player shot

; GetAlienStatPtr
; B is row number. C is column number (starts at 1). 
; Return pointer to alien-status flag for current player.
1581: 78          MOV   A,B                ; Hold original
1582: 07          RLC                      ; *2
1583: 07          RLC                      ; *4
1584: 07          RLC                      ; *8
1585: 80          ADD   B                  ; *9
1586: 80          ADD   B                  ; *10
1587: 80          ADD   B                  ; *11
1588: 81          ADD   C                  ; Add row offset to column offset
1589: 3D          DCR   A                  ; -1
158A: 6F          MOV   L,A                ; Set LSB of HL
158B: 3A 67 20    LDA   #playerDataMSB      ; Set ...
158E: 67          MOV   H,A                ; ... MSB of HL with active player indicator
158F: C9          RET                      

; WrapRef
; This is called if the reference point is greater than the target point. I believe the goal is to
; wrap the reference back around until it is lower than the target point. But the algorithm simply adds
; until the sign bit of the the reference is 0. If the target is 2 and the reference is 238 then this
; algorithm moves the reference 238+16=244 then 244+16=4. Then the algorithm stops. But the reference is
; STILL greater than the target.
;
; Also imagine that the target is 20 and the reference is 40. The algorithm adds 40+16=56, which is not
; negative, so it stops there.
;
; I think the intended code is "JP NC" instead of "JP M", but even that doesn't make sense.
; 
1590: 0C          INR   C                  ; Increase 16s count
1591: C6 10       ADI   $10                ; Add 16 to ref
1593: FA 90 15    JM    WrapRef            ; Keep going till result is positive
1596: C9          RET                      ; Out

; RackBump
; When rack bumps the edge of the screen then the direction flips and the rack
; drops 8 pixels. The deltaX and deltaY values are changed here. Interestingly
; if there is only one alien left then the right value is 3 instead of the 
; usual 2. The left direction is always -2.
1597: 3A 0D 20    LDA   #rackDirection      ; Get rack direction
159A: A7          ANA   A                  ; Moving right?
159B: C2 B7 15    JNZ   $15B7              ; No ... handle moving left
;
159E: 21 A4 3E    LXI   H,$3EA4            ; Line down the right edge of playfield
15A1: CD C5 15    CALL  $15C5              ; Check line down the edge
15A4: D0          RNC                      ; Nothing is there ... return
15A5: 06 FE       MVI   B,$FE              ; Delta X of -2
15A7: 3E 01       MVI   A,$01              ; Rack now moving right
;
15A9: 32 0D 20    STA   #rackDirection      ; Set new rack direction
15AC: 78          MOV   A,B                ; B has delta X
15AD: 32 08 20    STA   #refAlienDXr        ; Set new delta X
15B0: 3A 0E 20    LDA   #rackDownDelta      ; Set delta Y ...
15B3: 32 07 20    STA   #refAlienDYr        ; ... to drop rack by 8
15B6: C9          RET                      ; Done
;
15B7: 21 24 25    LXI   H,$2524            ; Line down the left edge of playfield
15BA: CD C5 15    CALL  $15C5              ; Check line down the edge
15BD: D0          RNC                      ; Nothing is there ... return
15BE: CD F1 18    CALL  $18F1              ; Get moving-right delta X value of 2 (3 if just one alien left)
15C1: AF          XRA   A                  ; Rack now moving left
15C2: C3 A9 15    JMP   $15A9              ; Set rack direction
;
15C5: 06 17       MVI   B,$17              ; Checking 23 bytes down the screen in a line
15C7: 7E          MOV   A,M                ; Get screen memory
15C8: A7          ANA   A                  ; Is screen memory empty?
15C9: C2 6B 16    JNZ   $166B              ; No ... set carry flag and out
15CC: 23          INX   H                  ; Next byte on screen
15CD: 05          DCR   B                  ; All column done?
15CE: C2 C7 15    JNZ   $15C7              ; No ... keep looking
15D1: C9          RET                      ; Return with carry flag clear

15D2: 00          NOP                      ; %% Why? Something optimized?
    
; DrawSprite
; Draw sprite at [DE] to screen at pixel position in HL
; The hardware shift register is used in converting pixel positions
; to screen coordinates.
15D3: CD 74 14    CALL  CnvtPixNumber      ; Convert pixel number to screen/shift
15D6: E5          PUSH  H                  ; Preserve screen coordinate
15D7: C5          PUSH  B                  ; Hold for a second
15D8: E5          PUSH  H                  ; Hold for a second
15D9: 1A          LDAX  D                  ; From sprite data
15DA: D3 04       OUT   $04                ; Write data to shift register
15DC: DB 03       IN    $03                ; Read back shifted amount
15DE: 77          MOV   M,A                ; Shifted sprite to screen
15DF: 23          INX   H                  ; Adjacent cell
15E0: 13          INX   D                  ; Next in sprite data
15E1: AF          XRA   A                  ; 0
15E2: D3 04       OUT   $04                ; Write 0 to shift register
15E4: DB 03       IN    $03                ; Read back remainder of previous
15E6: 77          MOV   M,A                ; Write remainder to adjacent
15E7: E1          POP   H                  ; Old screen coordinate
15E8: 01 20 00    LXI   B,$0020            ; Offset screen ...
15EB: 09          DAD   B                  ; ... to next row
15EC: C1          POP   B                  ; Restore count
15ED: 05          DCR   B                  ; All done?
15EE: C2 D7 15    JNZ   $15D7              ; No ... do all
15F1: E1          POP   H                  ; Restore HL
15F2: C9          RET                      ; Done

; CountAliens
; Count number of aliens remaining in active game and return count 2082 holds the current count.
; If only 1, 206B gets a flag of 1 %% but ever nobody checks this
15F3: CD 11 16    CALL  GetPlayerDataPtr   ; Get active player descriptor
15F6: 01 00 37    LXI   B,$3700            ; B=55 aliens to check?
15F9: 7E          MOV   A,M                ; Get byte
15FA: A7          ANA   A                  ; Is it a zero?
15FB: CA FF 15    JZ    $15FF              ; Yes ... don't count it
15FE: 0C          INR   C                  ; Count the live aliens
15FF: 23          INX   H                  ; Next alien
1600: 05          DCR   B                  ; Count ...
1601: C2 F9 15    JNZ   $15F9              ; ... all alien indicators
1604: 79          MOV   A,C                ; Get the count
1605: 32 82 20    STA   #numAliens          ; Hold it
1608: FE 01       CPI   $01                ; Just one?
160A: C0          RNZ                      ; No keep going
160B: 21 6B 20    LXI   H,$206B            ; Set flag if ...
160E: 36 01       MVI   M,$01              ; ... only one alien left
1610: C9          RET                      ; Out

; GetPlayerDataPtr
; Set HL with 2100 if player 1 is active or 2200 if player 2 is active
;
1611: 2E 00       MVI   L,$00              ; Byte boundary
1613: 3A 67 20    LDA   #playerDataMSB      ; Active player number
1616: 67          MOV   H,A                ; Set HL to data
1617: C9          RET                      ; Done

; PlrFireOrDemo
; Initiate player fire if button is pressed.
; Demo commands are parsed here if in demo mode
1618: 3A 15 20    LDA   #playerAlive        ; Is there an active player?
161B: FE FF       CPI   $FF                ; FF = alive
161D: C0          RNZ                      ; Player has been shot - no firing
161E: 21 10 20    LXI   H,$2010            ; Get player ...
1621: 7E          MOV   A,M                ; ... task ...
1622: 23          INX   H                  ; ... timer ...
1623: 46          MOV   B,M                ; ... value
1624: B0          ORA   B                  ; Is the timer 0 (object active)?
1625: C0          RNZ                      ; No ... no firing till player object starts
1626: 3A 25 20    LDA   #plyrShotStatus     ; Does the player have ...
1629: A7          ANA   A                  ; ... a shot on the screen?
162A: C0          RNZ                      ; Yes ... ignore
162B: 3A EF 20    LDA   #gameMode           ; Are we in ...
162E: A7          ANA   A                  ; ... game mode?
162F: CA 52 16    JZ    $1652              ; No ... in demo mode ... constant firing in demo
1632: 3A 2D 20    LDA   #fireBounce         ; Is fire button ...
1635: A7          ANA   A                  ; ... being held down?
1636: C2 48 16    JNZ   $1648              ; Yes ... wait for bounce
1639: CD C0 17    CALL  ReadInputs         ; Read active player controls
163C: E6 10       ANI   $10                ; Fire-button pressed?
163E: C8          RZ                       ; No ... out
163F: 3E 01       MVI   A,$01              ; Flag
1641: 32 25 20    STA   #plyrShotStatus     ; Flag shot active
1644: 32 2D 20    STA   #fireBounce         ; Flag that fire button is down
1647: C9          RET                      ; Out
1648: CD C0 17    CALL  ReadInputs         ; Read active player controls
164B: E6 10       ANI   $10                ; Fire-button pressed?
164D: C0          RNZ                      ; Yes ... ignore
164E: 32 2D 20    STA   #fireBounce         ; Else ... clear flag
1651: C9          RET                      ; Out
; Handle demo (constant fire, parse demo commands)
1652: 21 25 20    LXI   H,$2025            ; Demo fires ...
1655: 36 01       MVI   M,$01              ; ... constantly
1657: 2A ED 20    LHLD  #demoCmdPtrLSB      ; Demo command bufer
165A: 23          INX   H                  ; Next position
165B: 7D          MOV   A,L                ; Command buffer ...
165C: FE 7E       CPI   $7E                ; ... wraps around
165E: DA 63 16    JC    $1663              ; ... Buffer from 1F74 to 1F7E
1661: 2E 74       MVI   L,$74              ; ... overflow
1663: 22 ED 20    SHLD  #demoCmdPtrLSB      ; Next demo command
1666: 7E          MOV   A,M                ; Get next command
1667: 32 1D 20    STA   #nextDemoCmd        ; Set command for movement
166A: C9          RET                      ; Done

166B: 37          STC                      ; Set carry flag
166C: C9          RET                      ; Done

166D: AF          XRA   A                  ; 0
166E: CD 8B 1A    CALL  $1A8B              ; Print ZERO ships remain
1671: CD 10 19    CALL  CurPlyAlive        ; Get active-flag ptr for current player
1674: 36 00       MVI   M,$00              ; Flag player is dead
1676: CD CA 09    CALL  $09CA              ; Get score descriptor for current player
1679: 23          INX   H                  ; Point to high two digits
167A: 11 F5 20    LXI   D,$20F5            ; Current high score upper two digits
167D: 1A          LDAX  D                  ; Is player score greater ...
167E: BE          CMP   M                  ; ... than high score?
167F: 1B          DCX   D                  ; Point to LSB
1680: 2B          DCX   H                  ; Point to LSB
1681: 1A          LDAX  D                  ; Go ahead and fetch high score lower two digits
1682: CA 8B 16    JZ    $168B              ; Upper two are the same ... have to check lower two
1685: D2 98 16    JNC   $1698              ; Player score is lower than high ... nothing to do
1688: C3 8F 16    JMP   $168F              ; Player socre is higher ... go copy the new high score
;
168B: BE          CMP   M                  ; Is lower digit higher? (upper was the same)
168C: D2 98 16    JNC   $1698              ; No ... high score is still greater than player's score
168F: 7E          MOV   A,M                ; Copy the new ...
1690: 12          STAX  D                  ; ... high score lower two digits
1691: 13          INX   D                  ; Point to MSB
1692: 23          INX   H                  ; Point to MSB
1693: 7E          MOV   A,M                ; Copy the new ...
1694: 12          STAX  D                  ; ... high score upper two digits
1695: CD 50 19    CALL  PrintHiScore       ; Draw the new high score
1698: 3A CE 20    LDA   #twoPlayers         ; Number of players
169B: A7          ANA   A                  ; Is this a single player game?
169C: CA C9 16    JZ    $16C9              ; Yes ... short message
169F: 21 03 28    LXI   H,$2803            ; Screen coordinates
16A2: 11 A6 1A    LXI   D,$1AA6            ; "GAME OVER PLAYER< >"
16A5: 0E 14       MVI   C,$14              ; 20 characters
16A7: CD 93 0A    CALL  PrintMessageDel    ; Print message
16AA: 25          DCR   H                  ; Back up ...
16AB: 25          DCR   H                  ; ... to player indicator
16AC: 06 1B       MVI   B,$1B              ; "1"
16AE: 3A 67 20    LDA   #playerDataMSB      ; Player number
16B1: 0F          RRC                      ; Is this player 1?
16B2: DA B7 16    JC    $16B7              ; Yes ... keep the digit
16B5: 06 1C       MVI   B,$1C              ; Else ... set digit 2
16B7: 78          MOV   A,B                ; To A
16B8: CD FF 08    CALL  DrawChar           ; Print player number
16BB: CD B1 0A    CALL  OneSecDelay        ; Short delay
16BE: CD E7 18    CALL  $18E7              ; Get current player "alive" flag
16C1: 7E          MOV   A,M                ; Is player ...
16C2: A7          ANA   A                  ; ... alive?
16C3: CA C9 16    JZ    $16C9              ; No ... skip to "GAME OVER" sequence
16C6: C3 ED 02    JMP   $02ED              ; Switch players and game loop
;
16C9: 21 18 2D    LXI   H,$2D18            ; Screen coordinates
16CC: 11 A6 1A    LXI   D,$1AA6            ; "GAME OVER PLAYER< >"
16CF: 0E 0A       MVI   C,$0A              ; Just the "GAME OVER" part
16D1: CD 93 0A    CALL  PrintMessageDel    ; Print message
16D4: CD B6 0A    CALL  TwoSecDelay        ; Long delay
16D7: CD D6 09    CALL  ClearPlayField     ; Clear center window
16DA: AF          XRA   A                  ; Now in ...
16DB: 32 EF 20    STA   #gameMode           ; ... demo mode
16DE: D3 05       OUT   $05                ; All sound off
16E0: CD D1 19    CALL  EnableGameTasks    ; Enable ISR game tasks
16E3: C3 89 0B    JMP   $0B89              ; Print credit information and do splash

16E6: 31 00 24    LXI   SP,$2400           ; Reset stack
16E9: FB          EI                       ; Enable interrupts
16EA: AF          XRA   A                  ; Flag ...
16EB: 32 15 20    STA   #playerAlive        ; ... player is shot
16EE: CD D8 14    CALL  PlayerShotHit      ; Player's shot collision detection
16F1: 06 04       MVI   B,$04              ; Player has been hit ...
16F3: CD FA 18    CALL  SoundBits3On       ; ... sound
16F6: CD 59 0A    CALL  $0A59              ; Has flag been set?
16F9: C2 EE 16    JNZ   $16EE              ; No ... wait for the flag
16FC: CD D7 19    CALL  DsableGameTasks    ; Disable ISR game tasks
16FF: 21 01 27    LXI   H,$2701            ; Player's stash of ships
1702: CD FA 19    CALL  $19FA              ; Erase the stash of shps
1705: AF          XRA   A                  ; Print ...
1706: CD 8B 1A    CALL  $1A8B              ; ... a zero (number of ships)

1709: 06 FB       MVI   B,$FB              ; Turn off ...
170B: C3 6B 19    JMP   $196B              ; ... player shot sound

; AShotReloadRate
; Use the player's MSB to determine how fast the aliens reload their
; shots for another fire.
170E: CD CA 09    CALL  $09CA              ; Get score descriptor for active player
1711: 23          INX   H                  ; MSB value
1712: 7E          MOV   A,M                ; Get the MSB value
1713: 11 B8 1C    LXI   D,$1CB8            ; Score MSB table
1716: 21 A1 1A    LXI   H,$1AA1            ; Corresponding fire reload rate table
1719: 0E 04       MVI   C,$04              ; Only 4 entries (a 5th value of 7 is used after that)
171B: 47          MOV   B,A                ; Hold the score value
171C: 1A          LDAX  D                  ; Get lookup from table
171D: B8          CMP   B                  ; Compare them
171E: D2 27 17    JNC   $1727              ; Equal or below ... use this table entry
1721: 23          INX   H                  ; Next ...
1722: 13          INX   D                  ; ... entry in table
1723: 0D          DCR   C                  ; Do all ...
1724: C2 1C 17    JNZ   $171C              ; ... 4 entries in the tables
1727: 7E          MOV   A,M                ; Load the shot reload value
1728: 32 CF 20    STA   #aShotReloadRate    ; Save the value for use in shot routine
172B: C9          RET                      ; Done

; Shot sound on or off depending on 2025
; ShotSound
172C: 3A 25 20    LDA   #plyrShotStatus     ; Player shot flag
172F: FE 00       CPI   $00                ; Active shot?
1731: C2 39 17    JNZ   $1739              ; Yes ... go
1734: 06 FD       MVI   B,$FD              ; Sound mask
1736: C3 DC 19    JMP   SoundBits3Off      ; Mask off sound
;
1739: 06 02       MVI   B,$02              ; Sound bit
173B: C3 FA 18    JMP   SoundBits3On       ; OR on sound

173E: 00 00 ; %% Why?                       

; TimeFleetSound
; This called from the ISR times down the fleet and sets the flag at 2095 if 
; the fleet needs a change in sound handling (new delay, new sound)
1740: 21 9B 20    LXI   H,$209B            ; Pointer to hold time for fleet
1743: 35          DCR   M                  ; Decrement hold time
1744: CC 6D 17    CZ    $176D              ; If 0 turn fleet movement sound off
1747: 3A 68 20    LDA   #playerOK           ; Is player OK?
174A: A7          ANA   A                  ; 1  means OK
174B: CA 6D 17    JZ    $176D              ; Player not OK ... fleet movement sound off and out
174E: 21 96 20    LXI   H,$2096            ; Current time on fleet sound
1751: 35          DCR   M                  ; Count down
1752: C0          RNZ                      ; Not time to change sound ... out
1753: 21 98 20    LXI   H,$2098            ; Current sound port 3 value
1756: 7E          MOV   A,M                ; Get value
1757: D3 05       OUT   $05                ; Set sounds
1759: 3A 82 20    LDA   #numAliens          ; Number of aliens on active screen
175C: A7          ANA   A                  ; Is it zero?
175D: CA 6D 17    JZ    $176D              ; Yes ... turn off fleet movement sound and out
1760: 2B          DCX   H                  ; (2097) Point to fleet timer reload
1761: 7E          MOV   A,M                ; Get fleet delay value
1762: 2B          DCX   H                  ; (2096) Point to fleet timer
1763: 77          MOV   M,A                ; Reload the timer
1764: 2B          DCX   H                  ; Point to change-sound
1765: 36 01       MVI   M,$01              ; (2095) time to change sound
1767: 3E 04       MVI   A,$04              ; Set hold ...
1769: 32 9B 20    STA   #fleetSndHold       ; ... time for fleet sound
176C: C9          RET                      ; Done

176D: 3A 98 20    LDA   #soundPort5         ; Current sound port 3 value
1770: E6 30       ANI   $30                ; Mask off fleet movement sounds
1772: D3 05       OUT   $05                ; Set sounds
1774: C9          RET                      ; Out

; FleetDelayExShip
; This game-loop routine handles two sound functions. The routine does:
; 1) Time out the extra-ship awarded sound and turn it off when done
; 2) Load the fleet sound delay based on number of remaining aliens
; 3) Make the changing fleet sound
;
; The 2095 flag is set by the ISR and cleared here. The ISR does the timing and sets 2095 when it
; is time to make a new fleet sound.
;
1775: 3A 95 20    LDA   #changeFleetSnd     ; Time for new ...
1778: A7          ANA   A                  ; ... fleet movement sound?
1779: CA AA 17    JZ    $17AA              ; No ... skip to extra-man timing
177C: 21 11 1A    LXI   H,$1A11            ; Number of aliens list coupled ...
177F: 11 21 1A    LXI   D,$1A21            ; ... with delay list
1782: 3A 82 20    LDA   #numAliens          ; Get the number of aliens on the screen
1785: BE          CMP   M                  ; Compare it to the first list value
1786: D2 8E 17    JNC   $178E              ; Number of live aliens is higher than value ... use the delay
1789: 23          INX   H                  ; Move to ...
178A: 13          INX   D                  ; ... next list value
178B: C3 85 17    JMP   $1785              ; Find the right delay
178E: 1A          LDAX  D                  ; Get the delay from the second list
178F: 32 97 20    STA   #fleetSndReload     ; Store the new alien sound delay
1792: 21 98 20    LXI   H,$2098            ; Get current state ...
1795: 7E          MOV   A,M                ; ... of sound port
1796: E6 30       ANI   $30                ; Mask off all fleet movement sounds
1798: 47          MOV   B,A                ; Hold the value
1799: 7E          MOV   A,M                ; Get current state
179A: E6 0F       ANI   $0F                ; This time ONLY the fleet movement sounds
179C: 07          RLC                      ; Shift next to next sound
179D: FE 10       CPI   $10                ; Overflow?
179F: C2 A4 17    JNZ   $17A4              ; No ... keep it
17A2: 3E 01       MVI   A,$01              ; Reset back to first sound
17A4: B0          ORA   B                  ; Add fleet sounds to current sound value
17A5: 77          MOV   M,A                ; Store new sound value
17A6: AF          XRA   A                  ; Restart ...
17A7: 32 95 20    STA   #changeFleetSnd     ; ... waiting on fleet time
;
17AA: 21 99 20    LXI   H,$2099            ; Sound timer for award extra ship
17AD: 35          DCR   M                  ; Time expired?
17AE: C0          RNZ                      ; No ... leave sound playing
17AF: 06 EF       MVI   B,$EF              ; Turn off bit set with #$10 (award extra ship)
17B1: C3 DC 19    JMP   SoundBits3Off      ; Stop sound and out

; SndOffExtPly
17B4: 06 EF       MVI   B,$EF              ; Mask off sound bit 4 (Extended play)
17B6: 21 98 20    LXI   H,$2098            ; Current sound content
17B9: 7E          MOV   A,M                ; Get current sound bits
17BA: A0          ANA   B                  ; Turn off extended play
17BB: 77          MOV   M,A                ; Remember settings
17BC: D3 05       OUT   $05                ; Turn off extended play
17BE: C9          RET                      ; Out

17BF: 00 ; %% Why?

; ReadInputs
; Read control inputs for active player
17C0: 3A 67 20    LDA   #playerDataMSB      ; Get active player
17C3: 0F          RRC                      ; Test player
17C4: D2 CA 17    JNC   $17CA              ; Player 2 ... read port 2
17C7: DB 01       IN    $01                ; Player 1 ... read port 1
17C9: C9          RET                      ; Out
17CA: DB 02       IN    $02                ; Get controls for player 2
17CC: C9          RET                      ; Out

; Check and handle TILT
; CheckHandleTilt
17CD: DB 02       IN    $02                ; Read input port
17CF: E6 04       ANI   $04                ; Tilt?
17D1: C8          RZ                       ; No tilt ... return
17D2: 3A 9A 20    LDA   #tilt               ; Already in TILT handle?
17D5: A7          ANA   A                  ; 1 = yes
17D6: C0          RNZ                      ; Yes ... ignore it now
17D7: 31 00 24    LXI   SP,$2400           ; Reset stack
17DA: 06 04       MVI   B,$04              ; Do this 4 times
17DC: CD D6 09    CALL  ClearPlayField     ; Clear center window
17DF: 05          DCR   B                  ; All done?
17E0: C2 DC 17    JNZ   $17DC              ; No ... do again
17E3: 3E 01       MVI   A,$01              ; Flag ...
17E5: 32 9A 20    STA   #tilt               ; ... handling TILT
17E8: CD D7 19    CALL  DsableGameTasks    ; Disable game tasks
17EB: FB          EI                       ; Re-enable interrupts
17EC: 11 BC 1C    LXI   D,$1CBC            ; Message "TILT"
17EF: 21 16 30    LXI   H,$3016            ; Center of screen
17F2: 0E 04       MVI   C,$04              ; Four letters
17F4: CD 93 0A    CALL  PrintMessageDel    ; Print "TILT"
17F7: CD B1 0A    CALL  OneSecDelay        ; Short delay
17FA: AF          XRA   A                  ; Zero
17FB: 32 9A 20    STA   #tilt               ; TILT handle over
17FE: 32 93 20    STA   #waitStartLoop      ; Back into splash screens
1801: C3 C9 16    JMP   $16C9              ; Handle game over for player

; CtrlSaucerSound
1804: 21 84 20    LXI   H,$2084            ; Saucer on screen flag
1807: 7E          MOV   A,M                ; Is the saucer ...
1808: A7          ANA   A                  ; ... on the screen?
1809: CA 07 07    JZ    $0707              ; No ... UFO sound off
180C: 23          INX   H                  ; Saucer hit flag
180D: 7E          MOV   A,M                ; (2085) Get saucer hit flag
180E: A7          ANA   A                  ; Is saucer in "hit" sequence?
180F: C0          RNZ                      ; Yes ... out
1810: 06 01       MVI   B,$01              ; Retrigger saucer ...
1812: C3 FA 18    JMP   SoundBits3On       ; ... sound (retrigger makes it warble?)
  
; DrawAdvTable
; Draw "SCORE ADVANCE TABLE"
1815: 21 10 28    LXI   H,$2810            ; 0x410 is 1040 rotCol=32, rotRow=16
1818: 11 A3 1C    LXI   D,$1CA3            ; "*SCORE ADVANCE TABLE*"
181B: 0E 15       MVI   C,$15              ; 21 bytes in message
181D: CD F3 08    CALL  PrintMessage       ; Print message
1820: 3E 0A       MVI   A,$0A              ; 10 bytes in every "=xx POINTS" string
1822: 32 6C 20    STA   #temp206C           ; Hold the count
1825: 01 BE 1D    LXI   B,$1DBE            ; Coordinate/sprite for drawing table
1828: CD 56 18    CALL  ReadPriStruct      ; Get HL=coordinate, DE=image
182B: DA 37 18    JC    $1837              ; Move on if done
182E: CD 44 18    CALL  $1844              ; Draw 16-byte sprite
1831: C3 28 18    JMP   $1828              ; Do all in table
;
1834: CD B1 0A    CALL  OneSecDelay        ; One second delay
1837: 01 CF 1D    LXI   B,$1DCF            ; Coordinate/message for drawing table
183A: CD 56 18    CALL  ReadPriStruct      ; Get HL=coordinate, DE=message
183D: D8          RC                       ; Out if done
183E: CD 4C 18    CALL  $184C              ; Print message
1841: C3 3A 18    JMP   $183A              ; Do all in table
;
1844: C5          PUSH  B                  ; Hold BC
1845: 06 10       MVI   B,$10              ; 16 bytes
1847: CD 39 14    CALL  DrawSimpSprite     ; Draw simple
184A: C1          POP   B                  ; Restore BC
184B: C9          RET                      ; Out
;
184C: C5          PUSH  B                  ; Hold BC
184D: 3A 6C 20    LDA   #temp206C           ; Count of 10 ...
1850: 4F          MOV   C,A                ; ... to C
1851: CD 93 0A    CALL  PrintMessageDel    ; Print the message with delay between letters
1854: C1          POP   B                  ; Restore BC
1855: C9          RET                      ; Out

; ReadPriStruct
; Read a 4-byte print-structure pointed to by BC
; HL=Screen coordiante, DE=pointer to message
; If the first byte is FF then return with C=1.
1856: 0A          LDAX  B                  ; Get the screen LSB
1857: FE FF       CPI   $FF                ; Valid?
1859: 37          STC                      ; If not C will be 1
185A: C8          RZ                       ; Return if 255
185B: 6F          MOV   L,A                ; Screen LSB to L
185C: 03          INX   B                  ; Next
185D: 0A          LDAX  B                  ; Read screen MSB
185E: 67          MOV   H,A                ; Screen MSB to H
185F: 03          INX   B                  ; Next
1860: 0A          LDAX  B                  ; Read message LSB
1861: 5F          MOV   E,A                ; Message LSB to E
1862: 03          INX   B                  ; Next
1863: 0A          LDAX  B                  ; Read message MSB
1864: 57          MOV   D,A                ; Message MSB to D
1865: 03          INX   B                  ; Next (for next print)
1866: A7          ANA   A                  ; Clear C
1867: C9          RET                      ; Done

; SplashSprite
; Moves a sprite up or down in splash mode. Interrupt moves the sprite. When it reaches
; Y value in 20CA the flag at 20CB is raised. The image flips between two pictures every
; 4 movements.      

1868: 21 C2 20    LXI   H,$20C2            ; Descriptor
186B: 34          INR   M                  ; Change image
186C: 23          INX   H                  ; Point to delta-x
186D: 4E          MOV   C,M                ; Get delta-x
186E: CD D9 01    CALL  AddDelta           ; Add delta-X and delta-Y to X and Y
1871: 47          MOV   B,A                ; Current y coordinate
1872: 3A CA 20    LDA   #splashTargetY      ; Has sprite reached ...
1875: B8          CMP   B                  ; ... target coordinate?
1876: CA 98 18    JZ    $1898              ; Yes ... flag and out
1879: 3A C2 20    LDA   #splashAnForm       ; Image number
187C: E6 04       ANI   $04                ; Watching bit 3 for flip delay
187E: 2A CC 20    LHLD  #splashImRestLSB    ; Image
1881: C2 88 18    JNZ   $1888              ; Did bit 3 go to 0? No ... keep current image
1884: 11 30 00    LXI   D,$0030            ; 16*3 ...
1887: 19          DAD   D                  ; ...  use other image form
1888: 22 C7 20    SHLD  #splashImageLSB     ; Image to descriptor structure
188B: 21 C5 20    LXI   H,$20C5            ; X,Y,Image descriptor
188E: CD 3B 1A    CALL  ReadDesc           ; Read sprite descriptor
1891: EB          XCHG                     ; Image to DE, position to HL
1892: C3 D3 15    JMP   DrawSprite         ; Draw the sprite

1895: 00 00 00                          

1898: 3E 01       MVI   A,$01              ; Flag that sprite ...
189A: 32 CB 20    STA   #splashReached      ; ... reached location
189D: C9          RET                      ; Out

;Animate alien shot to extra "C" in splash
189E: 21 50 20    LXI   H,$2050            ; Task descriptor for game object 4 (squiggly shot)
18A1: 11 C0 1B    LXI   D,$1BC0            ; Task info for animate-shot-to-extra-C
18A4: 06 10       MVI   B,$10              ; Block copy ...
18A6: CD 32 1A    CALL  BlockCopy          ; ... 16 bytes
18A9: 3E 02       MVI   A,$02              ; Set shot sync ...
18AB: 32 80 20    STA   #shotSync           ; ... to run the squiggly shot
18AE: 3E FF       MVI   A,$FF              ; Shot direction (-1)
18B0: 32 7E 20    STA   #alienShotDelta     ; Alien shot delta
18B3: 3E 04       MVI   A,$04              ; Animate ...
18B5: 32 C1 20    STA   #isrSplashTask      ; ... shot
18B8: 3A 55 20    LDA   #squShotStatus      ; Has shot ...
18BB: E6 01       ANI   $01                ; ... collided?
18BD: CA B8 18    JZ    $18B8              ; No ... keep waiting
18C0: 3A 55 20    LDA   #squShotStatus      ; Wait ...
18C3: E6 01       ANI   $01                ; ... for explosion ...
18C5: C2 C0 18    JNZ   $18C0              ; ... to finish
18C8: 21 11 33    LXI   H,$3311            ; Here is where the extra C is
18CB: 3E 26       MVI   A,$26              ; Space character
18CD: 00          NOP                      ; %% Why?
18CE: CD FF 08    CALL  DrawChar           ; Draw character
18D1: C3 B6 0A    JMP   TwoSecDelay        ; Two second delay and out


; Initializiation comes here
;
18D4: 31 00 24    LXI   SP,$2400           ; Set stack pointer just below screen
18D7: 06 00       MVI   B,$00              ; Count 256 bytes
18D9: CD E6 01    CALL  $01E6              ; Copy ROM to RAM
18DC: CD 56 19    CALL  DrawStatus         ; Print scores and credits
;
18DF: 3E 08       MVI   A,$08              ; Set alien ...
18E1: 32 CF 20    STA   #aShotReloadRate    ; ... shot reload rate
18E4: C3 EA 0A    JMP   $0AEA              ; Top of splash screen loop

; Get player-alive flag for OTHER player
18E7: 3A 67 20    LDA   #playerDataMSB      ; Player data MSB
18EA: 21 E7 20    LXI   H,$20E7            ; Alive flags (player 1 and 2)
18ED: 0F          RRC                      ; Bit 1=1 for player 1
18EE: D0          RNC                      ; Player 2 ... we have it ... out
18EF: 23          INX   H                  ; Player 1's flag
18F0: C9          RET                      ; Done

; If there is one alien left then the right motion is 3 instead of 2. That's
; why the timing is hard to hit after the change.
18F1: 06 02       MVI   B,$02              ; Rack moving right delta X
18F3: 3A 82 20    LDA   #numAliens          ; Number of aliens on screen
18F6: 3D          DCR   A                  ; Just one left?
18F7: C0          RNZ                      ; No ... use right delta X of 2
18F8: 04          INR   B                  ; Just one alien ... move right at 3 instead of 2
18F9: C9          RET                      ; Done

; SoundBits3On
; Add in bit for sound
18FA: 3A 94 20    LDA   #soundPort3         ; Current value of sound port
18FD: B0          ORA   B                  ; Add in new sounds
18FE: 32 94 20    STA   #soundPort3         ; New value of sound port
1901: D3 03       OUT   $03                ; Write new value to sound hardware
1903: C9          RET                      

; InitAliensP2
1904: 21 00 22    LXI   H,$2200            ; Player 2 data area
1907: C3 C3 01    JMP   $01C3              ; Initialize player 2 aliens

; PlyrShotAndBump
190A: CD D8 14    CALL  PlayerShotHit      ; Player's shot collision detection
190D: C3 97 15    JMP   RackBump           ; Change alien deltaX and deltaY when rack bumps edges

; CurPlyAlive
; Get the current player's alive status
1910: 21 E7 20    LXI   H,$20E7            ; Alive flags
1913: 3A 67 20    LDA   #playerDataMSB      ; Player 1 or 2
1916: 0F          RRC                      ; Will be 1 if player 1
1917: D8          RC                       ; Return if player 1
1918: 23          INX   H                  ; Bump to player 2
1919: C9          RET                      ; Return

; DrawScoreHead
; Print score header " SCORE<1> HI-SCORE SCORE<2> "
191A: 0E 1C       MVI   C,$1C              ; 28 bytes in message
191C: 21 1E 24    LXI   H,$241E            ; Screen coordinates
191F: 11 E4 1A    LXI   D,$1AE4            ; Score header message
1922: C3 F3 08    JMP   PrintMessage       ; Print score header

1925: 21 F8 20    LXI   H,$20F8            ; Player 1 score descriptor
1928: C3 31 19    JMP   DrawScore          ; Print score

192B: 21 FC 20    LXI   H,$20FC            ; Player 2 score descriptor
192E: C3 31 19    JMP   DrawScore          ; Print score

; DrawScore
; Print score.
; HL = descriptor
1931: 5E          MOV   E,M                ; Get score LSB
1932: 23          INX   H                  ; Next
1933: 56          MOV   D,M                ; Get score MSB
1934: 23          INX   H                  ; Next
1935: 7E          MOV   A,M                ; Get coordinate LSB
1936: 23          INX   H                  ; Next
1937: 66          MOV   H,M                ; Get coordiante MSB
1938: 6F          MOV   L,A                ; Set LSB
1939: C3 AD 09    JMP   Print4Digits       ; Print 4 digits in DE

; Print message "CREDIT "
193C: 0E 07       MVI   C,$07              ; 7 bytes in message
193E: 21 01 35    LXI   H,$3501            ; Screen coordinates
1941: 11 A9 1F    LXI   D,$1FA9            ; Message = "CREDIT "
1944: C3 F3 08    JMP   PrintMessage       ; Print message

; DrawNumCredits
; Display number of credits on screen
1947: 3A EB 20    LDA   #numCoins           ; Number of credits
194A: 21 01 3C    LXI   H,$3C01            ; Screen coordinates
194D: C3 B2 09    JMP   DrawHexByte        ; Character to screen

; PrintHiScore
1950: 21 F4 20    LXI   H,$20F4            ; Hi Score descriptor
1953: C3 31 19    JMP   DrawScore          ; Print Hi-Score

; DrawStatus
; Print scores (with header) and credits (with label)
1956: CD 5C 1A    CALL  Clear2Rows         ; Clear 2 rows on the screen
1959: CD 1A 19    CALL  DrawScoreHead      ; Print score header
195C: CD 25 19    CALL  $1925              ; Print player 1 score
195F: CD 2B 19    CALL  $192B              ; Print player 2 score
1962: CD 50 19    CALL  PrintHiScore       ; Print hi score
1965: CD 3C 19    CALL  $193C              ; Print credit lable
1968: C3 47 19    JMP   DrawNumCredits     ; Number of credits

196B: CD DC 19    CALL  SoundBits3Off      ; From 170B with B=FB. Turn off player shot sound
196E: C3 71 16    JMP   $1671              ; Update high-score if player's score is greater

1971: 3E 01       MVI   A,$01              ; Set flag that ...
1973: 32 6D 20    STA   #invaded            ; ... aliens reached bottom of screen
1976: C3 E6 16    JMP   $16E6              ; End of round

1979: CD D7 19    CALL  DsableGameTasks    ; Disable ISR game tasks
197C: CD 47 19    CALL  DrawNumCredits     ; Display number of credits on screen
197F: C3 3C 19    JMP   $193C              ; Print message "CREDIT"

1982: 32 C1 20    STA   #isrSplashTask      ; Set ISR splash task
1985: C9          RET                      ; Done

1986: 8B 19 ; Points to print TAITO CORPORATION message ... not sure why
               
1988: C3 D6 09    JMP   ClearPlayField     ; Clear playfield and out

; Print "*TAITO CORPORATION*"
198B: 21 03 28    LXI   H,$2803            ; Screen coordinates
198E: 11 BE 19    LXI   D,$19BE            ; Message "*TAITO CORPORATION*"
1991: 0E 13       MVI   C,$13              ; Messgae length
1993: C3 F3 08    JMP   PrintMessage       ; Print message

1996: 00 00 00 00 ; %% Why?
                         
; CheckHiddenMes
; There is a hidden message "TAITO COP" (with no "R") in the game. It can only be 
; displayed in the demonstration game during the splash screens. You must enter
; 2 seqences of buttons. Timing is not critical. As long as you eventually get all
; the buttons up/down in the correct pattern then the game will register the
; sequence.
;
; 1st: 2start(down) 1start(up)   1fire(down) 1left(down) 1right(down)
; 2nd: 2start(up)   1start(down) 1fire(down) 1left(down) 1right(up)
;
; Unfortunately MAME does not deliver the simultaneous button presses correctly. You can see the message in
; MAME by changing 19A6 to 02 and 19B1 to 02. Then the 2start(down) is the only sequence. 
;
199A: 3A 1E 20    LDA   #hidMessSeq         ; Has the 1st "hidden-message" sequence ...
199D: A7          ANA   A                  ; ... been registered?
199E: C2 AC 19    JNZ   $19AC              ; Yes ... go look for the 2nd sequence
19A1: DB 01       IN    $01                ; Get player inputs
19A3: E6 76       ANI   $76                ; 0111_0110 Keep 2Pstart, 1Pstart, 1Pshot, 1Pleft, 1Pright
19A5: D6 72       SUI   $72                ; 0111_0010 1st sequence: 2Pstart, 1Pshot, 1Pleft, 1Pright
19A7: C0          RNZ                      ; Not first sequence ... out
19A8: 3C          INR   A                  ; Flag that 1st sequence ...
19A9: 32 1E 20    STA   #hidMessSeq         ; ... has been entered
19AC: DB 01       IN    $01                ; Check inputs for 2nd sequence
19AE: E6 76       ANI   $76                ; 0111_0110 Keep 2Pstart, 1Pstart, 1Pshot, 1Pleft, 1Pright
19B0: FE 34       CPI   $34                ; 0011_0100 2nd sequence: 1Pstart, 1Pshot, 1Pleft
19B2: C0          RNZ                      ; If not second sequence ignore
19B3: 21 1B 2E    LXI   H,$2E1B            ; Screen coordinates
19B6: 11 F7 0B    LXI   D,$0BF7            ; Message = "TAITO COP" (no R)
19B9: 0E 09       MVI   C,$09              ; Message length
19BB: C3 F3 08    JMP   PrintMessage       ; Print message and out

; MessageTaito
; "*TAITO CORPORATION*"
19BE: 28 13 00 08 13 0E 26 02 0E 11 0F 0E 11      
19CB: 00 13 08 0E 0D 28

; EnableGameTasks
; Enable ISR game tasks 
19D1: 3E 01       MVI   A,$01              ; Set ISR ...
19D3: 32 E9 20    STA   #suspendPlay        ; ... game tasks enabled
19D6: C9          RET                      ; Done

; DsableGameTasks
; Disable ISR game tasks
; Clear 20E9 flag
19D7: AF          XRA   A                  ; Clear ISR game tasks flag
19D8: C3 D3 19    JMP   $19D3              ; Save a byte (the RET)
19DB: 00                                          ; %% Here is the byte saved. I wonder if this was an optimizer pass.

; SoundBits3Off
; Turn off bit in sound port
19DC: 3A 94 20    LDA   #soundPort3         ; Current sound effects value
19DF: A0          ANA   B                  ; Mask bits off
19E0: 32 94 20    STA   #soundPort3         ; Store new hold value
19E3: D3 03       OUT   $03                ; Change sounds
19E5: C9          RET                      ; Done

; DrawNumShips
; Show ships remaining in hold for the player
19E6: 21 01 27    LXI   H,$2701            ; Screen coordinates
19E9: CA FA 19    JZ    $19FA              ; None in reserve ... skip display
; Draw line of ships
19EC: 11 60 1C    LXI   D,$1C60            ; Player sprite
19EF: 06 10       MVI   B,$10              ; 16 rows
19F1: 4F          MOV   C,A                ; Hold count
19F2: CD 39 14    CALL  DrawSimpSprite     ; Display 1byte sprite to screen
19F5: 79          MOV   A,C                ; Restore remaining
19F6: 3D          DCR   A                  ; All done?
19F7: C2 EC 19    JNZ   $19EC              ; No ... keep going
; Clear remainder of line
19FA: 06 10       MVI   B,$10              ; 16 rows
19FC: CD CB 14    CALL  ClearSmallSprite   ; Clear 1byte sprite at HL
19FF: 7C          MOV   A,H                ; Get Y coordinate
1A00: FE 35       CPI   $35                ; At edge?
1A02: C2 FA 19    JNZ   $19FA              ; No ... do all
1A05: C9          RET                      ; Out

; CompYToBeam
;
; The ISRs set the upper bit of 2072 based on where the beam is. This is compared to the
; upper bit of an object's Y coordinate to decide whic ISR should handle it. When the
; beam passes the halfway point (or near it ... at scanline 96), the upper bit is cleared.
; When the beam reaches the end of the screen the upper bit is set.
;
; The task then runs in the ISR if the Y coordiante bit matches the 2072 flag. Objects that
; are at the top of the screen (upper bit of Y clear) run in the mid-screen ISR when
; the beam has moved to the bottom of the screen. Objects that are at the bottom of the screen
; (upper bit of Y set) run in the end-screen ISR when the beam is moving back to the top.
;
; The pointer to the object's Y coordinate is passed in DE. CF is set if the upper bits are
; the same (the calling ISR should execute the task).
;
1A06: 21 72 20    LXI   H,$2072            ; Get the ...
1A09: 46          MOV   B,M                ; ... beam position status
1A0A: 1A          LDAX  D                  ; Get the task structure flag
1A0B: E6 80       ANI   $80                ; Only upper bits count
1A0D: A8          XRA   B                  ; XOR them together
1A0E: C0          RNZ                      ; Not the same (CF cleared)
1A0F: 37          STC                      ; Set the CF if the same
1A10: C9          RET                      ; Done

; Alien delay lists. First list is the number of aliens. The second list is the corresponding delay.
; This delay is only for the rate of change in the fleet's sound.
; The check takes the first num-aliens-value that is lower or the same as the actual num-aliens on screen.
;
; The game starts with 55 aliens. The aliens are move/drawn one per interrupt which means it
; takes 55 interrupts. The first delay value is 52 ... which is almost in sync with the number
; of aliens. It is a tad faster and you can observe the sound and steps getting out of sync.
;
1A11: 32 2B 24 1C 16 11 0D 0A 08 07 06 05 04 03 02 01
1A21: 34 2E 27 22 1C 18 15 13 10 0E 0D 0C 0B 09 07 05     
1A31: FF   ; %% Needless terminator. The list value "1" catches everything.

; BlockCopy
; Copy from [DE] to [HL] (b bytes)
1A32: 1A          LDAX  D                  ; Copy from [DE] to ...
1A33: 77          MOV   M,A                ; ... [HL]
1A34: 23          INX   H                  ; Next destination
1A35: 13          INX   D                  ; Next source
1A36: 05          DCR   B                  ; Count in B
1A37: C2 32 1A    JNZ   BlockCopy          ; Do all
1A3A: C9          RET                      ; Done

; ReadDesc
; Load 5 bytes sprite descriptor from [HL]
1A3B: 5E          MOV   E,M                ; Descriptor ...
1A3C: 23          INX   H                  ; ... sprite ...
1A3D: 56          MOV   D,M                ; ...
1A3E: 23          INX   H                  ; ... picture
1A3F: 7E          MOV   A,M                ; Descriptor ...
1A40: 23          INX   H                  ; ... screen ...
1A41: 4E          MOV   C,M                ; ...
1A42: 23          INX   H                  ; ... location
1A43: 46          MOV   B,M                ; Number of bytes in sprite
1A44: 61          MOV   H,C                ; From A,C to ...
1A45: 6F          MOV   L,A                ; ... H,L
1A46: C9          RET                      ; Done

; ConvToScr
; The screen is organized as one-bit-per-pixel.
; In: HL contains pixel number (bbbbbbbbbbbbbppp)
; Convert from pixel number to screen coordinates (without shift)
; Shift HL right 3 bits (clearing the top 2 bits)
; and set the third bit from the left.
1A47: C5          PUSH  B                  ; Hold B (will mangle)
1A48: 06 03       MVI   B,$03              ; 3 shifts (divide by 8)
1A4A: 7C          MOV   A,H                ; H to A
1A4B: 1F          RAR                      ; Shift right (into carry, from doesn't matter)
1A4C: 67          MOV   H,A                ; Back to H
1A4D: 7D          MOV   A,L                ; L to A
1A4E: 1F          RAR                      ; Shift right (from/to carry)
1A4F: 6F          MOV   L,A                ; Back to L
1A50: 05          DCR   B                  ; Do all ...
1A51: C2 4A 1A    JNZ   $1A4A              ; ... 3 shifts
1A54: 7C          MOV   A,H                ; H to A
1A55: E6 3F       ANI   $3F                ; Mask off all but screen (less than or equal 3F)
1A57: F6 20       ORI   $20                ; Offset into RAM
1A59: 67          MOV   H,A                ; Back to H
1A5A: C1          POP   B                  ; Restore B
1A5B: C9          RET                      ; Done

; Clear2Rows
; Clear 2 rows on the screen (2 vertical lines when rotated)
1A5C: 21 00 24    LXI   H,$2400            ; Screen coordinate
1A5F: 36 00       MVI   M,$00              ; Clear it
1A61: 23          INX   H                  ; Next byte
1A62: 7C          MOV   A,H                ; Have we done ...
1A63: FE 40       CPI   $40                ; ... 2 rows?
1A65: C2 5F 1A    JNZ   $1A5F              ; No ... keep going
1A68: C9          RET                      ; Out

; RestoreShields
; Logically OR the player's shields back onto the playfield
; DE = sprite
; HL = screen
; C = bytes per row
; B = number of rows
1A69: C5          PUSH  B                  ; Preserve BC
1A6A: E5          PUSH  H                  ; Hold for a bit
1A6B: 1A          LDAX  D                  ; From sprite
1A6C: B6          ORA   M                  ; OR with screen
1A6D: 77          MOV   M,A                ; Back to screen
1A6E: 13          INX   D                  ; Next sprite
1A6F: 23          INX   H                  ; Next on screen
1A70: 0D          DCR   C                  ; Row done?
1A71: C2 6B 1A    JNZ   $1A6B              ; No ... do entire row
1A74: E1          POP   H                  ; Original start
1A75: 01 20 00    LXI   B,$0020            ; Bump HL by ...
1A78: 09          DAD   B                  ; ... one screen row
1A79: C1          POP   B                  ; Restore
1A7A: 05          DCR   B                  ; Row counter
1A7B: C2 69 1A    JNZ   RestoreShields     ; Do all rows
1A7E: C9          RET                      

; RemoveShip
; Remove a ship from the players stash and update the
; hold indicators on the screen.
1A7F: CD 2E 09    CALL  $092E              ; Get last byte from player data
1A82: A7          ANA   A                  ; Is it 0?
1A83: C8          RZ                       ; Skip
1A84: F5          PUSH  PSW                ; Preserve number remaining
1A85: 3D          DCR   A                  ; Remove a ship from the stash
1A86: 77          MOV   M,A                ; New number of ships
1A87: CD E6 19    CALL  DrawNumShips       ; Draw the line of ships
1A8A: F1          POP   PSW                ; Restore number
1A8B: 21 01 25    LXI   H,$2501            ; Screen coordinates
1A8E: E6 0F       ANI   $0F                ; Make sure it is a digit
1A90: C3 C5 09    JMP   $09C5              ; Print number remaining




;==========================================================
; DATA FROM HERE DOWN
;
1A93: 00 00       

; Splash screen animation structure 1
; 00   Image form (increments each draw)
; 00   Delta X
; FF   Delta Y is -1
; B8   X coordinate
; FE   Y starting coordiante
; 1C20 Base image (small alien)
; 10   Size of image (16 bytes)
; 9E   Target Y coordiante
; 00   Reached Y flag
; 1C20 Base iamge (small alien)
1A95: 00 00 FF B8 FE 20 1C 10 9E 00 20 1C   

; AShotReloadRate
; The tables at 1CB8 and 1AA1 control how fast shots are created. The speed is based
; on the upper byte of the player's score. For a score of less than or equal 0200 then 
; the fire speed is 30. For a score less than or equal 1000 the shot speed is 10. Less 
; than or equal 2000 the speed is 0B. Less than or equal 3000 is 08. And anything 
; above 3000 is 07.
;
; 1CB8: 02 10 20 30
;
1AA1: 30 10 0B 08                           
1AA5: 07           ; Fastest shot firing speed

; MessageGOver
; GAME OVER PLAYER< >"
1AA6: 06 00 0C 04 26 0E 15 04 11 26 26 0F   
1AB2: 0B 00 18 04 11 24 26 25               

; MessageB1or2
; "1 OR 2PLAYERS BUTTON"
1ABA: 1B 26 0E 11 26 1C 0F 0B 00 18 04      
1AC5: 11 12 26 01 14 13 13 0E 0D 26

; Message1Only
; "ONLY 1PLAYER BUTTON "
; Note the space on the end ... both alternatives are same length
1ACF: 0E 0D 0B 18 26 1B 0F 0B 00 18 04 11 26 26 
1ADD: 01 14 13 13 0E 0D 26                  

; MessageScore
; " SCORE<1> HI-SCORE SCORE<2>"
1AE4: 26 12 02 0E 11 04 24 1B 25 26 07 08   
1AF0: 3F 12 02 0E 11 04 26 12 02 0E 11 04   
1AFC: 24 1C 25 26                           

;-------------------------- RAM initialization -----------------------------
; Coppied to RAM (2000) C0 bytes as initialization.
; See the description of RAM at the top of this file for the details on this data.

1B00: 01 00 00 10 00 00 00 00 02 78 38 78 38 00 F8 00
1B10: 00 80 00 8E 02 FF 05 0C 60 1C 20 30 10 01 00 00   
1B20: 00 00 00 BB 03 00 10 90 1C 28 30 01 04 00 FF FF   
1B30: 00 00 02 76 04 00 00 00 00 00 04 EE 1C 00 00 03    
1B40: 00 00 00 B6 04 00 00 01 00 1D 04 E2 1C 00 00 03 
1B50: 00 00 00 82 06 00 00 01 06 1D 04 D0 1C 00 00 03
1B60: FF 00 C0 1C 00 00 10 21 01 00 30 00 12 00 00 00         

; These don't need to be copied over to RAM (see 1BA0 below).
; MesssageP1
; "PLAY PLAYER<1>"                           
1B70: 0F 0B 00 18 26 0F 0B 00 18 04 11 24 1B 25 FC 
1B8F: 00 

1B80: 01 FF FF 00 00 00 20 64 1D D0 29 18 02 54 1D 00               
1B90: 08 00 06 00 00 01 40 00 01 00 00 10 9E 00 20 1C                                 
 
; These don't need to be copied over to RAM I believe this to be a mistake. The constant at 01E4 is C0,
; which is the size of this mirror with the added sprite. It should be A0. I believe there was a macro
; to size this area and later the splash screens where put in. Some of the data spilled over into this
; and the macro automatically included it. No harm.

; AlienSprCYA
; Alien sprite type C pulling upside down Y
; ........
; **......
; ..*.....
; ...****.
; ..*.*...
; **..*...
; ...*....
; .*.**...
; *.****..
; ...*.**.
; ..******
; ..******
; ...*.**.
; *.****..
; .*.**...
; ........
1BA0: 00 03 04 78 14 13 08 1A 3D 68 FC FC 68 3D 1A 00                                    

1BB0: 00 00 01 B8 98 A0 1B 10 FF 00 A0 1B 00 00 00 00                                    
;--------------------------- End of initialization copy -------------------------


; Shot descriptor for splash shooting the extra "C"
1BC0: 00 10 00 0E 05 00 00 00 00 00 07 D0 1C C8 9B 03      
                        

; AlienSprCYB
; Alien sprite C pulling upside down Y. Note the difference between this and the first picutre
; above. The Y is closer to the ship. This gives the effect of the Y kind of "sticking" in the
; animation.
; ........
; ........
; **......
; ..*.....
; ...****.
; ..*.*...
; **.*....
; *..**...
; .*.***..
; *.**.**.
; .*.*****
; .*.*****
; *.**.**.
; .*.***..
; *..**...
; ........
;
1BD0: 00 00 03 04 78 14 0B 19 3A 6D FA FA 6D 3A 19 00                                    

; More RAM initialization copied by 18D9
1BE0: 00 00 00 00 00 00 00 00 00 01 00 00 01 74 1F 00                                    
1BF0: 80 00 00 00 00 00 1C 2F 00 00 1C 27 00 00 1C 39 

; AlienSprA
; Alien sprite type A,B, and C at positions 0
;  ........ ........ ........
;  ........ ........ ........
;  *..***.. ........ ........
;  *..****. ...****. ........
;  .*.****. *.***... *..**...
;  .***.**. .*****.* .*.***..
;  ..**.*** ..**.**. *.**.**.
;  .*.***** ..****.. .*.*****
;  .*.***** ..****.. .*.*****
;  ..**.*** ..****.. *.**.**.
;  .***.**. ..**.**. .*.***..
;  .*.****. .*****.* *..**...
;  *..****. *.***... ........
;  *..***.. ...****. ........
;  ........ ........ ........
;  ........ ........ ........
1C00: 00 00 39 79 7A 6E EC FA FA EC 6E 7A 79 39 00 00 
1C10: 00 00 00 78 1D BE 6C 3C 3C 3C 6C BE 1D 78 00 00 
1C20: 00 00 00 00 19 3A 6D FA FA 6D 3A 19 00 00 00 00 

; AlienSprB
; Alien sprite type A,B, and C at positions 1
;  ........ ........ ........
;  ........ ........ ........
;  ...***.. ........ ........
;  .*.****. .***.... ........
;  *******. ...**... .*.**...
;  *.**.**. .*****.* *.****..
;  ..**.*** *.**.**. ...*.**.
;  .*.***** *.****.. ..******
;  .*.***** ..****.. ..******
;  ..**.*** *.****.. ...*.**.
;  *.**.**. *.**.**. *.****..
;  *******. .*****.* .*.**...
;  .*.****. ...**... ........
;  ...***.. .***.... ........
;  ........ ........ ........
;  ........ ........ ........
1C30: 00 00 38 7A 7F 6D EC FA FA EC 6D 7F 7A 38 00 00 
1C40: 00 00 00 0E 18 BE 6D 3D 3C 3D 6D BE 18 0E 00 00 
1C50: 00 00 00 00 1A 3D 68 FC FC 68 3D 1A 00 00 00 00 

; PlayerSprite
; Player sprite  
;  ........
;  ........
;  ****....
;  *****...
;  *****...
;  *****...
;  *****...
;  *******.
;  ********
;  *******.
;  *****...
;  *****...
;  *****...
;  *****...
;  ****....
;  ........  
1C60: 00 00 0F 1F 1F 1F 1F 7F FF 7F 1F 1F 1F 1F 0F 00 


; PlrBlowupSprites
;  ........
;  ..*.....
;  *.......
;  **..*...
;  **......
;  ***.....
;  **..**.*
;  ****....
;  ****.*..
;  **......
;  ****.*..
;  *..*..*.
;  ..*.....
;  **......
;  ........
;  *.......
;
1C70: 00 04 01 13 03 07 B3 0F 2F 03 2F 49 04 03 00 01 
;
;  ......*.
;  ...*....
;  *.*.....
;  **...*.*
;  .*.*....
;  **......
;  **.**.*.
;  ****....
;  ***..*..
;  ***..*..
;  **.*....
;  **.*..*.
;  ......*.
;  ..*....*
;  *...*...
;  ...*..*.
1C80: 40 08 05 A3 0A 03 5B 0F 27 27 0B 4B 40 84 11 48 

; PlayerShotSpr
1C90: 0F    ;....****      
        
; ShotExploding
; *..**..*
; ..****..
; .******.
; *.****..
; ..****.*
; .*****..
; ..*****.
; *..**..*           
1C91: 99 3C 7E 3D BC 3E 7C 99     
      
; Message10Pts
; Ran out of space at 1DFE
1C99: 27 1B 1A 26 0F 0E 08 0D 13 12    ; "=10 POINTS"

; MessageAdv
; "*SCORE ADVANCE TABLE*"                                
1CA3: 28 12 02 0E 11 04 26 00                                 
1CAB: 03 15 00 0D 02 04 26 13                                 
1CB3: 00 01 0B 04 28                                    


; AReloadScoreTab
; The tables at 1CB8 and 1AA1 control how fast shots are created. The speed is based
; on the upper byte of the player's score. For a score of less than or equal 0200 then 
; the fire speed is 30. For a score less than or equal 1000 the shot speed is 10. Less 
; than or equal 2000 the speed is 0B. Less than or equal 3000 is 08. And anything 
; above 3000 is 07.
;
; 1AA1: 30 10 0B 08                           
; 1AA5: 07           ; Fastest shot firing speed
;
1CB8: 02 10 20 30                           

; MessageTilt
1CBC: 13 08 0B 13   ; "TILT"

; AlienExplode
; Alien exploding sprite
;  ........
;  ...*....
;  *..*..*.
;   .*...*..
;  ..*.*...
;  *......*
;  .*....*.
;  ........
;  .*....*.
;  *......*
;  ..*.*...
;  .*...*..
;  *..*..*.
;  ...*....
;  ........
;  ........
1CC0: 00 08 49 22 14 81 42 00 42 81 14 22 49 08 00 00 

; SquiglyShot
; Squigly shot picture in 4 animation frames
;
1CD0: 44   ; ..*...*.               
1CD1: AA   ; .*.*.*.*                                 
1CD2: 10   ; ....*...

1CD3: 88   ; ...*...*                             
1CD4: 54   ; ..*.*.*.                                 
1CD5: 22   ; .*...*..

1CD6: 10   ; ....*...
1CD7: AA   ; .*.*.*.*                           
1CD8: 44   ; ..*...*.
                                 
1CD9: 22   ; .*...*..
1CDA: 54   ; ..*.*.*.
1CDB: 88   ; ...*...*


; AShotExplo
; Alien shot exploding                            
1CDC: 4A  ; .*.*..*.                                 
1CDD: 15  ; *.*.*...                                  
1CDE: BE  ; .*****.*                                  
1CDF: 3F  ; ******..                                  
1CE0: 5E  ; .****.*.                                  
1CE1: 25  ; *.*..*..                                  

; PlungerShot
; Alien shot ... the plunger looking one
1CE2: 04  ; ..*.....                                  
1CE3: FC  ; ..******
1CE4: 04  ; ..*.....

1CE5: 10  ; ....*...                            
1CE6: FC  ; ..******
1CE7: 10  ; ....*...

1CE8: 20  ; .....*..                            
1CE9: FC  ; ..******
1CEA: 20  ; .....*..

1CEB: 80  ; .......*                            
1CEC: FC  ; ..******
1CED: 80  ; .......*

; RollShot
; Alien shot ... the rolling one
1CEE: 00  ; ........                            
1CEF: FE  ; .*******
1CF0: 00  ; ........                               

1CF1: 24  ; ..*..*..                                  
1CF2: FE  ; .*******
1CF3: 12  ; .*..*...                               

1CF4: 00  ; ........                                  
1CF5: FE  ; .*******
1CF6: 00  ; ........                               

1CF7: 48  ; ...*..*.                                  
1CF8: FE  ; .*******
1CF9: 90  ; ....*..*       
               
; MessagePlayUY
1CFA: 0F 0B 00 29    ; "PLAy" with an upside down 'Y' for splash screen
                      
1CFE: 00 00        
                            
; ColFireTable
; This table decides which column a shot will fall from. The column number is read from the
; table (1-11) and the pointer increases for the shot type. For instance, the "squiggly" shot
; will fall from columns in this order: 0B, 01, 06, 03. If you play the game you'll see that
; order.
;
; The "plunger" shot uses index 00-0F (inclusive)
; The "squiggly" shot uses index 06-14 (inclusive)
; The "rolling" shot targets the player
1D00: 01 07 01 01 01 04 0B 01 06 03 01 01 0B 09 02 08                                    
1D10: 02 0B 04 07 0A    
;
; This appears to be part of the column-firing table, but it is never used.
; Perhaps this was originally intended for the "plunger" shot but then the
; "plunger" was change to target the player specifically.
1D15: 05 02 05 04 06 07 08 0A 06 0A 03              

; ShieldImage
; Shield image pattern. 2 x 22 = 44 bytes.
;
;************....
;*************...
;**************..
;***************.
;****************
;..**************
;...*************
;....************
;....************
;....************
;....************
;....************
;....************
;....************
;...*************
;..**************
;****************
;****************
;***************.
;**************..
;*************...
;************....
;             
1D20: FF 0F FF 1F FF 3F FF 7F FF FF FC FF F8 FF F0 FF F0 FF F0 FF F0 FF                                    
1D36: F0 FF F0 FF F0 FF F8 FF FC FF FF FF FF FF FF 7F FF 3F FF 1F FF 0F                                    


1D4C: 05 10 15 30  ; Table of possible saucer scores
1D50: 94 97 9A 9D  ; Table of corresponding string prints for each possible score                                  

; SaucerScrTab
; The 208D points here to the score given when the saucer is shot. It advances 
; every time the player-shot is removed. The table wraps. Thus the one and only
; 300 comes up every 16 shots (after an initial 8). 
1D54: 10 05 05 10 15 10 10 05 30 10 10 10 05 15 10 05    
                             

; SpriteSaucer
; ........
; ........
; ........
; ........
; ..*.....
; ..**....
; .****...
; ***.**..
; .*****..
; ..*****.
; ..*.***.
; .******.
; .******.
; ..*.***.
; ..*****.
; .*****..
; ***.**..
; .****...
; ..**....
; ..*.....      
; ........
; ........
; ........
; ........                         
1D64: 00 00 00 00 04 0C 1E 37 3E 7C 74 7E 7E 74 7C 3E 37 1E 0C 04 00 00 00 00

; SpriteSaucerExp
;........
;.*...*..
;........
;*.*..*.*
;......*.
;...*....
;...**..*
;*.****..
;.**.**.*
;..****..
;.**.**..
;*.***...
;....*...
;...*..*.
;.*...**.
;.**.**.*
;*.***...
;...**..*
;...*....
;.*....*.
;....*..*
;...*....
;........
;........
1D7C: 00 22 00 A5 40 08 98 3D B6 3C 36 1D 10 48 62 B6 1D 98 08 42 90 08 00 00  
         
; SaucSoreStr
1D94: 26 1F 1A  ; _50                                   
1D97: 1B 1A 1A  ; 100                                  
1D9A: 1B 1F 1A  ; 150                                  
1D9D: 1D 1A 1A  ; 300                                  

; AlienScores
; Score table for hitting alien type
1DA0: 10 ; Bottom 2 rows                                    
1DA1: 20 ; Middle row                                   
1DA2: 30 ; Highest row
         
; AlienStartTable
; Starting Y coordinates for aliens at beginning of rounds. The first round is initialized to $78 at 07EA.
; After that this table is used for 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, and 9th. The 10th starts over at
; 1DA3 (60).
1DA3: 60                                    
1DA4: 50                                    
1DA5: 48                                    
1DA6: 48                                    
1DA7: 48                                    
1DA8: 40                                    
1DA9: 40                                    
1DAA: 40   
                                 
; MessagePlayY
1DAB: 0F 0B 00 18   ; "PLAY" with normal Y

; MessageInvaders
; "SPACE  INVADERS"
1DAF: 12 0F 00 02 04 26 26 08 0D 15 00 03 04 11 12 

; Tables used to draw "SCORE ADVANCE TABLE" information
1DBE: 0E 2C 68 1D           ; Flying Saucer                         
1DC2: 0C 2C 20 1C           ; Alien C, sprite 0                      
1DC6: 0A 2C 40 1C           ; Alien B, sprite 1                         
1DCA: 08 2C 00 1C           ; Alien A, sprite 0                         
1DCE: FF                    ; End of list         
;
; AlienScoreTable
1DCF: 0E 2E E0 1D           ; "=? MYSTERY"                          
1DD3: 0C 2E EA 1D           ; "=30 POINTS"                        
1DD7: 0A 2E F4 1D           ; "=20 POINTS"                        
1DDB: 08 2E 99 1C           ; "=10 POINTS"
1DDF: FF                    ; End of list

; MessageMyst
1DE0: 27 38 26 0C 18 12 13 04 11 18   ; "=? MYSTERY"

; Message30Pts
1DEA: 27 1D 1A 26 0F 0E 08 0D 13 12   ; "=30 POINTS"                                 

; Message20Pts
1DF4: 27 1C 1A 26 0F 0E 08 0D 13 12   ; "=20 POINTS"

; Ran out of space here. The "=10" message is up at 1C99. That keeps
; the font table firmly at 1E00.

1DFE: 00 00 ; Padding to put font table at 1E00


;=============================================================
; Characters
; 8 byte sprites 
; The screen is turned so rotate these pictures counter-clockwise.
; Some of the font characters at the end were never needed. The ROM overwrites these characters with
; data near the end. For instance, 1F90 would be a character but has the "INSERT COIN" message. The "?"
; character is at 1FC0 and is used in messages as is 1FF8 "-".

1E00: 00 1F 24 44 24 1F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1E08: 00 7F 49 49 49 36 00 00  ; *****... *******. .*****.. *******. *******. *******. .*****.. *******. 
1E10: 00 3E 41 41 41 22 00 00  ; ..*..*.. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.....*. ...*.... 
1E18: 00 7F 41 41 41 3E 00 00  ; ..*...*. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.....*. ...*.... 
1E20: 00 7F 49 49 49 41 00 00  ; ..*..*.. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.*...*. ...*.... 
1E28: 00 7F 48 48 48 40 00 00  ; *****... .**.**.. .*...*.. .*****.. *.....*. ......*. ***...*. *******. 
1E30: 00 3E 41 41 45 47 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1E38: 00 7F 08 08 08 7F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 

1E40: 00 00 41 7F 41 00 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1E48: 00 02 01 01 01 7E 00 00  ; ........ .*...... *******. *******. *******. *******. .*****.. *******. 
1E50: 00 7F 08 14 22 41 00 00  ; *.....*. *....... ...*.... *....... .....*.. ....*... *.....*. ...*..*. 
1E58: 00 7F 01 01 01 01 00 00  ; *******. *....... ..*.*... *....... ...**... ...*.... *.....*. ...*..*. 
1E60: 00 7F 20 18 20 7F 00 00  ; *.....*. *....... .*...*.. *....... .....*.. ..*..... *.....*. ...*..*. 
1E68: 00 7F 10 08 04 7F 00 00  ; ........ .******. *.....*. *....... *******. *******. .*****.. ....**.. 
1E70: 00 3E 41 41 41 3E 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1E78: 00 7F 48 48 48 30 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 

1E80: 00 3E 41 45 42 3D 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1E88: 00 7F 48 4C 4A 31 00 00  ; .*****.. *******. .*..**.. ......*. .******. ..*****. *******. **...**. 
1E90: 00 32 49 49 49 26 00 00  ; *.....*. ...*..*. *..*..*. ......*. *....... .*...... .*...... ..*.*... 
1E98: 00 40 40 7F 40 40 00 00  ; *.*...*. ..**..*. *..*..*. *******. *....... *....... ..**.... ...*.... 
1EA0: 00 7E 01 01 01 7E 00 00  ; .*....*. .*.*..*. *..*..*. ......*. *....... .*...... .*...... ..*.*... 
1EA8: 00 7C 02 01 02 7C 00 00  ; *.****.. *...**.. .**..*.. ......*. .******. ..*****. *******. **...**. 
1EB0: 00 7F 02 0C 02 7F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1EB8: 00 63 14 08 14 63 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 

1EC0: 00 60 10 0F 10 60 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1EC8: 00 43 45 49 51 61 00 00  ; .....**. **....*. .*****.. ........ **...*.. .*....*. ..**.... .*..***. 
1ED0: 00 3E 45 49 51 3E 00 00  ; ....*... *.*...*. *.*...*. *....*.. *.*...*. *.....*. ..*.*... *...*.*. 
1ED8: 00 00 21 7F 01 00 00 00  ; ****.... *..*..*. *..*..*. *******. *..*..*. *..*..*. ..*..*.. *...*.*. 
1EE0: 00 23 45 49 49 31 00 00  ; ....*... *...*.*. *...*.*. *....... *..*..*. *..**.*. *******. *...*.*. 
1EE8: 00 42 41 49 59 66 00 00  ; .....**. *....**. .*****.. ........ *...**.. .**..**. ..*..... .***..*. 
1EF0: 00 0C 14 24 7F 04 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1EF8: 00 72 51 51 51 4E 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 

1F00: 00 1E 29 49 49 46 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1F08: 00 40 47 48 50 60 00 00  ; .****... ......*. .**.**.. *...**.. ...*.... ........ ........ ..*.*... 
1F10: 00 36 49 49 49 36 00 00  ; *..*.*.. ***...*. *..*..*. *..*..*. ..*.*... *.....*. ........ ..*.*... 
1F18: 00 31 49 49 4A 3C 00 00  ; *..*..*. ...*..*. *..*..*. *..*..*. .*...*.. .*...*.. ........ ..*.*... 
1F20: 00 08 14 22 41 00 00 00  ; *..*..*. ....*.*. *..*..*. .*.*..*. *.....*. ..*.*... ........ ..*.*... 
1F28: 00 00 41 22 14 08 00 00  ; .**...*. .....**. .**.**.. ..****.. ........ ...*.... ........ ..*.*... 
1F30: 00 00 00 00 00 00 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 
1F38: 00 14 14 14 14 14 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........ 

1F40: 00 22 14 7F 14 22 00 00  ; ........ ........   
1F48: 00 03 04 78 04 03 00 00  ; .*...*.. **......   
                               ; ..*.*... ..*.....   
                               ; *******. ...****.   
                               ; ..*.*... ..*.....   
                               ; .*...*.. **......   
                               ; ........ ........   
                               ; ........ ........   

; MessageP1or2
1F50: 24 1B 26 0E 11 26 1C 26  ; "<1 OR 2 PLAYERS>  "             
1F58: 0F 0B 00 18 04 11 12 25               
1F60: 26 26 

; Message1Coin
1F62: 28 1B 26 0F 0B 00 18 04  ; "*1 PLAYER  1 COIN "
1F6A: 11 26 26 1B 26 02 0E 08 
1F72: 0D 26                           

; DemoCommands
; (1=Right, 2=Left)
1F74: 01 01 00 00 01 00 02 01 00 02 01 00
        
; AlienSprCA
; Small alien pushing Y back onto screen
; .....**.
; ....*...
; ****....
; ....*...
; .....**.
; ....**..
; ...**...
; .*.**...
; *.****..
; ...*.**.
; ..******
; ..******
; ...*.**.
; *.****..
; .*.**...
; ........                         
1F80: 60 10 0F 10 60 30 18 1A 3D 68 FC FC 68 3D 1A 00               

; MessageCoin
1F90: 08 0D 12 04 11 13 26 26 02 0E 08 0D   ; "INSERT  COIN"         
                          
; CreditTable
1F9C: 0D 2A 50 1F                 ; "<1 OR 2 PLAYERS>  " to screen at 2A0D 
1FA0: 0A 2A 62 1F                 ; "*1 PLAYER  1 COIN " to screen at 2A0A
1FA4: 07 2A E1 1F                 ; "*2 PLAYERS 2 COINS" to screen at 2A07
1FA8: FF                          ; Terminates "table print"         

; MessageCredit
1FA9: 02 11 04 03 08 13 26       ; "CREDIT " (with space on the end)           

; AlienSprCB
; ........
; .....**.
; ....*...
; ****....
; ....*...
; .....**.
; ...***..
; *..**...
; .*.***..
; *.**.**.
; .*.*****
; .*.*****
; *.**.**.
; .*.***..
; *..**...
; ........
1FB0: 00 60 10 0F 10 60 38 19 3A 6D FA FA 6D 3A 19 00               

1FC0: 00 20 40 4D 50 20 00 00               ; "?"

1FC8: 00 

; Splash screen animation structure 3
; 00   Image form (increments each draw)
; 00   Delta X
; FF   Delta Y is -1
; B8   X coordinate
; FF   Y starting coordiante
; 1F80 Base image (small alien with Y)
; 10   Size of image (16 bytes)
; 97   Target Y coordiante
; 00   Reached Y flag
; 1F80 Base iamge (small alien with Y)
;
1FC9: 00 00 FF B8 FF 80 1F 10 97 00 80 1F 

; Splash screen animation structure 4
; 00   Image form (increments each draw)
; 00   Delta X
; 01   Delta Y is 1
; D0   X coordinate
; 22   Y starting coordiante
; 1C20 Base image (small alien)
; 10   Size of image (16 bytes)
; 94   Target Y coordiante
; 00   Reached Y flag
; 1C20 Base iamge (small alien)
;
1FD5: 00 00 01 D0 22 20 1C 10 94 00 20 1C 

; Message2Coins
1FE1: 28 1C 26 0F 0B 00 18 04    ; "*2 PLAYERS 2 COINS"
1FE9: 11 12 26 1C 26 02 0E 08 
1FF1: 0D 12                              

; MessagePush
1FF3: 0F 14 12 07 26             ; "PUSH " (with space on the end)                                 

1FF8: 00 08 08 08 08 08 00 00               ; 3F:"-"