
I'd appreciate any feedback from people NOTE! This email address does not work. Christopher! Please give me one that does
 Introduction is a general introduction to how I've set 
  out the disassembly
  Numerical Index is a list of routines for SWOOP 
  in ascending address order
Disassembly Itself
  
Page &0E Page &15 Page &16 Page &17 Page &18 Page &19 Page &1A Page &1B Page &1C Page &1D Page &1E Page &1F Page &20 Page &21 Page &22 Page &23 Page &24 Page &25 Page &26 Page &27 Page &28 Page &29 Page &2A Page &2B Page &2C
Original Text as Submitted to 8BS
  Download the text file
 SWOOP DISASSEMBLY
  This project is the first in what will hopefully be a long line of disassembly 
  articles which present the coding of some popular arcade games in a fairly digestible 
  format. The aim really is to help us learn more about how to program in machine 
  code by seeing it in action in your favourite games. But also you can find out 
  which parts of the code need altering to provide cheats such as extra lives, 
  immortality, and so on!
Now, machine code programmers should aim for a program that is efficient for the task in hand, and the way in which some people's programs are written doesn't necessarily mean they've found the 'right' way of doing something. In other words, the best code is the code that is specifically tailored to the job you are doing so you can't just go copying entire sections of code into your own programs. Unless, of course, it does exactly what you want, but the chances are that you'll want to adjust the code here and there to achieve the right effect you want.
I have seen dozens of different routines for plotting sprites or printing text in games, for instance, some of which are smart and impressive, others written downright lazily, and the rest are just a question of programming style. The latter case illustrates that there may not be a right or a wrong way of doing something simply because there are several equally good ways of going about the same task.
  Layout of the Disassembly
  When disassembling programs, I have one or two conventions that may seem a little 
  strange at first but you will see that they are very helpful. Firstly, you are 
  probably used to seeing disassembly presented as one instruction per line with 
  its location in memory on the left as in the following example:
 1A01 LDA &E00
  1A04 CMP #10
  1A06 BNE &1A0B
  1A08 INC &E00
  1A0B LDA &E00
  1A0E CMP &19D6
  1A11 BEQ &1A22
  1A13 LDA #&00
  1A15 STA &82
  1A17 LDA #&0E
  1A19 STA &83
  1A1B JSR &181B
This is a typical listing generated from a disassembler. Now, the only times that we're interested in the address on the left is at the beginning of a loop, at branch instructions (e.g. BNE &1A0B or BEQ &1A22 in the above), when locations or tables of data elsewhere in memory are being addressed (e.g. LDA &E00 or CMP &19D6 in the above) when the code is JSRing or JMPing to a different part of the program (e.g. JSR &181B in the above section of assembly).
I write my disassembly in a more concise way - in what I call "PAGEs sentences": starting a new sheet of paper for a new PAGE in memory, and putting all related code onto one line. So our previous example can be rewritten as:
PAGE &1A
  
  01:LDA &E00:CMP #10:BNE &1A0B
  INC &E00
  0B:LDA &E00:CMP &19D6:BEQ &1A22
  LDA #&00:STA &82:LDA #&0E:STA &83:JSR &181B
