Ski

This file is part of and Timex Sinclair Public Domain Library Tape 1007. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

This program implements a simple dodge/catch game where the player moves a marker left and right across the bottom of the screen to intercept falling objects. The player character is displayed as an inverse “Y” character and moves via the Z and C keys, while falling objects (displayed as “**”) descend one row per iteration using the SCROLL command. Collision detection is performed by directly reading display memory: lines 101–102 calculate the display file address via PEEK 16396/16397 and check whether the character at the player’s screen position matches character code 23 (the “**” asterisk). Each successful catch increments a hit counter H, and after 50 scroll cycles the score is printed and the program stops.


Program Analysis

Program Structure

The program is divided into a few logical phases:

  1. Initialisation (lines 1–30): Sets hit counter H=0, player position P=5, and draws a column of block-graphic “wall” characters at column 15 using a short FOR loop.
  2. Main game loop (lines 35–110): Runs for 50 iterations. Each iteration spawns a falling object, scrolls the screen, reads player input, performs collision detection, and briefly flashes the player sprite.
  3. End of game (lines 120–130): Prints the hit counter and stops.
  4. Collision/hit handler (lines 400–450): Prints a “BANG” message, pauses, increments H, and jumps back into the middle of the main loop at line 40.

Display Initialisation

Lines 10–30 draw eight rows of the block graphic (ZX81 character \ :) at TAB column 15, establishing a right-hand boundary marker before the game begins.

Falling Object Logic

At line 40, the new horizontal position of the falling object is computed as A = INT(P + RND*5 - 2), biasing the object toward the player’s current position with a small random offset. Line 41 clamps A to the valid range 0–14 by replacing out-of-range values with a fully random column. The object is printed as ** at row 8, column A.

Scrolling and Player Movement

The SCROLL command at line 50 moves all display content up by one character row, causing the object to descend visually over successive iterations. The player sprite is erased at its previous position (AT 3,P;" ") before scrolling, then redrawn as an inverse %Y at line 105. Movement keys Z (left) and C (right) are read via INKEY$ at lines 70–80 with boundary checks to keep P within 0–14.

Collision Detection via Display File PEEK

This is the most technically notable aspect of the program. Lines 101–102 implement collision detection by inspecting the display file directly:

  • Line 101: P1 = PEEK 16396 + 256 * PEEK 16397 reads the system variable D_FILE (at addresses 16396–16397), which holds the start address of the display file.
  • Line 102: PEEK (P1 + 1 + P + 3*17) reads the character at screen row 3 (the player row), column P. The formula adds 1 (for the newline byte at the start of each row), then 3*17 bytes to skip three complete rows (each row is 17 bytes: 16 character cells plus one newline), plus P for the column offset.
  • If the byte equals 23 (the character code for * on the ZX81), a collision is detected and execution jumps to line 400.

This technique avoids any coordinate-tracking variables for the falling object by reading back what is actually on screen, a common ZX81 optimisation.

Hit Counter and Loop Re-entry

On a successful hit, line 430 increments H and line 450 jumps to line 40 — back into the middle of the FOR I=1 TO 50 loop, bypassing NEXT I. This means the loop counter I is not incremented on a hit, effectively giving the player a “free” iteration. Whether intentional or a minor oversight is unclear.

Variable Summary

VariablePurpose
HHit (catch) counter
PPlayer column position (0–14)
IMain loop counter (1–50)
AFalling object column position
P1Display file base address (from D_FILE)

Bugs and Anomalies

  • The GOTO 40 at line 450 re-enters the FOR loop body without incrementing I, so a hit does not consume a turn — the 50-turn limit is effectively extended by the number of hits.
  • The PAUSE 15 at line 106 and the absence of any delay elsewhere means game speed is tied to the brief flash of the player sprite rather than a consistent frame rate.
  • Lines 460–480 (CLEAR, SAVE, RUN) are unreachable dead code following the STOP at line 130.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10294-10335.

Related Products

Related Articles

Related Content

Image Gallery

Ski

Source Code

   1 LET H=0
   5 LET P=5
  10 FOR I=1 TO 8
  20 PRINT TAB 15;"\ :"
  30 NEXT I
  35 FOR I=1 TO 50
  40 LET A=INT (P+RND*5-2)
  41 IF A<0 OR A>14 THEN LET A=INT (RND*15)
  45 PRINT AT 8,A;"**";AT 8,15;"\ :";AT 3,P;" "
  50 SCROLL 
  70 IF INKEY$="Z" AND P<>0 THEN LET P=P-1
  80 IF INKEY$="C" AND P<>14 THEN LET P=P+1
 101 LET P1=PEEK 16396+256*PEEK 16397
 102 IF PEEK (P1+1+P+3*17)=23 THEN GOTO 400
 105 PRINT AT 3,P;"%Y"
 106 PAUSE 15
 110 NEXT I
 120 PRINT H
 130 STOP 
 400 PRINT AT 2,0;"******BANG******"
 410 PAUSE 50
 430 LET H=H+1
 450 GOTO 40
 460 CLEAR 
 470 SAVE "1031%0"
 480 RUN 

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

People

No people associated with this content.

Scroll to Top