top of page
Search
Writer's pictureTom Grove

The Innkeeper

Updated: Jun 29, 2020

In the previous post, we looked at a small fragment of code. In this post, we look at the Innkeeper program, which accounts for roughly half of the engine code. The code is included in its entirety and I will go through it in the order that it appears in the file.

We kick off with the copyright note and few two letter variable declarations. The most important variable here is KA - this a pointer to the binary game data. This is followed in memory by KB, which holds the character data. This is stored in a region of memory below BASIC and will not be erased when a new program is loaded.

73  REM  TEMPLE OF APSHAI INNKEEPER - APPLE II APPLESOFT COPYRIGHT 1979 AUTOMATED SIMULATIONS, REV1(DISK)
74  DIM NA$(5),W(5),P(5),NC$(6),CH(6),SD(2),SP(2),SW(2),NW$(6),WW(5),WP(5),WD(5),WR(5),DS(1,1),DW(5,1),R$(6),RR(6),NS$(2)
75 KA = 4194:Q = 60:KB = KA + 2251
76 J8 = 248:J0 = 59:J7 = 249:JQ = 1

Being a RPG, we now have some tables. Starting with the armor that you can purchase and the six core stats.

77  DATA "NONE",0,0,"LEATHER",150,30,"RINGMAIL",350,100,"CHAIN MAIL",500,150,"PARTIAL PLATE",750,250,"FULL PLATE",1000,1000,"INTELLIGENCE","INTUITION","EGO","STRENGTH","CONSTITUTION","DEXTERITY"
78  FOR I = 0 TO 5: READ NA$(I),W(I),P(I):W(I) =  INT (W(I) / 16 + .5): NEXT I
79 W(0) = 0: FOR I = 1 TO 6: READ NC$(I): NEXT I

The armor table is as follows, with the weight rather oddly being expressed in ounces and converted to pounds on read. Weight is important in ToA, since the game has an encumberance system. The protection afforded by armor is implicit on its order in this table - i.e. None has an AC of 0, Full plate an AC of 5. The types of armor would be familiar to players of D&D - which is helpful, as the game provides no information about the mechanical effect of different armor types.

Weight (Oz) Price (Sp) AC

None 0 0 0

Leather 150 30 1

Ring 350 100 2

Chain 500 150 3

Partial 750 250 4

Full 1000 1000 5


The six characteristics are:


Intelligence

Intuition

Ego

Strength

Constitution

Dexterity


The manual suggests that if converting from "another system" ( by which they mean D&D - TSR, D&D's publishers - were extremely protective of their trademark in this period, so the game is never mentioned by name ), one should interpret "Intuition" as ( D&D's) "Wisdom" and "Ego" as "Charisma". However, the upper three stats play a fairly minor role.

These tables are followed by Weapons

80  DATA  "DAGGER",1,5,5,3,7,12,"SHORTSWORD",2,14,6,8,9,12,"BROADSWORD",3,18,7,10,9,13,"HAND-AND-A-HALF SWORD",6,35,8,16,9,14,"GREAT SWORD",9,70,10,15,7,15,"MAGIC SWORD"
85  FOR I = 1 TO 5: READ NW$(I),WW(I),WP(I),WD(I),WR(I): FOR J = 0 TO 1: READ DW(I,J): NEXT J: NEXT I: READ NW$(6)

Weight (lbs) Price Damage Str Req Dex Low Dex High

Dagger 1 5 5 3 7 12

Short 2 14 6 8 9 12

Broad 3 18 7 10 9 13

HnHalf 6 35 8 16 9 14

Great 9 70 10 15 7 15

Magic


Again, weapons have a weight ( now in lbs ), a price, a damage score, a minimum strength requirement and a dexterity range. Below "Dex Low", an attack penalty is incurred, above "Dex High" a bonus is received. Magic swords are special and don't have any explicit stats. The "Great Sword", while doing the most damage, is also the only two handed weapon, and so incompatible with wielding a shield:

90  DATA  6,3,10,8,15,12,5,15,6,17
95  FOR I = 1 TO 2: READ SW(I),SD(I),SP(I): FOR J = 0 TO 1: READ DS(I - 1,J): NEXT J: NEXT I
99 LS = 0:SM = 0

Weight (lbs) AC Price Dex Low Dex High

Small 6 3 10 8 15

Large 12 5 15 6 17


Like weapons, these have a dexterity range. The Armor class of the shield indicates how much protection it affords.


These items are purchased from the Innkeeper. This involves haggling and the following table presents the Innkeeper's responses. Each has a weight to manage the probability that it is emitted, which yields a bit of variety and improves immersion.

