Dam Attack is an educational math game in which the player must correctly answer addition or subtraction problems to prevent a dam from flooding. Math problems scroll across the screen toward a dam graphic, and the player types the answer before the question reaches the wall; a wrong answer or a miss causes the dam to break and water to fill the screen. The game features an extensive setup routine that uses machine code (poked directly into memory via USR) to copy character set data, redefining 43 individual characters plus 20 UDGs to create custom graphical fonts for the title screen and gameplay graphics. Configurable parameters include problem difficulty level, scroll speed, and automatic level/speed progression tied to hit counts, all entered through an interactive settings screen.
Program Analysis
Program Structure
The program is organized into clearly labeled subroutines introduced by REM comments. The main flow is:
- Line
40:GO SUB 2200— initialize variables - Line
90:GO TO 1650— settings/control screen - Line
100: draw game screen (GO SUB 1340), then enter main game loop - Lines
180–510: outer loops iterate over three rounds (I) of five sum slots (J), driving the core gameplay - Line
2200: variable initialization subroutine - Line
2270: graphics setup, including machine code installation and character redefinition
Machine Code Routine (Lines 2290–2390)
The most technically complex section of the program is the graphics initializer at line 2270. It uses CLEAR to move RAMTOP, then pokes a short machine code routine into high memory and calls it via USR. The routine performs a block memory copy (LDIR, opcode ED B0) to relocate the ROM character set into RAM so that individual character bitmaps can be modified. The destination address is computed dynamically using PEEK 23730/23731 (the PROG system variable), and the source and length are encoded into the 12-byte machine code sequence at lines 2350–2360.
- Line
2290:CLEAR VAL "PEEK 23675+256*PEEK 23676"-801— sets RAMTOP just below the current program to create safe scratch space - Lines
2340–2360: builds and pokes a 12-byteLD DE,n / LD HL,0x3D00 / LD BC,0x300 / LDIR / RETsequence - Lines
2370–2380: patch the system variable at23606/23607to point the character set at the newly copied RAM copy - Line
2390:LET f=USR (a-30)executes the machine code - Line
2500:RUNrestarts the program; becausePOKE 23609,25sets the autostart line to 25 (which does not exist), execution falls through to the next valid line — a well-known trick to restart without re-entering the graphics setup
Character Redefinition
Lines 2400–2460 loop 43 times, reading a character token and 8 bytes of bitmap data from DATA statements (lines 2510–2930). Each character’s address in the RAM copy of the font is computed as (CODE a$-32)*8 + base. The variable c is reused as a literal constant value 0 embedded in DATA statements — since c was set to a loop variable earlier, any c appearing in a DATA line is treated as the numeric value of that variable at READ time, which is consistently 0 by the time the graphics DATA is read. Lines 2470–2480 additionally define 20 UDG characters (160 bytes starting at USR "a") for the in-game sprites.
Gameplay Mechanics
Math problems are generated in subroutine 710. For addition, two operands summing to a random value scaled by difficulty level L are chosen; for subtraction, the minuend is always larger than the subtrahend. The problem string is stored in M$ and wrapped in color-control character sequences to form L$, which scrolls across the screen via repeated calls to GO SUB 650.
The shuffle at lines 280–340 randomizes the order of the five sum characters in C$ (the string "#$%&'") using an in-place Fisher-Yates-style pick without replacement, giving each round a different sequence of problem types.
The answer input routine (GO SUB 530) accumulates keystrokes digit by digit into N$, displaying each digit using a custom character from A$, and sets F=1 when VAL M$=VAL N$. The “P” key re-displays the current sum, and CHR$ 7 (EDIT key) returns to the settings screen.
Difficulty Progression
Two independent hit counters, O and K, track how many correct answers have been given. After B hits, the level L increases by A (capped at 30). After D hits, the scroll delay S decreases by C (floored at 1). Both counters reset to their respective trigger values after firing. These parameters are all user-configurable from the settings screen at line 1650.
Settings Screen (Lines 1650–2180)
The settings screen prompts for speed (S, 1–40), level (L, 1–30), operator (O$, “+” or “-“), level-increase amount and interval (A, B), and speed-increase amount and interval (C, D). Each value is validated in a loop that rejects out-of-range entries. The strings F$ and G$ embed FLASH-on and FLASH-off control codes (CHR$ 18+CHR$ 1 and CHR$ 18+CHR$ 0) to highlight the field being edited.
Flood Animation (Lines 1110–1340)
When the dam is breached (flag G=1), subroutine 1110 fills the screen from row 8 downward with alternating PAPER 1 (blue) and PAPER 5 (cyan) strips, simulating rising water. A five-note descending BEEP sequence accompanies the animation. The player is then offered a yes/no prompt to replay (GO TO 110) or quit (STOP).
Notable Techniques and Idioms
LET Z=-Ztoggling between +1 and −1 inside the explosion flash loop (lines960–1010) withINK (6 AND Z=1)+(2 AND Z=-1)alternates yellow and red ink without anIFstatement.- The string
"\\\\\\\\\"at line990is printed withOVER 1to XOR-erase the scrolling question during the correct-answer animation. ATTR (M,N+LEN M$+2)=54at line670detects collision with the dam wall by reading the screen attribute of the cell just ahead of the problem string; attribute 54 corresponds to INK 6, PAPER 6 (the dam’s yellow color).VAL "PEEK 23675+256*PEEK 23676"and similar constructions protect against the interpreter pre-evaluating system variable reads at parse time — a standard Spectrum BASIC technique for dynamic memory queries.- The scrolling problem display uses embedded color-escape strings built with
CHR$concatenation rather thanINK/PAPERkeywords, so the attribute bytes travel with the text as it moves across the screen.
Potential Anomalies
- At line
520,STOPis reached after three full rounds of five problems with no incorrect answers — the program ends with a bareSTOPrather than a congratulations message. - The variable
cappearing in DATA statements (e.g., lines2520–2930) relies on its runtime value being0; this is technically fragile sincecis also used as a loop variable in the poke loop at line2450, but the final value of the loop leavesc=0(the last byte read for each character), making the DATA reads functionally correct. - Line
2870containsDATA "x",0,c,32,c,c,c,c,C— the final element is uppercaseC, which in Spectrum BASIC is a distinct variable from lowercasec. UnlessChas been assigned the value 0, this will produce an incorrect bitmap byte for the “x” glyph.Cis used as the speed-increase parameter and is initialized to 0 at line2210, so in practice it reads as 0 on first run.
Content
Source Code
10 REM DAM ATTACK
30 CLS : INK 0
40 GO SUB 2200
50 PRINT AT 8,11;"DAM ATTACK"
60 PRINT AT 10,9;"N-B-WOOD 1984"
70 BEEP 1,4: BEEP 1,6: BEEP 1,4: BEEP 1,6
80 BORDER 0: CLS
90 GO TO 1650
100 BORDER 1: CLS
110 GO SUB 1340
120 PRINT AT 10,2;I$;"a j l l l"
130 PRINT AT 11,2;I$;"bcdee fgh kdh mn emfcm"
140 PRINT AT 12,2;I$;" i i"
150 IF INKEY$=CHR$ 7 THEN GO TO 1650
160 IF INKEY$="" THEN GO TO 150
170 IF INKEY$=CHR$ 7 THEN GO TO 90
180 FOR I=0 TO 93
190 INK 7: INVERSE 1
200 PLOT I,70
210 DRAW 0,24
220 PLOT 190-I,70
230 DRAW 0,24
240 BEEP 0.01,I/2: NEXT I: INVERSE 0
250 REM MAIN TEXT
260 LET L=R: LET S=T: LET Q=0
270 GO SUB 710
280 FOR I=0 TO 2
290 LET D$=""
300 FOR W=LEN C$ TO 1 STEP -1
310 LET X=INT (RND*W)+1
320 LET D$=D$+C$(X)
330 LET C$=C$(1 TO X-1)+C$(X+1 TO )
340 NEXT W
350 LET C$="#$%&'"
360 FOR J=1 TO 5
370 LET E=0: LET F=E: LET G=E
380 LET H=1
390 LET N=-1
400 LET M=CODE D$(J)-25
410 GO SUB 1600
420 GO SUB 650
430 IF E=1 THEN GO SUB 1060: IF G=1 THEN GO TO 1110
440 IF E=1 THEN GO TO 510
450 FOR Z=0 TO S
460 IF INKEY$="" THEN LET H=0
470 IF INKEY$<>"" AND H=0 THEN GO SUB 530
480 IF F=1 THEN GO SUB 790: GO TO 370
490 NEXT Z
500 GO TO 420
510 NEXT J: NEXT I
520 STOP
530 REM NUMBERS
540 LET W$=INKEY$
550 IF W$="P" OR W$="p" THEN GO SUB 1600: RETURN
560 IF W$=CHR$ 7 THEN GO TO 1650
570 IF W$<"0" OR W$>"9" THEN RETURN
580 IF P=15 THEN RETURN
590 BEEP .0005,50
600 LET N$=N$+W$
610 LET Y=CODE W$-47
620 PRINT AT 20,P; PAPER 7; INK 0;A$(Y)
630 IF VAL M$=VAL N$ THEN LET F=1
640 LET P=P+1: LET H=1: RETURN
650 REM MOVE SUM
660 LET N=N+1
670 IF ATTR (M,N+LEN M$+2)=54 THEN LET E=1
680 BEEP 0.002,N
690 PRINT AT M,N; BRIGHT 0;L$
700 RETURN
710 REM MAKE SUM
720 RANDOMIZE
730 LET Z=INT ((RND*(L*2))+1)+(L*3)
740 IF O$="+" THEN LET W=INT (RND*(Z/2))+INT (Z/3): LET X=Z-W: IF W>(Z/3)*2 THEN GO TO 740
750 IF O$="-" THEN LET W=INT (RND*(Z))+1: LET X=Z+W
760 LET M$=STR$ X+O$+STR$ W
770 LET L$=CHR$ 17+CHR$ 1+CHR$ 16+CHR$ 0+" "+CHR$ 19+CHR$ 1+"["+CHR$ 17+CHR$ 0+CHR$ 16+CHR$ 7+M$+CHR$ 17+CHR$ 1+CHR$ 16+CHR$ 0+"]"
780 RETURN
790 REM SHOOT
800 LET X=(108-(N*8))-((1+LEN M$/2)*8)
810 LET Y=((19-M)*8)
820 INK 7
830 PLOT 108,24
840 DRAW -X,Y
850 BEEP 0.4,50
860 PLOT 108,24
870 DRAW OVER 1;-X,Y
880 IF O=0 THEN GO TO 900
890 LET O=O-1: IF O<1 THEN LET L=L+A: LET O=B: IF L>30 THEN LET L=20
900 IF K=0 THEN GO TO 920
910 LET K=K-1: IF K<1 THEN LET S=S-C: LET K=D: IF S<1 THEN LET S=1
920 LET Q=Q+1
930 LET V=1
940 PRINT AT 21,23; PAPER 7; INK 0;"SCORE:";Q
950 LET Z=1
960 FOR X=0 TO 20
970 LET Z=-Z
980 INK (6 AND Z=1)+(2 AND Z=-1)
990 PRINT AT M,N+1; OVER 1;"\\\\\\\\\"( TO LEN M$+2)
1000 BEEP 0.01,Z
1010 NEXT X
1020 PRINT AT M,N+1; PAPER 1;" "( TO LEN M$+2)
1030 IF V=1 THEN GO SUB 710
1040 FOR X=1 TO 100
1050 NEXT X: RETURN
1060 REM HOLE
1070 LET V=0
1080 GO SUB 950
1090 IF I=2 THEN LET G=1
1100 RETURN
1110 REM FLOOD
1120 LET Z=21
1130 FOR I=8 TO M
1140 LET Z=Z-1
1150 IF I=Z THEN PRINT AT I,0; PAPER 1,,: GO TO 1190
1160 PRINT AT I,28; PAPER 1;" "
1170 PRINT AT Z,0; PAPER 5;TAB 24;" "
1180 NEXT I
1190 RESTORE 1200
1200 DATA .25,-3,.25,-5,.15,-2,.25,-3,.40,-5
1210 FOR I=1 TO 5
1220 READ Z,X
1230 BEEP Z,X
1240 NEXT I: INK 7
1250 PRINT AT 11,0;"o l l x r"
1260 PRINT "pn hnq tufgm mn vyfh fzfsg"
1270 PRINT " i w i # ": PAPER 1
1280 PRINT AT 15,6;" a "
1290 PRINT AT 16,6;" bcdee h nc g "
1300 PRINT AT 17,6;" i "
1310 IF INKEY$="Y" OR INKEY$="y" THEN GO TO 110
1320 IF INKEY$="N" OR INKEY$="n" THEN STOP
1330 GO TO 1310
1340 REM SCREEN
1350 BORDER 0: PAPER 1: INK 6
1360 FOR W=0 TO 21
1370 PRINT AT W,0,,: NEXT W
1380 FOR W=3 TO 26 STEP 7
1390 LET X=INT (RND*3)+1
1400 PRINT AT X,W;I$;"!@$$"
1410 PRINT AT X+1,W;I$;"%&&'"
1420 NEXT W
1430 PRINT AT 5,25;"( )"
1440 FOR W=6 TO 20
1450 PRINT AT W,25; PAPER 6;" "
1460 IF W>7 THEN PRINT AT W,28; PAPER 5;" "
1470 NEXT W
1480 FOR W=4 TO 11
1490 PLOT 0,W
1500 DRAW 255,0: NEXT W
1510 FOR W=0 TO 15
1520 PLOT 199,39
1530 DRAW -W,-32
1540 PLOT 224,39
1550 DRAW W,-32
1560 NEXT W
1570 LET Z=0
1580 PRINT AT 21,23; PAPER 7; INK 0;"SCORE:0"
1590 PRINT AT 19,13;I$;"_"
1600 PRINT AT 20,12; BRIGHT 1; PAPER 7;" "
1610 LET N$=""
1620 LET P=12
1630 LET Z=Z+5
1640 RETURN
1650 REM CONTROL
1660 BEEP 1,0
1670 FOR I=21 TO 0 STEP -1
1680 PRINT AT I,0; PAPER 0,,: NEXT I
1690 PAPER 0: INK 7
1700 PRINT AT 1,13;", l x"
1710 PRINT AT 2,13;".ngmcny"
1720 PRINT AT 5,0; PAPER 1;I$;" SPEED:1(FAST) - 40(SLOW): ";S
1730 PRINT ' PAPER 1;I$;" LEVEL:1(EASY) - 30(HARD): ";L
1740 PRINT ' PAPER 1;I$;" SUMS : + OR - : ";O$
1750 PRINT ' PAPER 2;I$;" LEVEL INCREASE:";A;" EVERY";B;" HITS"
1760 PRINT ' PAPER 2;I$;" SPEED INCREASE:";C;" EVERY ";D;" HITS"
1770 PRINT '''' INK 4;" ENTER EACH VALUE PRESSING ENTER"
1780 PRINT INK 4;"RESPECTIVELY"
1790 PRINT AT 5,28;F$;S
1800 INPUT S
1810 BEEP .05,40
1820 IF S<1 OR S>40 THEN GO TO 1800
1830 PRINT AT 5,28; PAPER 1;I$;S;" "
1840 PRINT AT 7,28;F$;L
1850 INPUT L
1860 BEEP .05,40
1870 IF L<1 OR L>30 THEN GO TO 1850
1880 PRINT AT 7,28; PAPER 1;I$;L;" "
1890 PRINT AT 9,28;F$;O$
1900 INPUT O$
1910 BEEP .05,40
1920 IF O$<>"+" AND O$<>"-" THEN GO TO 1900
1930 PRINT AT 9,28; PAPER 1;I$;O$
1940 PRINT AT 11,0; PAPER 2;I$;"LEVEL INCREASE:";F$;A;G$;" EVERY ";B;" HITS"
1950 INPUT A
1960 BEEP .05,40
1970 IF A<0 THEN GO TO 1950
1980 PRINT AT 11,0; PAPER 2;I$;" LEVEL INCREASE:";A;" EVERY ";F$;B;G$;" HITS"
1990 INPUT B
2000 BEEP .05,40
2010 IF B<0 THEN GO TO 1990
2020 LET O=B
2030 PRINT AT 11,0; PAPER 2;I$;" LEVEL INCREASE:";A;" EVERY ";B;" HITS"
2040 PRINT AT 13,0; PAPER 2;I$;" SPEED INCREASE:";F$;C;G$;" EVERY ";D;" HITS"
2050 INPUT C
2060 BEEP .05,40
2070 IF C<0 THEN GO TO 2050
2080 PRINT AT 13,0; PAPER 2;I$;" SPEED INCREASE:";C;" EVERY ";F$;D;G$;" HITS"
2090 INPUT D
2100 BEEP .05,40
2110 IF D<0 THEN GO TO 2090
2120 LET K=D
2130 PRINT AT 13,0; PAPER 2;I$;" SPEED INCREASE:";C;" EVERY ";D;" HITS"
2140 PRINT AT 18,0;I$;" TO RETURN THIS PAGE PRESS EDIT",,,
2150 FOR Z=1 TO 200: NEXT Z
2160 LET R=L
2170 LET T=S
2180 GO TO 100
2190 STOP
2200 REM VARIABLES
2210 LET A=0: LET B=A: LET C=A: LET D=A: LET L=10: LET S=20
2220 LET A$="0123456789"
2230 LET B$=" "
2240 LET C$="#$%&'"
2250 LET F$=CHR$ 18+CHR$ 1: LET G$=CHR$ 18+CHR$ 0: LET I$=CHR$ 16+CHR$ 7
2260 LET O$="+": RETURN
2270 REM GRAPHICS
2280 REM N-B-WOOD 1984
2290 CLEAR VAL "PEEK 23675+256*PEEK 23676"-801
2300 PRINT '''''''''' FLASH 1;" Developing the Graphics,"," Please Stand by",
2310 PRINT AT 0,0;
2320 LET a=VAL "PEEK 23730+256*PEEK 23731"+31
2330 RESTORE 2360
2340 LET b=a/256
2350 FOR c=a-30 TO a-19: READ d: POKE c,d: NEXT c
2360 DATA 17,(b-INT b)*256,INT b,33,0,61,1,0,3,237,176,201
2370 POKE 23606,(b-INT b)*256
2380 POKE 23607,INT b-1
2390 LET f=USR (a-30)
2400 FOR e=1 TO 43
2410 BEEP .01,e
2420 READ a$
2430 LET d=(CODE a$-32)*8+a
2440 FOR b=0 TO 7
2450 READ c: POKE d+b,c: NEXT b
2460 NEXT e: RESTORE 2940
2470 FOR b=0 TO 159
2480 READ a: POKE USR "a"+b,a: NEXT b
2490 POKE 23609,25
2500 RUN
2510 DATA "!",0,56,126,127,255,255,255,255
2520 DATA "@",0,c,c,48,126,255,c,c
2530 DATA "#",0,c,c,c,120,255,c,c
2540 DATA "$",0,c,c,c,c,56,254,255
2550 DATA "%",255,127,c,63,0,c,c,c
2560 DATA "&",255,c,c,c,0,c,c,c
2570 DATA "'",255,c,254,252,0,c,c,c
2580 DATA "(",1,3,7,15,31,63,127,255
2590 DATA ")",128,192,224,240,248,252,254,255
2600 DATA "_",24,c,c,c,c,60,126,255
2610 DATA "\",2,199,235,122,202,95,255,84
2620 DATA "[",195,227,115,127,c,115,227,195
2630 DATA "]",128,224,248,255,c,248,224,128
2640 DATA "a",0,c,126,65,c,c,c,c
2650 DATA "b",126,64,c,c,c,c,c,c
2660 DATA "c",92,99,64,c,c,c,c,c
2670 DATA "d",62,65,c,126,64,65,c,62
2680 DATA "e",62,65,64,62,1,c,65,62
2690 DATA "f",61,67,65,c,c,c,67,61
2700 DATA "g",94,97,65,c,c,c,c,c
2710 DATA "h",65,c,c,c,c,c,c,63
2720 DATA "i",1,c,c,c,65,62,0,c
2730 DATA "j",0,c,64,c,68,72,c,80
2740 DATA "k",80,96,c,80,c,72,68,66
2750 DATA "l",0,c,32,c,c,c,c,c
2760 DATA "m",124,32,c,c,c,c,34,28
2770 DATA "n",62,65,c,c,c,c,c,62
2780 DATA "o",0,c,60,34,65,c,c,c
2790 DATA "p",65,c,c,c,c,c,34,60
2800 DATA "q",65,c,c,c,c,c,97,94
2810 DATA "r",0,c,c,c,c,16,c,0
2820 DATA "s",16,c,c,c,c,c,c,8
2830 DATA "t",32,c,c,c,c,c,17,14
2840 DATA "u",130,c,c,c,c,c,68,56
2850 DATA "v",126,65,c,c,c,c,c,126
2860 DATA "w",64,c,c,c,c,c,0,c
2870 DATA "x",0,c,32,c,c,c,c,C
2880 DATA "y",32,c,c,c,c,c,34,28
2890 DATA "z",62,65,c,c,c,c,c,63
2900 DATA "#",1,c,c,c,65,62,0,c
2910 DATA ",",0,c,62,65,64,c,c,c
2920 DATA ".",64,c,c,c,c,65,c,62
2930 DATA "0",0,60,66,c,c,c,60,0
2940 DATA 0,4,12,28,60,108,12,a
2950 DATA a,a,a,a,a,63,a,0
2960 DATA a,30,63,99,a,6,a,12
2970 DATA a,24,a,48,a,127,a,0
2980 DATA a,60,126,99,3,a,6,60
2990 DATA a,6,3,a,99,126,60,0
3000 DATA a,6,14,a,30,54,a,102
3010 DATA a,127,a,6,a,a,a,0
3020 DATA a,127,a,96,a,a,124,126
3030 DATA 54,3,a,a,99,126,60,0
3040 DATA a,3,6,12,24,a,48,a
3050 DATA 124,118,99,a,a,54,28,0
3060 DATA a,127,a,3,a,6,a,12
3070 DATA a,24,a,48,a,96,a,0
3080 DATA a,28,62,99,a,a,62,28
3090 DATA 54,99,a,a,a,54,28,0
3100 DATA a,28,62,99,a,a,55,31
3110 DATA 6,a,12,a,24,48,96,0
3120 DATA a,28,54,99,a,a,a,a
3130 DATA a,a,a,a,a,54,28,0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

