Knight Fight

This file is part of and Miscellaneous Programs. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

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 rangeDATA startPurpose
A–I (\a–\i)9000Right-facing player knight (3×3 sprite, two leg positions)
J–R (\j–\r)9030Left-facing opponent knight (3×3 sprite, two leg positions)
S–U (\s–\u)9050Lance / shield UDGs
P–Q (reloaded)9060Dismount/fall frames
Various (reloaded)9100Lance-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.

Content

Related Products

Related Articles

Related Content

Image Gallery

Knight Fight

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 se<ez THEN LET ez=se-1
 1220 IF se<3 THEN LET ez=0
 1230 IF a$="0" THEN GO TO 1300
 1240 LET sa=sa-VAL a$: IF sa<1 THEN GO TO 4000
 1250 IF VAL a$+wa+(RND*7)+1>ez+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<am THEN LET sa=sa+1: NEXT f
 1420 IF se<em THEN LET se=se+1
 1430 GO TO 1100
 4000 PRINT INK 0;AT y,x;"   ";v$;"\a "; INK 7;AT y+1,x;" \c\d"; INK 0;" \e "
 4010 PRINT AT 20,0;"you die.": GO TO 5000
 4500 PRINT INK 7;AT y,x;"  \b";w$;"   ";AT y+1,x;"  \f "; INK 0;"\c\d"
 4510 PRINT AT 20,20;"he dies": GO TO 5000
 5000 INPUT "Play again? (Y/N)";b$
 5005 IF b$="y" THEN GO TO 10
 5010 STOP 
 7000 PRINT "Knight Fight"''
 7050 RANDOMIZE : LET ah=1: LET eh=1: LET x=26: LET y=10
 7060 LET cash=100: LET sh=0: LET ac=0: LET ec=7
 7100 PRINT '"(1) chain-mail costs 40 coins,"'"(2) plate-mail 50."
 7110 PRINT '"(1) light lances cost 10"'"(2) medium lances 20"'"(3)heavy lances 30."
 7120 PRINT '"(1)swords cost 20"'"(2) axes 20"'"(3) maces 30."'"(4) Shields 20."
 7130 FOR f=1 TO 21: FOR g=0 TO 7: READ a: POKE USR CHR$ (f+143)+g,a: NEXT g: NEXT f
 7200 PRINT AT 21,0;"What armour do you want?": LET a$=INKEY$: IF a$<"1" OR a$>"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

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top