A program still in the Spectrum’s memory is a fragile possession. Save Night Patrol, then prove that the saved copy can start the whole game again.
Use Finish Night Patrol unchanged. There are no additions, replacements or deletions in this lesson.
Complete finished program
10 GO SUB 7000: GO SUB 5000: GO SUB 7100
100 DIM v$(608): LET phase=0
120 LET x=3: LET y=16: LET gx=7: LET gy=5: LET gd=1
130 LET got=0: LET outcome=0: LET bn=0: LET beat=0: LET steps=0
140 GO SUB 1000: RESTORE 8900: READ gx,gy,gd,bn,n: GO SUB 3000: GO SUB 3300: GO SUB 2500
150 POKE 23560,0: LET tick=PEEK 23672
200 LET k$=INKEY$
210 IF k$="q" OR k$="Q" THEN GO TO 9000
220 IF k$="r" OR k$="R" THEN GO SUB 8100: GO TO 100
230 LET elapsed=PEEK 23672-tick: IF elapsed<0 THEN LET elapsed=elapsed+256
240 IF elapsed<8 THEN GO TO 200
250 LET k$=INKEY$: IF k$="" THEN LET k$=CHR$ (PEEK 23560)
260 POKE 23560,0: LET dx=0: LET dy=0
261 IF k$="q" OR k$="Q" THEN GO TO 9000
262 IF k$="r" OR k$="R" THEN GO SUB 8100: GO TO 100
270 IF k$="i" OR k$="I" THEN LET dy=-1
280 IF k$="k" OR k$="K" THEN LET dy=1
290 IF k$="j" OR k$="J" THEN LET dx=-1
300 IF k$="l" OR k$="L" THEN LET dx=1
310 LET nx=x+dx: LET ny=y+dy
320 IF m$(ny,nx)=CHR$ 145 THEN GO TO 370
330 IF nx=x AND ny=y THEN GO TO 370
340 LET r=y: LET c=x: LET x=nx: LET y=ny: GO SUB 2000
350 LET steps=steps+1: LET r=y: LET c=x: GO SUB 2000
370 IF v$(y*32+x)="!" OR (x=gx AND y=gy) THEN LET outcome=1: GO TO 4000
380 IF x=27 AND y=3 AND got=0 THEN LET got=1: GO SUB 2500
390 IF x=3 AND y=16 AND got=1 THEN LET outcome=2: GO TO 4000
400 LET beat=beat+1: IF beat<2 THEN GO TO 470
410 LET beat=0: LET r=gy: LET c=gx
420 LET phase=phase+1: IF phase=61 THEN LET phase=1
430 RESTORE 8200+10*phase: READ gx,gy,gd,bn,n
440 GO SUB 2000
450 GO SUB 3000
455 GO SUB 3300
460 IF v$(y*32+x)="!" OR (x=gx AND y=gy) THEN LET outcome=1: GO TO 4000
470 LET tick=PEEK 23672: GO TO 200
1000 BORDER 0: PAPER 0: INK 7: BRIGHT 0: CLS
1010 PRINT AT 0,1; INK 5; BRIGHT 1;"NIGHT PATROL";AT 0,20;"THE ARCHIVE"
1020 FOR r=1 TO 18: PRINT AT r+1,1; INK 1; BRIGHT 1;m$(r): NEXT r
1022 LET r=3: LET c=27: GO SUB 2000
1024 LET r=y: LET c=x: GO SUB 2000
1030 PRINT AT 20,1;"I up J left K down L right"
1040 PRINT AT 21,1;"R retry Q quit";
1050 RETURN
2000 LET z$=" ": LET colour=7: LET shade=0
2010 IF m$(r,c)=CHR$ 145 THEN LET z$=CHR$ 145: LET colour=1
2020 IF v$(r*32+c)="!" THEN LET shade=6
2030 IF r=3 AND c=27 AND got=0 THEN LET z$=CHR$ 146: LET colour=5
2040 IF r=16 AND c=3 THEN LET z$=CHR$ 147: LET colour=4
2050 IF r=gy AND c=gx THEN LET z$=g$(gd): LET colour=6
2060 IF r=y AND c=x THEN LET z$=CHR$ 144: LET colour=7
2070 IF v$(r*32+c)="!" AND ((r=y AND c=x) OR (r=3 AND c=27) OR (r=16 AND c=3)) THEN LET shade=2
2080 PRINT AT r+1,c; PAPER shade; INK colour; BRIGHT 1;z$: RETURN
2500 PRINT AT 1,1; INK 5;"TAKE THE FILE. RETURN TO EXIT. "
2510 IF got=1 THEN PRINT AT 1,1; INK 4;"FILE TAKEN. GET BACK TO EXIT. "
2520 RETURN
3000 IF n=0 THEN RETURN
3005 FOR j=1 TO n: READ ad: LET cell=ABS ad
3010 LET v$(cell)=CHR$ (32+(ad>0))
3020 POKE 22560+cell,71-2*(cell=123)-3*(cell=515)+48*(ad>0)
3030 NEXT j: LET r=y: LET c=x: GO SUB 2000: RETURN
3300 LET r=gy: LET c=gx: GO SUB 2000: RETURN
4000 LET r=y: LET c=x: GO SUB 2000
4010 IF outcome=1 THEN PRINT AT 1,1; INK 2; BRIGHT 1;"SPOTTED! Use the hiding places. "
4020 IF outcome=2 THEN PRINT AT 1,1; INK 4; BRIGHT 1;"FILE RECOVERED. CLEAN GETAWAY! "
4030 PRINT AT 20,1;"R tries again. Q quits. "
4040 GO SUB 8000
4050 IF k$="r" OR k$="R" THEN GO SUB 8100: GO TO 100
4060 IF k$="q" OR k$="Q" THEN GO TO 9000
4070 GO TO 4040
5000 BORDER 0: PAPER 0: INK 7: CLS
5010 PRINT AT 2,10; INK 5; BRIGHT 1;"NIGHT PATROL"
5020 PRINT AT 5,2;"Steal the file. Get back out."
5030 PRINT AT 7,2; INK 7;CHR$ 144;" You "; INK 6;"> Guard"
5040 PRINT AT 9,2; INK 5;CHR$ 146;" File "; INK 4;CHR$ 147;" Exit"
5050 PRINT AT 11,2; PAPER 6;" "; PAPER 0; INK 7;" Amber is the guard's sight."
5060 PRINT AT 13,2; INK 7;"Walls stop you and block sight."
5070 PRINT AT 15,2;"He looks back at each corner."
5080 PRINT AT 17,2;"Hold I J K L to move."
5090 PRINT AT 18,2;"R retries. Q quits."
5100 PRINT AT 21,2; INK 5;"S starts.";
5110 GO SUB 8000
5120 IF k$="q" OR k$="Q" THEN GO TO 9000
5130 IF k$<>"s" AND k$<>"S" THEN GO TO 5110
5140 RETURN
7000 RESTORE 7500: FOR j=0 TO 39: READ a: POKE USR "a"+j,a: NEXT j
7010 DIM a(4): DIM b(4): LET a(1)=1: LET b(2)=1: LET a(3)=-1: LET b(4)=-1
7020 LET g$=">v<"+CHR$ 94: RETURN
7100 DIM m$(18,30): RESTORE 7200
7110 FOR r=1 TO 18: READ m$(r): FOR c=1 TO 30
7120 IF m$(r,c)="#" THEN LET m$(r,c)=CHR$ 145
7130 NEXT c: NEXT r: RETURN
7200 DATA "##############################"
7210 DATA "##############################"
7220 DATA "########### ############# ###"
7230 DATA "##### ####### # ###"
7240 DATA "##### ###"
7250 DATA "##### ###### # #####"
7260 DATA "###### ######### ##### ######"
7270 DATA "###### ############ ######"
7280 DATA "###### ############ ######"
7290 DATA "###### ############## ######"
7300 DATA "#### ################ ####"
7310 DATA "#### #### ########## ####"
7320 DATA "##### ####### #####"
7330 DATA "##### #####"
7340 DATA "##### ###### # #####"
7350 DATA "## ######### ############"
7360 DATA "##############################"
7370 DATA "##############################"
7500 DATA 24,24,0,60,90,24,36,66
7510 DATA 255,128,128,255,8,8,8,255
7520 DATA 126,66,90,66,90,66,126,0
7530 DATA 126,66,66,74,66,66,126,0
7540 DATA 0,0,0,24,24,0,0,0
8000 GO SUB 8100
8010 LET k$=INKEY$: IF k$="" THEN GO TO 8010
8020 RETURN
8100 IF INKEY$<>"" THEN GO TO 8100
8110 RETURN
8200 DATA 7,5,1,11,0
8210 DATA 8,5,1,10,5,-168,-137,-201,141,173
8220 DATA 9,5,1,9,5,-169,-138,-202,109,174
8230 DATA 10,5,1,8,3,-170,-139,175
8240 DATA 11,5,1,6,4,-171,-140,-109,176
8250 DATA 12,5,1,5,3,-172,-141,177
8260 DATA 13,5,1,5,2,-173,178
8270 DATA 14,5,1,5,2,-174,179
8280 DATA 15,5,1,5,2,-175,180
8290 DATA 16,5,1,6,3,-176,211,181
8300 DATA 17,5,1,6,2,-177,182
8310 DATA 18,5,1,5,3,-178,-211,183
8320 DATA 19,5,1,8,5,-179,151,152,184,216
8330 DATA 20,5,1,12,6,-180,150,215,153,185,217
8340 DATA 21,5,1,11,3,-181,-150,186
8350 DATA 22,5,1,9,4,-182,-151,-215,187
8360 DATA 23,5,1,6,3,-183,-152,-216
8370 DATA 24,5,1,3,3,-184,-153,-217
8380 DATA 24,5,3,9,12,-185,-186,-187,179,180,149,181,213,150,182,214,183
8390 DATA 24,5,2,5,14,-179,-180,-149,-181,-213,-150,-182,-214,-183,216,248,280,312,344
8400 DATA 24,6,2,5,2,-216,376
8410 DATA 24,7,2,6,3,-248,343,408
8420 DATA 24,8,2,6,2,-280,440
8430 DATA 24,9,2,7,5,-343,-312,472,441,473
8440 DATA 24,10,2,9,4,-344,504,409,505
8450 DATA 24,11,2,7,2,-376,-409
8460 DATA 24,12,2,6,3,-408,-441,503
8470 DATA 24,13,2,4,2,-440,-473
8480 DATA 24,14,2,1,3,-503,-472,-505
8490 DATA 24,14,4,8,9,-504,312,344,376,408,440,377,409,378
8500 DATA 24,14,3,9,17,-312,-344,-376,-408,-440,-377,-409,-378,467,468,437,469,501,438,470,502,471
8510 DATA 23,14,3,7,4,-438,-502,-471,466
8520 DATA 22,14,3,5,4,-437,-501,-470,465
8530 DATA 21,14,3,6,3,-469,464,497
8540 DATA 20,14,3,7,3,-468,463,498
8550 DATA 19,14,3,6,3,-498,-467,462
8560 DATA 18,14,3,5,3,-497,-466,461
8570 DATA 17,14,3,5,2,-465,460
8580 DATA 16,14,3,5,2,-464,459
8590 DATA 15,14,3,6,3,-463,426,458
8600 DATA 14,14,3,8,4,-462,425,457,427
8610 DATA 13,14,3,9,3,-461,424,456
8620 DATA 12,14,3,11,6,-427,-460,423,455,487,488
8630 DATA 11,14,3,13,6,-426,-459,422,454,486,489
8640 DATA 10,14,3,13,6,-425,-489,-458,389,517,518
8650 DATA 9,14,3,10,5,-517,-424,-488,-457,390
8660 DATA 8,14,3,4,6,-389,-390,-518,-423,-487,-456
8670 DATA 7,14,3,1,3,-422,-486,-455
8680 DATA 7,14,1,11,12,-454,456,425,457,489,426,458,490,427,459,428,460
8690 DATA 7,14,4,8,19,-456,-425,-457,-489,-426,-458,-490,-427,-459,-428,-460,357,358,390,295,327,359,391,423
8700 DATA 7,13,4,6,4,-357,-390,-423,263
8710 DATA 7,12,4,5,3,-358,-391,231
8720 DATA 7,11,4,6,3,-359,199,264
8730 DATA 7,10,4,6,2,-327,167
8740 DATA 7,9,4,5,3,-295,-264,135
8750 DATA 7,8,4,5,2,-263,134
8760 DATA 7,7,4,6,3,-231,166,136
8770 DATA 7,6,4,4,2,-166,-199
8780 DATA 7,5,4,1,3,-134,-167,-136
8790 DATA 7,5,2,5,6,-135,199,231,263,295,327
8800 DATA 7,5,1,11,16,-199,-231,-263,-295,-327,168,137,169,201,138,170,202,139,171,140,172
8900 DATA 7,5,1,11,11,168,137,169,201,138,170,202,139,171,140,172
9000 PAPER 0: INK 7: BRIGHT 0: PRINT AT 21,0;"Finished. RUN to try again. ";: STOPSave an entry point
Quit with Q. Enter this direct command without a line number:
SAVE "patrol" LINE 10SAVE writes the BASIC program and its variables. LINE 10 tells a later load where to begin execution. That line installs the graphics and reaches the title before the attempt is initialised, so a fresh machine needs no earlier game session.
On the Spectrum keyboard, S enters SAVE in keyword mode. For LINE, enter extended mode with Caps Shift and Symbol Shift together, then Symbol Shift with 3. Enter the quoted tape name and the number normally.
At the recording prompt, press Enter and wait for 0 OK. In Emu198x, choose Tape → Export Recording… and give the recording a new host filename, such as night-patrol.tap. The saving guide explains the tape deck and platform-specific controls. A save report inside the Spectrum does not itself prove that a host file was kept.
Recover it in a fresh machine
Keep your source listing too, then close the emulator and start a fresh 48K machine. Open the exported file through File → Open Tape Deck…. Enter:
LOAD ""Start Tape → Play and wait for the title. On platforms using the command-line tape option, follow the linked saving guide for opening and playback. The empty name loads the next program on the tape. If your recording contains several saves, make sure you select or play the Night Patrol recording.
Check a complete cycle from the loaded copy: S starts, the guard moves without input, sight captures, R resets, and Q quits. Play a successful retrieval and return as well. The title, symbols and opening view should match the program before saving.
Does this tape resume the attempt you were playing when you saved?
Show the explanation
No. Although SAVE includes variables, the auto-start path resets the attempt. It preserves a reusable program. An emulator snapshot is the separate tool for resuming a particular machine state.
If loading reaches BASIC without the title, inspect whether the save included LINE 10. If the title appears but the map or graphics are wrong, compare the complete listing and DATA. If no program loads, check the exported file, tape position and playback before changing any game code.
Keep the map and sight records together with the program. You now have a game whose behaviour you can explain: the map owns walls, the phase table owns the patrol, the visibility mask owns detection and the drawing routines show their results.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 20.
Run it here
This unit's program, built for you.
- Program
- night-patrol.tap
- Machine
- ZX Spectrum 48K (PAL)