Bomber is a horizontally-scrolling arcade game in which the player pilots an aircraft across a cityscape, dropping bombs onto buildings. The aircraft moves row by row down the screen while the player presses “Z” to release a single bomb per pass; a one-time altitude boost with “K” adds a tactical element. Custom UDGs are defined in the subroutine at line 1500 to render the plane, bomb, explosion, and building-top graphics. Three separate high-score tables are maintained across three difficulty levels, each accepting up to 13 characters of player name via INPUT. The city skyline is procedurally generated using randomized building heights biased by the chosen difficulty offset variable L.
Program Structure
The program is organized into a main loop and several distinct subroutines accessed via GO SUB:
- Lines 5–170: Initialization, title screen, intro music, and the core gameplay loop.
- Lines 1000–1020: City generation subroutine — draws randomized buildings and ground.
- Lines 1100–1189: High-score and controls display screen.
- Lines 1200–1250: Initializes the three-slot high-score name array
Q$and zeroes scores. - Lines 1500–2040: UDG (User Defined Graphic) definition block, loading pixel data for all custom characters.
- Lines 3500–3570: Level selection screen (three difficulty tiers).
- Lines 4010–4499: Crash/death handler — records high scores, offers replay.
- Lines 4500–4560: Mission complete handler — records high scores, offers replay.
Initialization and Variable Layout
Line 11 sets up most game state in a single long LET chain: plane row H, bomb height BH, bomb trigger flag t, bomb column w, score SC, three high-score accumulators SCH1/SCH2/SCH3, level offset L, difficulty value D, lives indicator LI, loop variable j, and level number LE. Line 5 uses POKE 23658,8 to enable CAPS LOCK, ensuring uppercase key reads work reliably without holding CAPS SHIFT.
UDG Definitions (Lines 1500–2040)
Six UDGs are defined by poking pixel data into the UDG area using POKE USR "X"+Z,A loops with inline DATA and RESTORE:
| UDG | Purpose |
|---|---|
A | Building block (solid rectangle) |
B | Airplane body |
C | Airplane nose/tail |
D | Bomb/explosion marker |
e | Left building-top slope |
f | Right building-top slope |
G | Randomized texture block (each row is the same random byte) |
Note that line 1545 uses RESTORE 1550 but is immediately followed by the FOR loop for UDG “e” at line 1550, so the extra RESTORE on line 1545 is redundant. The UDG “G” definition at line 1580 reads a single random value D from a DATA D statement, but since D was computed once before the loop, all eight rows of the UDG receive the same byte — producing a uniform random texture per game session.
Core Gameplay Loop (Lines 110–170)
The main loop iterates column Q from 0 to 31, scrolling the plane across each row. Key mechanics within the loop:
- Plane display: Line 120 prints the plane UDGs (
\b\c) at position(H,Q)with a brief BEEP simulating engine noise. - Bomb drop: Line 140 checks for “Z” keypress; line 141 advances the bomb vertically each column iteration by incrementing
BH. - Bomb hit detection: Line 142 uses
ATTRto check whether the cell below the bomb has attribute value 1 (INK 1, PAPER 0 — building top) or 40 (PAPER 5, INK 0 — building body, since 40 = 5×8+0). A hit triggers a flash explosion animation, resets the bomb state, and awards 5 points. - Bomb ground impact: Line 144 catches the bomb reaching row 20 without hitting a building.
- Collision detection: Line 145 checks
ATTR(H, Q+2)for building attributes ahead of the plane; a collision triggers the scrolling destruction animation and branches to line 4000. - Altitude boost: Line 149 allows a single upward move with “K” when
J=0andH>3, settingJ=1to prevent reuse. - Mission complete: Line 148 checks for the specific coordinate
H=20, Q=15as a win condition, branching to line 4500.
After each full column sweep, line 160 increments H, moving the plane one row lower, and the loop restarts from column 0.
City Generation (Lines 1000–1020)
Buildings are drawn in pairs of columns stepping by 2 from column 2 to 31. Building height is randomized as INT(RND*8+10+L), where L is the difficulty offset (-3 for hard, 2 for medium, 4 for easy), biasing buildings taller at harder difficulties. Each building cell prints UDG \a (solid block) in INK 0 on PAPER 5; the building top row prints UDGs \e\f (slope characters) in INK 1.
Difficulty and High-Score System
Line 3500 presents three difficulty choices. The selected level sets L (city height bias) and LE (level index 1–3). Three independent high scores (SCH1, SCH2, SCH3) and player name slots (Q$(1), Q$(2), Q$(3)) are maintained for each level. At game-over or mission complete, lines 4041–4043 (or 4522–4526) compare the current score against the stored high score for the active level and prompt for a name if a new record is set. The name array is dimensioned at line 1200 with DIM Q$(Z,13) inside a loop, which reinitializes the array each pass — only the final iteration (Z=3) survives, correctly creating a 3×13 string array.
Notable Techniques and Anomalies
- The intro music loop (lines 40–70) uses
RESTORE 60and reads DATA from line 60 twice via nestedNEXT N/NEXT I— note that line 60 is actually aNEXT Istatement, not a DATA line; the DATA is at line 70.RESTORE 60will therefore position the data pointer before line 70’s DATA, which works correctly since RESTORE seeks to the nearest DATA at or after the given line. - The crash animation at line 145 uses
OVER 1withTAB 31inside a nested loop over all rows and all INK colors, producing a full-screen XOR stripe effect. - The high-score display subroutine (lines 1100–1189) uses a character-by-character typing effect: it prints each letter of a string individually with a short BEEP, then re-enters the loop with a new string via
GO TO 1110, exploitingLEN A$checks to sequence through multiple text sections. - Line 142 prints a “blank” at
AT bh-1,wafter the explosion, which may erase part of the plane graphic if the bomb detonates very close to the aircraft row. - The win condition at line 148 (
H=20 AND Q=15) is a fixed coordinate trigger rather than a completion-of-all-buildings check, meaning the game ends at a specific point in the plane’s descent regardless of how many buildings remain. - “COMPLEATED” (line 4510) and “CONTROLES” (line 1175) are spelling errors in the string literals.
Source Code
5 POKE 23658,8
11 LET H=3: LET BH=h: LET t=0: LET w=0: LET sc=0: LET SCH1=0: LET SCH2=0: LET SCH3=0: LET L=0: LET D=INT (RND*8+1): LET LI=3: LET j=0: LET LE=0
12 GO SUB 1200
15 GO SUB 1500: GO SUB 3500: GO SUB 1100
20 BORDER 0: PAPER 0: INK 5: CLS
21 FOR a=0 TO 20: BEEP .005,a: PRINT INK 2;AT a,0;"█";AT a,31;"█": NEXT a: FOR a=31 TO 0 STEP -1: BEEP .005,a: PRINT INK 2;AT 0,a;"█";AT 21,a;"█": NEXT a
30 PRINT AT 10,10;"CITY LANDER"
40 FOR N=1 TO 2: RESTORE 60
50 FOR I=1 TO 8: READ H,J: BEEP H,J
60 NEXT I: NEXT N
70 DATA .1,11,.1,11,.8,16,.05,11,.05,16,.05,11,.05,16,1,20
80 CLS : REM CITY
90 BORDER 0: INK 2: PAPER 0: CLS : GO SUB 1000
100 LET H=2: LET J=0: LET BH=H: LET SC=0: LET T=0: LET W=0
101 PLOT 0,160: DRAW 255,0: PRINT INK 6;AT 0,23;"SCORE ";SC;AT 0,2;"HIGH-SCORE "
102 IF L=-3 THEN PRINT AT 0,15;SCH1
103 IF L=2 THEN PRINT AT 0,15;SCH2
104 IF L=4 THEN PRINT AT 0,15;SCH3
110 FOR q=0 TO 31
120 PRINT INK 6;AT H,q;"\b\c": BEEP .0008,(H+6)*2
140 IF INKEY$="z" OR INKEY$="Z" AND w=0 THEN LET t=1: LET w=q
141 IF t=1 THEN PRINT INK 7;AT bh,w;"\d": BEEP .0008,50: LET BH=bh+1
142 IF ATTR (bh,w)=1 OR ATTR (bh,w)=40 THEN PRINT PAPER 2; INK 6; FLASH 1;AT bh,w-1;"\g\g";AT bh+1,w-1;"\g\g": PRINT INK 0; PAPER 0;AT bh-1,w;" ": FLASH 0: PRINT INK 2;AT 21,w-1;"██": BEEP .01,0: LET bh=h: LET t=0: LET w=0: LET SC=SC+5
143 PRINT INK 6;AT 0,29;SC
144 IF bh>20 THEN PRINT INK 0;AT bh-1,w;"█": BEEP .01,0: LET bh=h: LET t=0: LET w=0
145 IF ATTR (H,Q+2)=40 OR ATTR (h,q+2)=1 THEN FOR i=1 TO 7: INK i: FOR j=0 TO 21: BEEP .01,j: PRINT AT j,0; OVER 1;TAB 31: NEXT j: NEXT i: CLS : GO TO 4000
146 PRINT AT H,Q;" ": PRINT AT BH-1,W;" ": PRINT AT BH,W;" "
147 IF ATTR (bh+2,w)=2 THEN PRINT INK 0;AT bh,w;"█"
148 IF H=20 AND Q=15 THEN GO TO 4500
149 IF INKEY$="K" AND J=0 AND H>3 THEN LET h=h-1: PRINT AT h,q;" ": LET j=j+1
150 NEXT Q
160 LET H=H+1
170 GO TO 110
999 STOP
1000 REM CITY
1010 FOR N=2 TO 31 STEP 2: LET s=INT (RND*8+10+L): FOR Z=20 TO s STEP -1: PRINT INK 0; PAPER 5;AT Z,N;"\a";AT Z,N+1;"\a": PRINT INK 1;AT s-1,n;"\e\f": NEXT Z: NEXT N: FOR z=0 TO 31: PRINT INK 2;AT 21,z;"█": NEXT z
1015 INK 7
1020 RETURN
1100 PAPER 0: INK 4: BORDER 0: CLS : LET D=2: LET AL=6: LET A$="TODAYS GREATESTS"
1110 FOR A=1 TO LEN A$
1120 PRINT AT D,AL+A;A$(A TO A)
1125 BEEP .01,30
1130 NEXT A
1135 IF LEN A$=10 THEN GO TO 1150
1136 IF LEN A$=11 THEN GO TO 1160
1137 IF LEN A$=12 THEN GO TO 1170
1140 LET D=5: LET AL=0: LET A$="LEVEL(1)..": GO TO 1110
1150 LET D=7: LET AL=0: LET A$="LEVEL(2)...": GO TO 1110
1160 LET D=9: LET AL=0: LET A$="LEVEL(3)....": GO TO 1110
1170 PRINT AT 5,11;Q$(1);" ";SCH1
1172 PRINT AT 7,12;Q$(2);" ";SCH2
1173 PRINT AT 9,13;Q$(3);" ";SCH3
1174 PLOT 0,75: DRAW 255,0
1175 LET D=13: LET AL=3: LET A$="CONTROLES:-"
1176 FOR A=1 TO LEN A$
1177 PRINT AT D,AL+A;A$(A TO A)
1178 BEEP .01,30
1179 NEXT A
1180 IF LEN A$=9 THEN GO TO 1183
1181 IF LEN A$=18 THEN GO TO 1188
1182 LET D=15: LET AL=7: LET A$="Z....FIRE": GO TO 1176
1183 LET D=17: LET AL=7: LET A$="K....UP(ONCE ONLY)": GO TO 1176
1188 PRINT FLASH 1; INK 6;AT 20,9;"PRESS ANY KEY"
1189 PAUSE 0: RETURN
1200 FOR Z=1 TO 3: DIM Q$(Z,13): NEXT Z
1210 LET Q$(1)=" ___________"
1220 LET Q$(2)=" ___________"
1230 LET Q$(3)=" ___________"
1240 LET SCH1=0: LET SCH2=0: LET SCH3=0
1250 RETURN
1500 RESTORE 1500: FOR Z=0 TO 7: READ A: POKE USR "A"+Z,A: NEXT Z: DATA 0,126,126,126,126,126,126,0
1510 RESTORE 1510: FOR Z=0 TO 7: READ A: POKE USR "B"+Z,A: NEXT Z: DATA 128+64+32+1+2+4,128+64+7,255,255-128,63,3,3,0
1520 RESTORE 1520: FOR Z=0 TO 7: READ A: POKE USR "C"+Z,A: NEXT Z: DATA 0,128,152,254,255,254,128,0
1530 RESTORE 1530: FOR Z=0 TO 7: READ A: POKE USR "D"+Z,A: NEXT Z: DATA 195,126,126,90,126,126,60,24
1545 RESTORE 1550
1550 FOR z=0 TO 7: READ a: POKE USR "e"+z,a: NEXT z: DATA 1,3,7,15,31,63,127,255
1560 FOR z=0 TO 7: READ a: POKE USR "f"+z,a: NEXT z: DATA 128,192,224,240,248,252,254,255
1570 RESTORE 1580
1580 FOR z=0 TO 7: LET D=INT (RND*255+1): READ a: POKE USR "G"+z,a: NEXT z: DATA D,D,D,D,D,D,D,D
2040 RETURN
3500 PAPER 0: INK 6: BORDER 0: CLS
3510 PRINT FLASH 1;AT 19,10;"LEVEL (1/3)": FLASH 0
3515 INK 2: FOR A=0 TO 31: BEEP .005,a: PRINT AT 0,A;"█";AT 21,A;"█": NEXT A: FOR A=21 TO 1 STEP -1: BEEP .005,a: PRINT AT A,0;"█";AT A,31;"█": NEXT A
3520 INK 6: PRINT AT 4,2;"3......(EASY)";AT 6,2;"2......(QUITE HARD)";AT 8,2;"1......(VARY HARD)"
3525 FOR A=7 TO 12: PRINT PAPER 2; INK 0; PAPER 5;AT A,27;"\a\a": NEXT A: PRINT INK 1;AT 6,27;"\e\f"; INK 0; PAPER 5;AT 12,25;"\a\a";AT 11,25;"\a\a"; PAPER 0; INK 1;AT 10,25;"\e\f"
3530 IF INKEY$>"3" OR INKEY$<"1" THEN GO TO 3530
3540 PAUSE 0: IF INKEY$="1" THEN LET L=-3: LET LE=1
3550 IF INKEY$="2" THEN LET L=2: LET LE=2
3560 IF INKEY$="3" THEN LET L=4: LET LE=3
3570 RETURN
4010 PRINT FLASH 1;AT 10,3;"YOU NUT YOU COST US A PLANE"
4020 FOR Z=0 TO 50: BEEP .01,INT (RND*30)-20: NEXT Z
4041 IF LE=1 AND SC>=SCH1 THEN LET SCH1=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME.MAX 13": INPUT Q$(1)
4042 IF LE=2 AND SC>=SCH2 THEN LET SCH2=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME.MAX 13": INPUT Q$(2)
4043 IF LE=3 AND SC>=SCH3 THEN LET SCH3=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME,MAX 13": INPUT Q$(3)
4045 PRINT FLASH 1;AT 20,8;"ANOTHER GO (Y/N) ?"
4050 PAUSE 0
4060 IF INKEY$="Y" OR INKEY$="y" THEN GO TO 15
4499 STOP
4500 BORDER 0: PAPER 1: INK 7: CLS
4510 PRINT FLASH 1;AT 10,7;"WELL DONE YOU HAVE";AT 11,4;"COMPLEATED YOUR MISSION"
4520 FOR A=0 TO 60: BEEP .01,RND*30: NEXT A
4522 IF LE=1 AND SC>=SCH1 THEN LET SCH1=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME.MAX 13": INPUT Q$(1)
4524 IF LE=2 AND SC>=SCH2 THEN LET SCH2=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME.MAX 13": INPUT Q$(2)
4526 IF LE=3 AND SC>=SCH3 THEN LET SCH3=SC: PRINT AT 15,1;"HIGH SCORE INPUT NAME.MAX 13": INPUT Q$(3)
4530 PRINT PAPER 1; FLASH 1;AT 20,8;"ANOTHER GO (Y/N)"
4540 PAUSE 0
4550 IF INKEY$="Y" OR INKEY$="y" THEN GO TO 15
4560 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

