--- title: "LANDER FIX" id: 71202 type: "computer_media" slug: "lander-fix" url: "http://localhost/computer_media/lander-fix/" markdown_url: "http://localhost/computer_media/lander-fix.md" published_at: "2026-08-31T08:51:39+00:00" modified_at: "2026-08-31T08:55:39+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/lander-fix.png" alt: "LANDER FIX screen" excerpt: "Pilot a rotating lander across five procedurally drawn moonscapes, managing fuel and speed to touch down safely on every pad before your ships run out." 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/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/LANDER%20FIX%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/lander-fix.png" alt: "LANDER FIX screen" media_type_tags: "Game" --- # LANDER FIX LANDER FIX is a multi-screen Moon Lander game in which the player pilots a spacecraft, controlling vertical thrust and horizontal rotation via joystick, and must touch down on marked landing pads across five distinct scrolling moonscapes. The program defines 21 user-defined graphics (UDGs \a through \u) via POKEd DATA at line 1140, forming a multi-character lander sprite that rotates through four orientations (characters 144–147). Terrain is drawn procedurally using PLOT/DRAW commands read from DATA lines 1420–1470, with boundary-crossing logic at lines 770–870 that cycles through the five terrain sections. SOUND commands provide engine noise and crash effects throughout, and meteor hazards are simulated via randomly positioned PRINT statements in the game loop. Fuel, vertical speed, horizontal speed, score, and remaining ships are tracked across landings and levels, with difficulty increasing each time all five pads are successfully used. *** ### Program Structure The program is organized into clearly delineated sections, with REM statements used as section headers. The overall flow is: 1. Lines 10–20: Title screen and instructions 2. Lines 30–80: Variable setup and intro animation 3. Lines 90–140: Level initialization, terrain drawing, HUD setup 4. Lines 150–530: Main game loop 5. Lines 540–640: Scene/pad transition logic 6. Lines 650–760: Successful landing handler 7. Lines 770–870: Screen boundary (left/right scroll) logic 8. Lines 880–1010: Crash/explosion sequence 9. Lines 1020–1050: Game over screen 10. Lines 1060–1130: Level completion and bonus 11. Lines 1140–1160: UDG loader subroutine 12. Lines 1170–1370: UDG pixel DATA (21 characters) 13. Lines 1380–1480: Moonscape PLOT/DRAW subroutine and DATA ### User-Defined Graphics The subroutine at line 1140 POKEs 21 UDG characters (\a through \u) by reading DATA from lines 1170–1370. Each UDG is 8 bytes. The value `a` in the DATA lines is used as a literal token — in this context it represents the numeric value of the BASIC keyword `AND` (token 200 / 0xC8), serving as a compact stand-in for the value 200 in the pixel data. This is an intentional and well-known ZX Spectrum BASIC trick to embed specific byte values in DATA statements using keyword tokens. Together the 21 UDGs form a multi-tile lander sprite with four rotation states (characters 144–147 map to UDGs \a–\d) and various explosion/debris frames used in the crash animation at lines 920–990. ### Sprite Rotation and Movement The lander’s facing direction is tracked by the variable `gs`, which holds the character code of the current UDG to PRINT. It starts at 147 (pointing down) and is incremented or decremented by joystick input at line 360: ``` LET gs=gs+(STICK (1,2)=4)-(STICK (1,2)=8) ``` Lines 370–380 wrap `gs` around the range 144–147, implementing modular rotation through the four cardinal orientations. The thrust direction and drift adjustment at lines 340–350 are then conditional on which orientation the lander is currently in. ### Terrain Generation Five moonscape sections are stored as PLOT/DRAW DATA starting at line 1420 through 1470, each prefixed by a count `N` and starting coordinates. The subroutine at line 1380 reads and executes these commands to draw the terrain. The variable `ls` tracks the current DATA pointer, allowing `RESTORE ls` to reload any scene. Boundary crossings (lines 770–870) advance or retreat `ls` by 10 to move between adjacent sections, wrapping around at the extremes. ### Landing Pad Logic Five landing pad positions (one per terrain section) are encoded as hardcoded pairs of row `h` and column `d` in lines 590–600, selected by the column range the player was in when they descended. Line 180 checks for alignment: ``` IF INT line=h-2 AND (INT col=d OR INT (col+.5)=d) THEN GO TO 650 ``` A successful landing also checks `gs=147` (lander pointing down) and `vs<=10` (slow enough vertical speed) at line 660, otherwise it goes to the crash handler. The array `c(30)` records already-used pads (line 730), and attempting to re-use one triggers the “RESTRICTED LANDING PAD” message at line 680. All five pads must be used to complete a level (line 750 checks `pad=5`). ### Physics Model The physics are simplified but functional. Vertical speed `vs` and horizontal speed `hs` are display values only; actual position updates use `lv` (a fractional line-speed factor starting at 0.5) and `drift`. Line 330 moves the lander vertically, gated by an ATTR check to prevent passing through terrain (ATTR value 132 indicates a terrain pixel cell). Line 300 advances the column by the sign of `drift`. The variable `down` at line 350 acts as a thrust toggle, influenced by joystick fire-button state and cleared when INKEY$ is empty. ### SOUND and Audio SOUND commands are used extensively. Line 320 provides continuous engine audio modulated by column position. Lines 90 and 310 fire the SOUND chip with specific envelope parameters for engine boost. The crash sequence at line 950 uses a high-amplitude SOUND burst. Successful landings at line 730 use BEEP loops for a congratulatory tune. Fuel consumption is tracked and deducted by 10 per thrust activation (line 390), and an out-of-fuel branch exists at line 510. ### HUD and Display The status bar occupies the lower screen area (printed to stream `#0`) and shows fuel, vertical speed, horizontal speed, and remaining ships. Lines 140 and 170 redraw the HUD on alternate passes. Block graphics in the PRINT statements create decorative borders around the speed readouts. The `INK 5*RND` idiom causes a color-flicker effect on part of the speed display each frame. ### Scroll and Multi-Room Design The game world is divided into five horizontal rooms. When the lander exits left or right (lines 400–410 check `col` bounds), the program performs a `CLS`, `RESTORE`s the appropriate DATA block, redraws the terrain, and repositions the lander at the matching edge of the new room. This gives the illusion of a continuous scrolling world across five screens. ### Level Progression After all five pads are used, line 1060 adds remaining fuel as a bonus score. Lines 1100 increment the ship count and increase `lv` by 0.5, making the lander fall faster on subsequent levels, then restart the level setup. The `lv` factor in line 330 scales the vertical movement each tick. ### Notable Techniques and Idioms - `NOT PI` is used throughout as a compact literal for `0` (since `NOT 3.14159...` evaluates to 0 in Sinclair BASIC). - `PI` alone evaluates to approximately 3.14159, used at line 40 as `INK PI` (truncated to 3, cyan) and in calculations like `col/3.1`. - `VAL "number"` in `PAUSE VAL "80"` (line 890) is a memory optimization; storing a number as a string avoids the 5-byte floating-point representation in the token stream. - Boolean arithmetic is used heavily, e.g. `LET col=col*3.1:LET s=1` after scene selection, and the multi-condition column calculations in lines 560, 590, 600, 620. - The ATTR() function at line 250 is used for collision detection against terrain (ATTR value 4 = green INK on black PAPER, matching the meteor color) and at line 330 for floor collision (value 132). - The `c(30)` array uses `line+col` as a combined index key for visited pads, which is a space-efficient but collision-prone hash; however, with only five pads spread across different row/column combinations, collisions are unlikely in practice. ### Potential Bugs and Anomalies - Line 940 and 990 contain `\{16}\{5}` embedded mid-line in a PRINT statement outside a string — this appears to be a stray INK control code artifact that could cause unexpected display behavior or a syntax error depending on the interpreter state. - Line 1100 ends with `\{16}\{0}` appended after the statement, which is likely a stray INK 0 embedded control character that may cause no visible effect but is not syntactically clean. - Lines 190 and 240 both check `STICK (2,2)=1 AND gs=147` with identical PRINT effects, so the thrust-down visual fires twice in the same iteration when both conditions are met; this appears to be a redundancy rather than intentional behavior. - The `c(30)` array is dimensioned at line 70, but `line+col` could potentially exceed 30 given that `line` ranges up to about 20 and `col` up to 30, causing an out-of-bounds error. In practice, the five specific landing positions keep the sum within range. ## Source Code ``` 10 INK PI:CLS :PRINT ''''" MOON LANDER"''''"\{20}\{1}Fire button\{20}\{0} is jet propulsion."'"\{20}\{1}Joystick\{20}\{0} left & right to rotate."''"Land on pads. too fast you crash"''"Watch out for green meteors"''"\{20}\{1}Land on all for next level.\{20}\{0}" 20 PRINT "Press a key to start":PAUSE NOT PI 30 REM SetupVariables 40 PAPER NOT PI:BORDER NOT PI:CLS :INK 6 50 LET lv=.5:LET sc= NOT PI:LET z=3:LET l=sc:LET vs=30:LET hs=21 60 FOR j=10 TO 85:PLOT j* RND*3,j* RND*2:NEXT j:FOR x=1 TO 6:INK x+2:CIRCLE (x* RND)*40+6,(x* RND)*25+10,x:NEXT x:GO SUB 1140 70 LET pad= NOT PI:LET f=3000:DIM c(30) 80 FOR x= NOT PI TO 14:SOUND 7,14;8,2;9,x;10,x:INK x/2:BORDER 0::SOUND 0,100+x;3,x;5,15:PRINT AT 21-x, PI+x; INK 6;"\{18}\{1}\m\{18}\{0}"; INK 7;"\c":CIRCLE 200,140,x*2:PRINT AT 21-x, PI+x;" ":NEXT x:CLS 90 IF STICK (2,2)=1 THEN }6,6;7,0;8,15;9,16;10,16;12,56;13,8:PAUSE 2:SOUND 8,0;9,0;10,0 100 LET ls=1420:LET h= NOT PI:LET d= NOT PI:LET line=2:LET col=10:LET drift=3:LET gs=147:LET down=4:LET s=h 110 GO SUB 1380 120 FOR j=40 TO 85:INK 8:PLOT j* RND* PI, VAL "j* RND*1+80":NEXT j:CIRCLE INK 6;200,140,10: 130 PRINT AT 14,4;"\{18}\{1}x"; AT 20,9;"x"; AT 17,15;"x"; AT 15,21;"x"; AT 19,24;"x\{18}\{0}" 140 FOR x= NOT PI TO 21:FOR Y= NOT PI TO 21 STEP 21:PRINT AT Y, NOT PI; PAPER PI; INK NOT PI;"\{18}\{1}\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''\..\''"; AT X,0;"\{18}\{1}\''"; AT X,31;"\..\{18}\{0}":NEXT y:NEXT x:PRINT #0; AT 1,0;; INK 2;"\{20}\{1}v/speed:\{20}\{0}"; PAPER 6;"\{18}\{1}\.'\{18}\{0}"; INK 2;vs; INK 5* RND; PAPER 6;"\{18}\{1}\.'\'.\.'\. \''\ :\'.\n\'.\{18}\{0}\{20}\{0}"; AT 1,20; INK 2; PAPER 5;"\{20}\{1}h/speed: \{20}\{0}"; AT 1,28;hs;" "; AT 0,21; INK 8;"\d\d\::\{20}\{1}Ships:\{20}\{0}"; AT 0,31;z;#0; INVERSE 1; INK 2; AT 0,0;"\{20}\{1}fuel: \{20}\{0}";f;"\{18}\{1}\{20}\{1}\'.\'.\n\'.\''\'.\j\'.\k\'.\'.\{18}\{0}\{20}\{0}" 150 REM RUN program 160 FLASH NOT PI:BORDER NOT PI:INK 7 170 PRINT #0; AT 1,0;; INK 7;"\{20}\{1}v/speed:\{20}\{0}"; PAPER 1;"\{18}\{1}\.'\{18}\{0}";vs; INK 5* RND;"\{18}\{1}\.'\'.\.'\. \''\ :\'.\n\'.\{20}\{0}\{18}\{0}"; AT 1,20; INK 1; PAPER 7;"\{20}\{1}h/speed: \{20}\{0}"; AT 1,28;hs;" "; AT 0,21;"\d\d\::\{20}\{1}Ships:\{20}\{0}"; AT 0,31;z;#0; AT 0,0; PAPER 1; INK 7;"\{20}\{1}fuel: \{20}\{0}";f;"\{18}\{1}\{20}\{1}\'.\'.\n\'.\''\'.\j\'.\k\'.\'.\{20}\{0}\{18}\{0}" 180 IF INT line=h-2 AND (INT col=d OR INT (col+.5)=d) THEN GO TO 650 190 IF STICK (2,2)=1 AND gs=147 THEN PRINT AT line+1,col;"\p":PAUSE 2:PRINT AT line+1,col;" " 200 PRINT AT line,col; CHR$ gs 210 IF STICK (2,2)=1 AND gs=145 THEN PRINT AT line-1,col;"\p":PAUSE 2:PRINT AT line-1,col;" " 220 IF STICK (2,2)=1 AND gs=146 THEN PRINT AT line,col-1;"\p":PAUSE 2:PRINT AT line,col-1;" " 230 IF STICK (2,2)=1 AND gs=144 THEN PRINT AT line,col+1;"\p":PAUSE 2:PRINT AT line,col+1;" " 240 IF STICK (2,2)=1 AND gs=147 THEN PRINT AT line+1,col;"\p":PAUSE 2:PRINT AT line+1,col;" " 250 IF ATTR (line+ SGN vs,col+ SGN drift)=4 OR ATTR (line,col+ SGN drift)=4 THEN GO TO 880 260 FOR x=1 TO RND*2 270 PRINT AT x,(30* RND)-col; INK 7* RND;" \k \h \g\h \r\g " 280 NEXT x 290 LET pc=col:LET pl=line 300 LET col=col+ SGN drift 310 IF STICK (2,2)=1 THEN }6,6;7,0;8,15;9,16;10,16;12,200;13,8 320 SOUND 0,100;2,150;5,5;7,28;8,col;9,col;10,10 330 LET line=line+lv* SGN vs*(ATTR (line+ SGN vs,col) <>132) 340 LET drift=drift+(STICK (2,2)=1 AND gs=146)-(STICK (2,2)=1 AND gs=144) 350 LET down= SGN (down+(STICK (2,2)=1 AND gs=145)-(STICK (2,2)=1 AND gs=147)-down*(INKEY$="")) 360 LET gs=gs+(STICK (1,2)=4)-(STICK (1,2)=8) 370 IF gs=148 THEN LET gs=144 380 IF gs=143 THEN LET gs=147 390 IF STICK (2,2)=1 THEN LET f=f-10:BEEP .08,20 400 IF col >=30 THEN GO TO 770 410 IF col >=0 AND col<1 THEN GO TO 830 420 IF line=1 THEN LET line=2 430 LET vs=vs+5+15*down:LET hs=drift*7 440 IF s <>0 THEN GO TO 460 450 IF line >=12 AND s=0 THEN GO TO 550 460 IF s=1 AND line <=2 THEN RESTORE 1420:LET col=(col/3.1)+22*(ls=1470)+19*(ls=1460)+11*(ls=1450)+6*(ls=1440):LET ls=1420:CLS :INK 4:LET line=11:LET s= NOT PI:GO TO 110 470 IF l=4 THEN BEEP .08,40 480 IF l=6 THEN BEEP .12,42:LET l= NOT PI 490 LET l=l+1 500 IF line <=2 THEN LET line=2 510 IF NOT f THEN GO TO 1120 520 PRINT AT pl,pc;" " 530 GO TO 150 540 REM change scenery 550 LET col= INT col 560 LET ls=1420+10*(col>0 AND col<7)+20*(col>6 AND col<13)+30*(col>12 AND col<18)+40*(col>17 AND col<22)+50*(col>21 AND col<31) 570 CLS :INK 4:LET line=2:RESTORE ls 580 GO SUB 1380 590 LET h=6*(col>0 AND col<7)+21*(col>6 AND col<13)+16*(col>12 AND col<18)+9*(col>17 AND col<22)+21*(col>21 AND col<31) 600 LET d=12*(col>0 AND col<7)+9*(col>6 AND col<13)+12*(col>12 AND col<18)+16*(col>17 AND col<22)+6*(col>21 AND col<31) 610 PRINT AT h,d;"\{18}\{1}x\{18}\{0}" 620 LET col=col-6*(col>21)-5*(col>17)-5*(col>12)-6*(col>6) 630 LET col=col*3.1:LET s=1 640 GO TO 150 650 REM landing 660 IF gs <>147 OR vs>10 THEN GO TO 880 670 IF c(line+col) <>1 THEN GO TO 720 680 PRINT AT 21,0;"RESTRICTED LANDING PAD. GO AWAY." 690 FOR i=1 TO 500 700 IF INKEY$="9" THEN LET h= NOT PI:GO TO 150 710 NEXT i:GO TO 880 720 PRINT AT 10,7;"GREAT LANDING"'" CONGRATULATIONS!" 730 LET c(line+col)=1:FOR i=1 TO 4:FOR j= NOT PI TO 10:BEEP .08,j:NEXT j:NEXT i:RESTORE 1420:CLS :INK 4 740 LET sc=sc+100 750 LET pad=pad+1:IF pad=5 THEN GO TO 1060 760 GO TO 100 770 REM crossing boundries 780 IF ls <=1420 THEN LET col=1:GO TO 520 790 LET ls=ls+10 800 IF ls >=1480 THEN LET ls=1430 810 CLS :RESTORE ls:INK 4 820 LET col=(ls=1430)+8*(ls=1440)+13*(ls=1450)+18*(ls=1460)+22*(ls=1470):GO TO 580 830 IF ls <=1420 THEN LET col=29:GO TO 520 840 LET ls=ls-10 850 IF ls <=1420 THEN LET ls=1470 860 CLS :RESTORE ls:INK 4 870 LET col=6*(ls=1430)+12*(ls=1440)+17*(ls=1450)+21*(ls=1460)+29*(ls=1470):GO TO 580 880 REM crash landing 890 LET z=z-1:BEEP .08,0:BEEP .08,15:BEEP .08, PI:PAUSE VAL "80" 900 FOR x= NOT PI TO 2 910 FLASH 1:PAPER 8:INK 6 920 PRINT AT line-x,col-x;"\g\h\i"; AT line,col-1;"\j\k\m"; AT line+x,col-x;"\o\p\q" 930 PRINT AT line-x,col-x;"\m\o\p"; AT line-(7+x),col-x;"\k\l\r"; AT line-(5+x),col-x;"\g\u\i\l" 940 PRINT AT line-(9+x),col-(4+x);"\g\k \l"; AT line-(8+x),col-(2+x);"\k \l \r"; AT line-(6+x)\{16}\{5},col+x;"\g \u\i \l" 950 :SOUND 6,6;7,7;8,16;9,16;10,16;12,250;13,8: 960 PRINT AT line-x,col-x;" "; AT line,col-1;" "; AT line+x,col-x;" " 970 PRINT AT line-x,col-x;" "; AT line-(7+x),col-x;" "; AT line-(5+x),col-x;" " 980 PRINT AT line-(9+x),col-(4+x);" "; AT line-(8+x),col-(2+x);" "; AT line-(6+x),col+x;" " 990 PRINT AT line-(9+x),col-(4+x);"\g\k \l"; AT line-(8+x),col-(2+x);"\k \l \r"; AT line-(6+x)\{16}\{5},col+x;"\g \u\i \l" 1000 NEXT x:PAUSE 60:INK 7:PAPER NOT PI:BORDER NOT PI:CLS :IF NOT z THEN GO TO 1020 1010 FLASH 0:RESTORE 1420:CLS :INK 4:GO TO 100 1020 PRINT AT 2,10;"Your Score: ";sc 1030 PRINT AT 10,0;" GAME OVER"," Push Joystick up to start" 1040 IF STICK (1,2)=1 THEN CLEAR :CLS :FLASH 0:GO TO 30 1050 IF STICK (1,2)=0 THEN GO TO 1040 1060 REM Finish Game 1070 LET sc=sc+f 1080 CLS :INK 7:PRINT AT 5,1;"Well done , you have landed on all the pads with a score of "; AT 8,12; FLASH 1;sc 1090 IF NOT z THEN PRINT AT 12, PI;"Push stickup to start":IF STICK (1,2)=1 THEN RUN 1100 LET z=z+1:LET lv=lv+.5\{16}\{0} 1110 PAUSE VAL "200":CLS :INK 4:GO TO 70 1120 PRINT AT 10,7;"OUT OF FUEL":LET z= NOT PI:PAUSE 200 1130 GO TO 1020 1140 REM lander graphics 1150 FOR n= USR "\a" TO USR "\u"+7:READ a:POKE n,a 1160 NEXT n:RETURN 1170 DATA 5,15,109,252,a,109,15,5 1180 DATA 231,66,255,126,24,60,a,24 1190 DATA 80,240,182,63,a,182,240,160 1200 DATA 24,60,a,24,126,255,66,231 1210 DATA 0,24,40,a,16,0,a,a 1220 DATA 112,136,a,68,40,48,0,a 1230 DATA 0,a,a,56,44,16,0,a 1240 DATA 0,a,30,18,34,84,232,0 1250 DATA 94,177,130,228,34,65,66,60 1260 DATA 0,62,65,66,34,17,14,0 1270 DATA 96,144,a,116,10,49,65,126 1280 DATA 62,65,242,9,247,136,144,96 1290 DATA 145,82,16,7,244,8,74,137 1300 DATA 100,24,198,0,222,0,24,102 1310 DATA 0,4,34,18,1,68,50,9 1320 DATA 9,50,68,1,18,34,4,0 1330 DATA 0,8,170,42,73,65,137,a 1340 DATA 144,76,34,128,72,68,32,0 1350 DATA 0,3,15,a,120,200,255,56 1360 DATA 0,192,240,a,30,19,255,28 1370 DATA 0,32,68,72,128,36,76,144 1380 REM Moonscapes 1390 READ N,x,y:PLOT x,y 1400 FOR n= NOT PI TO N:READ h,v:DRAW h,v:NEXT n 1410 REM \{20}\{1} ls \{20}\{0} 1420 DATA 25,0,31,16,0,16,32,8,0,8,8,16,-48,8,-8,8,0,8,16,16,8,8,16,8,-16,8,0,2,8,2,0,4,8,16,16,8,-24,8,8,8,0,16,-32,8,0,16,40,8,-8,16,-8,8,16,6,-8 1430 DATA 7,0,31,48,0,48,96,24,0,24,24,48,-128,24,-16,24,0,8,16 1440 DATA 9,0,153,48,-128,22,-18,24,0,24,48,48,24,24,48,24,-48,24,0,6,12,4,0 1450 DATA 10,0,31,48,24,24,48,22,-56,24,0,6,12,6,0,6,24,48,48,24,-72,24,24,16,0 1460 DATA 9,0,55,6,24,6,0,12,24,48,48,24,-72,24,24,24,0,48,-96,24,0,32,104 1470 DATA 6,0,103,40,-96,24,0,56,120,24,-24,48,-24,24,48,32,-24 1480 RETURN 1490 SAVE "LANDER FIX" LINE 1 ```