100  DATA "I'D NOT PART WITH THESE FINE GOODS FOR  THAT PITTANCE!  MAYHAP FOR",5,"NOT SO CHEAP, MY FRIEND! BUT FOR THEE,  JUST",10,"BLACKHEART! THOU TAKEST THE FOOD FROM   MY CHILDREN'S MOUTHS! I'LL NOT SETTLE   FOR LESS THAN",5
110  DATA "WELL, LIFE IS SHORT AND THY ARSE LONG!  WHAT SAY THEE TO",2,"HMM..BUT SUCH FINE WORKMANSHIP. I COULD NOT PART WITH THIS FOR LESS THAN",10,"A POX ON THEE! BUT I'D TAKE",3
130 RN = 6:RT = 0: FOR I = 1 TO RN: READ R$(I),RR(I):RT = RT + RR(I): NEXT I

The shield names themselves are read in next, before jumping to the main body of the program.

140  DATA "NONE","SMALL","LARGE": FOR I = 0 TO 2: READ NS$(I): NEXT I 800  GOTO 1000

Line 1000 checks the contents of an address 12 below the character record. This stores the

magic number 123 if the innkeeper (INN) had been loaded by the Dunjonmaster.

If this is not the case, then a title screen is displayed. HOME, VTAB and HTAB are cursor positioning commands.









900  HOME : VTAB (8): HTAB (14): PRINT "DUNJONQUEST": VTAB (10): HTAB (10): PRINT "THE TEMPLE OF APSHAI": VTAB (16): HTAB (13): PRINT "COPYRIGHT 1979": VTAB (18): HTAB (9): PRINT "AUTOMATED  SIMULATIONS"
910  POKE KB,0
920  VTAB (23): HTAB (9): PRINT "HIT ANY KEY TO CONTINUE"
930 I =  RND (5) * 5: IF  PEEK ( - 16384) < 127 THEN 930
932  POKE  - 16368,0: RETURN 
990  RETURN 
1000  IF  PEEK (KB - 12) <  > 123 THEN  GOSUB 900

On pressing a key, you find yourself conversing with the Innkeeper. Based on the value of the magic number, if we are coming from the dungeon, we are asked if we want to see our treasure inventory. The reason we need to see it, is so that we can manually, on a piece of paper, add up how much money we have using the master the treasure key in the manual. ToA very much operates on an honour system. After all, you'd only be cheating yourself. We also initialise the weight carried to 5 lbs ( clothing ,etc. we assume)

1001  HOME :WC = 5: PRINT "THUS QUOTH THE INNKEEPER:"
1002  FOR I = 1 TO 1500: NEXT I
1003  IF  PEEK (KB - 12) = 123 THEN  INPUT "WOULDST THOU KNOW WHAT TREASURES THOU   HAST? ";A$: IF  LEFT$ (A$,1) = "Y" THEN  GOSUB 9920
1004  GOSUB 9940: IF  PEEK (KB - 12) = 123 THEN  GOSUB 4500
1005  IF  PEEK (KB - 12) = 123 THEN  PRINT "I TRUST THINE WAS A PLEASANT SOJURN     WITHIN THE TEMPLE.": PRINT "ART BUT PASSING THROUGH THE INN AND WISHTO RETURN";: INPUT A$: IF  LEFT$ (A$,1) = "Y" THEN  GOSUB 9900: INPUT "HOW MANY SILVER PIECES HAST THOU? ";MO:OM = MO
1006  IF  PEEK (KB - 12) = 123 THEN  IF  LEFT$ (A$,1) = "Y" THEN  GOSUB 2600: GOTO 1205

If we didn't come from the dungeon, we fall through to here. This is the game's rather roundabout way of asking if we want to generate a character or restore an existing one.

1008  POKE KB - 12,0
1009  HOME : POKE KA,0
1010  PRINT "HAIL AND WELL MET! SHALL I FIND THEE A  GOODLY CHARACTER, OR HAST THOU BROUGHT  ONE WITH THEE? PRITHEE, SAY YEA IF I    SHOULD";: INPUT ". ";C$: IF  LEFT$ (C$,1) = "Y" THEN  GOSUB 2200
1011  IF  LEFT$ (C$,1) = "Y" GOTO 1200

If we don't want to generate a character, we can load one from disk

1020  INPUT "HAST THOU A CHARACTER ON DISK?";C$: IF  LEFT$ (C$,1) <  > "Y" THEN  GOSUB 2400: GOTO 1200
1025 D$ =  CHR$ (4)
1030  INPUT "WHAT BE THE FELLOW'S NAME?";C$: PRINT "READING IN CHARACTERISTICS  FOR "C$
1038  PRINT D$;"OPEN "C$
1040  PRINT D$;"READ "C$: FOR I = 61 TO 96: INPUT J: POKE KA - I,J: NEXT I: INPUT J: PRINT "LAST ON LEVEL "J
1050  FOR I = 0 TO 37: INPUT J: POKE KB - 12 + I,J: NEXT I: PRINT D$;"CLOSE"
1060  POKE KB - 12,123: GOTO 1003

