* similar label number for the caller to "goto".
*/
-/* ANALYSE A VERB. REMEMBER WHAT IT WAS, GO BACK FOR OBJECT IF SECOND WORD
- * UNLESS VERB IS "SAY", WHICH SNARFS ARBITRARY SECOND WORD. */
+/* Analyse a verb. remember what it was, go back for object if second word
+ * unless verb is "say", which snarfs arbitrary second word. */
int action(long STARTAT) {
switch(STARTAT) {
if(VERB == SAY)OBJ=WD2;
if(OBJ > 0) goto L4090;
-/* ANALYSE AN INTRANSITIVE VERB (IE, NO OBJECT GIVEN YET). */
+/* Analyse an intransitive verb (ie, no object given yet). */
L4080: switch (VERB-1) { case 0: goto L8010; case 1: return(8000); case 2:
return(8000); case 3: goto L8040; case 4: return(2009); case 5: goto L8040;
* RESU FLY LSTN ZZZZ */
BUG(23);
-/* ANALYSE A TRANSITIVE VERB. */
+/* Analyse a transitive verb. */
L4090: switch (VERB-1) { case 0: goto L9010; case 1: goto L9020; case 2: goto
L9030; case 3: goto L9040; case 4: return(2009); case 5: goto L9040;
* RESU FLY LSTN ZZZZ */
BUG(24);
-/* ANALYSE AN OBJECT WORD. SEE IF THE THING IS HERE, WHETHER WE'VE GOT A VERB
- * YET, AND SO ON. OBJECT MUST BE HERE UNLESS VERB IS "FIND" OR "INVENT(ORY)"
- * (AND NO NEW VERB YET TO BE ANALYSED). WATER AND OIL ARE ALSO FUNNY, SINCE
- * THEY ARE NEVER ACTUALLY DROPPED AT ANY LOCATION, BUT MIGHT BE HERE INSIDE
- * THE BOTTLE OR URN OR AS A FEATURE OF THE LOCATION. */
+/* Analyse an object word. See if the thing is here, whether we've got a verb
+ * yet, and so on. Object must be here unless verb is "find" or "invent(ory)"
+ * (and no new verb yet to be analysed). Water and oil are also funny, since
+ * they are never actually dropped at any location, but might be here inside
+ * the bottle or urn or as a feature of the location. */
L5000: OBJ=K;
if(!HERE(K)) goto L5100;
-/* ROUTINES FOR PERFORMING THE VARIOUS ACTION VERBS */
+/* Routines for performing the various action verbs */
-/* STATEMENT NUMBERS IN THIS SECTION ARE 8000 FOR INTRANSITIVE VERBS, 9000 FOR
- * TRANSITIVE, PLUS TEN TIMES THE VERB NUMBER. MANY INTRANSITIVE VERBS USE THE
- * TRANSITIVE CODE, AND SOME VERBS USE CODE FOR OTHER VERBS, AS NOTED BELOW. */
+/* Statement numbers in this section are 8000 for intransitive verbs, 9000 for
+ * transitive, plus ten times the verb number. many intransitive verbs use the
+ * transitive code, and some verbs use code for other verbs, as noted below. */
-/* CARRY, NO OBJECT GIVEN YET. OK IF ONLY ONE OBJECT PRESENT. */
+/* Carry, no object given yet. OK if only one object present. */
L8010: if(ATLOC[LOC] == 0 || LINK[ATLOC[LOC]] != 0 || ATDWRF(LOC) > 0) return(8000);
OBJ=ATLOC[LOC];
-/* TRANSITIVE CARRY/DROP ARE IN SEPARATE FILE. */
+/* Transitive carry/drop are in separate file. */
L9010: return(carry());
L9020: return(discard(false));
-/* SAY. ECHO WD2 (OR WD1 IF NO WD2 (SAY WHAT?, ETC.).) MAGIC WORDS OVERRIDE. */
+/* SAY. Echo WD2 (or WD1 if no WD2 (SAY WHAT?, etc.).) Magic words override. */
L9030: SETPRM(1,WD2,WD2X);
if(WD2 <= 0)SETPRM(1,WD1,WD1X);
OBJ=0;
return(2630);
-/* LOCK, UNLOCK, NO OBJECT GIVEN. ASSUME VARIOUS THINGS IF PRESENT. */
+/* Lock, unlock, no object given. Assume various things if present. */
L8040: SPK=28;
if(HERE(CLAM))OBJ=CLAM;
if(HERE(CHAIN))OBJ=CHAIN;
if(OBJ == 0) return(2011);
-/* LOCK, UNLOCK OBJECT. SPECIAL STUFF FOR OPENING CLAM/OYSTER AND FOR CHAIN. */
+/* Lock, unlock object. Special stuff for opening clam/oyster and for chain. */
L9040: if(OBJ == CLAM || OBJ == OYSTER) goto L9046;
if(OBJ == DOOR)SPK=111;
K=K+2*PROP[GRATE];
return(2010);
-/* CLAM/OYSTER. */
+/* Clam/Oyster. */
L9046: K=0;
if(OBJ == OYSTER)K=1;
SPK=124+K;
DROP(PEARL,105);
return(2011);
-/* CHAIN. */
+/* Chain. */
L9048: if(VERB == LOCK) goto L9049;
SPK=171;
if(PROP[BEAR] == 0)SPK=41;
FIXED[CHAIN]= -1;
return(2011);
-/* LIGHT. APPLICABLE ONLY TO LAMP AND URN. */
+/* Light. Applicable only to lamp and urn. */
L8070: if(HERE(LAMP) && PROP[LAMP] == 0 && LIMIT >= 0)OBJ=LAMP;
if(HERE(URN) && PROP[URN] == 1)OBJ=OBJ*100+URN;
PROP[URN]=2;
return(2011);
-/* EXTINGUISH. LAMP, URN, DRAGON/VOLCANO (NICE TRY). */
+/* Extinguish. Lamp, urn, dragon/volcano (nice try). */
L8080: if(HERE(LAMP) && PROP[LAMP] == 1)OBJ=LAMP;
if(HERE(URN) && PROP[URN] == 2)OBJ=OBJ*100+URN;
if(DARK(0))RSPEAK(16);
return(2012);
-/* WAVE. NO EFFECT UNLESS WAVING ROD AT FISSURE OR AT BIRD. */
+/* Wave. No effect unless waving rod at fissure or at bird. */
L9090: if((!TOTING(OBJ)) && (OBJ != ROD || !TOTING(ROD2)))SPK=29;
if(OBJ != ROD || !TOTING(OBJ) || (!HERE(BIRD) && (CLOSNG || !AT(FISSUR))))
SPK=208;
return(2011);
-/* ATTACK ALSO MOVED INTO SEPARATE MODULE. */
+/* Attack also moved into separate module. */
L9120: return(attack());
-/* POUR. IF NO OBJECT, OR OBJECT IS BOTTLE, ASSUME CONTENTS OF BOTTLE.
- * SPECIAL TESTS FOR POURING WATER OR OIL ON PLANT OR RUSTY DOOR. */
+/* Pour. If no object, or object is bottle, assume contents of bottle.
+ * special tests for pouring water or oil on plant or rusty door. */
L9130: if(OBJ == BOTTLE || OBJ == 0)OBJ=LIQ(0);
if(OBJ == 0) return(8000);
L9134: OBJ=URN;
goto L9220;
-/* EAT. INTRANSITIVE: ASSUME FOOD IF PRESENT, ELSE ASK WHAT. TRANSITIVE: FOOD
- * OK, SOME THINGS LOSE APPETITE, REST ARE RIDICULOUS. */
+/* Eat. Intransitive: assume food if present, else ask what. transitive: food
+ * ok, some things lose appetite, rest are ridiculous. */
L8140: if(!HERE(FOOD)) return(8000);
L8142: DSTROY(FOOD);
OGRE)SPK=71;
return(2011);
-/* DRINK. IF NO OBJECT, ASSUME WATER AND LOOK FOR IT HERE. IF WATER IS IN
- * THE BOTTLE, DRINK THAT, ELSE MUST BE AT A WATER LOC, SO DRINK STREAM. */
+/* Drink. If no object, assume water and look for it here. if water is in
+ * the bottle, drink that, else must be at a water loc, so drink stream. */
L9150: if(OBJ == 0 && LIQLOC(LOC) != WATER && (LIQ(0) != WATER || !HERE(BOTTLE)))
return(8000);
SPK=240;
return(2011);
-/* RUB. YIELDS VARIOUS SNIDE REMARKS EXCEPT FOR LIT URN. */
+/* Rub. Yields various snide remarks except for lit urn. */
L9160: if(OBJ != LAMP)SPK=76;
if(OBJ != URN || PROP[URN] != 2) return(2011);
SPK=216;
return(2011);
-/* THROW MOVED INTO SEPARATE MODULE. */
+/* Throw moved into separate module. */
L9170: return(throw());
-/* QUIT. INTRANSITIVE ONLY. VERIFY INTENT AND EXIT IF THAT'S WHAT HE WANTS. */
+/* Quit. Intransitive only. verify intent and exit if that's what he wants. */
L8180: if(YES(22,54,54)) score(1);
return(2012);
-/* FIND. MIGHT BE CARRYING IT, OR IT MIGHT BE HERE. ELSE GIVE CAVEAT. */
+/* Find. Might be carrying it, or it might be here. Else give caveat. */
L9190: if(AT(OBJ) || (LIQ(0) == OBJ && AT(BOTTLE)) || K == LIQLOC(LOC) || (OBJ ==
DWARF && ATDWRF(LOC) > 0))SPK=94;
if(TOTING(OBJ))SPK=24;
return(2011);
-/* INVENTORY. IF OBJECT, TREAT SAME AS FIND. ELSE REPORT ON CURRENT BURDEN. */
+/* Inventory. If object, treat same as find. Else report on current burden. */
L8200: SPK=98;
/* 8201 */ for (I=1; I<=100; I++) {
if(TOTING(BEAR))SPK=141;
return(2011);
-/* FEED/FILL ARE IN THE OTHER MODULE. */
+/* Feed/fill are in the other module. */
L9210: return(feed());
L9220: return(fill());
-/* BLAST. NO EFFECT UNLESS YOU'VE GOT DYNAMITE, WHICH IS A NEAT TRICK! */
+/* Blast. No effect unless you've got dynamite, which is a neat trick! */
L9230: if(PROP[ROD2] < 0 || !CLOSED) return(2011);
BONUS=133;
RSPEAK(BONUS);
score(0);
-/* SCORE. CALL SCORING ROUTINE BUT TELL IT TO RETURN. */
+/* Score. Call scoring routine but tell it to return. */
L8240: score(-1);
SETPRM(1,SCORE,MXSCOR);
FOOBAR=0;
if(PLACE[EGGS] == PLAC[EGGS] || (TOTING(EGGS) && LOC == PLAC[EGGS]))
return(2011);
-/* BRING BACK TROLL IF WE STEAL THE EGGS BACK FROM HIM BEFORE CROSSING. */
+/* Bring back troll if we steal the eggs back from him before crossing. */
if(PLACE[EGGS] == 0 && PLACE[TROLL] == 0 && PROP[TROLL] ==
0)PROP[TROLL]=1;
K=2;
PSPEAK(EGGS,K);
return(2012);
-/* BRIEF. INTRANSITIVE ONLY. SUPPRESS LONG DESCRIPTIONS AFTER FIRST TIME. */
+/* Brief. Intransitive only. Suppress long descriptions after first time. */
L8260: SPK=156;
ABBNUM=10000;
DETAIL=3;
return(2011);
-/* READ. PRINT STUFF BASED ON OBJTXT. OYSTER (?) IS SPECIAL CASE. */
+/* Read. Print stuff based on objtxt. Oyster (?) is special case. */
L8270: /* 8275 */ for (I=1; I<=100; I++) {
L8275: if(HERE(I) && OBJTXT[I] != 0 && PROP[I] >= 0)OBJ=OBJ*100+I;
L9275: CLSHNT=YES(192,193,54);
return(2012);
-/* BREAK. ONLY WORKS FOR MIRROR IN REPOSITORY AND, OF COURSE, THE VASE. */
+/* Break. Only works for mirror in repository and, of course, the vase. */
L9280: if(OBJ == MIRROR)SPK=148;
if(OBJ == VASE && PROP[VASE] == 0) goto L9282;
FIXED[VASE]= -1;
return(2011);
-/* WAKE. ONLY USE IS TO DISTURB THE DWARVES. */
+/* Wake. Only use is to disturb the dwarves. */
L9290: if(OBJ != DWARF || !CLOSED) return(2011);
SPK=199;
return(18999);
-/* SUSPEND. OFFER TO SAVE THINGS IN A FILE, BUT CHARGING SOME POINTS (SO
- * CAN'T WIN BY USING SAVED GAMES TO RETRY BATTLES OR TO START OVER AFTER
- * LEARNING ZZWORD). */
+/* Suspend. Offer to save things in a file, but charging some points (so
+ * can't win by using saved games to retry battles or to start over after
+ * learning zzword). */
L8300: SPK=201;
RSPEAK(260);
SAVED=SAVED+5;
KK= -1;
-/* THIS NEXT PART IS SHARED WITH THE "RESUME" CODE. THE TWO CASES ARE
- * DISTINGUISHED BY THE VALUE OF KK (-1 FOR SUSPEND, +1 FOR RESUME). */
+/* This next part is shared with the "resume" code. the two cases are
+ * distinguished by the value of kk (-1 for suspend, +1 for resume). */
L8305: DATIME(I,K);
K=I+650*K;
K=VRSION;
SAVWRD(0,K);
if(K != VRSION) goto L8312;
-/* HEREWITH ARE ALL THE VARIABLES WHOSE VALUES CAN CHANGE DURING A GAME,
- * OMITTING A FEW (SUCH AS I, J, ATTACK) WHOSE VALUES BETWEEN TURNS ARE
- * IRRELEVANT AND SOME WHOSE VALUES WHEN A GAME IS
- * SUSPENDED OR RESUMED ARE GUARANTEED TO MATCH. IF UNSURE WHETHER A VALUE
- * NEEDS TO BE SAVED, INCLUDE IT. OVERKILL CAN'T HURT. PAD THE LAST SAVWDS
- * WITH JUNK VARIABLES TO BRING IT UP TO 7 VALUES. */
+/* Herewith are all the variables whose values can change during a game,
+ * omitting a few (such as I, J, ATTACK) whose values between turns are
+ * irrelevant and some whose values when a game is
+ * suspended or resumed are guaranteed to match. if unsure whether a value
+ * needs to be saved, include it. overkill can't hurt. pad the last savwds
+ * with junk variables to bring it up to 7 values. */
SAVWDS(ABBNUM,BLKLIN,BONUS,CLOCK1,CLOCK2,CLOSED,CLOSNG);
SAVWDS(DETAIL,DFLAG,DKILL,DTOTAL,FOOBAR,HOLDNG,IWEST);
SAVWDS(KNFLOC,LIMIT,LL,LMWARN,LOC,NEWLOC,NUMDIE);
RSPEAK(266);
exit(0);
-/* RESUME. READ A SUSPENDED GAME BACK FROM A FILE. */
+/* Resume. Read a suspended game back from a file. */
L8310: KK=1;
if(LOC == 1 && ABB[1] == 1) goto L8305;
L8318: RSPEAK(270);
exit(0);
-/* FLY. SNIDE REMARKS UNLESS HOVERING RUG IS HERE. */
+/* Fly. Snide remarks unless hovering rug is here. */
L8320: if(PROP[RUG] != 2)SPK=224;
if(!HERE(RUG))SPK=225;
RSPEAK(SPK);
return(2);
-/* LISTEN. INTRANSITIVE ONLY. PRINT STUFF BASED ON OBJSND/LOCSND. */
+/* Listen. Intransitive only. Print stuff based on objsnd/locsnd. */
L8330: SPK=228;
K=LOCSND[LOC];
} /* end loop */
return(2011);
-/* Z'ZZZ (WORD GETS RECOMPUTED AT STARTUP; DIFFERENT EACH GAME). */
+/* Z'ZZZ (word gets recomputed at startup; different each game). */
L8340: if(!AT(RESER) && LOC != FIXED[RESER]-1) return(2011);
PSPEAK(RESER,PROP[RESER]+1);
#include "share.h"
#include "funcs.h"
-/* CARRY AN OBJECT. SPECIAL CASES FOR BIRD AND CAGE (IF BIRD IN CAGE, CAN'T
- * TAKE ONE WITHOUT THE OTHER). LIQUIDS ALSO SPECIAL, SINCE THEY DEPEND ON
- * STATUS OF BOTTLE. ALSO VARIOUS SIDE EFFECTS, ETC. */
+/* Carry an object. Special cases for bird and cage (if bird in cage, can't
+ * take one without the other). Liquids also special, since they depend on
+ * status of bottle. Also various side effects, etc. */
int carry(void) {
if(TOTING(OBJ)) return(2011);
return(2011);
}
-/* DISCARD OBJECT. "THROW" ALSO COMES HERE FOR MOST OBJECTS. SPECIAL CASES FOR
- * BIRD (MIGHT ATTACK SNAKE OR DRAGON) AND CAGE (MIGHT CONTAIN BIRD) AND VASE.
- * DROP COINS AT VENDING MACHINE FOR EXTRA BATTERIES. */
+/* Discard object. "Throw" also comes here for most objects. Special cases for
+ * bird (might attack snake or dragon) and cage (might contain bird) and vase.
+ * Drop coins at vending machine for extra batteries. */
int discard(bool just_do_it) {
if(just_do_it) goto L9021;
goto L9021;
}
-/* ATTACK. ASSUME TARGET IF UNAMBIGUOUS. "THROW" ALSO LINKS HERE. ATTACKABLE
- * OBJECTS FALL INTO TWO CATEGORIES: ENEMIES (SNAKE, DWARF, ETC.) AND OTHERS
- * (BIRD, CLAM, MACHINE). AMBIGUOUS IF 2 ENEMIES, OR NO ENEMIES BUT 2 OTHERS. */
+/* Attack. Assume target if unambiguous. "Throw" also links here. Attackable
+ * objects fall into two categories: enemies (snake, dwarf, etc.) and others
+ * (bird, clam, machine). Ambiguous if 2 enemies, or no enemies but 2 others. */
int attack() {
I=ATDWRF(LOC);
if(OBJ == OGRE && I > 0) goto L9128;
if(OBJ == BEAR)SPK=165+(PROP[BEAR]+1)/2;
if(OBJ != DRAGON || PROP[DRAGON] != 0) return(2011);
-/* FUN STUFF FOR DRAGON. IF HE INSISTS ON ATTACKING IT, WIN! SET PROP TO DEAD,
- * MOVE DRAGON TO CENTRAL LOC (STILL FIXED), MOVE RUG THERE (NOT FIXED), AND
- * MOVE HIM THERE, TOO. THEN DO A NULL MOTION TO GET NEW DESCRIPTION. */
+/* Fun stuff for dragon. If he insists on attacking it, win! Set PROP to dead,
+ * move dragon to central loc (still fixed), move rug there (not fixed), and
+ * move him there, too. then do a null motion to get new description. */
RSPEAK(49);
VERB=0;
OBJ=0;
return(2011);
}
-/* THROW. SAME AS DISCARD UNLESS AXE. THEN SAME AS ATTACK EXCEPT IGNORE BIRD,
- * AND IF DWARF IS PRESENT THEN ONE MIGHT BE KILLED. (ONLY WAY TO DO SO!)
- * AXE ALSO SPECIAL FOR DRAGON, BEAR, AND TROLL. TREASURES SPECIAL FOR TROLL. */
+/* Throw. Same as discard unless axe. Then same as attack except ignore bird,
+ * and if dwarf is present then one might be killed. (Only way to do so!)
+ * Axe also special for dragon, bear, and troll. Treasures special for troll. */
int throw() {
if(TOTING(ROD2) && OBJ == ROD && !TOTING(ROD))OBJ=ROD2;
K=NUL;
return(8);
-/* THIS'LL TEACH HIM TO THROW THE AXE AT THE BEAR! */
+/* This'll teach him to throw the axe at the bear! */
L9176: SPK=164;
DROP(AXE,LOC);
FIXED[AXE]= -1;
JUGGLE(BEAR);
return(2011);
-/* BUT THROWING FOOD IS ANOTHER STORY. */
+/* But throwing food is another story. */
L9177: OBJ=BEAR;
return(feed());
L9178: SPK=159;
-/* SNARF A TREASURE FOR THE TROLL. */
+/* Snarf a treasure for the troll. */
DROP(OBJ,0);
MOVE(TROLL,0);
MOVE(TROLL+100,0);
return(2011);
}
-/* FEED. IF BIRD, NO SEED. SNAKE, DRAGON, TROLL: QUIP. IF DWARF, MAKE HIM
- * MAD. BEAR, SPECIAL. */
+/* Feed. If bird, no seed. snake, dragon, troll: quip. If dwarf, make him
+ * mad. Bear, special. */
int feed() {
if(OBJ != BIRD) goto L9212;
return(2011);
}
-/* FILL. BOTTLE OR URN MUST BE EMPTY, AND LIQUID AVAILABLE. (VASE IS NASTY.) */
+/* Fill. Bottle or urn must be empty, and liquid available. (Vase is nasty.) */
int fill() {
if(OBJ == VASE) goto L9222;
#include <stdbool.h>
-/* STATEMENT FUNCTIONS
+/* Statement functions
*
- * AT(OBJ) = TRUE IF ON EITHER SIDE OF TWO-PLACED OBJECT
- * CNDBIT(L,N) = TRUE IF COND(L) HAS BIT N SET (BIT 0 IS UNITS BIT)
- * DARK(DUMMY) = TRUE IF LOCATION "LOC" IS DARK
- * FORCED(LOC) = TRUE IF LOC MOVES WITHOUT ASKING FOR INPUT (COND=2)
- * FOREST(LOC) = TRUE IF LOC IS PART OF THE FOREST
- * GSTONE(OBJ) = TRUE IF OBJ IS A GEMSTONE
- * HERE(OBJ) = TRUE IF THE OBJ IS AT "LOC" (OR IS BEING CARRIED)
- * LIQ(DUMMY) = OBJECT NUMBER OF LIQUID IN BOTTLE
- * LIQLOC(LOC) = OBJECT NUMBER OF LIQUID (IF ANY) AT LOC
- * PCT(N) = TRUE N% OF THE TIME (N INTEGER FROM 0 TO 100)
- * TOTING(OBJ) = TRUE IF THE OBJ IS BEING CARRIED */
+ * AT(OBJ) = true if on either side of two-placed object
+ * CNDBIT(L,N) = true if COND(L) has bit n set (bit 0 is units bit)
+ * DARK(DUMMY) = true if location "LOC" is dark
+ * FORCED(LOC) = true if LOC moves without asking for input (COND=2)
+ * FOREST(LOC) = true if LOC is part of the forest
+ * GSTONE(OBJ) = true if OBJ is a gemstone
+ * HERE(OBJ) = true if the OBJ is at "LOC" (or is being carried)
+ * LIQ(DUMMY) = object number of liquid in bottle
+ * LIQLOC(LOC) = object number of liquid (if any) at LOC
+ * PCT(N) = true N% of the time (N integer from 0 to 100)
+ * TOTING(OBJ) = true if the OBJ is being carried */
#define TOTING(OBJ) (PLACE[OBJ] == -1)
#define AT(OBJ) (PLACE[OBJ] == LOC || FIXED[OBJ] == LOC)
#define FOREST(LOC) ((LOC) >= 145 && (LOC) <= 166)
#define VOCWRD(LETTRS,SECT) (VOCAB(MAKEWD(LETTRS),SECT))
-/* THE FOLLOWING TWO FUNCTIONS WERE ADDED TO FIX A BUG (CLOCK1 DECREMENTED
- * WHILE IN FOREST). THEY SHOULD PROBABLY BE REPLACED BY USING ANOTHER
- * "COND" BIT. FOR NOW, HOWEVER, A QUICK FIX... OUTSID(LOC) IS TRUE IF
- * LOC IS OUTSIDE, INDEEP(LOC) IS TRUE IF LOC IS "DEEP" IN THE CAVE (HALL
- * OF MISTS OR DEEPER). NOTE SPECIAL KLUDGES FOR "FOOF" LOCS. */
+/* The following two functions were added to fix a bug (CLOCK1 decremented
+ * while in forest). They should probably be replaced by using another
+ * "cond" bit. For now, however, a quick fix... OUTSID(LOC) is true if
+ * LOC is outside, INDEEP(LOC) is true if LOC is "deep" in the cave (hall
+ * of mists or deeper). Note special kludges for "FOOF" locs. */
#define OUTSID(LOC) ((LOC) <= 8 || FOREST(LOC) || (LOC) == PLAC[SAPPH] || (LOC) == 180 || (LOC) == 182)
#define INDEEP(LOC) ((LOC) >= 15 && !OUTSID(LOC) && (LOC) != 179)
#include <stdbool.h>
/*
- * INITIALISATION
+ * Initialisation
*/
-/* CURRENT LIMITS:
- * 12500 WORDS OF MESSAGE TEXT (LINES, LINSIZ).
- * 885 TRAVEL OPTIONS (TRAVEL, TRVSIZ).
- * 330 VOCABULARY WORDS (KTAB, ATAB, TABSIZ).
- * 185 LOCATIONS (LTEXT, STEXT, KEY, COND, ABB, ATLOC, LOCSND, LOCSIZ).
- * 100 OBJECTS (PLAC, PLACE, FIXD, FIXED, LINK (TWICE), PTEXT, PROP,
+/* Current limits:
+ * 12500 words of message text (LINES, LINSIZ).
+ * 885 travel options (TRAVEL, TRVSIZ).
+ * 330 vocabulary words (KTAB, ATAB, TABSIZ).
+ * 185 locations (LTEXT, STEXT, KEY, COND, ABB, ATLOC, LOCSND, LOCSIZ).
+ * 100 objects (PLAC, PLACE, FIXD, FIXED, LINK (TWICE), PTEXT, PROP,
* OBJSND, OBJTXT).
- * 35 "ACTION" VERBS (ACTSPK, VRBSIZ).
- * 277 RANDOM MESSAGES (RTEXT, RTXSIZ).
- * 12 DIFFERENT PLAYER CLASSIFICATIONS (CTEXT, CVAL, CLSMAX).
- * 20 HINTS (HINTLC, HINTED, HINTS, HNTSIZ).
- * 5 "# OF TURNS" THRESHHOLDS (TTEXT, TRNVAL, TRNSIZ).
- * THERE ARE ALSO LIMITS WHICH CANNOT BE EXCEEDED DUE TO THE STRUCTURE OF
- * THE DATABASE. (E.G., THE VOCABULARY USES N/1000 TO DETERMINE WORD TYPE,
- * SO THERE CAN'T BE MORE THAN 1000 WORDS.) THESE UPPER LIMITS ARE:
- * 1000 NON-SYNONYMOUS VOCABULARY WORDS
- * 300 LOCATIONS
- * 100 OBJECTS */
-
-
-/* DESCRIPTION OF THE DATABASE FORMAT
+ * 35 "action" verbs (ACTSPK, VRBSIZ).
+ * 277 random messages (RTEXT, RTXSIZ).
+ * 12 different player classifications (CTEXT, CVAL, CLSMAX).
+ * 20 hints (HINTLC, HINTED, HINTS, HNTSIZ).
+ * 5 "# of turns" threshholds (TTEXT, TRNVAL, TRNSIZ).
+ * There are also limits which cannot be exceeded due to the structure of
+ * the database. (E.G., The vocabulary uses n/1000 to determine word type,
+ * so there can't be more than 1000 words.) These upper limits are:
+ * 1000 non-synonymous vocabulary words
+ * 300 locations
+ * 100 objects */
+
+
+/* Description of the database format
*
*
- * THE DATA FILE CONTAINS SEVERAL SECTIONS. EACH BEGINS WITH A LINE CONTAINING
- * A NUMBER IDENTIFYING THE SECTION, AND ENDS WITH A LINE CONTAINING "-1".
+ * The data file contains several sections. each begins with a line containing
+ * a number identifying the section, and ends with a line containing "-1".
*
- * SECTION 1: LONG FORM DESCRIPTIONS. EACH LINE CONTAINS A LOCATION NUMBER,
- * A TAB, AND A LINE OF TEXT. THE SET OF (NECESSARILY ADJACENT) LINES
- * WHOSE NUMBERS ARE X FORM THE LONG DESCRIPTION OF LOCATION X.
- * SECTION 2: SHORT FORM DESCRIPTIONS. SAME FORMAT AS LONG FORM. NOT ALL
- * PLACES HAVE SHORT DESCRIPTIONS.
- * SECTION 3: TRAVEL TABLE. EACH LINE CONTAINS A LOCATION NUMBER (X), A SECOND
- * LOCATION NUMBER (Y), AND A LIST OF MOTION NUMBERS (SEE SECTION 4).
- * EACH MOTION REPRESENTS A VERB WHICH WILL GO TO Y IF CURRENTLY AT X.
- * Y, IN TURN, IS INTERPRETED AS FOLLOWS. LET M=Y/1000, N=Y MOD 1000.
- * IF N<=300 IT IS THE LOCATION TO GO TO.
- * IF 300<N<=500 N-300 IS USED IN A COMPUTED GOTO TO
- * A SECTION OF SPECIAL CODE.
- * IF N>500 MESSAGE N-500 FROM SECTION 6 IS PRINTED,
- * AND HE STAYS WHEREVER HE IS.
- * MEANWHILE, M SPECIFIES THE CONDITIONS ON THE MOTION.
- * IF M=0 IT'S UNCONDITIONAL.
- * IF 0<M<100 IT IS DONE WITH M% PROBABILITY.
- * IF M=100 UNCONDITIONAL, BUT FORBIDDEN TO DWARVES.
- * IF 100<M<=200 HE MUST BE CARRYING OBJECT M-100.
- * IF 200<M<=300 MUST BE CARRYING OR IN SAME ROOM AS M-200.
- * IF 300<M<=400 PROP(M MOD 100) MUST *NOT* BE 0.
- * IF 400<M<=500 PROP(M MOD 100) MUST *NOT* BE 1.
- * IF 500<M<=600 PROP(M MOD 100) MUST *NOT* BE 2, ETC.
- * IF THE CONDITION (IF ANY) IS NOT MET, THEN THE NEXT *DIFFERENT*
- * "DESTINATION" VALUE IS USED (UNLESS IT FAILS TO MEET *ITS* CONDITIONS,
- * IN WHICH CASE THE NEXT IS FOUND, ETC.). TYPICALLY, THE NEXT DEST WILL
- * BE FOR ONE OF THE SAME VERBS, SO THAT ITS ONLY USE IS AS THE ALTERNATE
- * DESTINATION FOR THOSE VERBS. FOR INSTANCE:
+ * Section 1: Long form descriptions. Each line contains a location number,
+ * a tab, and a line of text. The set of (necessarily adjacent) lines
+ * whose numbers are X form the long description of location X.
+ * Section 2: Short form descriptions. Same format as long form. Not all
+ * places have short descriptions.
+ * Section 3: Travel table. Each line contains a location number (X), a second
+ * location number (Y), and a list of motion numbers (see section 4).
+ * each motion represents a verb which will go to Y if currently at X.
+ * Y, in turn, is interpreted as follows. Let M=Y/1000, N=Y mod 1000.
+ * If N<=300 it is the location to go to.
+ * If 300<N<=500 N-300 is used in a computed goto to
+ * a section of special code.
+ * If N>500 message N-500 from section 6 is printed,
+ * and he stays wherever he is.
+ * Meanwhile, M specifies the conditions on the motion.
+ * If M=0 it's unconditional.
+ * If 0<M<100 it is done with M% probability.
+ * If M=100 unconditional, but forbidden to dwarves.
+ * If 100<M<=200 he must be carrying object M-100.
+ * If 200<M<=300 must be carrying or in same room as M-200.
+ * If 300<M<=400 PROP(M % 100) must *not* be 0.
+ * If 400<M<=500 PROP(M % 100) must *not* be 1.
+ * If 500<M<=600 PROP(M % 100) must *not* be 2, etc.
+ * If the condition (if any) is not met, then the next *different*
+ * "destination" value is used (unless it fails to meet *its* conditions,
+ * in which case the next is found, etc.). Typically, the next dest will
+ * be for one of the same verbs, so that its only use is as the alternate
+ * destination for those verbs. For instance:
* 15 110022 29 31 34 35 23 43
* 15 14 29
- * THIS SAYS THAT, FROM LOC 15, ANY OF THE VERBS 29, 31, ETC., WILL TAKE
- * HIM TO 22 IF HE'S CARRYING OBJECT 10, AND OTHERWISE WILL GO TO 14.
+ * This says that, from loc 15, any of the verbs 29, 31, etc., will take
+ * him to 22 if he's carrying object 10, and otherwise will go to 14.
* 11 303008 49
* 11 9 50
- * THIS SAYS THAT, FROM 11, 49 TAKES HIM TO 8 UNLESS PROP(3)=0, IN WHICH
- * CASE HE GOES TO 9. VERB 50 TAKES HIM TO 9 REGARDLESS OF PROP(3).
- * SECTION 4: VOCABULARY. EACH LINE CONTAINS A NUMBER (N), A TAB, AND A
- * FIVE-LETTER WORD. CALL M=N/1000. IF M=0, THEN THE WORD IS A MOTION
- * VERB FOR USE IN TRAVELLING (SEE SECTION 3). ELSE, IF M=1, THE WORD IS
- * AN OBJECT. ELSE, IF M=2, THE WORD IS AN ACTION VERB (SUCH AS "CARRY"
- * OR "ATTACK"). ELSE, IF M=3, THE WORD IS A SPECIAL CASE VERB (SUCH AS
- * "DIG") AND N MOD 1000 IS AN INDEX INTO SECTION 6. OBJECTS FROM 50 TO
- * (CURRENTLY, ANYWAY) 79 ARE CONSIDERED TREASURES (FOR PIRATE, CLOSEOUT).
- * SECTION 5: OBJECT DESCRIPTIONS. EACH LINE CONTAINS A NUMBER (N), A TAB,
- * AND A MESSAGE. IF N IS FROM 1 TO 100, THE MESSAGE IS THE "INVENTORY"
- * MESSAGE FOR OBJECT N. OTHERWISE, N SHOULD BE 000, 100, 200, ETC., AND
- * THE MESSAGE SHOULD BE THE DESCRIPTION OF THE PRECEDING OBJECT WHEN ITS
- * PROP VALUE IS N/100. THE N/100 IS USED ONLY TO DISTINGUISH MULTIPLE
- * MESSAGES FROM MULTI-LINE MESSAGES; THE PROP INFO ACTUALLY REQUIRES ALL
- * MESSAGES FOR AN OBJECT TO BE PRESENT AND CONSECUTIVE. PROPERTIES WHICH
- * PRODUCE NO MESSAGE SHOULD BE GIVEN THE MESSAGE ">$<".
- * SECTION 6: ARBITRARY MESSAGES. SAME FORMAT AS SECTIONS 1, 2, AND 5, EXCEPT
- * THE NUMBERS BEAR NO RELATION TO ANYTHING (EXCEPT FOR SPECIAL VERBS
- * IN SECTION 4).
- * SECTION 7: OBJECT LOCATIONS. EACH LINE CONTAINS AN OBJECT NUMBER AND ITS
- * INITIAL LOCATION (ZERO (OR OMITTED) IF NONE). IF THE OBJECT IS
- * IMMOVABLE, THE LOCATION IS FOLLOWED BY A "-1". IF IT HAS TWO LOCATIONS
- * (E.G. THE GRATE) THE FIRST LOCATION IS FOLLOWED WITH THE SECOND, AND
- * THE OBJECT IS ASSUMED TO BE IMMOVABLE.
- * SECTION 8: ACTION DEFAULTS. EACH LINE CONTAINS AN "ACTION-VERB" NUMBER AND
- * THE INDEX (IN SECTION 6) OF THE DEFAULT MESSAGE FOR THE VERB.
- * SECTION 9: LOCATION ATTRIBUTES. EACH LINE CONTAINS A NUMBER (N) AND UP TO
- * 20 LOCATION NUMBERS. BIT N (WHERE 0 IS THE UNITS BIT) IS SET IN
- * COND(LOC) FOR EACH LOC GIVEN. THE COND BITS CURRENTLY ASSIGNED ARE:
- * 0 LIGHT
- * 1 IF BIT 2 IS ON: ON FOR OIL, OFF FOR WATER
- * 2 LIQUID ASSET, SEE BIT 1
- * 3 PIRATE DOESN'T GO HERE UNLESS FOLLOWING PLAYER
- * 4 CANNOT USE "BACK" TO MOVE AWAY
- * BITS PAST 10 INDICATE AREAS OF INTEREST TO "HINT" ROUTINES:
- * 11 TRYING TO GET INTO CAVE
- * 12 TRYING TO CATCH BIRD
- * 13 TRYING TO DEAL WITH SNAKE
- * 14 LOST IN MAZE
- * 15 PONDERING DARK ROOM
- * 16 AT WITT'S END
- * 17 CLIFF WITH URN
- * 18 LOST IN FOREST
- * 19 TRYING TO DEAL WITH OGRE
- * 20 FOUND ALL TREASURES EXCEPT JADE
- * COND(LOC) IS SET TO 2, OVERRIDING ALL OTHER BITS, IF LOC HAS FORCED
- * MOTION.
- * SECTION 10: CLASS MESSAGES. EACH LINE CONTAINS A NUMBER (N), A TAB, AND A
- * MESSAGE DESCRIBING A CLASSIFICATION OF PLAYER. THE SCORING SECTION
- * SELECTS THE APPROPRIATE MESSAGE, WHERE EACH MESSAGE IS CONSIDERED TO
- * APPLY TO PLAYERS WHOSE SCORES ARE HIGHER THAN THE PREVIOUS N BUT NOT
- * HIGHER THAN THIS N. NOTE THAT THESE SCORES PROBABLY CHANGE WITH EVERY
- * MODIFICATION (AND PARTICULARLY EXPANSION) OF THE PROGRAM.
- * SECTION 11: HINTS. EACH LINE CONTAINS A HINT NUMBER (ADD 10 TO GET COND
- * BIT; SEE SECTION 9), THE NUMBER OF TURNS HE MUST BE AT THE RIGHT LOC(S)
- * BEFORE TRIGGERING THE HINT, THE POINTS DEDUCTED FOR TAKING THE HINT,
- * THE MESSAGE NUMBER (SECTION 6) OF THE QUESTION, AND THE MESSAGE NUMBER
- * OF THE HINT. THESE VALUES ARE STASHED IN THE "HINTS" ARRAY. HNTMAX IS
- * SET TO THE MAX HINT NUMBER (<= HNTSIZ).
- * SECTION 12: UNUSED IN THIS VERSION.
- * SECTION 13: SOUNDS AND TEXT. EACH LINE CONTAINS EITHER 2 OR 3 NUMBERS. IF
- * 2 (CALL THEM N AND S), N IS A LOCATION AND MESSAGE ABS(S) FROM SECTION
- * 6 IS THE SOUND HEARD THERE. IF S<0, THE SOUND THERE DROWNS OUT ALL
- * OTHER NOISES. IF 3 NUMBERS (CALL THEM N, S, AND T), N IS AN OBJECT
- * NUMBER AND S+PROP(N) IS THE PROPERTY MESSAGE (FROM SECTION 5) IF HE
- * LISTENS TO THE OBJECT, AND T+PROP(N) IS THE TEXT IF HE READS IT. IF
- * S OR T IS -1, THE OBJECT HAS NO SOUND OR TEXT, RESPECTIVELY. NEITHER
- * S NOR T IS ALLOWED TO BE 0.
- * SECTION 14: TURN THRESHHOLDS. EACH LINE CONTAINS A NUMBER (N), A TAB, AND
- * A MESSAGE BERATING THE PLAYER FOR TAKING SO MANY TURNS. THE MESSAGES
- * MUST BE IN THE PROPER (ASCENDING) ORDER. THE MESSAGE GETS PRINTED IF
- * THE PLAYER EXCEEDS N MOD 100000 TURNS, AT WHICH TIME N/100000 POINTS
- * GET DEDUCTED FROM HIS SCORE.
- * SECTION 0: END OF DATABASE. */
-
-/* THE VARIOUS MESSAGES (SECTIONS 1, 2, 5, 6, ETC.) MAY INCLUDE CERTAIN
- * SPECIAL CHARACTER SEQUENCES TO DENOTE THAT THE PROGRAM MUST PROVIDE
- * PARAMETERS TO INSERT INTO A MESSAGE WHEN THE MESSAGE IS PRINTED. THESE
- * SEQUENCES ARE:
- * %S = THE LETTER 'S' OR NOTHING (IF A GIVEN VALUE IS EXACTLY 1)
- * %W = A WORD (UP TO 10 CHARACTERS)
- * %L = A WORD MAPPED TO LOWER-CASE LETTERS
- * %U = A WORD MAPPED TO UPPER-CASE LETTERS
- * %C = A WORD MAPPED TO LOWER-CASE, FIRST LETTER CAPITALISED
- * %T = SEVERAL WORDS OF TEXT, ENDING WITH A WORD OF -1
- * %1 = A 1-DIGIT NUMBER
- * %2 = A 2-DIGIT NUMBER
+ * This says that, from 11, 49 takes him to 8 unless PROP(3)=0, in which
+ * case he goes to 9. Verb 50 takes him to 9 regardless of PROP(3).
+ * Section 4: Vocabulary. Each line contains a number (n), a tab, and a
+ * five-letter word. Call M=N/1000. If M=0, then the word is a motion
+ * verb for use in travelling (see section 3). Else, if M=1, the word is
+ * an object. Else, if M=2, the word is an action verb (such as "carry"
+ * or "attack"). Else, if M=3, the word is a special case verb (such as
+ * "dig") and N % 1000 is an index into section 6. Objects from 50 to
+ * (currently, anyway) 79 are considered treasures (for pirate, closeout).
+ * Section 5: Object descriptions. Each line contains a number (N), a tab,
+ * and a message. If N is from 1 to 100, the message is the "inventory"
+ * message for object n. Otherwise, N should be 000, 100, 200, etc., and
+ * the message should be the description of the preceding object when its
+ * prop value is N/100. The N/100 is used only to distinguish multiple
+ * messages from multi-line messages; the prop info actually requires all
+ * messages for an object to be present and consecutive. Properties which
+ * produce no message should be given the message ">$<".
+ * Section 6: Arbitrary messages. Same format as sections 1, 2, and 5, except
+ * the numbers bear no relation to anything (except for special verbs
+ * in section 4).
+ * Section 7: Object locations. Each line contains an object number and its
+ * initial location (zero (or omitted) if none). If the object is
+ * immovable, the location is followed by a "-1". If it has two locations
+ * (e.g. the grate) the first location is followed with the second, and
+ * the object is assumed to be immovable.
+ * Section 8: Action defaults. Each line contains an "action-verb" number and
+ * the index (in section 6) of the default message for the verb.
+ * Section 9: Location attributes. Each line contains a number (n) and up to
+ * 20 location numbers. Bit N (where 0 is the units bit) is set in
+ * COND(LOC) for each loc given. The cond bits currently assigned are:
+ * 0 Light
+ * 1 If bit 2 is on: on for oil, off for water
+ * 2 Liquid asset, see bit 1
+ * 3 Pirate doesn't go here unless following player
+ * 4 Cannot use "back" to move away
+ * Bits past 10 indicate areas of interest to "hint" routines:
+ * 11 Trying to get into cave
+ * 12 Trying to catch bird
+ * 13 Trying to deal with snake
+ * 14 Lost in maze
+ * 15 Pondering dark room
+ * 16 At witt's end
+ * 17 Cliff with urn
+ * 18 Lost in forest
+ * 19 Trying to deal with ogre
+ * 20 Found all treasures except jade
+ * COND(LOC) is set to 2, overriding all other bits, if loc has forced
+ * motion.
+ * Section 10: Class messages. Each line contains a number (n), a tab, and a
+ * message describing a classification of player. The scoring section
+ * selects the appropriate message, where each message is considered to
+ * apply to players whose scores are higher than the previous N but not
+ * higher than this N. Note that these scores probably change with every
+ * modification (and particularly expansion) of the program.
+ * SECTION 11: Hints. Each line contains a hint number (add 10 to get cond
+ * bit; see section 9), the number of turns he must be at the right loc(s)
+ * before triggering the hint, the points deducted for taking the hint,
+ * the message number (section 6) of the question, and the message number
+ * of the hint. These values are stashed in the "hints" array. HNTMAX is
+ * set to the max hint number (<= HNTSIZ).
+ * Section 12: Unused in this version.
+ * Section 13: Sounds and text. Each line contains either 2 or 3 numbers. If
+ * 2 (call them N and S), N is a location and message ABS(S) from section
+ * 6 is the sound heard there. If S<0, the sound there drowns out all
+ * other noises. If 3 numbers (call them N, S, and T), N is an object
+ * number and S+PROP(N) is the property message (from section 5) if he
+ * listens to the object, and T+PROP(N) is the text if he reads it. If
+ * S or T is -1, the object has no sound or text, respectively. Neither
+ * S nor T is allowed to be 0.
+ * Section 14: Turn threshholds. Each line contains a number (N), a tab, and
+ * a message berating the player for taking so many turns. The messages
+ * must be in the proper (ascending) order. The message gets printed if
+ * the player exceeds N % 100000 turns, at which time N/100000 points
+ * get deducted from his score.
+ * Section 0: End of database. */
+
+/* The various messages (sections 1, 2, 5, 6, etc.) may include certain
+ * special character sequences to denote that the program must provide
+ * parameters to insert into a message when the message is printed. these
+ * sequences are:
+ * %S = The letter 'S' or nothing (if a given value is exactly 1)
+ * %W = A word (up to 10 characters)
+ * %L = A word mapped to lower-case letters
+ * %U = A word mapped to upper-case letters
+ * %C = A word mapped to lower-case, first letter capitalised
+ * %T = Several words of text, ending with a word of -1
+ * %1 = A 1-digit number
+ * %2 = A 2-digit number
* ...
- * %9 = A 9-DIGIT NUMBER
- * %B = VARIABLE NUMBER OF BLANKS
- * %! = THE ENTIRE MESSAGE SHOULD BE SUPPRESSED */
+ * %9 = A 9-digit number
+ * %B = Variable number of blanks
+ * %! = The entire message should be suppressed */
static bool quick_init(void);
static int raw_init(void);
static int raw_init(void) {
printf("Couldn't find adventure.data, using adventure.text...\n");
-/* CLEAR OUT THE VARIOUS TEXT-POINTER ARRAYS. ALL TEXT IS STORED IN ARRAY
- * LINES; EACH LINE IS PRECEDED BY A WORD POINTING TO THE NEXT POINTER (I.E.
- * THE WORD FOLLOWING THE END OF THE LINE). THE POINTER IS NEGATIVE IF THIS IS
- * FIRST LINE OF A MESSAGE. THE TEXT-POINTER ARRAYS CONTAIN INDICES OF
- * POINTER-WORDS IN LINES. STEXT(N) IS SHORT DESCRIPTION OF LOCATION N.
- * LTEXT(N) IS LONG DESCRIPTION. PTEXT(N) POINTS TO MESSAGE FOR PROP(N)=0.
- * SUCCESSIVE PROP MESSAGES ARE FOUND BY CHASING POINTERS. RTEXT CONTAINS
- * SECTION 6'S STUFF. CTEXT(N) POINTS TO A PLAYER-CLASS MESSAGE. TTEXT IS FOR
- * SECTION 14. WE ALSO CLEAR COND (SEE DESCRIPTION OF SECTION 9 FOR DETAILS). */
+/* Clear out the various text-pointer arrays. All text is stored in array
+ * lines; each line is preceded by a word pointing to the next pointer (i.e.
+ * the word following the end of the line). The pointer is negative if this is
+ * first line of a message. The text-pointer arrays contain indices of
+ * pointer-words in lines. STEXT(N) is short description of location N.
+ * LTEXT(N) is long description. PTEXT(N) points to message for PROP(N)=0.
+ * Successive prop messages are found by chasing pointers. RTEXT contains
+ * section 6's stuff. CTEXT(N) points to a player-class message. TTEXT is for
+ * section 14. We also clear COND (see description of section 9 for details). */
/* 1001 */ for (I=1; I<=300; I++) {
if(I <= 100)PTEXT[I]=0;
CLSSES=0;
TRNVLS=0;
-/* START NEW DATA SECTION. SECT IS THE SECTION NUMBER. */
+/* Start new data section. sect is the section number. */
L1002: SECT=GETNUM(1);
OLDLOC= -1;
* (10) (11) (12) (13) (14) */
BUG(9);
-/* SECTIONS 1, 2, 5, 6, 10, 14. READ MESSAGES AND SET UP POINTERS. */
+/* Sections 1, 2, 5, 6, 10, 14. Read messages and set up pointers. */
L1004: KK=LINUSE;
L1005: LINUSE=KK;
TRNVAL[TRNVLS]=LOC;
goto L1005;
-/* THE STUFF FOR SECTION 3 IS ENCODED HERE. EACH "FROM-LOCATION" GETS A
- * CONTIGUOUS SECTION OF THE "TRAVEL" ARRAY. EACH ENTRY IN TRAVEL IS
- * NEWLOC*1000 + KEYWORD (FROM SECTION 4, MOTION VERBS), AND IS NEGATED IF
- * THIS IS THE LAST ENTRY FOR THIS LOCATION. KEY(N) IS THE INDEX IN TRAVEL
- * OF THE FIRST OPTION AT LOCATION N. */
+/* The stuff for section 3 is encoded here. Each "from-location" gets a
+ * contiguous section of the "TRAVEL" array. each entry in travel is
+ * NEWLOC*1000 + KEYWORD (from section 4, motion verbs), and is negated if
+ * this is the last entry for this location. KEY(N) is the index in travel
+ * of the first option at location N. */
L1030: LOC=GETNUM(1);
if(LOC == -1) goto L1002;
L1039: TRVS--; TRAVEL[TRVS]= -TRAVEL[TRVS]; TRVS++;
goto L1030;
-/* HERE WE READ IN THE VOCABULARY. KTAB(N) IS THE WORD NUMBER, ATAB(N) IS
- * THE CORRESPONDING WORD. THE -1 AT THE END OF SECTION 4 IS LEFT IN KTAB
- * AS AN END-MARKER. THE WORDS ARE GIVEN A MINIMAL HASH TO MAKE DECIPHERING
- * THE CORE-IMAGE HARDER. (WE DON'T USE GETTXT'S HASH SINCE THAT WOULD FORCE
- * US TO HASH EACH INPUT LINE TO MAKE COMPARISONS WORK, AND THAT IN TURN
- * WOULD MAKE IT HARDER TO DETECT PARTICULAR INPUT WORDS.) */
+/* Here we read in the vocabulary. KTAB(N) is the word number, ATAB(N) is
+ * the corresponding word. The -1 at the end of section 4 is left in KTAB
+ * as an end-marker. The words are given a minimal hash to make deciphering
+ * the core-image harder. (We don't use gettxt's hash since that would force
+ * us to hash each input line to make comparisons work, and that in turn
+ * would make it harder to detect particular input words.) */
L1040: J=10000;
/* 1042 */ for (TABNDX=1; TABNDX<=TABSIZ; TABNDX++) {
} /* end loop */
BUG(4);
-/* READ IN THE INITIAL LOCATIONS FOR EACH OBJECT. ALSO THE IMMOVABILITY INFO.
- * PLAC CONTAINS INITIAL LOCATIONS OF OBJECTS. FIXD IS -1 FOR IMMOVABLE
- * OBJECTS (INCLUDING THE SNAKE), OR = SECOND LOC FOR TWO-PLACED OBJECTS. */
+/* Read in the initial locations for each object. Also the immovability info.
+ * plac contains initial locations of objects. FIXD is -1 for immovable
+ * objects (including the snake), or = second loc for two-placed objects. */
L1050: OBJ=GETNUM(1);
if(OBJ == -1) goto L1002;
FIXD[OBJ]=GETNUM(0);
goto L1050;
-/* READ DEFAULT MESSAGE NUMBERS FOR ACTION VERBS, STORE IN ACTSPK. */
+/* Read default message numbers for action verbs, store in ACTSPK. */
L1060: VERB=GETNUM(1);
if(VERB == -1) goto L1002;
ACTSPK[VERB]=GETNUM(0);
goto L1060;
-/* READ INFO ABOUT AVAILABLE LIQUIDS AND OTHER CONDITIONS, STORE IN COND. */
+/* Read info about available liquids and other conditions, store in COND. */
L1070: K=GETNUM(1);
if(K == -1) goto L1002;
COND[LOC]=COND[LOC]+SETBIT(K);
goto L1071;
-/* READ DATA FOR HINTS. */
+/* Read data for hints. */
L1080: HNTMAX=0;
L1081: K=GETNUM(1);
HNTMAX=(HNTMAX>K ? HNTMAX : K);
goto L1081;
-/* READ THE SOUND/TEXT INFO, STORE IN OBJSND, OBJTXT, LOCSND. */
+/* Read the sound/text info, store in OBJSND, OBJTXT, LOCSND. */
L1090: K=GETNUM(1);
if(K == -1) goto L1002;
goto L1090;
}
-/* FINISH CONSTRUCTING INTERNAL DATA FORMAT */
+/* Finish constructing internal data format */
-/* HAVING READ IN THE DATABASE, CERTAIN THINGS ARE NOW CONSTRUCTED. PROPS ARE
- * SET TO ZERO. WE FINISH SETTING UP COND BY CHECKING FOR FORCED-MOTION TRAVEL
- * ENTRIES. THE PLAC AND FIXD ARRAYS ARE USED TO SET UP ATLOC(N) AS THE FIRST
- * OBJECT AT LOCATION N, AND LINK(OBJ) AS THE NEXT OBJECT AT THE SAME LOCATION
- * AS OBJ. (OBJ>100 INDICATES THAT FIXED(OBJ-100)=LOC; LINK(OBJ) IS STILL THE
- * CORRECT LINK TO USE.) ABB IS ZEROED; IT CONTROLS WHETHER THE ABBREVIATED
- * DESCRIPTION IS PRINTED. COUNTS MOD 5 UNLESS "LOOK" IS USED. */
+/* Having read in the database, certain things are now constructed. PROPS are
+ * set to zero. We finish setting up COND by checking for forced-motion travel
+ * entries. The PLAC and FIXD arrays are used to set up ATLOC(N) as the first
+ * object at location N, and LINK(OBJ) as the next object at the same location
+ * as OBJ. (OBJ>100 indicates that FIXED(OBJ-100)=LOC; LINK(OBJ) is still the
+ * correct link to use.) ABB is zeroed; it controls whether the abbreviated
+ * description is printed. Counts modulo 5 unless "LOOK" is used. */
static int finish_init(void) {
/* 1101 */ for (I=1; I<=100; I++) {
L1102: ATLOC[I]=0;
} /* end loop */
-/* SET UP THE ATLOC AND LINK ARRAYS AS DESCRIBED ABOVE. WE'LL USE THE DROP
- * SUBROUTINE, WHICH PREFACES NEW OBJECTS ON THE LISTS. SINCE WE WANT THINGS
- * IN THE OTHER ORDER, WE'LL RUN THE LOOP BACKWARDS. IF THE OBJECT IS IN TWO
- * LOCS, WE DROP IT TWICE. THIS ALSO SETS UP "PLACE" AND "FIXED" AS COPIES OF
- * "PLAC" AND "FIXD". ALSO, SINCE TWO-PLACED OBJECTS ARE TYPICALLY BEST
- * DESCRIBED LAST, WE'LL DROP THEM FIRST. */
+/* Set up the ATLOC and LINK arrays as described above. We'll use the DROP
+ * subroutine, which prefaces new objects on the lists. Since we want things
+ * in the other order, we'll run the loop backwards. If the object is in two
+ * locs, we drop it twice. This also sets up "PLACE" and "fixed" as copies of
+ * "PLAC" and "FIXD". Also, since two-placed objects are typically best
+ * described last, we'll drop them first. */
/* 1106 */ for (I=1; I<=100; I++) {
K=101-I;
L1107: if(PLAC[K] != 0 && FIXD[K] <= 0)DROP(K,PLAC[K]);
} /* end loop */
-/* TREASURES, AS NOTED EARLIER, ARE OBJECTS 50 THROUGH MAXTRS (CURRENTLY 79).
- * THEIR PROPS ARE INITIALLY -1, AND ARE SET TO 0 THE FIRST TIME THEY ARE
- * DESCRIBED. TALLY KEEPS TRACK OF HOW MANY ARE NOT YET FOUND, SO WE KNOW
- * WHEN TO CLOSE THE CAVE. */
+/* Treasures, as noted earlier, are objects 50 through MAXTRS (CURRENTLY 79).
+ * Their props are initially -1, and are set to 0 the first time they are
+ * described. TALLY keeps track of how many are not yet found, so we know
+ * when to close the cave. */
MAXTRS=79;
TALLY=0;
L1200: TALLY=TALLY-PROP[I];
} /* end loop */
-/* CLEAR THE HINT STUFF. HINTLC(I) IS HOW LONG HE'S BEEN AT LOC WITH COND BIT
- * I. HINTED(I) IS TRUE IFF HINT I HAS BEEN USED. */
+/* Clear the hint stuff. HINTLC(I) is how long he's been at LOC with cond bit
+ * I. HINTED(I) is true iff hint I has been used. */
/* 1300 */ for (I=1; I<=HNTMAX; I++) {
HINTED[I]=false;
L1300: HINTLC[I]=0;
} /* end loop */
-/* DEFINE SOME HANDY MNEMONICS. THESE CORRESPOND TO OBJECT NUMBERS. */
+/* Define some handy mnemonics. these correspond to object numbers. */
AXE=VOCWRD(12405,1);
BATTER=VOCWRD(201202005,1);
VOLCAN=VOCWRD(1765120301,1);
WATER=VOCWRD(1851200518,1);
-/* OBJECTS FROM 50 THROUGH WHATEVER ARE TREASURES. HERE ARE A FEW. */
+/* Objects from 50 through whatever are treasures. Here are a few. */
AMBER=VOCWRD(113020518,1);
CHAIN=VOCWRD(308010914,1);
TRIDNT=VOCWRD(2018090405,1);
VASE=VOCWRD(22011905,1);
-/* THESE ARE MOTION-VERB NUMBERS. */
+/* These are motion-verb numbers. */
BACK=VOCWRD(2010311,0);
CAVE=VOCWRD(3012205,0);
NUL=VOCWRD(14211212,0);
STREAM=VOCWRD(1920180501,0);
-/* AND SOME ACTION VERBS. */
+/* And some action verbs. */
FIND=VOCWRD(6091404,2);
INVENT=VOCWRD(914220514,2);
SAY=VOCWRD(190125,2);
THROW=VOCWRD(2008181523,2);
-/* INITIALISE THE DWARVES. DLOC IS LOC OF DWARVES, HARD-WIRED IN. ODLOC IS
- * PRIOR LOC OF EACH DWARF, INITIALLY GARBAGE. DALTLC IS ALTERNATE INITIAL LOC
- * FOR DWARF, IN CASE ONE OF THEM STARTS OUT ON TOP OF THE ADVENTURER. (NO 2
- * OF THE 5 INITIAL LOCS ARE ADJACENT.) DSEEN IS TRUE IF DWARF HAS SEEN HIM.
- * DFLAG CONTROLS THE LEVEL OF ACTIVATION OF ALL THIS:
- * 0 NO DWARF STUFF YET (WAIT UNTIL REACHES HALL OF MISTS)
- * 1 REACHED HALL OF MISTS, BUT HASN'T MET FIRST DWARF
- * 2 MET FIRST DWARF, OTHERS START MOVING, NO KNIVES THROWN YET
- * 3 A KNIFE HAS BEEN THROWN (FIRST SET ALWAYS MISSES)
- * 3+ DWARVES ARE MAD (INCREASES THEIR ACCURACY)
- * SIXTH DWARF IS SPECIAL (THE PIRATE). HE ALWAYS STARTS AT HIS CHEST'S
- * EVENTUAL LOCATION INSIDE THE MAZE. THIS LOC IS SAVED IN CHLOC FOR REF.
- * THE DEAD END IN THE OTHER MAZE HAS ITS LOC STORED IN CHLOC2. */
+/* Initialise the dwarves. DLOC is loc of dwarves, hard-wired in. ODLOC is
+ * prior loc of each dwarf, initially garbage. DALTLC is alternate initial loc
+ * for dwarf, in case one of them starts out on top of the adventurer. (No 2
+ * of the 5 initial locs are adjacent.) DSEEN is true if dwarf has seen him.
+ * DFLAG controls the level of activation of all this:
+ * 0 No dwarf stuff yet (wait until reaches Hall Of Mists)
+ * 1 Reached Hall Of Mists, but hasn't met first dwarf
+ * 2 Met first dwarf, others start moving, no knives thrown yet
+ * 3 A knife has been thrown (first set always misses)
+ * 3+ Dwarves are mad (increases their accuracy)
+ * Sixth dwarf is special (the pirate). He always starts at his chest's
+ * eventual location inside the maze. This loc is saved in CHLOC for ref.
+ * the dead end in the other maze has its loc stored in CHLOC2. */
CHLOC=114;
CHLOC2=140;
DLOC[6]=CHLOC;
DALTLC=18;
-/* OTHER RANDOM FLAGS AND COUNTERS, AS FOLLOWS:
- * ABBNUM HOW OFTEN WE SHOULD PRINT NON-ABBREVIATED DESCRIPTIONS
- * BONUS USED TO DETERMINE AMOUNT OF BONUS IF HE REACHES CLOSING
- * CLOCK1 NUMBER OF TURNS FROM FINDING LAST TREASURE TILL CLOSING
- * CLOCK2 NUMBER OF TURNS FROM FIRST WARNING TILL BLINDING FLASH
- * CONDS MIN VALUE FOR COND(LOC) IF LOC HAS ANY HINTS
- * DETAIL HOW OFTEN WE'VE SAID "NOT ALLOWED TO GIVE MORE DETAIL"
- * DKILL NUMBER OF DWARVES KILLED (UNUSED IN SCORING, NEEDED FOR MSG)
- * FOOBAR CURRENT PROGRESS IN SAYING "FEE FIE FOE FOO".
- * HOLDNG NUMBER OF OBJECTS BEING CARRIED
- * IGO HOW MANY TIMES HE'S SAID "GO XXX" INSTEAD OF "XXX"
- * IWEST HOW MANY TIMES HE'S SAID "WEST" INSTEAD OF "W"
- * KNFLOC 0 IF NO KNIFE HERE, LOC IF KNIFE HERE, -1 AFTER CAVEAT
- * LIMIT LIFETIME OF LAMP (NOT SET HERE)
- * MAXDIE NUMBER OF REINCARNATION MESSAGES AVAILABLE (UP TO 5)
- * NUMDIE NUMBER OF TIMES KILLED SO FAR
- * THRESH NEXT #TURNS THRESHHOLD (-1 IF NONE)
- * TRNDEX INDEX IN TRNVAL OF NEXT THRESHHOLD (SECTION 14 OF DATABASE)
- * TRNLUZ # POINTS LOST SO FAR DUE TO NUMBER OF TURNS USED
- * TURNS TALLIES HOW MANY COMMANDS HE'S GIVEN (IGNORES YES/NO)
- * LOGICALS WERE EXPLAINED EARLIER */
+/* Other random flags and counters, as follows:
+ * ABBNUM How often we should print non-abbreviated descriptions
+ * BONUS Used to determine amount of bonus if he reaches closing
+ * CLOCK1 Number of turns from finding last treasure till closing
+ * CLOCK2 Number of turns from first warning till blinding flash
+ * CONDS Min value for cond(loc) if loc has any hints
+ * DETAIL How often we've said "not allowed to give more detail"
+ * DKILL Number of dwarves killed (unused in scoring, needed for msg)
+ * FOOBAR Current progress in saying "FEE FIE FOE FOO".
+ * HOLDNG Number of objects being carried
+ * IGO How many times he's said "go XXX" instead of "XXX"
+ * IWEST How many times he's said "west" instead of "w"
+ * KNFLOC 0 if no knife here, loc if knife here, -1 after caveat
+ * LIMIT Lifetime of lamp (not set here)
+ * MAXDIE Number of reincarnation messages available (up to 5)
+ * NUMDIE Number of times killed so far
+ * THRESH Next #turns threshhold (-1 if none)
+ * TRNDEX Index in TRNVAL of next threshhold (section 14 of database)
+ * TRNLUZ # points lost so far due to number of turns used
+ * TURNS Tallies how many commands he's given (ignores yes/no)
+ * Logicals were explained earlier */
TURNS=0;
TRNDEX=1;
return(0); /* then we won't actually return from initialisation */
}
-/* REPORT ON AMOUNT OF ARRAYS ACTUALLY USED, TO PERMIT REDUCTIONS. */
+/* Report on amount of arrays actually used, to permit reductions. */
static void report(void) {
/* 1998 */ for (K=1; K<=LOCSIZ; K++) {
int main(int argc, char *argv[]) {
-/* ADVENTURE (REV 2: 20 TREASURES) */
+/* Adventure (rev 2: 20 treasures) */
-/* HISTORY: ORIGINAL IDEA & 5-TREASURE VERSION (ADVENTURES) BY WILLIE CROWTHER
- * 15-TREASURE VERSION (ADVENTURE) BY DON WOODS, APRIL-JUNE 1977
- * 20-TREASURE VERSION (REV 2) BY DON WOODS, AUGUST 1978
- * ERRATA FIXED: 78/12/25 */
+/* History: Original idea & 5-treasure version (adventures) by Willie Crowther
+ * 15-treasure version (adventure) by Don Woods, April-June 1977
+ * 20-treasure version (rev 2) by Don Woods, August 1978
+ * Errata fixed: 78/12/25 */
-/* LOGICAL VARIABLES:
+/* Logical variables:
*
- * CLOSED SAYS WHETHER WE'RE ALL THE WAY CLOSED
- * CLOSNG SAYS WHETHER IT'S CLOSING TIME YET
- * CLSHNT SAYS WHETHER HE'S READ THE CLUE IN THE ENDGAME
- * LMWARN SAYS WHETHER HE'S BEEN WARNED ABOUT LAMP GOING DIM
- * NOVICE SAYS WHETHER HE ASKED FOR INSTRUCTIONS AT START-UP
- * PANIC SAYS WHETHER HE'S FOUND OUT HE'S TRAPPED IN THE CAVE
- * WZDARK SAYS WHETHER THE LOC HE'S LEAVING WAS DARK */
+ * CLOSED says whether we're all the way closed
+ * CLOSNG says whether it's closing time yet
+ * CLSHNT says whether he's read the clue in the endgame
+ * LMWARN says whether he's been warned about lamp going dim
+ * NOVICE says whether he asked for instructions at start-up
+ * PANIC says whether he's found out he's trapped in the cave
+ * WZDARK says whether the loc he's leaving was dark */
#include "funcs.h"
-/* READ THE DATABASE IF WE HAVE NOT YET DONE SO */
+/* Read the database if we have not yet done so */
LINES = (long *)calloc(LINSIZ+1,sizeof(long));
if(!LINES){
if(!SETUP)initialise();
if(SETUP > 0) goto L1;
-/* UNLIKE EARLIER VERSIONS, ADVENTURE IS NO LONGER RESTARTABLE. (THIS
- * LETS US GET AWAY WITH MODIFYING THINGS SUCH AS OBJSND(BIRD) WITHOUT
- * HAVING TO BE ABLE TO UNDO THE CHANGES LATER.) IF A "USED" COPY IS
- * RERUN, WE COME HERE AND TELL THE PLAYER TO RUN A FRESH COPY. */
+/* Unlike earlier versions, adventure is no longer restartable. (This
+ * lets us get away with modifying things such as OBJSND(BIRD) without
+ * having to be able to undo the changes later.) If a "used" copy is
+ * rerun, we come here and tell the player to run a fresh copy. */
RSPEAK(201);
exit(0);
-/* START-UP, DWARF STUFF */
+/* Start-up, dwarf stuff */
L1: SETUP= -1;
I=RAN(-1);
LIMIT=330;
if(NOVICE)LIMIT=1000;
-/* CAN'T LEAVE CAVE ONCE IT'S CLOSING (EXCEPT BY MAIN OFFICE). */
+/* Can't leave cave once it's closing (except by main office). */
L2: if(!OUTSID(NEWLOC) || NEWLOC == 0 || !CLOSNG) goto L71;
RSPEAK(130);
if(!PANIC)CLOCK2=15;
PANIC=true;
-/* SEE IF A DWARF HAS SEEN HIM AND HAS COME FROM WHERE HE WANTS TO GO. IF SO,
- * THE DWARF'S BLOCKING HIS WAY. IF COMING FROM PLACE FORBIDDEN TO PIRATE
- * (DWARVES ROOTED IN PLACE) LET HIM GET OUT (AND ATTACKED). */
+/* See if a dwarf has seen him and has come from where he wants to go. If so,
+ * the dwarf's blocking his way. if coming from place forbidden to pirate
+ * (dwarves rooted in place) let him get out (and attacked). */
L71: if(NEWLOC == LOC || FORCED(LOC) || CNDBIT(LOC,3)) goto L74;
/* 73 */ for (I=1; I<=5; I++) {
} /* end loop */
L74: LOC=NEWLOC;
-/* DWARF STUFF. SEE EARLIER COMMENTS FOR DESCRIPTION OF VARIABLES. REMEMBER
- * SIXTH DWARF IS PIRATE AND IS THUS VERY DIFFERENT EXCEPT FOR MOTION RULES. */
+/* Dwarf stuff. See earlier comments for description of variables. Remember
+ * sixth dwarf is pirate and is thus very different except for motion rules. */
-/* FIRST OFF, DON'T LET THE DWARVES FOLLOW HIM INTO A PIT OR A WALL. ACTIVATE
- * THE WHOLE MESS THE FIRST TIME HE GETS AS FAR AS THE HALL OF MISTS (LOC 15).
- * IF NEWLOC IS FORBIDDEN TO PIRATE (IN PARTICULAR, IF IT'S BEYOND THE TROLL
- * BRIDGE), BYPASS DWARF STUFF. THAT WAY PIRATE CAN'T STEAL RETURN TOLL, AND
- * DWARVES CAN'T MEET THE BEAR. ALSO MEANS DWARVES WON'T FOLLOW HIM INTO DEAD
- * END IN MAZE, BUT C'EST LA VIE. THEY'LL WAIT FOR HIM OUTSIDE THE DEAD END. */
+/* First off, don't let the dwarves follow him into a pit or a wall. Activate
+ * the whole mess the first time he gets as far as the hall of mists (loc 15).
+ * If NEWLOC is forbidden to pirate (in particular, if it's beyond the troll
+ * bridge), bypass dwarf stuff. That way pirate can't steal return toll, and
+ * dwarves can't meet the bear. Also means dwarves won't follow him into dead
+ * end in maze, but c'est la vie. They'll wait for him outside the dead end. */
if(LOC == 0 || FORCED(LOC) || CNDBIT(NEWLOC,3)) goto L2000;
if(DFLAG != 0) goto L6000;
if(INDEEP(LOC))DFLAG=1;
goto L2000;
-/* WHEN WE ENCOUNTER THE FIRST DWARF, WE KILL 0, 1, OR 2 OF THE 5 DWARVES. IF
- * ANY OF THE SURVIVORS IS AT LOC, REPLACE HIM WITH THE ALTERNATE. */
+/* When we encounter the first dwarf, we kill 0, 1, or 2 of the 5 dwarves. If
+ * any of the survivors is at loc, replace him with the alternate. */
L6000: if(DFLAG != 1) goto L6010;
if(!INDEEP(LOC) || (PCT(95) && (!CNDBIT(LOC,4) || PCT(85)))) goto L2000;
DROP(AXE,LOC);
goto L2000;
-/* THINGS ARE IN FULL SWING. MOVE EACH DWARF AT RANDOM, EXCEPT IF HE'S SEEN US
- * HE STICKS WITH US. DWARVES STAY DEEP INSIDE. IF WANDERING AT RANDOM,
- * THEY DON'T BACK UP UNLESS THERE'S NO ALTERNATIVE. IF THEY DON'T HAVE TO
- * MOVE, THEY ATTACK. AND, OF COURSE, DEAD DWARVES DON'T DO MUCH OF ANYTHING. */
+/* Things are in full swing. move each dwarf at random, except if he's seen us
+ * he sticks with us. Dwarves stay deep inside. If wandering at random,
+ * they don't back up unless there's no alternative. If they don't have to
+ * move, they attack. And, of course, dead dwarves don't do much of anything. */
L6010: DTOTAL=0;
ATTACK=0;
STICK=0;
/* 6030 */ for (I=1; I<=6; I++) {
if(DLOC[I] == 0) goto L6030;
-/* FILL TK ARRAY WITH ALL THE PLACES THIS DWARF MIGHT GO. */
+/* Fill TK array with all the places this dwarf might go. */
J=1;
KK=DLOC[I];
KK=KEY[KK];
DLOC[I]=LOC;
if(I != 6) goto L6027;
-/* THE PIRATE'S SPOTTED HIM. HE LEAVES HIM ALONE ONCE WE'VE FOUND CHEST. K
- * COUNTS IF A TREASURE IS HERE. IF NOT, AND TALLY=1 FOR AN UNSEEN CHEST, LET
- * THE PIRATE BE SPOTTED. NOTE THAT PLACE(CHEST)=0 MIGHT MEAN THAT HE'S
- * THROWN IT TO THE TROLL, BUT IN THAT CASE HE'S SEEN THE CHEST (PROP=0). */
+/* The pirate's spotted him. He leaves him alone once we've found chest. K
+ * counts if a treasure is here. If not, and tally=1 for an unseen chest, let
+ * the pirate be spotted. Note that PLACE(CHEST)=0 might mean that he's
+ * thrown it to the troll, but in that case he's seen the chest (PROP=0). */
if(LOC == CHLOC || PROP[CHEST] >= 0) goto L6030;
K=0;
/* 6020 */ for (J=50; J<=MAXTRS; J++) {
-/* PIRATE WON'T TAKE PYRAMID FROM PLOVER ROOM OR DARK ROOM (TOO EASY!). */
+/* Pirate won't take pyramid from plover room or dark room (too easy!). */
if(J == PYRAM && (LOC == PLAC[PYRAM] || LOC == PLAC[EMRALD])) goto L6020;
if(TOTING(J)) goto L6021;
L6020: if(HERE(J))K=1;
goto L6030;
L6021: if(PLACE[CHEST] != 0) goto L6022;
-/* INSTALL CHEST ONLY ONCE, TO INSURE IT IS THE LAST TREASURE IN THE LIST. */
+/* Install chest only once, to insure it is the last treasure in the list. */
MOVE(CHEST,CHLOC);
MOVE(MESSAG,CHLOC2);
L6022: RSPEAK(128);
MOVE(MESSAG,CHLOC2);
goto L6024;
-/* THIS THREATENING LITTLE DWARF IS IN THE ROOM WITH HIM! */
+/* This threatening little dwarf is in the room with him! */
L6027: DTOTAL=DTOTAL+1;
if(ODLOC[I] != DLOC[I]) goto L6030;
L6030: /*etc*/ ;
} /* end loop */
-/* NOW WE KNOW WHAT'S HAPPENING. LET'S TELL THE POOR SUCKER ABOUT IT.
- * NOTE THAT VARIOUS OF THE "KNIFE" MESSAGES MUST HAVE SPECIFIC RELATIVE
- * POSITIONS IN THE RSPEAK DATABASE. */
+/* Now we know what's happening. Let's tell the poor sucker about it.
+ * Note that various of the "knife" messages must have specific relative
+ * positions in the RSPEAK database. */
if(DTOTAL == 0) goto L2000;
SETPRM(1,DTOTAL,0);
-/* DESCRIBE THE CURRENT LOCATION AND (MAYBE) GET NEXT COMMAND. */
+/* Describe the current location and (maybe) get next command. */
-/* PRINT TEXT FOR CURRENT LOC. */
+/* Print text for current loc. */
L2000: if(LOC == 0) goto L99;
KK=STEXT[LOC];
if(FORCED(LOC)) goto L8;
if(LOC == 33 && PCT(25) && !CLOSNG)RSPEAK(7);
-/* PRINT OUT DESCRIPTIONS OF OBJECTS AT THIS LOCATION. IF NOT CLOSING AND
- * PROPERTY VALUE IS NEGATIVE, TALLY OFF ANOTHER TREASURE. RUG IS SPECIAL
- * CASE; ONCE SEEN, ITS PROP IS 1 (DRAGON ON IT) TILL DRAGON IS KILLED.
- * SIMILARLY FOR CHAIN; PROP IS INITIALLY 1 (LOCKED TO BEAR). THESE HACKS
- * ARE BECAUSE PROP=0 IS NEEDED TO GET FULL SCORE. */
+/* Print out descriptions of objects at this location. If not closing and
+ * property value is negative, tally off another treasure. Rug is special
+ * case; once seen, its PROP is 1 (dragon on it) till dragon is killed.
+ * Similarly for chain; PROP is initially 1 (locked to bear). These hacks
+ * are because PROP=0 is needed to get full score. */
if(DARK(0)) goto L2012;
ABB[LOC]=ABB[LOC]+1;
PROP[OBJ]=0;
if(OBJ == RUG || OBJ == CHAIN)PROP[OBJ]=1;
TALLY=TALLY-1;
-/* NOTE: THERE USED TO BE A TEST HERE TO SEE WHETHER THE PLAYER HAD BLOWN IT
- * SO BADLY THAT HE COULD NEVER EVER SEE THE REMAINING TREASURES, AND IF SO
- * THE LAMP WAS ZAPPED TO 35 TURNS. BUT THE TESTS WERE TOO SIMPLE-MINDED;
- * THINGS LIKE KILLING THE BIRD BEFORE THE SNAKE WAS GONE (CAN NEVER SEE
- * JEWELRY), AND DOING IT "RIGHT" WAS HOPELESS. E.G., COULD CROSS TROLL
- * BRIDGE SEVERAL TIMES, USING UP ALL AVAILABLE TREASURES, BREAKING VASE,
- * USING COINS TO BUY BATTERIES, ETC., AND EVENTUALLY NEVER BE ABLE TO GET
- * ACROSS AGAIN. IF BOTTLE WERE LEFT ON FAR SIDE, COULD THEN NEVER GET EGGS
- * OR TRIDENT, AND THE EFFECTS PROPAGATE. SO THE WHOLE THING WAS FLUSHED.
- * ANYONE WHO MAKES SUCH A GROSS BLUNDER ISN'T LIKELY TO FIND EVERYTHING
- * ELSE ANYWAY (SO GOES THE RATIONALISATION). */
+/* Note: There used to be a test here to see whether the player had blown it
+ * so badly that he could never ever see the remaining treasures, and if so
+ * the lamp was zapped to 35 turns. But the tests were too simple-minded;
+ * things like killing the bird before the snake was gone (can never see
+ * jewelry), and doing it "right" was hopeless. E.G., could cross troll
+ * bridge several times, using up all available treasures, breaking vase,
+ * using coins to buy batteries, etc., and eventually never be able to get
+ * across again. If bottle were left on far side, could then never get eggs
+ * or trident, and the effects propagate. So the whole thing was flushed.
+ * anyone who makes such a gross blunder isn't likely to find everything
+ * else anyway (so goes the rationalisation). */
L2006: KK=PROP[OBJ];
if(OBJ == STEPS && LOC == FIXED[STEPS])KK=1;
PSPEAK(OBJ,KK);
OLDOBJ=OBJ;
OBJ=0;
-/* CHECK IF THIS LOC IS ELIGIBLE FOR ANY HINTS. IF BEEN HERE LONG ENOUGH,
- * BRANCH TO HELP SECTION (ON LATER PAGE). HINTS ALL COME BACK HERE EVENTUALLY
- * TO FINISH THE LOOP. IGNORE "HINTS" < 4 (SPECIAL STUFF, SEE DATABASE NOTES).
+/* Check if this loc is eligible for any hints. If been here long enough,
+ * branch to help section (on later page). Hints all come back here eventually
+ * to finish the loop. Ignore "HINTS" < 4 (special stuff, see database notes).
*/
L2600: if(COND[LOC] < CONDS) goto L2603;
L2602: /*etc*/ ;
} /* end loop */
-/* KICK THE RANDOM NUMBER GENERATOR JUST TO ADD VARIETY TO THE CHASE. ALSO,
- * IF CLOSING TIME, CHECK FOR ANY OBJECTS BEING TOTED WITH PROP < 0 AND SET
- * THE PROP TO -1-PROP. THIS WAY OBJECTS WON'T BE DESCRIBED UNTIL THEY'VE
- * BEEN PICKED UP AND PUT DOWN SEPARATE FROM THEIR RESPECTIVE PILES. DON'T
- * TICK CLOCK1 UNLESS WELL INTO CAVE (AND NOT AT Y2). */
+/* Kick the random number generator just to add variety to the chase. Also,
+ * if closing time, check for any objects being toted with PROP < 0 and set
+ * the prop to -1-PROP. This way objects won't be described until they've
+ * been picked up and put down separate from their respective piles. Don't
+ * tick CLOCK1 unless well into cave (and not at Y2). */
L2603: if(!CLOSED) goto L2605;
if(PROP[OYSTER] < 0 && TOTING(OYSTER))PSPEAK(OYSTER,1);
I=RAN(1);
GETIN(WD1,WD1X,WD2,WD2X);
-/* EVERY INPUT, CHECK "FOOBAR" FLAG. IF ZERO, NOTHING'S GOING ON. IF POS,
- * MAKE NEG. IF NEG, HE SKIPPED A WORD, SO MAKE IT ZERO. */
+/* Every input, check "FOOBAR" flag. If zero, nothing's going on. If pos,
+ * make neg. If neg, he skipped a word, so make it zero. */
L2607: FOOBAR=(FOOBAR>0 ? -FOOBAR : 0);
TURNS=TURNS+1;
case 3: goto L2010; }
BUG(22);
-/* GET SECOND WORD FOR ANALYSIS. */
+/* Get second word for analysis. */
L2800: WD1=WD2;
WD1X=WD2X;
WD2=0;
goto L2620;
-/* GEE, I DON'T UNDERSTAND. */
+/* Gee, I don't understand. */
L3000: SETPRM(1,WD1,WD1X);
RSPEAK(254);
goto L2600;
-/* VERB AND OBJECT ANALYSIS MOVED TO SEPARATE MODULE. */
+/* Verb and object analysis moved to separate module. */
L4000: I=4000; goto Laction;
L4090: I=4090; goto Laction;
}
BUG(99);
-/* RANDOM INTRANSITIVE VERBS COME HERE. CLEAR OBJ JUST IN CASE (SEE "ATTACK").
+/* Random intransitive verbs come here. Clear obj just in case (see "attack").
*/
L8000: SETPRM(1,WD1,WD1X);
OBJ=0;
goto L2600;
-/* FIGURE OUT THE NEW LOCATION
+/* Figure out the new location
*
- * GIVEN THE CURRENT LOCATION IN "LOC", AND A MOTION VERB NUMBER IN "K", PUT
- * THE NEW LOCATION IN "NEWLOC". THE CURRENT LOC IS SAVED IN "OLDLOC" IN CASE
- * HE WANTS TO RETREAT. THE CURRENT OLDLOC IS SAVED IN OLDLC2, IN CASE HE
- * DIES. (IF HE DOES, NEWLOC WILL BE LIMBO, AND OLDLOC WILL BE WHAT KILLED
- * HIM, SO WE NEED OLDLC2, WHICH IS THE LAST PLACE HE WAS SAFE.) */
+ * Given the current location in "LOC", and a motion verb number in "K", put
+ * the new location in "NEWLOC". the current loc is saved in "OLDLOC" in case
+ * he wants to retreat. the current OLDLOC is saved in OLDLC2, in case he
+ * dies. (if he does, NEWLOC will be limbo, and OLDLOC will be what killed
+ * him, so we need OLDLC2, which is the last place he was safe.) */
L8: KK=KEY[LOC];
NEWLOC=LOC;
NEWLOC=LOC;
goto L2;
-/* SPECIAL MOTIONS COME HERE. LABELLING CONVENTION: STATEMENT NUMBERS NNNXX
- * (XX=00-99) ARE USED FOR SPECIAL CASE NUMBER NNN (NNN=301-500). */
+/* Special motions come here. labelling convention: statement numbers NNNXX
+ * (XX=00-99) are used for special case number NNN (NNN=301-500). */
L30000: NEWLOC=NEWLOC-300;
switch (NEWLOC) { case 1: goto L30100; case 2: goto L30200; case 3: goto
L30300; }
BUG(20);
-/* TRAVEL 301. PLOVER-ALCOVE PASSAGE. CAN CARRY ONLY EMERALD. NOTE: TRAVEL
- * TABLE MUST INCLUDE "USELESS" ENTRIES GOING THROUGH PASSAGE, WHICH CAN NEVER
- * BE USED FOR ACTUAL MOTION, BUT CAN BE SPOTTED BY "GO BACK". */
+/* Travel 301. Plover-alcove passage. Can carry only emerald. Note: travel
+ * table must include "useless" entries going through passage, which can never
+ * be used for actual motion, but can be spotted by "go back". */
L30100: NEWLOC=99+100-LOC;
if(HOLDNG == 0 || (HOLDNG == 1 && TOTING(EMRALD))) goto L2;
RSPEAK(117);
goto L2;
-/* TRAVEL 302. PLOVER TRANSPORT. DROP THE EMERALD (ONLY USE SPECIAL TRAVEL IF
- * TOTING IT), SO HE'S FORCED TO USE THE PLOVER-PASSAGE TO GET IT OUT. HAVING
- * DROPPED IT, GO BACK AND PRETEND HE WASN'T CARRYING IT AFTER ALL. */
+/* Travel 302. Plover transport. Drop the emerald (only use special travel if
+ * toting it), so he's forced to use the plover-passage to get it out. Having
+ * dropped it, go back and pretend he wasn't carrying it after all. */
L30200: DROP(EMRALD,LOC);
goto L12;
-/* TRAVEL 303. TROLL BRIDGE. MUST BE DONE ONLY AS SPECIAL MOTION SO THAT
- * DWARVES WON'T WANDER ACROSS AND ENCOUNTER THE BEAR. (THEY WON'T FOLLOW THE
- * PLAYER THERE BECAUSE THAT REGION IS FORBIDDEN TO THE PIRATE.) IF
- * PROP(TROLL)=1, HE'S CROSSED SINCE PAYING, SO STEP OUT AND BLOCK HIM.
- * (STANDARD TRAVEL ENTRIES CHECK FOR PROP(TROLL)=0.) SPECIAL STUFF FOR BEAR. */
+/* Travel 303. Troll bridge. Must be done only as special motion so that
+ * dwarves won't wander across and encounter the bear. (They won't follow the
+ * player there because that region is forbidden to the pirate.) If
+ * PROP(TROLL)=1, he's crossed since paying, so step out and block him.
+ * (standard travel entries check for PROP(TROLL)=0.) Special stuff for bear. */
L30300: if(PROP[TROLL] != 1) goto L30310;
PSPEAK(TROLL,1);
OLDLC2=NEWLOC;
goto L99;
-/* END OF SPECIALS. */
+/* End of specials. */
-/* HANDLE "GO BACK". LOOK FOR VERB WHICH GOES FROM LOC TO OLDLOC, OR TO OLDLC2
- * IF OLDLOC HAS FORCED-MOTION. K2 SAVES ENTRY -> FORCED LOC -> PREVIOUS LOC. */
+/* Handle "go back". Look for verb which goes from LOC to OLDLOC, or to OLDLC2
+ * If OLDLOC has forced-motion. K2 saves entry -> forced loc -> previous loc. */
L20: K=OLDLOC;
if(FORCED(K))K=OLDLC2;
KK=KEY[LOC];
goto L9;
-/* LOOK. CAN'T GIVE MORE DETAIL. PRETEND IT WASN'T DARK (THOUGH IT MAY "NOW"
- * BE DARK) SO HE WON'T FALL INTO A PIT WHILE STARING INTO THE GLOOM. */
+/* Look. Can't give more detail. Pretend it wasn't dark (though it may "now"
+ * be dark) so he won't fall into a pit while staring into the gloom. */
L30: if(DETAIL < 3)RSPEAK(15);
DETAIL=DETAIL+1;
ABB[LOC]=0;
goto L2;
-/* CAVE. DIFFERENT MESSAGES DEPENDING ON WHETHER ABOVE GROUND. */
+/* Cave. Different messages depending on whether above ground. */
L40: K=58;
if(OUTSID(LOC) && LOC != 8)K=57;
RSPEAK(K);
goto L2;
-/* NON-APPLICABLE MOTION. VARIOUS MESSAGES DEPENDING ON WORD GIVEN. */
+/* Non-applicable motion. Various messages depending on word given. */
L50: SPK=12;
if(K >= 43 && K <= 50)SPK=52;
-/* "YOU'RE DEAD, JIM."
+/* "You're dead, Jim."
*
- * IF THE CURRENT LOC IS ZERO, IT MEANS THE CLOWN GOT HIMSELF KILLED. WE'LL
- * ALLOW THIS MAXDIE TIMES. MAXDIE IS AUTOMATICALLY SET BASED ON THE NUMBER OF
- * SNIDE MESSAGES AVAILABLE. EACH DEATH RESULTS IN A MESSAGE (81, 83, ETC.)
- * WHICH OFFERS REINCARNATION; IF ACCEPTED, THIS RESULTS IN MESSAGE 82, 84,
- * ETC. THE LAST TIME, IF HE WANTS ANOTHER CHANCE, HE GETS A SNIDE REMARK AS
- * WE EXIT. WHEN REINCARNATED, ALL OBJECTS BEING CARRIED GET DROPPED AT OLDLC2
- * (PRESUMABLY THE LAST PLACE PRIOR TO BEING KILLED) WITHOUT CHANGE OF PROPS.
- * THE LOOP RUNS BACKWARDS TO ASSURE THAT THE BIRD IS DROPPED BEFORE THE CAGE.
- * (THIS KLUGE COULD BE CHANGED ONCE WE'RE SURE ALL REFERENCES TO BIRD AND CAGE
- * ARE DONE BY KEYWORDS.) THE LAMP IS A SPECIAL CASE (IT WOULDN'T DO TO LEAVE
- * IT IN THE CAVE). IT IS TURNED OFF AND LEFT OUTSIDE THE BUILDING (ONLY IF HE
- * WAS CARRYING IT, OF COURSE). HE HIMSELF IS LEFT INSIDE THE BUILDING (AND
- * HEAVEN HELP HIM IF HE TRIES TO XYZZY BACK INTO THE CAVE WITHOUT THE LAMP!).
- * OLDLOC IS ZAPPED SO HE CAN'T JUST "RETREAT". */
-
-/* THE EASIEST WAY TO GET KILLED IS TO FALL INTO A PIT IN PITCH DARKNESS. */
+ * If the current loc is zero, it means the clown got himself killed. we'll
+ * allow this maxdie times. maxdie is automatically set based on the number of
+ * snide messages available. Each death results in a message (81, 83, etc.)
+ * which offers reincarnation; if accepted, this results in message 82, 84,
+ * etc. The last time, if he wants another chance, he gets a snide remark as
+ * we exit. When reincarnated, all objects being carried get dropped at OLDLC2
+ * (presumably the last place prior to being killed) without change of props.
+ * the loop runs backwards to assure that the bird is dropped before the cage.
+ * (this kluge could be changed once we're sure all references to bird and cage
+ * are done by keywords.) The lamp is a special case (it wouldn't do to leave
+ * it in the cave). It is turned off and left outside the building (only if he
+ * was carrying it, of course). He himself is left inside the building (and
+ * heaven help him if he tries to xyzzy back into the cave without the lamp!).
+ * OLDLOC is zapped so he can't just "retreat". */
+
+/* The easiest way to get killed is to fall into a pit in pitch darkness. */
L90: RSPEAK(23);
OLDLC2=LOC;
-/* OKAY, HE'S DEAD. LET'S GET ON WITH IT. */
+/* Okay, he's dead. Let's get on with it. */
L99: if(CLOSNG) goto L95;
NUMDIE=NUMDIE+1;
OLDLOC=LOC;
goto L2000;
-/* HE DIED DURING CLOSING TIME. NO RESURRECTION. TALLY UP A DEATH AND EXIT. */
+/* He died during closing time. No resurrection. Tally up a death and exit. */
L95: RSPEAK(131);
NUMDIE=NUMDIE+1;
-/* HINTS */
+/* Hints */
-/* COME HERE IF HE'S BEEN LONG ENOUGH AT REQUIRED LOC(S) FOR SOME UNUSED HINT.
- * HINT NUMBER IS IN VARIABLE "HINT". BRANCH TO QUICK TEST FOR ADDITIONAL
- * CONDITIONS, THEN COME BACK TO DO NEAT STUFF. GOTO 40010 IF CONDITIONS ARE
- * MET AND WE WANT TO OFFER THE HINT. GOTO 40020 TO CLEAR HINTLC BACK TO ZERO,
- * 40030 TO TAKE NO ACTION YET. */
+/* Come here if he's been long enough at required loc(s) for some unused hint.
+ * hint number is in variable "hint". Branch to quick test for additional
+ * conditions, then come back to do neat stuff. Goto 40010 if conditions are
+ * met and we want to offer the hint. Goto 40020 to clear HINTLC back to zero,
+ * 40030 to take no action yet. */
L40000: switch (HINT-1) { case 0: goto L40100; case 1: goto L40200; case 2: goto
L40300; case 3: goto L40400; case 4: goto L40500; case 5: goto
L40020: HINTLC[HINT]=0;
L40030: goto L2602;
-/* NOW FOR THE QUICK TESTS. SEE DATABASE DESCRIPTION FOR ONE-LINE NOTES. */
+/* Now for the quick tests. See database description for one-line notes. */
L40100: if(PROP[GRATE] == 0 && !HERE(KEYS)) goto L40010;
goto L40020;
-/* CAVE CLOSING AND SCORING */
+/* Cave closing and scoring */
-/* THESE SECTIONS HANDLE THE CLOSING OF THE CAVE. THE CAVE CLOSES "CLOCK1"
- * TURNS AFTER THE LAST TREASURE HAS BEEN LOCATED (INCLUDING THE PIRATE'S
- * CHEST, WHICH MAY OF COURSE NEVER SHOW UP). NOTE THAT THE TREASURES NEED NOT
- * HAVE BEEN TAKEN YET, JUST LOCATED. HENCE CLOCK1 MUST BE LARGE ENOUGH TO GET
- * OUT OF THE CAVE (IT ONLY TICKS WHILE INSIDE THE CAVE). WHEN IT HITS ZERO,
- * WE BRANCH TO 10000 TO START CLOSING THE CAVE, AND THEN SIT BACK AND WAIT FOR
- * HIM TO TRY TO GET OUT. IF HE DOESN'T WITHIN CLOCK2 TURNS, WE CLOSE THE
- * CAVE; IF HE DOES TRY, WE ASSUME HE PANICS, AND GIVE HIM A FEW ADDITIONAL
- * TURNS TO GET FRANTIC BEFORE WE CLOSE. WHEN CLOCK2 HITS ZERO, WE BRANCH TO
- * 11000 TO TRANSPORT HIM INTO THE FINAL PUZZLE. NOTE THAT THE PUZZLE DEPENDS
- * UPON ALL SORTS OF RANDOM THINGS. FOR INSTANCE, THERE MUST BE NO WATER OR
- * OIL, SINCE THERE ARE BEANSTALKS WHICH WE DON'T WANT TO BE ABLE TO WATER,
- * SINCE THE CODE CAN'T HANDLE IT. ALSO, WE CAN HAVE NO KEYS, SINCE THERE IS A
- * GRATE (HAVING MOVED THE FIXED OBJECT!) THERE SEPARATING HIM FROM ALL THE
- * TREASURES. MOST OF THESE PROBLEMS ARISE FROM THE USE OF NEGATIVE PROP
- * NUMBERS TO SUPPRESS THE OBJECT DESCRIPTIONS UNTIL HE'S ACTUALLY MOVED THE
- * OBJECTS. */
+/* These sections handle the closing of the cave. The cave closes "CLOCK1"
+ * turns after the last treasure has been located (including the pirate's
+ * chest, which may of course never show up). Note that the treasures need not
+ * have been taken yet, just located. Hence CLOCK1 must be large enough to get
+ * out of the cave (it only ticks while inside the cave). When it hits zero,
+ * we branch to 10000 to start closing the cave, and then sit back and wait for
+ * him to try to get out. If he doesn't within CLOCK2 turns, we close the
+ * cave; if he does try, we assume he panics, and give him a few additional
+ * turns to get frantic before we close. When CLOCK2 hits zero, we branch to
+ * 11000 to transport him into the final puzzle. Note that the puzzle depends
+ * upon all sorts of random things. For instance, there must be no water or
+ * oil, since there are beanstalks which we don't want to be able to water,
+ * since the code can't handle it. Also, we can have no keys, since there is a
+ * grate (having moved the fixed object!) there separating him from all the
+ * treasures. most of these problems arise from the use of negative prop
+ * numbers to suppress the object descriptions until he's actually moved the
+ * objects. */
-/* WHEN THE FIRST WARNING COMES, WE LOCK THE GRATE, DESTROY THE BRIDGE, KILL
- * ALL THE DWARVES (AND THE PIRATE), REMOVE THE TROLL AND BEAR (UNLESS DEAD),
- * AND SET "CLOSNG" TO TRUE. LEAVE THE DRAGON; TOO MUCH TROUBLE TO MOVE IT.
- * FROM NOW UNTIL CLOCK2 RUNS OUT, HE CANNOT UNLOCK THE GRATE, MOVE TO ANY
- * LOCATION OUTSIDE THE CAVE, OR CREATE THE BRIDGE. NOR CAN HE BE
- * RESURRECTED IF HE DIES. NOTE THAT THE SNAKE IS ALREADY GONE, SINCE HE GOT
- * TO THE TREASURE ACCESSIBLE ONLY VIA THE HALL OF THE MT. KING. ALSO, HE'S
- * BEEN IN GIANT ROOM (TO GET EGGS), SO WE CAN REFER TO IT. ALSO ALSO, HE'S
- * GOTTEN THE PEARL, SO WE KNOW THE BIVALVE IS AN OYSTER. *AND*, THE DWARVES
- * MUST HAVE BEEN ACTIVATED, SINCE WE'VE FOUND CHEST. */
+/* When the first warning comes, we lock the grate, destroy the bridge, kill
+ * all the dwarves (and the pirate), remove the troll and bear (unless dead),
+ * and set "CLOSNG" to true. Leave the dragon; too much trouble to move it.
+ * from now until CLOCK2 runs out, he cannot unlock the grate, move to any
+ * location outside the cave, or create the bridge. Nor can he be
+ * resurrected if he dies. Note that the snake is already gone, since he got
+ * to the treasure accessible only via the hall of the mt. king. Also, he's
+ * been in giant room (to get eggs), so we can refer to it. Also also, he's
+ * gotten the pearl, so we know the bivalve is an oyster. *And*, the dwarves
+ * must have been activated, since we've found chest. */
L10000: PROP[GRATE]=0;
PROP[FISSUR]=0;
OLDLOC=115;
NEWLOC=115;
-/* LEAVE THE GRATE WITH NORMAL (NON-NEGATIVE) PROPERTY. REUSE SIGN. */
+/* Leave the grate with normal (non-negative) property. reuse sign. */
I=PUT(GRATE,116,0);
I=PUT(SIGN,116,0);
CLOSED=true;
goto L2;
-/* ANOTHER WAY WE CAN FORCE AN END TO THINGS IS BY HAVING THE LAMP GIVE OUT.
- * WHEN IT GETS CLOSE, WE COME HERE TO WARN HIM. WE GO TO 12000 IF THE LAMP
- * AND FRESH BATTERIES ARE HERE, IN WHICH CASE WE REPLACE THE BATTERIES AND
- * CONTINUE. 12200 IS FOR OTHER CASES OF LAMP DYING. 12400 IS WHEN IT GOES
- * OUT. EVEN THEN, HE CAN EXPLORE OUTSIDE FOR A WHILE IF DESIRED. */
+/* Another way we can force an end to things is by having the lamp give out.
+ * When it gets close, we come here to warn him. We go to 12000 if the lamp
+ * and fresh batteries are here, in which case we replace the batteries and
+ * continue. 12200 is for other cases of lamp dying. 12400 is when it goes
+ * out. Even then, he can explore outside for a while if desired. */
L12000: RSPEAK(188);
PROP[BATTER]=1;
if(HERE(LAMP))RSPEAK(184);
goto L19999;
-/* OH DEAR, HE'S DISTURBED THE DWARVES. */
+/* Oh dear, he's disturbed the dwarves. */
L18999: RSPEAK(SPK);
L19000: RSPEAK(136);
/* hack to ignore GCC Unused Result */
#define IGNORE(r) do{if(r){}}while(0)
-/* I/O ROUTINES (SPEAK, PSPEAK, RSPEAK, SETPRM, GETIN, YES) */
+/* I/O routines (SPEAK, PSPEAK, RSPEAK, SETPRM, GETIN, YES) */
#undef SPEAK
void fSPEAK(long N) {
long BLANK, CASE, I, K, L, NEG, NPARMS, PARM, PRMTYP, STATE;
-/* PRINT THE MESSAGE WHICH STARTS AT LINES(N). PRECEDE IT WITH A BLANK LINE
- * UNLESS BLKLIN IS FALSE. */
+/* Print the message which starts at LINES(N). Precede it with a blank line
+ * unless BLKLIN is false. */
if(N == 0)return;
L32: if(LNPOSN > LNLENG) goto L40;
if(INLINE[LNPOSN] != 63) goto L30;
{long x = LNPOSN+1; PRMTYP=INLINE[x];}
-/* 63 IS A "%"; THE NEXT CHARACTER DETERMINE THE TYPE OF PARAMETER: 1 (!) =
- * SUPPRESS MESSAGE COMPLETELY, 29 (S) = NULL IF PARM=1, ELSE 'S' (OPTIONAL
- * PLURAL ENDING), 33 (W) = WORD (TWO 30-BIT VALUES) WITH TRAILING SPACES
- * SUPPRESSED, 22 (L) OR 31 (U) = WORD BUT MAP TO LOWER/UPPER CASE, 13 (C) =
- * WORD IN LOWER CASE WITH FIRST LETTER CAPITALISED, 30 (T) = TEXT ENDING
- * WITH A WORD OF -1, 65-73 (1-9) = NUMBER USING THAT MANY CHARACTERS,
- * 12 (B) = VARIABLE NUMBER OF BLANKS. */
+/* 63 is a "%"; the next character determine the type of parameter: 1 (!) =
+ * suppress message completely, 29 (S) = NULL If PARM=1, else 'S' (optional
+ * plural ending), 33 (W) = word (two 30-bit values) with trailing spaces
+ * suppressed, 22 (L) or 31 (U) = word but map to lower/upper case, 13 (C) =
+ * word in lower case with first letter capitalised, 30 (T) = text ending
+ * with a word of -1, 65-73 (1-9) = number using that many characters,
+ * 12 (B) = variable number of blanks. */
if(PRMTYP == 1)return;
if(PRMTYP == 29) goto L320;
if(PRMTYP == 30) goto L340;
void fPSPEAK(long MSG,long SKIP) {
long I, M;
-/* FIND THE SKIP+1ST MESSAGE FROM MSG AND PRINT IT. MSG SHOULD BE THE INDEX OF
- * THE INVENTORY MESSAGE FOR OBJECT. (INVEN+N+1 MESSAGE IS PROP=N MESSAGE). */
+/* Find the skip+1st message from msg and print it. MSG should be the index of
+ * the inventory message for object. (INVEN+N+1 message is PROP=N message). */
M=PTEXT[MSG];
void fRSPEAK(long I) {
;
-/* PRINT THE I-TH "RANDOM" MESSAGE (SECTION 6 OF DATABASE). */
+/* Print the I-TH "random" message (section 6 of database). */
if(I != 0)SPEAK(RTEXT[I]);
void fSETPRM(long FIRST, long P1, long P2) {
;
-/* STORES PARAMETERS INTO THE PRMCOM PARMS ARRAY FOR USE BY SPEAK. P1 AND P2
- * ARE STORED INTO PARMS(FIRST) AND PARMS(FIRST+1). */
+/* Stores parameters into the PRMCOM parms array for use by speak. P1 and P2
+ * are stored into PARMS(FIRST) and PARMS(FIRST+1). */
if(FIRST >= 25)BUG(29);
void fGETIN(long *wORD1, long *wORD1X, long *wORD2, long *wORD2X) {
long JUNK;
-/* GET A COMMAND FROM THE ADVENTURER. SNARF OUT THE FIRST WORD, PAD IT WITH
- * BLANKS, AND RETURN IT IN WORD1. CHARS 6 THRU 10 ARE RETURNED IN WORD1X, IN
- * CASE WE NEED TO PRINT OUT THE WHOLE WORD IN AN ERROR MESSAGE. ANY NUMBER OF
- * BLANKS MAY FOLLOW THE WORD. IF A SECOND WORD APPEARS, IT IS RETURNED IN
- * WORD2 (CHARS 6 THRU 10 IN WORD2X), ELSE WORD2 IS -1. */
+/* Get a command from the adventurer. snarf out the first word, pad it with
+ * blanks, and return it in WORD1. Chars 6 thru 10 are returned in WORD1X, in
+ * case we need to print out the whole word in an error message. Any number of
+ * blanks may follow the word. If a second word appears, it is returned in
+ * WORD2 (chars 6 thru 10 in WORD2X), else WORD2 is -1. */
L10: if(BLKLIN)TYPE0();
long YES, REPLY, JUNK1, JUNK2, JUNK3;
-/* PRINT MESSAGE X, WAIT FOR YES/NO ANSWER. IF YES, PRINT Y AND RETURN TRUE;
- * IF NO, PRINT Z AND RETURN FALSE. */
+/* Print message X, wait for yes/no answer. If yes, print Y and return true;
+ * if no, print Z and return false. */
L1: RSPEAK(X);
GETIN(REPLY,JUNK1,JUNK2,JUNK3);
-/* LINE-PARSING ROUTINES (GETNUM, GETTXT, MAKEWD, PUTTXT, SHFTXT, TYPE0)
+/* Line-parsing routines (GETNUM, GETTXT, MAKEWD, PUTTXT, SHFTXT, TYPE0)
*/
-/* THE ROUTINES ON THIS PAGE HANDLE ALL THE STUFF THAT WOULD NORMALLY BE
- * TAKEN CARE OF BY FORMAT STATEMENTS. WE DO IT THIS WAY INSTEAD SO THAT
- * WE CAN HANDLE TEXTUAL DATA IN A MACHINE INDEPENDENT FASHION. ALL THE
- * MACHINE DEPENDENT I/O STUFF IS ON THE FOLLOWING PAGE. SEE THAT PAGE
- * FOR A DESCRIPTION OF MAPCOM'S INLINE ARRAY. */
+/* The routines on this page handle all the stuff that would normally be
+ * taken care of by format statements. We do it this way instead so that
+ * we can handle textual data in a machine independent fashion. All the
+ * machine dependent i/o stuff is on the following page. See that page
+ * for a description of MAPCOM's inline array. */
#define YES(X,Y,Z) fYES(X,Y,Z)
#undef GETNUM
long fGETNUM(long K) {
long DIGIT, GETNUM, SIGN;
-/* OBTAIN THE NEXT INTEGER FROM AN INPUT LINE. IF K>0, WE FIRST READ A
- * NEW INPUT LINE FROM A FILE; IF K<0, WE READ A LINE FROM THE KEYBOARD;
- * IF K=0 WE USE A LINE THAT HAS ALREADY BEEN READ (AND PERHAPS PARTIALLY
- * SCANNED). IF WE'RE AT THE END OF THE LINE OR ENCOUNTER AN ILLEGAL
- * CHARACTER (NOT A DIGIT, HYPHEN, OR BLANK), WE RETURN 0. */
+/* Obtain the next integer from an input line. If K>0, we first read a
+ * new input line from a file; if K<0, we read a line from the keyboard;
+ * if K=0 we use a line that has already been read (and perhaps partially
+ * scanned). If we're at the end of the line or encounter an illegal
+ * character (not a digit, hyphen, or blank), we return 0. */
if(K != 0)MAPLIN(K > 0);
long fGETTXT(long SKIP,long ONEWRD, long UPPER, long HASH) {
long CHAR, GETTXT, I; static long SPLITTING = -1;
-/* TAKE CHARACTERS FROM AN INPUT LINE AND PACK THEM INTO 30-BIT WORDS.
- * SKIP SAYS TO SKIP LEADING BLANKS. ONEWRD SAYS STOP IF WE COME TO A
- * BLANK. UPPER SAYS TO MAP ALL LETTERS TO UPPERCASE. HASH MAY BE USED
- * AS A PARAMETER FOR ENCRYPTING THE TEXT IF DESIRED; HOWEVER, A HASH OF 0
- * SHOULD RESULT IN UNMODIFIED BYTES BEING PACKED. IF WE REACH THE
- * END OF THE LINE, THE WORD IS FILLED UP WITH BLANKS (WHICH ENCODE AS 0'S).
- * IF WE'RE ALREADY AT END OF LINE WHEN GETTXT IS CALLED, WE RETURN -1. */
+/* Take characters from an input line and pack them into 30-bit words.
+ * Skip says to skip leading blanks. ONEWRD says stop if we come to a
+ * blank. UPPER says to map all letters to uppercase. HASH may be used
+ * as a parameter for encrypting the text if desired; however, a hash of 0
+ * should result in unmodified bytes being packed. If we reach the
+ * end of the line, the word is filled up with blanks (which encode as 0's).
+ * If we're already at end of line when GETTXT is called, we return -1. */
if(LNPOSN != SPLITTING)SPLITTING = -1;
GETTXT= -1;
long fMAKEWD(long LETTRS) {
long I, L, MAKEWD;
-/* COMBINE FIVE UPPERCASE LETTERS (REPRESENTED BY PAIRS OF DECIMAL DIGITS
- * IN LETTRS) TO FORM A 30-BIT VALUE MATCHING THE ONE THAT GETTXT WOULD
- * RETURN GIVEN THOSE CHARACTERS PLUS TRAILING BLANKS AND HASH=0. CAUTION:
- * LETTRS WILL OVERFLOW 31 BITS IF 5-LETTER WORD STARTS WITH V-Z. AS A
- * KLUDGEY WORKAROUND, YOU CAN INCREMENT A LETTER BY 5 BY ADDING 50 TO
- * THE NEXT PAIR OF DIGITS. */
+/* Combine five uppercase letters (represented by pairs of decimal digits
+ * in lettrs) to form a 30-bit value matching the one that GETTXT would
+ * return given those characters plus trailing blanks and HASH=0. Caution:
+ * lettrs will overflow 31 bits if 5-letter word starts with V-Z. As a
+ * kludgey workaround, you can increment a letter by 5 by adding 50 to
+ * the next pair of digits. */
MAKEWD=0;
void fPUTTXT(long WORD, long *sTATE, long CASE, long HASH) {
long ALPH1, ALPH2, BYTE, DIV, I, W;
-/* UNPACK THE 30-BIT VALUE IN WORD TO OBTAIN UP TO 5 INTEGER-ENCODED CHARS,
- * AND STORE THEM IN INLINE STARTING AT LNPOSN. IF LNLENG>=LNPOSN, SHIFT
- * EXISTING CHARACTERS TO THE RIGHT TO MAKE ROOM. HASH MUST BE THE SAME
- * AS IT WAS WHEN GETTXT CREATED THE 30-BIT WORD. STATE WILL BE ZERO WHEN
- * PUTTXT IS CALLED WITH THE FIRST OF A SEQUENCE OF WORDS, BUT IS THEREAFTER
- * UNCHANGED BY THE CALLER, SO PUTTXT CAN USE IT TO MAINTAIN STATE ACROSS
- * CALLS. LNPOSN AND LNLENG ARE INCREMENTED BY THE NUMBER OF CHARS STORED.
- * IF CASE=1, ALL LETTERS ARE MADE UPPERCASE; IF -1, LOWERCASE; IF 0, AS IS.
- * ANY OTHER VALUE FOR CASE IS THE SAME AS 0 BUT ALSO CAUSES TRAILING BLANKS
- * TO BE INCLUDED (IN ANTICIPATION OF SUBSEQUENT ADDITIONAL TEXT). */
+/* Unpack the 30-bit value in word to obtain up to 5 integer-encoded chars,
+ * and store them in inline starting at LNPOSN. If LNLENG>=LNPOSN, shift
+ * existing characters to the right to make room. HASH must be the same
+ * as it was when gettxt created the 30-bit word. STATE will be zero when
+ * puttxt is called with the first of a sequence of words, but is thereafter
+ * unchanged by the caller, so PUTTXT can use it to maintain state across
+ * calls. LNPOSN and LNLENG are incremented by the number of chars stored.
+ * If CASE=1, all letters are made uppercase; if -1, lowercase; if 0, as is.
+ * any other value for case is the same as 0 but also causes trailing blanks
+ * to be included (in anticipation of subsequent additional text). */
ALPH1=13*CASE+24;
void fSHFTXT(long FROM, long DELTA) {
long I, II, JJ;
-/* MOVE INLINE(N) TO INLINE(N+DELTA) FOR N=FROM,LNLENG. DELTA CAN BE
- * NEGATIVE. LNLENG IS UPDATED; LNPOSN IS NOT CHANGED. */
+/* Move INLINE(N) to INLINE(N+DELTA) for N=FROM,LNLENG. Delta can be
+ * negative. LNLENG is updated; LNPOSN is not changed. */
if(LNLENG < FROM || DELTA == 0) goto L2;
void fTYPE0() {
long TEMP;
-/* TYPE A BLANK LINE. THIS PROCEDURE IS PROVIDED AS A CONVENIENCE FOR CALLERS
- * WHO OTHERWISE HAVE NO USE FOR MAPCOM. */
+/* Type a blank line. This procedure is provided as a convenience for callers
+ * who otherwise have no use for MAPCOM. */
TEMP=LNLENG;
#define TYPE0() fTYPE0()
-/* SUSPEND/RESUME I/O ROUTINES (SAVWDS, SAVARR, SAVWRD) */
+/* Suspend/resume I/O routines (SAVWDS, SAVARR, SAVWRD) */
#undef SAVWDS
void fSAVWDS(long *W1, long *W2, long *W3, long *W4, long *W5, long *W6, long *W7) {
-/* WRITE OR READ 7 VARIABLES. SEE SAVWRD. */
+/* Write or read 7 variables. See SAVWRD. */
SAVWRD(0,(*W1));
void fSAVARR(long ARR[], long N) {
long I;
-/* WRITE OR READ AN ARRAY OF N WORDS. SEE SAVWRD. */
+/* Write or read an array of N words. See SAVWRD. */
/* 1 */ for (I=1; I<=N; I++) {
void fSAVWRD(long OP, long *wORD) {
static long BUF[250], CKSUM = 0, H1, HASH = 0, N = 0, STATE = 0;
-/* IF OP<0, START WRITING A FILE, USING WORD TO INITIALISE ENCRYPTION; SAVE
- * WORD IN THE FILE. IF OP>0, START READING A FILE; READ THE FILE TO FIND
- * THE VALUE WITH WHICH TO DECRYPT THE REST. IN EITHER CASE, IF A FILE IS
- * ALREADY OPEN, FINISH WRITING/READING IT AND DON'T START A NEW ONE. IF OP=0,
- * READ/WRITE A SINGLE WORD. WORDS ARE BUFFERED IN CASE THAT MAKES FOR MORE
- * EFFICIENT DISK USE. WE ALSO COMPUTE A SIMPLE CHECKSUM TO CATCH ELEMENTARY
- * POKING WITHIN THE SAVED FILE. WHEN WE FINISH READING/WRITING THE FILE,
- * WE STORE ZERO INTO WORD IF THERE'S NO CHECKSUM ERROR, ELSE NONZERO. */
+/* If OP<0, start writing a file, using word to initialise encryption; save
+ * word in the file. If OP>0, start reading a file; read the file to find
+ * the value with which to decrypt the rest. In either case, if a file is
+ * already open, finish writing/reading it and don't start a new one. If OP=0,
+ * read/write a single word. Words are buffered in case that makes for more
+ * efficient disk use. We also compute a simple checksum to catch elementary
+ * poking within the saved file. When we finish reading/writing the file,
+ * we store zero into WORD if there's no checksum error, else nonzero. */
if(OP != 0){long ifvar; ifvar=(STATE); switch (ifvar<0? -1 : ifvar>0? 1 :
-/* DATA STRUC. ROUTINES (VOCAB, DSTROY, JUGGLE, MOVE, PUT, CARRY, DROP, ATDWRF)
+/* Data struc. routines (VOCAB, DSTROY, JUGGLE, MOVE, PUT, CARRY, DROP, ATDWRF)
*/
#undef WORD
long fVOCAB(long ID, long INIT) {
long HASH, I, VOCAB;
-/* LOOK UP ID IN THE VOCABULARY (ATAB) AND RETURN ITS "DEFINITION" (KTAB), OR
- * -1 IF NOT FOUND. IF INIT IS POSITIVE, THIS IS AN INITIALISATION CALL SETTING
- * UP A KEYWORD VARIABLE, AND NOT FINDING IT CONSTITUTES A BUG. IT ALSO MEANS
- * THAT ONLY KTAB VALUES WHICH TAKEN OVER 1000 EQUAL INIT MAY BE CONSIDERED.
- * (THUS "STEPS", WHICH IS A MOTION VERB AS WELL AS AN OBJECT, MAY BE LOCATED
- * AS AN OBJECT.) AND IT ALSO MEANS THE KTAB VALUE IS TAKEN MOD 1000. */
+/* Look up ID in the vocabulary (ATAB) and return its "definition" (KTAB), or
+ * -1 if not found. If INIT is positive, this is an initialisation call setting
+ * up a keyword variable, and not finding it constitutes a bug. It also means
+ * that only KTAB values which taken over 1000 equal INIT may be considered.
+ * (Thus "STEPS", which is a motion verb as well as an object, may be located
+ * as an object.) And it also means the KTAB value is taken modulo 1000. */
HASH=10000;
/* 1 */ for (I=1; I<=TABSIZ; I++) {
void fDSTROY(long OBJECT) {
;
-/* PERMANENTLY ELIMINATE "OBJECT" BY MOVING TO A NON-EXISTENT LOCATION. */
+/* Permanently eliminate "OBJECT" by moving to a non-existent location. */
MOVE(OBJECT,0);
void fJUGGLE(OBJECT)long OBJECT; {
long I, J;
-/* JUGGLE AN OBJECT BY PICKING IT UP AND PUTTING IT DOWN AGAIN, THE PURPOSE
- * BEING TO GET THE OBJECT TO THE FRONT OF THE CHAIN OF THINGS AT ITS LOC. */
+/* Juggle an object by picking it up and putting it down again, the purpose
+ * being to get the object to the front of the chain of things at its loc. */
I=PLACE[OBJECT];
void fMOVE(OBJECT,WHERE)long OBJECT, WHERE; {
long FROM;
-/* PLACE ANY OBJECT ANYWHERE BY PICKING IT UP AND DROPPING IT. MAY ALREADY BE
- * TOTING, IN WHICH CASE THE CARRY IS A NO-OP. MUSTN'T PICK UP OBJECTS WHICH
- * ARE NOT AT ANY LOC, SINCE CARRY WANTS TO REMOVE OBJECTS FROM ATLOC CHAINS. */
+/* Place any object anywhere by picking it up and dropping it. May already be
+ * toting, in which case the carry is a no-op. Mustn't pick up objects which
+ * are not at any loc, since carry wants to remove objects from ATLOC chains. */
if(OBJECT > 100) goto L1;
long fPUT(OBJECT,WHERE,PVAL)long OBJECT, PVAL, WHERE; {
long PUT;
-/* PUT IS THE SAME AS MOVE, EXCEPT IT RETURNS A VALUE USED TO SET UP THE
- * NEGATED PROP VALUES FOR THE REPOSITORY OBJECTS. */
+/* PUT is the same as MOVE, except it returns a value used to set up the
+ * negated PROP values for the repository objects. */
MOVE(OBJECT,WHERE);
void fCARRY(OBJECT,WHERE)long OBJECT, WHERE; {
long TEMP;
-/* START TOTING AN OBJECT, REMOVING IT FROM THE LIST OF THINGS AT ITS FORMER
- * LOCATION. INCR HOLDNG UNLESS IT WAS ALREADY BEING TOTED. IF OBJECT>100
- * (MOVING "FIXED" SECOND LOC), DON'T CHANGE PLACE OR HOLDNG. */
+/* Start toting an object, removing it from the list of things at its former
+ * location. Incr holdng unless it was already being toted. If OBJECT>100
+ * (moving "fixed" second loc), don't change PLACE or HOLDNG. */
if(OBJECT > 100) goto L5;
void fDROP(OBJECT,WHERE)long OBJECT, WHERE; {
;
-/* PLACE AN OBJECT AT A GIVEN LOC, PREFIXING IT ONTO THE ATLOC LIST. DECR
- * HOLDNG IF THE OBJECT WAS BEING TOTED. */
+/* Place an object at a given loc, prefixing it onto the ATLOC list. Decr
+ * HOLDNG if the object was being toted. */
if(OBJECT > 100) goto L1;
long fATDWRF(WHERE)long WHERE; {
long ATDWRF, I;
-/* RETURN THE INDEX OF FIRST DWARF AT THE GIVEN LOCATION, ZERO IF NO DWARF IS
- * THERE (OR IF DWARVES NOT ACTIVE YET), -1 IF ALL DWARVES ARE DEAD. IGNORE
- * THE PIRATE (6TH DWARF). */
+/* Return the index of first dwarf at the given location, zero if no dwarf is
+ * there (or if dwarves not active yet), -1 if all dwarves are dead. Ignore
+ * the pirate (6th dwarf). */
ATDWRF=0;
-/* UTILITY ROUTINES (SETBIT, TSTBIT, RAN, RNDVOC, BUG) */
+/* Utility routines (SETBIT, TSTBIT, RAN, RNDVOC, BUG) */
#undef SETBIT
long fSETBIT(BIT)long BIT; {
long I, SETBIT;
-/* RETURNS 2**BIT FOR USE IN CONSTRUCTING BIT-MASKS. */
+/* Returns 2**bit for use in constructing bit-masks. */
SETBIT=1;
long fTSTBIT(MASK,BIT)long BIT, MASK; {
long TSTBIT;
-/* RETURNS TRUE IF THE SPECIFIED BIT IS SET IN THE MASK. */
+/* Returns true if the specified bit is set in the mask. */
TSTBIT=MOD(MASK/SETBIT(BIT),2) != 0;
long fRAN(RANGE)long RANGE; {
static long D, R = 0, RAN, T;
-/* SINCE THE RAN FUNCTION IN LIB40 SEEMS TO BE A REAL LOSE, WE'LL USE ONE OF
- * OUR OWN. IT'S BEEN RUN THROUGH MANY OF THE TESTS IN KNUTH VOL. 2 AND
- * SEEMS TO BE QUITE RELIABLE. RAN RETURNS A VALUE UNIFORMLY SELECTED
- * BETWEEN 0 AND RANGE-1. */
+/* Since the ran function in LIB40 seems to be a real lose, we'll use one of
+ * our own. It's been run through many of the tests in Knuth vol. 2 and
+ * seems to be quite reliable. RAN returns a value uniformly selected
+ * between 0 and range-1. */
D=1;
long fRNDVOC(CHAR,FORCE)long CHAR, FORCE; {
long DIV, I, J, RNDVOC;
-/* SEARCHES THE VOCABULARY FOR A WORD WHOSE SECOND CHARACTER IS CHAR, AND
- * CHANGES THAT WORD SUCH THAT EACH OF THE OTHER FOUR CHARACTERS IS A
- * RANDOM LETTER. IF FORCE IS NON-ZERO, IT IS USED AS THE NEW WORD.
- * RETURNS THE NEW WORD. */
+/* Searches the vocabulary for a word whose second character is char, and
+ * changes that word such that each of the other four characters is a
+ * random letter. If force is non-zero, it is used as the new word.
+ * Returns the new word. */
RNDVOC=FORCE;
#undef BUG
void fBUG(NUM)long NUM; {
-/* THE FOLLOWING CONDITIONS ARE CURRENTLY CONSIDERED FATAL BUGS. NUMBERS < 20
- * ARE DETECTED WHILE READING THE DATABASE; THE OTHERS OCCUR AT "RUN TIME".
- * 0 MESSAGE LINE > 70 CHARACTERS
- * 1 NULL LINE IN MESSAGE
- * 2 TOO MANY WORDS OF MESSAGES
- * 3 TOO MANY TRAVEL OPTIONS
- * 4 TOO MANY VOCABULARY WORDS
- * 5 REQUIRED VOCABULARY WORD NOT FOUND
- * 6 TOO MANY RTEXT MESSAGES
- * 7 TOO MANY HINTS
- * 8 LOCATION HAS COND BIT BEING SET TWICE
- * 9 INVALID SECTION NUMBER IN DATABASE
- * 10 TOO MANY LOCATIONS
- * 11 TOO MANY CLASS OR TURN MESSAGES
- * 20 SPECIAL TRAVEL (500>L>300) EXCEEDS GOTO LIST
- * 21 RAN OFF END OF VOCABULARY TABLE
- * 22 VOCABULARY TYPE (N/1000) NOT BETWEEN 0 AND 3
- * 23 INTRANSITIVE ACTION VERB EXCEEDS GOTO LIST
- * 24 TRANSITIVE ACTION VERB EXCEEDS GOTO LIST
- * 25 CONDITIONAL TRAVEL ENTRY WITH NO ALTERNATIVE
- * 26 LOCATION HAS NO TRAVEL ENTRIES
- * 27 HINT NUMBER EXCEEDS GOTO LIST
- * 28 INVALID MONTH RETURNED BY DATE FUNCTION
- * 29 TOO MANY PARAMETERS GIVEN TO SETPRM */
+/* The following conditions are currently considered fatal bugs. Numbers < 20
+ * are detected while reading the database; the others occur at "run time".
+ * 0 Message line > 70 characters
+ * 1 Null line in message
+ * 2 Too many words of messages
+ * 3 Too many travel options
+ * 4 Too many vocabulary words
+ * 5 Required vocabulary word not found
+ * 6 Too many RTEXT messages
+ * 7 Too many hints
+ * 8 Location has cond bit being set twice
+ * 9 Invalid section number in database
+ * 10 Too many locations
+ * 11 Too many class or turn messages
+ * 20 Special travel (500>L>300) exceeds goto list
+ * 21 Ran off end of vocabulary table
+ * 22 Vocabulary type (N/1000) not between 0 and 3
+ * 23 Intransitive action verb exceeds goto list
+ * 24 Transitive action verb exceeds goto list
+ * 25 Conditional travel entry with no alternative
+ * 26 Location has no travel entries
+ * 27 Hint number exceeds goto list
+ * 28 Invalid month returned by date function
+ * 29 Too many parameters given to SETPRM */
printf("Fatal error %ld. See source code for interpretation.\n",
NUM);
-/* MACHINE DEPENDENT ROUTINES (MAPLIN, TYPE, MPINIT, SAVEIO) */
+/* Machine dependent routines (MAPLIN, TYPE, MPINIT, SAVEIO) */
#define BUG(NUM) fBUG(NUM)
#undef MAPLIN
void fMAPLIN(FIL)long FIL; {
long I, VAL; static FILE *OPENED = NULL;
-/* READ A LINE OF INPUT, EITHER FROM A FILE (IF FIL=.TRUE.) OR FROM THE
- * KEYBOARD, TRANSLATE THE CHARS TO INTEGERS IN THE RANGE 0-126 AND STORE
- * THEM IN THE COMMON ARRAY "INLINE". INTEGER VALUES ARE AS FOLLOWS:
- * 0 = SPACE [ASCII CODE 40 OCTAL, 32 DECIMAL]
- * 1-2 = !" [ASCII 41-42 OCTAL, 33-34 DECIMAL]
- * 3-10 = '()*+,-. [ASCII 47-56 OCTAL, 39-46 DECIMAL]
- * 11-36 = UPPER-CASE LETTERS
- * 37-62 = LOWER-CASE LETTERS
- * 63 = PERCENT (%) [ASCII 45 OCTAL, 37 DECIMAL]
- * 64-73 = DIGITS, 0 THROUGH 9
- * REMAINING CHARACTERS CAN BE TRANSLATED ANY WAY THAT IS CONVENIENT;
- * THE "TYPE" ROUTINE BELOW IS USED TO MAP THEM BACK TO CHARACTERS WHEN
- * NECESSARY. THE ABOVE MAPPINGS ARE REQUIRED SO THAT CERTAIN SPECIAL
- * CHARACTERS ARE KNOWN TO FIT IN 6 BITS AND/OR CAN BE EASILY SPOTTED.
- * ARRAY ELEMENTS BEYOND THE END OF THE LINE SHOULD BE FILLED WITH 0,
- * AND LNLENG SHOULD BE SET TO THE INDEX OF THE LAST CHARACTER.
+/* Read a line of input, either from a file (if FIL=true) or from the
+ * keyboard, translate the chars to integers in the range 0-126 and store
+ * them in the common array "INLINE". Integer values are as follows:
+ * 0 = space [ASCII CODE 40 octal, 32 decimal]
+ * 1-2 = !" [ASCII 41-42 octal, 33-34 decimal]
+ * 3-10 = '()*+,-. [ASCII 47-56 octal, 39-46 decimal]
+ * 11-36 = upper-case letters
+ * 37-62 = lower-case letters
+ * 63 = percent (%) [ASCII 45 octal, 37 decimal]
+ * 64-73 = digits, 0 through 9
+ * Remaining characters can be translated any way that is convenient;
+ * The "TYPE" routine below is used to map them back to characters when
+ * necessary. The above mappings are required so that certain special
+ * characters are known to fit in 6 bits and/or can be easily spotted.
+ * Array elements beyond the end of the line should be filled with 0,
+ * and LNLENG should be set to the index of the last character.
*
- * IF THE DATA FILE USES A CHARACTER OTHER THAN SPACE (E.G., TAB) TO
- * SEPARATE NUMBERS, THAT CHARACTER SHOULD ALSO TRANSLATE TO 0.
+ * If the data file uses a character other than space (e.g., tab) to
+ * separate numbers, that character should also translate to 0.
*
- * THIS PROCEDURE MAY USE THE MAP1,MAP2 ARRAYS TO MAINTAIN STATIC DATA FOR
- * THE MAPPING. MAP2(1) IS SET TO 0 WHEN THE PROGRAM STARTS
- * AND IS NOT CHANGED THEREAFTER UNLESS THE ROUTINES ON THIS PAGE CHOOSE
- * TO DO SO.
+ * This procedure may use the map1,map2 arrays to maintain static data for
+ * the mapping. MAP2(1) is set to 0 when the program starts
+ * and is not changed thereafter unless the routines on this page choose
+ * to do so.
*
- * NOTE THAT MAPLIN IS EXPECTED TO OPEN THE FILE THE FIRST TIME IT IS
- * ASKED TO READ A LINE FROM IT. THAT IS, THERE IS NO OTHER PLACE WHERE
- * THE DATA FILE IS OPENED. */
+ * Note that MAPLIN is expected to open the file the first time it is
+ * asked to read a line from it. that is, there is no other place where
+ * the data file is opened. */
if(MAP2[1] == 0)MPINIT();
} /* end loop */
LNPOSN=1;
if(FIL && LNLENG == 0) goto L15;
-/* ABOVE IS TO GET AROUND AN F40 COMPILER BUG WHEREIN IT READS A BLANK
- * LINE WHENEVER A CRLF IS BROKEN ACROSS A RECORD BOUNDARY. */
+/* Above is to get around an F40 compiler bug wherein it reads a blank
+ * line whenever a crlf is broken across a record boundary. */
return;
}
void fTYPE() {
long I, VAL;
-/* TYPE THE FIRST "LNLENG" CHARACTERS STORED IN INLINE, MAPPING THEM
- * FROM INTEGERS TO TEXT PER THE RULES DESCRIBED ABOVE. INLINE(I),
- * I=1,LNLENG MAY BE CHANGED BY THIS ROUTINE. */
+/* Type the first "LNLENG" characters stored in inline, mapping them
+ * from integers to text per the rules described above. INLINE(I),
+ * I=1,LNLENG may be changed by this routine. */
if(LNLENG != 0) goto L10;
L20: /*etc*/ ;
} /* end loop */
MAP1[128]=MAP1[10];
-/* FOR THIS VERSION, TAB (9) MAPS TO SPACE (32), SO DEL (127) USES TAB'S VALUE */
+/* For this version, tab (9) maps to space (32), so del (127) uses tab's value */
MAP1[10]=MAP1[33];
MAP1[11]=MAP1[33];
void fSAVEIO(OP,IN,ARR)long ARR[], IN, OP; {
static FILE *F; char NAME[50];
-/* IF OP=0, ASK FOR A FILE NAME AND OPEN A FILE. (IF IN=.TRUE., THE FILE IS FOR
- * INPUT, ELSE OUTPUT.) IF OP>0, READ/WRITE ARR FROM/INTO THE PREVIOUSLY-OPENED
- * FILE. (ARR IS A 250-INTEGER ARRAY.) IF OP<0, FINISH READING/WRITING THE
- * FILE. (FINISHING WRITING CAN BE A NO-OP IF A "STOP" STATEMENT DOES IT
- * AUTOMATICALLY. FINISHING READING CAN BE A NO-OP AS LONG AS A SUBSEQUENT
- * SAVEIO(0,.FALSE.,X) WILL STILL WORK.) IF YOU CAN CATCH ERRORS (E.G., NO SUCH
- * FILE) AND TRY AGAIN, GREAT. DEC F40 CAN'T. */
+/* If OP=0, ask for a file name and open a file. (If IN=true, the file is for
+ * input, else output.) If OP>0, read/write ARR from/into the previously-opened
+ * file. (ARR is a 250-integer array.) If OP<0, finish reading/writing the
+ * file. (Finishing writing can be a no-op if a "stop" statement does it
+ * automatically. Finishing reading can be a no-op as long as a subsequent
+ * SAVEIO(0,false,X) will still work.) If you can catch errors (e.g., no such
+ * file) and try again, great. DEC F40 can't. */
{long ifvar; ifvar=(OP); switch (ifvar<0? -1 : ifvar>0? 1 : 0) { case -1:
#include "share.h"
/*
- * SCORING AND WRAP-UP
+ * scoring and wrap-up
*/
void score(long MODE) {
/* <0 if scoring, >0 if quitting, =0 if died or won */
-/* THE PRESENT SCORING ALGORITHM IS AS FOLLOWS:
- * OBJECTIVE: POINTS: PRESENT TOTAL POSSIBLE:
- * GETTING WELL INTO CAVE 25 25
- * EACH TREASURE < CHEST 12 60
- * TREASURE CHEST ITSELF 14 14
- * EACH TREASURE > CHEST 16 224
- * SURVIVING (MAX-NUM)*10 30
- * NOT QUITTING 4 4
- * REACHING "CLOSNG" 25 25
- * "CLOSED": QUIT/KILLED 10
- * KLUTZED 25
- * WRONG WAY 30
- * SUCCESS 45 45
- * CAME TO WITT'S END 1 1
- * ROUND OUT THE TOTAL 2 2
+/* The present scoring algorithm is as follows:
+ * Objective: Points: Present total possible:
+ * Getting well into cave 25 25
+ * Each treasure < chest 12 60
+ * Treasure chest itself 14 14
+ * Each treasure > chest 16 224
+ * Surviving (MAX-NUM)*10 30
+ * Not quitting 4 4
+ * Reaching "CLOSNG" 25 25
+ * "Closed": Quit/Killed 10
+ * Klutzed 25
+ * Wrong way 30
+ * Success 45 45
+ * Came to Witt's End 1 1
+ * Round out the total 2 2
* TOTAL: 430
- * POINTS CAN ALSO BE DEDUCTED FOR USING HINTS OR TOO MANY TURNS, OR FOR
- * SAVING INTERMEDIATE POSITIONS. */
+ * Points can also be deducted for using hints or too many turns, or for
+ * saving intermediate positions. */
L20000: SCORE=0;
MXSCOR=0;
-/* FIRST TALLY UP THE TREASURES. MUST BE IN BUILDING AND NOT BROKEN.
- * GIVE THE POOR GUY 2 POINTS JUST FOR FINDING EACH TREASURE. */
+/* First tally up the treasures. must be in building and not broken.
+ * Give the poor guy 2 points just for finding each treasure. */
/* 20010 */ for (I=50; I<=MAXTRS; I++) {
if(PTEXT[I] == 0) goto L20010;
L20010: /*etc*/ ;
} /* end loop */
-/* NOW LOOK AT HOW HE FINISHED AND HOW FAR HE GOT. MAXDIE AND NUMDIE TELL US
- * HOW WELL HE SURVIVED. DFLAG WILL
- * TELL US IF HE EVER GOT SUITABLY DEEP INTO THE CAVE. CLOSNG STILL INDICATES
- * WHETHER HE REACHED THE ENDGAME. AND IF HE GOT AS FAR AS "CAVE CLOSED"
- * (INDICATED BY "CLOSED"), THEN BONUS IS ZERO FOR MUNDANE EXITS OR 133, 134,
- * 135 IF HE BLEW IT (SO TO SPEAK). */
+/* Now look at how he finished and how far he got. MAXDIE and NUMDIE tell us
+ * how well he survived. DFLAG will
+ * tell us if he ever got suitably deep into the cave. CLOSNG still indicates
+ * whether he reached the endgame. And if he got as far as "cave closed"
+ * (indicated by "CLOSED"), then bonus is zero for mundane exits or 133, 134,
+ * 135 if he blew it (so to speak). */
SCORE=SCORE+(MAXDIE-NUMDIE)*10;
MXSCOR=MXSCOR+MAXDIE*10;
if(BONUS == 133)SCORE=SCORE+45;
L20020: MXSCOR=MXSCOR+45;
-/* DID HE COME TO WITT'S END AS HE SHOULD? */
+/* Did he come to Witt's End as he should? */
if(PLACE[MAGZIN] == 108)SCORE=SCORE+1;
MXSCOR=MXSCOR+1;
-/* ROUND IT OFF. */
+/* Round it off. */
SCORE=SCORE+2;
MXSCOR=MXSCOR+2;
-/* DEDUCT FOR HINTS/TURNS/SAVES. HINTS < 4 ARE SPECIAL; SEE DATABASE DESC. */
+/* Deduct for hints/turns/saves. Hints < 4 are special; see database desc. */
/* 20030 */ for (I=1; I<=HNTMAX; I++) {
L20030: if(HINTED[I])SCORE=SCORE-HINTS[I][2];
if(CLSHNT)SCORE=SCORE-10;
SCORE=SCORE-TRNLUZ-SAVED;
-/* RETURN TO SCORE COMMAND IF THAT'S WHERE WE CAME FROM. */
+/* Return to score command if that's where we came from. */
if(MODE < 0) return;
-/* THAT SHOULD BE GOOD ENOUGH. LET'S TELL HIM ALL ABOUT IT. */
+/* that should be good enough. Let's tell him all about it. */
if(SCORE+TRNLUZ+1 >= MXSCOR && TRNLUZ != 0)RSPEAK(242);
if(SCORE+SAVED+1 >= MXSCOR && SAVED != 0)RSPEAK(143);