--- title: "Knight Fight" id: 64778 type: "computer_media" slug: "knight-fight" url: "http://localhost/computer_media/knight-fight/" markdown_url: "http://localhost/computer_media/knight-fight.md" published_at: "2026-03-08T00:47:24+00:00" modified_at: "2026-03-30T21:43:25+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/03/Knight-1.png" excerpt: "Two knights charge across the screen in this equipment-buying jousting game, where armour, lance weight, and RND combine to decide who takes the hit." 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_contents: - id: 64715 title: "Miscellaneous Programs" type: "computer_media" url: "http://localhost/computer_media/miscellaneous-programs/" media_type: "Program" spectrum_computing: "https://spectrumcomputing.co.uk/entry/13330/ZX-Spectrum/Knight_Fight" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/03/Knight-1.png" - url: "http://localhost/wp-content/uploads/2026/03/Knight-2.png" media_type_tags: "Game" --- # Knight Fight Knight Fight is a two-player-style jousting game in which the human controls one knight and the computer controls the other, animating them charging toward each other across the screen. The program uses 21 user-defined graphics (UDGs A through U) loaded from DATA statements to draw the knights and lance-impact effects, with separate sprite frames for left-facing and right-facing characters. An equipment-purchase phase lets the player spend 100 coins on armor (chain-mail or plate), lance (light, medium, or heavy), a secondary weapon (sword, axe, or mace), and an optional shield, each affecting combat outcome probabilities. The jousting pass is animated by decrementing an x-coordinate each iteration with BEEP calls to simulate hoof-beats, and the collision check at line 170 triggers hit-or-miss resolution using RND weighted by both sides’ lance and armor ratings. Hit/miss outcomes are shown with additional UDG frames and score displayed in hit-points at rows 20–21. *** ## Program Structure 1. **Lines 1–10**: Title splash and initialisation. 2. **Lines 7000–7460**: Equipment shop subroutine — player spends 100 coins on armour, lance, weapon, shield; opponent loadout chosen randomly. 3. **Lines 8000–8060 / 8500**: Draw the castle using `PLOT`/`DRAW`, including a repeating-segment subroutine at 8500. 4. **Lines 100–190**: Main animation loop — draws both knights at current `x` position, decrements `x`, beeps, repeats. 5. **Lines 200–240**: Collision adjudication — determines hit/miss for each side using weighted RND expressions. 6. **Lines 500–540**: Enemy knight hit — splash UDGs, deduct enemy HP. 7. **Lines 600–640**: Player knight hit — splash UDGs, deduct player HP. 8. **Lines 800–910**: Post-pass repositioning and shield/horse-handling for subsequent passes. 9. **Lines 1000–1430**: Unhorsed close-combat loop — keyboard input selects weapon, RND combat resolution, HP display. 10. **Lines 4000–4510**: Death screens. 11. **Lines 5000–5010**: Play-again prompt. 12. **Lines 9000–9140**: UDG DATA (21 characters × 8 bytes each, with extra splash-effect data at 9100+). ## User-Defined Graphics All 21 UDG slots (A–U, chars 144–164) are loaded from DATA in two phases. The full set is poked at line 7130 during setup. Additional re-pokes at lines 520, 620, 1020, and 1030 swap in lance-impact / dismount frames mid-game using `RESTORE 9060` or `RESTORE 9100` followed by targeted `POKE USR CHR$ NNN` loops. | UDG range | DATA start | Purpose | | --- | --- | --- | | A–I (\a–\i) | 9000 | Right-facing player knight (3×3 sprite, two leg positions) | | J–R (\j–\r) | 9030 | Left-facing opponent knight (3×3 sprite, two leg positions) | | S–U (\s–\u) | 9050 | Lance / shield UDGs | | P–Q (reloaded) | 9060 | Dismount/fall frames | | Various (reloaded) | 9100 | Lance-impact splash frames | ## Animation Technique The two knights are drawn symmetrically: the player knight at column `x` and the opponent mirrored at column `28-x`. Leg animation is achieved by selecting between two sets of UDGs based on `x/2=INT(x/2)` (i.e. even/odd frame), giving a two-frame gallop cycle. The variable `x` starts at 26 and decrements each pass; collision is checked at `x=16` (line 170). ## Combat Resolution At the collision point (line 200), hit probabilities are computed for each side: - `ad = le + INT(RND*6) - ar - (ar=2) - INT(RND*6)` — player hit on enemy: enemy lance rating minus player armour, with randomness. `(ar=2)` evaluates to −1 (boolean) giving plate-mail a bonus. - `ed = la + INT(RND*4) - er - (er=2) - INT(RND*4)` — enemy hit on player: similar formula using `la` (player lance) and `er` (enemy armour). - If both `ad>0` and `ed>0`, the larger value determines the dominant hit (line 220). Close combat (lines 1100–1430) uses a similar scheme: player presses 1–4 to choose attack level; damage is applied if `VAL a$ + wa + RND*7 + 1 > ez + es + er - 1 + (we=1)`, weighted by weapon type (`wa`, `we`), shield (`sh`), and armour ratings. ## Key BASIC Idioms - **Boolean arithmetic**: `(ar=2)`, `(we=1)`, `(a$="y")` etc. return −1/0 and are used directly in arithmetic to apply conditional bonuses/penalties without `IF` branches. - **`PAUSE 0` + `INKEY$`**: Used at line 8000 to wait for Enter before the joust begins. - **`VAL a$`**: Converts the single-character menu key press directly to a numeric weapon/armour index. - **`RESTORE NNN` mid-program**: Allows selective re-reading of DATA blocks to swap UDG definitions without storing them in arrays. - **`CHR$ 163+g` / `CHR$ (143+f)+g`**: Computes UDG base addresses inline within the POKE loop. ## Castle Drawing Lines 8010–8060 draw a side-on jousting fence using `PLOT`/`DRAW` with the subroutine at 8500 rendering a repeating crenellation pattern. An arc for the gate (`DRAW 20,0,-PI`) and loops (`FOR f=15 TO 230 STEP 70`) complete the castle before gameplay begins. ## Source Code ``` 1 PRINT "From ZX COMPUTING": PAUSE 300 10 PAPER 4: BORDER 4: CLS : RESTORE : GO SUB 7000 100 INK ec: IF eh=1 THEN PRINT AT y-1,x-1;"_\u\s " 110 PRINT AT y,x;"\a\b\c ": IF x/2=INT (x/2) THEN PRINT AT y+1,x;"\d\e\f " 120 IF x/2<>INT (x/2) THEN PRINT AT y+1,x;"\g\h\i " 130 INK ac: IF ah=1 THEN PRINT AT y-1,29-x;" \t\u_" 140 PRINT AT y,28-x;" \l\k\j": IF x/2=INT (x/2) THEN PRINT AT y+1,28-x;" \o\n\m" 150 IF x/2<>INT (x/2) THEN PRINT AT y+1,28-x;" \r\q\p" 160 LET x=x-1: BEEP .003,10: PAUSE 2: BEEP .003,5: PAUSE 3: BEEP .003,0: PAUSE 5 170 IF x=16 AND ec=7 THEN GO TO 200 180 IF x<2 THEN GO TO 800 190 GO TO 100 200 LET ad=le+INT (RND*6)-ar-(ar=2)-INT (RND*6): LET ed=la+INT (RND*4)-er-(er=2)-INT (RND*4) 210 IF ad<=0 AND ed<=0 THEN GO TO 100 220 IF ad>0 AND ed>0 THEN GO TO 500+100*(ad>ed) 230 IF ad>0 THEN GO TO 600 240 GO TO 500 500 PRINT AT y-1,x-4;" \t/\\": BEEP .1,50: BEEP .1,30 510 PRINT AT y-1,x-4;" ": BEEP .1,20: BEEP .1,10 520 RESTORE 9100: FOR f=0 TO 1: FOR g=0 TO 7: READ a: POKE USR CHR$ 163+g,a: NEXT g: PRINT AT y+1,x-6+f;CHR$ 163;: NEXT f 530 PRINT " ";AT y,x+3;" ";AT y,28-x;" " 540 LET x=x-1: LET ex=x+9: LET y=y-1: LET ah=0: LET em=em-INT (RND*6)-1: LET se=se-8: GO TO 100 600 PRINT AT y-1,x;"/\\\s": BEEP .1,50: BEEP .1,30 610 PRINT AT y-1,x;" ": BEEP .1,50: BEEP .1,30 620 INK 7: RESTORE 9100: FOR f=0 TO 1: FOR g=0 TO 7: READ a: POKE USR CHR$ 162+g,a: NEXT g: PRINT AT y+1,x+4+f;CHR$ 162;: NEXT f 630 PRINT AT y+1,x-4;" ";AT y,x+3;" ";AT y,x-28;" " 640 LET x=x-1: LET ex=x+9: LET y=y-1: LET eh=0: LET am=am-INT (RND*4): LET sa=sa-5: GO TO 100 800 IF eh=1 AND ah=1 THEN GO TO 900 810 LET x=20: LET ex=10: LET y=y+1 820 IF eh=1 THEN LET x=5 830 IF ah=1 THEN LET ex=25 840 GO TO 1000 900 PRINT AT y-1,x;" ";AT y-1,28-x;" " 910 LET x=26: LET y=10: LET dc=ac: LET ac=ec: LET ec=dc: GO TO 100 1000 PRINT AT y-1,0;" ";TAB 31;" "; INK 7;AT y,0;" \l\k\j"; INK 0;TAB 28;" \a\b\c"; INK 7;AT y+1,0;" \o\n\m"; INK 0;AT y+1,28;" \g\h\i" 1010 FOR f=1 TO 2: PRINT AT y-f,0;" ";AT y-f,27;" ": NEXT f 1020 RESTORE 9060: FOR f=1 TO 2: FOR g=0 TO 7: READ a: POKE USR CHR$ (143+f)+g,a: NEXT g: NEXT f 1030 RESTORE 9100: FOR f=3 TO 12: FOR g=0 TO 7: READ a: POKE USR CHR$ (143+f)+g,a: NEXT g: NEXT f 1040 PRINT AT y+1,5;" " 1100 PRINT INK 0;AT y,ex;v$;"\a ";AT y+1,ex;" \e "; INK 7;AT y,x-1;" \b";w$;AT y+1,x-1;" \f " 1110 IF ex>x+2 THEN PRINT AT y,ex-1;" ";AT y,x+3;" " 1120 LET x=x+(INKEY$="8")-(INKEY$="5")+(x<6)-(x>25): LET x=x-(x>ex-2) 1130 LET ex=ex+SGN (-(ex>x+1 AND RND<.5)+(ex<5)-(ex>25)+(RND<.3)+(se<3 AND ex<25)): IF ex-x>2 THEN GO TO 1400 1200 LET a$=INKEY$: IF a$<"1" OR a$>"4" THEN LET a$="0" 1210 LET ez=INT (RND*4)+1: IF seez+es+er-1+(we=1) THEN LET em=em-1 1260 IF em<1 THEN GO TO 4500 1300 BEEP .03,45: LET se=se-ez 1305 IF se<1 THEN GO TO 4500 1310 IF ez+we+INT (RND*3)>VAL a$+sh+ar+(wa=1) THEN LET am=am-1 1320 IF am<1 THEN GO TO 4000 1330 IF sa>am THEN LET sa=am 1340 IF se>em THEN LET se=em 1400 PRINT AT 20,0; INK 7;sa;" ";AT 20,20; INK 0;se;" " 1405 PRINT AT 21,0; INK 7;am;" ";AT 21,20; INK 0;;em;" ": IF ex-x<3 THEN GO TO 1100 1410 FOR f=1 TO 2: IF sa"2" THEN GO TO 7200 7210 BEEP .5,0: LET ar=VAL a$: LET cash=cash-30-10*ar 7220 PRINT AT 21,0;"What lance do you want? ": LET a$=INKEY$: IF a$<"1" OR a$>"3" THEN GO TO 7220 7230 BEEP .5,0: LET la=VAL a$: LET cash=cash-10*la 7240 PRINT AT 21,0;"What other weapon do you buy?": LET a$=INKEY$: IF a$<"1" OR a$>"3" THEN GO TO 7240 7250 BEEP .5,0: LET wa=VAL a$: LET w$=CHR$ (152+wa): IF cash-20-10*(wa=3)<0 THEN GO TO 7240 7260 LET cash=cash-10-10*(wa=3): IF cash<20 THEN GO TO 7300 7270 PRINT AT 21,0;"Do you buy a shield? (Y/N) ": LET a$=INKEY$: IF a$<>"y" AND a$<>"n" THEN GO TO 7270 7280 BEEP .5,0: LET cash=-20*(a$="y"): LET sh=(a$="y") 7320 LET sa=25: LET se=20: LET am=25: LET em=20 7360 CLS : PRINT ''"your opponent chooses:-"'' 7370 GO TO 7400+INT (RND*2)*50 7400 PRINT "defence: medium armour."''"attack:-heavy lance and a mace." 7410 LET er=2: LET es=0: LET we=3: LET le=3: LET v$="\i": GO TO 8000 7450 PRINT "Defense:-Heavy armour and shield"''"Attack:-medium lance and sword." 7460 LET er=2: LET es=1: LET we=1: LET le=2: LET v$="\g" 8000 PRINT ''"(Press enter to start)": PAUSE 0: CLS 8010 PLOT 0,120: DRAW 250,0: PLOT 0,120: DRAW 0,30: GO SUB 8500 8020 DRAW 0,-20: GO SUB 8500: DRAW 0,30: GO SUB 8500 8030 DRAW 0,-10: GO SUB 8500: DRAW 0,10: GO SUB 8500 8040 DRAW 0,-30: GO SUB 8500: DRAW 0,20: GO SUB 8500: DRAW 0,-30 8050 PLOT 115,120: DRAW 0,10: DRAW 20,0,-PI: DRAW 0,-10 8060 FOR f=15 TO 230 STEP 70: PLOT f,130: DRAW 5,0: DRAW 0,7: DRAW -5,0,PI: DRAW 0,-7: NEXT f: GO TO 9140 8500 FOR f=1 TO 3: DRAW 0,5: DRAW 5,0: DRAW 0,-5: DRAW 5,0: NEXT f: DRAW 0,5: DRAW 5,0: DRAW 0,-5: RETURN 9000 DATA 1,10,15,23,31,59,51,33,236,61,191,255,255,255,255,255,0,128,224,240,248,244,243,224 9010 DATA 3,6,8,8,4,3,0,0,255,227,128,0,0,0,0,0,192,192,112,56,8,4,2,6 9020 DATA 1,1,0,1,3,2,6,0,254,248,192,128,1,2,2,0,224,192,64,128,0,0,0,0 9030 DATA 128,80,240,232,248,220,204,132,55,188,253,255,255,255,255,255 9040 DATA 0,1,7,15,31,47,207,7,128,128,0,128,192,64,96,0,127,31,3,1,128,64,64,0,7,3,2,1,0,0,0,0 9050 DATA 192,96,16,16,32,192,0,0,255,199,1,0,0,0,0,0,3,3,14,28,16,32,64,96 9060 DATA 120,248,112,56,40,246,214,116,30,31,14,28,20,111,107,48,0,0,0,0,0,0,255,255 9100 DATA 0,0,32,63,0,71,120,0,3,4,9,251,255,248,8,240 9110 DATA 60,60,60,60,54,34,34,102,60,60,60,60,108,68,68,54 9120 DATA 0,64,32,16,10,4,10,3,16,24,60,24,16,8,4,3,0,0,48,112,72,8,4,3 9130 DATA 0,2,4,8,80,32,80,8,24,60,24,16,32,64,192,192,0,0,12,14,18,16,32,192 9140 RETURN 9998 SAVE "knight" LINE 1 ```