depending on exactly which options we chose, we end up at either 1200 or 1205. We end up at 1200 if we rolled a new character or entered one manually. Otherwise we find ourselves at 1205. The subroutines off of this are related to purchasing various pieces of equipment:


2600 weapons

2800 shields

2000 armor

3000 bow and arrows

3200 healing salves


Calls to these are gated by the character having enough money ( MO ).


It is also here that the players base "ToHit" (PB) score is computed. This is


11 - WeaponPoints(WP) - Level/2


Weapon points are computed from dexterity and "Level" is the character's advancement level. In combat, a D20 is rolled against this value ( adjusted by some modifiers ) and if the player rolls higher, then a hit is scored. This is clearly inspired by this 1st edition D&D attack matrix, although armor works slightly differently in the dunjonquest games.



PA is similar but from the monster's point of view.










1200 OM = MO: INPUT "CHARACTER NAME? ";NM$: IF MO > 0 THEN  GOSUB 2600
1205 IF MO > 0 THEN  GOSUB 2800
1206  IF PS = 0 THEN WP = WP + SP:SP = 0
1207 PB = PB - WP -  INT ( PEEK (KB + 15) / 2)
1208  IF PB < 0 THEN PB = 0
1210  IF WP > 0 THEN PA = PA + WP - 1
1211  IF WP < 0 THEN PA = PA + WP + 1
1212  IF MO <  > 0 THEN  GOSUB 2000: GOSUB 3000: GOSUB 3200

Next we enter the monster speed. ToA is a semi real time game: the player and the monsters take it in turns, but the player only has a limited amount of time to enter their move. The amount of time granted is controlled by the "monster speed" variable.

1215 SE = 100
1216  INPUT "MONSTER SPEED (SLOW, MEDIUM, OR FAST)   ? ";C$: IF  LEFT$ (C$,1) = "S" THEN SE = 250
1217  IF  LEFT$ (C$,1) = "F" THEN SE = 60
1218  IF  LEFT$ (C$,1) = "M" THEN SE = 120

Finally, everything is safely packed away outside of BASIC and the DM program is loaded.

1219  POKE KB + 9,SE: POKE KB + 11,HS: POKE KB + 13,RS: POKE KB + 14,RM: POKE KB + 12,WC: POKE KB + 7,WM
1220  POKE KB + 24,CA: POKE KB + 6,HN: POKE KB + 11,HS
1221  POKE KB + 23,AS: POKE KB + 7,WM: POKE KB + 18,PB: POKE KB + 19,PA: POKE KB + 21,IT: POKE KB + 22,EG: POKE KB + 4,SP: POKE KB + 25,DX:J =  INT (EX / 65536): POKE KB + 3,J:JJ =  INT (EX / 256 - J * 256): POKE KB + 2,JJ: POKE KB + 1,EX - JJ * 256 - J * 65536
1223 WC = 5 + WW( PEEK (KB + 17)) + W(AA) + SW( INT ( PEEK (KB) / 2)) + 1 + (RS + RM) / 10
1225  POKE KB + 13,RS: POKE KB + 14,RM: POKE KB + 12,WC: POKE KB + 20,CH(1)
1230  POKE KB + 10,SM
1260  POKE KB,PS
1270  POKE KB + 8,AA: IF  PEEK (KB - 12) = 123 GOTO 1400
1315 J =  LEN (NM$): IF J > 11 THEN J = 11
1320  FOR I = 1 TO J: POKE KB - 12 + I, ASC ( MID$ (NM$,I,1)): NEXT I
1330  IF J < 11 THEN  FOR I = J + 1 TO 11: POKE KB - 12 + I, ASC (" "): NEXT I
1400  GOSUB 4500
1500  POKE KB - 12,123
1900  PRINT : PRINT "WHEN THOU ART READY TO CONTINUE, PRESS 'RETURN'.": GET A$: PRINT : PRINT "I SHALL NOW LOAD THE DUNJONMASTER.": PRINT  CHR$ (04);"RUN DM"

The remainder of the code in INN is related to shopping and character generation. First Armor. This prints the table above, although it only shows the weight

and price - the manual gives a little additional information, but for the most part the player has to figure out the mechanics for themselves. The routine at 4000 is used in the purchase subroutines to implement haggling.


