--- title: "Glenagleys" id: 71056 type: "computer_media" slug: "glenagleys" url: "http://localhost/computer_media/glenagleys/" markdown_url: "http://localhost/computer_media/glenagleys.md" published_at: "2026-08-27T11:21:52+00:00" modified_at: "2026-08-27T11:25:20+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/glenagleys-1.png" alt: "Glenagleys screen" excerpt: "A full 18-hole golf game with procedurally generated courses, eight clubs to choose from, live wind effects, and a separate putting phase complete with scorecard." 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/" indiv: - name: "Richard Warren" slug: "richard-warren" taxonomy: "indiv" url: "http://localhost/indiv/richard-warren/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" programmers: - name: "Richard Warren" slug: "richard-warren" taxonomy: "indiv" url: "http://localhost/indiv/richard-warren/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Glenagleys%20%28198x%29%28Warren%2C%20Richard%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "Glenagleys (198x)(Warren, Richard)(TS2068)(US)(Program).tap" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/glenagleys-1.png" alt: "Glenagleys screen" - url: "http://localhost/wp-content/uploads/2026/08/glenagleys-2.png" alt: "Glenagleys screen" media_type_tags: "Game" --- # Glenagleys Glenagleys is a text-and-graphics golf simulation game for up to 18 holes, procedurally generating each hole’s fairway, distance (170–489 yards), and par rating. The program defines five User Defined Graphics (UDGs) via POKE USR to represent a golfer, flag, tree, and ball sprites used during course rendering and putting sequences. Players select from eight clubs (1 wood through putter/sand wedge), adjust shot angle and strength within a countdown timer, and contend with a randomly varying wind speed and direction shown as a compass needle. Two distinct gameplay phases handle the fairway shot (using pixel-level PLOT/DRAW ballistics with wind deflection and surface detection via ATTR) and a zoomed-in putting green sequence. Running totals of strokes versus par are tracked across all holes in DIM arrays, with final scoring displaying eagle, birdie, par, or bogey outcomes. *** ## Program Analysis ### Program Structure The program is organized into several functional blocks: 1. **Lines 100–199:** Initialization — UDG setup, array allocation, title screen, and instructions. 2. **Lines 200–299:** Hole generation — random distance, par, fairway drawing using BEEP-animated tree sprites. 3. **Lines 300–505:** Main input loop — club selection, angle/direction setting via compass needle, wind display, countdown timer. 4. **Lines 506–599:** Shot calculation — ballistic trajectory with wind deflection, PLOT-based animation, surface detection. 5. **Lines 600–740:** Landing/surface handlers — sand (INK 1), water (INK 6), rough distance penalty. 6. **Lines 1000–1080:** Putting green phase — zoomed-in view, pixel-ball movement toward hole center. 7. **Lines 2000–2130:** Scoring and scorecard display — eagle/birdie/par/bogey classification, per-hole table, running total vs. par. 8. **Lines 3000–3015:** End-of-round summary with FLASH score banner. 9. **Lines 9000–9100:** UDG loader subroutine using DATA/POKE USR. ### Initialization Idioms The program uses a common memory-efficient idiom to establish constants: `LET o=PI-PI` (= 0) and `LET l=PI/PI` (= 1). These single-letter variables replace literal `0` and `1` throughout, saving tokenized bytes. `POKE 23609, CODE "#"` sets the border color attribute byte directly, here using `CODE "#"` (= 35) which encodes red border with paper/ink values — a common direct-hardware shortcut. ### UDG Definitions Five UDGs are loaded at line 9000 via a nested loop using `POKE USR CHR$ (143+f)` for f = 1 to 5, placing data into UDG slots \a through \e (characters 144–148). The five sprites defined are: | UDG | Label in code | Purpose | | --- | --- | --- | | \a [UDG-A] | Golfer | Player character on fairway | | \b [UDG-B] | Flag/marker | Flag near hole | | \c [UDG-C] | Tree segment | Used in fairway tree animation | | \d [UDG-D] | Tree segment | Used in fairway tree animation | | \e [UDG-E] | Hole cup | Displayed on putting green | The `RESTORE 9000` at the start of the subroutine ensures the DATA pointer is reset correctly before reading, which is necessary since `DATA` lines are distributed later in the program. ### Course Generation Each hole’s distance is chosen as `170 + INT(RND*319)` (170–488 yards), with par derived by thresholds: `3 + (d>229) + (d>429)` giving par 3, 4, or 5 without any IF statements — a clean Boolean arithmetic trick. The fairway is drawn using nested loops that PRINT randomized tree UDG substrings at random positions, with BEEP calls providing audio feedback during generation. The green/hole position is set by `ho = d/2` (horizontal pixel) and `he = 60 + INT(RND*80)` (vertical pixel). ### Ballistic Physics Shot trajectory uses trigonometric stepping: each iteration of the flight loop at lines 551–563 adds `SIN a` to x and `COS a` to y, giving a straight-line vector flight. Wind deflection is applied probabilistically: `IF RND*10 < ws THEN` add wind vector components, making stronger wind more frequently deflecting. The shot has two phases: an airborne arc for `air = dist * g` iterations (where `g` is a club-specific loft factor, 0 for putter), then a rolling phase for the remainder of `dist`. Surface type is checked with `ATTR(yp,xp)` and compared to stored attribute values (`at = CODE "£"` = 96 for fairway, 33 for sand, 102 for water). ### Club Selection and Strength System Eight clubs are implemented at lines 435–442, each setting a maximum distance multiplier `st` and loft factor `g`: | Key | Club | st (base) | g (loft) | | --- | --- | --- | --- | | 1 | 1 Wood | ~18–23 | 0.65 | | 2 | 3 Wood | ~15–20 | 0.70 | | 3 | 3 Iron | ~13–16 | 0.75 | | 4 | 5 Iron | ~10–13 | 0.80 | | 5 | 7 Iron | 9 | 0.85 | | 6 | 9 Iron | 7 | 0.90 | | 7 | Putter | 3 | 0 | | 8 | Sand Wedge | 5 | 0.95 | Shot distance is computed as `dist = (e * st) / 2` where `e` (1–10) is the strength set during the second input phase. The putter’s `g=0` means zero airborne travel — the entire shot rolls. ### Putting Green Phase Upon reaching the green (within 8 pixels of the hole), the game switches to a zoomed-in view at line 1000. The ball’s position is recalculated relative to the hole center (`xb = 5*(ho-x)+92`, `yb = 5*(he-y)+124`), giving a 5× zoom. The ball is drawn as a 3×3 pixel block using a loop over `xb-l TO xb+l`. Putting uses `COS a`/`SIN a` for motion components (note the swap from fairway convention — x uses COS, y uses SIN), and a hole-in check at pixel coordinates (92, 124) with tolerance 1. ### Scoring and Scorecard Arrays `q(18)` and `w(18)` store strokes and par per hole respectively. After each hole, the scorecard at lines 2085–2094 prints a formatted table. The running score differential `t - pt` (total strokes minus total par) is displayed. The end-of-round summary at line 3000 uses `FLASH 1` for the final score line. The game loops back to line 100 (re-initializing) rather than line 200, so a new round resets all state including hole counter `hn`. ### Notable Bugs and Anomalies - Line 420 is referenced by `GO TO 420` at line 505, but the actual input loop code begins at line 419 — line 420 does not exist as labeled; however the jump lands cleanly at line 435 due to how the interpreter seeks the next line. Actually re-examining: `GO TO 420` would seek from 419 forward and execute 435 next — the missing line 420 is effectively a `GO TO 435`-equivalent skip. - Line 506 is referenced by `GO TO 506` at lines 490, 491, and 1050, but no line 506 exists in the listing — the interpreter falls through to line 510 (the strength input loop). This is intentional: it skips re-displaying certain prompts. - Line 564 is referenced at line 562 (`IF f>dist THEN GO TO 564`) but does not appear — execution would continue at line 570, which appears to be the intended target. - Line 565 is referenced at lines 610 and 715 but is absent; execution falls to 570. This seems intentional, as 570 increments stroke count and checks proximity to the hole. - At line 2050, the condition `IF p-go > -l` (i.e., ≥ 0) will print the birdie/par/eagle message, but `b$` is only assigned for differences of 2, 1, or 0. A difference of 3 or more (albatross) leaves `b$` undefined or stale, potentially printing a wrong value. - The `DATA` line 9030 contains a literal `o` instead of `0` — this works because `o` was set to 0.0 and `READ a` reads numeric data. However, `o` is a variable, not a literal, and DATA statements in Sinclair BASIC store numeric values at parse time. This will cause an error at runtime since `o` in a DATA line is treated as a string token, not the variable. This is likely a typo for the literal digit `0`. - The `VAL "4"` at line 402 (`LET x = VAL "4"`) and `CODE "\"` (`LET y = CODE "\"` = 92) and `CODE "£"` (`LET at = CODE "£"` = 96) establish pixel starting positions and the fairway attribute value. Using `VAL` and `CODE` here is a byte-saving technique. ### Input Loop Architecture The main game loop uses a polled (non-blocking) INKEY$ approach rather than INPUT or PAUSE/INKEY$. The countdown timer at lines 455/513 decrements `ti` on each pass through the loop, and if it reaches zero the shot is taken with zero strength (`st=0`). The loop at lines 419–505 handles both Stage 1 (direction setting) and Stage 2 (strength setting) by testing the `stage` variable, with `GO TO 492` short-circuiting club selection during Stage 2. ## Source Code ``` 100 LET o= PI- PI:LET l= PI/ PI:LET hn=l:POKE 23609, CODE "#":GO SUB 9000 105 DIM q(18):DIM w(18) 165 BORDER 2:PAPER 2:INK 7:CLS :PRINT TAB VAL "9";"GLENAGLEYS"''" By Richard Warren" 180 INPUT "Number of holes? (18 max.) "; LINE y$ 181 IF VAL y$>18 THEN GO TO 180 183 LET limit= VAL y$ 190 PRINT ''" Controls are:"''" Number keys select club"'" A and S to set direction"''" ENTER when happy, then:"''" A and S to set strength"'" And ENTER to shoot." 195 PRINT ''" When on the Green, the club is automatically a putter."''" Press a key to continue." 199 PAUSE o 201 LET go=o 205 PAPER 4:BRIGHT o:INK o:CLS 210 LET d=170+ INT (RND*319) 220 LET p=3+(d>229)+(d>429) 230 LET ho=(d/2):LET t=o:LET he=60+ INT (RND*80):LET a$="[UDG-C][UDG-C][UDG-D][UDG-C][UDG-D][UDG-C][UDG-C]" 250 FOR f=l TO 20:BEEP .1,-30:LET c= RND*8:PRINT AT 5+c,(RND*(ho/8)); INK l;a$( TO (INT (RND*4)+l)); AT 4+c,(RND*(ho/8)); INK l;a$( TO (INT (RND*4)+l)) 260 NEXT f 261 LET de=o:BRIGHT l 262 FOR f=o TO (ho/16):BEEP .2,-10:PRINT AT 10+de,f;" "; AT 9+de,f;" "; AT 11+de,f;" ":LET de=de+ INT (RND*3)-l:NEXT f 263 LET hc=10+de:LET hp=(175-he)/8:IF hc>14 THEN LET hc=14 264 FOR f=(ho/16) TO (ho/8)+l:BEEP .2,-10:PRINT AT hc,f;" "; AT hc-l,f;" "; AT hc+l,f;" ":LET hc=hc+(hchp):NEXT f 265 BRIGHT o 267 FOR f=-l TO l:PRINT AT ((175-he)/8)+f-l,(ho)/8-l; BRIGHT l;" "; AT (175-he)/8-l,(ho/8)+f-l; BRIGHT l;" ":NEXT f 270 CIRCLE BRIGHT l;ho,he,8 280 CIRCLE ho,he,l 290 PRINT AT 10,o; PAPER o; INK 7;"[UDG-A]" 295 FOR f=-l TO l STEP 2:PRINT AT (21-(he/8))+f,(ho/8)-2; INK 6; BRIGHT l;"[UDG-B]":NEXT f 300 PAPER 2:INK 7 301 FOR h=o TO 2:PRINT AT h,o;" ":NEXT h 305 PRINT AT o,o;"DIST. ";d;" yds PAR ";p;" HOLE ";hn 310 FOR f=17 TO 21:PRINT AT f,o;" ":NEXT f 315 PRINT AT 17,13;"ANGLE"; AT 17,l;"WIND SPEED"; AT 17,26;"TIME"; AT 17,20;"STR." 320 PLOT o,o:DRAW 255,o:DRAW o,39:DRAW -255,o:DRAW o,-39 321 PLOT o,o:DRAW 255,o:DRAW o,151:DRAW -255,o:DRAW o,-151 322 PLOT 200,o:DRAW o,39:PLOT 44,o:DRAW o,39 323 PLOT 94,o:DRAW o,39:PLOT 152,o:DRAW o,39 402 LET e=5:LET a$=" ":LET aw= RND*6:LET aw1=o:LET ws= INT (RND*4)+l:LET co=o:LET stage=l:LET i=o:LET x= VAL "4":LET y= CODE "\":LET at= CODE "£" 405 CIRCLE 123,16,12:CIRCLE 20,16,12 416 INK 7:PAPER 2 418 LET ti=100 419 LET a$=" " 435 IF INKEY$="1" THEN LET st=20+ INT (RND*5)-2:LET g=.65:LET a$="1 wood" 436 IF INKEY$="2" THEN LET st=17+ INT (RND*5)-2:LET g=.7:LET a$="3 wood" 437 IF INKEY$="3" THEN LET st=14+ INT (RND*3)-l:LET g=.75:LET a$="3 iron" 438 IF INKEY$="4" THEN LET st=11+ INT (RND*3)-l:LET g=.8:LET a$="5 iron" 439 IF INKEY$="5" THEN LET st=9:LET g=.85:LET a$="7 iron" 440 IF INKEY$="6" THEN LET st=7:LET g=.9:LET a$="9 iron" 441 IF INKEY$="7" THEN LET st=3:LET g=o:LET a$="Putter" 442 IF INKEY$="8" THEN LET st=5:LET g=.95:LET a$="Sand Wedge" 450 IF INKEY$<"9" AND INKEY$>"0" THEN PRINT AT 2,o; PAPER 2;"CLUB SELECTED ";a$;" ":BEEP .5,o 455 LET ti=ti-l:PRINT AT 19,27;ti;" ":IF ti <=o THEN LET st=o:GO TO 535 465 LET a1=a 470 LET a=a+((INKEY$="s")/10)-((INKEY$="a")/10) 475 PLOT 123,16:DRAW INVERSE l;10*(SIN a1),10*(COS a1) 480 PLOT 123,16:DRAW 10*(SIN a),10*(COS a) 490 IF INKEY$= CHR$ 13 AND a$ <>" " AND stage=l THEN BEEP .5,o:GO TO 506 491 IF INKEY$= CHR$ 13 AND stage=2 THEN BEEP .5,o:GO TO 1050 492 IF stage=2 THEN GO TO 465 496 IF INKEY$="x" AND stage=l THEN PLOT o,y:DRAW OVER l; INK l;x,o:PLOT x,40:DRAW OVER l; INK l;o,y-40: 499 PLOT 20,16:DRAW INVERSE l;10*(SIN aw1),10*(COS aw1) 500 PLOT 20,16:DRAW 10*(SIN aw),10*(COS aw) 501 LET aw1=aw 502 LET aw=aw+((INT (RND*3))-l)/10 503 LET ws=ws+(INT (RND*3)-l)/10:IF ws<.5 THEN LET ws=.5 504 PRINT AT 19,6; PAPER 2;ws;" " 505 GO TO 420 510 LET e=e+(INKEY$="s")-(INKEY$="a") 511 IF e10 THEN LET e=10 513 IF stage=l THEN LET ti=ti-l:PRINT AT 19,27;ti;" ":IF ti <=o THEN LET st=o:GO TO 535 515 PRINT AT 19,21; PAPER 2; INK 7;e;" " 517 FOR f=l TO 50:NEXT f 520 IF INKEY$= CHR$ 13 THEN BEEP .5,o:GO TO 531 525 GO TO 510 532 IF stage=l THEN PRINT AT 2,o;" " 534 INK o 535 IF stage=2 THEN GO TO 1051 539 LET dist=(e*st)/2 545 LET e=5 548 LET air=dist*g 549 LET x1=x:LET y1=y 551 FOR f=o TO air:LET x1=x:LET y1=y:LET x=x+(SIN a):LET y=y+(COS a) 552 IF RND*10at THEN GO TO 701 562 PLOT INVERSE l;x1,y1::PLOT INK i;x,y:IF f>dist THEN GO TO 564 563 NEXT f 570 LET go=go+l 580 IF ABS (x-ho) <=8 AND ABS (y-he) <=8 THEN GO TO 1000 599 GO TO 415 610 IF ATTR (yp,xp)=33 OR ATTR (yp,xp)=102 THEN GO TO 565 700 GO TO 563 705 LET xs= ATTR (yp,xp) 710 IF xs=33 THEN LET i=l 715 IF xs=102 THEN LET i=6:GO TO 565 726 IF xs=32 THEN LET i=o:LET dist=dist-l 740 GO TO 562 1000 PAPER 4:INK 7:CLS 1001 LET stage=2 1002 FOR f=18 TO 21:PRINT AT f,0; PAPER 2;" ":NEXT f 1003 FOR f=-20 TO 20 STEP 2:BEEP .1,f:NEXT f 1004 PLOT o,o:DRAW 255,o:DRAW o,32:DRAW -255,o:DRAW o,-32 1005 CIRCLE INK 7;123,16,12 1020 PRINT AT 10,15; INK o;"[UDG-E]" 1029 LET xb=(5*(ho-x))+92:LET yb=(5*(he-y))+124 1031 FOR g=xb-l TO xb+l:PLOT yb-l,g:PLOT yb,g:PLOT yb+l,g:NEXT g 1040 GO TO 459 1050 GO TO 506 1055 :LET s=e*8 1056 INK 7 1058 LET go=go+l 1060 FOR f=o TO s:LET xb1=xb:LET yb1=yb:LET xb=xb+(COS a):LET yb=yb+(SIN a) 1061 FOR g=xb1-l TO xb1+l:PLOT INVERSE l;yb1-l,g:PLOT INVERSE l;yb1,g:PLOT INVERSE l;yb1+l,g:NEXT g 1062 FOR g=xb-l TO xb+l:PLOT yb-l,g:PLOT yb,g:PLOT yb+l,g:NEXT g 1063 IF INT (ABS (yb-124)) <=l AND INT (ABS (xb-92)) <=l THEN GO TO 2000 1064 NEXT f 1074 PRINT AT 10,15; INK o;"[UDG-E]" 1075 FOR g=xb-l TO xb+l:PLOT yb-l,g:PLOT yb,g:PLOT yb+l,g:NEXT g 1080 GO TO 1040 2000 BEEP .2,2:BEEP .4,2:BEEP .6,2:BEEP .2,2:BEEP .4,2:BEEP .6,2:BEEP .2,4:BEEP .4,5:BEEP .6,6 2002 PAPER 2:INK 7:CLS 2010 PRINT " GLENEAGLES" 2020 PRINT :PRINT :PRINT "You completed the hole in ";go 2030 PRINT "strokes":PRINT :PRINT :PRINT "Par for hole ";hn;" is ";p 2040 IF p-go=2 THEN LET b$="eagled" 2041 IF p-go=l THEN LET b$="birdied" 2042 IF p-go=o THEN LET b$="parred" 2050 IF p-go>-l THEN PRINT :PRINT :PRINT "You have ";b$;" the hole" 2055 IF go-p>o THEN PRINT :PRINT :PRINT "You have a bogie "+ STR$ INT (go-p)+" on this hole" 2060 LET q(hn)=go:LET w(hn)=p 2070 PRINT :PRINT :PRINT "Press any key to continue" 2080 PAUSE o 2085 CLS :PRINT AT o,3;"HOLE"; TAB 13;"PAR"; TAB 23;"STROKES" 2090 FOR f=l TO hn:PRINT AT f,5;f; AT f,25;q(f); AT f,15;w(f):NEXT f 2094 LET t=o:LET pt=o:FOR f=l TO hn:LET t=t+q(f):NEXT f:FOR f=l TO hn:LET pt=pt+w(f):NEXT f:PRINT AT hn+2,0;"Score so far = ";t-pt 2095 IF hn >=limit THEN GO TO 3000 2100 LET hn=hn+l 2110 PRINT AT 21,7; INK 7;"Press to continue" 2120 PAUSE o 2130 GO TO 200 3000 LET t=o:LET pt=o:FOR f=l TO hn:LET t=t+q(f):NEXT f:FOR f=l TO hn:LET pt=pt+w(f):NEXT f:PRINT AT 19,10;"par ";pt; AT 19,20;"total ";t; AT 21,o; FLASH l;" "; AT 21,o;" Score ";t-pt;" " 3010 PAUSE o 3015 GO TO 100 9000 RESTORE 9000:FOR f=l TO 5:FOR g=o TO 7:READ a:POKE USR CHR$ (143+f)+g,a:NEXT g:NEXT f 9010 DATA 255,255,195,219,219,195,255,255 9020 DATA 12,60,120,120,120,120,60,12 9030 DATA o,16,56,84,56,84,16,16 9040 DATA o,28,62,28,62,8,8,8 9050 DATA 28,34,65,65,65,34,28,o 9100 RETURN 9998 SAVE "Golf" LINE 1 9999 ```