The PAGE number (the first two digits of the 16-bit hexadecimal address, &1A in this case) is written at the top. Subsequent addresses within the PAGE are specified as the offset within the page. Branch addresses are specified in full after the BRanch instruction but the destination of the branch is again specified as the offset within the page. Stick to this convention and you'll save a lot of space - and pencil lead if, like me, you initially write the disassembly out by hand.
Note that in the above example the first offset isn't 00 (for &1A00) as you might expect. This is because the previous routine spilled over onto page &1A by one byte and, since routines aren't always going to conveniently end on the last byte of a PAGE, it's more sensible to keep instructions which form one routine together.
  Number Formats
  
  In our example above (which, by the way, is a snippet of code from SWOOP which 
  we'll come on to discuss in a moment) there are two number formats. In CMP #10 
  I have specified 10 in decimal, yet in the last line of the example I have written 
  LDA #&00. The reason for this - instead of say, CMP #&A and LDA #0 respectively 
  - is that one number represents a co-ordinate and the other is the low byte 
  of a memory address. If I tell you that CMP #10 is comparing the player ship's 
  x co-ordinate with 10, and that &0E00 is a table of information about the 
  ship's co-ordinates (the first byte of which is the x co-ordinate) that need 
  to be set up for the sprite routine at &181B, then you'll understand that 
  it's a useful convention to specify the number according to its context.
This illustrates why it takes the human touch to diassemble the program into the meaningful "pages and sentences" mentioned earlier because a disassembler, which is an essential tool to get at the code in the first place, can't know the significance of the code it's disassembling. Of course, you may disagree entirely with my method of disassembly, but I believe it is the best way to go about it. On the other hand, if you adopt my system then please acknowledge it.
  Sprite Data - and use of Pseudo Extended EQU
  
  Sprite data is laid out according to how it is plotted on the screen, usually 
  one or sometimes two of the three formats represented below:
|  
       Type 1 
     | 
     
       Type 2 
     | 
     
       Type 3 
     | 
    |
| Column by char row |  
       Row by Row 
     | 
     
       Column by column 
     | 
    |
|  
       0 8 
     | 
     
       0 1 
     | 
     
       0 16 
     | 
    |
|  
       1 9 
     | 
     
       2 3 
     | 
     
       1 17 
     | 
    |
|  
       2 10 
     | 
     
       4 5 
     | 
     
       2 18 
     | 
    |
|  
       3 11 
     | 
     
       6 7 
     | 
     
       3 19 
     | 
    |
|  
       4 12  
     | 
     
       8 9 
     | 
     
       4 20 
     | 
    |
|  
       5 13 
     | 
     
       10 11 
     | 
     
       5 21 
     | 
    |
|  
       6 14  
     | 
     
       12 13 
     | 
     
       6 22 
     | 
    |
|  
       7 15 
     | 
     
       14 15 
     | 
     
       7 23 
     | 
    |
|  
       ------ 
     | 
     
       ------  
     | 
     
       ------ --- 
     | 
    Character row boundary | 
|  
       16 24 
     | 
     
       16 17 
     | 
     
       8 24 
     | 
    |
|  
       17 25 
     | 
     
       18 19 
     | 
     
       9 25 
     | 
    |
|  
       18 26 
     | 
     
       20 21 
     | 
     
       10 26 
     | 
    |
|  
       19 27 
     | 
     
       22 23 
     | 
     
       11 27 
     | 
    |
|  
       20 28  
     | 
     
       24 25 
     | 
     
       12 28 
     | 
    |
|  
       21 29  
     | 
     
       26 27  
     | 
     
       13 29 
     | 
    |
|  
       22 30  
     | 
     
       28 29  
     | 
     
       14 30 
     | 
    |
|  
       23 31  | 
     
       30 31  
     | 
     
       15 31 
     | 
    
 
  (For more information on sprite formats subject, see the documentation for EUGUSE 
  the Universal Sprite Editor.)
Example:
PAGE &16
  \egg sprite data
  4C:EQUB 3,8
  4E:EQUB 00,2A,00 \007000
  EQUB 15,3F,00 \077700
  EQUB 15,3F,00 \077700
  EQUB 3F,3F,00 \777770
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \077700
Here we have some sprite data (again, taken from SWOOP). The first two bytes specify that the sprite is three columns by eight rows big, and the next eight lines give the sprite data in hex without the ampersand. The comments (digits after the \ character) are a textual representation of the sprite, for example 0=black pixel, 1=red pixel, and so on.
The "Pseudo Extended EQU" is an invention of mine for convenience 
  of disassembly only. "Extended" because more than one number comes 
  after the EQUB EQUD, EQUW, or EQUS, each separated by commas. "Pseudo" 
  because you *can't actually do this ON THE bbc*; you have to either write lots 
  of separate EQUBs or READ in data from DATA lines. (It useful if there was such 
  a thing as extended assembler directives in BBC Basic, but that's
  life.)
  Missing/Unused Memory
  
  Sometimes, particularly in older games, pockets of memory are not used or are 
  filled with garbage. Such sections are not presented unless they are of interest 
  with regard to the rest of the game. For example, SWOOP contains coding for 
  a title page at &2492 (presumably a test version that the author was using) 
  never actually drawn unless the location &2800 is not equal to 33 - which 
  it never is!
If anyone can see errors in the disassembly then please let me know. Disassembling an entire game is a large undertaking and I don't expect to get it all correct.
 Christopher Dewhurst
  13 October 2001
Numerical Index of Routines in Swoop
  
  Addresses are in hex
181B Print sprite at new position, erase at old position
19D6 Move player ship
1A38 Move a bird
1B00 Clear kbd (cf 2000,2841)
  1B0B Init player bullet
  1B29 Move player bullet
  1BC5 Init bird bullet
1C4D Move bird bullets
1D26 Init bird explosion
1E00 Change colours 8,9,10,11
  1E64 Print hi score at (14,0)
  1E8A VDU 19,X,0;0;
  1EB4 Print egg at bottom of screen where bird was
  1ED8 Init egg/explosion
  1EF9 Ship explosion
1F58 Check if ship collided with egg
  1F9E Make level complete sound
  1FA7 Make egg sound
  1FB0 Sound routine
  1FC3 VDU 19,0,A;0;
  1FDE Make bird swoop sound on channel A
  1FED Choose whether bird fires bullet
2000 Clear kbd (cf 1B00,2B41)
  2013 MAIN LOOP
218F Add A to score and print hiscore if nec.
2243 Init player ship
  228F Set up mode 2 screen
  22CE Delay routine (cf 2A5E)
  22E3 Calculate bird block address &E20 + A*16
2307 Print text (cf 2A33)
  231E Check if player bullet has hit bird
2405 GET a key and check for escape (cf 2A49)
  2424 Make bird killed sound
  242D Define envelopes
  2431 Make ship exploding sound
  2464 Check if bird has hit ship
  24C9 Zeroise score, define envelopes, lives=3, init birds
  24EB Set mode 2 screen, init egg blocks, ship, bird positions, loop till
  player has lost their lives
  2520 Set mode 2 screen, all birds present, init player bullet block, egg
  block, print birds
  2549 Init a line of birds
  25B3 Reset attributes in egg blocks
  25D2 Init birds and signal all birds present
  25F9 Print flock of birds minus any killed
280C Init keys, main loop: REPEAT draw mode 7 scr, play game, check hi 
  score UNTIL FALSE
  2853 Draw mode 7 scr
  28D7 Clear name in hi score table
  28F1 Check score against those in table
2935 Move scores and names down one position
  2977 Set up input buffer for player's name
  299A Print starry backdrop
  29CA Move starry backdrop
2A33 Message print (cf 2307)
  2A49 GET a key and check escape (cf 2405)
  2A5E Delay routine (cf 22CE)
  2A73 Do MODE 7 and cursor off
  2A7E Check if A is 6th position in hi score table
  2A8B Calculate address of hi score data &2780 + A*16
  2AEE Print 16bit number with leading spaces
2B38 Print a digit or space if leading 0
  2B41 Clear kbd (cf 1B00,2000)
04:EQUW &1707 \player sprite data
10:BRK \player bullet x coordinate
  11:BRK \player bullet y coordinate
  14:EQUW 0 \player bullet sprite addr
  19:EQUW 0 \player bullet old scr addr
  &E20 - &FFF
  
  30 16-byte blocks of bird data. Attributes at beginning of game are as
  follows:
Offset 
  00:EQUB 16 \x coordinate (16 for 1st bird) 
  01:EQUB 16 \y coordinate (16 for 1st bird) 
  02:EQUB 1 \presence flag, 1=present, 0=absent 
  03: 
  04:EQUW &1526 \sprite addr 
  06:EQUW &80xx \old scr addr 
  08:EQUW &3540 \new scr addr (&3540 for 1st bird)
  0A
  0B
  0C:BRK \homing byte
  Page &1000-&107F
  
  8 16-byte bird bullet blocks
  Page &1080-&11EF
  
  16 16-byte egg/explosion blocks
 E0:EQUB -98 \INKEY code for left key
  E1:EQUB -67 \INKEY code for right key
  E2:EQUB 47 \ASCII code for fire key
  E3:
  E4:BRK \silence flag, sound on=0, sound off=1
  E5:EQUW 0 \copy of score at end of game
PAGE &15
  
  \Each sprite comprises [columns,rows] in decimal
  \then (column x rows) of data in hex
\bird up sprite data
  26:EQUB 6,8
  28:EQUB 04,00,00,00,00,08 \020000000020
  EQUB 04,08,05,0A,04,08 \022003300220
  EQUB 00,0C,0D,0E,0C,00 \002223322200
  EQUB 00,04,0C,0C,08,00 \000222222000
  EQUB 00,00,0C,0C,00,00 \000022220000
  EQUB 00,00,26,19,00,00 \000052250000
  EQUB 00,00,22,11,00,00 \000050050000
  EQUB 00,00,22,11,00,00 \000050050000
\bird down sprite data
  88:EQUB 6,8
  8A:EQUB 00,00,00,00,00,00 \000000000000
  EQUB 00,00,05,0A,00,00 \000003300000
  EQUB 00,04,0D,0E,08,00 \000223322000
  EQUB 00,0C,0C,0C,0C,00 \002222222200
  EQUB 04,08,0C,0C,04,08 \022022220220
  EQUB 04,00,0C,19,00,08 \020022250020
  EQUB 00,00,22,11,00,00 \000050050000
  EQUB 00,00,22,11,00,00 \000050050000
  PAGE &16
  
  \egg sprite data
  4C:EQUB 3,8
  4E:EQUB 00,2A,00 \007000
  EQUB 15,3F,00 \077700
  EQUB 15,3F,00 \077700
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \777770
  EQUB 3F,3F,2A \777770
  EQUB 15,3F,00 \077700
\'20' bonus sprite data
  8A:EQUB 3,5
  8C:EQUB F0,50,F0 \CC0CCC
  EQUB 50,50,50 \0C0C0C
  EQUB F0,50,50 \CC0C0C
  EQUB A0,50,50 \C00C0C
  EQUB F0,50,F0 \CC0CCC
\player bullet sprite data
  F3:EQUB 1,8
  F5:EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
  EQUB 2A \70
FD:EQUB 1,8
  FE:EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  EQUB 28 \60
  PAGE &17
  
  \player ship sprite data
  07:EQUB 4,12
  09:EQUB 00,05,00,00 \00030000
  EQUB 00,05,00,00 \00030000
  EQUB 00,05,00,00 \00030000
  EQUB 00,0F,0A,00 \00333000
  EQUB 00,0F,0A,00 \00333000
  EQUB 40,0F,4A,00 \08333800
  EQUB 01,85,81,00 \01838100
  EQUB 03,85,81,02 \11838110
  EQUB 03,07,03,02 \11131110
  EQUB 03,07,03,02 \11131110
  EQUB 03,02,03,02 \11101110
  EQUB 03,02,03,02 \11101110
\bird/egg explosion sprite data 
  39:EQUB 4,12
  3B:EQUB 00,CD,45,00 \00AB0B00
  EQUB 45,40,88,00 \0B08A000
  EQUB CE,41,41,88 \BA0909A0
  EQUB 40,82,00,00 \08900000
  EQUB 00,88,C2,88 \00A098A0
  EQUB CE,C2,41,45 \BA98090B
  EQUB 00,00,80,88 \000080A0
  EQUB 44,41,40,45 \0A09080B
  EQUB 00,8A,82,8A \00B090B0
  EQUB 45,44,44,88 \0B0A0AA0
  EQUB 00,45,C4,00 \000B8A00
  EQUB 00,00,00,00 \00000000
\player ship explosion sprite data
  6B:EQUB 9,16
  6D:EQUB 00,00,00,00,00,00,00,00,00 \000000000000000000
  EQUB 00,00,00,00,00,00,00,00,00 \000000000000000000
  EQUB 00,00,00,8A,8A,8A,8A,00,00 \000000B0B0B0B00000
  EQUB 00,00,8A,00,00,00,00,00,00 \0000B0000000000000
  EQUB 00,00,45,00,8A,45,00,8A,00 \00000B00B00B00B000
  EQUB 00,45,00,00,88,88,00,00,00 \000B0000A0A0000000
  EQUB 00,00,00,8A,00,00,45,00,00 \000000B000000B0000
  EQUB 45,00,8A,00,8A,8A,88,00,8A \0B00B000B0B0A000B0
  EQUB 00,45,00,8A,CD,88,00,45,00 \000B00B0ABA0000B00
  EQUB 00,00,45,88,82,00,8A,88,45 \00000BA09000B0A00B
  EQUB 45,00,00,41,41,C2,CD,00,8A \0B0000090998AB00B0
  EQUB 00,8A,8A,C2,00,41,00,00,00 \00B0B0980009000000
  EQUB 00,44,41,00,82,00,C6,CE,00 \000A090090009ABA00
  EQUB 00,00,44,C1,C1,40,00,00,8A \00000A8989080000B0
  EQUB 00,00,CE,00,C2,82,C2,45,00 \0000BA009890980B00
  EQUB 45,CE,41,C1,C1,C2,00,8A,45 \0BBA0989899800B00B
00:JMP &1806 \EXECUTE
  03:JMP &24C9 \zeroise score, define envelopes etc
  06:LDA &2800:CMP #33:BNE &1810 \?&2800 is always 33
  JMP &2801 \so we always go to &2801
\ the top level layout of the game is this:
  \ &1800:JMP &1806
  \ &1806:JMP &2801
  \ &2801:JMP &280C
  \ &280C:REPEAT set up keys, draw mode 7 screen, play game until all lives
  \ lost, check score against hi scores, enter name if required UNTIL FALSE
\ if you change ?&2800 to any number <> 33 the following will happen:
  10:LDA #0:STA &2490:STA &2491 \zeroise hi score
  JMP &2492 \and jump to alternate title page
\ *** sprite routine ***
  \ entry: &82/3 points to parameter block:
  \ 0 x coordinate of sprite
  \ 1 y coordinate of sprite
  \ 4-5 new sprite data addr
  \ 6-7 old sprite data addr
  \ 9-10 old screen addr. 
  \ Offset 9 usually set to &80 by routines to give &80xx, an address 
  in ROM, 
  \ when plotting sprite on scr for 1st time.
  
  \exit: &82/3 points to updated parameter block, extra details as thus:
  \ 8 y coordinate AND 7
  \ 11 x coordinate AND 1
\calculate screen address
  \in Basic this would be &3000 + (x AND &FE)*8 + (x AND 7) +
  \ (y AND &F8)*80 + (y AND 7) 
  1B:LDY #0:LDA (&82),Y \get x coordinate
  AND #1:STA &70 \odd or even coordinate
  LDA (&82),Y:AND #&FE:STA &72 \remainder
  STY &73:STY &75 \zeroise &73/75
  ASLA:ROL &73:ASLA:ROL &73:STA &72 \now &72/3 = (x AND &FE)*8
  INY:LDA (&82),Y \get y coordinate
  AND #7:STA &71 \&71 = row within char row
  LDA (&82),Y:AND #&F8 \remainder
  ASLA:ROL &75:ASLA:ROL &75
  ASLA:ROL &75:ASLA:ROL &75:STA &74 \&74/5 = (y AND &F8)*16
  LDA &75:STA &77
  LDA &74:ASLA:ROL &77
  ASLA:ROL &77:STA &76 \&76/7 = (y AND &F8)*64 
  LDA &72:CLC:ADC &71:STA &72
  LDA &73:ADC #0:STA &73 \(x AND &FE)*8 + (x AND 7)
  LDA &72:CLC:ADC &74:STA &72
  LDA &73:ADC &75:STA &73 \ + (y AND &F8)*16
  LDA &72:CLC:ADC &76:STA &72
  LDA &73:ADC &77:STA &73 \ + (y AND &F8)*64
  NOP:CLC:ADC &72:STA &72
  LDA #&30:NOP:CLC:ADC &73:STA &73 \ + &3000
93:LDY #4:LDA (&82),Y:STA &74 \
  INY:LDA (&82),Y:STA &75 \Y=5, &74/5 = new sprite data address
  INY:LDA (&82),Y:STA &76 \Y=6
  INY:LDA (&82),Y:STA &77 \Y=7, &76/7 = old sprite address
  INY:LDA (&82),Y:STA &7C \Y=8, &7C = (old y AND 7)
  INY:LDA (&82),Y:STA &7A \Y=9 
  INY:LDA (&82),Y:STA &7B \Y=10 ,&7A/B old screen address
  INY:LDA (&82),Y:STA &7D \Y=11. &7D = (oldx AND 1)
  LDY #0:LDA (&74),Y:STA &78 \&78 = rows
  INY:LDA (&74),Y:STA &79 \Y=1, &79 = columns 
  LDY #6:LDA &74:STA (&82),Y \
  INY:LDA &75:STA (&82),Y \Y=7, sprite data address
  INY:LDA &71:STA (&82),Y \Y=8 (new y AND 7)
  INY:LDA &72:STA (&82),Y \Y=9
  INY:LDA &73:STA (&82),Y \Y=10 new screen address
  INY:LDA &70:STA (&82),Y \Y=11 (new x AND 1)
  
  DEC &79
  LDA &74:CLC:ADC #2:STA &74 \was pointing to rows+columns data
  LDA &75:ADC #0:STA &75 \now point to sprite data itself
  LDA &76:CLC:ADC #2:STA &76 \
  LDA &77:ADC #0:STA &77 \
PAGE &19
  
  \ remember
  \ &71 = y AND 7, counter indicating position in char row
  \ &72/3 = new scr addr
  \ &74/5 = new sprite addr
  \ &76/7 = old sprite addr
  \ &78 = rows
  \ &79 = columns
  \ &7A/B = old scr addr
02:LDY #0:JSR &190B 
  DEC &79:BNE &1902 \dec columns until all done
  0B:LDX &78 \load rows count
  LDA &72:PHA:LDA &73:PHA \preserve new scr
  LDA &7A:PHA:LDA &7B:PHA \preserve old scr
  \plot byte at new scr addr
  19:LDA &70:BEQ &1938 \even newx so don't split byte
  LDA (&74),Y:BEQ &1940 \zero byte (you don't really need to do this)
  LSRA:AND #85 \mask right pixel
  EOR (&72),Y:STA (&72),Y \store right pixel in this column
  LDA (&74),Y:ASLA:AND #170 \mask left pixel
  LDY #8 \point to next column
  EOR (&72),Y:STA (&72),Y
  LDY #0:JMP &1940 \point to last column and jump back
  \store pixels straight in memory without splitting
  38:LDA (&74),Y:BEQ &1940
  EOR (&72),Y:STA (&72),Y
  \plot byte at old scr addr
  40:LDA &7D:BEQ &195F \even oldx so don't split pixels
  LDA (&76),Y:BEQ &1967
  LSRA:AND #85 \mask right pixel
  EOR (&7A),Y:STA (&7A),Y \store right pixel in this column
  LDA (&76),Y:ASLA:AND #170 \mask left pixel
  LDY #8 \point to next column
  EOR (&7A),Y:STA (&7A),Y
  LDY #0:JMP &1967 \point to last column and jump
  \store pixels in memory without splitting
  5F:LDA (&76),Y:BEQ &1967
  EOR (&7A),Y:STA (&7A),Y
  67:LDA &72:CLC:ADC #8:STA &72 \point to next column
  BCC &1972:INC &73 \new scr=new scr + 8
  72:LDA &7A:CLC:ADC #8:STA &7A \point to next column
  BCC &197D:INC &7B \old scr=old scr + 8
  7D:INC &74:BNE &1983:INC &75 \new data=new data + 1, next byte of 
  new sprite
  83:INC &76:BNE &1989:INC &77 \old data=old data + 1, next byte of 
  old sprite
  89:DEX:BEQ &198F:JMP &1919 \loop till all rows done
  8F:PLA:STA &7B:PLA:STA &7A \restore original old scr
  PLA:STA &73:PLA:STA &72 \restore original new scr
  INC &71:LDA &71:AND #7:BEQ &19AC \bottom of char row
  INC &72:BNE &19B9:INC &73 \new scr=new scr+1
  B9:JMP &19B9
  AC:LDA &72:CLC:ADC #&79:STA &72
  LDA &73:ADC #2:STA &73 \new scr = new scr + &279
  B9:INC &7C:LDA &7C:AND #7:BEQ &19C8 \bottom of char row
  INC &79:BNE &19D5:INC &7B
  RTS
  C8:LDA &7A:CLC:ADC #&79:STA &7A
  LDA &7B:ADC #2:STA &7B \old scr = old scr + &279
  D8:RTS
\ *** move player ship ***
  D6:BRK \copy of shipx
  LDA &E00:STA &19D6
  LDX &11E1 \get INKEY code for right
  JSR &1A2A:CPY #&FF:BNE &19F4 \not pressed
  INC &E00:LDA &E00:CMP #140:BNE &19F4 \not at maximum right
  DEC &E00 \put back to left
  F4:LDX &11E0 \get INKEY code for left
  JSR &1A2A:CPY #&FF:BNE &1A0B \not pressed
  DEC &E00
 PAGE &1A
  
  01:LDA &E00:CMP #10:BNE &1A0B \ship not at maximum left
  INC &E00 \put back to right
  0B:LDA &E00:CMP &19D6:BEQ &1A22 \ship hasn't moved so don't print
  LDA #&00:STA &82:LDA #&0E:STA &83:JSR &181B \print ship
  JSR &1F58 \check for collision
  RTS
  22:JSR &1F58 \check if collided with egg
  LDX #6:JMP &22CE \delay
\ *** check for keypress ***
  \ entry: X=INKEY number
  \ exit: A and X preserved
  2A:PHA:TXA:PHA
  LDA #&81:LDY #&FF:JSR osbyte
  PLA:TAX:PLA
  RTS
\ *** move bird ***
  \ entry: &8E/8F points to data block of bird to be moved
  38:LDY #1:LDA (&8E),Y \birdy =
  TAX:INX:TXA:STA (&8E),Y \birdy + 1
  AND #15:BNE &1A48 \wings change position every 16th line
  JSR &1ACA \swap bird sprite
  48:LDY #1:LDA (&8E),Y:CMP #236:BNE &1A5F \birdy <> 236
  JSR &1EAE \put egg
  LDY #1:LDA #8:STA (&8E),Y \set birdy=8
  JSR &1FDE \swoop sound
  5F:LDY #14:LDA (&8E),Y
  CLC:ADC #32:AND #&F0
  CMP #32:BEQ &1A95:BMI &1A83
  LDY #0:LDA (&8E),Y:SEC:SBC #1:STA (&8E),Y \birdx = birdx - 1
  CMP #2:BCS &1A95 \ birdx >= 2
  CLC:ADC #1:STA (&8E),Y:JMP &1A95
  83:LDY #0:LDA (&8E),Y:SEC:ADC #0:STA (&8E),Y \birdx = birdx + 1
  CMP #147:BCC &1A95 \ birdx <= 147
  SEC:SBC #1:STA (&8E),Y
  95:JSR &1EA3 \print egg
  JSR &2464 \check collision
  LDY #0:LDA (&8E),Y:CMP &E00:BEQ &1AB7 \birdx = shipx
  BCC &1AB8 \birdx < shipx
  LDY #14:LDA (&8E),Y:CLC:ADC #1:STA (&8E),Y
  CMP #32:BNE &1AB7
  LDA #31:STA (&8E),Y
  B7:RTS
B8:LDY #14:LDA (&8E),Y
  CLC:SBC #0:STA (&8E),Y
  CMP #224:BNE &1AB7
  LDA #225:STA (&8E),Y:RTS
\ *** change bird wing position ***
  \ if bird sprite addr is &1526 change to &1588 and vice versa
  CA:LDY #4:LDA (&8E),Y \get sprite data hi
  CMP #&26:BNE &1AD7
  LDA #&88:STA (&8E),Y:RTS
  D7:LDA #&26:STA (&8E),Y:RTS
  
  DC:LDA &E10:BNE &1B29 \player bullet x is active
  LDA #129:LDX #0:LDY #0:JSR osbyte
  CPY #0:BNE &1AFB \key not pressed
  CPX &11E2:BEQ &1B0B \fire key pressed
  CPX #ASC"P":BEQ &1B00:CPX #ASC"p":BEQ &1B00 \pause 
  pressed
  LDX #1:JMP &22CE \delay to slow down game
PAGE &1B
  
  00:JSR &2000 \clear kbd
  LDA #7:JSR oswrch:JMP &2405 \beep and wait for key press
\ *** init player bullet ***
  0B:LDA &E00:CLC:ADC #3:STA &E10 \bulletx at shipx+3
  LDA #230:STA &E11 \bullety at 230
  LDA #&80:STA &E1A \old screen &80xx
  LDA #&10:STA &82:LDA #&0E:STA &83 \point to &E10
  JMP &181B \and call sprite routine to print bullet
\ *** move player bullet up screen ***
  29:DEC &E11 \bullety = bullety -1
  LDA &E11:CMP #11:BCS &1B4E \bullety >= 11 so at top of scr yet
  LDA #&10:STA &82:LDA #&0E:STA &83 \point to &E10
  JSR &181B \erase bullet
  LDA #0:STA &E10 \signal bullet now inactive
  JMP &2000 \clear keybd
  4E:LDA &E19:STA &70:LDA &E1A:STA &71 \old screen
  JSR &1B69 \move bullet up
  LDA &70:STA &E19
  LDA &71:STA &E1A:JSR &231E
  RTS
\ *** print bullet at addr in &70/1 ***
  \ uses &70/1 = addr of top of bullet
  \ &72 = pixel code to be written
  \ &73/4 = &70/1 + &280, addr of bottom of bullet
  69:LDA &70:AND #7:BNE &1B7F \in row
  LDA &70:SEC:SBC #&79:STA &70
  LDA &71:SBC #2:STA &71 \screen=screen + &279
  JMP &1B8C
  7F:LDA &70:SEC:SBC #1:STA &70
  LDA &71:SBC #0:STA &71 \screen=screen - 1
  LDA &E1B:CMP #1:BNE &1B9A
  LDA #21:STA &72 \code for black-white
  JMP &1B9E
  9A:LDA #42:STA &72 \code for white-black
  DEC &E18:LDA &E18:AND #7:STA &E18 \old row no
  LDY #0:LDA &72:EOR (&70),Y:STA (&70),Y \print top pixel of bullet
  LDA &70:CLC:ADC #&80:STA &73
  LDA &71:ADC #2:STA &74 \add &280 to get bottom of bullet
  EOR (&73),Y:STA (&73),Y \erase bottom pixel of bullet
  RTS
\ *** init bird bullet ***
  \ entry; &8E/F point to bird block
  C5:LDY #2:LDA (&8E),Y:BNE &1BCC \bird active
  RTS
  CC:LDY #0:LDA (&8E),Y \bird bulletx will be
  CLC:ADC #6:STA &74 \at birdx + 6
  LDA #&00:STA &70:STA &73
  LDA #&10:STA &71 \&70/71 points to 1st bullet block
  LDA &248F:AND #6:CLC:ADC #2:STA &72 \(level AND 6) + 2
  E9:LDY #2:LDA (&70),Y \get bullet state
  BNE &1BFE \bullet block in use
  LDA &70:STA &75:LDA &71:STA &76
  LDA #1:STA &73 \signify free block found
  FE:LDY #0
PAGE &1C
  
  00:LDA (&70),Y:CMP &74:BEQ &1C1B \get
  LDA &70:CLC:ADC #16:STA &70 \point to
  LDA &71:ADC #0:STA &71 \next bullet block
  DEC &72:BNE &1BE9 \loop until block found
  LDA &73:BNE &1C1C \and coords aren't same as another bullet
  1B:RTS
  LDA #1:LDY #2:STA (&72),Y \singal bullet active
  LDY #0:LDA &74:STA (&75),Y
  LDY #1:LDA (&8E),Y:CLC:ADC #6:STA (&75),Y \store birdy+6
  LDY #4:LDA #&FD:STA (&75),Y
  INY:LDA #&16:STA (&75),Y \bird bullet data @&16FD
  LDY #10:LDA #&80:STA (&75),Y \old scr &80xx
  LDA &75:STA &82:LDA &76:STA &83
  JMP &181B
\ *** check bird bullets ***
  4D:LDA #&00:STA &8B:LDA #&10:STA &8C \&8B/8C point to 1st 
  bullet block
  LDA #8:STA &8D \count 8 blocks
  59:LDY #2:LDA (&8B),Y:CMP #1:BEQ &1C91 \bullet active
  LDA &8B:CLC:ADC #16:STA &8B
  LDA &8C:ADC #0:STA &8C \point to next block
  DEC &8D:BNE &1C59 \loop till all bullets checked
  RTS
  73:LDY #1:LDA (&8B),Y:CMP #232:BCC &1C90 \bullety <= 232
  DEY:LDA (&8B),Y:CMP &E00:BCC &1C90 \bulletx < shipx
  CLC:SBC #6:CMP &E00:BCS &1C90 \bulletx + 5 > shipx
  PLA:PLA:PLA:PLA \ship hit
  90:RTS
\ move bird bullet, block addr in &8B/C
  91:LDY #1:LDA (&8B),Y:CLC:ADC #1:STA (&8B),Y \bullety=bullety + 1
  CMP #246:BCS &1D05 \bullety > 246
  LDY #9:LDA (&8B),Y:STA &70
  INY:LDA (&8B),Y:STA &71
  LDA &70:CLC:ADC #&80:STA &73 \bottom of bullet &280 bytes
  LDA &71:ADC #2:STA &74 \or 1 char row away from top of bullet
  INY:LDA (&8B),Y \get old (x AND 1)
  CMP #1:BNE &1CC4 \=0 so even coord
  LDA #20:STA &72 \code for black-cyan
  JMP &1CC8
  C4:LDA #40:STA &72 \code for cyan-black
  C8:LDA &72:LDY #0:EOR (&70),Y:STA (&70),Y \erase top of bullet
  LDA &72:EOR (&73),Y:STA (&73),Y \add to bottom of bullet
  LDA &70:AND #7:CMP #7:BNE &1CEE \not at bottom of row
  LDA &70:CLC:ADC #&79:STA &70
  LDA &71:ADC #2:STA &71 \scr = scr + &279
  JMP &1CF4
  EE:INC &70:BNE &1CF4:INC &71 \scr = scr + 1
  F4:LDY #9:LDA &70:STA (&8B),Y \put new addr of bullet
  INY:LDA &71:STA (&8B),Y \back in bird block
  JSR &1C73 \check if ship hit
PAGE &1D
  
  02:JMP &1C61 \loop to check next bullet
  \ bullet has reached bottom of scr
  05:LDY #1:SEC:SBC #1:STA (&8B),Y \y=y-1
  LDA #&80:LDY #10:STA (&8B),Y \old scr &80xx
  LDA &8B:STA &82:LDA &8C:STA &83
  JSR &181B \print bullet
  LDY #2:LDA #0:STA (&8B),Y \signal bullet inactive
  JMP &1C61 \loop to check next bullet
\*** init egg block ***
  \entry: &70/1 = sprite addr
  \ &74 = timer countdown value before change of state (e.g. egg -> explosion)
  \ &78 = state: 1 for explosion or 2 for an egg
  26:LDA #&80:STA &75:LDA #&10:STA &76 \first egg block @&1080
  LDA #16:STA &77 \count 16 blocks
  32:LDY #2:LDA (&75),Y:CMP #0:BNE &1D69 \block occupied
  LDA &78:STA (&75),Y \store timer
  LDA &74:INY:STA (&75),Y \store state
  INY:LDA &70:STA (&75),Y \store new
  INY:LDA &71:STA (&75),Y \scr addr
  LDY #0:LDA &72:STA (&75),Y \store eggx
  INY:LDA &73:STA (&75),Y
  LDY #10:LDA #&80:STA (&75),Y \old screen &80xx
  LDA &75:STA &82:LDA &76:STA &83 \transfer egg block to sprite 
  ptr
  JMP &181B \print egg
  69:LDA &75:CLC:ADC #16:STA &75
  LDA &76:ADC #0:STA &76 \point to next block
  DEC &77:BNE &1D32 \loop till all blocks checked
  RTS
\ *** countdown timer for egg or explosion ***
  7B:LDA #&80:STA &75:LDA #&10:STA &76 \1st egg block &1080
  LDA #16:STA &77 \count 16 blocks
  LDY #2:LDA (&75),Y:BEQ &1DEE \not active
  INY:LDA (&75),Y:SEC:SBC #1:STA (&75),Y \timer = timer -1
  BNE &1DEE \not 0 yet
  DEY:LDA (&75),Y:CMP #1:BEQ &1DAA \status=1
  CMP #2:BEQ &1DAA \status=2
  SEC:SBC #1:STA (&75),Y:JMP &1DEE
  AA:LDY #10:LDA #&80:STA (&75),Y \old screen &80xx
  LDA &75:STA &82:LDA &76:STA &83 \egg block addr to &82/83
  LDA &75:PHA:LDA &&76:PHA \preserve current block addr
  LDA &77:PHA \and timer
  JSR &181B \erase egg
  PLA:STA &77 \restore timer
  PLA:STA &66:PLA:STA &75 \and addr
  LDY #2:LDA (&75),Y:CMP #2:BEQ &1DDC \status=2 so do explosion
  LDA #0:STA (&75),Y \status=1
  JMP &1DEE
  DC:LDA #0:STA (&75),Y
  LDY #0:LDA (&75),Y:STA &72
  INY:LDA (&75),Y:STA &73:JSR &1EE6 \print explosion
  EE:LDA &75:CLC:ADC #16:STA &75 \point to next
  LDA &76:ADC #0:STA &76 \egg block
  DEC &77:BNE &1D87 \loop till egg blocks checked
  RTS
PAGE &1E
  
  \ *** fancy colours ***
  00:LDA &200F:AND #15:BEQ &1E08 \change colour every 16th count
  RTS
  08:LDA #0:STA &70
  0C:LDA &200F:AND #&F0:LSRA:LSRA:LSRA:LSRA
  CLC:ADC &70:AND #3:PHA 
  LDA #19:JSR oswrch \VDU 19,
  LDA &70:CLC:ADC #8:JSR oswrch \ ?&70+8,
  PLA:JSRoswrch \((count DIV 16)+?&70) AND 3 
  LDA #0:JSR oswrch:JSR oswrch:JSR oswrch
  INC &70:LDA &70:CMP #4:BNE &1E0C \loop till colours 8,9,10,11 are 
  done
  LDA #19:JSR oswrch \VDU19,
  LDA &200F:LSRA:LSRA:LSRA:LSRA:AND #3 \
  CLC:ADC #1:JSR oswrch \(?&200F DIV 16) AND 3 + 1
  LDA #0:JSR oswrch:JSR oswrch:JSR oswrch
  RTS
\ *** print hi score ***
  64:LDA #31:JSR oswrch:LDA #14:JSR oswrch:LDA #0:JSR oswrch \VDU31,14,0
  LDA &2490:STA &70:LDA &2491:STA &71 \hi score -> &70/71
  JSR &21FC \print number
  LDA #17:JSR oswrch:LDA #7:JMP oswrch \COLOUR 7
\ *** VDU 19,2,X;0; ***
  8A:LDA #19:JSR oswrch:LDA #2:JSR oswrch \VDU 19,2,
  TXA:JSR oswrch:LDA #0:JSR oswrch:JSR oswrch:JMP oswrch \X,0,0,0
A3:LDA &11E3:BEQ &1EB4
  RTS
  B4:JSR &1FA7 \egg sound
  LDY #0:LDA (&8E),Y:CLC:ADC #4:STA &72 \birdx + 2
  INY:LDA (&8E),Y:STA &73 \birdy
  LDA #3:STA &78
  LDA #&4C:STA &70:LDA #&16:STA &71 \egg sprite @&164C
  JMP &1D26 \insert into egg block
\ *** exploding egg/bird ***
  D8:LDY #0:LDA (&8E),Y:CLC:ADC #2:STA &72 \birdx + 2
  INY:LDA (&8E),Y:STA &73 \birdy
  E6:LDA #50:STA &74 \timer
  LDA #1:STA &78 \egg status=1
  LDA #&39:STA &70:LDA #&17:STA &71 \explosion sprite @&1739
  JMP &1D26 \insert into block
\ *** ship explosion ***
  F9:LDA #&00:STA &82:LDA #&0E:STA &83 \point to ship block
PAGE &1F
  
  01:LDA #&80:STA &E0A \old addr =&80xx
  JSR &181B \erase ship
  LDA &E00:SBC #4:STA &73 \shipx-4
  LDA #90:STA &74 \timer
  LDA #1:STA &78 \status
  LDA #&6B:STA &70:LDA #&17:STA &71 \explosion sprite @&176B
  JSR &1D26
  LDA #7:JSR &1FC3 \do VDU19,0,7;0;
  LDX #20:JSR &22CE \delay
  JSR &2451 \explosion sound
  LDA #2:STA &200F
  LDA #90
  45:LDX #13:JSR &22CE \delay
  INC &200F:PHA:JSR &1E00 \fancy colours
  PLA:SEC:SBC #1:BNE &1F45
  RTS
\ *** check if ship has collided with egg ***
  58:LDA #&80:STA &70:LDA #&10:STA &71 \first egg block @&1080
  STA &72 \count 16 eggs
  62:LDY #2:LDA (&70),Y:CMP #2:BEQ &1F71 \get status
  CMP #3:BEQ &1F71 \1 if exploding
  JMP &1F8C \so loop to next block
  71:LDA &E00:CLC:ADC #5 \shipx + 5
  DEY:DEY:CMP (&70),Y:BCC &1F8C \without 5 pixels
  LDA (&70),Y:CLC:ADC #4 \get eggx + 4
  CMP &E00:BEQ &1F8C \
  PLA:PLA:PLA:PLA:RTS \collision
  8C:LDA &70:CLC:ADC #16:STA &70 \point to next block
  LDA &71:ADC #0:STA &71
  DEC &72:BNE &1F62 \loop till all eggs examined against ship
  RTS
\ *** make level complete sound, data @&26F7 ***
  9E:LDX #&F7:LDY #&26:LDA #7:JMP &1FB0
\ *** make egg sound, data @&270D ***
  A7:LDX #&0D:LDY #&27:LDA #7:JMP &1FB0
\ *** sound routine ***
  B0:CMP #7:BEQ &1FB7:JMP osword \A<>7 for e.g. defining envelope
  B7:PHA:LDA &11E4:BEQ &1FBF \if silence flag =0 make sound
  PLA:RTS \else just return
  BF:PLA:JMP osword
\ *** VDU19,0,A;0; ***
  C3:PHA:LDA #19:JSR oswrch:LDA #0:JSR oswrch \VDU19,0,
  PLA:JSR oswrch \A,
  LDA #0:JSR oswrch:JSR oswrch:JSR oswrch:RTS \0,0,0
\ *** make bird swoop sound on channel A ***
  DE:CLC:ADC #&10:STA &2716 \add &10 to force sound
  LDX #&16:LDY #&27:LDA #7:JMP &1FB0
\ *** choose if bird will drop bullet ***
  ED:LDY #7:LDA (&8E),Y \get birdy
  AND #7:BNE &1FFF \not multiple of 8
  LDA &FE44 \get a 'changing number'
  CMP #63:BCC &1FFF \exit if <=63
  JSR &1BC5 \else init bird bullet
  FF:RTS
 PAGE &20
  
  00:LDA #15:LDX #0:LDY #0:JMP osbyte \clear kbd
  09:BRK \1st bird no in flight
  0A:BRK \bird x dir +/-2
  0B
  0C
  0D:BRK \no birds killed
  0E:BRK \2nd bird no in flight
  0F:BRK \delay for star backdrop
  10:BRK \ level AND 1
  11:
  12:
13:JSR &2000 \clear kbd
  LDA #2:STA &200A \set bird dx = 0
  STA &200D \no birds killed = 0
  STA &2011
  STA &200C
  LDA #31:STA &200E \bird count =31
  LDA &248F:AND #1:STA &2010 \get (level AND 1)
  LDA #2:JSR &1FDE \bird swoop sound on ch2
  LDA &2010:BEQ &2045 \even level so don't
  LDA #3:JSR &1FDE \do bird swoop sound on ch3
  45:LDA #0:STA &2009 \bird to fly = 0
  INC &2011
  4D:INC &200F \inc star delay
  JSR &1E00 \change colours
  JSR &1ADC \check fire and pause
  JSR &1D7B \egg timer
  JSR &241F \check escape
  JSR &19D7 \move ship
  JSR &1ADC \check fire and pause again
  LDA #2:STA &2012
  LDA &200F:AND #1:BEQ &2071:JMP &2807 \move stars every 2nd count
  71:LDA &200D:JSR &22E3 \calc bird block address
  LDY #2:LDA (&8E),Y:BNE &208F \extant
  INC &200D \increase 1st bird no in flight
  LDA #2:JSR &1FDE \swoop next bird on ch2
  LDA &200D:CMP #30:BNE &2071 \30 birds not killed yet
  JMP &216D \next level
  8F:JSR &1A38 \bird flies down
  LDA &2463:BEQ &2098 \loop till dead flag is TRUE
  RTS \dead so return
  98:JSR &1FED \choose rnd to see if bird will fire
  LDA #3:STA &2012
  JSR &1C4D \check bullets
  JSR &1ADC \check fire and pause
  A6:LDA &2010:BEQ &20DB \even level
  LDA &200E:JSR &22E3 \calc bird block address
  LDY #2:LDA (&8E),Y:BNE &20C9 \extant
  DEC &200E \decrease 2nd bird no in flight
  LDA #3:JSR &1FDE \swoop next bird on ch3
  LDA &200E:CMP #&FF:BNE &20A6
  JMP &216D \next level
  C9:JSR &1A38 \bird flies down
  LDA &2463:BEQ &20D2 \dead = FALSE
  RTS \player killed
  D2:JSR &1FED \choose rnd to see if bird will fire
  JSR &1C4D \check bullets
  JSR &1ADC \check fire and pause
  DB:LDA &248F:CMP #6:BCC &20E5 \level <= 6
  JSR &1C4D \check bullets
  E5:LDA &200F:AND #3:BEQ &20EF
  JMP &204D
  EF:LDA &2009:CMP &200D:BEQ &213D
  LDA &2010:BEQ &2104 \even level (easy)
  LDA &2009:CMP &200E:BEQ &213D
  
  
   PAGE &21
  
  04:LDA &200A:JSR &22E3 \calc bird block address
  JSR &1ACA \change wing position
  LDY #2:LDA (&8E),Y:BEQ &213A \bird not present
  13:LDY #0:LDA (&8E),Y:CLC:ADC &200A \birdx = birdx + dx
  CMP #6:BCC &2156 \birdx <= 6 so change dx
  CMP #144:BCS &2167 \birdx >= 144 so change dx
  LDA &8E:STA &82:LDA &8F:STA &83 \point to current bird block
  JSR &181B \print bird
  LDA &FE44:CMP #150:BCC &213A \rnd <= 150
  JSR &1BC5 \init bullet
  3A:JSR &1C4D \check bullets
  3D:INC &2009:CMP #30:BEQ &2153
  JSR &22E3 \calc bird block address
  LDY #2:LDA (&8E),Y:BEQ &213D \not present
  JMP &204D 
  53:JMP &2045
  56:LDA &200A:CMP #2:BNE &2165 \dx=-2
  LDA #-2:STA &200A \set dx=-2
  JMP &2113
  65:LDA #2:STA &200A \set dx=2
  JMP &2113
\ *** next level! ***
  6D:INC &248F \level = level + 1
  LDA &248F:AND #1:BNE &217D \(level AND 1) <> 0
  INC &E02 \award extra life after even level
  JSR &1F9E \make whacky sound
  7D:LDA &248F:CMP #8:BNE &2189 \level <> 8
  LDA #6:STA &248F \reset level to 6
  89:JSR &2520 \set screen for next lot
  JMP &2013 \back to main loop
\*** add A to score ***
  8F:CLC:ADC &248B:STA &248B
  LDA &248C:CMP &2491:BCC &21CC
  BNE &21B3
  LDA &2490:CMP &248B:BCC &21B3
  JMP &21CC
  B3:LDA &248B:STA &2490
  LDA &248C:STA &2491 \hiscore = score
  LDA #17:JSR oswrch:LDA #12:JSR oswrch \COLOUR 12
  JSR &1E64 \print hi score
  CC:LDA #31:JSR oswrch:LDA #2:JSR oswrch:LDA #0:JSR oswrch \VDU31,2,0
  LDA #17:JSR oswrch \COLOUR
  LDA #7:SEC:SBC &248F \7 - (score AND &FF)
  CLC:ADC #1:CMP #8:BNE &21EF \if colour=8
  LDA #3 \then colour=3
  EF:JSR oswrch
  LDA &248B:STA &70:LDA &248C:STA &71
  FC:LDY #0
  FE:LDX #0
PAGE &22
  
  00:SEC:SBC &26DF,Y:STA &70 \subtract power of 10
  LDA &71:INY:SBC &26DF,Y:STA &71
  BCC &2217 \number's gone < 0
  STA &71:INX:DEY:JMP &2200
  17:DEY:LDA &70:ADC &26DF,Y:STA &70 \make no +ve again
  TXA:ORA #ASC"0":JSR &2237 \print digit
  INY:INY:CPY #8:BCC &21FE \loop till digits checked
  LDA &70:ORA #ASC"0":JSR &2237
  LDA #ASC"0":JMP &2237 \add extra 0 on end of score
  37:CMP #ASC"0":BNE &2240 \check if 0
  LDA #ASC"O":JMP oswrch \if so substitute for O and print
  40:JMP oswrch
\ *** init player ship ***
  43:LDA #0:STA &E10 \player bullet x =0
  LDA #&80:STA &E1A \old screen addr =&80xx
  LDA #76:STA &E00 \player x =76
  LDA #235:STA &E01 \player y =235
  LDA #&07:STA &E04:LDA #&17:STA &E05 \player ship data @&1707
  LDA #&00:STA &82 \point to player ship block
  LDA #&0E:STA &83 \in &82/83
  JMP &181B \and print ship
7A:LDA #0:STA &E10 \set player bullet x =0 (not present)
  LDA #&80:STA &E1A \bullet address &80xx
  LDA #&F3:STA &E14:LDA #&16:STA &E15 \bullet sprite @&16F3
  RTS
\ *** set up mode 2 screen ***
  8F:LDA #&21:STA &80:LDA #&26:STA &81
  JSR &2307 \Mode 2 + off cursor data @&2621
  JSR &2804 \print starry backdrop
  LDA #17:JSR oswrch \COLOUR
  LDA &E02:AND #7:JSR oswrch \ (lives AND 7)
  LDA &E02:CLC:ADC #ASC"0":JSR oswrch \print lives
  LDA #0:JSR &218F
  JSR &1E64 \print hi score
  LDA &248F:BEQ &22C9
  AND #3:CLC:ADC #3:TAX:JMP &1E8A \change colour 2
  C9:LDX #2:JMP &1E8A \colour 2 = black
\ *** delay routine ***
  \ entry: X=arbitrary counter
  \ exit: AXY intact
  CE:PHA:TXA:PHA:TYA:PHA
  D3:LDA #0
  D5:SEC:SBC #1:BNE &22D5:DEX:BNE &22D3
  PLA:TAY:PLA:TAX:PLA:RTS
\ *** calculate bird block ***
  \ entry: A=bird no
  \ exit: &8E/F= &E20 + A*16
  E3:STA &8E:LDA #0:STA &8F
  LDA &8E
  ASLA:ROL &8F:ASLA:ROL &8F
  ASLA:ROL &8F:ASLA:ROL &8F
  STA &8E \*16
  LDA #&20:CLC:ADC &8E:STA &8E
  LDA &8F:ADC #&0E:STA &8F \ + &E20
  RTS
  PAGE &23
  
  \*** print text ***
  \entry: &80/81 point to text terminated by &FF
  \exit A and Y intact
  07:PHA:TYA:PHA:LDY #0
  0C:LDA (&80),Y:CMP #&FF:BNE &2316 \not &FF yet
  PLA:TAY:PLA:RTS
  16:JSR oswrch:INY:JMP &230C \print and jump back into loop
\ *** check if player bullet has hit bird ***
  1D:BRK
  1E:LDA #0:STA &231D
  LDA &E11:STA &70 \get bullet y in &70
  CLC:ADC #8:STA &71 \bulletx+8
  LDA #&20:STA &8E:LDA #&0E:STA &8F \first bird block @&E20
  LDY #2:LDA (&8E),Y \get bird status
  BEQ &2347 \not present
  LDY #0:LDA (&8E),Y:CMP &E10 \get bird x and cf player bullet x
  BCS &2347 \its > than
  JMP &234A
  47:JMP &23EA \next bird
  4A:LDA #10:CLC:ADC (&8E),Y \add 10 to bird x
  CMP &E10:BCS &2357 \its >
  JMP &23EA \next bird
  57:LDY #1:LDA (&8E),Y:CLC:ADC #6 \get bird y + 6
  CMP &E11:BCS &2366 \it's >
  JMP &23EA \next bird
  66:LDA (&8E),Y:CMP &71:BCS &2363 \bird y > bullet y + 6
  LDA &8E:STA &82:LDA &83:STA &83 \bird block -> &82/83
  LDY #0:STA (&8E),Y \signal bird now inactive
  LDY #10:LDA #&80:STA (&8E),Y \new bird address =&80xx
  JSR &181B \erase bird
  JSR &2000 \clear kbd
  LDA #&10:STA &82:LDA #&0E:STA &83 \set ptr to player bullet 
  block
  LDA #&80:STA &E1A \new address =&80xx
  JSR &181B \erase bullet
  LDA &231D:CMP &200D:BEQ &23B6
  LDA &2010:BEQ &23AB
  LDA &200E:CMP &231D:BEQ &23B6
  AB:JSR &1ED8 \eggsplosion
  LDA #1:JSR &281F:JMP &23E2 \add 10 to score
B6:LDA #&8A:STA &70:LDA #&16:STA &71 \'20' sprite @&168A
  LDY #0:LDA (&8E),Y:CLC:ADC #3:STA &72 \birdx + 20
  INY:LDA (&8E),Y:SEC:SBC #6:STA &73 \birdy - 6
  LDA #1:STA &78 \status=1=exploding
  JSR &1D26 \find free space in egg blocks
  LDA #2:JSR &218F \add 20 to score
  JSR &1ED8 \print
  E2:LDA #0:STA &E10 \signal player bullet inactive
  JMP &2424
EA:LDA &8E:CLC:ADC #16:STA &8E \
  LDA &8F:ADC #0:STA &8F \point to next bird block
  INC &213D \increment count
  LDA &231D:CMP #30:BNE &2402 \loop till all birds checked
  RTS 
  02:JMP &2335
05:JSR osrdch \GET
  CMP #27:BEQ &240D \escape pressed
  RTS
  0D:LDA #126:JSR osbyte \clear escape
  JMP &1800 \and start over
24:LDX #&A6:LDY #&26:LDA #7:JMP &1FB0 \killed bird sound @&26A6
\ *** define envelopes ***
  \ (could have been done with less hassle in a Basic loader)
  2D:LDX #&AF:LDY #&26:LDA #8:JSR &1FB0 \env 1
  LDX #&BE:LDY #&26:LDA #8:JSR &1FB0 \env 2
  LDX #&E8:LDY #&26:LDA #8:JSR &1FB0 \env 3
  LDX #&F1:LDY #&27:LDA #8:JMP &1FB0 \env 4
51:LDX #&0D:LDY #&26:LDA #7:JSR &1FB0 \player explodes sound @&260D
  LDX #&D6:LDY #&26:LDA #7:JMP &1FB0 \and &26D6
\ *** check to see if bird has hit player ***
  63:BRK \dead flag
  64:LDY #0:STY &2463
  INY:LDA (&8E),Y \get bird y coord
  BPL &2489 \<128 so is nowhere near player
  CMP #232:BMI &2489 \above player and out of harm's way
  CMP #243:BPL &2489 \below player on screen
  DEY:LDA (&8E),Y \get x coord
  SEC:SBC &E00 \subtract player x coord
  CLC:ADC #10:CMP #17:BCS &2489 \not within 17 pixels of player x
  LDA #1:STA &2463 \within 17 pixels, set dead flag = 1
  89:RTS
8A:EQUW 0 \current score
  8F:BRK \colour cycle
  90:EQUW 0 \hi score
\ *** set keys and draw alternate title screen ***
  \ note this is never used!
  92:LDA #12:LDX #0:LDY #0:JSR osbyte \autorepeat off
  LDA #0:STA &11E3:STA &11E4:STA &11E5
  LDA #&9E:STA &11E0 \INKEY code for Z (-98)
  LDA #&BD:STA &11E1 \INKEY code for X (-67)
  LDA #ASC"?":STA &11E2 \fire key ASCII code
  LDA #&37:STA &80:LDA #&26:STA &81:JSR &2307 \text at &2637
  JSR &2405 \check if escape pressed
  JSR &1803:JMP &24C0 
\ *** zeroise score, define envelopes, init birds ***
  C9:LDY #0
  LDA #&8A:STA &70:LDA #&24:STA &71 \&70/71=&248A
  LDX #6
  D5:LDA #0:STA (&70),Y:INY:DEX:BNE &24D5 \zeroise score + level no
  JSR &242D \define envelopes
  LDA #3:STA &E02 \number of lives=3
  JSR &2520 \initialise birds
  JMP &24FA
EB:JSR &228F \set up mode 2 screen
  JSR &2589 \init egg data blocks
  JSR &2243 \init and print ship
  JSR &25B3 \init bird positions
  JSR &25F9 \print birds
  FA:JSR &2013 \main game routine
  
  \ routines that pull 2 addrs of stack (see &1C4D and &1F58)
  \ will return here where...
PAGE &25
  
  00:DEC &E02 \decrement lives
  BNE &24EB \until all lives lost
  JSR &2000 \clear kbd
  LDA #&2E:STA &80:LDA #&27:STA &81:JSR &2307 \game over message 
  @&272E
  LDA &248B:STA &11E5:LDA &248C:STA &11E6 \copy score
  RTS
20:JSR &228F \set up mode 2
  JSR &25D2 \set all birds present
  JSR &227A \init player bullet data block
  JSR &2589 \init egg data blocks
  JSR &25F9 \print birds
  LDA &248F:BEQ &2546 \don't pause on first level
  AND #1:BNE &2546 \don't pause on odd levels
  LDX #0:JSR &22CE:JSR &22CE:JSR &22CE:JSR &22CE \long pause
  46:JMP &2243 \init player ship
\ *** init a line of birds ***
  \ Entry: &70/71 contains address of bird block, &73=y coord of birds
  49:LDX #6 \set up for 6 birds
  LDA #16:STA &74 \first bird on line at x=16
  4F:LDY #0:LDA &74:STA (&70),Y \store x coord
  INY:LDA &73:STA (&70),Y \store y from &73
  LDY #10:LDA #&80:STA (&70),Y \set old addr to &80xx
  LDA #1:LDY #14:STA (&70),Y \signal bird present
  LDY #4:LDA #&26:STA (&70),Y \set sprite
  INY:LDA #&15:STA (&70),Y \address to &1526 (bird data)
  LDA &70:CLC:ADC #16:STA &70 \point to next
  LDA &71:ADC #0:STA &71 \bird data block
  LDA &74:CLC:ADC #16:STA &74 \next bird 16 pixels to the right
  DEX:BNE &254F \loop until all bird attributes set
  RTS
\ *** reset attributes in egg/explosion block ***
  49:LDA #&00:STA &70:LDA #&10:STA &71 \first egg block @&1000
  LDA #24:STA &72 \there can be up to 24 eggs on screen
  95:LDY #2:LDA #0:STA (&70),Y \signal egg not present
  LDY #10:LDA #&80:STA (&70),Y \set old addr to &80xx
  LDA &70:CLC:ADC #16:STA &70 \point to next
  LDA &71:ADC #0:STA &71 \egg data block
  DEC &72:BNE &2595 \loop until all egg attributes set
  RTS
\ *** init all lines of birds ***
  B3:LDA #&20:STA &70:LDA #&0E:STA &71 \first bird block @&0E20
  LDA #5:STA &72 \5 lines of birds
  LDA #16:STA &73 \y coord of first line is 16
  C3:JSR &2549 \print a line of birds
  LDA &73:CLC:ADC #12:STA &73 \next birds are 12 pixels down
  DEC &72:BNE &25C3 \loop till all lines printed
  RTS
\ *** print birds and signify all present ***
  D2:JSR &25B3 \init birds
  LDA #&20:STA &70:LDA #&0E:STA &71 \first bird block @&0E20
  LDA #30:STA &72
  E1:LDY #2:LDA #1:STA (&70),Y \signal bird present
  LDA &70:CLC:ADC #16:STA &70 \point to next
  LDA &71:ADC #0:STA &71 \bird block
  DEC &72:BNE &25E1 \loop till all birds done
  RTS
F9:LDA #&20:STA &82:LDA #&0E:STA &83 \first bird block @&E20
PAGE &26
  
  01:LDA #30:STA &84 \count 30 birds
  05:LDY #2:LDA (&82),Y:BEQ &260E \bird not present
  JSR &181B \print bird
  0E:LDA &82:CLC:ADC #&10:STA &82
  LDA &83:ADC #0:STA &83 \update pointer to next bird block
  DEC &84:BNE &2605 \loop till all birds printed
  RTS:RTS
\ data for MODE 2 play screen and titles
  21:EQUB 22,2, 31,10,0 \MODE 2:VDU 31,10,0
  EQUS "HI:"
  EQUB 30, 23,0,10,32,0,0,0,0,0,0 \home cursor, cursor off
  EQUB 0,&FF
\ data for alternative title screen, never actually seen!
  37:EQUB 22,7, 10,10,10,130,141
  EQUS STRING$(9," ")+"** SWOOP **"+STRING$(9," ")
  EQUB 10,13,130,141
  EQUS STRING$(9," ")+"** SWOOP **"+STRING$(9," ")
  EQUB 10,10,10,10,13, 134
  EQUS " Z left X right ? fire"
  EQUB 10,10,10,13
  EQUS " Press SPACE to play."
  EQUB &FF
\ sounds data
  A6:EQUW &10,1,6,16 \bird dead
  AF:EQUB 1,1,0,0,0,0,0,0,126,-1,-1,-1,126,100 \ENVELOPE 1
  BE:EQUB 2,1,-1,-1,-1,65,65,70,1,0,0,0,1,1 \ENVELOPE 2
  CD:EQUW &110,-15,7,30 \
  D6:EQUW &111,2,200,30 \player dead
  DF:EQUW 10000,1000,100,10 \another tens table used at &218F
  E8:EQUB 3,1,-15,-15,-15,255,255,255,126,0,0,-126,126,100 \ENV.3
  F7:EQUW &12,3,128,50 \level complete
  PAGE &27
  
  0D:EQUW 1,3,140,2 \egg
  16:EQUW &12,4,175,65 \bird swooping
  1F:EQUB 4,6,-1,-1,-1,80,80,96,126,-2,0,-1,90,40 \ENVELOPE 4
\ GAME OVER message
  2E:EQUB 31,5,14
  EQUS "Game Over"
  EQUB &FF
\hi score names and scores
  \1st 14 bytes is name + CR, last 2 bytes is score
  \(divided by 10 since extra 0 always printed)
  80:EQUS "David Elliot ":EQUB 13:EQUW 578 \hi score of 5780
  90:EQUS STRING$(16,CHR$0)
  A0:EQUS STRING$(16,CHR$0)
  B0:EQUS STRING$(16,CHR$0)
  C0:EQUS STRING$(16,CHR$0)
  D0:EQUS STRING$(16,CHR$0)
PAGE &28
  
  00:EQUB 33 \change this to any number <>33 for the alternate title scr
  01:JMP &280C 
  04:JMP &299A \not used (move backdrop)
  07:JMP &29CA \not used (move stars)
  0A:EQUB 31 \number of stars in backdrop
  0C:LDA #0:STA &11E3:STA &11E4 \set silence flag = FALSE
  LDA #&96:STA &11E0 \INKEY code for Z
  LDA #&BD:STA &11E1 \INKEY code for X
  LDA #&2F:STA &11E2 \ASCII code for ?
  23:JSR &2A73 \go into mode 7
  JSR &2853 \draw mode 7 scr
  29:JSR &1803 \ -> &24C9 -> main game
  JSR &28F1:CMP #5:BEQ &284A \check hi score for place in table 
  33:JSR &2B41 \clear kbd
  LDA #&66:STA &80:LDA #&2B:STA &81
  JSR &2A35 \print 'You are in the top 5'
  JSR &2977 \input player name
  JSR &2A59 \check loc &FF for Escape
  JMP &2823 \until the cows come home
  \not in the top 5
  4A:JSR &2B41 \clear kbd
  JSR &2A49 \get a key
  JMP &2829 \until the cows come home
\ *** draw mode 7 scr ***
  53:LDA #0:STA &70:STA &72 \&70/71=&7C00 and &72/73=&2C00
  LDA #&7C:STA &71:LDA #&2C:STA &73
  LDA #&FF:STA &74:LDA #4:STA &75:LDY #0
  6B:LDA (&72),Y:STA (&70),Y
  INC &70:BNE &2875:INC &71 \scr=scr+1
  75:INC &72:BNE &287B:INC &73 \dat=dat+1
  7B:DEC &74:BNE &286B:DEC &75:BNE &286B \loop till 4 pages done
  \ print hi score table
  83:LDA #0
  85:PHA:JSR &2A9A \print a hi score
  PLA:CLC:ADC #1:CMP #5:BNE &2885 \until all 5 done
  \ check Y/N keypress for sound options 
  LDA &11E4:BEQ &28B1:JMP &28C4 \check sound flag
  99:JSR &2A49 \get keypress
  CMP #ASC"Y":BEQ &28B1:CMP #ASC"y":BEQ &28B1 \Y or 
  y?
  CMP #ASC"N":BEQ &28C4:CMP #ASC"n":BEQ &28C4 \N or 
  n?
  CMP #32:BNE &2899 \spacebar not pressed so loop back to &2899
  B1:LDA #&4A:STA &80:LDA #&2B:STA &81 \YES message at &284A
  JSR &2A33 \print that message
  LDA #0:STA &11E4:JMP &2899 \set sound flag FALSE and jump back
  C4:LDA #&52:STA &80:LDA #&2B:STA &81:JSR &2A33 \NO message 
  at &2852
  LDA #1:STA &11E4:JMP &2899 \set sound flag TRUE and jump back
\ *** clear name in hi score table ***
  \ &8E/F point to data of position in table
  D7:LDA #0:PHA:JSR &2A7E
  LDA #0:LDY #0
  E1:STA (&8E),Y:INY:CPY #16:BNE &28E1
  PLA:CLC:ADC #1:CMP #5:BNE &28D9:RTS
\ *** check score against those in table ***
  F1:LDA #&80:STA &70:LDA #&27:STA &71 \&70/71=&2780
  LDA #0:STA &72:LDY #15:LDA &11E6
02:CMP (&70),Y:BEQ &2918:BCS &2922
  08:LDA &70:CLC:ADC #16:STA &70 \next position
  INC &72:LDA &72:CMP #5:BNE &28FD \loop till score >= hi byte 
  in table
  RTS \or 5th place reached
  18:DEY:LDA &11E5
  CMP (&70),Y:BEQ &2908:BCC &2908 \low byte of score <= lo in table
  22:JSR &2935 \
  LDY #15:LDA &11E6:STA (&70),Y \store hi byte of score
  DEY:LDA &11E5:STA (&70),Y \store lo byte
  LDA #0:RTS
  35:LDA &72:CMP #4:BEQ &2966:STA &73:LDA #4
  3F:PHA:JSR &2A7E
  LDA &8E:STA &8C:LDA &8F:STA &8D \copy from position in &8D/E
  PLA:PHA:SEC:SBC #1:JSR &2A7E \to pos in &8E/F
  LDY #0
  55:LDA (&8E),Y:STA (&8C),Y \move scores down 1 position
  INY:CPY #16:BNE &2955
  PLA:SEC:SBC #1:CMP &72:BNE &293F
  66:LDA &72:JSR &2A7E
  LDY #0:LDA #20
  6F:STA (&8E),Y
  INY:CPY #14:BNE &296F:RTS
\ *** set up buffer for typing name ***
  77:LDA &72:JSR &2A7E
  LDA &8E:STA &78:LDA &8F:STA &79 \buffer pointed to by &78/79
  LDA #13:STA &7A \max chars allowed is 13
  LDA #32:STA &7B \min ascii char allowed is 32
  LDA #127:STA &7C \max ascii char is 127
  LDA #0:LDX #&78:LDY #0 \set up registers
  JSR osword:RTS \call OSWORD 0 to input chars
\ *** print starry backdrop ***
  9A:LDA #&A0:STA &70:LDA #&2B:STA &71 \&70/71=&2BA0
  LDA &280A:STA &72 \number of stars
  LDY #0:LDA (&70),Y:STA &73 \star's address on mode 2
  INY:LDA (&70),Y:STA &74 \screen in &73/74
  INY:LDA (&70),Y:STA &75 \pixel value
  A7:LDY #0:LDA (&73),Y:EOR &75:STA (&73),Y \put star on screen
  INC &70:INC &70:INC &70 \point to next address and value
  DEC &72:BNE &29A7:RTS \loop until all stars done then return
\ *** move starry backdrop ***
  CA:LDA #&A0:STA &70:LDA #&2B:STA &71 \&70/71=&28A0
  LDA &280A:STA &72 \number of stars
  D7:LDY #0:LDA (&70),Y:STA &73: \get
  INY:LDA (&70),Y:STA &74 \star's address
  INY:LDA (&70),Y:STA &75 \pixel value
  LDY #0:LDA (&73),Y:EOR &75:STA (&73),Y \EOR it to screen
  LDA &73:AND #7:CMP #7 \bottom of char row?
  BEQ &2A00 \yes
  INC &73:BCC &2A0D:INC &74 \no, just add 1 to scr addr
  JMP &2A0D \and continue
  
   PAGE &2A
\ *** scroll starry backdrop cont'd ***
  00:LDA &73:CLC:ADC #&79:STA &73
  LDA &74:ADC #2:STA &74 \scr=scr+&279
  0D:LDA &74:CMP #&80 \check hi byte of screen
  BCC &2A17 \less than &8000 so still on screen
  SBC #&4E:STA &74 \wrap round to top of screen
  17:LDY #0:LDA (&73),Y:EOR &75:STA (&73),Y
  LDA &73:STA (&70),Y \put pixel value back in table
  INC &70:INC &70:INC &70 \point to next addr and value
  DEC &72:BNE &29D7:RTS \loop till all stars done and return
\ *** message print ***
  \ Entry: &80/81 point to text terminated by &FF.
  \ Exit: A and Y preserved
  33:PHA:TYA:PHA:LDY #0
  38:LDA (&80),Y:CMP #&FF:BNE &2A42 \not yet &FF
  PLA:TAY:PLA:RTS \restore and return
  42:JSR oswrch:INY:JMP &2A38 \print it and jump back into loop
\ *** get a key, eq of GET in Basic ***
  49:JSR osrdch:CMP #27 \escape?
  BEQ &2A51 \yes, deal with it
  RTS \no, return with value in A
  51:LDA #126:JSR osbyte:JMP &1800 \clear escape and start over
\ *** check location &FF ***
  \ will be -ve if Escape pressed 
  59:LDA &FF:BMI &2A51:RTS \branch to routine which clears escape
\ *** delay routine ***
  \ Entry: X=arbitrary counter
  \ Exit: A X and Y preserved
  5E:PHA:TXA:PHA:TYA:PHA \preserve AXY
  63:LDA #0
  65:SEC:SBC #1:BNE &2A65
  DEX:BNE &2A63
  PLA:TAY:PLA:TAX:PLA:RTS \restore and return
\ *** do MODE 7 ***
  73:LDA #&5A:STA &80:LDA #&2B:STA &81 \&2B5A contains 22,7,
  JMP &2A33 \do MODE 7 via message routine
\ check position in hi score table
  7E:CMP #5:BCC &2A8B \A<5
  \ set pointer to '6th' position
  LDA #&D0:STA &8E:LDA #&27:STA &8F \&27D0 addr of 6th hi 
  name
  RTS
\ *** calculate address of hiscore name ***
  \ Entry: A=rank of hi name required
  8B:ASLA:ASLA:ASLA:ASLA
  ADC #&80:STA &8E:LDA #&27:STA &8F \&2780 + A*16
  RTS
\ *** print a high score ***
  99:BRK \workspace
  9A:STA &2A99 \store rank temporarily
  JSR &2A7E \is it in '6th' place?
  A0:LDA #31:JSR oswrch:LDA #3:JSR oswrch \
  LDA #15:CLC:ADC &2A99:JSR oswrch \VDU 31,3,15+rank
  LDY #0
  B5:LDA (&8E),Y:JSR oswrch \get char from hi name
  CMP #13:BEQ &2AC3 \CR is end of hi name
  INY:CPY #14:BNE &2AB5 \loop till 14 chars of name printed
  C3:LDA #31:JSR oswrch:LDA #18:JSR oswrch \
  LDA &2A99:CLC:ADC #15:JSR oswrch \VDU 31,18,15+rank
  LDY #14:LDA (&8E),Y:STA &70 \put score in &70/71
  INY:LDA (&8E),Y:STA &71
  LDA &70:ORA &71:BEQ &2AEA
  JSR &2AEE 
  EA:LDA &2A99
  RTS
\ *** print 16bit number with leading spaces ***
  \ Entry: &70/71 contain number
  EE:LDY #0
  LDA #1:STA &72 \set leading zero as true initially
  F4:LDA #0
  F6:LDA &70:SEC:SBC &2B5D,Y:STA &70 \subtract power of ten from table
  LDA &71
00:INY:SBC &2B5D,Y:BCC &2B0D
  STA &71:INX:DEY:JMP &2AF6
  0D:DEY:LDA &70:ADC &2B5D,Y:STA &70 \restore to +ve
  JSR &2B28 \print digit
  INY:INY:CPY #8:BCC &2AF4
  LDX &70:JSR &2B28
  LDA #&30:JMP oswrch \add extra 0 after number
28:TXA:CMP #0:BNE &2B36 \is digit 0? 
  LDA &72:BEQ &2B3C \leading space flag=0 if first non0 printed
  LDA #32:JMP oswrch \print leading space
  36:PHA:
  LDA #0:STA &72 \leading space = FALSE now non0 number has been printed
  PLA:ORA #&30:JMP oswrch
\ *** clear keyboard buffer ***
  41:LDA #15:LDX #0:LDY #0:JMP osbyte
  \ YES message (see &28B1)
  4A:EQUB 31,32,22
  EQUS "YES"
  EQUB 30,&FF
\ NO message (see &28C4)
  52:EQUB 31,32,22
  EQUS "NO "
  EQUB &30,&FF
\ VDU 22,7 data (see &2B73)
  EQUB 22,7,&FF
\ powers of tens table
  5D:EQUW 10000,1000,100,10
\ message inviting player to enter name
  66:EQUB 31,0,16
  EQUS "You are in the TOP"
  EQUB 10,10,13
  EQUS "FIVE"
  EQUB 10,10,13
  EQUS "Name?"
  EQUB 8, 23,0,10,103,0,0,0,0,0,0 \backspace + cursor on
  EQUB 0,&FF
\ data for starry backdrop
  \ there are 31 stars, the number held at &280A
  \ each item of data comprises a mode 2 address and a pixel value
  \ see &299A (set up stars) and &29CA (move stars)
A0:EQUW &42A8:EQUB 21
  EQUW &4E53:EQUB 21
  EQUW &3F60:EQUB 21
  EQUW &5712:EQUB 21
  EQUW &4DBC:EQUB 21
  EQUW &4B91:EQUB 21
  EQUW &49C4:EQUB 21
  EQUW &6417:EQUB 21
  EQUW &5A41:EQUB 21
  EQUW &68BC:EQUB 21
  EQUW &52C5:EQUB 21
  EQUW &6FA3:EQUB 21
  EQUW &4D30:EQUB 21
  EQUW &69EC:EQUB 21
  EQUW &7491:EQUB 21
  EQUW &59B6:EQUB 21
  EQUW &6320:EQUB 21
  EQUW &7137:EQUB 21
  EQUW &3A86:EQUB 21
  EQUW &775E:EQUB 21
  EQUW &4D69:EQUB 21
  EQUW &3A2A:EQUB 21
  EQUW &3E34:EQUB 21
  EQUW &6D62:EQUB 21
  EQUW &4F05:EQUB 21
  EQUW &6734:EQUB 21
  EQUW &7345:EQUB 21
  EQUW &6D65:EQUB 21
  EQUW &4098:EQUB 21
  EQUW &3E25:EQUB 21
  EQUW &6693:EQUB 21
00:150,154,
  02:EQUS " "
  28:EQUB 150,154,160,240,240,160,146,224,240,160,
  32:EQUS " "
  34:EQUB 224,240,145,
  37:EQUS " "
  39:EQUB 224,240,176,
  3C:EQUS " "
  3E:EQUB 148,
  3F:EQUS " "
  41:EQUB 240,240,
  43:EQUS " "
  45:EQUB 147,240,240,240,176,
  4A:EQUS " "
  50:EQUB 154,150,254,191,175,253,146,234,255,160,
  5A:EQUS " "
  5C:EQUB 234,255,145,
  5F:EQUS " "
  60:EQUB 248,255,175,255,244,148,
  66:EQUS " "
  67:EQUB 224,254,191,239,253,176,147,255,191,175,239,253,176,
  74:EQUS " "
  78:EQUB 150,154,255,181,
  7C:EQUS " "
  7D:EQUB 162,146,234,255,
  81:EQUS " "
  82:EQUB 224,
  83:EQUS " "
  84:EQUB 234,255,145,232,255,
  89:EQUS " "
  8B:EQUB 162,255,180,148,254,183,
  91:EQUS " "
  92:EQUB 160,235,253,147,255,181,160,
  99:EQUS " "
  9A:EQUB 255,181,
  9C:EQUS " "
  A0:EQUB 150,154,171,255,244,160,146,234,255,232,255,253,234,255,145,234,255,
  B1:EQUS " "
  B4:EQUB 255,181,148,255,181,
  B9:EQUS " "
  BB:EQUB 234,255,147,255,253,252,254,191,161,
  C4:EQUS " "
  C8:EQUB 150,154,
  CA:EQUS " "
  CB:EQUB 162,239,253,146,234,255,255,183,255,255,255,145,234,255,
  D9:EQUS " "
  DC:EQUB 255,181,148,255,181,
  E1:EQUS " "
  E3:EQUB 234,255,147,255,183,163,161,
  EA:EQUS " "
  F0:EQUB 154,150,244,
  F3:EQUS " "
  F4:EQUB 234,255,146,234,255,191,160,170,255,255,145,162,255,244,
  02:EQUS " "
  03:EQUB 248,255,161,148,235,253,176,224,254,183,147,255,181,
  10:EQUS " "
  18:EQUB 150,154,171,255,255,167,146,234,255,161,160,
  23:EQUS " "
  24:EQUB 235,255,145,
  27:EQUS " "
  28:EQUB 162,239,255,191,161,
  2D:EQUS " "
  2E:EQUB 148,160,171,255,255,167,
  34:EQUS " "
  35:EQUB 147,255,181,
  38:EQUS " "
  43:EQUB 160,
  44:EQUS " "
  4D:EQUB 160,
  4E:EQUS " "
  5D:EQUB 160,
  5E:EQUS " "
  68:EQUB 131,
  69:EQUS " Z=left X=right ?=fire P=pause. "
  B8:EQUB 134,
  B9:EQUS " Watch out for the exploding eggs. "
  08:EQUB 132,157,
  0A:EQUS " "
  0B:EQUB 130,135,
  0D:EQUS " ** Top Five ** "
  21:EQUB 131,
  22:EQUS "Written by "
  2D:EQUB 156,
  2E:EQUS " "
  30:EQUB 148,255,130,
  33:EQUS " Name: Score:"
  48:EQUB 132,157,132,157,
  4C:EQUS " "
  55:EQUB 156,
  56:EQUS " "
  58:EQUB 148,255,131,
  5B:EQUS " "
  70:EQUB 132,157,134,
  73:EQUS " David "
  7D:EQUB 156,
  7E:EQUS " "
  80:EQUB 148,255,130,
  83:EQUS " "
  98:EQUB 132,157,134,
  9B:EQUS " Elliot "
  A5:EQUB 156,
  A6:EQUS " "
  A8:EQUB 148,255,130,
  AB:EQUS " "
  C0:EQUB 132,157,131,
  C3:EQUS " "
  CD:EQUB 156,
  CE:EQUS " "
  D0:EQUB 148,255,130,
  D3:EQUS " "
  E8:EQUB 132,157,131,
  EB:EQUS " Elliot "
  F5:EQUB 156,
  F6:EQUS " "
  F8:EQUB 148,255,130,
  FB:EQUS " "
  10:EQUB 132,157,131,
  13:EQUS "Software "
  1D:EQUB 156,
  1E:EQUS " "
  20:EQUB 132,157,130,
  23:EQUS " "
  45:EQUB 156,
  46:EQUS " "
  48:EQUB 131,157,129,
  4B:EQUS " Copyright 1982 Program Power "
  6D:EQUB 156,
  6E:EQUS " "
  70:EQUB 129,157,131,
  73:EQUS "Do you want sound (Y/N)? = "
  95:EQUB 156,
  96:EQUS " "
  98:EQUB 130,157,136,132,
  9C:EQUS " Press SPACE to play. "
  BD:EQUB 156,
  BE:EQUS " "
  D3:EQUB 160,
  D4:EQUS "