2000  INPUT "WILT THOU BUY NEW ARMOR? ";A$: IF  LEFT$ (A$,1) <  > "Y" THEN  RETURN 
2001  FOR I = 1 TO 900: NEXT : HOME : PRINT  TAB( 5);"TYPE"; TAB( 20);"WEIGHT"; TAB( 30);"PRICE"
2005  PRINT 
2010  FOR I = 1 TO 5: PRINT NA$(I); TAB( 20);W(I); TAB( 30);P(I): NEXT I
2020  INPUT "WHAT SORT OF ARMOR WOULDST THOU WEAR?   ";A$: IF  LEFT$ (A$,1) = "N" THEN AM = 0:AA = 0: RETURN 
2021  FOR I = 1 TO 5: IF  LEFT$ (A$,2) =  LEFT$ (NA$(I),2) THEN N = I: GOTO 2026
2022  NEXT I: PRINT "I HAVE NOT ";A$;" FOR SALE": GOTO 2020
2024  IF  PEEK (KB - 12) = 123 THEN WC = WC - W(AA)
2026 LO = .3 * P(N):AK = P(N):A1 = AK: GOSUB 4000: IF OO = 0 GOTO 2020

Once armor is purchased (or otherwise acquired), update money and weight. Also clears (KB+16) which holds a bonus for magic armor.

2030 AA = N:MO = MO - OO:WC = WC + W(N): POKE KB + 16,0
2040  PRINT "THOU HAST ";MO;" SILVER PIECES LEFT": PRINT "IN THY PURSE.": RETURN 

The next routine will be familiar to anyone who has ever played DnD: a subroutine to generate 3d6 to supply the core stats:

2190 J =  INT ( RND (6) * 6 + 1) +  INT ( RND (6) * 6 + 1) +  INT ( RND (6) * 6 + 1): RETURN 

Followed by the actual character generator:

2200 HB = 0:SC = 0: FOR I = 1 TO 6: GOSUB 2190:CH(I) = J:SC = SC + J: NEXT I: IF SC < 60 OR CH(4) < 8 OR CH(5) < 7 GOTO 2200

There's no option to re-roll, but the generator attempts

to ensure that your character is viable by re-rolling until the total score is at least 60 and Strength and Constitution have reasonable values.


Once we have some reasonable core stats, the remaining variables are filled in, the character's level ( KB+15) is set to 1 and some money is awarded ( 3d6 * 10 silver pieces ).

2205 EX = 0:RS = 0:RM = 0:AA = 0:PS = 0: POKE KB + 17,0:SP = 0:WP = 0:AM = 0:SM = 0:HS = 0:HN = 0: POKE KB + 15,1
2210  HOME : PRINT  TAB( 5);"THY QUALITIES:": PRINT : FOR I = 1 TO 6: PRINT NC$(I); TAB( 25);CH(I): NEXT 
2215  FOR I = 1 TO 6: POKE KA - 97 + I,CH(I): NEXT 
2220  PRINT " ": GOSUB 2190:MO = J * 10: PRINT "THOU HAST ";MO;" PIECES OF SILVER"
2225  GOSUB 2250:L = 1: POKE KB + 16,0
2230 EG = CH(3):IN = CH(1):AS = CH(4):CA = CH(5):IT = CH(2):DX = CH(6):PA = 11:PB = 11
2240  RETURN 
2250  FOR I = KA - 90 TO KA - 81: POKE I,0
2255  NEXT I: RETURN 

The following long, but straight forward, slab of code, allows one to enter a character manually. The writers of ToA expected many of their players to be DnD players who would want to take their pencil and paper characters into the game. The manual had quidelines for converting, but there is nothing to prevent you from creating super human characters. Again, the feeling was that you would be only cheating yourself of fun.

