Bring back the walking patrol and its corner scans. This time the guard carries its view with it, and a stationary turn can expose the player.
Continue from the Mark what can be seen program. Lesson 7 changed no BASIC lines. The additions below install the prepared table alongside the code that reads it.
Replace lines 130, 1010, 3005, 3010, 3020.
Add lines 400–450 in steps of ten, 455, 460, 8200–8800 in steps of ten.
There are no lines to delete. Enter the changed lines below; their numbers replace existing lines or insert new ones.
130 LET got=0: LET outcome=0: LET bn=0: LET beat=0: LET steps=0
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
1010 PRINT AT 0,1; INK 5; BRIGHT 1;"NIGHT PATROL";AT 0,20;"THE ARCHIVE"
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)
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,172Complete program at this stage
10 GO SUB 7000: 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 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$
260 LET dx=0: LET dy=0
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
7000 RESTORE 7500: FOR j=0 TO 31: 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
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. ";: STOPRUN. The heading returns to THE ARCHIVE. Watch the opening step: some lit squares clear, some remain and new ones appear farther ahead. At a corner, the guard must look back before facing the next corridor.
Change the facts, then their appearance
At 3005, READ gets one signed change into ad, and ABS produces its cell index. Line 3010 stores either a space or ! in v$. Sinclair BASIC comparisons yield zero for false and one for true, so 32+(ad>0) is 32 or 33; CHR$ turns those into the two characters.
The next line updates that square’s attribute byte. Attributes hold colour and brightness separately from the character’s dot pattern. Their memory starts at 22528, with 32 entries per screen row. Our map row appears one screen row lower than its number, giving:
22528 + 32*(row+1) + column = 22560 + cell
For cell 169, that is address 22729. POKE changes its colours without printing another character.
Read the colour arithmetic
An attribute combines INK, eight times PAPER, 64 for BRIGHT and 128 for FLASH. We leave FLASH off. Ordinary floor uses bright white ink on black: 64 + 7 = 71. A visible square adds yellow paper, 8 × 6 = 48, making 119.
The expression at 3020 starts with 71, subtracts two at file cell 123 for cyan ink, subtracts three at entrance cell 515 for green ink, and adds 48 for positive changes. Negative changes remove the yellow paper. These fixed cells come from 32*3+27 and 32*16+3.
After updating the mask, the routine redraws the player; line 455 redraws the guard. The player drawing rule can use red paper under a visible symbol. This is why the general attribute update and entity drawing have a deliberate order. Neither POKE nor the drawing colours decide detection: v$ and the coordinates do.
Check danger twice
Trace one update in the listing:
- Read a key, propose a player move and reject walls.
- Check the player’s position against the current mask and guard.
- Pick up the file, or finish a safe return to the entrance.
- When beat reaches two, advance the phase and restore the old guard square.
- Apply the sight changes, draw the guard and check the new danger.
- Reset the wait clock and repeat.
Why not wait until the guard has moved before testing the player's square?
Show the explanation
That would let a player enter a square the guard currently sees and escape detection if the fan moved away in the same update. The first check catches entering danger; the second catches danger arriving.
Try waiting behind the guard near a corner. Its look-back can catch you while its position stays fixed. On another attempt, use a wall-screened recess and watch the patrol pass. Complete the file’s round trip, then retry after both capture and success. The opening view must be clean, with no stray lit squares from the previous attempt.
The game already plays here. The next lesson adds the title and catches short keypresses that fall between the loop’s movement reads.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 11, chapter 16, chapter 24.
Run it here
This unit's program, built for you.
- Program
- night-patrol.tap
- Machine
- ZX Spectrum 48K (PAL)