BLOKMAN

This file is part of and CATS Library Tape 6. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Arcade, Game

BLOKMAN is a maze-avoidance and bomb-defusal game in which the player navigates a two-character-wide sprite across a grid, using a joystick in the left port, collecting flags, avoiding skulls, and defusing TNT before a shrinking timer bar runs out. The program uses a block of UDG characters (lines 8–13) loaded via POKE into USR addresses at startup, defining the player, enemy, flag, bomb, and explosion sprites as 8×8 bitmaps read from DATA statements that use the literal variable `b` (value 0) and `-4` (252) as shorthand constants within the data. Joystick input is handled through the TS2068 STICK keyword, with keyboard equivalents mapped in the string `b$` at line 50. The timer is visualized as a row of colored block characters printed at row 20, shrinking one character per frame via the loop variable `j`. A two-stage level structure sends the player through five enemy screens before a bonus flag-catching mini-game, then repeats with a narrower timer bar; difficulty at startup is set by adjusting the initial timer width `i` based on a 0–9 player-chosen level.


Program Analysis

Program Structure

The program is organized into clearly separated functional regions, navigated by computed GO TO and GO SUB targets expressed as numeric literals and floating-point shorthand (e.g., GO SUB 8e3, GO TO 5e3, GO TO 6e3, GO TO 7e3). The major regions are:

  1. Lines 2–7: Initialization — UDG setup, variable reset, screen attributes, entry point.
  2. Lines 8–18: UDG loader subroutine — POKEs bitmap data into the UDG area.
  3. Lines 19–30: Grid drawing — draws a repeating diamond/tile pattern across the play field.
  4. Lines 40–300: Main game loop — places enemies and flags, runs the timer bar, handles movement, collision detection, and scoring.
  5. Lines 1000: Wraparound subroutine for player position.
  6. Lines 4000–4120: Stage 2 bonus mini-game — player must press a key when the man is over the flag.
  7. Lines 5000–5020: Time-expired handler (bomb explodes).
  8. Lines 6000–6040: TNT defused handler — awards bonus, advances level, calls stage 2.
  9. Lines 7000–7070: Life-loss handler — death animation, high-score check, restart logic.
  10. Lines 8000–8270: Title screen, instructions, and difficulty/level entry.

UDG Sprite Loading

Lines 8–18 form a subroutine that loads 20 UDG definitions (characters \a through \t, i.e., UDGs A–T) by POKEing 8 bytes each into the range USR "a" to USR "t"+7. The data is read with RESTORE 9 to reset the DATA pointer, then a single FOR/READ/POKE/NEXT loop fills all 160 bytes. This covers the player (4 UDGs in a 2×2 arrangement), flag, skull/enemy, bomb/TNT, and explosion sprites.

Within the DATA statements, the program exploits the fact that at the time of reading, the variable b holds the value 0 (it was used as a loop counter in line 8 and has just finished at 0 from the previous run, or is initialized to 0 at line 2). This allows b to serve as a compact zero literal inside DATA lines. Similarly, -4 appears as a shorthand for 252 (i.e., 256-4), which BASIC stores and READs as the negative value but which POKE interprets modulo 256.

Sprite Rendering

All in-game objects use 2×2 character (4-cell) UDG sprites, printed with two consecutive PRINT AT statements: the top row at AT r,s and the bottom row at AT r+1,s. Each sprite occupies UDGs arranged as quadrants: for example the player uses \a\b / \c\d, the enemy uses \e\g / \f\h, the flag uses \m\o / \n\p, and the TNT bomb uses \i\k / \j\l. The explosion sprite uses \q\s / \r\t.

Timer Bar

The countdown timer is rendered as a row of colored block characters (\::, the solid block UDG/graphic) at row 20, printed with INK 3. At line 115, the bar is initialized to width i (set from the difficulty level at line 8260 as 32-2*(VAL a$), ranging from 32 at easy to 14 at hardest). The outer loop at line 117 counts j down from i-1 to 0; at line 135 the leftmost cell is erased by printing a space at position j, giving a smooth left-to-right shrink. When the loop exhausts, control falls to line 165 and then jumps to 5e3 (line 5000), the explosion handler.

Movement and Collision Detection

Player position is stored in x (column, always even) and y (row, always even), reflecting the 2×2 sprite grid. Movement direction d is decoded from the action string b$="ASZXPLaszxpl" at line 50, where indices 1–6 map to shoot/left/right/up/down actions (the program uses 3=left, 4=right, 5=up, 6=down based on the arithmetic at lines 175–185). Joystick directions from STICK (1,1) are translated to the same letter values at lines 140–143.