2400  POKE KB + 15,0: FOR I = 1 TO 6: PRINT "ENTER ";NC$(I);: INPUT ": ";CH(I): IF CH(I) >  = 0 AND CH(I) <  = 18 THEN  POKE KA - 97 + I,CH(I): GOTO 2403
2401  IF CH(I) > 18 THEN  PRINT CH(I);" BE TOO HIGH. NO MORE THAN 18 CAN": PRINT "IT BE.":I = I - 1: GOTO 2403
2402  IF CH(I) < 0 THEN  PRINT CH(I);"? ART THOU SUPERNATURAL, OR MERELY": PRINT "A FOOL? THOU CAN HAVE NO NEGATIVE TRAIT!":I = I - 1
2403  NEXT I
2405  INPUT "THY CHARACTER'S EXPERIENCE IS? ";EX: IF EX > 16000000 THEN  PRINT "THY CHARACTER IS TOO WORLDWISE; FIND    ANOTHER, MY FRIEND.": GOTO 2400
2410 E = EX / 1000: FOR L = 1 TO 20: IF 2 ^ L < E THEN  NEXT L
2420  INPUT "HOW MUCH MONEY HAST THOU TO SPEND? ";MO
2425  GOSUB 2500
2427  PRINT "WHAT KIND OF SWORD HAST THOU?": INPUT A$: FOR I = 1 TO 5: IF  LEFT$ (A$,1) =  LEFT$ (NW$(I),1) THEN  IF CH(4) >  = WR(I) THEN N = I:OO = 0: GOSUB 2690: GOTO 2429
2428  NEXT I: PRINT "THOU CANNOT TAKE A ";A$;: PRINT " TO THE": PRINT "DUNJON. THOU MUST BUY ANOTHER."
2429  PRINT "WHAT SORT OF ARMOR DOST THOU WEAR?": INPUT A$: FOR I = 0 TO 5: IF  LEFT$ (A$,2) =  LEFT$ (NA$(I),2) THEN N = I:OO = 0: GOSUB 2030: GOTO 2435
2432  NEXT I: PRINT "THOU CANNOT WEAR ";A$: PRINT "IN THE DUNJON": GOTO 2429
2435 N = 0: INPUT "HAST THOU A SHIELD? ";A$: IF  LEFT$ (A$,1) = "Y" THEN  INPUT "BE IT LARGE OR SMALL? ";A$:N = 1: IF  LEFT$ (A$,1) = "L" THEN N = 2
2437  IF N > 0 THEN  GOSUB 2865
2439 HB = 0: INPUT "HAST THOU A BOW? ";A$: IF  LEFT$ (A$,1) = "Y" THEN HB = 1
2440  INPUT "HOW MANY ARROWS HAST THOU? ";RS: IF RS > 60 THEN  PRINT "THOU CAN HAVE BUT SIXTY": GOTO 2440
2445  INPUT "HOW MANY MAGIC ARROWS? ";RM: IF RM > 60 THEN  PRINT "THOU CAN HAVE BUT SIXTY": GOTO 2445
2450  INPUT "HOW MANY HEALING POTIONS HAST THOU? ";HN: INPUT "HOW MANY HEALING SALVES HAST THOU? ";HS: IF HS > 10 THEN HS = 10
2480  INPUT "IS THY SWORD MAGICAL? ";A$: IF  LEFT$ (A$,1) = "Y" THEN  INPUT "WHAT BE THE PLUS? ";SM
2485  POKE KB + 16,0: INPUT "IS THY ARMOR MAGICAL? ";A$: IF  LEFT$ (A$,1) = "Y" THEN  INPUT "WHAT BE THE PLUS? ";AM: POKE KB + 16,AM
2490  GOSUB 2250: GOTO 2230

Next we have the level up code. I am not convinced this code will work correctly, but the intent is to increase the player's core stats as they gain experience.

2500 WP =  INT ((L + 1) / 2):SP = L - WP: IF W2 = 1 THEN WP = L:SP = 0
2503  IF  PEEK (KB + 15) = L THEN  RETURN 
2504  POKE KB + 15,L
2505  IF  PEEK (KB - 12) = 123 THEN J = L - 1:L = 2: IF J < 0 THEN J = 0: ON J GOTO 2510,2520,2530,2540,2550,2510,2520,2530,2540,2550
2510 L = L - 1: IF L = 0 THEN 2565
2515  IF CH(5) >  = 9 THEN CH(4) = CH(4) + 1: GOTO 2520
2516 CH(5) = CH(5) + 1
2520 L = L - 1: IF L = 0 THEN 2565
2525  IF CH(6) >  = 9 THEN CH(5) = CH(5) + 1: GOTO 2530
2526 CH(6) = CH(6) + 1
2530 L = L - 1: IF L = 0 THEN 2565
2535 CH(5) = CH(5) + 1
2540 L = L - 1: IF L = 0 THEN 2565
2545  IF CH(6) < 9 THEN CH(6) = CH(6) + 1: GOTO 2550
2546  IF CH(4) >  = CH(5) THEN CH(5) = CH(5) + 1: GOTO 2550
2547 CH(4) = CH(4) + 1
2550 L = L - 1: IF L = 0 THEN 2565
2555  IF CH(2) >  = CH(3) THEN CH(3) = CH(3) + 1: GOTO 2560
2556 CH(2) = CH(2) + 1
2560  GOTO 2510
2565  FOR I = 1 TO 6:M = CH(I) - 18: IF M <  = 0 THEN 2580
2570 CH(I) = 18: FOR J = 1 TO M: IF CH(4) < 18 THEN CH(4) = CH(4) + 1: GOTO 2575
2571  IF CH(5) < 18 THEN CH(5) = CH(5) + 1: GOTO 2575
2572  IF CH(6) < 18 THEN CH(6) = CH(6) + 1: GOTO 2575
2574 R =  RND (1) * 3:CH(R) = CH(R) + 1
2575  NEXT J
2580  NEXT I:CA = CH(5):AS = CH(4):DX = CH(6):EG = CH(3):IT = CH(2): RETURN 

Similar to armor purchasing is weapon purchasing. The only real difference is the strength requirement.

