REM
REM --- "Kingdom of the Lyre"
REM --- Simple Role Playing Game with Procedural Generation
REM --- Written for PROCJAM 2019 - https://itch.io/jam/procjam
REM
REM --- Also written as a test for:
REM --- Tiny BASIC Interpreter and Compiler Project
REM --- http://tinybasic.cyningstan.org.uk/
REM
REM --- Variables
REM --- A - distance between two points
REM --- B - bearing of one point from another
REM --- C - short term counter
REM --- D - direction of movement chosen
REM --- 2 = south
REM --- 4 = west
REM --- 6 = east
REM --- 8 = north
REM --- E - exits available from a location. A combination of:
REM --- 1 = east
REM --- 2 = south
REM --- 4 = west
REM --- 8 = north
REM --- F - fight seed for encounters
REM --- G - game turn seed
REM --- H - player health
REM --- I - potion carried
REM --- 0 - none
REM --- 1 - health
REM --- 2 - speed
REM --- 3 - invisibility
REM --- 4 - seeing
REM --- J - potion in effect
REM --- K - turns left for potion effect
REM --- L - the lyre location (=O if carried)
REM --- M - number of monsters encountered
REM --- N - new player position
REM --- O - original village position
REM --- P - player position
REM --- Q - flag for quitting the game
REM --- R - random 3-way junction
REM --- S - game seed
REM --- T - terrain of a location
REM --- U - position of principal enemy
REM --- V - special encounter type
REM --- 0 = standard chance of random encounter
REM --- 1 = found a village
REM --- 2 = found the lyre
REM --- 3 = found the enemy (game lost)
REM --- 4 = returned the lyre (game found)
REM --- 5 = the player has fled!
REM --- X - location parameter for various subroutines
REM --- Y - temporary location variable for various subroutines
REM --- Z - the random number seed and result
REM --- Control routine
GOSUB 100
001 GOSUB 110
IF Q=0 THEN GOTO 001
GOSUB 120
END
REM --- Initialisation subroutine
100 LET D=0
LET H=20
LET I=1
LET J=0
LET K=0
LET Q=0
REM --- Set the seed for the game
PRINT "Welcome to the Kingdom of the Lyre"
PRINT ""
PRINT "Long, long ago your people suffered an invasion of the forces"
PRINT "of the underworld. Being a musical people, they made a"
PRINT "magical lyre and banished the evil forces using the power of"
PRINT "music. Somehow, in the centuries since, the whereabouts of"
PRINT "the lyre was forgotten."
PRINT ""
PRINT "Now, the forces of the underworld are returning. The lyre must"
PRINT "be found, and brought back to the village where the elders"
PRINT "can use its power to deal with the underworld armies once and"
PRINT "for all. Are you the hero that can achieve this?"
PRINT ""
PRINT "Enter a 4-digit number."
INPUT S
PRINT ""
IF S<0 THEN LET S=0
IF S>9999 THEN LET S=9999
IF S>6547 THEN LET S=S-S/6547*6547
LET Z=S
REM --- Initialise other seeds
GOSUB 990
LET F=Z
GOSUB 990
LET G=Z
REM --- Initialise player position
GOSUB 990
LET P=Z-Z/6400*6400
LET O=P
REM --- Initialise lyre position
101 GOSUB 990
LET L=Z-Z/6400*6400
LET X=L
GOSUB 600
IF A<30 THEN GOTO 101
REM --- Initialise enemy position
102 GOSUB 990
LET U=Z-Z/6400*6400
LET X=U
GOSUB 600
IF A<30 THEN GOTO 102
RETURN
REM --- Subroutine to process a turn
REM --- Changes: Q - Non-zero to quit
110 GOSUB 200
GOSUB 210+10*V
IF Q=0 THEN GOSUB 260
IF Q=0 THEN GOSUB 270
RETURN
REM --- End Game subroutine
120 PRINT ""
PRINT "Your adventure is over."
REM --- Where were the forces of the underworld?
IF P=U THEN GOTO 121
LET X=U
GOSUB 600
PRINT "The forces of the underworld were ",A," leagues"
GOSUB 730
REM --- Where was the lyre?
121 IF L=O THEN GOTO 122
LET X=L
GOSUB 600
PRINT "The lyre was ",A," leagues"
GOSUB 730
REM --- Where was the village?
122 IF P=O THEN GOTO 123
LET X=O
GOSUB 600
PRINT "You were ",A," leagues from your home"
GOSUB 730
123 RETURN
REM --- Initialise and display player location
200 LET X=P
GOSUB 300
GOSUB 310
GOSUB 320
GOSUB 330
GOSUB 340
RETURN
REM --- Deal with a random encounter
210 LET Z=F
LET C=0
211 GOSUB 990
LET C=C+1
IF C<=P THEN GOTO 211
IF Z-Z/8*8>1 THEN RETURN
REM --- Monster encountered
GOSUB 400
IF J=3 THEN GOTO 213
LET Z=G
REM --- Combat loop
212 PRINT "Health: ",H,", enemy strength: ",M
PRINT "Menu:"
PRINT " 0:Quit"
PRINT " 1:Fight"
PRINT " 2:Flee"
INPUT C
IF C<0 THEN GOTO 212
IF C>2 THEN GOTO 212
IF C=0 THEN LET Q=1
IF C=2 THEN GOTO 214
REM --- Do battle!
GOSUB 990
LET G=Z
IF Z/100-Z/200*2=1 THEN GOSUB 410
IF Z/100-Z/200*2=0 THEN GOSUB 420
IF M=0 THEN GOSUB 430
IF H=0 THEN GOSUB 440
IF Q=0 THEN IF H>0 THEN IF M>0 THEN IF C<>2 THEN GOTO 212
RETURN
REM --- The player is invisible - sneak past the monsters
213 PRINT "You are invisible, so you sneak past the enemy."
RETURN
REM --- The cowardly player flees the monsters
214 PRINT "You flee back whence you came!"
LET D=10-D
IF D=2 THEN LET P=P-80
IF D=4 THEN LET P=P-1
IF D=6 THEN LET P=P+1
IF D=8 THEN LET P=P+80
LET X=P
GOSUB 300
GOSUB 310
RETURN
REM --- Subroutine to deal with a village encounter
220 PRINT "There is a village here."
REM --- Do the people tell us about the lyre?
IF L=O THEN GOTO 221
IF I=4 THEN GOTO 221
LET X=L
GOSUB 600
IF A<=8 THEN GOTO 221
GOSUB 700
GOSUB 720
REM --- Do they give us a potion?
221 IF I<>0 THEN RETURN
LET Z=G
GOSUB 990
LET G=Z
LET I=1+Z-Z/4*4
PRINT "Well-wishers give you a"
LET X=I
GOSUB 710
RETURN
REM --- Subroutine to deal with finding the lyre
230 PRINT "You have found the object of your quest!"
PRINT "The golden lyre sits on a silken cushion,"
PRINT "A glow emanating from all around it."
PRINT "You pick it up, and its song ceases."
PRINT "Now you must take it home."
LET L=O
RETURN
REM --- Subroutine to deal with the forces of the underworld
240 PRINT "You fall into the clutches of the forces of the underworld!"
IF L=O THEN PRINT "Now they have the lyre to wreak what havoc they will."
IF L<>O THEN PRINT "Their defeat will be some other hero's task."
LET Q=2
RETURN
REM --- Subroutine to deal with returning the lyre
250 PRINT "As you approach your sleepy little village,"
PRINT "all your friends come to meet you."
PRINT "With your friends are the village elders,"
PRINT "who have the knowledge to use the lyre"
PRINT "to banish the forces of the underworld forever!"
LET Q=3
RETURN
REM --- Subroutine to deal with player actions
REM --- Changes: D - user input for direction
REM --- E - exits from location
REM --- N - new player position
REM --- P - player position
REM --- Q - quit flag
260 LET N=P
LET X=P
REM --- check if the underworld forces are near enough to hear
LET X=U
GOSUB 600
IF A<16 THEN GOSUB 740
IF A<16 THEN GOSUB 730
REM --- check if the lyre is near enough to hear
IF L=O THEN GOTO 261
LET X=L
GOSUB 600
IF A<8 THEN GOSUB 700
IF A<8 THEN GOSUB 720
GOTO 262
REM --- We're on the way back to the village
261 LET X=O
GOSUB 600
PRINT "Your home lies ",A," leagues"
GOSUB 730
REM --- Ask direction and calculate new position
262 GOSUB 350
INPUT D
IF D=0 THEN LET Q=1
IF D=1 THEN IF I<>0 THEN GOSUB 360
IF D=2 THEN IF E/2-E/4*2>0 THEN GOSUB 370
IF D=4 THEN IF E/4-E/8*2>0 THEN GOSUB 370
IF D=6 THEN IF E-E/2*2>0 THEN GOSUB 370
IF D=8 THEN IF E/8>0 THEN GOSUB 370
IF N=P THEN IF Q=0 THEN GOTO 262
LET P=N
RETURN
REM --- Subroutine to move the forces of the underworld
270 IF P=U THEN RETURN
IF J=2 THEN RETURN
REM --- See where the forces are in relation to the player
LET X=U
GOSUB 600
LET B=10-B
REM --- See if the forces can travel towards the player
GOSUB 310
IF B=2 THEN IF E/2-E/4*2>0 THEN GOTO 271
IF B=4 THEN IF E/4-E/8*2>0 THEN GOTO 271
IF B=6 THEN IF E-E/2*2>0 THEN GOTO 271
IF B=8 THEN IF E/8>0 THEN GOTO 271
IF A>2 THEN GOTO 271
REM --- If not, pick a random direction and see if they can go there
LET Z=G
GOSUB 990
LET G=Z
LET B=2*(1+Z-Z/4*4)
IF B=2 THEN IF E/2-E/4*2>0 THEN GOTO 271
IF B=4 THEN IF E/4-E/8*2>0 THEN GOTO 271
IF B=6 THEN IF E-E/2*2>0 THEN GOTO 271
IF B=8 THEN IF E/8>0 THEN GOTO 271
RETURN
271 IF B=2 THEN LET U=U-80
IF B=4 THEN LET U=U-1
IF B=6 THEN LET U=U+1
IF B=8 THEN LET U=U+80
RETURN
REM --- Get the terrain of a location
REM --- Inputs: X - origin location
REM --- Changes: C - counter
REM --- Y - latitude
REM --- Z - random number seed
REM --- Outputs: T - terrain at the current square
REM --- 0 = plain
REM --- 1 = forest
REM --- 2 = mountain
REM --- 3 = swamp
300 LET C=0
LET T=0
LET Z=4882
LET Y=X/80
LET X=X-80*Y
REM --- Get terrain for the general area and its surroundings
301 GOSUB 990
IF Y<72 THEN IF C=(X/8*8)+80*(Y/8*8+8) THEN LET T=T+256*(Z-Z/4*4)
IF X>7 THEN IF C=(X/8*8-8)+80*(Y/8*8) THEN LET T=T+64*(Z-Z/4*4)
IF Y>7 THEN IF C=(X/8*8)+80*(Y/8*8-8) THEN LET T=T+16*(Z-Z/4*4)
IF X<72 THEN IF C=(X/8*8+8)+80*(Y/8*8) THEN LET T=T+4*(Z-Z/4*4)
IF C=(X/8*8)+80*(Y/8*8) THEN LET T=T+(Z-Z/4*4)
LET C=C+1
IF C<=X+80*Y+8 THEN GOTO 301
REM --- Narrow it down for this specific square
GOSUB 990
IF Y>Y/8*8+4 THEN IF Z-Z/8*8X/8*8+4 THEN IF Z-Z/8*80 THEN IF C=X-1+80*Y THEN LET E=E+4*(R-R/2*2)
IF Y>0 THEN IF C=X+80*(Y-1) THEN LET E=E+2*(R/8)
IF X<79 THEN IF C=X+1+80*Y THEN LET E=E+(R-R/8*8)/4
LET C=C+1
IF C<=X+80*(Y+1) THEN IF C<=80*80-1 THEN GOTO 313
RETURN
REM --- Display the player's current location
REM --- Inputs: T - the current terrain
320 GOTO 321+T
321 PRINT "You are travelling a road on an open plain."
RETURN
322 PRINT "You are wandering along a forest path."
RETURN
323 PRINT "You are trekking through mountains."
RETURN
324 PRINT "You are navigating a safe route through a swamp."
RETURN
REM --- Display the player's inventory
REM --- Inputs: I - potion in hand
REM --- J - potion already drunk
REM --- K - turns left
330 IF I=0 THEN GOTO 331
PRINT "You are carrying"
LET X=I
GOSUB 710
REM --- display potion in effect
331 IF J=0 THEN RETURN
GOTO 331+J
REM --- Health potion
332 IF H<20 THEN PRINT "The potion you drank raises your health to ",H+1,"."
IF H=20 THEN PRINT "The potion you drank keeps you at full health."
GOTO 337
REM --- Speed potion
333 PRINT "The potion you drank allows you to run all day."
GOTO 337
REM --- Invisibility potion
334 PRINT "The potion you drank makes you invisible to monsters."
GOTO 337
REM --- Potion of Seeing
335 PRINT "The potion you drank reveals visions to you."
IF L=O THEN GOTO 336
LET X=L
GOSUB 600
PRINT " You see the lyre ",A," leagues"
GOSUB 730
GOTO 337
336 LET X=U
GOSUB 600
PRINT "You see the forces of the underworld ",A," leagues"
GOSUB 730
REM --- Show time left
337 PRINT " (",K," turns left)"
RETURN
REM --- Determine possible encounter types
340 LET V=0
IF P=L THEN IF P<>O THEN LET V=2
IF V=0 THEN IF P=U THEN LET V=3
IF V=0 THEN IF P=L THEN IF P=O THEN LET V=4
IF V=0 THEN IF P=O THEN LET V=1
IF V<>0 THEN RETURN
REM --- All predictable encounters eliminated - check villages
LET Z=4883
LET C=0
341 GOSUB 990
LET C=C+1
IF C<=P THEN GOTO 341
IF Z-Z/20*20=0 THEN LET V=1
RETURN
REM --- Subroutine to display available directions
REM --- Inputs: E - directions available, comprising:
REM --- 1 = east
REM --- 2 = south
REM --- 4 = west
REM --- 8 = north
350 PRINT "Menu:"
PRINT " 0:Quit"
IF I<>0 THEN PRINT " 1:Drink"
IF E/2-E/4*2>0 THEN PRINT " 2:South"
IF E/4-E/8*2>0 THEN PRINT " 4:West"
IF E-E/2*2>0 THEN PRINT " 6:East"
IF E/8>0 THEN PRINT " 8:North"
RETURN
REM --- Subroutine to drink a potion
REM --- Changes: I - potion in hand is removed
REM --- J - potion in effect is updated
REM --- K - potion duration is refreshed
360 PRINT "You drink"
LET X=I
GOSUB 710
LET J=I
LET K=10
LET I=0
RETURN
REM --- Subroutine to deal with player movement
REM --- Inputs: D - direction of movement
370 GOTO 370+D/2
371 LET N=P-80
PRINT "You travel south."
GOTO 375
372 LET N=P-1
PRINT "You travel west."
GOTO 375
373 LET N=P+1
PRINT "You travel east."
GOTO 375
374 LET N=P+80
PRINT "You travel north."
REM --- Player has moved; update things
375 PRINT ""
LET Z=G
GOSUB 990
LET G=Z
IF J=1 THEN IF H<20 THEN LET H=H+1
IF K>0 THEN LET K=K-1
IF K=0 THEN LET J=0
RETURN
REM --- Subroutine to generate a monster encounter
REM --- Inputs: T - the terrain
REM --- Changes: Z - random number seed
REM --- Outputs: M - the number/strength of the monster(s)
400 GOSUB 990
LET M=1+Z-Z/5*5
GOTO 401+T
401 IF M=1 THEN PRINT "There is a thief here."
IF M>1 THEN PRINT "There are ",M," thieves here."
RETURN
402 PRINT "You see ",M," wild boar emerge from the undergrowth."
RETURN
403 IF M=1 THEN PRINT "You encounter a goblin in the mountain pass."
IF M>1 THEN PRINT "You encounter ",M," goblins in the mountain pass."
RETURN
404 PRINT "You are stalked by a hungry crocodile."
RETURN
REM --- Subroutine process a monster hit on the player
REM --- Inputs: T - the terrain
REM --- Changes: H - player's reduced health
410 LET H=H-1
GOTO 411+T
411 PRINT "A thief hits you, reducing your health to ",H
RETURN
412 PRINT "A boar impales you, reducing your health to ",H
RETURN
413 PRINT "A goblin slashes at you, reducing your health to ",H
RETURN
414 PRINT "The crocodile snaps at you, reducing your health to ",H
RETURN
REM --- Subroutine process a player hit on a monster
REM --- Inputs: T - the terrain
REM --- Changes: M - the reduced number of monsters
420 LET M=M-1
GOTO 421+T
421 PRINT "You kill a thief, reducing their numbers to ",M
RETURN
422 PRINT "You kill a boar, reducing their numbers to ",M
RETURN
423 PRINT "You kill a goblin, reducing their numbers to ",M
RETURN
424 PRINT "You hit the crocodile, reducing its strength to ",M
RETURN
REM --- Subroutine to deal the the aftermath of combat victory
REM --- Inputs: H - health affects how grateful peasants are
REM --- L - location of the lyre
REM --- O - location of the home village
REM --- Changes: A - distance to the lyre is calculated
REM --- B - bearing to the lyre is calculated
REM --- F - encounter seed is changed
REM --- I - possible potion reward
REM --- X - parameter for finding lyre
REM --- Z - random number seed
430 PRINT "You have slain the enemy!"
LET Z=F
GOSUB 990
LET F=Z
REM --- Do grateful peasants give directions?
IF L=O THEN GOTO 431
LET X=L
GOSUB 600
IF A<=8 THEN GOTO 431
IF Z-Z/20*200 THEN RETURN
GOSUB 990
IF Z-Z/8*8>=4 THEN RETURN
LET I=Z-Z/8*8+1
PRINT "With the enemy dead, you notice"
LET X=I
GOSUB 710
RETURN
REM --- The player is dead!
REM --- Outputs: Q - quit flag
440 PRINT "The enemy has slain you!"
LET Q=2
RETURN
REM --- Generate a random 3-way junction
REM --- Changes: Z - random number seed
REM --- Outputs: R - directional exits for a 3-way junction
REM --- 07 - west, south, east
REM --- 11 - north, south, east
REM --- 13 - north, west, east
REM --- 14 - north, west, south
500 GOSUB 990
LET R=Z-Z/4*4
LET R=15-(R+1+R/2+R/3*3)
RETURN
REM --- Subroutine to ascertain direction and distance
REM --- Inputs: P - origin (player location)
REM --- X - destination
REM --- Changes: C - temporary scratchpad
REM --- Outputs: A - distance to destination
REM --- B - bearing of destination
600 LET A=(X-X/80*80)-(P-P/80*80)
IF A<0 THEN LET A=-A
LET C=X/80-P/80
IF C<0 THEN LET C=-C
IF A>=C THEN LET A=A+C/2
IF A(P/80) THEN LET B=8
IF (X/80)<(P/80) THEN LET B=2
IF X-X/80*80>P-P/80*80 THEN IF (X-X/80*80)-(P-P/80*80)>C THEN LET B=6
IF X-X/80*80C THEN LET B=4
RETURN
REM --- Subroutine to print vague distance to the lyre
REM --- Inputs: A - distance to the lyre
REM --- B - bearing to the lyre
700 IF A>1 THEN GOTO 701
PRINT "An overpowering and beautiful melody can be heard"
RETURN
701 IF A>4 THEN GOTO 702
PRINT "You hear sweet music coming"
RETURN
702 IF A>8 THEN GOTO 703
PRINT "You catch strains of magical music"
RETURN
703 PRINT "Peasants bring tales of a lyre"
RETURN
REM --- Print the name of a potion
REM --- Inputs: X - potion type
710 GOTO 710+X
711 PRINT " a potion of health"
RETURN
712 PRINT " a potion of speed"
RETURN
713 PRINT " a potion of invisibility"
RETURN
714 PRINT " a potion of seeing"
RETURN
REM --- Print a single "from" direction
REM --- Inputs: B - the direction on the numeric keypad
720 GOTO 720+B/2
721 PRINT " from the south."
RETURN
722 PRINT " from the west."
RETURN
723 PRINT " from the east."
RETURN
724 PRINT " from the north."
RETURN
REM --- Print a single "from" direction
REM --- Inputs: B - the direction on the numeric keypad
730 GOTO 730+B/2
731 PRINT " to the south."
RETURN
732 PRINT " to the west."
RETURN
733 PRINT " to the east."
RETURN
734 PRINT " to the north."
RETURN
REM --- Subroutine to print vague distance to the lyre
REM --- Inputs: A - distance to the lyre
REM --- B - bearing to the lyre
740 IF A>1 THEN GOTO 741
PRINT "You see black banners flying"
RETURN
741 IF A>4 THEN GOTO 742
PRINT "You hear the sound of drums and marching"
RETURN
742 IF A>8 THEN GOTO 743
PRINT "Faint notes of battle horns can be heard"
RETURN
743 PRINT "Fleeing peasants tell of a large army"
RETURN
REM --- Random Number Generator Subroutine
REM --- Inputs: Z - random number seed
REM --- Outputs: Z - random number generated and the new seed
990 LET Z=5*Z+35
LET Z=Z-Z/6547*6547
RETURN