--- title: "Stellar Fighter" id: 71642 type: "computer_media" slug: "stellar-fighter" url: "http://localhost/computer_media/stellar-fighter/" markdown_url: "http://localhost/computer_media/stellar-fighter.md" published_at: "2026-09-25T00:40:07+00:00" modified_at: "2026-09-25T00:40:08+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/stellar-fighter.png" excerpt: "Pilot a space fighter through escalating alien waves, managing phasor energy and hull damage while enemy sprite designs evolve as your kill count climbs." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" basic: - name: "User Defined Graphics (UDG)" slug: "user-defined-graphics-udg" taxonomy: "basic" url: "http://localhost/basic/user-defined-graphics-udg/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Stellar%20Fighter%20(198x)(-)(TS2068)(US)(Program).zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/09/stellar-fighter.png" media_type_tags: "Arcade" --- # Stellar Fighter Stellar Fighter is a space combat game in which the player pilots a fighter craft across a cockpit-display screen, maneuvering to intercept and destroy waves of alien ships using phasor fire. The game uses User Defined Graphics (UDGs) to render several distinct alien sprite designs, swapping between them by POKEing bitmap data into UDG memory as the score advances. A machine-code-free but UDG-heavy approach drives the visual variety: five separate enemy sprite sets (each three characters wide) are loaded at runtime via RESTORE/READ/POKE loops into UDGs \\a–\\u. Game mechanics track phasor energy (PHE), hull damage (DAM%), alien craft destroyed (ACD), and docking count, with difficulty scaling upward after each completed wave by reducing the enemy fire-rate thresholds. *** ### Program Structure The program is organized into well-separated functional blocks: 1. **Lines 1–19:** Initialization — intro screen, title music (BEEP sequence via DATA at line 12), lift-off animation, and UDG setup via `GO SUB 8000`. 2. **Lines 20–26:** Cockpit HUD drawing using PLOT/DRAW graphics and PRINT for instrument labels. 3. **Lines 590–655:** Main game loop — enemy movement, player input polling, display of enemy sprite. 4. **Lines 700–840:** Enemy attack resolution, damage accumulation, explosion animation, and end-condition checks. 5. **Lines 6000–6143:** Laser firing routine — draws laser beams with looped PLOT/DRAW, checks hit via `ATTR`, calls explosion subroutine, increments score. 6. **Lines 7000–7045:** Explosion animation subroutine using expanding UDG characters in all eight directions. 7. **Lines 8000–8052:** UDG definition routines — five enemy sprite sets loaded from DATA. 8. **Lines 8500–8650:** Docking sequence — animated docking bar, energy/damage reset after three docks. 9. **Lines 9300–9430:** Player-destroyed sequence with “Heaven” screen, music, and replay prompt. 10. **Lines 9500–9530:** Intro radio-message routine, printed character by character with BEEP. 11. **Lines 9600–9640:** Mission-complete handler — resets stats, increases difficulty, loops to next wave. 12. **Lines 9990–9998:** Abort and SAVE/CLEAR. ### UDG Sprite System Five distinct enemy sprite designs are defined across UDGs `\\a`–`\\u` (characters 144–164). Each design occupies four UDG characters arranged as a 1×3 display string plus a three-character wide “damaged” variant. Loading is done by `FOR F / FOR G / POKE USR CHR$ (144+f)+g, a` loops reading from DATA statements, with `RESTORE` pointing to the correct DATA block before each load. | Subroutine | UDGs used | A$ (normal) | C$ (damaged) | Trigger score | | --- | --- | --- | --- | --- | | 8000 | \\a–\\d (144–147) | `" \\a "` | `"\\b\\c\\d"` | Start | | 8015 | \\f–\\i (149–152) | `" \\f "` | `"\\g\\h\\i"` | SC=RA (random 4–11) | | 8025 | \\k–\\m (153–155) | `" ,J, "` | `"\\k\\l\\m"` | SC=RAN (random 13–25) | | 8035 | \\n–\\q (157–160) | `" \\n "` | `"\\o\\p\\q"` | SC=GOG (random 27–52) | | 8045 | \\r–\\u (161–164) | `" \\r "` | `"\\s\\t\\u"` | Docking | Note that the subroutine at line 8035 has a bug: the inner POKE loop reads `a` without a preceding `READ a` statement, so it will POKE whatever value `a` holds from the last assignment rather than the DATA values. The corresponding DATA at lines 8037–8040 is never consumed by this routine, meaning the fourth enemy sprite set will display incorrectly or be identical to the previous UDG state. A similar bug exists at line 8045: `POKE USR CHR$ (161+f)+g,a` again lacks `READ a`, so DATA lines 8047–8051 are also never read by their intended loop. ### Main Game Loop Logic The main loop runs from approximately line 620 to 1000. Enemy position is stored in `D` (row) and `A` (column). Lines 620–630 apply random drift to both axes. Lines 641–644 read `INKEY$` for the five control keys (5/6/7/8/1) with boundary checks. The counter `C` is incremented each iteration; it is compared to thresholds `FO`, `FOR`, and `FORT` to determine which sprite variant to display and when the enemy fires back. This creates a timed attack cycle without any explicit timing loop.`DA` | Variable | Initial value | Meaning | | --- | --- | --- | | `FO` | 10 | Threshold for damaged sprite display | | `FOR` | 20 | Threshold for second damaged sprite | | `FORT` | 30 | Threshold for enemy fire | | `RF` | 0 | Enemy fire-event counter | | | Random damage per hit (15–44) | | After each completed wave of 43 kills (`SC=43`, line 6136), the thresholds `FO`, `FOR`, `FORT` are each decremented by 5 at line 9605, making enemies attack faster. A floor check at line 9611 prevents them from dropping below 3/2/4 respectively. ### Hit Detection Hit detection uses `ATTR (10,16)` at line 6130 to check whether the screen cell at the center crosshair position has the enemy’s ink color (6 = yellow). This is a compact and idiomatic attribute-based collision method that avoids any coordinate arithmetic. If the attribute matches, the explosion subroutine at line 7000 is called. ### Laser and Explosion Effects The laser is drawn in a loop (lines 6105–6125) that plots two converging lines from the cockpit sides toward the center, then redraws them in INK 0 to erase. The explosion routine at line 7000 prints the UDG `\\e` (char 148) at the hit point and then in expanding rings of eight positions using `AT 10±P, 15±P` patterns, cycling through decreasing INK values for a flash effect. The `COX` counter repeats the flash twice before returning. ### Docking Sequence When the player presses “1”, line 8500 checks the color of the cockpit bay area using `ATTR (20,17)`. If the bay is showing the correct color (5 = cyan), docking proceeds. After four dock events (`DOCK=4`), an animated docking bar crawls across row 10 using a CP pointer incremented with a PAUSE delay. Energy and damage are reset at line 8650 via `GO SUB 8001` then `GO TO 598`. Only three docks are permitted per mission (counter checked at line 8503). ### Notable BASIC Idioms and Techniques - The intro radio message at line 9500 prints each character individually with a BEEP to simulate a teletype/radio effect: `FOR B=1 TO LEN I$: BEEP .05,3: PRINT I$(B);: NEXT B`. - `RESTORE 6` at line 11 re-reads the program’s own DATA from line 12 for the title music — though the DATA is actually at line 12, not line 6. This points to a non-existent line, so RESTORE will find the first DATA statement it can reach, which is line 12. This is intentional and works correctly. - The “Heaven” end screen at line 9412 draws a pixel-art figure using block-graphic escapes (`\\ \\` etc.) combined with OVER 1 printing at line 9412 for overlay effects. - Line 8001 is referenced as a subroutine label via `GO SUB 8001` (lines 8610, 9640) but is not a subroutine — it contains only LET statements and falls through. This functions as an inline reset of `A$` and `C$` to the default enemy type, relying on the calling code to subsequently GO TO an appropriate line rather than RETURN. - The variable name `FOR` (line 591) shadows the BASIC keyword `FOR`. This is valid in Sinclair BASIC since variable names can match keywords when used in an assignment context, but it is unusual and could cause confusion. ### Anomalies and Bugs - Lines 8035 and 8045 are missing `READ a` inside their POKE loops (see UDG section above), leaving those two enemy sprite sets non-functional. - `LET B$` is never defined anywhere in the program, so line 651 (`PRINT AT D,A;B$`) will cause a variable-not-found error if reached. The `FOR` threshold comparison logic at line 649 may prevent this in practice if `C` always exceeds `FOR` before reaching line 651, but the variable is nonetheless undefined. ## Source Code ``` 1 REM FROM LIST LIBRARY TAPE V1.7 5 BORDER 0:PAPER 6:INK 0:CLS :GO SUB 9500:GO TO 7 7 PAPER 7:INK 1:BORDER 1:CLS :PRINT AT 3,8;"STELLAR FIGHTER":PRINT AT 4,8;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''":REM STOP 8 PRINT INK 2; AT 7,8;"COCKPIT CONTROLS"; INK 0; AT 9,11;"5=LEFT"; AT 11,11;"8=RIGHT"; AT 13,11;"6=DIVE"; AT 15,11;"7=CLIMB" 9 PRINT INK 0:PRINT AT 17,11;"1=DOCK":PRINT AT 19,11;"0=FIRE" 11 RESTORE 6:FOR N=1 TO 19:READ C,D:BEEP C,D:NEXT N:PAUSE 500 12 DATA .15,7,.15,7,.15,7,.9,0,.9,7,.15,5,.15,4,.15,2,.9,12,.45,7,.15,5,.15,4,.15,2,.9,12,.45,7,.15,5,.15,4,.15,5,1,2 13 BORDER 0:PAPER 1:INK 7:CLS 14 PRINT AT 5,14;"WE"; AT 7,13;"HAVE"; AT 9,11;"LIFT OFF" 15 FOR G=1 TO 20:FOR F=0 TO 7:BORDER F:BEEP .02,F:NEXT F:NEXT G 18 GO SUB 8000 19 INK 5:PAPER 0:BORDER 0:CLS 20 PLOT 0,40:DRAW 70,0:DRAW 20,-20:DRAW 75,0:DRAW 20,20:DRAW 70,0 21 PLOT 2,38:DRAW 68,0:DRAW 20,-20:DRAW 75,0:DRAW 20,20:DRAW 68,0 22 PLOT 2,38:DRAW 0,-36:DRAW 251,0:DRAW 0,36:PLOT 90,18:DRAW 0,-16:PLOT 165,18:DRAW 0,-16 25 PRINT INK 7:PRINT AT 18,23;"ACD":PRINT AT 20,23;"CI":PRINT AT 18,1;"DAM%" 26 PRINT INK 7:PRINT AT 20,1;"PHE":PRINT AT 20,12;"CODE" 590 LET DOCK=0:LET GOG= INT (RND*26)+27:LET RAN= INT (RND*13)+13:LET RF=0:LET C=0:LET SC=0:LET RA= INT (RND*8)+4:LET ACD=0 591 LET FO=10:LET FOR=20:LET FORT=30 598 LET PH=1000:LET DAM=0 599 PRINT INK 5:PRINT AT 20,17;"\ \ " 600 LET DA= INT (RND*30)+15 610 LET D= INT (RND*14):LET A= INT (RND*27) 620 LET R1= INT (RND+.5):IF R1=0 AND D>4 THEN LET D=D-1:IF R1=1 AND D<17 THEN LET D=D+1 630 LET R2= INT (RND+.5):IF R2=0 AND A>2 THEN LET A=A-1:IF R2=1 AND A<16 THEN LET A=A+1 641 IF INKEY$="8" AND A<17 THEN LET A=A+3 642 IF INKEY$="7" AND D>3 THEN LET D=D-3 643 IF INKEY$="6" AND D<13 THEN LET D=D+3 644 IF INKEY$="5" AND A>2 THEN LET A=A-3 645 IF INKEY$="1" THEN GO TO 8500 647 IF INKEY$=" " THEN GO TO 9995 649 LET C=C+1:IF C>FO THEN GO TO 652:IF C >=FOR THEN GO TO 651 650 PRINT INK 6; AT D,A;A$:GO TO 654 651 PRINT AT D,A;B$:GO TO 655 652 PRINT INK 6; AT D,A;C$ 655 IF INKEY$="0" THEN LET PH=PH-10:PRINT INK 7; AT 20,5;PH:GO TO 6000 700 FOR B=-20 TO -15:BEEP .005,B:NEXT B 800 LET RF=RF+1 801 PRINT INK 6; AT 20,26;C$ 805 PRINT INK 7:PRINT AT 9,16;"!":PRINT AT 11,16;"!":PRINT AT 10,15;"-":PRINT AT 10,17;"-" 810 IF RF60 AND DAM<100 THEN GO TO 9300 830 IF DAM >=99 THEN GO TO 9400 840 PRINT AT D,A;" ":GO TO 600 900 PRINT AT D,A;" " 1000 GO TO 620 5000 REM FIRING LASER 6000 REM SHOOT 6001 IF PH<100 AND PH>0 THEN PRINT AT 20,7;" " 6010 IF PH <=-100 THEN GO TO 9300 6105 FOR N=3 TO 0 STEP -3 6110 PLOT INK 0;7,48:DRAW INK N;119,41 6120 PLOT INK 0;248,48:DRAW INK N;-110,40 6125 NEXT N 6127 FOR Q=1 TO 10:BEEP .01,1+F:BEEP .01,10:NEXT Q 6130 IF ATTR (10,16)=6 THEN GO TO 6134 6133 GO TO 656 6134 GO SUB 7000 6135 LET ACD=ACD+1:LET SC=SC+1:LET RF=0:PRINT INK 7:PRINT AT 18,27;ACD 6136 IF SC=43 THEN GO TO 9600 6139 LET C=0:IF SC=RA THEN GO SUB 8015 6140 IF SC=RAN THEN GO SUB 8025 6141 IF SC=GOG THEN GO SUB 8035 6143 GO TO 600 7000 LET Z$="\e" 7010 FOR N=6 TO 0 STEP -6 7011 LET COX=0 7015 PRINT INK N; BRIGHT 1; AT 10,15;Z$ 7020 FOR P=1 TO 4 7030 PRINT INK N; AT 10+P,15+P;Z$; AT 10-P,15-P;Z$; AT 10+P,15-P;Z$; AT 10-P,15+P;Z$; AT 10,15+P;Z$; AT 10,15-P;Z$; AT 10+P,15;Z$; AT 10-P,15;Z$ 7035 BEEP .0025, INT (RND*20) 7040 NEXT P:NEXT N 7041 LET COX=COX+1 7042 IF COX=2 THEN GO TO 7045 7043 FOR N=3 TO 0 STEP -3 7044 GO TO 7015 7045 BRIGHT 0:RETURN 8000 FOR F=0 TO 4:FOR G=0 TO 7:READ A:POKE USR CHR$ (144+f)+g,a:NEXT G:NEXT F 8001 LET A$= " \a ":LET C$="\b\c\d" 8005 DATA 0,0,36,195,255,219,0,0 8006 DATA 96,241,250,252,255,255,241,96 8007 DATA 129,24,60,126,255,255,255,90 8008 DATA 6,143,95,63,255,255,143,6 8009 DATA BIN 01000000,0, BIN 01100010, BIN 00100001,0, BIN 00011000,1, BIN 10000101 8010 RETURN 8015 RESTORE 8020:FOR F=0 TO 3:FOR G=0 TO 7:READ a:POKE USR CHR$ (149+f)+g,a:NEXT G:NEXT F 8016 LET A$=" \f ":LET C$="\g\h\i" 8020 DATA 0,129,66,60,60,66,129,0 8021 DATA 192,48,12,3,3,12,48,192 8022 DATA 0,126,195,231,255,126,0,0 8023 DATA 3,12,48,192,192,48,12,3 8024 RETURN 8025 RESTORE 8027:FOR F=0 TO 3:FOR G=0 TO 7:READ A:POKE USR CHR$ (153+f)+g,a:NEXT G:NEXT F 8026 LET A$=" ,J, ":LET C$="\k\l\m" 8027 DATA 0,0,126,219,255,126,0,0 8028 DATA 3,15,62,252,63,15,3,0 8029 DATA 255,255,126,60,255,255,255,165 8030 DATA 192,240,124,63,252,240,192,0 8031 RETURN 8035 RESTORE 8037:FOR F=0 TO 3:FOR G=0 TO 7:POKE USR CHR$ (157+f)+g,a:NEXT G:NEXT F 8036 LET A$=" \n ":LET C$="\o\p\q" 8037 DATA 0,66,153,255,153,66,0 8038 DATA 96,64,193,255,255,193,64,96 8039 DATA 0,255,231,219,219,231,255,0 8040 DATA 6,2,131,255,255,131,2,6 8041 RETURN 8045 RESTORE 8047:FOR F=0 TO 3:FOR G=0 TO 7:POKE USR CHR$ (161+f)+g,a:NEXT G:NEXT F 8046 LET A$=" \r ":LET C$="\s\t\u" 8047 DATA 0,0,219,255,255,219,0,0 8048 DATA 0,112,250,142,255,254,250,112 8050 DATA 0,24,60,126,195,126,60,24 8051 DATA 0,14,95,113,255,127,95,14 8052 RETURN 8500 IF ATTR (20,17)=5 THEN GO TO 610:GO TO 8501 8501 GO SUB 8045:GO TO 8502 8502 LET DOCK=DOCK+1 8503 IF DOCK <>4 THEN GO SUB 8035:GO TO 610 8506 PRINT INK 6; FLASH 1; AT 20,12;"DOCKING" 8507 LET CP=1 8508 PRINT BRIGHT 1:INK 4:PRINT AT 10,CP;C$ 8509 LET CP=CP+1 8510 IF CP=16 THEN GO TO 8590 8511 PAUSE 25 8512 PRINT AT 10,CP-1;" " 8513 GO TO 8508 8591 FOR N=7 TO 0 STEP -7 8592 PLOT INK 0;248,48:DRAW INK N;119,40 8594 BEEP 1,-10:BEEP 1,10:BEEP 1,-10 8595 NEXT N 8599 PRINT AT 10,14;"( )" 8600 PRINT INK 5; AT 20,17;"\ \ "; INK 7; AT 20,12;"CODE " 8605 PRINT AT 18,6;" " 8606 PRINT AT 20,5;" " 8610 GO SUB 8001 8650 GO TO 598 9300 PRINT INK 2:PRINT AT 20,17;"\ \ " 9350 GO TO 700 9400 PRINT AT D,A;" ":BORDER 0 9401 FOR G=1 TO 3:FOR F=0 TO 7:BORDER F:BEEP .05,F+G-1:NEXT F:NEXT G 9405 BORDER 0:PAPER 7:INK 1:CLS 9410 PRINT AT 7,10;"S O T H I S"; AT 9,10;"M U S T B E"; AT 11,10;"H E A V E N" 9411 PRINT TAB 10;"\''\''\''\''\''\''\''\''\''\''\''" 9412 PRINT INK 0; AT 15,15;"\ \ "; AT 16,15;"\ \ "; AT 17,13;"\ \ \ \ \ \ "; AT 18,15;"\ \ "; AT 19,15;"\ \ "; AT 20,15;"\ \ "; AT 21,14;"\.'\ \ \'.":PRINT OVER 1; AT 21,14;\{20}\{0}"\.: \:." 9420 RESTORE 9425:FOR N=0 TO 35:READ C,D:BEEP C,D:NEXT N 9425 DATA 1,0,1,2,.5,3,.5,2,1,0,1,0,1,2,.5,3,.5,2,1,0,1,3,1,5,2,7,1,3,1,5,2,7,.75,7,.25,8,.5,7,.5,5,.5,3,.5,2,1,0,.75,7,.25,8,.5,7,.5,5,.5,3,.5,2,1,0,1,0,1,-5,2,0,1,0,1,-5,2,0 9426 CLS :PRINT "O.K.TRAINEE DO YOU WANT ANOTHER TRY AT STAYING ALIVE??? PUSH 'N' TO STOP PROGRAM OR 'Y' TO RUN AGAIN" 9427 PAUSE 0:IF INKEY$="N" THEN GO TO 9998 9428 PRINT FLASH 1:PRINT AT 16,11;"BRAVE LAD" 9429 FOR F=1 TO 30:LET RS= INT (RND*50):BEEP .05,RS:NEXT F 9430 PAUSE 100:CLS :RUN 9500 LET I$="THIS IS BASE CALLING FIGHTER.... YOUR MISSION IS TO ESCORT A CONVOY OF CRAFT ACROSS THE GALAXY. IT IS UNLIKELY YOU WILL SURVIVE THOUGH. YOU MAY DOCK FOR REPAIRS ONLY 3 TIMES. " 9505 LET I$=I$+" READ -OUTS *DAM%=DAMAGE *PHE =PHASOR ENERGY *ACD =ALIEN CRAFT DESTROYED *CI =CRAFT IDENTITY THIS IS BASE----OVER AND OUT" 9510 PRINT " RADIO MESSAGE " 9511 PRINT " ++++++++++++++ " 9520 FOR B=1 TO LEN I$:BEEP .005,3:PRINT I$(B);:NEXT B 9530 PAUSE 0:RETURN 9600 PRINT AT D,A;" " 9601 PRINT FLASH 1:PRINT AT 0,0;" MISSION COMPLETE ":PAUSE 300 9605 LET SC=0:LET DAM=0:LET PH=1000:LET DOCK=0:LET FO=FO-5:LET FOR=FOR-5:LET FORT=FORT-5 9610 PAUSE 100:PRINT FLASH 0; AT 0,0;" " 9611 IF FOR<2 THEN LET FOR=2:IF FO<3 THEN LET FO=3:IF FORT<4 THEN LET FORT=4 9615 PRINT AT 0,0;" RETURN HOME TO FLY AGAIN" 9616 PAUSE 200:PRINT AT 0,0;"(32*SP)" 9620 PRINT AT 18,6;" ":PRINT AT 20,5;" " 9630 FOR F=1 TO 30:BEEP .05,20:BEEP .05,0:NEXT F 9640 GO SUB 8001:GO TO 598 9990 PRINT FLASH 1:PRINT AT 0,0;" MISSION ABORTED ":PAUSE 50 9995 PAUSE 50:RUN 9997 CLEAR :SAVE "STELRF.B1" LINE 1 9998 CLEAR ```