2600  IF MO = 0 THEN  RETURN 
2605  PRINT "WILT THOU BUY ONE OF OUR FINE SWORDS?": INPUT "";A$: IF  LEFT$ (A$,1) = "N" THEN N =  PEEK (KB + 17): GOSUB 2694: RETURN 
2606 W2 = 0
2645  HOME 
2650  PRINT "WEAPON"; TAB( 20);"WEIGHT"; TAB( 30);"PRICE"
2660  PRINT : FOR I = 1 TO 5: PRINT NW$(I); TAB( 23);WW(I); TAB( 30);WP(I): NEXT I
2670  PRINT "WHAT WEAPON WILT THOU PURCHASE?": INPUT "";A$: FOR I = 1 TO 5: IF  LEFT$ (A$,1) =  LEFT$ (NW$(I),1) THEN N = I: GOTO 2675
2671  IF  LEFT$ (A$,1) = "N" THEN N =  PEEK (KB + 17): GOSUB 2694: RETURN 
2672  NEXT I: PRINT "I HAVE NO SUCH WEAPON AS THAT.": GOTO 2670
2675  IF WR(N) > AS THEN  PRINT "THOU CANNOT WIELD SUCH A GREAT WEAPON.": GOTO 2670
2677  PRINT "FEAST THINE EYES 'PON THIS FINE": PRINT NW$(N);: IF  RND (4) * 4 > 2 THEN  PRINT ". 'TIS SURE TO": PRINT "DRINK THY FOE'S BLOOD.": GOTO 2679
2678  PRINT " 'TIS WELL FORGED IRON."
2679 LO = .3 * WP(N):AK = WP(N):A1 = AK: GOSUB 4000: IF OO = 0 GOTO 2670
2680 MO = MO - OO: PRINT "THOU HAST ";MO;" SILVER PIECES LEFT."

Compute weapon stats. The maximum damage that a weapon can do is:


WeaponDamage * Strength / 10


Where "WeaponDamage" comes from the weapon table. The weapon points check dexterity against the Lo/Hi ranges, although it looks like the subtraction of the low range is missing ( this is fixed in the sequel ) so this is bugged. The actual bonus penalty is roughly Log2 of this difference - so if this was working properly, we would have roughly a -3 - +3 range.


The flag W2 is set to indicate that a weapon is two handed.

2690 WM =  INT (WD(N) * AS / 10 + .5):SM = 0: POKE KB + 10,0: POKE KB + 17,N:WC = WC + WW(N): IF N = 5 THEN W2 = 1
2694  IF DW(N,0) > CH(6) THEN WP = WP + CH(6): GOTO 2696
2695  IF DW(N,1) < CH(6) THEN WP = WP + CH(6) - DW(N,1)
2696  IF WP > 0 THEN WP =  INT (1.3 *  LOG (WP) + 1)
2700  RETURN 

Shield purchasing is the similar to weapons and armor, but skipped if the character is wielding a two-handed great sword.

2800  IF W2 = 1 THEN PS = 0: POKE KB,0:SP = 0: RETURN 
2840  INPUT "WILT THOU BUY A SHIELD? ";A$: IF  LEFT$ (A$,1) = "N" THEN  GOSUB 2885: RETURN 
2841  HOME : PRINT "SHIELD     WEIGHT     ASK": PRINT : PRINT "SMALL"; TAB( 11);SW(1); TAB( 22);SP(1): PRINT "LARGE"; TAB( 11);SW(2); TAB( 22);SP(2): PRINT : INPUT "WHAT SORT? ";C$: IF  LEFT$ (C$,1) = "L" THEN N = 2: GOTO 2843
2842 N = 1
2843  IF  LEFT$ (C$,1) <  > "L" AND  LEFT$ (C$,1) <  > "S" THEN N = 0: POKE KB,0:PS = 0: RETURN 
2850 LO = .3 * SP(N):AK = SP(N):A1 = AK: GOSUB 4000: IF OO = 0 THEN 2840

Shield points computed like weapon points ( although this time correctly!)

2865  IF DS(N - 1,0) > DX THEN SP = SP + DX - DS(N - 1,0): GOTO 2870
2866  IF DS(N - 1,1) < DX THEN SP = SP + DX - DS(N - 1,1)
2870 MO = MO - OO: PRINT "THOU HAST ";MO;" SILVER PIECES LEFT.":WC = WC + SW(N):PS = SD(N): POKE KB,PS: GOSUB 2885: RETURN 
2885  IF PS = 5 THEN SP =  INT (SP / 2)
2890  IF SP > 0 THEN SP =  INT (1.3 *  LOG (SP) + 1)
2895 SP = 2 * PS + SP: RETURN 

Purchasing a bow and arrows. One oddity is that bow ownership is not recorded in the character record, and a character is always assumed to have purchased a bow when the character is restored after visiting the dungeon. This is fixed in the sequel.

