8-Bit Software

The BBC and Master Computer Public Domain Library

Back to 8BS
Back to Game Disassemblies

Games Disassemblies

Swoop Submitted by Christopher Dewhurst

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

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:


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.)


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

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)

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
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)


00:BRK \player x coordinate
01:BRK \player y coordinate
02:BRK \number of lives

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

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
04:EQUW &1526 \sprite addr
06:EQUW &80xx \old scr addr
08:EQUW &3540 \new scr addr (&3540 for 1st bird)
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
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

\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

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

PAGE &18

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: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
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
C8:LDA &7A:CLC:ADC #&79:STA &7A
LDA &7B:ADC #2:STA &7B \old scr = old scr + &279

\ *** 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


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
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
LDA #&81:LDY #&FF:JSR osbyte

\ *** 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

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


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

\ *** 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
7F:LDA &70:SEC:SBC #1:STA &70
LDA &71:SBC #0:STA &71 \screen=screen - 1
LDA #21:STA &72 \code for black-white
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

\ *** init bird bullet ***
\ entry; &8E/F point to bird block
C5:LDY #2:LDA (&8E),Y:BNE &1BCC \bird active
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


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
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 &8C:ADC #0:STA &8C \point to next block
DEC &8D:BNE &1C59 \loop till all bullets checked
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

\ 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
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
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


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

\ *** 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
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


\ *** fancy colours ***
00:LDA &200F:AND #15:BEQ &1E08 \change colour every 16th count
08:LDA #0:STA &70
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,
CLC:ADC #1:JSR oswrch \(?&200F DIV 16) AND 3 + 1
LDA #0:JSR oswrch:JSR oswrch:JSR oswrch

\ *** 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
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


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

\ *** 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

\ *** 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

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
0D:BRK \no birds killed
0E:BRK \2nd bird no in flight
0F:BRK \delay for star backdrop
10:BRK \ level AND 1

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
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

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

\ *** 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
D3:LDA #0
D5:SEC:SBC #1:BNE &22D5:DEX:BNE &22D3

\ *** calculate bird block ***
\ entry: A=bird no
\ exit: &8E/F= &E20 + A*16
E3:STA &8E:LDA #0:STA &8F
STA &8E \*16
LDA #&20:CLC:ADC &8E:STA &8E
LDA &8F:ADC #&0E:STA &8F \ + &E20

PAGE &23

\*** print text ***
\entry: &80/81 point to text terminated by &FF
\exit A and Y intact
0C:LDA (&80),Y:CMP #&FF:BNE &2316 \not &FF yet
16:JSR oswrch:INY:JMP &230C \print and jump back into loop

\ *** check if player bullet has hit bird ***
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
02:JMP &2335

PAGE &24

02:JMP &2335

05:JSR osrdch \GET
CMP #27:BEQ &240D \escape pressed
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

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

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

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

\ *** 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

\ *** 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

\ *** 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

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

\ data for MODE 2 play screen and titles
21:EQUB 22,2, 31,10,0 \MODE 2:VDU 31,10,0
EQUB 30, 23,0,10,32,0,0,0,0,0,0 \home cursor, cursor off

\ 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."

\ 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"

\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

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
LDA #0:LDY #0
E1:STA (&8E),Y:INY:CPY #16:BNE &28E1

\ *** 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

PAGE &29

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
35:LDA &72:CMP #4:BEQ &2966:STA &73:LDA #4
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

\ *** 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


\ *** 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
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
63:LDA #0
65:SEC:SBC #1:BNE &2A65
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

\ *** calculate address of hiscore name ***
\ Entry: A=rank of hi name required
ADC #&80:STA &8E:LDA #&27:STA &8F \&2780 + A*16

\ *** 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
EA:LDA &2A99

\ *** print 16bit number with leading spaces ***
\ Entry: &70/71 contain number
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
0D:DEY:LDA &70:ADC &2B5D,Y:STA &70 \restore to +ve
JSR &2B28 \print digit
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
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

\ NO message (see &28C4)
52:EQUB 31,32,22
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
EQUB 10,10,13
EQUS "Name?"
EQUB 8, 23,0,10,103,0,0,0,0,0,0 \backspace + cursor on

\ 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 &4B91:EQUB 21
EQUW &49C4:EQUB 21
EQUW &6417:EQUB 21
EQUW &5A41:EQUB 21
EQUW &52C5:EQUB 21
EQUW &4D30: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 &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


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,
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,
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,
C0:EQUB 132,157,131,
C3:EQUS " "
CD:EQUB 156,
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,
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,
D3:EQUB 160,

Back to 8BS
Back to Game Disassemblies