After movement, the subroutine at line 1000 applies toroidal wraparound: if x reaches -2 it wraps to 30, and if it reaches 32 it wraps to 0; similarly for y between -2 and 20. Collision is detected at line 200 by reading the screen attribute at the new position with ATTR (y,x) and comparing to known attribute values:

ATTR valueMeaningAction
54Wall/obstacle (INK 6, PAPER 6, BRIGHT 1)Movement reversed
42Flag (INK 2, PAPER 5)+140 points, sound effect
>63Skull/enemy (BRIGHT or FLASH set)Life lost (go to 6000)
48TNT/bomb (FLASH 1, INK 4, PAPER 0 → 4+48=52? checked carefully)Defuse sequence (go to 7000)

Note: The ATTR value 48 matches INK 0, PAPER 6 (no BRIGHT/FLASH), which corresponds to the background grid squares — the bomb check at line 230 may actually detect background cells rather than the TNT sprite whose ATTR would be BRIGHT 1 + FLASH 1 + INK 4 + PAPER 0 = 192+128+4 = 324 mod 256. This could be a latent bug in collision detection for the bomb object.

Joystick Support

The STICK (1,1) keyword is used at lines 140–143 to read a joystick port, with bitmask values 4=down, 8=up, 1=right, 2=left mapped to the corresponding keyboard letter variables. Keyboard input is handled by scanning INKEY$ against the string b$ in the loop at lines 150–160.

Stage 2 Bonus Mini-Game

After completing 5 screens (loop at lines 85–6030 with FOR t=1 TO 5), the program calls the subroutine at line 4000. This displays a row of background tiles with a randomly placed flag, then animates the player sprite walking across all grid positions. The player must press any key when the man sprite is over the flag column (x=b). The bonus is 4000-(50*y), rewarding faster reactions (lower y means higher row, reached sooner). Success detection uses the idiom FOR a=n TO 1: IF INKEY$<>"" — since n=0, this loop body executes once per iteration and exits via GO TO 4100 on a keypress, or falls through the outer x/y loops on no input.

Sound Effects

Movement sounds at line 250 use a compact single BEEP expression: BEEP .01,(12 AND d=6)+(d<>5)+(5 AND d=3)+(17 AND d=4), exploiting the fact that Boolean expressions evaluate to 1 (true) or 0 (false), so each directional condition contributes a different pitch offset. The death sequence (line 7000) uses a flashing INVERSE animation loop before showing an explosion sprite. The level-complete/defuse tune at lines 7015 plays notes encoded in the parallel strings x$ and y$ initialized at line 5.

Notable Techniques

  • b used as a zero literal in DATA statements, saving bytes over writing 0 repeatedly.
  • Floating-point line number targets (1e3, 4e3, 5e3, 6e3, 7e3, 8e3) compress jump targets to fewer characters in the source.
  • Boolean arithmetic for direction-dependent pitch in a single BEEP call.
  • Screen attribute reading via ATTR for collision detection, avoiding a separate sprite-tracking array.
  • Toroidal wraparound encoded as a single-line subroutine at line 1000 using compound Boolean arithmetic.
  • Difficulty level mapped linearly: i=32-2*(VAL a$) gives timer widths 32 (level 0) down to 14 (level 9).
  • PRINT #1; FLASH 1;"Press any key to begin" at line 8200 prints to the lower screen (stream 1 = bottom two lines), keeping the instruction text visible without scrolling.

Content

Appears On

Capital Area Timex Sinclair User Group’s Library Tape.

Related Products

Related Articles

Related Content

Image Gallery

BLOKMAN