3000  IF HB > 0 GOTO 3030
3010  INPUT "WILT THOU BUY A BOW? ";C$: IF  LEFT$ (C$,1) = "N" THEN  RETURN 
3020  PRINT "I'VE A FINE BOW, YEW AND NEARLY NEW, FOR12 SILVER PIECES.":LO = 4:AK = 12:A1 = AK: GOSUB 4000: IF OO = 0 THEN  RETURN 
3025 MO = MO - OO: PRINT "THOU HAST ";MO;" REMAINING."
3030  IF RS + RM > 60 THEN RS = 60 - RM: GOTO 3050
3040 N = 0: INPUT "HOW MANY ARROWS WILT THOU BUY (AT TWO PER SILVER PIECE)? ";N: IF  INT ((N + 1) / 2) > MO THEN  PRINT "NO CREDIT!": GOTO 3040
3041  IF RS + RM + N > 60 THEN  PRINT "THOU CANST CARRY BUT SIXTY ARROWS. BUY  FEWER.": GOTO 3040
3045 RS = RS + N:MO = MO -  INT ((N + 1) / 2)
3050  RETURN 

Healing Salves - i.e. healing potions.

3200  REM 
3210  INPUT "HOW MANY SALVES WILT THOU BUY (THEY COSTTHEE 10 SILVER PIECES EACH)? ";N: IF 10 * N > MO THEN  PRINT "NO CREDIT!": GOTO 3210
3211 MO = MO - N * 10:HS = HS + N: IF HS > 10 THEN N = HS - 10:MO = MO + 10 * N:HS = 10: PRINT "MORE THAN TEN WILL DO THEE NO GOOD!"
3220  IF MO < .35 * OM THEN  PRINT NM$;"! THOU SPENDTHRIFT!": PRINT "THOU HAST BUT ";MO;" SILVER PIECES LEFT": PRINT "TO THEE!": RETURN 
3225  PRINT NM$;", THOU ART FRUGAL. THOU": PRINT "HAST ";MO;" SILVER PIECES LEFT."
3230  RETURN 


The haggle subroutine is used by all the purchase routines above. It's one of the few places in the game where the intelligence stat is used. This, along with ego, determines by how much the Innkeeper adjusts his asking price in response to the player's offer. The important lines are 4058 and 4060. Here we consider the difference between the player's offer and the asking price. A fraction of this is added to the player's previous offer weighted by the player's stats and a non-uniform random number. This number is generated by feeding a uniformly generated number through square root (SQR) to get a distribution biased towards 1. If the sum of ego and intelligence are 20 or greater, the Innkeeper will move his asking price towards the player's. If they are less than 20, there is some chance that he will raise his asking price.

4000  IF  RND (3) * 3 > 2 THEN  PRINT "WHAT MAY BE THY OFFER, ";NM$;"?": GOTO 4010
4005  PRINT "WHAT OFFEREST THOU?"
4010  INPUT OO:OO =  INT (OO): IF OO > MO THEN  PRINT "LIAR, THOU HAST BUT ";MO;".": GOTO 4000
4020  IF OO = 0 THEN LS = 0: RETURN 
4030  IF OO <  = LO THEN  GOSUB 4800: GOTO 4000
4035  IF OO <  = LS THEN  GOSUB 4700: GOTO 4000
4040  IF OO >  = AK THEN  PRINT "DONE!":LS = 0: RETURN 
4050  IF OO > AK - .3 *  RND (1) ^ 2 * AK THEN  IF OO < .6 * A1 THEN  PRINT "THOU ART A HARD BARGAINER,": PRINT NM$:LS = 0: RETURN 
4051  IF OO > AK - .3 *  RND (1) ^ 2 * AK THEN  PRINT "DONE!":LS = 0: RETURN 
4055  IF  RND (200) * 200 + 1 = 200 THEN  PRINT "I SEE THE GODS LOOK FAVORABLY UPON THEE,SO TAKE IT FOR THAT.":LS = 0: RETURN 
4058 B = 20 / (CH(1) + CH(3)): IF CH(3) > 12 AND CH(1) < 10 THEN B = 20 / (CH(1) + 20 - CH(3))
4060 AK = OO + (AK - OO) *  SQR (1 -  RND (1)) * B
4070 LS = OO: GOSUB 4900: GOTO 4000

The character summary screen



