Star Trek

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 is a space combat strategy game in the style of Star Trek, played on a 10×10 grid. Two parallel arrays, A() and B(), track game state and display state respectively: A() holds logical values (0=empty, 1=alien, 2=player) while B() drives the map rendering with additional codes for misses (3) and kills (4). The player chooses between scanning, moving, and firing each turn, with an energy budget that depletes by 10, 50, or 100 units depending on the action. Sector names are derived by multiplying the player’s grid coordinates and mapping the product to one of ten star names. The program uses FAST/SLOW mode switching around the map redraw routine at line 8000 to speed up screen output.


Program Analysis

Program Structure

The program is organized into a main loop and a set of subroutines identified by line-number ranges:

Line RangePurpose
10–500Main loop: initialisation calls, command menu, dispatch
1000–1700Scanner (close and long-range)
2000–2300Move command
3000–3460Fire command
3800–3890Game-over / energy exhausted
5000–5900Ship collision / stop
6950–6970Clear message area (lines 13+)
7000–7490Status display
7500–7900Random crew-member voice prefix
8000–8490Map redraw
8500–8740Sector name lookup
9000–9900Initialisation (arrays, position, energy, alien name)

Command Dispatch

Line 160 uses the expression GOSUB 1000*D where D is 1, 2, or 3, dispatching to subroutines at lines 1000, 2000, or 3000 respectively. This is a compact computed-GOSUB idiom that avoids an IF/GOTO ladder. Input validation at line 150 ensures D is always in range before the multiplication.

Dual-Array Map Design

Two 10×10 arrays serve distinct roles:

  • A(Q,P) — logical state: 0 = empty, 1 = alien ship, 2 = player ship
  • B(Q,P) — display state: 0 = empty, 2 = player, 3 = missed shot marker, 4 = destroyed alien

The map renderer at line 8000 iterates over B() exclusively, printing inverse-video characters for each cell code. This separation means the game logic can query A() cleanly without display artefacts interfering.

Map Rendering and FAST/SLOW

The subroutine at line 8000 wraps its output between FAST (line 8002) and SLOW (line 8225) to minimise flicker and speed up the 10×10 grid draw. A compass rose (N/+/W·E/S) is printed at a fixed position (lines 8220–8223) using AT coordinates to the right of the grid. Each row also prints a cursor-reset sequence (AT Q,13;"\@@" then AT Q,13;" ") before printing cell contents, likely to handle line-wrap artefacts.

Sector Name Calculation

Line 8520 computes Q=B*C (player row × column) and maps the product to one of ten sector names via a chain of IF comparisons spanning lines 8540–8720. This gives a positionally-derived name that changes as the player moves, though the mapping is not bijective — many coordinate pairs yield the same product and thus the same sector name. Note line 8700 contains a typo: STRIUS instead of SIRIUS.

Random Crew Voice

Subroutine 7500 picks R=INT(RND*5) and prints one of five crew-member prefixes (Spock, Scott, Uhura, Chekov, Sulu) before any message. This is called before nearly every player-facing PRINT to simulate crew reporting, adding narrative flavour without additional logic.

Energy Economy

ActionEnergy Cost
Close scanner (K=1)10
Long-range scanner (K=2)20
Move50
Fire (hit or miss)100
Enemy return fire hit100 × RND (additional)

Starting energy is 1000 + 2000*RND (line 9340), giving a range of 1000–3000. Energy is checked at line 7030; if it drops below 1, execution jumps to the game-over sequence at line 3800.

Initialisation and Variable Reuse

The initialisation subroutine at line 9000 uses the loop variable A for its FOR loop (lines 9060–9140) even though A is also the name of the 2D array A(). In Sinclair BASIC, a simple variable and an array variable share the same name space only if they have the same name but differ in dimension; here the loop variable A and array A() coexist because array access always uses parentheses. However, this is a risky naming choice that could confuse maintenance.

Collision Detection

After a move, line 2260 checks IF A(B,C)=1 (new cell contains an alien) and branches to line 5500, which enters an alternating inverse/normal print loop displaying a collision message — effectively a terminal game-over state that loops indefinitely without a clean exit.

Bugs and Anomalies

  • Line 3400 is referenced by GOTO 3400 at line 3340 but does not exist; the branch falls through to line 3420 which prints the miss message. This is intentional ZX81 behaviour: branching to a non-existent line runs the next available line.
  • Line 1020 is the effective entry point for the scanner subroutine, but the dispatch at line 160 calls GOSUB 1000 — line 1000 does not exist, so execution begins at 1020. Same technique as above.
  • The game-over loop at line 3890 jumps back to 3805 (a SCROLL statement), creating an infinite scroll that cannot be escaped without a manual break.
  • Typo at line 8700: STRIUS should be SIRIUS.
  • The FOR G=1 TO 30: NEXT G loops at lines 3315–3317 and 3330–3335 serve as busy-wait delays with no body, a common ZX81 timing technique.
  • Line 9260 sets E=RND (a value between 0 and 1) solely to drive the alien-name selection at lines 9280–9320 before being overwritten by the actual energy value at line 9340. This is a valid but potentially confusing reuse of the energy variable.

