Dam Attack

This file is part of . Download the collection to get this file.
Date: 1984
Type: Program
Platform(s): TS 2068
Tags: Education

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:

  1. Line 40: GO SUB 2200 — initialize variables
  2. Line 90: GO TO 1650 — settings/control screen
  3. Line 100: draw game screen (GO SUB 1340), then enter main game loop
  4. Lines 180–510: outer loops iterate over three rounds (I) of five sum slots (J), driving the core gameplay
  5. Line 2200: variable initialization subroutine
  6. 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-byte LD DE,n / LD HL,0x3D00 / LD BC,0x300 / LDIR / RET sequence
  • Lines 2370–2380: patch the system variable at 23606/23607 to point the character set at the newly copied RAM copy
  • Line 2390: LET f=USR (a-30) executes the machine code
  • Line 2500: RUN restarts the program; because POKE 23609,25 sets 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=-Z toggling between +1 and −1 inside the explosion flash loop (lines 960–1010) with INK (6 AND Z=1)+(2 AND Z=-1) alternates yellow and red ink without an IF statement.
  • The string "\\\\\\\\\" at line 990 is printed with OVER 1 to XOR-erase the scrolling question during the correct-answer animation.
  • ATTR (M,N+LEN M$+2)=54 at line 670 detects 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 than INK/PAPER keywords, so the attribute bytes travel with the text as it moves across the screen.

Potential Anomalies

  • At line 520, STOP is reached after three full rounds of five problems with no incorrect answers — the program ends with a bare STOP rather than a congratulations message.
  • The variable c appearing in DATA statements (e.g., lines 2520–2930) relies on its runtime value being 0; this is technically fragile since c is also used as a loop variable in the poke loop at line 2450, but the final value of the loop leaves c=0 (the last byte read for each character), making the DATA reads functionally correct.
  • Line 2870 contains DATA "x",0,c,32,c,c,c,c,C — the final element is uppercase C, which in Spectrum BASIC is a distinct variable from lowercase c. Unless C has been assigned the value 0, this will produce an incorrect bitmap byte for the “x” glyph. C is used as the speed-increase parameter and is initialized to 0 at line 2210, so in practice it reads as 0 on first run.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

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.

People

No people associated with this content.

Scroll to Top