Tiny BASIC

Interpreter and Compiler Project

Kingdom of the Lyre: Combat

Thursday, 14th November 2019

In this series, Damian blogs about how the game works.

Since it's a simple game, combat in Kingdom of the Lyre is as simple as I could make it. You have one stat, health, stored in the variable H. Monsters from random encounters have their strength or number stored in the variable M. Each combat round, one or other stat gets reduced by one, and combat finishes when one side is dead or the player flees. The main routine is here:

    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 " 0:quit, 1:fight or 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
    GOSUB 300
    GOSUB 310
    RETURN

We've already dealt with the initial encounter in the previous blog post. After generating and displaying the monsters, combat will be skipped entirely if J (the variable for potion Just drunk) is 3 (invisibility). Otherwise, initialise the random number generator from a variable seed, G.

If the F seed were used for combat, then each fight with a particular random enemy would go the same way. If a fight goes badly and you flee, you don't want it to go exactly the same way when you return. So the G seed is used instead, and this is changed every time the player attempts to hit an enemy.

The combat round itself chooses randomly between the routines at 410 and 420, which I reproduce here. 410 is what happens if a monster hits the player, 420 if the player hits the monster.

    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

Their complexity comes from the need for flavour text and the lack of strings or arrays: in Tiny BASIC you can't have a line like

    PRINT "The ",M$," hits you."

Because of this limitation, it's actually easier to make the monsters behave differently from each other. Had I had more time I'd definitely have done this. Subroutine 430 deals with a player victory over the enemy:

    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*20<H THEN GOTO 431
    GOSUB 700
    GOSUB 720
    RETURN
    REM Is there a treasure?
431 IF I<>0 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

Notice the change to the F seed discussed earlier. The second part of the routine decides whether local peasantry, grateful for your policing efforts, give you a clue to the whereabouts of the lyre. The more damage you've taken, the more grateful they are.

The final part of the routine decides whether to give you a potion reward, assuming you're not already carrying one (I, for potion in Inventory). The subroutine at 710 just displays the name of the potion. This is another area where I could have varied the gameplay for different biomes. If potions of far-seeing were more common in the mountains, it would give the player a reason to seek out the mountains, for instance.

The subroutine for player death is trivial:

    REM --- The player is dead!
    REM --- Outputs: Q - quit flag
440 PRINT "The enemy has slain you!"
    LET Q=2
    RETURN

The other types of encounter are quite simple, so if you want to see them just look at subroutines 220-250 the full source code. In tomorrow's post I'll discuss how the players' actions are dealt with.

Comments

New Comment

Yes No