Disassembly of Dragon 32 game Invader's Revenge
Ben North, September 2025
This document is my attempt to disassemble and annotate Ken Kalish's Dragon 32 game Invader's Revenge. More details are available in the main write-up, but if you just want to browse, then here are two good starting points:
Sub_InitialEntryPoint
— where execution starts when you run the game.Sub_MainPlayLoop
— the main loop while playing the game; then explore the subroutines called from within this code.
I have used the following convention for prefixes of variable names and other labels:
D32_
— a location defined by the Dragon 32 system itselfVar_b_
— a byte variableCon_B_
— a constant byte valueVar_w_
— a word (two-byte) variableCon_W_
— a constant word valueVar_s_
— a word variable whose value is understood as a pointer into screen memoryVar_p_
— a word variable whose value is understood as a pointer to some non-screen dataCon_P_
— a constant word value used as a pointer
And some other abbreviations, used where necessary to stop symbol names becoming too long:
Plr
— playerDfr
— defender (the player's enemies)Norm
— normal (of a defender, the blue ones)Spcl
— special (of a defender, the red ones)Expln
— explosionKbd
— keyboardJoy
— joystickInstrns
— instructions (to the player, not assembly-language or machine code instructions)_0
— suffix indicating “initial value of” or “first element of array”
Many variables also have another prefix which is the initials of the subroutine they are most associated with. E.g., the variable Var_b_INDE_Rows
is a byte variable associated with the subroutine Sub_InitNormalDfrExpln
.
;;****************************************************
;;* Used Labels *
;;****************************************************
D32_RestartFlagEQU$0071
D32_RestartVectorEQU$0072
D32_VduCursorAddrEQU$0088
D32_R_Joy_XEQU$015A
D32_R_Joy_YEQU$015B
D32_L_Joy_XEQU$015C
D32_L_Joy_YEQU$015D
D32_TextScreenEQU$0400
Loc_x000_y000EQU$0600
Loc_x000_y002EQU$0640
Loc_x044_y002EQU$064B
Loc_x080_y002EQU$0654
Loc_x124_y002EQU$065F
Loc_x000_y008EQU$0700
Loc_x072_y008EQU$0712
Loc_x116_y008EQU$071D
Loc_x028_y010EQU$0747
Loc_x092_y010EQU$0757
Loc_x000_y015EQU$07E0
Loc_x004_y015EQU$07E1
Loc_x116_y015EQU$07FD
Loc_x000_y022EQU$08C0
Loc_x116_y022EQU$08DD
Loc_x052_y023EQU$08ED
Loc_x000_y029EQU$09A0
Loc_x116_y029EQU$09BD
Loc_x000_y032EQU$0A00
Loc_x000_y035EQU$0A60
Loc_x000_y039EQU$0AE0
Loc_x048_y039EQU$0AEC
Loc_x000_y040EQU$0B00
Loc_x124_y040EQU$0B1F
Loc_x124_y041EQU$0B3F
Loc_x000_y043EQU$0B60
Loc_x124_y048EQU$0C1F
Loc_x124_y057EQU$0D3F
Loc_x124_y066EQU$0E5F
Loc_x124_y075EQU$0F7F
Loc_x124_y084EQU$109F
Loc_x124_y093EQU$11BF
Loc_x028_y100EQU$1287
Loc_x056_y100EQU$128E
Loc_x124_y102EQU$12DF
Loc_x124_y117EQU$14BF
Loc_x124_y127EQU$15FF
Loc_x124_y137EQU$173F
Loc_x124_y147EQU$187F
Loc_x124_y157EQU$19BF
Loc_x000_y175EQU$1BE0
Loc_x000_y181EQU$1CA0
Loc_x120_y181EQU$1CBE
Loc_x000_y189EQU$1DA0
Loc_x000_y191EQU$1DE0
D32_GraphicsPage5EQU$1E00
D32_ReadKbd_VecEQU$8007
D32_TextOutCharEQU$B54A
D32_TextClsEQU$BA77
D32_SndDisableEQU$BAC3
D32_TextScanKbdEQU$BBE5
D32_SysReadJoystickEQU$BD52
D32_CasMotorOffEQU$BDDC
D32_PIA_0_A_DataEQU$FF00
D32_PIA_0_B_DataEQU$FF02
D32_PIA_1_A_DataEQU$FF20
D32_PIA_1_B_DataEQU$FF22
D32_PIA_1_B_CtrlEQU$FF23
D32_SAM_Clr_V1EQU$FFC2
D32_SAM_Set_V1EQU$FFC3
D32_SAM_Clr_V2EQU$FFC4
D32_SAM_Set_V2EQU$FFC5
D32_SAM_Clr_F0EQU$FFC6
D32_SAM_Set_F0EQU$FFC7
;;****************************************************
;;* Program Code / Data Areas *
;;****************************************************
ORG$2D2D
;Sub_InitWarmReset
;Turn off cassette motor; configure for warm reset at Sub_WarmReset; jump to
;next phase of boot.
Sub_InitWarmResetJSRD32_CasMotorOff2D2DBD BD DC '...'
ORCC#$502D301A 50 '.P'
LDA#$552D3286 55 '.U'
STAD32_RestartFlag2D3497 71 '.q'
LDX#Sub_WarmReset2D368E 2D 3E '.->'
STXD32_RestartVector2D399F 72 '.r'
JMPSub_ShowIntroQryNPlayers2D3B7E 39 03 '~9.'
;Sub_WarmReset
;First instruction must be NOP to allow warm reset. Clear screen and wipe
;most code and data. (I don't know why it wipes everything; to make it
;harder to cheat?) Then enter infinite loop.
Sub_WarmResetNOP2D3E12 '.'
JSRD32_TextCls2D3FBD BA 77 '..w'
LDX#WarmRestart_WipeStart2D428E 2D 4F '.-O'
WR_L1CLR,X+2D456F 80 'o.'
CMPX#$3FFC2D478C 3F FC '.?.'
BLEWR_L12D4A2F F9 '/.'
WR_L2JMPWR_L22D4C7E 2D 4C '~-L'
WarmRestart_WipeStartFCB$09,$C0,$00,$002D4F09 C0 00 00 '....'
Var_b_MDCH_BltRowsFCB$002D5300 '.'
;TXT_Ken_Kalish
TXT_Ken_KalishFCB'K,'E,'N,'N,'E,'T,'H,'2D544B 45 4E 4E 45 54 48 20 'KENNETH '
FCB'K,'A,'L,'I,'S,'H2D5C4B 41 4C 49 53 48 'KALISH'
;GFX_SmallUnusedDefender
;This doesn't look like random unused data, but it is not used in the code.
;Maybe there was a plan to include this small defender in the game somehow.
GFX_SmallUnusedDefenderFCB$28,$282D6228 28 '(('
FCB$AA,$AA2D64AA AA '..'
FCB$0A,$A02D660A A0 '..'
FCB$22,$882D6822 88 '".'
FCB$20,$082D6A20 08 ' .'
;GFX_SpecialDefender
;A rare defender, worth more points.
GFX_SpecialDefenderFCB$03,$C02D6C03 C0 '..'
FCB$0F,$F02D6E0F F0 '..'
FCB$3C,$3C2D703C 3C '<<'
FCB$FF,$FF2D72FF FF '..'
FCB$0F,$F02D740F F0 '..'
FCB$33,$CC2D7633 CC '3.'
FCB$30,$0C2D7830 0C '0.'
;GFX_NormalDefender
;The standard defender.
GFX_NormalDefenderFCB$2A,$A82D7A2A A8 '*.'
FCB$AA,$AA2D7CAA AA '..'
FCB$88,$222D7E88 22 '."'
FCB$AA,$AA2D80AA AA '..'
FCB$2A,$A82D822A A8 '*.'
FCB$22,$882D8422 88 '".'
FCB$80,$022D8680 02 '..'
Var_b_Unused_81FCB$012D8801 '.'
Var_b_IDP_NextXVelocityFCB$012D8901 '.'
Var_b_IDP_NRemainingFCB$002D8A00 '.'
Var_b_IDP_NextKindPhaseFCB$002D8B00 '.'
;Sub_InitDefenderPatrol
;Start a new defender on a patrol across the screen.
Sub_InitDefenderPatrolLDY#Arr_DefendersData2D8C10 8E 2E B2 '....'
LDA#112D9086 0B '..'
STAVar_b_IDP_NRemaining2D92B7 2D 8A '.-.'
;Search for free slot (one with Location == 0) within Arr_DefendersData
IDP_L1LDD,Y++2D95EC A1 '..'
LDX,Y++2D97AE A1 '..'
BNEIDP_L92D9926 4E '&N'
;Found a free slot (Y points just past it); get velocity of new patrol:
;A = $01 or $FF; negate for next time so patrols alternate direction
LDAVar_b_IDP_NextXVelocity2D9BB6 2D 89 '.-.'
NEGVar_b_IDP_NextXVelocity2D9E70 2D 89 'p-.'
;phase += 1; if phase == 17...
INCVar_b_IDP_NextKindPhase2DA17C 2D 8B '|-.'
LDB#172DA4C6 11 '..'
CMPBVar_b_IDP_NextKindPhase2DA6F1 2D 8B '.-.'
BNEIDP_L22DA926 05 '&.'
;...reset phase, and turn L-to-R normal defender into special
CLRVar_b_IDP_NextKindPhase2DAB7F 2D 8B '.-.'
ORA#$402DAE8A 40 '.@'
;defender->KindAndVelocity = A (one of: $01, $41, $FF)
IDP_L2STA-$03,Y2DB0A7 3D '.='
;Compute XColumn field — clear "special" bit, leaving $01 or $BF; if L-to-R
;(KindAndVelocity is either $01 or $41), then $01 is the correct starting
;value for XColumn...
ANDA#$BF2DB284 BF '..'
;...but if we got $BF...
BPLIDP_L32DB42A 02 '*.'
;...then defender is R-to-L, so XColumn should be $1F
LDA#$1F2DB686 1F '..'
;defender->XColumn = $01 (L-to-R) or $1F (R-to-L)
IDP_L3STA-$04,Y2DB8A7 3C '.<'
;Search for patrol start location in unoccupied row
IDP_L4LDX[Var_p_IDP_LaunchLoc]2DBAAE 9F 2E 09 '....'
;Scan every other byte of row two rows down for evidence of existing
;defender (any blue or red pixel)
LEAX$40,X2DBE30 88 40 '0.@'
LDA#162DC186 10 '..'
IDP_L5LDB,X++2DC3E6 81 '..'
ANDB#$AA2DC5C4 AA '..'
BEQIDP_L62DC727 04 ''.'
;Row contains blue or red; try next patrol-start location, by using the
;"cyclically advance pointer" logic at the end of this subroutine as a
;subroutine in its own right
BSRIDP_L72DC98D 0B '..'
BRAIDP_L42DCB20 ED ' .'
;Keep looking for blue or red
IDP_L6DECA2DCD4A 'J'
BNEIDP_L52DCE26 F3 '&.'
;Scan completed without finding blue or red; we have found a suitable
;patrol-start location; store to defender->Location
LDX[Var_p_IDP_LaunchLoc]2DD0AE 9F 2E 09 '....'
STX-$02,Y2DD4AF 3E '.>'
;Cyclically advance launch-location pointer; the CMPD operand is as it is
;because the pointer lives just beyond the array into which it points
IDP_L7LDDVar_p_IDP_LaunchLoc2DD6FC 2E 09 '...'
ADDD#$00022DD9C3 00 02 '...'
CMPD#Var_p_IDP_LaunchLoc2DDC10 83 2E 09 '....'
BCSIDP_L82DE025 03 '%.'
LDDCon_P_IDP_LaunchLocs_02DE2FC 2E 0B '...'
IDP_L8STDVar_p_IDP_LaunchLoc2DE5FD 2E 09 '...'
RTS2DE839 '9'
;Continue search for free slot
IDP_L9DECVar_b_IDP_NRemaining2DE97A 2D 8A 'z-.'
BNEIDP_L12DEC26 A7 '&.'
RTS2DEE39 '9'
;Arr_Con_IDP_LaunchLocs
;Start points of patrols. They are all pointers to the last byte of a
;screen row, at various row indexes (see values as Loc_X_Y labels). A
;right-to-left defender travels along that row; a left-to-right defender
;travels along the row below.
;
;Reordering the launch rows from top to bottom gives:
;40, 48, 57, 66, 75, 84, 93, 102, 117, 127, 137, 147, 157
Arr_Con_IDP_LaunchLocsFDBLoc_x124_y0402DEF0B 1F '..'
FDBLoc_x124_y1022DF112 DF '..'
FDBLoc_x124_y1372DF317 3F '.?'
FDBLoc_x124_y0662DF50E 5F '._'
FDBLoc_x124_y0842DF710 9F '..'
FDBLoc_x124_y0932DF911 BF '..'
FDBLoc_x124_y0482DFB0C 1F '..'
FDBLoc_x124_y1172DFD14 BF '..'
FDBLoc_x124_y1572DFF19 BF '..'
FDBLoc_x124_y0752E010F 7F '..'
FDBLoc_x124_y0572E030D 3F '.?'
FDBLoc_x124_y1272E0515 FF '..'
FDBLoc_x124_y1472E0718 7F '..'
Var_p_IDP_LaunchLocFDBArr_Con_IDP_LaunchLocs2E092D EF '-.'
Con_P_IDP_LaunchLocs_0FDBArr_Con_IDP_LaunchLocs2E0B2D EF '-.'
;Sub_EndDfrPatrolStartNew
;Mark the entry of the Arr_DefendersData array immediately before the one
;pointed to by Y as unused (by setting its location field to zero), and
;launch a new patrol. (The search for an available array slot is therefore
;guaranteed to succeed because of the slot we just marked as free.)
;
;This could be considered part of Sub_MoveDefenderCheckHit; its only use
;is being tail-called from there.
Sub_EndDfrPatrolStartNewPSHSY2E0D34 20 '4 '
CLR-$02,Y2E0F6F 3E 'o>'
CLR-$01,Y2E116F 3F 'o?'
JSRSub_InitDefenderPatrol2E13BD 2D 8C '.-.'
PULSY2E1635 20 '5 '
RTS2E1839 '9'
;Sub_MoveDefenderCheckHit
;Move one defender one step. Check whether it collides with the player or
;with a player's shot. If so, award points, and initiate an explosion and
;sound effect.
;
;Arguments (data about defender being processed) in registers:
; B = struct[0] = XColumn
; A = velocity ($01 L-R, $FF R-L)
; X = struct[2:3] = Location
; U → graphics data according to kind of defender
; Y → just past struct of defender to be moved (elt of Arr_DefendersData)
; (Y is preserved)
Sub_MoveDefenderCheckHitPSHSX,A2E1934 12 '4.'
;Determine whether this defender has just started its patrol; the product of
;its XColumn and velocity will tell us this: the only product with low byte
;$01 is $01 × $01, and the only product with low byte $E1 is $1F × $FF
MUL2E1B3D '='
;If L-to-R defender at far left...
CMPB#$012E1CC1 01 '..'
;...skip hit check and erase
LBEQMDCH_L072E1E10 27 00 53 '.'.S'
;If R-to-L defender at far right...
CMPB#$E12E22C1 E1 '..'
;...skip hit check and erase
LBEQMDCH_L072E2410 27 00 4D '.'.M'
;Prepare for "erase" loop
LDA#72E2886 07 '..'
STAVar_b_MDCH_BltRows2E2AB7 2D 53 '.-S'
;Get two-byte sample within defender's bounding box — five rows down from
;top row (recall: 0=G, 1=Y, 2=B, 3=R) — in order to test whether the
;defender has been turned yellow from being hit by a player shot
LDD$00A0,X2E2DEC 89 00 A0 '....'
;If neither byte has any red or yellow pixels...
BITB#$552E31C5 55 '.U'
BNEMDCH_L012E3326 04 '&.'
BITA#$552E3585 55 '.U'
;...skip down to "erase, move, redraw" logic
BEQMDCH_L052E3727 2F ''/'
;...or, if right-hand byte has any red...
MDCH_L01ANDB#$AA2E39C4 AA '..'
;...skip down to "erase, move, redraw"
BNEMDCH_L052E3B26 2B '&+'
;Defender is drawn in yellow; it got turned yellow because it got hit by
;player shot
STXVar_s_LastDfrExpln2E3DBF 39 E0 '.9.'
;Overwrite X value on stack with zero to signal this defender gone
LDD#$00002E40CC 00 00 '...'
STD$01,S2E43ED 61 '.a'
PSHSU,Y,X2E4534 70 '4p'
;Determine what kind of defender was destroyed
LDA#12E4786 01 '..'
LDB-$03,Y2E49E6 3D '.='
BMIMDCH_L032E4B2B 0D '+.'
ANDB#$402E4DC4 40 '.@'
BNEMDCH_L022E4F26 02 '&.'
BRAMDCH_L032E5120 07 ' .'
;Special (red) defender destroyed
MDCH_L02JSRSub_InitSpclDfrExpln2E53BD 2F 74 './t'
LDA#102E5686 0A '..'
BRAMDCH_L042E5820 03 ' .'
;Normal (blue) defender destroyed
MDCH_L03JSRSub_InitNormalDfrExpln2E5ABD 2F 29 './)'
;Tasks arising from destroyed defender
MDCH_L04STAVar_b_LastDfrExplnKind2E5DB7 39 DF '.9.'
JSRSub_AwardPoints2E60BD 37 BB '.7.'
JSRSub_InitDfrExplosion2E63BD 39 E4 '.9.'
PULSU,Y,X2E6635 70 '5p'
;Erase an 8-wide, 7-high block of pixels (i.e., 2 bytes wide), with the
;top-left byte pointed to by X; this erases the defender
MDCH_L05LDD#$00002E68CC 00 00 '...'
MDCH_L06STD,X2E6BED 84 '..'
LEAX$20,X2E6D30 88 20 '0. '
DECVar_b_MDCH_BltRows2E707A 2D 53 'z-S'
BNEMDCH_L062E7326 F6 '&.'
;Retrieve location (X) and location/column increment (A); if this is an
;active slot, compute new location
MDCH_L07PULSX,A2E7535 12 '5.'
CMPX#$00002E778C 00 00 '...'
LBEQSub_EndDfrPatrolStartNew2E7A10 27 FF 8F '.'..'
LEAXA,X2E7E30 86 '0.'
;A defender moving along the top row does so at double speed; update
;location and increment in this case
CMPX#Loc_x000_y0432E808C 0B 60 '..`'
BGTMDCH_L082E832E 03 '..'
LEAXA,X2E8530 86 '0.'
ASLA2E8748 'H'
;Compute new column; if that takes the defender to or beyond the leftmost
;column, or to one beyond the rightmost column, mark this patrol as over and
;launch a new one
MDCH_L08ADDA-$04,Y2E88AB 3C '.<'
LBEQSub_EndDfrPatrolStartNew2E8A10 27 FF 7F '.'..'
LBMISub_EndDfrPatrolStartNew2E8E10 2B FF 7B '.+.{'
CMPA#$212E9281 21 '.!'
LBEQSub_EndDfrPatrolStartNew2E9410 27 FF 75 '.'.u'
;Still on screen; store new location and column to the structure, and draw
;defender in new position
STA-$04,Y2E98A7 3C '.<'
LDA#72E9A86 07 '..'
STAVar_b_MDCH_BltRows2E9CB7 2D 53 '.-S'
STX-$02,Y2E9FAF 3E '.>'
MDCH_L09LDD,X2EA1EC 84 '..'
ORA,U+2EA3AA C0 '..'
ORB,U+2EA5EA C0 '..'
STD,X2EA7ED 84 '..'
LEAX$20,X2EA930 88 20 '0. '
DECVar_b_MDCH_BltRows2EAC7A 2D 53 'z-S'
BNEMDCH_L092EAF26 F0 '&.'
RTS2EB139 '9'
;Arr_DefendersData
;Array of 11 entries each of a four-byte structure:
;
;[0] b XColumn: initially $01 L-to-R; $1F R-to-L
;[1] b KindAndVelocity: $01 L-R normal; $FF R-L normal; $41 L-R special
;[2:3] w Location
;
;Initialised by code in InitForNewGame with both byte values $01 and all
;word values $0B3F. So all structs are init'd to { $01, $01, (124, 41) }.
Arr_DefendersDataFCB$01,$01,$0C,$402EB201 01 0C 40 '...@'
FCB$00,$00,$00,$002EB600 00 00 00 '....'
FCB$00,$00,$00,$002EBA00 00 00 00 '....'
FCB$00,$00,$00,$002EBE00 00 00 00 '....'
FCB$00,$00,$00,$002EC200 00 00 00 '....'
FCB$00,$00,$00,$002EC600 00 00 00 '....'
FCB$00,$00,$00,$002ECA00 00 00 00 '....'
FCB$00,$00,$00,$002ECE00 00 00 00 '....'
FCB$00,$00,$00,$002ED200 00 00 00 '....'
FCB$00,$00,$00,$002ED600 00 00 00 '....'
FCB$00,$00,$00,$002EDA00 00 00 00 '....'
Var_b_SDM_MovePhaseFCB$0A2EDE0A '.'
Con_B_DfrMovePeriod_0FCB$0D2EDF0D '.'
Var_b_Unused_83FCB$0A2EE00A '.'
Var_b_SDM_NRemainingFCB$002EE100 '.'
;Sub_StepDfrsMovement
;If we're at the correct phase (when Var_b_SDM_Phase is 1 on entry to this
;subroutine), reset the phase to the DefenderMovementPeriod slot of the
;active player, and do one step of movement for all active defenders.
Sub_StepDfrsMovementDECVar_b_SDM_MovePhase2EE27A 2E DE 'z..'
BNESDM_L42EE526 31 '&1'
;MovePhase = active_player->DfrMvPeriod
LDUVar_p_ActivePlayerData2EE7FE 37 B9 '.7.'
LDA$01,U2EEAA6 41 '.A'
STAVar_b_SDM_MovePhase2EECB7 2E DE '...'
LDY#Arr_DefendersData2EEF10 8E 2E B2 '....'
LDA#112EF386 0B '..'
STAVar_b_SDM_NRemaining2EF5B7 2E E1 '...'
;Prepare to blt normal defender gfx; might be overridden below
SDM_L1LDU#GFX_NormalDefender2EF8CE 2D 7A '.-z'
;B = defender->XColumn
LDB,Y+2EFBE6 A0 '..'
;A = defender->KindAndVelocity
LDA,Y+2EFDA6 A0 '..'
;R-to-L normal defender?
CMPA#$012EFF81 01 '..'
BEQSDM_L22F0127 09 ''.'
;L-to-R normal defender?
CMPA#$FF2F0381 FF '..'
BEQSDM_L22F0527 05 ''.'
;Must be L-R special defender; A becomes $01
ANDA#$BF2F0784 BF '..'
;Prepare to blt special defender gfx instead
LDU#GFX_SpecialDefender2F09CE 2D 6C '.-l'
;X = defender->location
SDM_L2LDX,Y++2F0CAE A1 '..'
;If defender active (location != 0)...
BEQSDM_L32F0E27 03 ''.'
;...move it and check for collisions
JSRSub_MoveDefenderCheckHit2F10BD 2E 19 '...'
SDM_L3DECVar_b_SDM_NRemaining2F137A 2E E1 'z..'
BNESDM_L12F1626 E0 '&.'
SDM_L4RTS2F1839 '9'
Var_b_INDE_RowsFCB$002F1900 '.'
;GFX_NormalDefenderExpln
GFX_NormalDefenderExplnFCB$0F,$F02F1A0F F0 '..'
FCB$3A,$A32F1C3A A3 ':.'
FCB$E5,$5B2F1EE5 5B '.['
FCB$E9,$6B2F20E9 6B '.k'
FCB$E5,$5B2F22E5 5B '.['
FCB$3A,$A32F243A A3 ':.'
FCB$0F,$F02F260F F0 '..'
;Complement of current half-period of beep for normal defender hit
Var_b_INDE_BeepHPeriodCFCB$002F2800 '.'
;Sub_InitNormalDfrExpln
;Blt the initial "normal defender" explosion graphic to X, and play a short
;(c.60ms) chirp consisting of 48 cycles of linearly increasing period (so
;gently falling pitch).
Sub_InitNormalDfrExplnPSHSU,Y,X,D2F2934 76 '4v'
;Blt 7 rows of explosion gfx to X
LDU#GFX_NormalDefenderExpln2F2BCE 2F 1A './.'
LDA#72F2E86 07 '..'
STAVar_b_INDE_Rows2F30B7 2F 19 './.'
INDE_L1LDD,U++2F33EC C1 '..'
STD,X2F35ED 84 '..'
LEAX$20,X2F3730 88 20 '0. '
DECVar_b_INDE_Rows2F3A7A 2F 19 'z/.'
BNEINDE_L12F3D26 F4 '&.'
;Set initial half-period complement of falling-tone beep
LDB#$AF2F3FC6 AF '..'
STBVar_b_INDE_BeepHPeriodC2F41F7 2F 28 './('
;Play one cycle of tone
INDE_L2LDA#$FF2F4486 FF '..'
STAD32_PIA_1_A_Data2F46B7 FF 20 '.. '
LDBVar_b_INDE_BeepHPeriodC2F49F6 2F 28 './('
INDE_L3INCB2F4C5C '\'
BNEINDE_L32F4D26 FD '&.'
CLRD32_PIA_1_A_Data2F4F7F FF 20 '.. '
LDBVar_b_INDE_BeepHPeriodC2F52F6 2F 28 './('
INDE_L4INCB2F555C '\'
BNEINDE_L42F5626 FD '&.'
;Decrease half-period complement, thereby increasing half-period
DECVar_b_INDE_BeepHPeriodC2F587A 2F 28 'z/('
;Keep going if half-period complement is at least (in unsigned sense) $80
BMIINDE_L22F5B2B E7 '+.'
;Playing the sound takes time; no need to explicitly delay
CLRVar_b_PostDrawDelay2F5D7F 30 DE '.0.'
PULSU,Y,X,D2F6035 76 '5v'
RTS2F6239 '9'
Var_b_ISDE_RowsFCB$002F6300 '.'
;GFX_BlueYellowSparks
GFX_BlueYellowSparksFCB$0C,$502F640C 50 '.P'
FCB$CC,$552F66CC 55 '.U'
FCB$55,$CC2F6855 CC 'U.'
FCB$05,$C02F6A05 C0 '..'
FCB$0C,$502F6C0C 50 '.P'
FCB$CC,$552F6ECC 55 '.U'
FCB$C0,$052F70C0 05 '..'
Con_B_ISDE_InitPeriodFCB$822F7282 '.'
Var_b_ISDE_PeriodFCB$002F7300 '.'
;Sub_InitSpclDfrExpln
;Blt the initial "special defender" explosion graphic to X, and play two
;equal short rising-pitch chirps.
Sub_InitSpclDfrExplnPSHSU,Y,X,D2F7434 76 '4v'
;If about to draw explosion too high up screen...
CMPX#Loc_x048_y0392F768C 0A EC '...'
;...don't
BLEISDE_L22F792F 14 '/.'
;Blt 7 rows of explosion gfx to X
LDU#GFX_BlueYellowSparks2F7BCE 2F 64 './d'
LDA#72F7E86 07 '..'
STAVar_b_ISDE_Rows2F80B7 2F 63 './c'
ISDE_L1LDD,U++2F83EC C1 '..'
STD,X2F85ED 84 '..'
LEAX$20,X2F8730 88 20 '0. '
DECVar_b_ISDE_Rows2F8A7A 2F 63 'z/c'
BNEISDE_L12F8D26 F4 '&.'
;Play two chirps
ISDE_L2LDB#22F8FC6 02 '..'
ISDE_L3LDACon_B_ISDE_InitPeriod2F91B6 2F 72 './r'
STAVar_b_ISDE_Period2F94B7 2F 73 './s'
ISDE_L4LDAVar_b_ISDE_Period2F97B6 2F 73 './s'
ISDE_L5DECA2F9A4A 'J'
BNEISDE_L52F9B26 FD '&.'
COMD32_PIA_1_A_Data2F9D73 FF 20 's. '
DECVar_b_ISDE_Period2FA07A 2F 73 'z/s'
BNEISDE_L42FA326 F2 '&.'
DECB2FA55A 'Z'
BNEISDE_L32FA626 E9 '&.'
;Playing the sound takes time; no need to explicitly delay
CLRVar_b_PostDrawDelay2FA87F 30 DE '.0.'
PULSU,Y,X,D2FAB35 76 '5v'
RTS2FAD39 '9'
;GFX_Text_SHOTS
;Text "SHOTS" in red
GFX_Text_SHOTSFCB$FC,$C0,$FC,$0C,$FC2FAEFC C0 FC 0C FC '.....'
FCB$CC,$CC,$FC,$CC,$CC2FB3CC CC FC CC CC '.....'
FCB$FC,$CC,$CC,$CC,$FC2FB8FC CC CC CC FC '.....'
FCB$FC,$30,$30,$30,$302FBDFC 30 30 30 30 '.0000'
FCB$FC,$C0,$FC,$0C,$FC2FC2FC C0 FC 0C FC '.....'
FCB$FF2FC7FF '.'
;GFX_Text_SPEED
;Text "SPEED" in red
GFX_Text_SPEEDFCB$FC,$C0,$FC,$0C,$FC2FC8FC C0 FC 0C FC '.....'
FCB$FC,$CC,$FC,$C0,$C02FCDFC CC FC C0 C0 '.....'
FCB$FC,$C0,$F0,$C0,$FC2FD2FC C0 F0 C0 FC '.....'
FCB$FC,$C0,$F0,$C0,$FC2FD7FC C0 F0 C0 FC '.....'
FCB$F0,$CC,$CC,$CC,$F02FDCF0 CC CC CC F0 '.....'
FCB$FF2FE1FF '.'
;GFX_Text_SPC_1_to_5
;Text " [1-5]" in red
GFX_Text_SPC_1_to_5FCB$00,$00,$00,$00,$002FE200 00 00 00 00 '.....'
FCB$0F,$0C,$0C,$0C,$0F2FE70F 0C 0C 0C 0F '.....'
FCB$0C,$0C,$0C,$0C,$0C2FEC0C 0C 0C 0C 0C '.....'
FCB$00,$00,$3C,$00,$002FF100 00 3C 00 00 '..<..'
FCB$FC,$C0,$F0,$0C,$F02FF6FC C0 F0 0C F0 '.....'
FCB$3C,$0C,$0C,$0C,$3C2FFB3C 0C 0C 0C 3C '<...<'
FCB$FF3000FF '.'
;GFX_Text_SELECT_SPC
;Text "SELECT " in red
GFX_Text_SELECT_SPCFCB$FC,$C0,$FC,$0C,$FC3001FC C0 FC 0C FC '.....'
FCB$FC,$C0,$F0,$C0,$FC3006FC C0 F0 C0 FC '.....'
FCB$C0,$C0,$C0,$C0,$FC300BC0 C0 C0 C0 FC '.....'
FCB$FC,$C0,$F0,$C0,$FC3010FC C0 F0 C0 FC '.....'
FCB$FC,$C0,$C0,$C0,$FC3015FC C0 C0 C0 FC '.....'
FCB$FC,$30,$30,$30,$30301AFC 30 30 30 30 '.0000'
FCB$00,$00,$00,$00,$00301F00 00 00 00 00 '.....'
FCB$FF3024FF '.'
;Sub_DisplayPauseMsg
;Cycle between displaying two variants of the PAUSE text until the player
;presses something other than "P", at which point clear the message and
;resume play.
Sub_DisplayPauseMsgLDU#GFX_Text_PAUSE_Blue3025CE 30 65 '.0e'
;Check for completion of 256-iteration cycle; if done...
DPM_L1INCB30285C '\'
;...switch text colour
BEQDPM_L2302927 12 ''.'
;If no key pressed...
JSR[D32_ReadKbd_Vec]302BAD 9F 80 07 '....'
;...loop
BEQDPM_L1302F27 F7 ''.'
;...or if "p" key pressed...
CMPA#'P303181 50 '.P'
;...loop
BEQDPM_L1303327 F3 ''.'
;Exit pause: clear text from screen and resume play loop
LDX#Loc_x052_y02330358E 08 ED '...'
BSRSub_EraseSixBySix30388D 15 '..'
JMPSub_MainPlayLoop303A7E 30 DF '~0.'
;Blt text, leaving U pointing one beyond just-blt'd text
DPM_L2LDX#Loc_x052_y023303D8E 08 ED '...'
PSHSB304034 04 '4.'
JSRSub_DrawTextCharCells3042BD 37 04 '.7.'
PULSB304535 04 '5.'
;If U is just beyond second (yellow) text...
CMPU#Sub_SetGraphicsMode304711 83 30 A3 '..0.'
;...loop, resetting U to point to first (blue) text
BGESub_DisplayPauseMsg304B2C D8 ',.'
;...otherwise, loop, with U pointing to second (yellow) text
BRADPM_L1304D20 D9 ' .'
;Sub_EraseSixBySix
;Erase a 6×6 block of bytes (i.e., a 24-wide and 6-high rectangle of pixels)
;with the top-left such byte pointed to by X.
Sub_EraseSixBySixLDB#6304FC6 06 '..'
LDY#$0000305110 8E 00 00 '....'
ESBS_L1STY,X++305510 AF 81 '...'
STY,X++305810 AF 81 '...'
STY,X305B10 AF 84 '...'
LEAX$1C,X305E30 88 1C '0..'
DECB30615A 'Z'
BNEESBS_L1306226 F1 '&.'
RTS306439 '9'
;GFX_Text_PAUSE_Blue
;Text "PAUSE" in blue
GFX_Text_PAUSE_BlueFCB$0A,$08,$0A,$08,$0830650A 08 0A 08 08 '.....'
FCB$8A,$88,$8A,$08,$08306A8A 88 8A 08 08 '.....'
FCB$88,$88,$88,$88,$8A306F88 88 88 88 8A '.....'
FCB$8A,$88,$8A,$80,$8A30748A 88 8A 80 8A '.....'
FCB$8A,$08,$8A,$88,$8A30798A 08 8A 88 8A '.....'
FCB$80,$00,$00,$00,$80307E80 00 00 00 80 '.....'
FCB$FF3083FF '.'
;GFX_Text_PAUSE_Yellow
;Text "PAUSE" in yellow
GFX_Text_PAUSE_YellowFCB$05,$04,$05,$04,$04308405 04 05 04 04 '.....'
FCB$45,$44,$45,$04,$04308945 44 45 04 04 'EDE..'
FCB$44,$44,$44,$44,$45308E44 44 44 44 45 'DDDDE'
FCB$45,$44,$45,$40,$45309345 44 45 40 45 'EDE@E'
FCB$45,$04,$45,$44,$45309845 04 45 44 45 'E.EDE'
FCB$40,$00,$00,$00,$40309D40 00 00 00 40 '@...@'
FCB$FF30A2FF '.'
;Sub_SetGraphicsMode
;Configure the desired graphics mode, play an introductory sound effect,
;then chain to the subroutine which asks the player to choose settings.
;Set registers for graphics mode
Sub_SetGraphicsModeLDA#$E030A386 E0 '..'
STAD32_PIA_1_B_Data30A5B7 FF 22 '.."'
STAD32_SAM_Set_V130A8B7 FF C3 '...'
STAD32_SAM_Set_V230ABB7 FF C5 '...'
STAD32_SAM_Set_F030AEB7 FF C7 '...'
;Play sound effect
LDA#2530B186 19 '..'
STAVar_b_IntroSoundPDDelay30B3B7 30 C9 '.0.'
SGM_L1STAVar_b_PostDrawDelay30B6B7 30 DE '.0.'
JSRSub_FallingPitchBeep30B9BD 3B B4 '.
DECVar_b_IntroSoundPDDelay30BC7A 30 C9 'z0.'
LDAVar_b_IntroSoundPDDelay30BFB6 30 C9 '.0.'
CMPA#830C281 08 '..'
BNESGM_L130C426 F0 '&.'
;Chain to next phase of boot
JMPSub_QueryShotsSpeed30C67E 3D A6 '~=.'
Var_b_IntroSoundPDDelayFCB$0030C900 '.'
;Sub_SetTextMode
;Configure the VDG and SAM for text mode. Some usages, to handle an error
;condition, jump to this subroutine, which I think will terminate the game
;immediately.
;
;Unknown: Why set A to $34?
Sub_SetTextModeCLRA30CA4F 'O'
STAD32_PIA_1_B_Data30CBB7 FF 22 '.."'
STAD32_SAM_Clr_V230CEB7 FF C4 '...'
STAD32_SAM_Clr_V130D1B7 FF C2 '...'
STAD32_SAM_Clr_F030D4B7 FF C6 '...'
LDA#$3430D786 34 '.4'
RTS30D939 '9'
SWI30DA3F '?'
JMPSub_SetGraphicsMode30DB7E 30 A3 '~0.'
;Init 12; set to 0, or 14, or 25 (whence steps down to 9), or 40
Var_b_PostDrawDelayFCB$0C30DE0C '.'
;Sub_MainPlayLoop
;Infinite loop, performing all tasks for playing the game:
;
;Move all the player's shots down, checking for hitting something
;Check for keypresses moving the player or firing a player shot
;Every Nth loop, move the defender base
;Move the player, checking for collisions
;Do one step of animation of player explosion (if active)
;Play a little bit of sound
;Do one step of animation of any active defender explosions
;Do one step of animation of defender's shot hitting something
;Do one step of animation of defender's shot
;Every Nth loop, move the defenders
;Delay to keep game at proper pace
;
;In the above, "Nth" is used to denote that the action occurs once in a
;period which gets shorter as the player gets more points.
Sub_MainPlayLoopJSRSub_MovePlayerShotsDown30DFBD 32 E9 '.2.'
;If the player's ship is exploding...
TSTVar_b_PlrExplnUnderway30E27D 3C C4 '}<.'
;...do not allow the player to move the ship
LBNEMPL_L430E510 26 00 4A '.&.J'
;If key "P" pressed...
LDA#$FE30E986 FE '..'
STAD32_PIA_0_B_Data30EBB7 FF 02 '...'
LDAD32_PIA_0_A_Data30EEB6 FF 00 '...'
BITA#$1030F185 10 '..'
;...enter flashing PAUSE loop
LBEQSub_DisplayPauseMsg30F310 27 FF 2E '.'..'
;Three bytes at MPL_MovePlrFromKbd are overwritten by "JMP $4100"
;if joysticks are enabled.
;If key "right arrow" pressed...
MPL_MovePlrFromKbdLDA#$BF30F786 BF '..'
STAD32_PIA_0_B_Data30F9B7 FF 02 '...'
LDAD32_PIA_0_A_Data30FCB6 FF 00 '...'
BITA#$2030FF85 20 '. '
BNEMPL_L1310126 03 '&.'
;...update position to move right
JSRSub_MovePlayerRight3103BD 31 8E '.1.'
;If key "left arrow" pressed...
MPL_L1LDA#$DF310686 DF '..'
STAD32_PIA_0_B_Data3108B7 FF 02 '...'
LDAD32_PIA_0_A_Data310BB6 FF 00 '...'
BITA#$20310E85 20 '. '
BNEMPL_L2311026 03 '&.'
;...update position to move left
JSRSub_MovePlayerLeft3112BD 31 A9 '.1.'
;If key "down arrow" pressed...
MPL_L2LDA#$EF311586 EF '..'
STAD32_PIA_0_B_Data3117B7 FF 02 '...'
LDAD32_PIA_0_A_Data311AB6 FF 00 '...'
BITA#$20311D85 20 '. '
BNEMPL_L3311F26 03 '&.'
;...update position to move down
JSRSub_MovePlayerDown3121BD 32 6D '.2m'
;If key "up arrow" pressed...
MPL_L3LDA#$F7312486 F7 '..'
STAD32_PIA_0_B_Data3126B7 FF 02 '...'
LDAD32_PIA_0_A_Data3129B6 FF 00 '...'
BITA#$20312C85 20 '. '
BNEMPL_L4312E26 03 '&.'
;...update position to move up
JSRSub_MovePlayerUp3130BD 32 5D '.2]'
MPL_L4JSRSub_MoveDfrBaseCheckHit3133BD 33 91 '.3.'
;If key "space" pressed...
LDA#$7F313686 7F '..'
STAD32_PIA_0_B_Data3138B7 FF 02 '...'
LDAD32_PIA_0_A_Data313BB6 FF 00 '...'
ANDA#$20313E84 20 '. '
BNEMPL_L5314026 05 '&.'
;...fire player shot
JSRSub_LaunchPlayerShot3142BD 32 98 '.2.'
;...and leave flag alone
BRAMPL_L6314520 03 ' .'
;...otherwise ("space" not pressed), clear flag
MPL_L5CLRVar_b_ShotInProgress31477F 32 97 '.2.'
MPL_L6JSRSub_RedrawPlayer314ABD 31 EB '.1.'
JSRSub_StepPlayerExpln314DBD 3C C8 '.<.'
JSRSub_PlaySoundSlice3150BD 3B 6D '.
JSRSub_StepDefenderExplns3153BD 3A 3C '.:<'
JSRSub_StepDfrShotHitAnimn3156BD 34 23 '.4#'
JSRSub_StepDfrShotMovement3159BD 34 7B '.4{'
JSRSub_StepDfrsMovement315CBD 2E E2 '...'
;If a delay is required...
LDBVar_b_PostDrawDelay315FF6 30 DE '.0.'
BEQMPL_L8316227 06 ''.'
;...do so, for time proportional to Var_b_PostDrawDelay
MPL_L7DECA31644A 'J'
BNEMPL_L7316526 FD '&.'
DECB31675A 'Z'
BNEMPL_L7316826 FA '&.'
MPL_L8LDAVar_b_Init_PostDrawDelay316AB6 31 73 '.1s'
STAVar_b_PostDrawDelay316DB7 30 DE '.0.'
JMPSub_MainPlayLoop31707E 30 DF '~0.'
Var_b_Init_PostDrawDelayFCB$0E31730E '.'
Var_s_ClrLowerScreen_0FDBLoc_x000_y000317406 00 '..'
;Sub_ClearLowerScreen
;Clear from the location in Var_ClearLowerScreen_Start to the end of the
;screen, then set Var_ClearLowerScreen_Start to 5/24 down from the top of
;the screen. On boot, Var_ClearLowerScreen_Start points to the very
;top-left of the screen.
Sub_ClearLowerScreenLDXVar_s_ClrLowerScreen_03176BE 31 74 '.1t'
CLS_L1CLR,X+31796F 80 'o.'
CMPX#D32_GraphicsPage5317B8C 1E 00 '...'
BNECLS_L1317E26 F9 '&.'
LDX#Loc_x000_y04031808E 0B 00 '...'
STXVar_s_ClrLowerScreen_03183BF 31 74 '.1t'
LDX#$000131868E 00 01 '...'
CLS_L2LEAX-$01,X318930 1F '0.'
BNECLS_L2318B26 FC '&.'
RTS318D39 '9'
;Sub_MovePlayerRight
;Move the player right one half-byte, i.e., two pixels. The condition for
;no update to whole (whole + fraction == $1E) can in theory happen in two
;ways: (whole, fraction) == ($1E, $00) or ($1F, $FF). But the former will
;always happen before the latter can become true, so the rightmost the
;player can be is at ($1E, $00), i.e., in right-position with centre byte in
;column $1E.
;If player already at right-end limit of travel...
Sub_MovePlayerRightLDAVar_b_ActivePlr_Xwhole318EB6 31 E6 '.1.'
ADDAVar_b_ActivePlr_Xfrac3191BB 31 E5 '.1.'
CMPA#$1E319481 1E '..'
;...do not move (see comment above for detail)
BEQMPR_L2319627 10 ''.'
LDXVar_s_ActivePlayer3198BE 31 E7 '.1.'
;If toggling fraction results in new value being $00=right...
COMVar_b_ActivePlr_Xfrac319B73 31 E5 's1.'
;...we can leave byte-column and screen-loc as they are
BEQMPR_L1319E27 05 ''.'
;...otherwise (new value $FF=left), increase byte-column and screen-loc
LEAX$01,X31A030 01 '0.'
INCVar_b_ActivePlr_Xwhole31A27C 31 E6 '|1.'
;Other player movement subroutines jump here too
MPR_L1STXVar_s_ActivePlayer31A5BF 31 E7 '.1.'
MPR_L2RTS31A839 '9'
;Sub_MovePlayerLeft
;Move the player left one half-byte, i.e., two pixels. The condition for no
;update to whole (whole + fraction == $00) can in theory happen in two ways:
;if (whole, fraction) == ($01, $FF) or ($00, $00). But the former will
;always happen before the latter can become true, so the leftmost the player
;can be is at ($01, $FF), i.e., left-position, centre byte in column $01.
;If player already at left-end limit of travel...
Sub_MovePlayerLeftLDBVar_b_ActivePlr_Xwhole31A9F6 31 E6 '.1.'
ADDBVar_b_ActivePlr_Xfrac31ACFB 31 E5 '.1.'
;...do not move (see comment above for detail)
BEQMPR_L231AF27 F7 ''.'
LDXVar_s_ActivePlayer31B1BE 31 E7 '.1.'
;If toggling fraction results in new value being $FF=left...
COMVar_b_ActivePlr_Xfrac31B473 31 E5 's1.'
;...we can leave byte-column and screen-loc as they are
BNEMPR_L131B726 EC '&.'
;...otherwise (new value $00=right), decrease byte-column and screen-loc
LEAX-$01,X31B930 1F '0.'
DECVar_b_ActivePlr_Xwhole31BB7A 31 E6 'z1.'
BRAMPR_L131BE20 E5 ' .'
Var_b_RP_RowsFCB$0031C000 '.'
GFX_PlayerRightPosnFCB$00,$05,$4031C100 05 40 '..@'
FCB$00,$15,$5031C400 15 50 '..P'
FCB$00,$44,$4431C700 44 44 '.DD'
FCB$01,$55,$5531CA01 55 55 '.UU'
FCB$00,$15,$5031CD00 15 50 '..P'
FCB$00,$05,$4031D000 05 40 '..@'
GFX_PlayerLeftPosnFCB$00,$54,$0031D300 54 00 '.T.'
FCB$01,$55,$0031D601 55 00 '.U.'
FCB$04,$44,$4031D904 44 40 '.D@'
FCB$15,$55,$5031DC15 55 50 '.UP'
FCB$01,$55,$0031DF01 55 00 '.U.'
FCB$00,$54,$0031E200 54 00 '.T.'
;Whether player in left ($FF) or right ($00) position for its byte-column
Var_b_ActivePlr_XfracFCB$0031E500 '.'
;Byte-column of centre of three-byte-column image of player ship
Var_b_ActivePlr_XwholeFCB$0131E601 '.'
Var_s_ActivePlayerFDBLoc_x000_y03231E70A 00 '..'
Var_s_ActivePlayer_PrevFDBLoc_x000_y03231E90A 00 '..'
;Sub_RedrawPlayer
;Erase the player (checking for collision with blue/red) from previous
;location, and then redraw at current location, taking account of fractional
;position (i.e., whether at "left" or "right" position within byte).
;If the player is mid-explosion...
Sub_RedrawPlayerTSTVar_b_PlrExplnUnderway31EB7D 3C C4 '}<.'
;...skip all this
LBNERP_L531EE10 26 00 39 '.&.9'
;Prepare for erase and hit check; if player is in "left" position...
TSTVar_b_ActivePlr_Xfrac31F27D 31 E5 '}1.'
;...use "left position" ship graphic for hit-detect mask
BNERP_L631F526 35 '&5'
;...else use "right position" ship graphic
LDU#GFX_PlayerRightPosn31F7CE 31 C1 '.1.'
RP_L1JSRSub_ErasePlayerCheckHit31FABD 32 32 '.22'
;Prepare for drawing; assume "right position" ship graphic
LDU#GFX_PlayerRightPosn31FDCE 31 C1 '.1.'
;But if player is in "left" position...
TSTVar_b_ActivePlr_Xfrac32007D 31 E5 '}1.'
BEQRP_L2320327 03 ''.'
;...use "left position" ship graphic
LDU#GFX_PlayerLeftPosn3205CE 31 D3 '.1.'
;If both players have zero lives...
RP_L2LDAPlrData_0_b_NLives3208B6 37 A3 '.7.'
ADDAPlrData_1_b_NLives320BBB 37 AF '.7.'
;...do not redraw player ship
BEQRP_L5320E27 1B ''.'
;Blt (with "OR") 6 rows and 3 bytes
LDXVar_s_ActivePlayer3210BE 31 E7 '.1.'
LDA#6321386 06 '..'
STAVar_b_RP_Rows3215B7 31 C0 '.1.'
RP_L3LDA#3321886 03 '..'
RP_L4LDB,U+321AE6 C0 '..'
ORB,X321CEA 84 '..'
STB,X+321EE7 80 '..'
DECA32204A 'J'
BNERP_L4322126 F7 '&.'
LEAX$1D,X322330 88 1D '0..'
DECVar_b_RP_Rows32267A 31 C0 'z1.'
BNERP_L3322926 ED '&.'
RP_L5RTS322B39 '9'
RP_L6LDU#GFX_PlayerLeftPosn322CCE 31 D3 '.1.'
BRARP_L1322F20 C9 ' .'
Var_b_EP_RowsFCB$00323100 '.'
;Sub_ErasePlayerCheckHit
;Erase yellow from a 6-high, 3-byte-wide section of screen whose top-left
;byte is in Var_s_ActivePlayer_Prev. While doing so, use the bitmask
;pointed to by U for hit-detection against red or blue pixels. If a red
;or blue pixel is found, then this means that the player ship has crashed
;into something, and we jump to HandlePlayerCrash.
;
;I'm not fully clear on the choice of mask, because we use the mask
;corresponding to the _current_ ship position but the display-RAM address
;for the _previous_ ship position. Maybe this doesn't matter; the fact that
;defenders are byte-aligned might be relevant.
Sub_ErasePlayerCheckHitLDXVar_s_ActivePlayer_Prev3232BE 31 E9 '.1.'
;Prepare to loop over 6 rows of bitmask
LDA#6323586 06 '..'
STAVar_b_EP_Rows3237B7 32 31 '.21'
;Prepare to loop over 3 byte-columns of bitmask (12 pixels)
EPCH_L1LDA#3323A86 03 '..'
;Turn next mask byte into red/blue detect mask (recall: 0=G, 1=Y, 2=B, 3=R)
EPCH_L2LDB,U+323CE6 C0 '..'
ASLB323E58 'X'
;If the player overlaps with something red or blue...
ANDB,X323FE4 84 '..'
;...they have hit a defender or defender shot; chain to handler sub
LBNESub_HandlePlayerCrash324110 26 03 5C '.&.\'
;Mask out yellow from destination byte (Y->G, R->B)
LDB,X3245E6 84 '..'
ANDB#$AA3247C4 AA '..'
STB,X+3249E7 80 '..'
;Loop over byte-columns
DECA324B4A 'J'
BNEEPCH_L2324C26 EE '&.'
;Loop over rows
LEAX$1D,X324E30 88 1D '0..'
DECVar_b_EP_Rows32517A 32 31 'z21'
BNEEPCH_L1325426 E4 '&.'
LDXVar_s_ActivePlayer3256BE 31 E7 '.1.'
STXVar_s_ActivePlayer_Prev3259BF 31 E9 '.1.'
RTS325C39 '9'
;Sub_MovePlayerUp
;Compute screen location two rows higher
Sub_MovePlayerUpLDXVar_s_ActivePlayer325DBE 31 E7 '.1.'
LEAX-$40,X326030 88 C0 '0..'
;If proposed new location is too high up screen...
CMPX#Loc_x000_y04032638C 0B 00 '...'
;...do not store new value
LBLTMPR_L2326610 2D FF 3E '.-.>'
;...otherwise (not too high up), DO store new value
JMPMPR_L1326A7E 31 A5 '~1.'
;Sub_MovePlayerDown
;Compute screen location two rows lower
Sub_MovePlayerDownLDXVar_s_ActivePlayer326DBE 31 E7 '.1.'
LEAX$40,X327030 88 40 '0.@'
;If player is above double-stripe...
CMPX#Loc_x000_y03532738C 0A 60 '..`'
BGEMPD_L132762C 04 ',.'
;...move down six more rows to enter main play area
LEAX$0120,X327830 89 01 20 '0.. '
;If proposed new location is too low down screen...
MPD_L1CMPX#Loc_x000_y175327C8C 1B E0 '...'
;...do not store new value
LBGTMPR_L2327F10 2E FF 25 '...%'
;...otherwise (not too low down), DO store new value
JMPMPR_L132837E 31 A5 '~1.'
;Arr_PlayerShots
;State of up to five shots that the player has fired. Each shot is
;described by a 3-byte structure:
;
;[0] b Bitmask (0x10 or 0x01)
;[1:2] w ScreenLoc — location of bottom pixel of shot
;
;Bitmask is used for drawing using OR, which turns a pixel from green to
;yellow. It is also shifted left and then used (with AND) to detect when
;the shot overlaps with some blue or red.
;
;(Cleared as part of Sub_ResetShotExplnData.)
Arr_PlayerShotsFCB$00,$00,$00328600 00 00 '...'
FCB$00,$00,$00328900 00 00 '...'
FCB$00,$00,$00328C00 00 00 '...'
FCB$00,$00,$00328F00 00 00 '...'
FCB$00,$00,$00329200 00 00 '...'
Var_p_ShotPtrLimitFDBVar_p_ShotPtrLimit329532 95 '2.'
Var_b_ShotInProgressFCB$00329700 '.'
;Sub_LaunchPlayerShot
;Attempt to launch a shot from the player's ship. A free struct is sought,
;and if one is found, it is populated with the location of the new shot, and
;a bitmask for drawing it, depending on the fractional horizontal position
;of the player's ship. Also play a beep. If a shot is already being
;launched, do not launch another one, but instead prolong the beep, lowering
;its pitch.
;If a shot is already in the process of being fired...
Sub_LaunchPlayerShotLDAVar_b_ShotInProgress3298B6 32 97 '.2.'
;...do not launch another, but do (perhaps) extend sound effect
BNELPS_L3329B26 36 '&6'
;If player is above double-stripe...
LDXVar_s_ActivePlayer329DBE 31 E7 '.1.'
CMPX#Loc_x000_y04032A08C 0B 00 '...'
;...do not launch a shot — TODO check if sound still happens
BCSLPS_L332A325 2E '%.'
;Scan for available shot struct...
LDY#Arr_PlayerShots32A510 8E 32 86 '..2.'
LPS_L1LDB,Y+32A9E6 A0 '..'
LDX,Y++32ABAE A1 '..'
BNELPS_L532AD26 33 '&3'
;... leaving Y just past struct to populate
;Compute screen-loc 6 rows down, one byte to right of player's location,
;i.e., under the centre byte-column of the three-wide ship image
LDXVar_s_ActivePlayer32AFBE 31 E7 '.1.'
LEAX$00C1,X32B230 89 00 C1 '0...'
;Start by assuming right-posn shot mask...
LDA#$0132B686 01 '..'
;...but if fraction is $FF=left...
TSTVar_b_ActivePlr_Xfrac32B87D 31 E5 '}1.'
BEQLPS_L232BB27 02 ''.'
;...use left-posn mask instead
LDA#$1032BD86 10 '..'
;Store to Bitmask field of being-populated struct
LPS_L2STA-$03,Y32BFA7 3D '.='
;Draw bottom pixel of shot; rest will be drawn as it starts moving
ORA,X32C1AA 84 '..'
STA,X32C3A7 84 '..'
;Store to ScreenLoc field of being-populated struct
STX-$02,Y32C5AF 3E '.>'
;High-pitched beep
LDA#132C786 01 '..'
STAVar_b_ShotInProgress32C9B7 32 97 '.2.'
STAVar_b_ShotSoundProgress32CCB7 32 E1 '.2.'
JSRSub_FallingPitchBeep32CFBD 3B B4 '.
RTS32D239 '9'
;Extend the beep for up to five calls, lowering the pitch
LPS_L3LDAVar_b_ShotSoundProgress32D3B6 32 E1 '.2.'
CMPA#632D681 06 '..'
BEQLPS_L432D827 06 ''.'
JSRSub_FallingPitchBeep32DABD 3B B4 '.
INCVar_b_ShotSoundProgress32DD7C 32 E1 '|2.'
LPS_L4RTS32E039 '9'
;Make sound for 1,2,3,4,5 but not at 6
Var_b_ShotSoundProgressFCB$0032E100 '.'
;Loop if within bound set by max n.shots
LPS_L5CMPYVar_p_ShotPtrLimit32E210 BC 32 95 '..2.'
BLTLPS_L132E62D C1 '-.'
RTS32E839 '9'
;Sub_MovePlayerShotsDown
;Iterate over all potential player shots, processing each "active" one. A
;shot is "active" if its Location is not $0000. Processing consists of the
;following. Move down the screen. Check for collision with defender
;(patrol or base), turning that defender yellow and marking the shot slot
;"inactive" if so. Erase shot once it reaches the bottom, marking that
;array slot "inactive" if so.
Sub_MovePlayerShotsDownLDY#Arr_PlayerShots32E910 8E 32 86 '..2.'
;B = shot->Bitmask; X = shot->ScreenLoc
MPSD_L1LDB,Y+32EDE6 A0 '..'
LDX,Y++32EFAE A1 '..'
;If this shot not active, move on to next
BEQMPSD_L232F127 2F ''/'
;Erase both possible shot pixels from rows two above and one above
;current shot location
LDA-$40,X32F3A6 88 C0 '...'
ANDA#$EE32F684 EE '..'
STA-$40,X32F8A7 88 C0 '...'
LDA-$20,X32FBA6 88 E0 '...'
ANDA#$EE32FE84 EE '..'
STA-$20,X3300A7 88 E0 '...'
;Compute potential new shot location, two rows down
LEAX$40,X330330 88 40 '0.@'
;If shot has reached bottom of screen...
CMPX#Loc_x000_y18933068C 1D A0 '...'
;...it is finished with
BGEMPSD_L333092C 1E ',.'
;A = current screen byte of four pixels
LDA,X330BA6 84 '..'
;Convert drawing bitmask into red/blue detection bitmask (which will be
;either $20 for a left-posn shot or $02 for a right-posn one)
ASLB330D58 'X'
STB-$02,S330EE7 7E '.~'
;If screen byte contains red/blue at the shot's position...
BITA-$02,S3310A5 7E '.~'
;...the shot has hit a defender (or base or shot); turn defender yellow
BNEMPSD_L4331226 2C '&,'
;...else draw shot pixel into new bottom row and row above it
ORA-$03,Y3314AA 3D '.='
STA,X3316A7 84 '..'
LDA-$20,X3318A6 88 E0 '...'
ORA-$03,Y331BAA 3D '.='
STA-$20,X331DA7 88 E0 '...'
;Update shot->ScreenLoc
STX-$02,Y3320AF 3E '.>'
;Loop while more shots might be active
MPSD_L2CMPYVar_p_ShotPtrLimit332210 BC 32 95 '..2.'
BCSMPSD_L1332625 C5 '%.'
RTS332839 '9'
;Mark this array entry as unused
MPSD_L3CLR-$02,Y33296F 3E 'o>'
CLR-$01,Y332B6F 3F 'o?'
;Erase both possible shot pixels from rows one above and two above
;current shot location
LDA-$20,X332DA6 88 E0 '...'
ANDA#$EE333084 EE '..'
STA-$20,X3332A7 88 E0 '...'
LDA-$40,X3335A6 88 C0 '...'
ANDA#$EE333884 EE '..'
STA-$40,X333AA7 88 C0 '...'
;If more potential shots, process next one
BRAMPSD_L2333D20 E3 ' .'
Var_b_PSH_RowsFCB$00333F00 '.'
;Find the defender which the player's shot has hit, and turn it yellow.
;Unclear why we process 8 rows, when the flying defenders are 7 rows high
;and the base is 9 rows high.
MPSD_L4LDA#8334086 08 '..'
STAVar_b_PSH_Rows3342B7 33 3F '.3?'
PSHSX334534 10 '4.'
;Point one row higher, then test the byte one to the right of where we
;originally found the collision; if there are no defender pixels there...
LEAX-$20,X334730 88 E0 '0..'
LDB$21,X334AE6 88 21 '..!'
BNEMPSD_L5334D26 02 '&.'
;...point one byte (four pixels) to the left
LEAX-$01,X334F30 1F '0.'
;We are now pointing somewhere in the left half of the defender; scan
;upwards until the pixel above us has no blue or red (or until we are
;pointing at the row below the bottom stripe of the double stripe); we will
;then be pointing to the top-left byte of the defender
MPSD_L5LDA-$20,X3351A6 88 E0 '...'
CMPX#Loc_x000_y04033548C 0B 00 '...'
BLEMPSD_L633572F 09 '/.'
ANDA#$AA335984 AA '..'
BEQMPSD_L6335B27 05 ''.'
LEAX-$20,X335D30 88 E0 '0..'
BRAMPSD_L5336020 EF ' .'
;(Recall: bit patterns: 00=G, 01=Y, 10=B, 11=R); blue and red pixels become
;yellow; green and yellow pixels become green; this works because any set
;bits overflowing from one pixel into the one to its right get masked off
MPSD_L6LDD,X3362EC 84 '..'
LSRA336444 'D'
ANDA#$55336584 55 '.U'
LSRB336754 'T'
ANDB#$553368C4 55 '.U'
STD,X336AED 84 '..'
;Process next row up; the "ANDA #$AA; BEQ" branch above will be taken
;because of the ANDing with $55 we just did
LEAX$20,X336C30 88 20 '0. '
DECVar_b_PSH_Rows336F7A 33 3F 'z3?'
BNEMPSD_L5337226 DD '&.'
;Clear this shot and process any others
PULSX337435 10 '5.'
BRAMPSD_L3337620 B1 ' .'
;GFX_BlueDefenderBase
GFX_BlueDefenderBaseFCB$02,$00337802 00 '..'
FCB$02,$00337A02 00 '..'
FCB$0A,$80337C0A 80 '..'
FCB$02,$00337E02 00 '..'
FCB$0A,$8033800A 80 '..'
FCB$0A,$8033820A 80 '..'
FCB$2A,$A033842A A0 '*.'
FCB$AA,$A83386AA A8 '..'
FCB$AA,$A83388AA A8 '..'
Var_s_DefenderBaseFDBLoc_x000_y181338A1C A0 '..'
Con_B_BaseFirePeriod_0FCB$0D338C0D '.'
Var_b_MDBCH_MovePhaseFCB$01338D01 '.'
Var_b_Unused_86FCB$01338E01 '.'
Var_b_DfrBase_X_bytesFCB$00338F00 '.'
;Edge to spawn next defender base ($00=right, $FF=left)
Var_b_MDBCH_SpawnSideFCB$00339000 '.'
;Sub_MoveDfrBaseCheckHit
;Move the defender base and check whether it's been hit, launching the
;appropriate actions (starting new base patrol, initiating explosion and
;sound effect) if so.
Sub_MoveDfrBaseCheckHitDECVar_b_MDBCH_MovePhase33917A 33 8D 'z3.'
LBNEMDBCH_L5339410 26 00 80 '.&..'
;MovePhase = active_player->BaseMovePeriod
LDUVar_p_ActivePlayerData3398FE 37 B9 '.7.'
LDA,U339BA6 C4 '..'
STAVar_b_MDBCH_MovePhase339DB7 33 8D '.3.'
;Look for any yellow pixels in a sample of three bytes within the defender
;base bounding box (left byte six rows down; right byte six rows down; left
;byte two rows down)
LDXVar_s_DefenderBase33A0BE 33 8A '.3.'
LDA#933A386 09 '..'
LDB$00C0,X33A5E6 89 00 C0 '....'
ORB$00C1,X33A9EA 89 00 C1 '....'
ORB$40,X33ADEA 88 40 '..@'
ANDB#$5533B0C4 55 '.U'
;If no yellow, move base as normal
BEQMDBCH_L233B227 2D ''-'
;Defender base hit; record its location...
LDUVar_s_DefenderBase33B4FE 33 8A '.3.'
STUVar_s_LastDfrExpln33B7FF 39 E0 '.9.'
PSHSY,X,D33BA34 36 '46'
;...and the fact that a base was just destroyed
LDA#1233BC86 0C '..'
STAVar_b_LastDfrExplnKind33BEB7 39 DF '.9.'
;...and initiate the explosion
JSRSub_InitDfrExplosion33C1BD 39 E4 '.9.'
PULSY,X,D33C435 36 '56'
;Start by assuming defender base will spawn at left edge...
CLRVar_b_DfrBase_X_bytes33C67F 33 8F '.3.'
LDU#Loc_x000_y18133C9CE 1C A0 '...'
;...but if SpawnSide == $00 == RIGHT...
TSTVar_b_MDBCH_SpawnSide33CC7D 33 90 '}3.'
BNEMDBCH_L133CF26 08 '&.'
;...arrange to spawn at right edge instead
LDU#Loc_x120_y18133D1CE 1C BE '...'
LDA#3033D486 1E '..'
STAVar_b_DfrBase_X_bytes33D6B7 33 8F '.3.'
;Store screen-loc of to-be-spawned base
MDBCH_L1STUVar_s_DefenderBase33D9FF 33 8A '.3.'
;Get ready to spawn from other side next time
COMVar_b_MDBCH_SpawnSide33DC73 33 90 's3.'
;Erase the defender base, by clearing an 8-wide, 9-high block of pixels
;(i.e., 2 bytes wide) with the top-left byte pointed to by X; panic if this
;takes us beyond screen memory
LDA#933DF86 09 '..'
MDBCH_L2CMPX#D32_GraphicsPage533E18C 1E 00 '...'
LBGESub_SetTextMode33E410 2C FC E2 '.,..'
CLR,X+33E86F 80 'o.'
CLR,X33EA6F 84 'o.'
LEAX$1F,X33EC30 88 1F '0..'
DECA33EF4A 'J'
BNEMDBCH_L233F026 EF '&.'
;Adjust the base's location and byte-column to try to track the player's
;ship, by moving base left if player is strictly to the left of base,
;otherwise moving base right
LDXVar_s_DefenderBase33F2BE 33 8A '.3.'
LDAVar_b_DfrBase_X_bytes33F5B6 33 8F '.3.'
CMPAVar_b_ActivePlr_Xwhole33F8B1 31 E6 '.1.'
BCSMDBCH_L633FB25 1C '%.'
LEAX-$01,X33FD30 1F '0.'
DECVar_b_DfrBase_X_bytes33FF7A 33 8F 'z3.'
;Store new defender location
MDBCH_L3STXVar_s_DefenderBase3402BF 33 8A '.3.'
;Blt defender-base graphic to new location
LDU#GFX_BlueDefenderBase3405CE 33 78 '.3x'
LDA#9340886 09 '..'
MDBCH_L4LDB,U+340AE6 C0 '..'
STB,X+340CE7 80 '..'
LDB,U+340EE6 C0 '..'
STB,X3410E7 84 '..'
LEAX$1F,X341230 88 1F '0..'
DECA34154A 'J'
BNEMDBCH_L4341626 F2 '&.'
MDBCH_L5RTS341839 '9'
;Part of above; move base right if player not to our left
MDBCH_L6LEAX$01,X341930 01 '0.'
INCVar_b_DfrBase_X_bytes341B7C 33 8F '|3.'
BRAMDBCH_L3341E20 E2 ' .'
Var_s_DefenderShotFDB$0000342000 00 '..'
;0:launch shot, <0:NOP, 1:erase
Var_b_DefenderShot_StateFCB$00342200 '.'
;Sub_StepDfrShotHitAnimn
;When a defender base shot has hit something, wait three frames then draw the
;red asterisk small explosion graphic, and leave it there for a duration of
;four frames before erasing it; on the next frame, launch a new shot and
;become idle. Progression through this sequence is tracked by the variable
;Var_b_DefenderShot_State, which can acquire a non-idle state externally by:
;
; Sub_StepDfrShotMovement setting DefenderShot_State to 0 when the
; shot reaches the top of the play area, causing a new shot to be launched
;
;or
;
; Sub_InitDefenderShotHit (which is called when a hit by the defender shot
; is detected) setting DefenderShot_State to 8, causing the explosion
; sequence to run.
;
;In terms of the value of Var_b_DefenderShot_State on entry:
;
; >0 (except 5 or 1): do nothing, decrement state value
; 5: draw mini explosion; move to state 4
; 1: erase mini explosion; move to state 0
; 0: launch new shot; move to state -1
; -1: idle; do nothing; stay in state -1
;Branch according to state; if zero...
Sub_StepDfrShotHitAnimnLDAVar_b_DefenderShot_State3423B6 34 22 '.4"'
;...launch new shot
BEQSDSHA_L3342627 28 ''('
;...else if negative (in practice only ever -1), do nothing
BMISDSHA_L434282B 32 '+2'
;Move to logically "next" state; if state was 1...
DECVar_b_DefenderShot_State342A7A 34 22 'z4"'
;...erase explosion
BEQSDSHA_L5342D27 2E ''.'
;If state on entry was not 5...
CMPA#5342F81 05 '..'
;...nothing more to do
BNESDSHA_L4343126 29 '&)'
;State-on-entry 5 — draw red asterisk (bottom up)
LDXVar_s_DefenderShot3433BE 34 20 '.4 '
LDA#5343686 05 '..'
STAVar_b_DefenderShot_Rows3438B7 34 BB '.4.'
LDU#GFX_RedAsterisk343BCE 34 BC '.4.'
SDSHA_L1LDD,U++343EEC C1 '..'
CMPX#Loc_x000_y04034408C 0B 00 '...'
BLESDSHA_L234432F 02 '/.'
STD,X3445ED 84 '..'
SDSHA_L2LEAX-$20,X344730 88 E0 '0..'
DECVar_b_DefenderShot_Rows344A7A 34 BB 'z4.'
BNESDSHA_L1344D26 EF '&.'
RTS344F39 '9'
;State-on-entry 0 — launch new shot; move to state -1 (idle)
SDSHA_L3LDXVar_s_DefenderBase3450BE 33 8A '.3.'
LEAX-$60,X345330 88 A0 '0..'
STXVar_s_DefenderShot3456BF 34 20 '.4 '
DECVar_b_DefenderShot_State34597A 34 22 'z4"'
SDSHA_L4RTS345C39 '9'
;State-on-entry 1 — erase shot / asterisk (bottom up)
SDSHA_L5LDXVar_s_DefenderShot345DBE 34 20 '.4 '
LEAX$60,X346030 88 60 '0.`'
LDA#9346386 09 '..'
STAVar_b_DefenderShot_Rows3465B7 34 BB '.4.'
LDD#$00003468CC 00 00 '...'
SDSHA_L6CMPX#Loc_x000_y040346B8C 0B 00 '...'
BLESDSHA_L7346E2F 02 '/.'
STD,X3470ED 84 '..'
SDSHA_L7LEAX-$20,X347230 88 E0 '0..'
DECVar_b_DefenderShot_Rows34757A 34 BB 'z4.'
BNESDSHA_L6347826 F1 '&.'
RTS347A39 '9'
;Sub_StepDfrShotMovement
;Perform one frame of work for dealing with the shot fired by the defender
;base.
;If we are in the middle of animating the explosion caused by the defender
;base shot hitting something, do nothing
Sub_StepDfrShotMovementLDAVar_b_DefenderShot_State347BB6 34 22 '.4"'
BGESDSM_L3347E2C 30 ',0'
;Get lowest (of three) pixel of current shot; erase that pixel; check its
;original value to determine whether it is yellow, in which case it has hit
;something; see comment lower down for details of bit testing
LDXVar_s_DefenderShot3480BE 34 20 '.4 '
LDA$40,X3483A6 88 40 '..@'
TFRA,B34861F 89 '..'
ANDA#$FC348884 FC '..'
STA$40,X348AA7 88 40 '..@'
BITB#$01348DC5 01 '..'
BEQSDSM_L1348F27 04 ''.'
ANDB#$023491C4 02 '..'
BEQSub_InitDefenderShotHit349327 3B ''
;Bottom pixel of shot has not hit anything; consider moving it up one pixel
SDSM_L1LEAX-$20,X349530 88 E0 '0..'
;If this would position shot too high, launch new one...
CMPX#Loc_x000_y04034988C 0B 00 '...'
BLESDSM_L4349B2F 14 '/.'
;...otherwise record this as new location
STXVar_s_DefenderShot349DBF 34 20 '.4 '
LDA,X34A0A6 84 '..'
;Check colour of rightmost pixel in byte of proposed new location of top of
;shot (recall: 0=G, 1=Y, 2=B, 3=R); if BIT $01 is clear, pixel is 0=green
;(background) or 2=blue (normal defender) and shot can be there
BITA#$0134A285 01 '..'
BEQSDSM_L234A427 04 ''.'
;We know BIT $01 is set; if BIT $02 is clear, pixel is 1=yellow and we have
;hit something destructible (player or player shot); otherwise it is 3=red
;and the shot can be there (special defender)
BITA#$0234A685 02 '..'
BEQSub_InitDefenderShotHit34A827 26 ''&'
;Plot next pixel upwards of defender base shot by making it blue; exit
SDSM_L2LDA,X34AAA6 84 '..'
ORA#$0234AC8A 02 '..'
STA,X34AEA7 84 '..'
SDSM_L3RTS34B039 '9'
;Shot has reached double-stripe at the top of the play area; start a new one
SDSM_L4CLRVar_b_DefenderShot_State34B17F 34 22 '.4"'
CLR$20,X34B46F 88 20 'o. '
CLR$40,X34B76F 88 40 'o.@'
RTS34BA39 '9'
Var_b_DefenderShot_RowsFCB$0034BB00 '.'
;GFX_RedAsterisk
;This is drawn vertically inverted, but it is symmetrical so the result is
;the same.
GFX_RedAsteriskFCB$33,$3034BC33 30 '30'
FCB$0F,$C034BE0F C0 '..'
FCB$FF,$FC34C0FF FC '..'
FCB$0F,$C034C20F C0 '..'
FCB$33,$3034C433 30 '30'
;GFX_YellowAsterisk
;This is drawn vertically inverted, but it is symmetrical so the result is
;the same.
GFX_YellowAsteriskFCB$11,$1034C611 10 '..'
FCB$05,$4034C805 40 '.@'
FCB$55,$5434CA55 54 'UT'
FCB$05,$4034CC05 40 '.@'
FCB$11,$1034CE11 10 '..'
;Sub_InitDefenderShotHit
;Initiate the behaviour when a defender base shot hits the player or a
;player shot: Draw the yellow asterisk explosion where the defender base
;shot is, play a low beep, and set the rest of the defender base shot hit
;animation in progress via Var_b_DefenderShot_State.
;
;Argument:
; X → bottom left corner of explosion
;Write (with "OR") 5 rows of graphics data, bottom to top, ensuring we do
;not write too high on the screen
Sub_InitDefenderShotHitLDU#GFX_YellowAsterisk34D0CE 34 C6 '.4.'
LDA#534D386 05 '..'
STAVar_b_DefenderShot_Rows34D5B7 34 BB '.4.'
IDSH_L1LDD,U++34D8EC C1 '..'
ORA,X34DAAA 84 '..'
ORB$01,X34DCEA 01 '..'
CMPX#Loc_x000_y03934DE8C 0A E0 '...'
BLEIDSH_L234E12F 02 '/.'
STD,X34E3ED 84 '..'
IDSH_L2LEAX-$20,X34E530 88 E0 '0..'
DECVar_b_DefenderShot_Rows34E87A 34 BB 'z4.'
BNEIDSH_L134EB26 EB '&.'
;Low-ish pitched beep
LDA#834ED86 08 '..'
STAVar_b_DefenderShot_State34EFB7 34 22 '.4"'
JSRSub_FallingPitchBeep34F2BD 3B B4 '.
RTS34F539 '9'
Var_w_SoundPeriodLimitFDB$01F434F601 F4 '..'
Var_w_SoundPeriodIncrFDB$000434F800 04 '..'
Var_w_SoundPeriodFDB$000034FA00 00 '..'
;Sub_FlashColourSets
;Briefly flash the screen by selecting Colour Set 1 (buff, cyan, magenta,
;orange), and then falling through into Sub_LongFallPitchSound, which
;will at its end revert to Colour Set 0 (green, yellow, blue, red).
Sub_FlashColourSetsLDAD32_PIA_1_B_Data34FCB6 FF 22 '.."'
ORA#$0834FF8A 08 '..'
STAD32_PIA_1_B_Data3501B7 FF 22 '.."'
LDD#$00043504CC 00 04 '...'
STAVar_w_SoundPeriodIncr3507B7 34 F8 '.4.'
LDD#$00C8350ACC 00 C8 '...'
;Fall through...
;Sub_LongFallPitchSound
;Play a reasonably long sound of falling pitch, starting at a high pitch,
;and ending at a pitch determined by D. Before exit, select Colour Set 0.
Sub_LongFallPitchSoundSTDVar_w_SoundPeriodLimit350DFD 34 F6 '.4.'
LDD#$00023510CC 00 02 '...'
LFPS_L1STDVar_w_SoundPeriod3513FD 34 FA '.4.'
COMD32_PIA_1_A_Data351673 FF 20 's. '
LDDVar_w_SoundPeriod3519FC 34 FA '.4.'
LFPS_L2SUBD#$0001351C83 00 01 '...'
BNELFPS_L2351F26 FB '&.'
LDDVar_w_SoundPeriod3521FC 34 FA '.4.'
ADDDVar_w_SoundPeriodIncr3524F3 34 F8 '.4.'
CMPDVar_w_SoundPeriodLimit352710 B3 34 F6 '..4.'
BLTLFPS_L1352B2D E6 '-.'
;Playing the sound takes time; no need to explicitly delay
CLRVar_b_PostDrawDelay352D7F 30 DE '.0.'
;Choose Colour Set 0 (green/yellow/blue/red)
LDAD32_PIA_1_B_Data3530B6 FF 22 '.."'
ANDA#$F7353384 F7 '..'
STAD32_PIA_1_B_Data3535B7 FF 22 '.."'
RTS353839 '9'
Var_b_Unused_88FCB$00353900 '.'
;GFX_YellowExplodingPlr
;This is big enough to look OK for both values of fractional position.
GFX_YellowExplodingPlrFCB$00,$11,$44,$00353A00 11 44 00 '..D.'
FCB$01,$45,$51,$40353E01 45 51 40 '.EQ@'
FCB$05,$55,$51,$50354205 55 51 50 '.UQP'
FCB$15,$15,$54,$54354615 15 54 54 '..TT'
FCB$11,$15,$54,$44354A11 15 54 44 '..TD'
FCB$11,$45,$51,$44354E11 45 51 44 '.EQD'
FCB$04,$55,$55,$10355204 55 55 10 '.UU.'
FCB$00,$55,$55,$00355600 55 55 00 '.UU.'
Var_b_DOEPE_RowsFCB$00355A00 '.'
Var_b_DOEPE_EraseFCB$00355B00 '.'
Var_s_PlayerExplosionFDB$0000355C00 00 '..'
;Sub_DrawOrErasePlrExpln
;Either draw or erase the player explosion graphic, and (in either case)
;play a sound effect.
;
;Arguments passed in static locations:
; Var_s_PlayerExplosion = top-left byte where to draw/erase
; Var_b_PlayerExplosion_Erase = whether draw (0) or erase (non-zero)
;Erase 4 pixels above X and 4 pixels to the left of that
Sub_DrawOrErasePlrExplnLDXVar_s_PlayerExplosion355EBE 35 5C '.5\'
CLR-$20,X35616F 88 E0 'o..'
CLR-$1E,X35646F 88 E2 'o..'
;Set up to work with the 8 rows of the explosion graphic
LDU#GFX_YellowExplodingPlr3567CE 35 3A '.5:'
LDA#8356A86 08 '..'
STAVar_b_DOEPE_Rows356CB7 35 5A '.5Z'
;Assume we are going to erase...
LDD#$0000356FCC 00 00 '...'
;...but if we are meant to be drawing...
TSTVar_b_DOEPE_Erase35727D 35 5B '}5['
BNEDOEPE_L2357526 02 '&.'
;...get the next two graphics bytes instead
DOEPE_L1LDD,U++3577EC C1 '..'
;If we are too high up the screen...
DOEPE_L2CMPX#Loc_x000_y04035798C 0B 00 '...'
;...do not write anything
BLTDOEPE_L4357C2D 0B '-.'
;Write left-hand two bytes of row (either $0000 or graphics bytes)
STD,X357EED 84 '..'
;If we are meant to be drawing...
TSTVar_b_DOEPE_Erase35807D 35 5B '}5['
BNEDOEPE_L3358326 02 '&.'
;...get next two graphics bytes
LDD,U3585EC C4 '..'
;Write right-hand two bytes of row (either $0000 or graphics bytes)
DOEPE_L3STD$02,X3587ED 02 '..'
;Advance source and destination pointers (although we do not care where the
;source pointer points if we are erasing)
DOEPE_L4LEAU$02,U358933 42 '3B'
LEAX$20,X358B30 88 20 '0. '
;If that was the last row...
DECVar_b_DOEPE_Rows358E7A 35 5A 'z5Z'
;...we are done with drawing/erasing
BEQDOEPE_L5359127 07 ''.'
;...else loop, fetching next graphics bytes if drawing
TSTVar_b_DOEPE_Erase35937D 35 5B '}5['
BEQDOEPE_L1359627 DF ''.'
BRADOEPE_L2359820 DF ' .'
;Play sound effect
DOEPE_L5LDA#2359A86 02 '..'
JSRSub_FallingPitchBeep359CBD 3B B4 '.
RTS359F39 '9'
Var_b_ETLS_RowsFCB$0035A000 '.'
;Sub_HandlePlayerCrash
;Perform required tasks when the player ship is hit:
;
;Cancel other sound effects
;Launch the scattering-fragment explosion animation
;Draw and erase the explosion graphic, pulsing an orange background
;Decrement the active player's lives
;In 2-up mode, if that was the last life, switch to other player
Sub_HandlePlayerCrashPSHSU,Y,X,D35A134 76 '4v'
;Cancel any in-progress shot sound
LDA#635A386 06 '..'
STAVar_b_ShotSoundProgress35A5B7 32 E1 '.2.'
;Record that the player ship is exploding (so other subroutines know not to
;do their normal work, and to initiate the scattering fragments)
INCVar_b_PlrExplnUnderway35A87C 3C C4 '|<.'
;If the player is in right-hand position...
LDXVar_s_ActivePlayer35ABBE 31 E7 '.1.'
TSTVar_b_ActivePlr_Xfrac35AE7D 31 E5 '}1.'
BNEHPC_L135B126 02 '&.'
;...draw explosion one byte (4 pixels) to the right
LEAX$01,X35B330 01 '0.'
HPC_L1STXVar_s_LastPlayerExpln35B5BF 3C C5 '.<.'
;Flash orange; draw explosion (one byte to left of player position, to
;account for width of explosion graphic)
JSRSub_FlashColourSets35B8BD 34 FC '.4.'
CLRVar_b_DOEPE_Erase35BB7F 35 5B '.5['
LEAX-$01,X35BE30 1F '0.'
STXVar_s_PlayerExplosion35C0BF 35 5C '.5\'
JSRSub_DrawOrErasePlrExpln35C3BD 35 5E '.5^'
;Flash orange; redraw stripes in case they were damaged; play a further
;sound effect
JSRSub_FlashColourSets35C6BD 34 FC '.4.'
JSRSub_DrawTwoStripes35C9BD 36 C4 '.6.'
LDD#$012C35CCCC 01 2C '..,'
STDVar_w_SoundPeriodLimit35CFFD 34 F6 '.4.'
JSRSub_LongFallPitchSound35D2BD 35 0D '.5.'
;Erase explosion
INCVar_b_DOEPE_Erase35D57C 35 5B '|5['
JSRSub_DrawOrErasePlrExpln35D8BD 35 5E '.5^'
;active_player->NLives -= 1
LDUVar_p_ActivePlayerData35DBFE 37 B9 '.7.'
DEC$02,U35DE6A 42 'jB'
;If the active player now has no lives...
BNEHPC_L235E026 03 '&.'
;...note this fact for use when finishing explosion animation
INCVar_b_ActivePlrNoLives35E27C 3D 5B '|=['
;If neither player has any lives...
HPC_L2LDAPlrData_0_b_NLives35E5B6 37 A3 '.7.'
ADDAPlrData_1_b_NLives35E8BB 37 AF '.7.'
;...nothing more to do
BEQHPC_L535EB27 28 ''('
;If two-player mode...
TSTVar_b_TwoPlayerMode35ED7D 36 45 '}6E'
BEQHPC_L335F027 06 ''.'
;...and it was Player One who just lost a life...
CMPU#Arr_PlayerData35F211 83 37 A1 '..7.'
;...set up for getting Player Two ready (if they are not out of lives)
BEQHPC_L635F627 26 ''&'
;If Player One has run out of lives...
HPC_L3LDU#Arr_PlayerData35F8CE 37 A1 '.7.'
TST$02,U35FB6D 42 'mB'
;...try Player Two instead
BEQHPC_L635FD27 1F ''.'
;...else (i.e., Player One not out of lives) use Player One's start locn
LDX#Loc_x000_y02935FF8E 09 A0 '...'
LDA#$01360286 01 '..'
;Set up working variables with active player's data; set "active player" ptr
HPC_L4STAVar_b_ActivePlr_Xwhole3604B7 31 E6 '.1.'
STXVar_s_ActivePlayer3607BF 31 E7 '.1.'
STXVar_s_ActivePlayer_Prev360ABF 31 E9 '.1.'
STUVar_p_ActivePlayerData360DFF 37 B9 '.7.'
LDA$0B,U3610A6 4B '.K'
STAVar_b_ActivePlr_Xfrac3612B7 31 E5 '.1.'
;If two-player mode, flip which joystick will be read; I am not clear on
;how the code keeps the same joystick if the same player is going to be
;active again (e.g., if Player Two has earned an extra life)
HPC_L5JSRSub_MaybeUpdateActiveJoy3615BD 41 60 '.A`'
;Repair any damage to stripes
JSRSub_DrawTwoStripes3618BD 36 C4 '.6.'
PULSU,Y,X,D361B35 76 '5v'
RTS361D39 '9'
;If Player Two has run out of lives...
HPC_L6LDU#Arr_PlayerData_1361ECE 37 AD '.7.'
TST$02,U36216D 42 'mB'
;...try Player One instead
BEQHPC_L3362327 D3 ''.'
;...else use Player Two's start locn; active-player pointer value now in U
LDA#$1E362586 1E '..'
LDX#Loc_x116_y02936278E 09 BD '...'
BRAHPC_L4362A20 D8 ' .'
;Sub_EraseTopLivesShip
;Erase top lives display ship graphic and update top-lives-display-ship
;location.
;
;Argument:
; U → player-data structure
Sub_EraseTopLivesShipLDX$03,U362CAE 43 '.C'
LDA#7362E86 07 '..'
STAVar_b_ETLS_Rows3630B7 35 A0 '.5.'
LDD#$00003633CC 00 00 '...'
ETLS_L1STA,X3636A7 84 '..'
STD$01,X3638ED 01 '..'
LEAX$20,X363A30 88 20 '0. '
DECVar_b_ETLS_Rows363D7A 35 A0 'z5.'
BNEETLS_L1364026 F4 '&.'
STX$03,U3642AF 43 '.C'
RTS364439 '9'
Var_b_TwoPlayerModeFCB$00364500 '.'
;Sub_EndOfGame
;Reset some bits of state ready to start a new game, as follows. Mark all
;defender-explosion and player-shot structs as inactive. Prepare to launch
;new defender shot on first call to Sub_StepDfrShotHitAnimn.
Sub_EndOfGameJSRSub_ResetShotExplnData3646BD 3B DF '.
JSRSub_MaybeNewHighScore3649BD 37 2F '.7/'
LDA#3364C86 03 '..'
STAPlrData_0_b_NLives364EB7 37 A3 '.7.'
TSTVar_b_TwoPlayerMode36517D 36 45 '}6E'
BEQEOG_L1365427 03 ''.'
STAPlrData_1_b_NLives3656B7 37 AF '.7.'
;Avoid leaking stack; this sub is called from inside Sub_StepPlayerExpln
EOG_L1PULSX365935 10 '5.'
JMPSub_InitForNewGame365B7E 39 47 '~9G'
;GFX_Text_HIGH_SCORE
;Text "HIGH SCORE" in red (shares just "SCORE" in next data block)
GFX_Text_HIGH_SCOREFCB$CC,$CC,$FC,$CC,$CC365ECC CC FC CC CC '.....'
FCB$30,$30,$30,$30,$30366330 30 30 30 30 '00000'
FCB$FC,$C0,$CC,$CC,$FC3668FC C0 CC CC FC '.....'
FCB$CC,$CC,$FC,$CC,$CC366DCC CC FC CC CC '.....'
FCB$00,$00,$00,$00,$00367200 00 00 00 00 '.....'
;GFX_Text_SCORE
;Text "SCORE" in red
GFX_Text_SCOREFCB$FC,$C0,$FC,$0C,$FC3677FC C0 FC 0C FC '.....'
FCB$FC,$C0,$C0,$C0,$FC367CFC C0 C0 C0 FC '.....'
FCB$FC,$CC,$CC,$CC,$FC3681FC CC CC CC FC '.....'
FCB$FC,$CC,$FC,$F0,$CC3686FC CC FC F0 CC '.....'
FCB$FC,$C0,$F0,$C0,$FC368BFC C0 F0 C0 FC '.....'
FCB$FF3690FF '.'
;GFX_Arr_Digits
GFX_Arr_DigitsFCB$FC,$CC,$CC,$CC,$FC3691FC CC CC CC FC '.....'
FCB$30,$30,$30,$30,$30369630 30 30 30 30 '00000'
FCB$FC,$0C,$FC,$C0,$FC369BFC 0C FC C0 FC '.....'
FCB$FC,$0C,$3C,$0C,$FC36A0FC 0C 3C 0C FC '..<..'
FCB$CC,$CC,$FC,$0C,$0C36A5CC CC FC 0C 0C '.....'
FCB$FC,$C0,$F0,$0C,$F036AAFC C0 F0 0C F0 '.....'
FCB$FC,$C0,$FC,$CC,$FC36AFFC C0 FC CC FC '.....'
FCB$FC,$0C,$30,$30,$3036B4FC 0C 30 30 30 '..000'
FCB$FC,$CC,$FC,$CC,$FC36B9FC CC FC CC FC '.....'
FCB$FC,$CC,$FC,$0C,$0C36BEFC CC FC 0C 0C '.....'
Var_b_SixZerosOut_NPairsFCB$0036C300 '.'
;Sub_DrawTwoStripes
;Draw the two horizontal red strips separating the status area (top) from
;the play area (bottom). The top stripe runs along y=37 and the bottom
;along y=39.
Sub_DrawTwoStripesLDX#Loc_x000_y03936C48E 0A E0 '...'
LDA#$FF36C786 FF '..'
DTS_L1STA-$40,X36C9A7 88 C0 '...'
STA,X+36CCA7 80 '..'
CMPX#Loc_x000_y04036CE8C 0B 00 '...'
BNEDTS_L136D126 F6 '&.'
RTS36D339 '9'
;Sub_GraphicsContentsInit
;Set up the fixed parts of the display, and the starting contents for the
;various score displays. Also reset high-score.
;Ensure entire screen will be cleared shortly
Sub_GraphicsContentsInitLDX#Loc_x000_y00036D48E 06 00 '...'
STXVar_s_ClrLowerScreen_036D7BF 31 74 '.1t'
;Reset high-score to zero
LDX#$000036DA8E 00 00 '...'
STXVar_w_HighScore36DDBF 37 2C '.7,'
;Clear screen and draw stripes
JSRSub_ClearLowerScreen36E0BD 31 76 '.1v'
BSRSub_DrawTwoStripes36E38D DF '..'
;Initialise Player One score display
LDU#GFX_Text_SCORE36E5CE 36 77 '.6w'
LDX#Loc_x000_y00236E88E 06 40 '..@'
BSRSub_DrawTextCharCells36EB8D 17 '..'
BSRSub_SixZerosOut36ED8D 2C '.,'
;Initialise high-score display
LDX#Loc_x028_y01036EF8E 07 47 '..G'
LDU#GFX_Text_HIGH_SCORE36F2CE 36 5E '.6^'
BSRSub_DrawTextCharCells36F58D 0D '..'
BSRSub_SixZerosOut36F78D 22 '."'
;Initialise Player Two score display
LDX#Loc_x080_y00236F98E 06 54 '..T'
LDU#GFX_Text_SCORE36FCCE 36 77 '.6w'
BSRSub_DrawTextCharCells36FF8D 03 '..'
BSRSub_SixZerosOut37018D 18 '..'
RTS370339 '9'
;Sub_DrawTextCharCells
;Draw text, with the source bitmap data organised in runs of five bytes.
;Each such group represents one text character cell, one byte per row; so a
;4-wide 5-high block of pixels. A sequence of such cells is drawn
;horizontally, each one four pixels to the right of the previous. The end
;of the sequence is marked with a $FF byte in the source graphics data.
;
;Arguments:
; U = source graphics data
; X = location of top-left of destination
Sub_DrawTextCharCellsLDB#53704C6 05 '..'
DTCC_L1LDA,U+3706A6 C0 '..'
CMPA#$FF370881 FF '..'
BNEDTCC_L2370A26 01 '&.'
RTS370C39 '9'
DTCC_L2STA,X370DA7 84 '..'
LEAX$20,X370F30 88 20 '0. '
DECB37125A 'Z'
BNEDTCC_L1371326 F1 '&.'
LEAX$FF61,X371530 89 FF 61 '0..a'
BRASub_DrawTextCharCells371920 E9 ' .'
;Sub_SixZerosOut
;Write six zero digit text characters starting at X.
Sub_SixZerosOutLDA#3371B86 03 '..'
STAVar_b_SixZerosOut_NPairs371DB7 36 C3 '.6.'
LEAX$06,X372030 06 '0.'
SZO_L1CLRA37224F 'O'
JSRSub_TwoDigitsOut3723BD 38 3D '.8='
DECVar_b_SixZerosOut_NPairs37267A 36 C3 'z6.'
BNESZO_L1372926 F7 '&.'
RTS372B39 '9'
;Highest score yet, units of 100
Var_w_HighScoreFDB$0000372C00 00 '..'
Var_b_CHS_NFlashesLeftFCB$00372E00 '.'
;Sub_MaybeNewHighScore
;Clear the play area, then check whether the better player has achieved a
;new high score. If so, record it, update the high-score display, and
;perform an animation with sound effect.
Sub_MaybeNewHighScoreJSRSub_ClearLowerScreen372FBD 31 76 '.1v'
;Prepare to access Player One's struct; record Player One as active
LDU#Arr_PlayerData3732CE 37 A1 '.7.'
STUVar_p_ActivePlayerData3735FF 37 B9 '.7.'
;(Player One)->Score = max(PlayerOne->Score, PlayerTwo->Score)
LDX$05,U3738AE 45 '.E'
CMPX$11,U373AAC C8 11 '...'
BCCMNHS_L1373D24 05 '$.'
LDX$11,U373FAE C8 11 '...'
STX$05,U3742AF 45 '.E'
;If winning score <= high score...
MNHS_L1CMPXVar_w_HighScore3744BC 37 2C '.7,'
;...nothing more to do
BLEMNHS_L737472F 40 '/@'
;New high score — store it and write to high-score display location
STXVar_w_HighScore3749BF 37 2C '.7,'
LDX#Loc_x092_y010374C8E 07 57 '..W'
LDY#Arr_PlayerData374F10 8E 37 A1 '..7.'
JSRSub_DisplayPlayerScore3753BD 38 04 '.8.'
;Flash lines above/below high score
LDB#123756C6 0C '..'
STBVar_b_CHS_NFlashesLeft3758F7 37 2E '.7.'
;Prepare to draw red lines
LDA#$FF375B86 FF '..'
;Draw two 6-byte-wide (24-pixel-wide) lines, one above and one below the
;high-score display
MNHS_L2LDX#Loc_x072_y008375D8E 07 12 '...'
LDB#63760C6 06 '..'
MNHS_L3STA$0100,X3762A7 89 01 00 '....'
STA,X+3766A7 80 '..'
DECB37685A 'Z'
BNEMNHS_L3376926 F7 '&.'
;Toggle red/green drawing
COMA376B43 'C'
;If an even-indexed iteration...
LDBVar_b_CHS_NFlashesLeft376CF6 37 2E '.7.'
ANDB#$01376FC4 01 '..'
;...skip to delay
BEQMNHS_L4377127 05 ''.'
;...else (odd-indexed) play sound effect; there is a check inside
;Sub_InitSpclDfrExpln which skips the graphics part if X is out of
;range for the play area
JSRSub_InitSpclDfrExpln3773BD 2F 74 './t'
BRAMNHS_L6377620 0C ' .'
;Perform a short delay
MNHS_L4LDY#$3FFF377810 8E 3F FF '..?.'
MNHS_L5LEAY-$01,Y377C31 3F '1?'
CMPY#$0000377E10 8C 00 00 '....'
BNEMNHS_L5378226 F8 '&.'
;Loop for remaining flash iterations
MNHS_L6DECVar_b_CHS_NFlashesLeft37847A 37 2E 'z7.'
BNEMNHS_L2378726 D4 '&.'
MNHS_L7RTS378939 '9'
;Sub_ResetDisplayScores
;Reset both players' scores to zero, and update display to match.
;PlayerOne->Score = PlayerTwo->Score = 0
Sub_ResetDisplayScoresLDX#$0000378A8E 00 00 '...'
LDY#Arr_PlayerData378D10 8E 37 A1 '..7.'
STX$05,Y3791AF 25 '.%'
STX$11,Y3793AF A8 11 '...'
;Draw PlayerOne->Score to Player One score display location
LDXPlrData_0_s_ScoreDisplay3796BE 37 AA '.7.'
BSRSub_DisplayPlayerScore37998D 69 '.i'
;Draw PlayerOne->Score to Player Two score display location; both score are
;zero so it is OK to use Player One's score
LDXPlrData_1_s_ScoreDisplay379BBE 37 B6 '.7.'
BSRSub_DisplayPlayerScore379E8D 64 '.d'
RTS37A039 '9'
;Arr_PlayerData
;Array of two 12-byte structures, one per player.
;[0] b BaseMovePeriod — how often defender base moves
;[1] b DfrMvPeriod — how often patrolling defenders move
;[2] b NLives
;[3:4] s TopLivesShip — location of current top spare lives ship
;[5:6] w Score — in units of 100 points
;[7:8] w SpeedUpScore — score (in 100s) for next speed-up
;[9:10] s ScoreDisplay — location where score is drawn
;[11] b XFraction — $00 right posn; $FF left posn
Arr_PlayerDataFCB$0D37A10D '.'
PlrData_0_b_DfrMvPeriodFCB$0037A200 '.'
PlrData_0_b_NLivesFCB$0337A303 '.'
PlrData_0_s_TopLifeShipFDBLoc_x004_y01537A407 E1 '..'
PlrData_0_w_ScoreFDB$000037A600 00 '..'
PlrData_0_w_SpeedUpScoreFDB$000337A800 03 '..'
PlrData_0_s_ScoreDisplayFDBLoc_x044_y00237AA06 4B '.K'
PlrData_0_b_XFractionFCB$0037AC00 '.'
;This data block is 12 bytes on from block 0
Arr_PlayerData_1FCB$0D37AD0D '.'
PlrData_1_b_DfrMvPeriodFCB$0037AE00 '.'
PlrData_1_b_NLivesFCB$0337AF03 '.'
PlrData_1_s_TopLifeShipFDBLoc_x116_y01537B007 FD '..'
PlrData_1_s_ScoreFDB$000037B200 00 '..'
PlrData_1_w_SpeedUpScoreFDB$000337B400 03 '..'
PlrData_1_s_ScoreDisplayFDBLoc_x124_y00237B606 5F '._'
PlrData_1_b_XFractionFCB$FF37B8FF '.'
Var_p_ActivePlayerDataFDBArr_PlayerData37B937 A1 '7.'
;Sub_AwardPoints
;Add 100 × A points to the active player's score, and check for two
;score-driven events:
;
;If the newly-awarded points move the score over the next multiple of 10,000
;points, award an extra life (up to the maximum of the life in play plus
;three spares).
;
;If the new points move the score over the next threshold where we should
;increase the overall game speed, do so (Sub_MaybeSpeedUp)
Sub_AwardPointsLDUVar_p_ActivePlayerData37BBFE 37 B9 '.7.'
;active_player->Score[Hundreds/Thousands] += A with BCD
ADDA$06,U37BEAB 46 '.F'
DAA37C019 '.'
STA$06,U37C1A7 46 '.F'
;A = active_player->Score[Ten-Thousands/Hundred-Thousands]
LDA$05,U37C3A6 45 '.E'
;If no carry from the hundreds/thousands, no extra life possible
BCCAP_L137C524 35 '$5'
;There was a carry; add it to the ten-thousands/hundred-thousands
ADCA#$0037C789 00 '..'
DAA37C919 '.'
STA$05,U37CAA7 45 '.E'
CLRA37CC4F 'O'
;X = active_player->TopLifeShip
LDX$03,U37CDAE 43 '.C'
;A = active_player->XFraction
LDA$0B,U37CFA6 4B '.K'
;If top life-ship high enough up that there must already be three...
CMPX#Loc_x116_y00837D18C 07 1D '...'
;...no extra life possible
BLEAP_L137D42F 26 '/&'
;active_player->NLives += 1
INC$02,U37D66C 42 'lB'
;active_player->TopLifeShip -= 7 × $20
LEAX$FF20,X37D830 89 FF 20 '0.. '
STX$03,U37DCAF 43 '.C'
;Draw the new "spare life ship", preserving relevant variables
LDBVar_b_ActivePlr_Xfrac37DEF6 31 E5 '.1.'
LDUVar_s_ActivePlayer37E1FE 31 E7 '.1.'
LDYVar_s_ActivePlayer_Prev37E410 BE 31 E9 '..1.'
PSHSU,Y,B37E834 64 '4d'
STAVar_b_ActivePlr_Xfrac37EAB7 31 E5 '.1.'
JSRSub_EraseThenDrawPlayer37EDBD 39 C7 '.9.'
PULSU,Y,B37F035 64 '5d'
STBVar_b_ActivePlr_Xfrac37F2F7 31 E5 '.1.'
STUVar_s_ActivePlayer37F5FF 31 E7 '.1.'
STYVar_s_ActivePlayer_Prev37F810 BF 31 E9 '..1.'
;Extra life or not, check whether we should increase overall game speed
AP_L1BSRSub_MaybeSpeedUp37FC8D 12 '..'
;Prepare to display new score: X = active_player->ScoreDisplay
LDYVar_p_ActivePlayerData37FE10 BE 37 B9 '..7.'
LDX$09,Y3802AE 29 '.)'
;Fall through into Sub_DisplayPlayerScore...
;Sub_DisplayPlayerScore
;Draw a player's score to the screen.
;
;Arguments:
; Y → PlayerData structure; score word is at Y+5 and Y+6
; X → destination of units zero on screen
Sub_DisplayPlayerScoreCLRA38044F 'O'
BSRSub_TwoDigitsOut38058D 36 '.6'
LDA$06,Y3807A6 26 '.&'
BSRSub_TwoDigitsOut38098D 32 '.2'
LDA$05,Y380BA6 25 '.%'
BSRSub_TwoDigitsOut380D8D 2E '..'
RTS380F39 '9'
;Sub_MaybeSpeedUp
;If the active player's score has reached the next threshold for a speed
;increase for that player, do the following. Compute the new "next speed-up
;score". Speed the game up by reducing the base-move period and
;defender-move period.
Sub_MaybeSpeedUpLDUVar_p_ActivePlayerData3810FE 37 B9 '.7.'
;If active_player->Score < active_player->SpeedUpScore...
LDD$05,U3813EC 45 '.E'
CMPD$07,U381510 A3 47 '..G'
;...do nothing
BLTMSU_L338182D 22 '-"'
;Compute proposed next speed-up score
LDD$07,U381AEC 47 '.G'
CMPD#$0040381C10 83 00 40 '...@'
BLEMSU_L138202F 03 '/.'
ADDD#$00253822C3 00 25 '..%'
MSU_L1ADDD#$00103825C3 00 10 '...'
;If proposed speed-up score exceeds 15,000...
CMPD#$0150382810 83 01 50 '...P'
;...do nothing
BGTMSU_L3382C2E 0E '..'
;active_player->SpeedUpScore = proposed value
STD$07,U382EED 47 '.G'
;Decrease active_player->BaseMovePeriod but only down to 1
DEC,U38306A C4 'j.'
BNEMSU_L2383226 02 '&.'
INC,U38346C C4 'l.'
;Decrease active_player->DfrMvPeriod but only down to 1
MSU_L2DEC$01,U38366A 41 'jA'
BNEMSU_L3383826 02 '&.'
INC$01,U383A6C 41 'lA'
MSU_L3RTS383C39 '9'
;Sub_TwoDigitsOut
;Write BCD number in A to screen with the units at location X. X is left
;two less than on entry, allowing repeated calls to draw a multi-digit-pair
;number from least significant pair of digits to most.
Sub_TwoDigitsOutPSHSA383D34 02 '4.'
ANDA#$0F383F84 0F '..'
BSRSub_DigitOut38418D 0C '..'
PULSA384335 02 '5.'
ASRA384547 'G'
ASRA384647 'G'
ASRA384747 'G'
ASRA384847 'G'
ANDA#$0F384984 0F '..'
BSRSub_DigitOut384B8D 02 '..'
RTS384D39 '9'
Var_b_Unused_93FCB$00384E00 '.'
;Sub_DigitOut
;Write digit given by A to screen starting at location X. X is left one
;less than on entry, allowing repeated calls to draw a multi-digit number.
Sub_DigitOutLDB#5384FC6 05 '..'
MUL38513D '='
LDU#GFX_Arr_Digits3852CE 36 91 '.6.'
LEAUB,U385533 C5 '3.'
LDB#53857C6 05 '..'
DO_L1LDA,U+3859A6 C0 '..'
STA,X385BA7 84 '..'
LEAX$20,X385D30 88 20 '0. '
DECB38605A 'Z'
BNEDO_L1386126 F6 '&.'
LEAX$FF5F,X386330 89 FF 5F '0.._'
RTS386739 '9'
;Sub_TextOutTilPctCvtHash
;Write text to the text-mode screen, until a percent character is read.
;Hash characters are converted to carriage returns. Characters are written
;using the ROM routine.
Sub_TextOutTilPctCvtHashLDA,X+3868A6 80 '..'
CMPA#'%386A81 25 '.%'
BEQTOTPCH_L2386C27 0C ''.'
CMPA#'#386E81 23 '.#'
BNETOTPCH_L1387026 02 '&.'
LDA#$0D387286 0D '..'
TOTPCH_L1NOP387412 '.'
JSRD32_TextOutChar3875BD B5 4A '..J'
BRASub_TextOutTilPctCvtHash387820 EE ' .'
TOTPCH_L2RTS387A39 '9'
;TXT_Title
TXT_TitleFCB'#,'#,'#,'#,' ,' ,' ,'387B23 23 23 23 20 20 20 20 '#### '
FCB' ,' ,'I,'N,'V,'A,'D,'E388320 20 49 4E 56 41 44 45 ' INVADE'
FCB'R,'','S,' ,' ,'R,'E,'V388B52 27 53 20 20 52 45 56 'R'S REV'
FCB'E,'N,'G,'E,'#,'#,'%389345 4E 47 45 23 23 25 'ENGE##%'
;TXT_By
TXT_ByFCB' ,' ,' ,' ,' ,' ,' ,'389A20 20 20 20 20 20 20 20 ' '
FCB' ,' ,' ,' ,' ,' ,'B,'Y38A220 20 20 20 20 20 42 59 ' BY'
FCB'#,'%38AA23 25 '#%'
;TXT_AuthorCopyright
TXT_AuthorCopyrightFCB' ,' ,' ,' ,' ,' ,' ,'38AC20 20 20 20 20 20 20 20 ' '
FCB'K,'E,'N,'N,'E,'T,'H,'38B44B 45 4E 4E 45 54 48 20 'KENNETH '
FCB'K,'A,'L,'I,'S,'H,'#,'#38BC4B 41 4C 49 53 48 23 23 'KALISH##'
FCB'#,'#,' ,' ,' ,' ,' ,'(38C423 23 20 20 20 20 20 28 '## ('
FCB'C,'),' ,'1,'9,'8,'2,'38CC43 29 20 31 39 38 32 20 'C) 1982 '
FCB'*,' ,'M,'E,'D,' ,'S,'Y38D42A 20 4D 45 44 20 53 59 '* MED SY'
FCB'S,'T,'E,'M,'S,'%38DC53 54 45 4D 53 25 'STEMS%'
;TXT_HowManyPlayers
TXT_HowManyPlayersFCB'#,'#,'#,'#,'#,'#,' ,'38E223 23 23 23 23 23 20 20 '###### '
FCB' ,' ,' ,'S,'E,'L,'E,'C38EA20 20 20 53 45 4C 45 43 ' SELEC'
FCB'T,' ,'1,' ,'O,'R,' ,'238F254 20 31 20 4F 52 20 32 'T 1 OR 2'
FCB' ,'P,'L,'A,'Y,'E,'R,'S38FA20 50 4C 41 59 45 52 53 ' PLAYERS'
FCB'%390225 '%'
;Sub_ShowIntroQryNPlayers
;Clear the text-mode screen, write the introductory message, and play a long
;sound effect. Ask how many players and note answer, then fall through to
;next stage of boot.
;Set up and clear text-mode screen.
Sub_ShowIntroQryNPlayersLDA#$3C390386 3C '.<'
STAD32_PIA_1_B_Ctrl3905B7 FF 23 '..#'
JSRD32_TextCls3908BD BA 77 '..w'
;Write introductory message
LDX#TXT_Title390B8E 38 7B '.8{'
JSRSub_TextOutTilPctCvtHash390EBD 38 68 '.8h'
LDX#TXT_By39118E 38 9A '.8.'
JSRSub_TextOutTilPctCvtHash3914BD 38 68 '.8h'
LDX#TXT_AuthorCopyright39178E 38 AC '.8.'
JSRSub_TextOutTilPctCvtHash391ABD 38 68 '.8h'
;Play intro sound effect
LDD#$0ADF391DCC 0A DF '...'
STDVar_w_SoundPeriodLimit3920FD 34 F6 '.4.'
JSRSub_LongFallPitchSound3923BD 35 0D '.5.'
;Write "how many players" question
SIQNP_L1JSRD32_TextCls3926BD BA 77 '..w'
LDX#TXT_HowManyPlayers39298E 38 E2 '.8.'
JSRSub_TextOutTilPctCvtHash392CBD 38 68 '.8h'
JSRSub_SetTextMode392FBD 30 CA '.0.'
;Loop, reading a key, until "2" or "1"
SIQNP_L2JSR[D32_ReadKbd_Vec]3932AD 9F 80 07 '....'
CMPA#'2393681 32 '.2'
BGTSIQNP_L239382E F8 '..'
CMPA#'1393A81 31 '.1'
BCSSIQNP_L2393C25 F4 '%.'
;Convert key code into number 0 or 1...
ANDA#$03393E84 03 '..'
DECA39404A 'J'
;...and use to set state for one- or two-player mode
JSRSub_InitTwoPlayerState3941BD 41 73 '.As'
JSRSub_GraphicsContentsInit3944BD 36 D4 '.6.'
;Fall through...
;Sub_InitForNewGame
;Set up various pieces of state ready for a new game, as follows. Set up
;player data (next speed-up score, defender base move period, defender move
;period, number of lives). Set up defenders (L-R normal, row 41). Set up
;"active player" variables. Draw stack/s of "spare lives" ships.
Sub_InitForNewGameCLRVar_b_Unused_8939477F 3D 5A '.=Z'
;Init active player's X-coord-whole to 1
LDA#$01394A86 01 '..'
STAVar_b_ActivePlr_Xwhole394CB7 31 E6 '.1.'
;Set Player One as active player
LDU#Arr_PlayerData394FCE 37 A1 '.7.'
STUVar_p_ActivePlayerData3952FF 37 B9 '.7.'
;Init both players' SpeedUpScore to 3
LDD#$00033955CC 00 03 '...'
STD$07,U3958ED 47 '.G'
STD$13,U395AED C8 13 '...'
;Init both players' BaseMovePeriod to 13
LDACon_B_BaseFirePeriod_0395DB6 33 8C '.3.'
STA,U3960A7 C4 '..'
STA$0C,U3962A7 4C '.L'
;Init both players' DfrMvPeriod to 13
LDACon_B_DfrMovePeriod_03964B6 2E DF '...'
STA$01,U3967A7 41 '.A'
STA$0D,U3969A7 4D '.M'
;Init all defenders as left-to-right normal
LDD#$0101396BCC 01 01 '...'
LDX#Arr_DefendersData396E8E 2E B2 '...'
BSRSub_WriteDfrsDataWords39718D 62 '.b'
;Init all defenders' locations to $0B3F = (124, 41)
LDD#Loc_x124_y0413973CC 0B 3F '..?'
LDX#Arr_DefendersData_Loc39768E 2E B4 '...'
BSRSub_WriteDfrsDataWords39798D 5A '.Z'
;Init player lives: 0 for Player Two; 3 for Player One
CLRPlrData_1_b_NLives397B7F 37 AF '.7.'
LDA#$03397E86 03 '..'
STAPlrData_0_b_NLives3980B7 37 A3 '.7.'
;If two-player mode...
TSTVar_b_TwoPlayerMode39837D 36 45 '}6E'
;...skip to rest of Player One setup
BEQM1A_L1398627 1E ''.'
;...else, init Player Two to 3 lives too
STAPlrData_1_b_NLives3988B7 37 AF '.7.'
;...and draw their "spare lives" ships
CLRVar_b_ActivePlr_Xfrac398B7F 31 E5 '.1.'
COMVar_b_ActivePlr_Xfrac398E73 31 E5 's1.'
LDX#Loc_x116_y00839918E 07 1D '...'
STXPlrData_1_s_TopLifeShip3994BF 37 B0 '.7.'
BSRSub_EraseThenDrawPlayer39978D 2E '..'
LDX#Loc_x116_y01539998E 07 FD '...'
BSRSub_EraseThenDrawPlayer399C8D 29 '.)'
LDX#Loc_x116_y022399E8E 08 DD '...'
BSRSub_EraseThenDrawPlayer39A18D 24 '.$'
COMVar_b_ActivePlr_Xfrac39A373 31 E5 's1.'
;Draw Player One's "spare lives" ships
M1A_L1LDX#Loc_x000_y00839A68E 07 00 '...'
BSRSub_EraseThenDrawPlayer39A98D 1C '..'
LDX#Loc_x000_y02239AB8E 08 C0 '...'
BSRSub_EraseThenDrawPlayer39AE8D 17 '..'
LDX#Loc_x000_y01539B08E 07 E0 '...'
STXPlrData_0_s_TopLifeShip39B3BF 37 A4 '.7.'
BSRSub_EraseThenDrawPlayer39B68D 0F '..'
;Set up for main play loop with Player One's ship
LDX#Loc_x000_y00839B88E 07 00 '...'
STXVar_s_ActivePlayer_Prev39BBBF 31 E9 '.1.'
LDX#Loc_x000_y02939BE8E 09 A0 '...'
STXVar_s_ActivePlayer39C1BF 31 E7 '.1.'
;Chain to next phase of boot
JMPSub_SetGraphicsMode39C47E 30 A3 '~0.'
;Sub_EraseThenDrawPlayer
;Erase and redraw the player at screen address X, but using the
;x-posn-fraction value from Var_b_ActivePlayer_X_fraction
Sub_EraseThenDrawPlayerSTXVar_s_ActivePlayer39C7BF 31 E7 '.1.'
STXVar_s_ActivePlayer_Prev39CABF 31 E9 '.1.'
PSHSU39CD34 40 '4@'
JSRSub_RedrawPlayer39CFBD 31 EB '.1.'
PULSU39D235 40 '5@'
RTS39D439 '9'
;Sub_WriteDfrsDataWords
;Write D to X and then every fourth address after that (so X, X+4, X+8, ...)
;as long as the address is within the Arr_DefendersData array of structures.
Sub_WriteDfrsDataWordsSTD,X39D5ED 84 '..'
LEAX$04,X39D730 04 '0.'
CMPX#Var_b_SDM_MovePhase39D98C 2E DE '...'
BLTSub_WriteDfrsDataWords39DC2D F7 '-.'
RTS39DE39 '9'
;1=normal, 10=special, 12=base
Var_b_LastDfrExplnKindFCB$0039DF00 '.'
Var_s_LastDfrExplnFDB$000039E000 00 '..'
Var_w_Unused_87FDB$000039E200 00 '..'
;Sub_InitDfrExplosion
;Find a free slot in the Arr_DefenderExplosions array and populate it. A
;slot is "free" if its Location slot is $0000. Populated values are then:
;
; DefenderKind = 1: normal(blue) ship; 10: special(red) ship; 12: base
; AnimationFramesRemaining = 7: ship; 24: base
; Location = location of top-left byte of defender
;
;Arguments in static variables:
; Var_s_LastDestroyedDefender = Location
; Var_b_LastDefenderDestroyedKind = kind (1, 10, 12 as above)
Sub_InitDfrExplosionLDXVar_s_LastDfrExpln39E4BE 39 E0 '.9.'
LDY#Arr_DefenderExplosions39E710 8E 3A 14 '..:.'
LDA#1039EB86 0A '..'
;Search for free slot (one whose Location is $0000)
IDE_L1DECA39ED4A 'J'
BEQIDE_L239EE27 1A ''.'
LEAY$04,Y39F031 24 '1$'
LDU-$02,Y39F2EE 3E '.>'
LBNEIDE_L139F410 26 FF F5 '.&..'
;Found a free slot; populate as described above
STX-$02,Y39F8AF 3E '.>'
LDA#739FA86 07 '..'
STA-$03,Y39FCA7 3D '.='
LDAVar_b_LastDfrExplnKind39FEB6 39 DF '.9.'
STA-$04,Y3A01A7 3C '.<'
CMPA#123A0381 0C '..'
BNEIDE_L23A0526 03 '&.'
ASLA3A0748 'H'
STA-$03,Y3A08A7 3D '.='
;Unclear why we reset Var_s_LastDestroyedDefender
IDE_L2LDD#$00003A0ACC 00 00 '...'
STDVar_s_LastDfrExpln3A0DFD 39 E0 '.9.'
RTS3A1039 '9'
Var_b_SDE_PhaseFCB$023A1102 '.'
Var_b_SDE_RowsFCB$003A1200 '.'
Var_b_SDE_ExplnsFCB$003A1300 '.'
;Arr_DefenderExplosions
;Data to track defender explosions (ship or base). Up to ten explosions
;can be happening at once. Data here is 10 structs of 4 bytes each:
;
;[0] b DefenderKind
;[1] b AnimationFramesRemaining
;[2:3] w Location
;
;Slot is free if Location == $0000.
;
;Reset (all bytes cleared to $00) as part of Sub_ResetShotExplnData.
Arr_DefenderExplosionsFCB$00,$00,$00,$003A1400 00 00 00 '....'
FCB$00,$00,$00,$003A1800 00 00 00 '....'
FCB$00,$00,$00,$003A1C00 00 00 00 '....'
FCB$00,$00,$00,$003A2000 00 00 00 '....'
FCB$00,$00,$00,$003A2400 00 00 00 '....'
FCB$00,$00,$00,$003A2800 00 00 00 '....'
FCB$00,$00,$00,$003A2C00 00 00 00 '....'
FCB$00,$00,$00,$003A3000 00 00 00 '....'
FCB$00,$00,$00,$003A3400 00 00 00 '....'
FCB$00,$00,$00,$003A3800 00 00 00 '....'
;Sub_StepDefenderExplns
;Advance any animations of exploding defenders (normal/special patrolling,
;or the shooting base). Erase defender if its animation has finished.
;Leave appropriate value in PlaySoundSlice_InitHalfPeriod to get
;desired sound effect.
;Only step the animations every other call; if not in such a call...
Sub_StepDefenderExplnsDECVar_b_SDE_Phase3A3C7A 3A 11 'z:.'
;...leave screen alone, and attend just to sound effects
BNESDE_L073A3F26 70 '&p'
;...else proceed, resetting phase for next call
LDA#23A4186 02 '..'
STAVar_b_SDE_Phase3A43B7 3A 11 '.:.'
;Prepare to loop over array of explosions
LDY#Arr_DefenderExplosions3A4610 8E 3A 14 '..:.'
LDA#103A4A86 0A '..'
STAVar_b_SDE_Explns3A4CB7 3A 13 '.:.'
;If no more explosions remain to be processed...
SDE_L01DECVar_b_SDE_Explns3A4F7A 3A 13 'z:.'
;...attend to sound effects
BEQSDE_L073A5227 5D '']'
;...else (there are explosions still to process), advance Y to just past
;next explosion struct to work with
LEAY$04,Y3A5431 24 '1$'
;X = explosion->Location; if inactive...
SDE_L02LDX-$02,Y3A56AE 3E '.>'
;...skip remainder of processing
BEQSDE_L013A5827 F5 ''.'
;B = explosion->AnimationFramesRemaining (recall this starts at 7 for
;patrolling defenders and 24 for the defender base)
LDB-$03,Y3A5AE6 3D '.='
STBVar_b_SDE_HPeriodPreVal3A5CF7 3B 6B '.
;If no more frames...
DEC-$03,Y3A5F6A 3D 'j='
;...jump to "erase" logic
BMISDE_L103A612B 68 '+h'
;Prepare to blt seven rows of yellow normal defender explosion...
LDA#73A6386 07 '..'
STAVar_b_SDE_Rows3A65B7 3A 12 '.:.'
LDU#GFX_NormDfrYellow3A68CE 3A F9 '.:.'
;...but every other frame...
ANDB#$013A6BC4 01 '..'
BNESDE_L033A6D26 03 '&.'
;...use the red (with yellow eyes) explosion instead
LDU#GFX_NormDfrRedYellowEyes3A6FCE 3B 07 '.
;A = explosion->DefenderKind (1: normal(blue), 10: special(red), 12: base)
SDE_L03LDA-$04,Y3A72A6 3C '.<'
;If this explosion is for the defender base...
CMPA#123A7481 0C '..'
BNESDE_L043A7626 19 '&.'
;...we need nine rows
LDA#93A7886 09 '..'
STAVar_b_SDE_Rows3A7AB7 3A 12 '.:.'
;...and a sound param precursor of (60 - frames-remaining) AND $F6
LDA#$3C3A7D86 3C '.<'
SUBA-$03,Y3A7FA0 3D '.='
ANDA#$F63A8184 F6 '..'
STAVar_b_SDE_HPeriodPreVal3A83B7 3B 6B '.
;Assume we want the yellow-base-with-red-sparks graphic...
LDU#GFX_YellowBaseRedSparks3A86CE 3B 43 '.
;...but if this is the last frame...
TSTB3A895D ']'
BNESDE_L053A8A26 0B '&.'
;...use the red-base-with-yellow-sparks one instead
LDU#GFX_RedBaseYellowSparks3A8CCE 3B 31 '.
BRASDE_L053A8F20 06 ' .'
;Defender ship is being destroyed (A=1: normal/blue, A=10: special/red)
SDE_L04DECA3A914A 'J'
;If it is a special defender...
BEQSDE_L053A9227 03 ''.'
;...advance U to appropriate one of two special-ship-explosion graphics
LEAU$1C,U3A9433 C8 1C '3..'
;Blt the relevant number of rows of pairs of bytes (8 pixels), checking that
;we do not go outside bounds of the play area section of display memory
SDE_L05LDD,U++3A97EC C1 '..'
CMPX#Loc_x000_y1913A998C 1D E0 '...'
LBGESub_SetTextMode3A9C10 2C F6 2A '.,.*'
CMPX#Loc_x000_y0393AA08C 0A E0 '...'
BLESDE_L063AA32F 02 '/.'
STD,X3AA5ED 84 '..'
SDE_L06LEAX$20,X3AA730 88 20 '0. '
DECVar_b_SDE_Rows3AAA7A 3A 12 'z:.'
BNESDE_L053AAD26 E8 '&.'
;Loop round for next (potential) explosion
BRASDE_L013AAF20 9E ' .'
;Compute sound parameter from frame counter according to below expression; I
;did not get to the bottom of what effect this has on the sound
;
;PSS_IHP = FRMS == 0 ? 0
; : FRMS > 4 ? 2 × FRMS + 3
; ? (FRMS + 8) × 2
SDE_L07LDBVar_b_SDE_HPeriodPreVal3AB1F6 3B 6B '.
BEQSDE_L093AB427 14 ''.'
CMPB#43AB6C1 04 '..'
BLESDE_L083AB82F 07 '/.'
ASLB3ABA58 'X'
ADDB#33ABBCB 03 '..'
STBVar_b_PSS_InitHalfPeriod3ABDF7 3B 6C '.
RTS3AC039 '9'
SDE_L08ADDB#83AC1CB 08 '..'
STBVar_b_SDE_HPeriodPreVal3AC3F7 3B 6B '.
ASLB3AC658 'X'
STBVar_b_PSS_InitHalfPeriod3AC7F7 3B 6C '.
SDE_L09RTS3ACA39 '9'
;Prepare to erase explosion; assume a patrolling defender (7 rows)...
SDE_L10LDA#73ACB86 07 '..'
;...but if the defender base is exploding...
LDB#123ACDC6 0C '..'
CMPB-$04,Y3ACFE1 3C '.<'
BNESDE_L113AD126 02 '&.'
;...we need to erase 9 rows instead
LDA#93AD386 09 '..'
;Erase relevant number of rows, checking we do not go outside bounds of the
;play area section of display memory
SDE_L11STAVar_b_SDE_EraseRows3AD5B7 3A F8 '.:.'
LDD#$00003AD8CC 00 00 '...'
SDE_L12CMPX#Loc_x000_y0403ADB8C 0B 00 '...'
BLESDE_L133ADE2F 02 '/.'
STD,X3AE0ED 84 '..'
SDE_L13LEAX$20,X3AE230 88 20 '0. '
CMPX#Loc_x000_y1913AE58C 1D E0 '...'
LBGESDE_L143AE810 2C 00 05 '.,..'
DECVar_b_SDE_EraseRows3AEC7A 3A F8 'z:.'
BNESDE_L123AEF26 EA '&.'
;Mark this explosion as finished and loop back for next
SDE_L14CLR-$02,Y3AF16F 3E 'o>'
CLR-$01,Y3AF36F 3F 'o?'
JMPSDE_L013AF57E 3A 4F '~:O'
Var_b_SDE_EraseRowsFCB$003AF800 '.'
;GFX_NormDfrYellow
GFX_NormDfrYellowFCB$15,$543AF915 54 '.T'
FCB$55,$553AFB55 55 'UU'
FCB$44,$113AFD44 11 'D.'
FCB$55,$553AFF55 55 'UU'
FCB$15,$543B0115 54 '.T'
FCB$14,$143B0314 14 '..'
FCB$40,$013B0540 01 '@.'
;GFX_NormDfrRedYellowEyes
GFX_NormDfrRedYellowEyesFCB$3F,$FC3B073F FC '?.'
FCB$FF,$FF3B09FF FF '..'
FCB$DD,$773B0BDD 77 '.w'
FCB$FF,$FF3B0DFF FF '..'
FCB$3F,$FC3B0F3F FC '?.'
FCB$3C,$3C3B113C 3C '<<'
FCB$C0,$033B13C0 03 '..'
;GFX_SpclDfrYellow
GFX_SpclDfrYellowFCB$01,$403B1501 40 '.@'
FCB$05,$503B1705 50 '.P'
FCB$14,$143B1914 14 '..'
FCB$55,$553B1B55 55 'UU'
FCB$05,$503B1D05 50 '.P'
FCB$11,$443B1F11 44 '.D'
FCB$10,$043B2110 04 '..'
;GFX_SpclDfrRedYellowEyes
GFX_SpclDfrRedYellowEyesFCB$03,$C03B2303 C0 '..'
FCB$0F,$F03B250F F0 '..'
FCB$3D,$7C3B273D 7C '=|'
FCB$FF,$FF3B29FF FF '..'
FCB$0F,$F03B2B0F F0 '..'
FCB$33,$CC3B2D33 CC '3.'
FCB$30,$0C3B2F30 0C '0.'
;GFX_RedBaseYellowSparks
GFX_RedBaseYellowSparksFCB$53,$043B3153 04 'S.'
FCB$53,$043B3353 04 'S.'
FCB$1F,$D03B351F D0 '..'
FCB$13,$103B3713 10 '..'
FCB$4F,$C43B394F C4 'O.'
FCB$0F,$C03B3B0F C0 '..'
FCB$3F,$F03B3D3F F0 '?.'
FCB$FF,$FC3B3FFF FC '..'
FCB$FF,$FC3B41FF FC '..'
;GFX_YellowBaseRedSparks
GFX_YellowBaseRedSparksFCB$F1,$0C3B43F1 0C '..'
FCB$F1,$0C3B45F1 0C '..'
FCB$35,$703B4735 70 '5p'
FCB$31,$303B4931 30 '10'
FCB$C5,$7C3B4BC5 7C '.|'
FCB$05,$403B4D05 40 '.@'
FCB$15,$503B4F15 50 '.P'
FCB$55,$543B5155 54 'UT'
FCB$55,$543B5355 54 'UT'
ORG$3B67
Var_b_PSS_HalfCyclesFCB$003B6700 '.'
Var_w_Unused_84FDB$04003B6804 00 '..'
Var_b_Unused_85FCB$003B6A00 '.'
Var_b_SDE_HPeriodPreValFCB$003B6B00 '.'
Var_b_PSS_InitHalfPeriodFCB$003B6C00 '.'
;Sub_PlaySoundSlice
;Play a fragment of sound to take time proportional to PostDrawDelay. The
;initial half-period is set by B = PlaySoundSlice_InitHalfPeriod + 2.
;If B<17, this half-period is used for the whole sound-slice. If B>=17, the
;half-period increases by 1 per three half-cycles.
;
;(If PlaySoundSlice_InitHalfPeriod or PostDrawDelay is zero, do nothing.)
Sub_PlaySoundSliceLDAVar_b_PSS_InitHalfPeriod3B6DB6 3B 6C '.
BEQPSS_L53B7027 41 ''A'
LDAVar_b_PostDrawDelay3B72B6 30 DE '.0.'
BEQPSS_L53B7527 3C ''<'
;Compute approx (64)×(PostDrawDelay) into Y
LSRA3B7744 'D'
CLRB3B785F '_'
LSRA3B7944 'D'
RORB3B7A56 'V'
TFRD,Y3B7B1F 02 '..'
PSS_L1LDBVar_b_PSS_InitHalfPeriod3B7DF6 3B 6C '.
ADDB#23B80CB 02 '..'
PSS_L2TFRB,A3B821F 98 '..'
PSS_L3LEAY-$01,Y3B8431 3F '1?'
BEQPSS_L43B8627 1A ''.'
NOP3B8812 '.'
DECA3B894A 'J'
BNEPSS_L33B8A26 F8 '&.'
COMD32_PIA_1_A_Data3B8C73 FF 20 's. '
CMPB#173B8FC1 11 '..'
BLTPSS_L23B912D EF '-.'
DECVar_b_PSS_HalfCycles3B937A 3B 67 'z
BNEPSS_L23B9626 EA '&.'
LDA#33B9886 03 '..'
STAVar_b_PSS_HalfCycles3B9AB7 3B 67 '.
INCB3B9D5C '\'
BNEPSS_L23B9E26 E2 '&.'
BRAPSS_L13BA020 DB ' .'
PSS_L4LDY#$00013BA210 8E 00 01 '....'
STYVar_w_Unused_843BA610 BF 3B 68 '..
;Playing the sound takes time; no need to explicitly delay
CLRVar_b_PostDrawDelay3BAA7F 30 DE '.0.'
CLRD32_PIA_1_A_Data3BAD7F FF 20 '.. '
CLRVar_b_PSS_InitHalfPeriod3BB07F 3B 6C '.
PSS_L5RTS3BB339 '9'
;Sub_FallingPitchBeep
;Play a short beep with falling pitch. Duration set by PostDrawDelay (do
;nothing if PostDrawDelay is zero). Initial pitch set by A on entry (by
;means of half-period, so larger values of A give lower initial pitches);
;pitch then falls until duration used up.
;
;Called with values of A:
; 25 (SetGraphicsMode)
; 1 up to 5 (LaunchPlayerShot, as long as SPC held down)
; 8 (InitDefenderShotHit)
; 2 (DrawOrErasePlayerExpln)
; 1 (QueryShotsSpeed)
; 128 (InitPostDrawDelay)
Sub_FallingPitchBeepPSHSA3BB434 02 '4.'
LDAVar_b_PostDrawDelay3BB6B6 30 DE '.0.'
BEQFPB_L33BB927 1B ''.'
;Compute approx (128)×(PostDrawDelay - 4) into Y
LDB#$FF3BBBC6 FF '..'
LSRA3BBD44 'D'
SUBA#23BBE80 02 '..'
TFRD,Y3BC01F 02 '..'
;Compute (30)×(original A) into D
LDA,S3BC2A6 E4 '..'
LDB#303BC4C6 1E '..'
MUL3BC63D '='
FPB_L1INCB3BC75C '\'
TFRB,A3BC81F 98 '..'
FPB_L2LEAY-$01,Y3BCA31 3F '1?'
BEQFPB_L33BCC27 08 ''.'
DECA3BCE4A 'J'
BNEFPB_L23BCF26 F9 '&.'
COMD32_PIA_1_A_Data3BD173 FF 20 's. '
BRAFPB_L13BD420 F1 ' .'
;Playing the sound takes time; no need to explicitly delay
FPB_L3CLRVar_b_PostDrawDelay3BD67F 30 DE '.0.'
STAVar_b_Unused_823BD9B7 3B DE '.
PULSPC,A3BDC35 82 '5.'
Var_b_Unused_82FCB$003BDE00 '.'
;Sub_ResetShotExplnData
;Reset defender-explosion data and player-shot data to "all unused" state.
Sub_ResetShotExplnDataLDX#Arr_DefenderExplosions3BDF8E 3A 14 '.:.'
LDA#403BE286 28 '.('
RSED_L1CLR,X+3BE46F 80 'o.'
DECA3BE64A 'J'
BNERSED_L13BE726 FB '&.'
LDX#Arr_PlayerShots3BE98E 32 86 '.2.'
LDA#153BEC86 0F '..'
RSED_L2CLR,X+3BEE6F 80 'o.'
DECA3BF04A 'J'
BNERSED_L23BF126 FB '&.'
CLRVar_b_PSS_InitHalfPeriod3BF37F 3B 6C '.
CLRVar_b_SDE_HPeriodPreVal3BF67F 3B 6B '.
CLRVar_b_DefenderShot_State3BF97F 34 22 '.4"'
RTS3BFC39 '9'
;Arr_PlayerExplnFragments
;Array of 33 structs, each of 6 bytes, representing the tiny scattering
;explosion fragments when the player ship is hit.
;
;[0:1] w InitLocationOffset
;[2:3] s Location
;[4] b Velocity
;[5] b DrawBitmask
Arr_PlayerExplnFragmentsFCB$00,$00,$00,$00,$A0,$113BFD00 00 00 00 A0 11 '......'
FCB$00,$01,$00,$00,$80,$113C0300 01 00 00 80 11 '......'
FCB$00,$02,$00,$00,$C0,$113C0900 02 00 00 C0 11 '......'
FCB$FF,$C0,$00,$00,$A0,$443C0FFF C0 00 00 A0 44 '.....D'
FCB$FF,$BF,$00,$00,$A1,$443C15FF BF 00 00 A1 44 '.....D'
FCB$00,$20,$00,$00,$9F,$113C1B00 20 00 00 9F 11 '. ....'
FCB$00,$21,$00,$00,$81,$413C2100 21 00 00 81 41 '.!...A'
FCB$00,$22,$00,$00,$80,$413C2700 22 00 00 80 41 '."...A'
FCB$00,$A0,$00,$00,$41,$413C2D00 A0 00 00 41 41 '....AA'
FCB$00,$A1,$00,$00,$3F,$413C3300 A1 00 00 3F 41 '....?A'
FCB$00,$A2,$00,$00,$9F,$443C3900 A2 00 00 9F 44 '.....D'
FCB$00,$80,$00,$00,$01,$113C3F00 80 00 00 01 11 '......'
FCB$00,$81,$00,$00,$41,$443C4500 81 00 00 41 44 '....AD'
FCB$00,$82,$00,$00,$FF,$443C4B00 82 00 00 FF 44 '.....D'
FCB$00,$9F,$00,$00,$FF,$413C5100 9F 00 00 FF 41 '.....A'
FCB$00,$A2,$00,$00,$01,$413C5700 A2 00 00 01 41 '.....A'
FCB$00,$C0,$00,$00,$61,$413C5D00 C0 00 00 61 41 '....aA'
FCB$00,$C1,$00,$00,$7F,$113C6300 C1 00 00 7F 11 '......'
FCB$00,$C2,$00,$00,$9F,$113C6900 C2 00 00 9F 11 '......'
FCB$00,$E0,$00,$00,$60,$443C6F00 E0 00 00 60 44 '....`D'
FCB$00,$E1,$00,$00,$40,$443C7500 E1 00 00 40 44 '....@D'
FCB$00,$E2,$00,$00,$7F,$113C7B00 E2 00 00 7F 11 '......'
FCB$00,$C0,$00,$00,$20,$113C8100 C0 00 00 20 11 '.... .'
FCB$00,$C1,$00,$00,$80,$443C8700 C1 00 00 80 44 '.....D'
FCB$00,$40,$00,$00,$BF,$443C8D00 40 00 00 BF 44 '.@...D'
FCB$00,$41,$00,$00,$C1,$113C9300 41 00 00 C1 11 '.A....'
FCB$00,$42,$00,$00,$A1,$113C9900 42 00 00 A1 11 '.B....'
FCB$00,$40,$00,$00,$81,$113C9F00 40 00 00 81 11 '.@....'
FCB$00,$41,$00,$00,$9F,$113CA500 41 00 00 9F 11 '.A....'
FCB$00,$60,$00,$00,$DF,$113CAB00 60 00 00 DF 11 '.`....'
FCB$00,$61,$00,$00,$E1,$113CB100 61 00 00 E1 11 '.a....'
FCB$00,$62,$00,$00,$60,$143CB700 62 00 00 60 14 '.b..`.'
FCB$00,$C0,$00,$00,$41,$413CBD00 C0 00 00 41 41 '....AA'
Var_b_SPE_ActionPhaseFCB$0C3CC30C '.'
Var_b_PlrExplnUnderwayFCB$003CC400 '.'
Var_s_LastPlayerExplnFDB$00003CC500 00 '..'
Var_b_SPE_FragmentPhaseFCB$003CC700 '.'
;Sub_StepPlayerExpln
;If required, initiate or step the explosion animation and sound effect for
;when the player ship is hit. There is an overall flag
;Var_b_PlayerExplnUnderway, and even when this is true, the graphics are
;only updated every other call. (Although the sound effect is processed on
;every call.) Keep track of how far through the process we are in the
;Var_b_SPE_ActionPhase variable, which starts as 12 and counts down. If it
;is 12 on entry, initialise the fragments. Otherwise, if >1 on entry, move
;the fragments. Otherwise (if 1 on entry), just erase the fragments, and
;reset everything ready for the next time an explosion is needed.
;If there is no explosion underway...
Sub_StepPlayerExplnLDAVar_b_PlrExplnUnderway3CC8B6 3C C4 '.<.'
;...there is nothing for us to do
LBEQSPE_L73CCB10 27 00 8A '.'..'
;If this is a non-graphics-update call...
COMVar_b_SPE_FragmentPhase3CCF73 3C C7 's<.'
;...just attend to sound effect
BEQSPE_L53CD227 5B ''['
;Check for first call of this explosion...
DECVar_b_SPE_ActionPhase3CD47A 3C C3 'z<.'
LDA#113CD786 0B '..'
;...if not...
CMPAVar_b_SPE_ActionPhase3CD9B1 3C C3 '.<.'
;...skip the initialisation
BNESPE_L23CDC26 15 '&.'
;Initialise fragment locations:
;frag->Location = frag->InitLocationOffset + PlayerLocation
LDY#Arr_PlayerExplnFragments3CDE10 8E 3B FD '..
LDDVar_s_LastPlayerExpln3CE2FC 3C C5 '.<.'
SPE_L1LDX,Y3CE5AE A4 '..'
LEAXD,X3CE730 8B '0.'
STX$02,Y3CE9AF 22 '."'
LEAY$06,Y3CEB31 26 '1&'
CMPY#Var_b_SPE_ActionPhase3CED10 8C 3C C3 '..<.'
BLTSPE_L13CF12D F2 '-.'
;Move each explosion fragment
SPE_L2LDY#Arr_PlayerExplnFragments3CF310 8E 3B FD '..
;X = frag->Location
SPE_L3LDX$02,Y3CF7AE 22 '."'
;A = frag->Velocity; B = frag->DrawBitmask
LDD$04,Y3CF9EC 24 '.$'
;If fragment is off the screen...
CMPX#Loc_x000_y1913CFB8C 1D E0 '...'
;...skip to next fragment
BGESPE_L43CFE2C 1F ',.'
;Erase all previous yellow bits
LDB,X3D00E6 84 '..'
ANDB#$AA3D02C4 AA '..'
STB,X3D04E7 84 '..'
;If animation is finishing...
TSTVar_b_SPE_ActionPhase3D067D 3C C3 '}<.'
;...do not redraw
BEQSPE_L43D0927 14 ''.'
;B = frag->DrawBitmask
LDB$05,Y3D0BE6 25 '.%'
;Compute new location: X = frag->Location + frag->Velocity
LEAXA,X3D0D30 86 '0.'
;If new location of fragment is off bottom of screen...
CMPX#Loc_x000_y1913D0F8C 1D E0 '...'
;...skip to next fragment
BGESPE_L43D122C 0B ',.'
;If new location of fragment is off top of play area...
CMPX#Loc_x000_y0403D148C 0B 00 '...'
;...skip to next fragment
BLTSPE_L43D172D 06 '-.'
;Update frag->Location and draw yellow pixel/s
STX$02,Y3D19AF 22 '."'
ORB,X3D1BEA 84 '..'
STB,X3D1DE7 84 '..'
;Loop for next fragment
SPE_L4LEAY$06,Y3D1F31 26 '1&'
CMPY#Var_b_SPE_ActionPhase3D2110 8C 3C C3 '..<.'
BLTSPE_L33D252D D0 '-.'
;If explosion over...
TSTVar_b_SPE_ActionPhase3D277D 3C C3 '}<.'
;...set up for next one
BEQSPE_L63D2A27 0A ''.'
;The sound we're about to play will take time; do not explicitly delay
CLRVar_b_PostDrawDelay3D2C7F 30 DE '.0.'
;Play fragment of sound effect
SPE_L5LDAVar_b_SPE_ActionPhase3D2FB6 3C C3 '.<.'
JSRSub_PlayerExplnSound3D32BD 3D 60 '.=`'
RTS3D3539 '9'
;Reset state for next explosion
SPE_L6CLRVar_b_PlrExplnUnderway3D367F 3C C4 '.<.'
LDA#123D3986 0C '..'
STAVar_b_SPE_ActionPhase3D3BB7 3C C3 '.<.'
;If that was the last life the player had...
TSTVar_b_ActivePlrNoLives3D3E7D 3D 5B '}=['
BEQSPE_L73D4127 16 ''.'
;...play game-over sound for this player
CLRVar_b_ActivePlrNoLives3D437F 3D 5B '.=['
LDD#$044C3D46CC 04 4C '..L'
STDVar_w_SoundPeriodLimit3D49FD 34 F6 '.4.'
JSRSub_LongFallPitchSound3D4CBD 35 0D '.5.'
;If neither player has any lives left...
LDAPlrData_0_b_NLives3D4FB6 37 A3 '.7.'
ADDAPlrData_1_b_NLives3D52BB 37 AF '.7.'
;...that's the end of the whole game
LBEQSub_EndOfGame3D5510 27 F8 ED '.'..'
SPE_L7RTS3D5939 '9'
Var_b_Unused_89FCB$003D5A00 '.'
Var_b_ActivePlrNoLivesFCB$003D5B00 '.'
Var_b_Unused_90FCB$003D5C00 '.'
Var_b_Unused_91FCB$003D5D00 '.'
Var_b_PES_HalfPeriodFCB$003D5E00 '.'
Var_b_Unused_92FCB$043D5F04 '.'
;Sub_PlayerExplnSound
;Play repeated rising-tone chirps for a duration based on PostDrawDelay,
;with a starting period based on how far through the player explosion
;animation we are. This information is provided in A on entry, 0 <= A < 12,
;counting down every other call.
;Compute HalfPeriod = (4 × A) + 56; unclear why "+56" is expressed as "-$C8"
Sub_PlayerExplnSoundASLA3D6048 'H'
ASLA3D6148 'H'
SUBA#$C83D6280 C8 '..'
STAVar_b_PES_HalfPeriod3D64B7 3D 5E '.=^'
;Compute duration, X = min($02FF, ((128 × PostDrawDelay) + $015D))
LDAVar_b_PostDrawDelay3D67B6 30 DE '.0.'
CLRB3D6A5F '_'
LSRA3D6B44 'D'
RORB3D6C56 'V'
ADDD#$015D3D6DC3 01 5D '..]'
CMPD#$02FF3D7010 83 02 FF '....'
BHIPES_L13D7422 03 '".'
LDD#$02FF3D76CC 02 FF '...'
PES_L1TFRD,X3D791F 01 '..'
;Play chirps for duration
LDAVar_b_PES_HalfPeriod3D7BB6 3D 5E '.=^'
PES_L2TFRA,B3D7E1F 89 '..'
DECA3D804A 'J'
BNEPES_L33D8126 05 '&.'
LDAVar_b_PES_HalfPeriod3D83B6 3D 5E '.=^'
TFRA,B3D861F 89 '..'
PES_L3LEAX-$01,X3D8830 1F '0.'
BEQPES_L43D8A27 08 ''.'
DECB3D8C5A 'Z'
BNEPES_L33D8D26 F9 '&.'
COMD32_PIA_1_A_Data3D8F73 FF 20 's. '
BRAPES_L23D9220 EA ' .'
;Playing the sound takes time; no need to explicitly delay
PES_L4CLRVar_b_PostDrawDelay3D947F 30 DE '.0.'
RTS3D9739 '9'
;Sub_ResetShotsSpeed
;Set the number of shots and the speed to their default values. However,
;the opcode is inavlid — there is no "store immediate X" instruction. I
;didn't get to the bottom of this.
Sub_ResetShotsSpeedLDX#Var_p_ShotPtrLimit3D988E 32 95 '.2.'
STX#Var_p_ShotPtrLimit3D9B8F 32 95 '.2.'
LDA#143D9E86 0E '..'
STAVar_b_Init_PostDrawDelay3DA0B7 31 73 '.1s'
JMPSub_PreMainPlayLoop3DA37E 3D EA '~=.'
;Sub_QueryShotsSpeed
;Ask the player for their preferences of number of shots, and speed of
;defender movement.
;Write "SELECT SHOTS" and read player response
Sub_QueryShotsSpeedLDU#GFX_Text_SELECT_SPC3DA6CE 30 01 '.0.'
LDX#Loc_x028_y1003DA98E 12 87 '...'
JSRSub_DrawTextCharCells3DACBD 37 04 '.7.'
LDU#GFX_Text_SHOTS3DAFCE 2F AE './.'
JSRSub_ReadKbd_1_5_R3DB2BD 3D FD '.=.'
;If player pressed return...
CMPA#$0D3DB581 0D '..'
;...leave settings as previously (or default)
BEQSub_PreMainPlayLoop3DB727 31 ''1'
;If player pressed "R"...
CMPA#$523DB981 52 '.R'
;...restart at "how many players?" question
LBEQSIQNP_L13DBB10 27 FB 67 '.'.g'
;Compute upper bound on valid initial segment of shots array:
; ShotPtrLimit = (ShotPtrLimit for 5 shots) - 3 × (5 - nShots)
;where the 3 is sizeof(PlayerShot struct) in Arr_PlayerShots
SUBA#53DBF80 05 '..'
PSHSA3DC134 02 '4.'
ADDA,S3DC3AB E4 '..'
ADDA,S+3DC5AB E0 '..'
LDX#Var_p_ShotPtrLimit3DC78E 32 95 '.2.'
LEAXA,X3DCA30 86 '0.'
STXVar_p_ShotPtrLimit3DCCBF 32 95 '.2.'
;Play quite long high-pitched beep
LDA#403DCF86 28 '.('
STAVar_b_PostDrawDelay3DD1B7 30 DE '.0.'
LDA#13DD486 01 '..'
JSRSub_FallingPitchBeep3DD6BD 3B B4 '.
;Write "SELECT SPEED" and read player response
LDU#GFX_Text_SPEED3DD9CE 2F C8 './.'
JSRSub_ReadKbd_1_5_R3DDCBD 3D FD '.=.'
;If player pressed return...
CMPA#$0D3DDF81 0D '..'
;...leave setting as previously (or default)
BEQSub_PreMainPlayLoop3DE127 07 ''.'
;Compute delay value from chosen speed:
; Init_PostDrawDelay = 20 - 2 × (speed) = 18,16,14,12,10
ASLA3DE348 'H'
NEGA3DE440 '@'
ADDA#203DE58B 14 '..'
STAVar_b_Init_PostDrawDelay3DE7B7 31 73 '.1s'
;Fall through...
;Sub_PreMainPlayLoop
;Play sound effect; set up screen and score displays.
;The value of $80 (-128) passed (in A) to FallingPitchBeep has the same
;effect as A=0 would have; not sure why $80 used
Sub_PreMainPlayLoopLDA#403DEA86 28 '.('
STAVar_b_PostDrawDelay3DECB7 30 DE '.0.'
LDA#1283DEF86 80 '..'
JSRSub_FallingPitchBeep3DF1BD 3B B4 '.
JSRSub_ClearLowerScreen3DF4BD 31 76 '.1v'
JSRSub_ResetDisplayScores3DF7BD 37 8A '.7.'
JMPSub_MainPlayLoop3DFA7E 30 DF '~0.'
;Sub_ReadKbd_1_5_R
;Write a question to the screen, then loop until timeout or until one of
;"Return", "R", or "1"–"5" keys is pressed by user. Return (in A):
;
; $0D if "Return" pressed
; $52 if "R" pressed
; $01–$05 if "1"–"5" pressed
;
;If timeout, do not return; instead jump to Sub_ResetShotsSpeed.
;
;Argument:
; U → graphical text characters to print as question
;Write first part of message (as passed in, pointed to by U) to screen
Sub_ReadKbd_1_5_RLDX#Loc_x056_y1003DFD8E 12 8E '...'
JSRSub_DrawTextCharCells3E00BD 37 04 '.7.'
;Write message suffix " [1-5]"
LDU#GFX_Text_SPC_1_to_53E03CE 2F E2 './.'
JSRSub_DrawTextCharCells3E06BD 37 04 '.7.'
;Prepare to loop, polling keyboard, until either we get a valid input,
;or until we time out
LDU#$00003E09CE 00 00 '...'
LDX#$C0003E0C8E C0 00 '...'
RK15_L1JSR[D32_ReadKbd_Vec]3E0FAD 9F 80 07 '....'
LEAU-$01,U3E1333 5F '3_'
BNERK15_L23E1526 06 '&.'
;Inner loop finished; if we should time out...
LEAX-$01,X3E1730 1F '0.'
;...reset game parameters to default and proceed with play
LBEQSub_ResetShotsSpeed3E1910 27 FF 7B '.'.{'
;If there was no keypress...
RK15_L2TSTA3E1D4D 'M'
;...loop
BEQRK15_L13E1E27 EF ''.'
;If keypress was "return"...
CMPA#$0D3E2081 0D '..'
BEQRK15_L33E2227 0E ''.'
;...or "R"...
CMPA#$523E2481 52 '.R'
;...return that keycode to caller
BEQRK15_L33E2627 0A ''.'
;If keypress was NOT a digit key from "1" up to "5", loop
CMPA#$313E2881 31 '.1'
BLTRK15_L13E2A2D E3 '-.'
CMPA#$353E2C81 35 '.5'
BGTRK15_L13E2E2E DF '..'
;Map keypress "1" to "5" to value $01 to $05 and return it
ANDA#$0F3E3084 0F '..'
RK15_L3RTS3E3239 '9'
ORG$408D
;Sub_InitialEntryPoint
;Startup location for whole program. Ask whether joysticks should be used,
;set state (and maybe self-modify code) accordingly, then chain to next
;stage of boot.
Sub_InitialEntryPointBSRSub_ResetScreen408D8D 2E '..'
;Display "joysticks?" question
LDX#TXT_JoysticksQuestion408F8E 40 DD '.@.'
BSRSub_TextOutTilNulCvtPct40928D 39 '.9'
;Loop, reading key until either "N", in which case jump to next phase of
;boot, or "Y", in which case set up for joysticks
IEP_L1JSRD32_TextScanKbd4094BD BB E5 '...'
CMPA#'N409781 4E '.N'
BEQIEP_L3409927 19 ''.'
CMPA#'Y409B81 59 '.Y'
BEQIEP_L2409D27 02 ''.'
BRAIEP_L1409F20 F3 ' .'
;Init joystick state (last-read values, and which joystick to read)
IEP_L2JSRSub_InitLastJoyValues40A1BD 41 79 '.Ay'
CLRVar_b_ActiveJoystickIdx40A47F 41 D2 '.A.'
;Overwrite code in keyboard-checking subroutine; bytes written are 7E 41 00,
;which is "JMP $4100"
LDA#$7E40A786 7E '.~'
STAMPL_MovePlrFromKbd40A9B7 30 F7 '.0.'
LDA#$4140AC86 41 '.A'
STA$30F840AEB7 30 F8 '.0.'
CLR$30F940B17F 30 F9 '.0.'
IEP_L3LBRASub_MaybeShowInstrns40B416 09 89 '...'
;Sub_AwaitKeyPress
;Loop until a key is pressed.
Sub_AwaitKeyPressJSRD32_TextScanKbd40B7BD BB E5 '...'
BEQSub_AwaitKeyPress40BA27 FB ''.'
RTS40BC39 '9'
;Sub_ResetScreen
;Reset text cursor to top-left; fill the text screen memory with spaces.
Sub_ResetScreenLDX#D32_TextScreen40BD8E 04 00 '...'
STXD32_VduCursorAddr40C09F 88 '..'
LDD#$606040C2CC 60 60 '.``'
RS_L1STD,X++40C5ED 81 '..'
CMPX#Loc_x000_y00040C78C 06 00 '...'
BLTRS_L140CA2D F9 '-.'
RTS40CC39 '9'
;Sub_TextOutTilNulCvtPct
;Use the ROM routine to write a string (pointed to by X) to the text
;display. Any "%" characters in the input are converted to newlines.
;Output stops at the first $00 byte of the input.
Sub_TextOutTilNulCvtPctLDA,X+40CDA6 80 '..'
BEQTOTNCP_L240CF27 0B ''.'
CMPA#$2540D181 25 '.%'
BNETOTNCP_L140D326 02 '&.'
LDA#$0D40D586 0D '..'
TOTNCP_L1JSRD32_TextOutChar40D7BD B5 4A '..J'
BRASub_TextOutTilNulCvtPct40DA20 F1 ' .'
TOTNCP_L2RTS40DC39 '9'
;TXT_JoysticksQuestion
TXT_JoysticksQuestionFCB'%,'%,'%,'%,'%,'%,'%,'40DD25 25 25 25 25 25 25 20 '%%%%%%% '
FCB' ,' ,' ,' ,' ,' ,'J,'O40E520 20 20 20 20 20 4A 4F ' JO'
FCB'Y,'S,'T,'I,'C,'K,'S,'40ED59 53 54 49 43 4B 53 20 'YSTICKS '
FCB'(,'Y,'/,'N,'),'?,$0040F528 59 2F 4E 29 3F 00 '(Y/N)?.'
FCB$30,$30,$30,$3040FC30 30 30 30 '0000'
;Sub_MovePlrByActiveJoy
;Read the "active" joystick (identified by ActiveJoystickIdx) and move the
;active player if required.
;Use ROM routines to prepare PIAs then read all joystick axes
Sub_MovePlrByActiveJoyJSRD32_SndDisable4100BD BA C3 '...'
JSRD32_SysReadJoystick4103BD BD 52 '..R'
;Enable sound again and set DAC output to known value
LDA#$FF410686 FF '..'
STAD32_PIA_1_A_Data4108B7 FF 20 '.. '
LDA#$08410B86 08 '..'
ORAD32_PIA_1_B_Ctrl410DBA FF 23 '..#'
STAD32_PIA_1_B_Ctrl4110B7 FF 23 '..#'
;If the left joystick is active...
TSTVar_b_ActiveJoystickIdx41137D 41 D2 '}A.'
;...read that instead
BNESub_MovePlrByLeftJoy411626 70 '&p'
;Move player left/right according to right joystick X value
LDAD32_R_Joy_X4118B6 01 5A '..Z'
CMPAVar_b_PlayerOneLastJoyX411BB1 41 D0 '.A.'
BCSMPBAJ_L3411E25 20 '% '
BHIMPBAJ_L4412022 26 '"&'
;Move player up/down according to right joystick Y value
MPBAJ_L1LDAD32_R_Joy_Y4122B6 01 5B '..['
CMPAVar_b_PlayerOneLastJoyY4125B1 41 D1 '.A.'
BCSMPBAJ_L6412825 2E '%.'
BHIMPBAJ_L5412A22 24 '"$'
MPBAJ_L2JSRSub_MoveDfrBaseCheckHit412CBD 33 91 '.3.'
;If right joystick fire button not down...
LDAD32_PIA_0_A_Data412FB6 FF 00 '...'
ORA#$8041328A 80 '..'
CMPA#$FE413481 FE '..'
;...chain to appropriate point in main play loop
LBNEMPL_L5413610 26 F0 0D '.&..'
;...else (fire button IS down) launch player shot
JSRSub_LaunchPlayerShot413ABD 32 98 '.2.'
;...and chain to appropriate point in main play loop
LBRAMPL_L6413D16 F0 0A '...'
MPBAJ_L3DECVar_b_PlayerOneLastJoyX41407A 41 D0 'zA.'
JSRSub_MovePlayerLeft4143BD 31 A9 '.1.'
BRAMPBAJ_L1414620 DA ' .'
MPBAJ_L4INCVar_b_PlayerOneLastJoyX41487C 41 D0 '|A.'
JSRSub_MovePlayerRight414BBD 31 8E '.1.'
BRAMPBAJ_L1414E20 D2 ' .'
MPBAJ_L5INCVar_b_PlayerOneLastJoyY41507C 41 D1 '|A.'
JSRSub_MovePlayerDown4153BD 32 6D '.2m'
BRAMPBAJ_L2415620 D4 ' .'
MPBAJ_L6DECVar_b_PlayerOneLastJoyY41587A 41 D1 'zA.'
JSRSub_MovePlayerUp415BBD 32 5D '.2]'
BRAMPBAJ_L2415E20 CC ' .'
;Sub_MaybeUpdateActiveJoy
;If required, switch which is the "active" joystick. Also erase the
;just-lost spare life ship. (It seems odd that these two things are
;coupled. Perhaps there was originally the intent to allow a "two players
;but sharing one joystick" mode.)
;
;Argument:
; U → active player struct (for erasing top lives ship)
;If we are in two-player mode...
Sub_MaybeUpdateActiveJoyTSTVar_b_TwoPlayerModeDup41607D 41 D5 '}A.'
BEQMUAJ_L1416327 08 ''.'
;...toggle ActiveJoystickIdx between 0 and 1
LDA#$01416586 01 '..'
EORAVar_b_ActiveJoystickIdx4167B8 41 D2 '.A.'
STAVar_b_ActiveJoystickIdx416AB7 41 D2 '.A.'
MUAJ_L1BSRSub_InitLastJoyValues416D8D 0A '..'
JSRSub_EraseTopLivesShip416FBD 36 2C '.6,'
RTS417239 '9'
;Sub_InitTwoPlayerState
;Note whether we are playing a two-player game. A = 0 (no) or 1 (yes).
;I don't know why there are two variables representing this information;
;maybe there was a plan to allow two players to share a joystick?
Sub_InitTwoPlayerStateSTAVar_b_TwoPlayerMode4173B7 36 45 '.6E'
STAVar_b_TwoPlayerModeDup4176B7 41 D5 '.A.'
;Fall through...
;Sub_InitLastJoyValues
;Act as though right joystick was most recently at top-left
Sub_InitLastJoyValuesCLRVar_b_PlayerOneLastJoyX41797F 41 D0 '.A.'
CLRVar_b_PlayerOneLastJoyY417C7F 41 D1 '.A.'
;Act as though left joystick was most recently at top-right
LDA#$3F417F86 3F '.?'
STAVar_b_PlayerTwoLastJoyX4181B7 41 D3 '.A.'
CLRVar_b_PlayerTwoLastJoyY41847F 41 D4 '.A.'
RTS418739 '9'
;Sub_MovePlrByLeftJoy
;Move the active player according to the position of the left joystick, and
;launch a player shot if the left fire button is down. Analogous to the
;code in Sub_MovePlrByActiveJoy.
Sub_MovePlrByLeftJoyLDAD32_L_Joy_X4188B6 01 5C '..\'
CMPAVar_b_PlayerTwoLastJoyX418BB1 41 D3 '.A.'
BCSCLJ_L2418E25 0E '%.'
BHICLJ_L3419022 14 '".'
CLJ_L1LDAD32_L_Joy_Y4192B6 01 5D '..]'
CMPAVar_b_PlayerTwoLastJoyY4195B1 41 D4 '.A.'
BCSCLJ_L5419825 1C '%.'
BHICLJ_L4419A22 12 '".'
BRACLJ_L6419C20 1E ' .'
CLJ_L2DECVar_b_PlayerTwoLastJoyX419E7A 41 D3 'zA.'
JSRSub_MovePlayerLeft41A1BD 31 A9 '.1.'
BRACLJ_L141A420 EC ' .'
CLJ_L3INCVar_b_PlayerTwoLastJoyX41A67C 41 D3 '|A.'
JSRSub_MovePlayerRight41A9BD 31 8E '.1.'
BRACLJ_L141AC20 E4 ' .'
CLJ_L4INCVar_b_PlayerTwoLastJoyY41AE7C 41 D4 '|A.'
JSRSub_MovePlayerDown41B1BD 32 6D '.2m'
BRACLJ_L641B420 06 ' .'
CLJ_L5DECVar_b_PlayerTwoLastJoyY41B67A 41 D4 'zA.'
JSRSub_MovePlayerUp41B9BD 32 5D '.2]'
CLJ_L6JSRSub_MoveDfrBaseCheckHit41BCBD 33 91 '.3.'
LDAD32_PIA_0_A_Data41BFB6 FF 00 '...'
ORA#$8041C28A 80 '..'
CMPA#$FD41C481 FD '..'
LBNEMPL_L541C610 26 EF 7D '.&.}'
JSRSub_LaunchPlayerShot41CABD 32 98 '.2.'
LBRAMPL_L641CD16 EF 7A '..z'
Var_b_PlayerOneLastJoyXFCB$0041D000 '.'
Var_b_PlayerOneLastJoyYFCB$0041D100 '.'
Var_b_ActiveJoystickIdxFCB$0041D200 '.'
Var_b_PlayerTwoLastJoyXFCB$0041D300 '.'
Var_b_PlayerTwoLastJoyYFCB$0041D400 '.'
Var_b_TwoPlayerModeDupFCB$0041D500 '.'
;TXT_NeedInstructions
TXT_NeedInstructionsFCB'%,'%,'%,'%,' ,' ,' ,'41D625 25 25 25 20 20 20 20 '%%%% '
FCB' ,' ,' ,'I,'N,'V,'A,'D41DE20 20 20 49 4E 56 41 44 ' INVAD'
FCB'E,'R,'S,' ,'R,'E,'V,'E41E645 52 53 20 52 45 56 45 'ERS REVE'
FCB'N,'G,'E,'%,'%,'%,'%,'%41EE4E 47 45 25 25 25 25 25 'NGE%%%%%'
FCB' ,' ,' ,' ,'N,'E,'E,'D41F620 20 20 20 4E 45 45 44 ' NEED'
FCB' ,'I,'N,'S,'T,'R,'U,'C41FE20 49 4E 53 54 52 55 43 ' INSTRUC'
FCB'T,'I,'O,'N,'S,' ,'(,'Y420654 49 4F 4E 53 20 28 59 'TIONS (Y'
FCB'/,'N,'),'?,$00420E2F 4E 29 3F 00 '/N)?.'
;TXT_Instructions_1
TXT_Instructions_1FCB'%,' ,' ,' ,' ,' ,' ,'421325 20 20 20 20 20 20 20 '% '
FCB' ,'I,'N,'V,'A,'D,'E,'R421B20 49 4E 56 41 44 45 52 ' INVADER'
FCB'S,' ,'R,'E,'V,'E,'N,'G422353 20 52 45 56 45 4E 47 'S REVENG'
FCB'E,'%,'%,' ,'I,'N,'V,'A422B45 25 25 20 49 4E 56 41 'E%% INVA'
FCB'D,'E,'R,'','S,' ,'R,'E423344 45 52 27 53 20 52 45 'DER'S RE'
FCB'V,'E,'N,'G,'E,' ,'I,'S423B56 45 4E 47 45 20 49 53 'VENGE IS'
FCB' ,'A,'%,' ,'F,'A,'S,'T424320 41 25 20 46 41 53 54 ' A% FAST'
FCB'-,'P,'A,'C,'E,'D,' ,'A424B2D 50 41 43 45 44 20 41 '-PACED A'
FCB'R,'C,'A,'D,'E,' ,'G,'A425352 43 41 44 45 20 47 41 'RCADE GA'
FCB'M,'E,'.,' ,'Y,'O,'U,',425B4D 45 2E 20 59 4F 55 2C 'ME. YOU,'
FCB'%,' ,'A,'S,' ,'T,'H,'E426325 20 41 53 20 54 48 45 '% AS THE'
FCB' ,'L,'A,'S,'T,' ,'R,'E426B20 4C 41 53 54 20 52 45 ' LAST RE'
FCB'M,'A,'I,'N,'I,'N,'G,'42734D 41 49 4E 49 4E 47 20 'MAINING '
FCB'S,'P,'A,'C,'E,'%,' ,'I427B53 50 41 43 45 25 20 49 'SPACE% I'
FCB'N,'V,'A,'D,'E,'R,',,'42834E 56 41 44 45 52 2C 20 'NVADER, '
FCB'M,'U,'S,'T,' ,'B,'A,'T428B4D 55 53 54 20 42 41 54 'MUST BAT'
FCB'T,'L,'E,' ,'T,'H,'E,'429354 4C 45 20 54 48 45 20 'TLE THE '
FCB'H,'U,'M,'A,'N,'%,' ,'S429B48 55 4D 41 4E 25 20 53 'HUMAN% S'
FCB'H,'I,'P,'S,' ,'T,'H,'A42A348 49 50 53 20 54 48 41 'HIPS THA'
FCB'T,' ,'P,'R,'O,'W,'L,'42AB54 20 50 52 4F 57 4C 20 'T PROWL '
FCB'T,'H,'E,' ,'S,'P,'A,'C42B354 48 45 20 53 50 41 43 'THE SPAC'
FCB'E,'%,' ,'L,'A,'N,'E,'S42BB45 25 20 4C 41 4E 45 53 'E% LANES'
FCB',,' ,'A,'N,'D,' ,'A,'V42C32C 20 41 4E 44 20 41 56 ', AND AV'
FCB'O,'I,'D,' ,'T,'H,'E,'42CB4F 49 44 20 54 48 45 20 'OID THE '
FCB'L,'A,'S,'E,'R,'%,' ,'S42D34C 41 53 45 52 25 20 53 'LASER% S'
FCB'T,'A,'T,'I,'O,'N,' ,'T42DB54 41 54 49 4F 4E 20 54 'TATION T'
FCB'H,'A,'T,' ,'S,'E,'E,'K42E348 41 54 20 53 45 45 4B 'HAT SEEK'
FCB'S,' ,'T,'O,' ,'D,'E,'S42EB53 20 54 4F 20 44 45 53 'S TO DES'
FCB'T,'R,'O,'Y,'%,' ,'Y,'O42F354 52 4F 59 25 20 59 4F 'TROY% YO'
FCB'U,' ,'A,'S,' ,'I,'T,'42FB55 20 41 53 20 49 54 20 'U AS IT '
FCB'D,'I,'D,' ,'Y,'O,'U,'R430344 49 44 20 59 4F 55 52 'DID YOUR'
FCB' ,'C,'O,'M,'P,'A,'N,'I430B20 43 4F 4D 50 41 4E 49 ' COMPANI'
FCB'O,'N,'S,'.,'%,' ,'Y,'O43134F 4E 53 2E 25 20 59 4F 'ONS.% YO'
FCB'U,'R,' ,'S,'H,'I,'P,'431B55 52 20 53 48 49 50 20 'UR SHIP '
FCB'I,'S,' ,'C,'O,'N,'T,'R432349 53 20 43 4F 4E 54 52 'IS CONTR'
FCB'O,'L,'L,'E,'D,' ,'E,'I432B4F 4C 4C 45 44 20 45 49 'OLLED EI'
FCB'T,'H,'E,'R,'%,' ,'B,'Y433354 48 45 52 25 20 42 59 'THER% BY'
FCB' ,'J,'O,'Y,'S,'T,'I,'C433B20 4A 4F 59 53 54 49 43 ' JOYSTIC'
FCB'K,'S,' ,'O,'R,' ,'T,'H43434B 53 20 4F 52 20 54 48 'KS OR TH'
FCB'E,' ,'F,'O,'U,'R,' ,'A434B45 20 46 4F 55 52 20 41 'E FOUR A'
FCB'R,'R,'O,'W,'%,' ,'K,'E435352 52 4F 57 25 20 4B 45 'RROW% KE'
FCB'Y,'S,'.,'%,' ,' ,' ,'p435B59 53 2E 25 20 20 20 70 'YS.% p'
FCB'r,'e,'s,'s,' ,'a,'n,'y436372 65 73 73 20 61 6E 79 'ress any'
FCB' ,'k,'e,'y,' ,'t,'o,'436B20 6B 65 79 20 74 6F 20 ' key to '
FCB'c,'o,'n,'t,'i,'n,'u,'e437363 6F 6E 74 69 6E 75 65 'continue'
FCB':,'%,$00437B3A 25 00 ':%.'
;TXT_Instructions_2
TXT_Instructions_2FCB'%,'%,'%,' ,'T,'H,'E,'437E25 25 25 20 54 48 45 20 '%%% THE '
FCB'K,'E,'Y,'S,' ,'M,'O,'V43864B 45 59 53 20 4D 4F 56 'KEYS MOV'
FCB'E,' ,'Y,'O,'U,' ,'U,'P438E45 20 59 4F 55 20 55 50 'E YOU UP'
FCB',,' ,'D,'O,'W,'N,',,'%43962C 20 44 4F 57 4E 2C 25 ', DOWN,%'
FCB' ,'L,'E,'F,'T,' ,'A,'N439E20 4C 45 46 54 20 41 4E ' LEFT AN'
FCB'D,' ,'R,'I,'G,'H,'T,'43A644 20 52 49 47 48 54 20 'D RIGHT '
FCB'O,'N,' ,'T,'H,'E,' ,'S43AE4F 4E 20 54 48 45 20 53 'ON THE S'
FCB'C,'R,'E,'E,'N,'.,'%,'43B643 52 45 45 4E 2E 25 20 'CREEN.% '
FCB'T,'H,'E,' ,'S,'P,'A,'C43BE54 48 45 20 53 50 41 43 'THE SPAC'
FCB'E,' ,'B,'A,'R,' ,'F,'I43C645 20 42 41 52 20 46 49 'E BAR FI'
FCB'R,'E,'S,' ,'M,'I,'S,'S43CE52 45 53 20 4D 49 53 53 'RES MISS'
FCB'I,'L,'E,'S,'%,' ,'F,'R43D649 4C 45 53 25 20 46 52 'ILES% FR'
FCB'O,'M,' ,'Y,'O,'U,'R,'43DE4F 4D 20 59 4F 55 52 20 'OM YOUR '
FCB'S,'H,'I,'P,'.,' ,'Y,'O43E653 48 49 50 2E 20 59 4F 'SHIP. YO'
FCB'U,' ,'B,'E,'G,'I,'N,'43EE55 20 42 45 47 49 4E 20 'U BEGIN '
FCB'W,'I,'T,'H,'%,' ,'T,'H43F657 49 54 48 25 20 54 48 'WITH% TH'
FCB'R,'E,'E,' ,'S,'H,'I,'P43FE52 45 45 20 53 48 49 50 'REE SHIP'
FCB'S,',,' ,'L,'O,'C,'A,'T440653 2C 20 4C 4F 43 41 54 'S, LOCAT'
FCB'E,'D,' ,'I,'N,' ,'T,'H440E45 44 20 49 4E 20 54 48 'ED IN TH'
FCB'E,'%,' ,'T,'O,'P,' ,'L441645 25 20 54 4F 50 20 4C 'E% TOP L'
FCB'E,'F,'T,' ,'H,'A,'N,'D441E45 46 54 20 48 41 4E 44 'EFT HAND'
FCB' ,'C,'O,'R,'N,'E,'R,'442620 43 4F 52 4E 45 52 20 ' CORNER '
FCB'O,'F,' ,'T,'H,'E,'%,'442E4F 46 20 54 48 45 25 20 'OF THE% '
FCB'S,'C,'R,'E,'E,'N,',,'443653 43 52 45 45 4E 2C 20 'SCREEN, '
FCB'A,'B,'O,'V,'E,' ,'T,'H443E41 42 4F 56 45 20 54 48 'ABOVE TH'
FCB'E,' ,'L,'I,'N,'E,'.,'444645 20 4C 49 4E 45 2E 20 'E LINE. '
FCB'Y,'O,'U,'%,' ,'U,'S,'E444E59 4F 55 25 20 55 53 45 'YOU% USE'
FCB' ,'T,'H,'E,' ,'J,'O,'Y445620 54 48 45 20 4A 4F 59 ' THE JOY'
FCB'S,'T,'I,'C,'K,' ,'O,'R445E53 54 49 43 4B 20 4F 52 'STICK OR'
FCB' ,'A,'R,'R,'O,'W,' ,'K446620 41 52 52 4F 57 20 4B ' ARROW K'
FCB'E,'Y,'S,'%,' ,'T,'O,'446E45 59 53 25 20 54 4F 20 'EYS% TO '
FCB'M,'O,'V,'E,' ,'T,'H,'E44764D 4F 56 45 20 54 48 45 'MOVE THE'
FCB' ,'S,'H,'I,'P,' ,'B,'E447E20 53 48 49 50 20 42 45 ' SHIP BE'
FCB'L,'O,'W,' ,'T,'H,'E,'%44864C 4F 57 20 54 48 45 25 'LOW THE%'
FCB' ,'L,'I,'N,'E,' ,'T,'O448E20 4C 49 4E 45 20 54 4F ' LINE TO'
FCB' ,'S,'T,'A,'R,'T,' ,'T449620 53 54 41 52 54 20 54 ' START T'
FCB'H,'E,' ,'G,'A,'M,'E,'.449E48 45 20 47 41 4D 45 2E 'HE GAME.'
FCB' ,'T,'H,'E,'%,' ,'R,'I44A620 54 48 45 25 20 52 49 ' THE% RI'
FCB'G,'H,'T,' ,'H,'A,'N,'D44AE47 48 54 20 48 41 4E 44 'GHT HAND'
FCB' ,'J,'O,'Y,'S,'T,'I,'C44B620 4A 4F 59 53 54 49 43 ' JOYSTIC'
FCB'K,' ,'C,'O,'N,'T,'R,'O44BE4B 20 43 4F 4E 54 52 4F 'K CONTRO'
FCB'L,'S,'%,' ,'T,'H,'E,'44C64C 53 25 20 54 48 45 20 'LS% THE '
FCB'S,'H,'I,'P,' ,'O,'F,'44CE53 48 49 50 20 4F 46 20 'SHIP OF '
FCB'P,'L,'A,'Y,'E,'R,' ,'144D650 4C 41 59 45 52 20 31 'PLAYER 1'
FCB' ,'A,'N,'D,' ,'T,'H,'E44DE20 41 4E 44 20 54 48 45 ' AND THE'
FCB'%,' ,'L,'E,'F,'T,' ,'H44E625 20 4C 45 46 54 20 48 '% LEFT H'
FCB'A,'N,'D,' ,'J,'O,'Y,'S44EE41 4E 44 20 4A 4F 59 53 'AND JOYS'
FCB'T,'I,'C,'K,' ,' ,'T,'H44F654 49 43 4B 20 20 54 48 'TICK TH'
FCB'E,' ,'S,'H,'I,'P,'%,'44FE45 20 53 48 49 50 25 20 'E SHIP% '
FCB'O,'F,' ,'P,'L,'A,'Y,'E45064F 46 20 50 4C 41 59 45 'OF PLAYE'
FCB'R,' ,'2,'.,'%,' ,' ,'450E52 20 32 2E 25 20 20 20 'R 2.% '
FCB'p,'r,'e,'s,'s,' ,'a,'n451670 72 65 73 73 20 61 6E 'press an'
FCB'y,' ,'k,'e,'y,' ,'t,'o451E79 20 6B 65 79 20 74 6F 'y key to'
FCB' ,'c,'o,'n,'t,'i,'n,'u452620 63 6F 6E 74 69 6E 75 ' continu'
FCB'e,':,'%,$00452E65 3A 25 00 'e:%.'
;TXT_Instructions_3
TXT_Instructions_3FCB'%,'%,'%,' ,'T,'H,'E,'453225 25 25 20 54 48 45 20 '%%% THE '
FCB'o,'b,'j,'e,'c,'t,' ,'I453A6F 62 6A 65 63 74 20 49 'object I'
FCB'S,' ,'T,'O,' ,'S,'H,'O454253 20 54 4F 20 53 48 4F 'S TO SHO'
FCB'O,'T,' ,'T,'H,'E,'%,'454A4F 54 20 54 48 45 25 20 'OT THE% '
FCB's,'h,'i,'p,'s,' ,'A,'N455273 68 69 70 73 20 41 4E 'ships AN'
FCB'D,' ,'T,'H,'E,' ,'l,'a455A44 20 54 48 45 20 6C 61 'D THE la'
FCB's,'e,'r,' ,'b,'a,'s,'e456273 65 72 20 62 61 73 65 'ser base'
FCB's,'.,' ,'Y,'O,'U,'%,'456A73 2E 20 59 4F 55 25 20 's. YOU% '
FCB'm,'u,'s,'t,' ,'n,'o,'t45726D 75 73 74 20 6E 6F 74 'must not'
FCB' ,'c,'o,'l,'l,'i,'d,'e457A20 63 6F 6C 6C 69 64 65 ' collide'
FCB' ,'W,'I,'T,'H,' ,'A,'N458220 57 49 54 48 20 41 4E ' WITH AN'
FCB'Y,' ,'O,'F,'%,' ,'T,'H458A59 20 4F 46 25 20 54 48 'Y OF% TH'
FCB'E,' ,'S,'H,'I,'P,'S,',459245 20 53 48 49 50 53 2C 'E SHIPS,'
FCB' ,'n,'o,'r,' ,'b,'e,'459A20 6E 6F 72 20 62 65 20 ' nor be '
FCB'h,'i,'t,' ,'B,'Y,' ,'T45A268 69 74 20 42 59 20 54 'hit BY T'
FCB'H,'E,'%,' ,'F,'I,'R,'E45AA48 45 25 20 46 49 52 45 'HE% FIRE'
FCB' ,'F,'R,'O,'M,' ,'T,'H45B220 46 52 4F 4D 20 54 48 ' FROM TH'
FCB'E,' ,'L,'A,'S,'E,'R,'45BA45 20 4C 41 53 45 52 20 'E LASER '
FCB'B,'A,'S,'E,'.,'%,' ,'D45C242 41 53 45 2E 25 20 44 'BASE.% D'
FCB'I,'F,'F,'E,'R,'E,'N,'T45CA49 46 46 45 52 45 4E 54 'IFFERENT'
FCB' ,'S,'O,'U,'N,'D,' ,'E45D220 53 4F 55 4E 44 20 45 ' SOUND E'
FCB'F,'F,'E,'C,'T,'S,'%,'45DA46 46 45 43 54 53 25 20 'FFECTS% '
FCB'I,'N,'D,'I,'C,'A,'T,'E45E249 4E 44 49 43 41 54 45 'INDICATE'
FCB' ,'W,'H,'E,'N,' ,'Y,'O45EA20 57 48 45 4E 20 59 4F ' WHEN YO'
FCB'U,' ,'H,'A,'V,'E,' ,'H45F255 20 48 41 56 45 20 48 'U HAVE H'
FCB'I,'T,' ,'A,'%,' ,'N,'O45FA49 54 20 41 25 20 4E 4F 'IT A% NO'
FCB'R,'M,'A,'L,' ,'S,'H,'I460252 4D 41 4C 20 53 48 49 'RMAL SHI'
FCB'P,' ,'O,'R,' ,'A,' ,'L460A50 20 4F 52 20 41 20 4C 'P OR A L'
FCB'A,'S,'E,'R,' ,'B,'A,'S461241 53 45 52 20 42 41 53 'ASER BAS'
FCB'E,'.,'%,' ,'A,'N,'O,'T461A45 2E 25 20 41 4E 4F 54 'E.% ANOT'
FCB'H,'E,'R,' ,'S,'O,'U,'N462248 45 52 20 53 4F 55 4E 'HER SOUN'
FCB'D,' ,'E,'F,'F,'E,'C,'T462A44 20 45 46 46 45 43 54 'D EFFECT'
FCB' ,'O,'C,'C,'U,'R,'S,'%463220 4F 43 43 55 52 53 25 ' OCCURS%'
FCB' ,'W,'H,'E,'N,' ,'Y,'O463A20 57 48 45 4E 20 59 4F ' WHEN YO'
FCB'U,' ,'A,'R,'E,' ,'B,'L464255 20 41 52 45 20 42 4C 'U ARE BL'
FCB'O,'W,'N,' ,'U,'P,'.,'%464A4F 57 4E 20 55 50 2E 25 'OWN UP.%'
FCB'%,' ,' ,' ,'p,'r,'e,'s465225 20 20 20 70 72 65 73 '% pres'
FCB's,' ,'a,'n,'y,' ,'k,'e465A73 20 61 6E 79 20 6B 65 's any ke'
FCB'y,' ,'t,'o,' ,'c,'o,'n466279 20 74 6F 20 63 6F 6E 'y to con'
FCB't,'i,'n,'u,'e,':,'%,'%466A74 69 6E 75 65 3A 25 25 'tinue:%%'
FCB$00467200 '.'
;TXT_Instructions_4
TXT_Instructions_4FCB'%,'%,'%,'%,'%,' ,'s,'c467325 25 25 25 25 20 73 63 '%%%%% sc'
FCB'o,'r,'i,'n,'g,':,'%,'467B6F 72 69 6E 67 3A 25 20 'oring:% '
FCB' ,'N,'O,'R,'M,'A,'L,'468320 4E 4F 52 4D 41 4C 20 ' NORMAL '
FCB'S,'H,'I,'P,' ,' ,' ,'468B53 48 49 50 20 20 20 20 'SHIP '
FCB' ,'1,'0,'0,' ,' ,'P,'O469320 31 30 30 20 20 50 4F ' 100 PO'
FCB'I,'N,'T,'S,'%,' ,' ,'F469B49 4E 54 53 25 20 20 46 'INTS% F'
FCB'L,'A,'G,'S,'H,'I,'P,'46A34C 41 47 53 48 49 50 20 'LAGSHIP '
FCB' ,' ,' ,' ,' ,' ,' ,'146AB20 20 20 20 20 20 20 31 ' 1'
FCB'0,'0,'0,' ,'P,'O,'I,'N46B330 30 30 20 50 4F 49 4E '000 POIN'
FCB'T,'S,'%,' ,' ,'L,'A,'S46BB54 53 25 20 20 4C 41 53 'TS% LAS'
FCB'E,'R,' ,'B,'A,'S,'E,'46C345 52 20 42 41 53 45 20 'ER BASE '
FCB' ,' ,' ,' ,' ,'0,' ,'46CB20 20 20 20 20 30 20 20 ' 0 '
FCB' ,' ,'P,'O,'I,'N,'T,'S46D320 20 50 4F 49 4E 54 53 ' POINTS'
FCB'%,' ,' ,'B,'O,'N,'U,'S46DB25 20 20 42 4F 4E 55 53 '% BONUS'
FCB' ,'S,'H,'I,'P,' ,'A,'T46E320 53 48 49 50 20 41 54 ' SHIP AT'
FCB' ,'1,'0,',,'0,'0,'0,'46EB20 31 30 2C 30 30 30 20 ' 10,000 '
FCB'P,'O,'I,'N,'T,'S,'%,'%46F350 4F 49 4E 54 53 25 25 'POINTS%%'
FCB' ,' ,' ,'p,'r,'e,'s,'s46FB20 20 20 70 72 65 73 73 ' press'
FCB' ,'a,'n,'y,' ,'k,'e,'y470320 61 6E 79 20 6B 65 79 ' any key'
FCB' ,'t,'o,' ,'c,'o,'n,'t470B20 74 6F 20 63 6F 6E 74 ' to cont'
FCB'i,'n,'u,'e,':,'%,'%,'%471369 6E 75 65 3A 25 25 25 'inue:%%%'
FCB'%,'%,$00471B25 25 00 '%%.'
;TXT_Instructions_5
TXT_Instructions_5FCB'%,' ,'A,'T,' ,'T,'H,'E471E25 20 41 54 20 54 48 45 '% AT THE'
FCB' ,'B,'E,'G,'I,'N,'N,'I472620 42 45 47 49 4E 4E 49 ' BEGINNI'
FCB'N,'G,' ,'O,'F,' ,'T,'H472E4E 47 20 4F 46 20 54 48 'NG OF TH'
FCB'E,' ,'G,'A,'M,'E,',,'%473645 20 47 41 4D 45 2C 25 'E GAME,%'
FCB' ,'S,'E,'V,'E,'R,'A,'L473E20 53 45 56 45 52 41 4C ' SEVERAL'
FCB' ,'S,'E,'L,'E,'C,'T,'I474620 53 45 4C 45 43 54 49 ' SELECTI'
FCB'O,'N,'S,' ,'C,'A,'N,'474E4F 4E 53 20 43 41 4E 20 'ONS CAN '
FCB'B,'E,'%,' ,'M,'A,'D,'E475642 45 25 20 4D 41 44 45 'BE% MADE'
FCB'.,' ,'A,' ,'1,' ,'O,'R475E2E 20 41 20 31 20 4F 52 '. A 1 OR'
FCB' ,'2,' ,'P,'L,'A,'Y,'E476620 32 20 50 4C 41 59 45 ' 2 PLAYE'
FCB'R,' ,'G,'A,'M,'E,' ,'M476E52 20 47 41 4D 45 20 4D 'R GAME M'
FCB'A,'Y,'%,' ,'B,'E,' ,'S477641 59 25 20 42 45 20 53 'AY% BE S'
FCB'E,'L,'E,'C,'T,'E,'D,'.477E45 4C 45 43 54 45 44 2E 'ELECTED.'
FCB' ,'I,'F,' ,'2,' ,'P,'L478620 49 46 20 32 20 50 4C ' IF 2 PL'
FCB'A,'Y,'E,'R,'S,' ,'A,'R478E41 59 45 52 53 20 41 52 'AYERS AR'
FCB'E,'%,' ,'D,'E,'S,'I,'R479645 25 20 44 45 53 49 52 'E% DESIR'
FCB'E,'D,',,' ,'O,'N,'E,'479E45 44 2C 20 4F 4E 45 20 'ED, ONE '
FCB'P,'L,'A,'Y,'E,'R,' ,'P47A650 4C 41 59 45 52 20 50 'PLAYER P'
FCB'L,'A,'Y,'S,'%,' ,'U,'N47AE4C 41 59 53 25 20 55 4E 'LAYS% UN'
FCB'T,'I,'L,' ,'H,'E,' ,'L47B654 49 4C 20 48 45 20 4C 'TIL HE L'
FCB'O,'S,'E,'S,' ,'A,' ,'S47BE4F 53 45 53 20 41 20 53 'OSES A S'
FCB'H,'I,'P,',,' ,'A,'N,'D47C648 49 50 2C 20 41 4E 44 'HIP, AND'
FCB'%,' ,'T,'H,'E,'N,' ,'T47CE25 20 54 48 45 4E 20 54 '% THEN T'
FCB'H,'E,' ,'O,'T,'H,'E,'R47D648 45 20 4F 54 48 45 52 'HE OTHER'
FCB' ,'P,'L,'A,'Y,'E,'R,'47DE20 50 4C 41 59 45 52 20 ' PLAYER '
FCB'T,'A,'K,'E,'S,'%,' ,'O47E654 41 4B 45 53 25 20 4F 'TAKES% O'
FCB'V,'E,'R,'.,' ,'T,'H,'E47EE56 45 52 2E 20 54 48 45 'VER. THE'
FCB' ,'n,'u,'m,'b,'e,'r,'47F620 6E 75 6D 62 65 72 20 ' number '
FCB'o,'f,' ,'s,'h,'o,'t,'s47FE6F 66 20 73 68 6F 74 73 'of shots'
FCB' ,'C,'A,'N,'%,' ,'B,'E480620 43 41 4E 25 20 42 45 ' CAN% BE'
FCB' ,'S,'E,'L,'E,'C,'T,'E480E20 53 45 4C 45 43 54 45 ' SELECTE'
FCB'D,' ,'(,'1,' ,'T,'O,'481644 20 28 31 20 54 4F 20 'D (1 TO '
FCB'5,'),'.,' ,'T,'H,'I,'S481E35 29 2E 20 54 48 49 53 '5). THIS'
FCB'%,' ,'D,'E,'T,'E,'R,'M482625 20 44 45 54 45 52 4D '% DETERM'
FCB'I,'N,'E,'S,' ,'H,'O,'W482E49 4E 45 53 20 48 4F 57 'INES HOW'
FCB' ,'M,'A,'N,'Y,' ,'M,'I483620 4D 41 4E 59 20 4D 49 ' MANY MI'
FCB'S,'S,'I,'L,'E,'S,'%,'483E53 53 49 4C 45 53 25 20 'SSILES% '
FCB'M,'A,'Y,' ,'B,'E,' ,'I48464D 41 59 20 42 45 20 49 'MAY BE I'
FCB'N,' ,'T,'H,'E,' ,'A,'I484E4E 20 54 48 45 20 41 49 'N THE AI'
FCB'R,' ,'A,'T,' ,'O,'N,'E485652 20 41 54 20 4F 4E 45 'R AT ONE'
FCB' ,'T,'I,'M,'E,'.,'%,'485E20 54 49 4D 45 2E 25 20 ' TIME.% '
FCB'T,'H,'E,' ,'H,'I,'G,'H486654 48 45 20 48 49 47 48 'THE HIGH'
FCB'E,'R,' ,'T,'H,'E,' ,'N486E45 52 20 54 48 45 20 4E 'ER THE N'
FCB'U,'M,'B,'E,'R,',,' ,'T487655 4D 42 45 52 2C 20 54 'UMBER, T'
FCB'H,'E,'%,' ,'E,'A,'S,'I487E48 45 25 20 45 41 53 49 'HE% EASI'
FCB'E,'R,' ,'T,'H,'E,' ,'G488645 52 20 54 48 45 20 47 'ER THE G'
FCB'A,'M,'E,'.,'%,'%,' ,'488E41 4D 45 2E 25 25 20 20 'AME.%% '
FCB' ,'p,'r,'e,'s,'s,' ,'a489620 70 72 65 73 73 20 61 ' press a'
FCB'n,'y,' ,'k,'e,'y,' ,'t489E6E 79 20 6B 65 79 20 74 'ny key t'
FCB'o,' ,'c,'o,'n,'t,'i,'n48A66F 20 63 6F 6E 74 69 6E 'o contin'
FCB'u,'e,':,'%,$0048AE75 65 3A 25 00 'ue:%.'
;TXT_Instructions_6
TXT_Instructions_6FCB'%,' ,'T,'H,'E,' ,'s,'p48B325 20 54 48 45 20 73 70 '% THE sp'
FCB'e,'e,'d,' ,'o,'f,' ,'t48BB65 65 64 20 6F 66 20 74 'eed of t'
FCB'h,'e,' ,'g,'a,'m,'e,'48C368 65 20 67 61 6D 65 20 'he game '
FCB'(,'1,' ,'T,'O,' ,'5,')48CB28 31 20 54 4F 20 35 29 '(1 TO 5)'
FCB'%,' ,'M,'A,'Y,' ,'B,'E48D325 20 4D 41 59 20 42 45 '% MAY BE'
FCB' ,'C,'H,'O,'S,'E,'N,'.48DB20 43 48 4F 53 45 4E 2E ' CHOSEN.'
FCB' ,'T,'H,'E,' ,'H,'I,'G48E320 54 48 45 20 48 49 47 ' THE HIG'
FCB'H,'E,'R,' ,'T,'H,'E,'%48EB48 45 52 20 54 48 45 25 'HER THE%'
FCB' ,'N,'U,'M,'B,'E,'R,',48F320 4E 55 4D 42 45 52 2C ' NUMBER,'
FCB' ,'T,'H,'E,' ,'F,'A,'S48FB20 54 48 45 20 46 41 53 ' THE FAS'
FCB'T,'E,'R,' ,'(,'A,'N,'D490354 45 52 20 28 41 4E 44 'TER (AND'
FCB'%,' ,'H,'A,'R,'D,'E,'R490B25 20 48 41 52 44 45 52 '% HARDER'
FCB'),' ,'T,'H,'E,' ,'G,'A491329 20 54 48 45 20 47 41 ') THE GA'
FCB'M,'E,'.,' ,'I,'F,' ,'Y491B4D 45 2E 20 49 46 20 59 'ME. IF Y'
FCB'O,'U,' ,'H,'I,'T,'%,'49234F 55 20 48 49 54 25 20 'OU HIT% '
FCB'e,'n,'t,'e,'r,' ,'F,'O492B65 6E 74 65 72 20 46 4F 'enter FO'
FCB'R,' ,'A,'N,'Y,' ,'O,'F493352 20 41 4E 59 20 4F 46 'R ANY OF'
FCB' ,'T,'H,'E,'S,'E,'%,'493B20 54 48 45 53 45 25 20 ' THESE% '
FCB'Q,'U,'E,'S,'T,'I,'O,'N494351 55 45 53 54 49 4F 4E 'QUESTION'
FCB'S,',,' ,'T,'H,'E,' ,'V494B53 2C 20 54 48 45 20 56 'S, THE V'
FCB'A,'L,'U,'E,' ,'F,'O,'R495341 4C 55 45 20 46 4F 52 'ALUE FOR'
FCB' ,'T,'H,'E,'%,' ,'L,'A495B20 54 48 45 25 20 4C 41 ' THE% LA'
FCB'S,'T,' ,'G,'A,'M,'E,'496353 54 20 47 41 4D 45 20 'ST GAME '
FCB'W,'I,'L,'L,' ,'B,'E,'496B57 49 4C 4C 20 42 45 20 'WILL BE '
FCB'U,'S,'E,'D,'.,' ,'Y,'O497355 53 45 44 2E 20 59 4F 'USED. YO'
FCB'U,'%,' ,'C,'A,'N,' ,'A497B55 25 20 43 41 4E 20 41 'U% CAN A'
FCB'L,'S,'O,' ,'P,'A,'U,'S49834C 53 4F 20 50 41 55 53 'LSO PAUS'
FCB'E,' ,'T,'H,'E,' ,'G,'A498B45 20 54 48 45 20 47 41 'E THE GA'
FCB'M,'E,' ,'B,'Y,'%,' ,'H49934D 45 20 42 59 25 20 48 'ME BY% H'
FCB'I,'T,'T,'I,'N,'G,' ,'T499B49 54 54 49 4E 47 20 54 'ITTING T'
FCB'H,'E,' ,'",'P,'",' ,'K49A348 45 20 22 50 22 20 4B 'HE "P" K'
FCB'E,'Y,'.,' ,'T,'H,'I,'S49AB45 59 2E 20 54 48 49 53 'EY. THIS'
FCB'%,' ,'F,'R,'E,'E,'Z,'E49B325 20 46 52 45 45 5A 45 '% FREEZE'
FCB'S,' ,'T,'H,'E,' ,'G,'A49BB53 20 54 48 45 20 47 41 'S THE GA'
FCB'M,'E,' ,'I,'N,' ,'P,'L49C34D 45 20 49 4E 20 50 4C 'ME IN PL'
FCB'A,'C,'E,' ,'S,'O,'%,'49CB41 43 45 20 53 4F 25 20 'ACE SO% '
FCB'Y,'O,'U,' ,'C,'A,'N,'49D359 4F 55 20 43 41 4E 20 'YOU CAN '
FCB'L,'E,'A,'V,'E,' ,'T,'O49DB4C 45 41 56 45 20 54 4F 'LEAVE TO'
FCB' ,'A,'N,'S,'W,'E,'R,'49E320 41 4E 53 57 45 52 20 ' ANSWER '
FCB'T,'H,'E,'%,' ,'P,'H,'O49EB54 48 45 25 20 50 48 4F 'THE% PHO'
FCB'N,'E,',,' ,'E,'T,'C,'.49F34E 45 2C 20 45 54 43 2E 'NE, ETC.'
FCB' ,'H,'I,'T,'T,'I,'N,'G49FB20 48 49 54 54 49 4E 47 ' HITTING'
FCB' ,'A,'N,'Y,' ,'K,'E,'Y4A0320 41 4E 59 20 4B 45 59 ' ANY KEY'
FCB'%,' ,'W,'I,'L,'L,' ,'R4A0B25 20 57 49 4C 4C 20 52 '% WILL R'
FCB'E,'S,'U,'M,'E,' ,'T,'H4A1345 53 55 4D 45 20 54 48 'ESUME TH'
FCB'E,' ,'G,'A,'M,'E,'.,'%4A1B45 20 47 41 4D 45 2E 25 'E GAME.%'
FCB'%,' ,' ,' ,'p,'r,'e,'s4A2325 20 20 20 70 72 65 73 '% pres'
FCB's,' ,'a,'n,'y,' ,'k,'e4A2B73 20 61 6E 79 20 6B 65 's any ke'
FCB'y,' ,'t,'o,' ,'s,'t,'a4A3379 20 74 6F 20 73 74 61 'y to sta'
FCB'r,'t,':,'%,$004A3B72 74 3A 25 00 'rt:%.'
;Sub_MaybeShowInstrns
;Ask the user whether they want instructions. If so, show the instructions
;one page at a time.
;Clear screen and write "instructions?" text
Sub_MaybeShowInstrnsLBSRSub_ResetScreen4A4017 F6 7A '..z'
LDX#TXT_NeedInstructions4A438E 41 D6 '.A.'
LBSRSub_TextOutTilNulCvtPct4A4617 F6 84 '...'
;Loop until the player types "Y" or "N", and act accordingly
MSI_L1JSRD32_TextScanKbd4A49BD BB E5 '...'
CMPA#'N4A4C81 4E '.N'
BEQMSI_L34A4E27 3F ''?'
CMPA#'Y4A5081 59 '.Y'
BEQMSI_L24A5227 02 ''.'
BRAMSI_L14A5420 F3 ' .'
;Show the instructions, waiting for a keypress between each page
MSI_L2JSRSub_ResetScreen4A56BD 40 BD '.@.'
LDX#TXT_Instructions_14A598E 42 13 '.B.'
LBSRSub_TextOutTilNulCvtPct4A5C17 F6 6E '..n'
LBSRSub_AwaitKeyPress4A5F17 F6 55 '..U'
LDX#TXT_Instructions_24A628E 43 7E '.C~'
LBSRSub_TextOutTilNulCvtPct4A6517 F6 65 '..e'
LBSRSub_AwaitKeyPress4A6817 F6 4C '..L'
LDX#TXT_Instructions_34A6B8E 45 32 '.E2'
LBSRSub_TextOutTilNulCvtPct4A6E17 F6 5C '..\'
LBSRSub_AwaitKeyPress4A7117 F6 43 '..C'
LDX#TXT_Instructions_44A748E 46 73 '.Fs'
LBSRSub_TextOutTilNulCvtPct4A7717 F6 53 '..S'
LBSRSub_AwaitKeyPress4A7A17 F6 3A '..:'
LDX#TXT_Instructions_54A7D8E 47 1E '.G.'
LBSRSub_TextOutTilNulCvtPct4A8017 F6 4A '..J'
LBSRSub_AwaitKeyPress4A8317 F6 31 '..1'
LDX#TXT_Instructions_64A868E 48 B3 '.H.'
LBSRSub_TextOutTilNulCvtPct4A8917 F6 41 '..A'
LBSRSub_AwaitKeyPress4A8C17 F6 28 '..('
;Move on to next phase of boot
MSI_L3JMPSub_InitWarmReset4A8F7E 2D 2D '~--'
END