4500 CH(1) =  PEEK (KB + 20):CH(2) =  PEEK (KB + 21):CH(3) =  PEEK (KB + 22):CH(4) =  PEEK (KB + 23):CH(5) =  PEEK (KB + 24):CH(6) =  PEEK (KB + 25):SM =  PEEK (KB + 10):RM =  PEEK (KB + 14):AA =  PEEK (KB + 8):WM =  PEEK (KB + 7) - SM:WN =  PEEK (KB + 17)
4501 RS =  PEEK (KB + 13)
4505  IF SM <  > 0 THEN WN = 6
4510  GOSUB 9800: HOME : PRINT "CHARACTER SUMMARY FOR ";NM$
4520  PRINT : FOR I = 1 TO 6: PRINT NC$(I); TAB( 20); PEEK (KA - 97 + I): NEXT I
4525 J = 0: IF  PEEK (KB) = 3 THEN J = 1
4526  IF  PEEK (KB) = 5 THEN J = 2
4530  PRINT "WEAPON: ";NW$(WN);: IF WN = 6 THEN  PRINT " PLUS "; PEEK (KB + 10);
4531  PRINT 
4532  PRINT "ARMOR: ";NA$(AA);: IF  PEEK (KB + 16) > 0 THEN  PRINT " PLUS "; PEEK (KB + 16);
4533  PRINT 
4535  PRINT "ARROWS: ";RS; TAB( 20);"MAGIC ARROWS: ";RM
4536  PRINT "SHIELD: ";NS$(J)
4537  PRINT "SALVES: "; PEEK (KB + 11); TAB( 20);"ELIXIRS: "; PEEK (KB + 6)
4538  PRINT "SILVER: ";MO
4540  PRINT "EXPERIENCE: "; PEEK (KB + 1) + 256 *  PEEK (KB + 2) + 65536 *  PEEK (KB + 3)
4541  PRINT "WEIGHT CARRIED: "; PEEK (KB + 12)
4550  RETURN 

A subroutine to emit a random response when the player makes an offer lower or equal to the last.

4700 R =  RND (3) * 3: ON  RND (3) * 3 + 1 GOTO 4710,4720,4730
4710  PRINT "DOST THOU TAKE ME FOR A DOLT?": RETURN 
4720  PRINT "ART THOU A FOOL OR A KNAVE, ";NM$;"?": PRINT "MAKE AN OFFER HIGHER THAN THY LAST!": RETURN 
4730  PRINT "PERCHANCE THY WOULDST NOT HAVE THIS AT  ALL?": RETURN 

A subroutine to emit a random response if the player offers less than the minimum price.

4800  IF  RND (100) * 100 > 50 THEN  PRINT "HA! TIS LESS THAN I PAID FOR IT!": RETURN 
4801  PRINT "I SPIT UPON THY PALTRY OFFER!": RETURN 

A subroutine to emit a response to a reasonable offer.

4900  FOR I1 = 1 TO 10:R =  RND (RTT) * RT: NEXT I1:RQ = 0:R =  RND (RT) * RT: FOR I1 = 1 TO RN:RQ = RQ + RR(I1): IF RQ < R THEN  NEXT I1
4901  PRINT R$(I1);" "; INT (AK + .999): RETURN 

A subroutine to restore the characters name from the binary data

9800 NM$ = "": FOR I = 1 TO 11:NM$ = NM$ +  CHR$ ( PEEK (KB - 12 + I)): NEXT I
9810  FOR I = 1 TO 10: IF  MID$ (NM$,12 - I,1) <  > " " GOTO 9830
9820  NEXT I
9830 NM$ =  LEFT$ (NM$,12 - I): RETURN 

Restores character stats after returning from the dungeon. Experience is a 24-bit value, with

level being Log2 of experience. The new level ( NL ) is not used anywhere, which makes me a bit sceptical that the level up code actually works. Also note that we set HB to1 ( have bow ) regardless of whether the player actually purchased on before entering the dungeon.

9900 SM =  PEEK (KB + 10):HS =  PEEK (KB + 11):HN =  PEEK (KB + 6):RS =  PEEK (KB + 13):RM =  PEEK (KB + 14): FOR I = 1 TO 6:CH(I) =  PEEK (KB + 19 + I): NEXT :AA =  PEEK (KB + 8):WM =  PEEK (KB + 7):PS =  PEEK (KB):WC =  PEEK (KB + 12)
9901  IF  PEEK (KB + 17) = 5 THEN W2 = 1
9902  IF AA <  > 5 THEN W2 = 0
9907 EX =  PEEK (KB + 1) + 256 *  PEEK (KB + 2) + 65536 *  PEEK (KB + 3): IF EX > 1999 THEN NL =  LOG (EX / 1000) /  LOG (2) + 1
9908  IF EX <  = 1999 THEN L = 1
9909 HB = 1: GOSUB 2500: GOSUB 2230
9910  RETURN 

That's the INN program. We now move onto the more involved DM program.

16 views0 comments

Recent Posts

See All

Flying Shark : Object Logic

Every object has a type field ( 0x5 ) that selects a tick routine. The tick routine for a bomb power-up is shown below (link to video)....

コメント


bottom of page