FIRE

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

FIRE is a maze-building survival game where the player navigates a firefighter (“+”) around a grid while fire (“E” characters, displayed in magenta on red) spreads randomly and an oxygen meter counts down. The 21×31 string array `a$` serves as a collision map, tracking which cells are blocked by fire (represented internally as the block graphic “█”). Each move, one of four adjacent cells is randomly selected via a computed GO SUB (lines 190–220) to receive a new fire tile, gradually surrounding the player. The oxygen display uses PAPER and FLASH attributes triggered by the expression `(e<20)` to create a visual warning when oxygen drops below 20 units.


Program Structure

The program is organized into a main game loop with an initialization subroutine and four fire-spreading subroutines:

  1. Lines 5–10: Title REM and global initialization (colors, variables, call to setup at line 1000).
  2. Line 20: Per-level reset — clears the collision array a$, resets position, increments level r, replenishes oxygen e, and places a new target at random coordinates (m, n).
  3. Lines 30–40: Display pass — prints the HUD (score, oxygen, level) and draws the target “E” tile four times for emphasis, then erases the player’s old position.
  4. Lines 50–180: Main game loop — reads input, moves the player, checks win/lose conditions, decrements oxygen, then calls a random fire-spread subroutine before looping back to line 30.
  5. Lines 190–220: Fire-spread subroutines, one per cardinal direction, each marking a cell in a$ and printing a colored block character.
  6. Lines 1000–1060: Setup subroutine that defines the target character b$ as “E”.

Collision Detection via String Array

The 21×31 string array a$(21,31) acts as a 2D collision map. Fire-spread subroutines write the block graphic "█" into the relevant cell, and movement checks (lines 60–90) test adjacent cells in a$ before allowing motion. This avoids any need for SCREEN$ reads and is efficient for a BASIC collision system.

Computed GO SUB

Line 170 picks a random direction index rl from 1 to 4, and line 180 dispatches with GO SUB (rl*10)+180, targeting lines 190, 200, 210, or 220. This is a compact dispatch table idiom that avoids a chain of IF statements.

Key Variables

VariableRole
x, yPlayer row and column
eOxygen level (starts at 50, +25 per level)
rLevel counter
sScore (100 per target found, +1 per move)
m, nColumn and row of the target tile
rlRandom direction index (1–4)
a$21×31 collision map string array
b$Target character (“E”), set in the setup subroutine

HUD and Attribute Tricks

Line 30 uses the Boolean expression (e<20), which evaluates to 1 (true) or 0 (false), directly inside PAPER and FLASH to activate a red flashing oxygen warning without any IF statement. PAPER (e<20)*2 gives PAPER 2 (red) when oxygen is critical, and FLASH (e<20) enables flashing simultaneously.

Fire Spread Subroutines

Lines 190–220 each handle one direction. They write into a$, emit a short BEEP, and print a block graphic in a different INK color per direction (cyan, green, red, magenta), creating a colorful fire effect. No bounds checking is performed before writing adjacent cells, which can cause an index-out-of-range error if the player is at the edge of the screen (row 0, row 20, column 0, or column 30) when a fire tile is placed adjacent to them.

Trapping Detection

Line 130 checks all four immediate neighbors of the player in a$ for the fire block character. If all four are blocked, the game declares the player trapped and stops. This is a simple but effective dead-end detection that matches the game’s stated lose condition.

Bugs and Anomalies

  • The collision array a$ is declared as DIM a$(21,31) inside line 20, which is inside the main game loop. DIM is legal here and reinitializes the array each level, but it is unusual placement.
  • The fire-spread subroutines (lines 190–220) do not guard against out-of-bounds array indices. If x is 1, accessing a$(x-1,y) (row 0) will cause an error, and similarly for the other boundaries.
  • Line 40 draws the target tile four times with a short delay loop between each draw (FOR a=1 TO 3: NEXT a), but the practical visual effect is negligible at normal Spectrum speeds — it appears to be vestigial animation code.
  • Line 180 uses GO TO 30 immediately after the GO SUB dispatch, so it acts as a fall-through back to the display loop rather than a true subroutine call structure; the RETURN in each fire subroutine correctly returns to line 180, which then immediately jumps to 30.
  • The setup subroutine at line 1000 defines b$="E" but spans from 1000 to 1060 with only a RETURN at 1060, leaving lines 1010–1059 undefined. This is harmless but wastes line-number space.

Image Gallery

Source Code

    5 REM "FIRE"
   10 INK 7: PAPER 0: BORDER 0: CLS : GO SUB 1000: LET e=50: LET r=0: LET s=0
   20 DIM a$(21,31): CLS : LET c=0: LET r=r+1: LET x=10: LET y=15: LET e=e+25: LET m=INT (RND*28)+2: LET n=INT (RND*18)+2
   30 PRINT AT x,y; INK 5;"+";AT 0,0; INK 7;"SCORE="; PAPER (e<20)*2; FLASH (e<20);" OXYGEN=";e; PAPER 0; FLASH 0;" level=";r;" "
   40 FOR b=1 TO 4: LET a$(n,m)=b$: PRINT AT n,m; INK 5; PAPER 1;b$: FOR a=1 TO 3: NEXT a: NEXT b: PRINT AT x,y;" "
   50 LET f$=INKEY$
   60 IF a$(x,y-1)<>"█" AND f$="5" AND y>2 THEN LET y=y-1
   70 IF a$(x,y+1)<>"█" AND f$="8" AND y<39 THEN LET y=y+1
   80 IF a$(x+1,y)<>"█" AND f$="6" AND x<20 THEN LET x=x+1
   90 IF a$(x-1,y)<>"█" AND f$="7" AND x>2 THEN LET x=x-1
  100 IF n=x AND m=y THEN LET s=s+100: PRINT AT 21,0;"WELL DONE !!": FOR m=10 TO 40: BEEP .01,m: NEXT m: GO TO 20
  110 IF e<=0 THEN PRINT AT 21,0;"OUT OF OXYGEN : GAMEOVER": STOP 
  120 LET e=e-1
  130 IF a$(x-1,y)="█" AND a$(x+1,y)="█" AND a$(x,y-1)="█" AND a$(x,y+1)="█" THEN PRINT AT 21,0;"YOU ARE TRAPPED : GAMEOVER": STOP 
  140 IF f$="" THEN GO TO 30
  150 LET s=s+1
  160 LET rl=INT (RND*4)+1
  170 GO SUB (rl*10)+180
  180 GO TO 30
  190 LET a$(x-1,y)="█": BEEP .01,40: PRINT AT x-1,y; INK 6;"█": RETURN 
  200 LET a$(x+1,y)="█": BEEP .01,40: PRINT AT x+1,y; INK 3;"█": RETURN 
  210 LET a$(x,y-1)="█": BEEP .01,42: PRINT AT x,y-1; INK 4;"█": RETURN 
  220 LET a$(x,y+1)="█": BEEP .01,43: PRINT AT x,y+1; INK 5;"█": RETURN 
 1000 LET b$="E"
 1060 RETURN 

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