Content

Appears On

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

Related Products

Related Articles

Related Content

Image Gallery

Star Trek

Source Code

  10 FAST 
  20 GOSUB 9000
  25 GOSUB 8000
  30 GOSUB 6950
  40 GOSUB 7000
  50 GOSUB 6950
  80 GOSUB 7500
 100 PRINT "WHAT IS YOUR ORDER,"
 120 PRINT TAB 5;"SIR ?",,TAB 12;"1-SCAN";TAB 12;"2-MOVE";TAB 12;"3-FIRE"
 140 INPUT D
 150 IF D<1 OR D>3 THEN GOTO 140
 155 GOSUB 6950
 160 GOSUB 1000*D
 170 FOR W=1 TO 30
 180 PRINT AT 20,5;"\ :\ :\ :\ :\ :";AT 20,5;"     "
 190 NEXT W
 500 GOTO 30
\n1020 PRINT TAB 4;"% %  SCANNER % % "
\n1030 GOSUB 7500
\n1040 PRINT "CLOSE (1) OR ","LONG-RANGE (2), SIR ?"
\n1060 INPUT K
\n1080 LET E=E-10*K
\n1090 GOSUB 6950
\n1100 IF K=2 THEN GOTO 1500
\n1120 IF A(B+1,C)=1 OR A(B+1,C+1)=1 OR A(B,C+1)=1 OR A(B-1,C)=1 OR A(B-1,C-1)=1 OR A(B,C-1)=1 OR A(B+1,C-1)=1 OR A(B-1,C+1)=1 THEN PRINT Z$;" IN VICINITY,","SIR"
\n1140 RETURN 
\n1500 GOSUB 7500
\n1520 PRINT AT 15,0;"DIRECTION: N-1, S-2, E-3, W-4 ?"
\n1525 PRINT TAB 8;"(ENTER A NUMBER)"
\n1530 INPUT N
\n1540 LET Z=0
\n1560 IF N=1 AND A(B-2,C)=1 THEN LET Z=1
\n1580 IF N=2 AND A(B+2,C)=1 THEN LET Z=1
\n1600 IF N=3 AND A(B,C+2)=1 THEN LET Z=1
\n1620 IF N=4 AND A(B,C-2)=1 THEN LET Z=1
\n1630 GOSUB 7500
\n1640 PRINT "LONG-RANGE SCANNER REPORT IS"
\n1660 IF Z=1 THEN PRINT "POSITIVE"
\n1680 IF Z=0 THEN PRINT "NEGATIVE"
\n1700 RETURN 
\n2020 LET E=E-50
\n2040 LET A(B,C)=0
\n2050 LET B(B,C)=0
\n2060 PRINT "DIRECTION (N/S)?"
\n2080 INPUT A$
\n2100 LET B=B-1
\n2120 IF A$="S" THEN LET B=B+2
\n2130 GOSUB 7500
\n2140 PRINT "NOW AT ";B;",";C
\n2160 PRINT TAB 12;"(E/W)?"
\n2180 INPUT A$
\n2200 LET C=C-1
\n2220 IF A$="E" THEN LET C=C+2
\n2240 PRINT "NOW AT ";B;",";C
\n2260 IF A(B,C)=1 THEN GOTO 5500
\n2270 LET A(B,C)=2
\n2280 LET B(B,C)=2
\n2290 GOSUB 8000
\n2300 RETURN 
\n3000 REM FIRE
\n3010 GOSUB 7500
\n3020 PRINT "DIRECTION OF FIRE (N/S)?"
\n3040 INPUT A$
\n3060 LET G=B-1
\n3080 IF A$="S" THEN LET G=G+2
\n3100 PRINT TAB 12;"(E/W)?"
\n3120 LET F=C-1
\n3140 INPUT A$
\n3160 IF A$="E" THEN LET F=F+2
\n3180 LET E=E-100
\n3190 IF A(G,F)<>1 THEN GOTO 3300
\n3195 GOSUB 7500
\n3200 PRINT "YOU HIT THE ";Z$
\n3220 LET AL=AL+1
\n3260 LET B(G,F)=4
\n3290 RETURN 
\n3300 GOSUB 7500
\n3305 LET B(G,F)=3
\n3310 PRINT "YOU MISSED, SIR"
\n3315 FOR G=1 TO 30
\n3317 NEXT G
\n3320 PRINT "THE ";Z$;" ARE","SHOOTING BACK"
\n3330 FOR G=1 TO 30
\n3335 NEXT G
\n3337 GOSUB 6950
\n3340 IF RND>.6 THEN GOTO 3400
\n3360 PRINT "THEY HIT US, SIR"
\n3370 GOSUB 8000
\n3380 LET E=E-100*RND
\n3390 RETURN 
\n3420 PRINT "THE ";Z$;" MISSED, SIR"
\n3460 RETURN 
\n3800 GOSUB 6950
\n3805 SCROLL 
\n3810 PRINT "ENERGY BANKS EXHAUSTED"
\n3815 SCROLL 
\n3820 PRINT "YOU KILLED ";AL;" ALIEN";
\n3830 IF AL<>1 THEN PRINT "S"
\n3850 SCROLL 
\n3860 PRINT "ON THIS MISSION"
\n3870 SCROLL 
\n3880 PRINT "YOUR COMMANDER RATING IS ";INT (AL/8*100)
\n3890 GOTO 3805
\n5000 REM END
\n5500 GOSUB 6950
\n5520 PRINT AT 15,0;"YOUR SHIP HAS LANDED ON A",Z$;" VESSEL"
\n5540 PRINT AT 15,0;"%Y%O%U%R% %S%H%I%P% %H%A%S% %L%A%N%D%E%D% %O%N% %A"
\n5560 GOTO 5520
\n5900 STOP 
\n6950 PRINT AT 13,0;"                                                                                                                                                                                                                               "
\n6955 PRINT AT 13,0;
\n6970 RETURN 
\n7000 REM STATUS
\n7020 PRINT AT 2,14;"ENERGY BANK: ";INT E;" "
\n7030 IF E<1 THEN GOTO 3800
\n7040 IF AL>0 THEN PRINT AT 3,14;"ALIEN KILL";AT 4,17;"TALLY: ";AL
\n7060 PRINT AT 7,14;"YOU ARE AT ";B;",";C
\n7070 PRINT AT 8,14;"                 " 
\n7075 PRINT AT 8,14;"IN ";
\n7080 GOSUB 8500
\n7100 PRINT " SECTOR"
\n7120 PRINT AT 12,0;
\n7490 RETURN 
\n7500 LET R=INT (RND*5)
\n7520 IF R=0 THEN PRINT "SPOCK: AS YOU HUMANS SAY,"
\n7540 IF R=1 THEN PRINT "SCOTT: ";
\n7560 IF R=2 THEN PRINT "LT. UHURA: ";
\n7580 IF R=3 THEN PRINT "CHEKOV: ";
\n7600 IF R=4 THEN PRINT "SULU: ";
\n7900 RETURN 
\n7999 STOP 
\n8000 REM PRINT OUT
\n8002 FAST 
\n8005 PRINT AT 0,0;
\n8010 PRINT "  1234567890"
\n8020 FOR Q=1 TO 10
\n8025 PRINT AT Q,13;"\@@";AT Q,13;" "
\n8030 IF Q<10 THEN PRINT Q;" ";
\n8035 IF Q=10 THEN PRINT Q;
\n8040 FOR P=1 TO 10
\n8060 IF B(Q,P)=0 THEN PRINT "% ";
\n8080 IF B(Q,P)=2 THEN PRINT "%$";
\n8100 IF B(Q,P)=3 THEN PRINT "%X";
\n8120 IF B(Q,P)=4 THEN PRINT "%*";
\n8160 NEXT P
\n8200 NEXT Q
\n8210 PRINT 
\n8220 PRINT AT 4,15;"N"
\n8221 PRINT AT 5,15;"+"
\n8222 PRINT AT 5,14;"W";AT 5,16;"E"
\n8223 PRINT AT 6,15;"S"
\n8225 SLOW 
\n8490 RETURN 
\n8500 REM SECTOR
\n8520 LET Q=B*C
\n8540 IF Q<10 THEN PRINT "ANTARES";
\n8560 IF Q>9 AND Q<20 THEN PRINT "RIGEL";
\n8580 IF Q>19 AND Q<30 THEN PRINT "PROCYON";
\n8600 IF Q>29 AND Q<40 THEN PRINT "VEGA";
\n8620 IF Q>39 AND Q<50 THEN PRINT "CANOPUS";
\n8640 IF Q>49 AND Q<60 THEN PRINT "ALTAIR";
\n8660 IF Q>59 AND Q<70 THEN PRINT "SAGITTARIUS";
\n8680 IF Q>69 AND Q<80 THEN PRINT "POLLUX";
\n8700 IF Q>79 AND Q<90 THEN PRINT "STRIUS";
\n8720 IF Q>89 THEN PRINT "BETELGEUSE";
\n8740 RETURN 
\n8999 STOP 
\n9000 DIM A(10,10)
\n9020 DIM B(10,10)
\n9060 FOR A=1 TO 20
\n9080 LET X=INT (RND*10+1)
\n9100 LET Y=INT (RND*10+1)
\n9120 LET A(X,Y)=1
\n9140 NEXT A
\n9160 LET B=5
\n9180 LET C=5
\n9200 LET A(B,C)=2
\n9220 LET B(B,C)=2
\n9240 LET AL=0
\n9260 LET E=RND
\n9280 IF E<.33 THEN LET Z$="BRARKONS "
\n9300 IF E>.33 AND E<.66 THEN LET Z$="WRERKTONIONS "
\n9320 IF E>.66 THEN LET Z$="POLLUXIANS "
\n9340 LET E=1000+2000*RND
\n9900 RETURN 
\n9910 CLEAR 
\n9920 SAVE "1031%6"
\n9930 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