Source Code

    2 LET n=0: GO SUB 8
    3 GO SUB 8e3: LET hs=n
    4 LET lv=3: LET l=1: LET sc=n
    5 LET x$="11114331101": LET y$="32132121216"
    6 BORDER 4: INK 1: PAPER 6: BRIGHT n: FLASH n: OVER n: INVERSE n: CLS 
    7 GO TO 19
    8 RESTORE 9: FOR a=USR "a" TO USR "t"+7: READ b: POKE a,b: NEXT a
    9 DATA 15,79,63,9,11,30,60,63,240,242,-4,144,176,120,60,-4,63,63,b,47,6,b,30,62,-4,b,b,244,96,96,120,124
   10 DATA 7,31,b,57,b,63,29,7,103,242,-4,31,7,-1,-4,96,224,248,b,156,b,-4,184,224,230,175,63,248,224,127,63,6
   11 DATA 0,1,3,15,63,119,99,247,244,245,b,117,127,63,15,3,192,128,192,240,-4,238,198,239,47,175,175,174,-1,-4,240,192
   12 DATA n,3,14,62,126,62,14,3,n,b,b,b,b,b,b,b,124,-4,60,-4,60,-4,b,b,124,12,b,b,b,b,b,b
   13 DATA 1,3,15,31,63,b,127,99,109,99,103,107,109,127,b,b,128,192,240,248,-4,-4,-2,70,86,70,94,b,b,-2,b,b
   17 DATA b,b,b,b,b,b,b,b
   18 RETURN 
   19 FOR a=n TO 240 STEP 16: FOR b=173 TO 15 STEP -16: PLOT a,b
   20 DRAW n,-13: DRAW 13,n: DRAW 1,1: DRAW -13,n: DRAW n,13: DRAW 1,1: DRAW 13,n: DRAW n,-13
   30 NEXT b: NEXT a
   40 LET x=16: LET y=10
   50 LET b$="ASZXPLaszxpl"
   60 FOR a=1 TO l*4+5
   65 LET p=2*INT (RND*10): LET r=2*INT (RND*10): LET q=2*INT (RND*15): LET s=2*INT (RND*15)
   67 IF p=r AND q=s THEN GO TO 65
   70 PRINT AT r,s; INK 2; PAPER 5;"\m\o";AT r+1,s;"\n\p"
   75 PRINT AT p,q; INK 0; PAPER 6;"\e\g";AT p+1,q;"\f\h"
   80 NEXT a
   85 FOR t=1 TO 5
   90 LET a=2*INT (RND*10): LET b=2*INT (RND*16)
  100 IF a=y AND b=x THEN GO TO 90
  110 PRINT AT a,b; BRIGHT 1; FLASH 1; INK 4; PAPER n;"\i\k";AT a+1,b;"\j\l"
  115 PRINT AT 20,n; INK 3;"\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::"( TO i)
  116 PAUSE 100
  117 FOR j=i-1 TO n STEP -1
  120 PRINT AT y,x; INK 1; PAPER 6;"\a\b";AT y+1,x;"\c\d"
  130 PRINT AT 21,n;"SCORE=";sc;" ";AT 21,13;"HIGH=";hs;AT 21,25;"LIVES=";lv
  135 PRINT AT 20,j;" "
  140 IF STICK (1,1)=4 THEN LET a$="Z"
  141 IF STICK (1,1)=8 THEN LET a$="X"
  142 IF STICK (1,1)=1 THEN LET a$="P"
  143 IF STICK (1,1)=2 THEN LET a$="L"
  150 FOR c=1 TO 12
  155 IF a$=b$(c) THEN LET d=c-(6 AND c>6): LET a$="k": GO TO 170
  160 NEXT c
  165 NEXT j: GO TO 5e3
  170 IF d>2 THEN PRINT AT y,x; INK 6;"  ";AT y+1,x;"  "
  175 LET x=x+2*(d=4)-2*(d=3): LET y=y+2*(d=6)-2*(d=5)
  185 IF d<=2 THEN GO TO 5e3
  190 GO SUB 1e3
  200 LET a=ATTR (y,x)
  205 IF a=54 THEN LET x=x+2*(d=3)-2*(d=4): LET y=y+2*(d=5)-2*(d=6)
  207 GO SUB 1e3
  210 IF a=42 THEN BEEP .005,30: BEEP .005,25: LET sc=sc+140
  220 IF a>63 THEN GO TO 6e3
  230 IF a=48 THEN GO TO 7e3
  240 LET sc=sc+10
  250 BEEP .01,(12 AND d=6)+(d<>5)+(5 AND d=3)+(17 AND d=4)
  300 NEXT j: GO TO 5e3
 1000 LET x=x+(32 AND x=-2)-(32 AND x=32): LET y=y+(20 AND y=-2)-(20 AND y=20): RETURN 
 4000 CLS : PRINT AT 20,0; INK 0; PAPER 6;"\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\e\g\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h\f\h"
 4005 LET b=2*INT (RND*15): PRINT INK 2; PAPER 5;AT 20,b;"\m\o";AT 21,b;"\n\p"
 4010 PRINT AT 10,1;"Press any key when man appears        `   over the flag"
 4020 FOR a=1 TO 250: NEXT a
 4030 PRINT AT 10,n,,,,
 4040 FOR y=n TO 18 STEP 2: FOR x=n TO 30 STEP 2
 4050 PRINT AT y,x;"\a\b";AT y+1,x;"\c\d"
 4060 FOR a=n TO 1: IF INKEY$<>"" THEN GO TO 4100
 4070 NEXT a
 4080 PRINT AT y,x;"  ";AT y+1,x;"  ": NEXT x: NEXT y
 4083 PRINT AT 10,n; FLASH 1;" FAILED! FAILED! FAILED! FAILED!"
 4085 FOR a=255 TO n STEP -5: BEEP .01,a/10: OUT 254,a: NEXT a
 4087 FOR a=1 TO 50: NEXT a
 4090 RETURN 
 4100 PRINT AT y,x;"  ";AT y+1,x;"  ": FOR a=y+1 TO 20: PRINT AT a,x;"\a\b";AT a+1,x;"\c\d": PRINT AT a-1,x;"  ": BEEP .01,a: NEXT a
 4110 IF x=b THEN LET sc=sc+4e3-(50*y): PRINT AT 10,n; FLASH 1;" BONUS!! BONUS!! BONUS!! BONUS!!": FOR b=1 TO 5: FOR a=30 TO 15 STEP -1: BEEP .005,a: NEXT a: NEXT b: FOR a=1 TO 50: NEXT a: RETURN 
 4120 GO TO 4083
 5000 PRINT AT 20,n;" ": FOR a=n TO 255 STEP 5: BEEP .01,a/10: OUT 254,a: NEXT a
 5020 GO TO 7020
 6000 PRINT INK n;AT y,x;"\e\g";AT y+1,x;"\f\h"
 6005 FOR b=1 TO 5: FOR a=30 TO 15 STEP -1: BEEP .005,a: NEXT a: NEXT b
 6010 LET sc=sc+1e3
 6025 LET x=x+2-(4 AND x=30)
 6027 PAUSE 50
 6030 NEXT t: LET i=i-(i>14): LET l=l+1
 6035 GO SUB 4e3
 6040 GO TO 5
 7000 FOR a=1 TO 50: LET b=(a/2=INT (a/2)): PRINT INVERSE b; OVER 1;AT y,x;"  ";AT y+1,x;"  ": NEXT a
 7010 PRINT AT y,x; INK 7; PAPER 0;"\q\s";AT y+1,x;"\r\t"
 7015 FOR a=1 TO 11: BEEP VAL (y$(a))/4,VAL (x$(a))-1: NEXT a
 7020 LET lv=lv-1: IF lv THEN GO TO 5
 7030 IF sc>hs THEN PRINT AT 21,17;hs;" ": LET hs=sc: PRINT AT 19,n; FLASH 1; INVERSE 1;"          NEW HIGH SCORE!!      "
 7040 PRINT AT 20,n; FLASH 1;"  Press any key to play again   "
 7050 IF INKEY$<>"" THEN GO TO 7050
 7060 IF INKEY$="" THEN GO TO 7060
 7070 GO SUB 8230: GO TO 3
 8000 BORDER n: PAPER n: BRIGHT n: INVERSE n: OVER n: FLASH n: INK 7: CLS 
 8010 PRINT TAB 10; INK 2; PAPER 5; FLASH 1;"\:: \:: \:: \:: \::"
 8020 PRINT TAB 10; INK 2; PAPER 5; FLASH n;"BLOKMAN"; PAPER 5; INK 2; FLASH 1;" "
 8030 PRINT TAB 10; INK 2; PAPER 5; FLASH 1;"\:: \:: \:: \:: \::"
 8040 PRINT " The object of this game is to  defuse the TNT before the linearscale at the bottom indicates   timeup and the bomb explodes. Ifthis happens you will lose one  of your three lives."
 8050 PRINT " After 5 screens of avoiding    skulls,gaining points by landingon flags and defusing bombs,    stage 2 is reached:"
 8060 PRINT " You must press a key when the  man is over the flag for a bonusof up to 4000-the quicker you   are the greater the bonus!"
 8070 PRINT " Stage 1 then begins again but  now with less time!"
 8080 PRINT "Good Luck!!!"
 8200 PRINT #1; FLASH 1;"Press any key to begin"
 8210 IF INKEY$<>"" THEN GO TO 8210
 8220 IF INKEY$="" THEN GO TO 8220
 8230 CLS 
 8240 PRINT AT 5,5; FLASH 1;"ENTER LEVEL (0 TO 9)"'' FLASH N;"    0 = EASY          9=HARD"
 8250 LET a$=INKEY$: IF a$<"0" OR a$>"9" THEN GO TO 8250
 8260 LET i=32-2*(VAL a$)
 8270 RETURN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top