V10/games/adv/adv.c

Compare this file to the similar file:
Show the results in this format:

/* Adventure (3/6/79 17:32:41 1.20)
   Current limits:
        999 lines, linsiz of message text (lines).
        750 travel options (travel, trvsiz).
        300 vocabulary words (ktab, atab, tabsiz).
        150 locations (ltext, stext, key, cond, abb, atloc, locsiz).
        100 objects (plac, place, fixd, fixed, rlink (twice), ptext,
                    prop).
         35 "action" verbs (actspk, vrbsiz).
        205 random messages (rtext, rtxsiz).
         12 different player classifications (ctext, cval, clsmax).
         20 hints, less 3 (hintlc, hinted, hints, hntsiz).
         35 magic messages (mtext, magsiz).
   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
 */
#include <stdio.h>
#include <signal.h>

long longabs(x)
	long x;
{
	return x<0? -x: x;
}

long getl (file)
	register FILE *file;
{
	long l;
	l = getw (file);
	l <<= 16;
	l |= getw (file);
	return l;
}

putl (l, file)
	long l;
	register FILE *file;
{
	putw ((int) (l >> 16), file);
	putw ((int) l, file);
}

FILE *caves, *suspfd;
long tvec, xtime, time();
long ftell();
struct passwd *pwbuf;
char suspbeg;	/* Start of variables to write during suspension */
char tkword[10];
char wd2x[5];
char wd2[5];
char wd1x[5];
char wd1[5];
char atab[300+1][6];
char linebuf[100];	/* For reading cave description, etc */
char chr;
char *cp1, *cp2;
int rtext[205];
long newloc = 0L;
long lines[1000];	/* Assumed initialized to zero */
int blklin = 1;
int dseen[6];
int odloc[6];
int dloc[6];
int tk[20+1];
int hinted[20+1];
int hinted[20+1];	/* Assumed initialized to 0 */
int hints[12+1][4+1];	/* Assumed initialized to 0 */
int cval[12+1];	/* Assumed initialized to 0 */
int ctext[12+1];	/* Assumed initialized to 0 */
int actspk[35+1];	/* Assumed initialized to 0 */
int prop[100+1];	/* Assumed initialized to 0 */
int fixd[100+1];	/* Assumed initialized to 0 */
int plac[100+1];	/* Assumed initialized to 0 */
int cond[150+1];	/* Assumed initialized to 0 */
int key[150+1];	/* Assumed initialized to 0 */
int stext[150+1];	/* Assumed initialized to 0 */
int ltext[150+1];	/* Assumed initialized to 0 */
long travel[750+1];	/* Assumed initialized to 0 */
int hintlc[21+1];	/* Assumed initialized to zero */
int abb[150+1];
int holdng;
int fixed[100+1];
int place[100+1];
int rlink[200+1];
int atloc[150+1];
int tabsiz = 300;
int ktab[300+1];
int ptext[100+1];
#ifdef	INITBUG
int clssiz = 12;
int linsiz = 999;
int vrbsiz = 35;
#endif	INITBUG
int trvsiz = 750;
int locsiz = 150;
int rtxsiz = 205;
int clsmax = 12;
int hntsiz = 20;
int wzdark;
int lmwarn;
int closng;
int panic;
int closed;
int gaveup;
int scorng;
int yea;
long ll;

#ifdef unix
#include <pwd.h>
#define GETPWUID() pwbuf=getpwuid(getuid());cp2=pwbuf->pw_dir;while(*cp1++ = *cp2++);cp1--;
#define HOURS "Colossal Cave is always open\n"
#ifndef	CAVE
#define CAVE "/usr/games/lib/cave"
#endif	CAVE
#define SUSPREAD "r"
#define SUSPWRITE "w"
#endif
#ifdef gcos
#define CLOSED "Colossal Cave is closed weekdays between 8 AM and 6 PM.\n"
#define GETPWUID()  if(lmsgrd()<3){printf(CLOSED);return(0);}fprompt("\r\n");
#define HOURS CLOSED
#define CAVE "cc/adve/cave$abracadabra"
#define SUSPREAD "ri"
#define SUSPWRITE "wi"
#endif

#define abbnum	ints[0]
#define iy	ints[1]
#define axe	ints[2]
#define back	ints[3]
#define batter	ints[4]
#define bear	ints[5]
#define bird	ints[6]
#define bonus	ints[7]
#define bottle	ints[8]
#define cage	ints[9]
#define cave	ints[10]
#define ccode	ints[11]
#define ch	ints[12]
#define chain	ints[13]
#define chasm	ints[14]
#define chest	ints[15]
#define chloc	ints[16]
#define chloc2	ints[17]
#define clam	ints[18]
#define clock1	ints[19]
#define clock2	ints[20]
#define clsses	ints[21]
#define coins	ints[22]
#define daltlc	ints[23]
#define detail	ints[24]
#define dflag	ints[25]
#define dkill	ints[26]
#define door	ints[27]
#define dprssn	ints[28]
#define dragon	ints[29]
#define dtotal	ints[30]
#define dwarf	ints[31]
#define eggs	ints[32]
#define emrald	ints[33]
#define entrnc	ints[34]
#define find	ints[35]
#define fissur	ints[36]
#define foo	ints[37]
#define foobar	ints[38]
#define food	ints[39]
#define from	ints[40]
#define grate	ints[41]
#define hint	ints[42]
#define hntmax	ints[43]
#define i	ints[44]
#define inlen	ints[45]
#define invent	ints[46]
#define iwest	ints[47]
#define j	ints[48]
#define k	ints[49]
#define keys	ints[50]
#define kk	ints[51]
#define knfloc	ints[52]
#define knife	ints[53]
#define kq	ints[54]
#define k2	ints[55]
#define l	ints[56]
#define lamp	ints[57]
#define limit	ints[58]
#define linuse	ints[59]
#define hungup	ints[60]
#define loc	ints[61]
#define lock	ints[62]
#define look	ints[63]
#define m	ints[64]
#define magzin	ints[65]
#define maxdie	ints[66]
#define maxtrs	ints[67]
#define messag	ints[68]
#define mirror	ints[69]
#define mxscor	ints[70]
#define nugget	ints[71]
#define nullx	ints[72]
#define numdie	ints[73]
#define obj	ints[74]
#define oil	ints[75]
#define oldlc2	ints[76]
#define oldloc	ints[77]
#define oyster	ints[78]
#define pearl	ints[79]
#define pillow	ints[80]
#define plant	ints[81]
#define plant2	ints[82]
#define posn	ints[83]
#define pyram	ints[84]
#define rod	ints[85]
#define rod2	ints[86]
#define rug	ints[87]
#define say	ints[88]
#define score	ints[89]
#define sect	ints[90]
#define snake	ints[91]
#define spices	ints[92]
#define spk	ints[93]
#define steps	ints[94]
#define stick	ints[95]
#define tablet	ints[96]
#define tabndx	ints[97]
#define tally	ints[98]
#define tally2	ints[99]
#define temp	ints[100]
#define throw	ints[101]
#define attack	ints[102]
#define tridnt	ints[103]
#define troll	ints[104]
#define troll2	ints[105]
#define trvs	ints[106]
#define turns	ints[107]
#define vase	ints[108]
#define vend	ints[109]
#define verb	ints[110]
#define water	ints[111]
#define word	ints[112]
#define wordend	ints[113]
#define wordsize	ints[114]
#define wordstrt	ints[115]
#define logon	ints[116]
#define	srel	ints[117]
#define	slev	ints[118]
#define	tleft	ints[119]
#define	tright	ints[120]
int ints[121];

char suspend;	/* End of variables to write during suspension */

/*
   wzdark says whether the loc he's leaving was dark
   lmwarn says whether he's been warned about lamp going dim
   closng says whether its closing time yet
   panic says whether he's found out he's trapped in the cave
   closed says whether we're all the way closed
   gaveup says whether he exited via "quit"
   scorng indicates to the score routine whether we're doing
   a "score" command
   yea is random yes/no reply
   hungup says whether he hung up the phone
 */

sethup()
{
	hungup = 1;
	signal (SIGHUP, SIG_IGN);

#ifndef	INITBUG
	signal (SIGINT, SIG_IGN);
	signal (SIGQUIT, SIG_IGN);
#endif	INITBUG

}

main()
{
	char suspfile[100];
	static char outbuf[BUFSIZ];
	struct passwd *getpwuid();

	setbuf(stdout, outbuf);
	setbuf(stderr, NULL);
	printf ("@(#)Adventure 1.20\n" + 4);

	cp1 = suspfile;
	GETPWUID();
	cp2 = "/adv.susp";
	while (*cp1++ = *cp2++);

#ifndef	INITBUG
	if (signal (SIGINT, SIG_IGN) != SIG_IGN)
		signal (SIGINT, sethup);
	if (signal (SIGQUIT, sethup) != SIG_IGN)
		signal (SIGQUIT, sethup);
#endif	INITBUG

	if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
		signal (SIGHUP, sethup);

#ifdef LOG
	logon = 1;
#else
	logon = 0;
#endif

	if ((caves = fopen (CAVE, "r")) == NULL)
		fatal ("Couldn't open cave file\n");

	/*  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".
	   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:
	           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.
	               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:  liquid assets, etc.  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
	       Other bits are used to indicate areas of interest to
	       "hint" routines:
	               4       trying to get into cave
	               5       trying to catch bird
	               6       trying to deal with snake
	               7       lost in maze
	               8       pondering dark room
	               9       at Witt's end
	       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
	       (corresponding to a 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).  Numbers 1-3
	       are unusable since cond bits are otherwise assigned,
	       so 2 is used to remember if he's read the clue in the
	       repository, and 3 is used to remember whether he
	       asked for instructions (gets more turns, but loses
	       points).
	   Section 12:  magic messages.  Identical to section 6
	       except put in a separate section for easier
	       reference.  Magic messages are used by the startup,
	       maintenance mode, and related routines.
	   Section 0:  end of database.
	 */

	/*  Read the database */

	printf("Initializing...  ");
	fflush(stdout);

	/*
	   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.  mtext is for section 12.  we also
	   clear cond.  see description of section 9 for details.
	 */
	for (i=1; i<=300; i++) {
		if (i <= 100) ptext[i] = 0;
		if (i <= rtxsiz) rtext[i] = 0;
		if (i <= clsmax) ctext[i] = 0;
		if (i <= locsiz) {
			stext[i]=0;
			ltext[i]=0;
			cond[i]=0;
		}
	}
	/* key=0; */
	linuse=1;
	trvs=1;
	clsses=1;

	/* Start new data section.  sect is the section number. */
l1002:
	fscanf (caves, "%d", &sect);
	oldloc= -1;

#ifdef	INITBUG
	fprintf(stderr, "\nSect=%d\n", sect);
#endif	INITBUG

	switch (sect) {
	case 0:  
		goto l1100;        /* (0) */
	case 1:  
	case 2:  
	case 5:  
	case 6:  
	case 10:  
		goto l1004;        /* 1, 2, 5, 6, 10 */
	case 3:  
		goto l1030;        /* (3) */
	case 4:  
		goto l1040;        /* (4) */
	case 7:  
		goto l1050;        /* (7) */
	case 8:  
		goto l1060;        /* (8) */
	case 9:  
		goto l1070;        /* (9) */
	case 11:  
		goto l1080;       /* (11) */
	}

	bug(9);

	/* Sections 1, 2, 5, 6, 10.  Read messages and set up pointers. */
l1004:
	fscanf (caves, "%d", &loc);
#ifdef	INITBUG
	fprintf(stderr, "Sect=%d; Loc=%d\n", sect, loc);
#endif	INITBUG
	while ((chr = getc (caves)) == ' ' || chr == '\t')
		;
	ungetc (chr, caves);
	lines[linuse] = ftell (caves);
	fgets (linebuf, sizeof linebuf, caves);
	if (loc == -1) goto l1002;
	if (loc != oldloc) {
		lines[linuse] = -lines[linuse];
		if (sect == 10) {
			ctext[clsses] = linuse;
			cval[clsses] = loc;
			clsses++;
		}
		else if (sect == 6) {
			if (loc > rtxsiz) bug(6);
			rtext[loc] = linuse;
		}
		else if (sect == 5) {
			if (loc > 0 && loc <= 100) ptext[loc] = linuse;
		}
		else if (sect == 1) {
			ltext[loc] = linuse;
		}
		else
			stext[loc] = linuse;
	}
	linuse++;
	oldloc = loc;
	goto l1004;
	/*
	   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:
	fscanf (caves, "%d\t%ld", &loc, &newloc);
#ifdef	INITBUG
	fprintf(stderr, "Sect=%d; Loc=%d; newloc=%d\n", sect, loc, newloc);
#endif	INITBUG
	i = 0;
	while ((chr = getc (caves)) != '\n') {
		ungetc (chr, caves);
		fscanf (caves, "%d", &tk[i++]);
	}
	if (loc == -1) goto l1002;
	if (key[loc])
		travel[trvs-1] = -travel[trvs-1];
	else
		key[loc] = trvs;
	for (l=0; l<i; l++) {
		travel[trvs] = newloc * 1000L + tk[l];
		trvs++;
		if (trvs >= trvsiz) bug(3);
	}
	travel[trvs-1]= -travel[trvs-1];
	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.
	*/
l1040:
	for (tabndx = 1; tabndx <= tabsiz; tabndx++) {
		char str[6];
		fscanf (caves, "%d\t%s", &ktab[tabndx], str);
#ifdef	INITBUG
		fprintf(stderr, "Sect=%d; k=%d; str=%s\n", sect, ktab[tabndx], str);
#endif	INITBUG
		while ((chr = getc(caves)) != '\n')
			;
		cpy (&atab[tabndx][0], str);
		if (ktab[tabndx] == -1) goto l1002;
	}
	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.
	*/
l1050:
	while (fscanf (caves, "%d\t%d\t%d", &obj, &j, &k), obj != -1) {
#ifdef	INITBUG
		fprintf(stderr, "Sect=%d; obj=%d; plac=%d; fixd=%d\n", sect, obj, j, k);
#endif	INITBUG
		plac[obj]=j;
		fixd[obj]=k;
	}
	goto l1002;

	/* Read default message numbers for action verbs, store in actspk. */
l1060:
	while (fscanf (caves, "%d\t%d", &verb, &j), verb != -1) {
#ifdef	INITBUG
		fprintf(stderr, "Sect=%d; verb=%d; j=%d\n", sect, verb, j);
#endif	INITBUG
		actspk[verb]=j;
	}
	goto l1002;

	/* Read info about available liquids and other conditions,
	   store in cond.  */
l1070:
	while (fscanf (caves, "%d", &k), k != -1) {
#ifdef	INITBUG
		fprintf(stderr, "Sect=%d; cond=%d\n", sect, k);
#endif	INITBUG
		i = 0;
		while ((chr = getc(caves)) != '\n') {
			ungetc(chr, caves);
			fscanf (caves, "%d", &i);
			if (bitset (i, k)) {
				int z;
				for (z=0; z<10; z++)
					printf ("cond[%d]=%d\n", z, cond[z]);
				fatal ("Duplicate bit\n");
			}
			cond[i] |= (1 << k);
		}
	}
	goto l1002;

	/* Read data for hints. */
l1080:  
	hntmax=0;

	while (fscanf (caves, "%d\t%d\t%d\t%d\t%d",
		&k, &tk[1], &tk[2], &tk[3], &tk[4]), k != -1) {
#ifdef	INITBUG
		fprintf(stderr, "Sect=%d; k=%d; tk=[%d,%d,%d,%d]\n",
			sect, k, tk[1], tk[2], tk[3], tk[4]);
#endif	INITBUG
		if (k != 0) {
			if (k < 0 || k > hntsiz) bug(7);
			for (i=1; i<=4; i++)
				hints[k][i]=tk[i];
			if (k > hntmax)
				hntmax = k;
		}
	}
	goto l1002;

	/*
	   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 rlink[obj] as the next
	   object at the same location as obj.  (obj>100 indicates
	   that fixed[obj-100]=loc; rlink[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.
	*/
l1100:

	printf("Linking...  ");
	fflush(stdout);

	for (i=1; i<=100; i++) {
		place[i]=0;
		prop[i]=0;
		rlink[i]=0;
		rlink[i+100]=0;
	}
	for (i=1; i<=locsiz; i++) {
		abb[i]=0;
		if (ltext[i] != 0 && key[i] != 0) {
			k=key[i];
			if (longabs(travel[k]) % 1000 == 1)
				cond[i]=2;
		}
		atloc[i]=0;
	}
	/*
	   Set up the atloc and rlink 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.
	*/
	for (i=1; i<=100; i++) {
		k=101-i;
		if (fixd[k] > 0) {
			drop (k+100,fixd[k]);
			drop (k,plac[k]);
		}
	}
	for (i=1; i<=100; i++) {
		k=101-i;
		fixed[k]=fixd[k];
		if (plac[k] != 0 && fixd[k] <= 0) drop(k,plac[k]);
	}
	/*
	   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.  Tally2 counts how many can never
	   be found (e.g.  if lost bird or bridge).
	*/
	maxtrs=79;
	tally=0;
	tally2=0;
	for (i=50; i<=maxtrs; i++) {
		if (ptext[i] != 0) prop[i]= -1;
		tally -= prop[i];
	}
	/*
	   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.
	*/
	for (i = 1; i<=hntmax; i++)
		hinted[i] = hintlc[i] = 0;
	/* Define some handy mnemonics.  these correspond to object numbers. */
	keys=vocab("keys",1);
	lamp=vocab("lamp",1);
	grate=vocab("grate",1);
	cage=vocab("cage",1);
	rod=vocab("rod",1);
	rod2=rod+1;
	steps=vocab("steps",1);
	bird=vocab("bird",1);
	door=vocab("door",1);
	pillow=vocab("pillo",1);
	snake=vocab("snake",1);
	fissur=vocab("fissu",1);
	tablet=vocab("table",1);
	clam=vocab("clam",1);
	oyster=vocab("oyste",1);
	magzin=vocab("magaz",1);
	dwarf=vocab("dwarf",1);
	knife=vocab("knife",1);
	food=vocab("food",1);
	bottle=vocab("bottl",1);
	water=vocab("water",1);
	oil=vocab("oil",1);
	plant=vocab("plant",1);
	plant2=plant+1;
	axe=vocab("axe",1);
	mirror=vocab("mirro",1);
	dragon=vocab("drago",1);
	chasm=vocab("chasm",1);
	troll=vocab("troll",1);
	troll2=troll+1;
	bear=vocab("bear",1);
	messag=vocab("messa",1);
	vend=vocab("vendi",1);
	batter=vocab("batte",1);
	/* Objects from 50 through whatever are treasures.  here are a few. */
	nugget=vocab("gold",1);
	coins=vocab("coins",1);
	chest=vocab("chest",1);
	eggs=vocab("eggs",1);
	tridnt=vocab("tride",1);
	vase=vocab("vase",1);
	emrald=vocab("emera",1);
	pyram=vocab("pyram",1);
	pearl=vocab("pearl",1);
	rug=vocab("rug",1);
	chain=vocab("chain",1);
	/* These are motion-verb numbers. */
	back=vocab("back",0);
	look=vocab("look",0);
	cave=vocab("cave",0);
	nullx=vocab("null",0);
	entrnc=vocab("entra",0);
	dprssn=vocab("depre",0);
	/* And some action verbs. */
	say=vocab("say",2);
	lock=vocab("lock",2);
	throw=vocab("throw",2);
	find=vocab("find",2);
	invent=vocab("inven",2);
	/*
	   Initialize 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;
	for (i=1; i<=6; i++)
		dseen[i] = 0;
	dflag=0;
	dloc[1]=19;
	dloc[2]=27;
	dloc[3]=33;
	dloc[4]=44;
	dloc[5]=64;
	dloc[6]=chloc;
	daltlc=18;
	/*
	   Other random flags and counters, as follows:
	        turns   tallies how many commands he's given
	                (ignores yes/no)
	        limit   lifetime of lamp (not set here)
	        iwest   how many times he's said "west" instead of
	                "w"
	        knfloc  0 if no knife here, loc if knife here, -1
	                after caveat
	        detail  how often we've said "not allowed to give
	                more detail"
	        abbnum  how often we should print non-abbreviated
	                descriptions
	        maxdie  number of reincarnation messages available
	                (up to 5)
	        numdie  number of times killed so far
	        holdng  number of objects being carried
	        dkill   number of dwarves killed (unused in scoring,
	                needed for msg)
	        foobar  current progress in saying "fee fie foe
	                foo".
	        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
	        logicals were explained earlier
	*/
	turns=0;
	lmwarn=0;
	iwest=0;
	knfloc=0;
	detail=0;
	abbnum=5;
	for (i=0; i<=4; i++)
		if (rtext[2*i+81] != 0) maxdie=i+1;
	numdie=0;
	/*holdng=0; */
	dkill=0;
	foobar=0;
	bonus=0;
	clock1=30;
	clock2=50;
	closng=0;
	panic=0;
	closed=0;
	gaveup=0;
	scorng=0;
	/* Report on amount of arrays actually used,
	   to permit reductions. */
	for (kk = locsiz; kk > 0; kk--) {
		if (ltext[kk] != 0)
			break;
	}
	obj=0;
	for (k = 1; k <= 100; k++) {
		if (ptext[k] != 0) obj++;
	}
	for (k = 1; k <= tabndx; k++) {
		if (ktab[k]/1000 == 2) verb=ktab[k]-2000;
	}
	for (j = rtxsiz; j > 0; j--) {
		if (rtext[j] != 0)
			break;
	}
	k=100;
#ifdef	INITBUG
	printf ("%d of %d messages; ", linuse, linsiz);
	printf ("%d of %d travel options;\n", trvs, trvsiz);
	printf ("%d of %d vocabulary words; ", tabndx, tabsiz);
	printf ("%d of %d locations;\n", kk, locsiz);
	printf ("%d of %d objects; ", obj, k);
	printf ("%d of %d action verbs;\n", verb, vrbsiz);
	printf ("%d of %d rtext messages; ", j, rtxsiz);
	printf ("%d of %d class messages;\n", clsses, clssiz);
	printf ("%d of %d hints.\n", hntmax, hntsiz);
#endif	INITBUG
	/* Finally, since we're clearly setting things up for the first time */
	printf ("Done!\n");
	tvec = time((long *) 0);
	srand ((int) (tvec % 32768L));
	if ((suspfd = fopen (suspfile, SUSPREAD)) != NULL) {
		/* check if we suspended in this release */
		srel = getw (suspfd);
		slev = getw (suspfd);
		if (srel != 1 || slev != 20) {
			printf("I deleted a suspend file from version %d.%d\n",
				srel, slev);
			unlink (suspfile);
			hinted[3] = yes (65, 1, 0);
			loc = newloc = 1;
			limit = hinted[3]? 1000: 330;
		}
		else
		    {
			/* When did we suspend? */
			xtime = getl (suspfd);
#ifndef NOTIME
			tvec = time((long *) 0);
			if (tvec - xtime < 1800) {
				printf ("You cannot restart a suspended game");
				printf ("for at least half an hour.\n");
				exit (1);
			}
#endif

			/* Delete the suspend file */
			if (unlink (suspfile) == -1)
				fatal ("can't unlink suspend file");

			fread (&suspbeg, sizeof suspbeg, &suspend - &suspbeg, suspfd);
			fclose (suspfd);
			printf ("Restarting a suspended game...\n");
			newloc = loc;
		}
	}
	else
	    {
		hinted[3]=yes(65,1,0);
		loc=newloc=1;
		limit = hinted[3]? 1000: 330;
	}
	/*  Can't leave cave once it's closing (except by main office). */
l2:     
	if (newloc < 9 && newloc != 0 &&  closng) {
		rspeak(130);
		newloc=loc;
		if (!panic) clock2=15;
		panic=1;
	}
	/*
		   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).
		*/
	if (newloc != loc && !forced(loc) && !bitset(loc,3)) {
		for (i = 1; i <= 5; i++) {
			if (!(odloc[i] != newloc ||  !dseen[i])) {
				newloc=loc;
				rspeak(2);
				break;
			}
		}
	}
	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.
		   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) || bitset((int)newloc,3)) goto l2000;
	if (dflag == 0) {
		if (loc >= 15) 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.
		*/
	if (dflag == 1) {
		if (loc < 15 || pct(95)) goto l2000;
		dflag=2;
		for (i = 1; i <= 2; i++) {
			j=1+ran(5);
			if (pct(50)) dloc[j]=0;
		}
		for (i = 1; i <= 5; i++) {
			if (dloc[i] == loc) dloc[i]=daltlc;
			odloc[i]=dloc[i];
		}
		rspeak(3);
		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 never
		   go to locs <15.  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.
		*/
	dtotal=0;
	attack=0;
	stick=0;
	for (i = 1; i <= 6; i++) {
		if (dloc[i] == 0) goto l6030;
		j=1;
		kk=dloc[i];
		kk=key[kk];
		if (kk != 0) {
			do 
			    {
				newloc=longabs(travel[kk])/1000 % 1000;
				if (newloc <= 300 && newloc >=15 && newloc != odloc[i]
				    && !(j > 1 && newloc == tk[j-1]) && j < 20
				    && newloc != dloc[i] && !forced((int)newloc)
				    && !(i == 6 && bitset((int)newloc,3))
				    && longabs(travel[kk] / 1000000) != 100) {
					tk[j]=newloc;
					j++;
				}
				kk++;
			} 
			while (travel[kk-1] >= 0);
		}
		tk[j]=odloc[i];
		if (j >= 2) j--;
		j=1+ran(j);
		odloc[i]=dloc[i];
		dloc[i]=tk[j];
		dseen[i]=(dseen[i] && loc >= 15)
			|| (dloc[i] == loc || odloc[i] == loc);
		if (!dseen[i]) goto l6030;
		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=tally2 plus one for an unseen chest, let the
				pirate be spotted.
				*/
		if (loc == chloc || prop[chest] >= 0) goto l6030;
		k=0;
		for (j = 50; j <= maxtrs; j++) {
			/* Pirate won't take pyramid from plover room or dark room (too easy!).  */
			if (j != pyram || !(loc == plac[pyram]
			    || loc == plac[emrald])) {
				if (toting(j)) goto l6022;
			}
			if (here(j)) k=1;
		}
		if (tally == tally2+1 && k == 0 && place[chest] == 0
		    && here(lamp) && prop[lamp] == 1) goto l6025;
		if (odloc[6] != dloc[6] && pct(20)) rspeak(127);
		goto l6030;
l6022:      
		rspeak(128);
		/* Don't steal chest back from troll! */
		if (place[messag] == 0) move(chest,chloc);
		move(messag,chloc2);
		for (j = 50; j <= maxtrs; j++) {
			if (j == pyram && (loc == plac[pyram]
			    || loc == plac[emrald])) goto l6023;
			if (at(j) && fixed[j] == 0) carry(j,loc);
			if (toting(j)) drop(j,chloc);
l6023:          
			; 
		}
l6024:      
		dloc[6]=chloc;
		odloc[6]=chloc;
		dseen[6]=0;
		goto l6030;
l6025:      
		rspeak(186);
		move(chest,chloc);
		move(messag,chloc2);
		goto l6024;
		/* This threatening little dwarf is in the room with him! */
l6027:     
		dtotal++;
		if (odloc[i] != dloc[i]) goto l6030;
		attack++;
		if (knfloc >= 0) knfloc=loc;
		if (ran(1000) < 95*(dflag-2))stick++;
l6030:      
		; 
	}
	/* Now we know what's happening.  let's tell the poor sucker about it.  */
	if (dtotal == 0) goto l2000;
	if (dtotal != 1) {
		printf ("There are %d threatening little dwarves", dtotal);
		printf (" in the room with you.\n");
	} else
		rspeak(4);
	if (attack == 0) goto l2000;
	if (dflag == 2) dflag=3;
	/*
		   Dwarves get VERY mad!
		*/
	if (attack == 1) {
		rspeak(5);
		k=52;
	}
	else {
		printf ("%d of them throw knives at you!\n", attack);
		k=6;
	}
	if (stick <= 1) {
		rspeak(k+stick);
		if (stick == 0) goto l2000;
	}
	else
	    printf ("%d of them get you!\n", stick);
	oldlc2=loc;
	goto l99;
	/* Describe the current location and (maybe) get next command. */
	/* Print text for current loc. */
l2000:  
	if (loc == 0) goto l99;
	kk=stext[loc];
	if (abb[loc] % abbnum == 0 || kk == 0) kk=ltext[loc];
	if (forced(loc) ||  ! dark()) goto l2001;
	if (wzdark && pct(35)) goto l90;
	kk=rtext[16];
l2001:  
	if (toting(bear)) rspeak(141);
	speak(kk);
	k=1;
	if (forced(loc)) goto l8;
	if (loc == 33 && pct(25) &&  ! closng) rspeak(8);
	/*
		   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()) goto l2012;
	abb[loc]++;
	i=atloc[loc];
	for(;;) {
		if (i == 0) goto l2012;
		obj=i;
		if (obj > 100) obj -= 100;
		if (obj == steps && toting(nugget)) goto l2008;
		if (prop[obj] < 0) {
			if (closed) goto l2008;
			prop[obj]=0;
			if (obj == rug || obj == chain) prop[obj]=1;
			tally--;
			/* If remaining treasures too elusive, zap his lamp. */
			if (tally == tally2 && tally != 0)
				limit = limit > 35? 35: limit;
		}
		kk=prop[obj];
		if (obj == steps && loc == fixed[steps]) kk=1;
		pspeak(obj,kk);
l2008:  
		i=rlink[i];
	}
l2009:  
	k=54;
l2010:  
	spk=k;
l2011:  
	rspeak(spk);
l2012:  
	verb=0;
	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).
		*/
l2600:
	for (hint = 4; hint <= hntmax; hint++) {
		if (! (hinted[hint])) {
			if (!bitset(loc,hint)) hintlc[hint]= -1;
			hintlc[hint]++;
			if (hintlc[hint] >= hints[hint][1]) goto l40000;
		}
	}
	/*
		   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).
		*/
l2602:  
	if (!closed) goto l2605;
	if (prop[oyster] < 0 && toting(oyster)
	    ) pspeak(oyster,1);
	for (i = 1; i <= 100; i++) {
		if (toting(i) && prop[i] < 0) prop[i]= -1-prop[i];
	}
l2605:  
	wzdark=dark();
	if (knfloc > 0 && knfloc != loc) knfloc=0;
	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.
		*/
l2608:
	foobar = foobar < 0? 0: -foobar;
	turns++;
	if (verb == say && !blankp(wd2)) verb=0;
	if (verb == say) goto l4090;
	if (tally == 0 && loc >= 15 && loc != 33) clock1--;
	if (clock1 == 0) goto l10000;
	if (clock1 < 0) clock2--;
	if (clock2 == 0) goto l11000;
	if (prop[lamp] == 1) limit--;
	if (limit <= 30 && here(batter) && prop[batter] == 0
	    && here(lamp)) goto l12000;
	if (limit == 0) goto l12400;
	if (limit < 0 && loc <= 8) goto l12600;
	if (limit <= 30) goto l12200;
l19999: 
	k=43;
	if (liqloc(loc) == water) k=70;
	if (eqp (wd1, "enter") && (eqp (wd2, "strea") || eqp (wd2, "water")))
		goto l2010;
	if (eqp (wd1, "enter") && !blankp(wd2)) goto l2800;
	if (!eqp (wd1, "water") && !eqp (wd1, "oil")
	    || (!eqp (wd2, "plant") && !eqp (wd2, "door "))) goto l2610;
	if (at(vocab(wd2,1))) cpy (wd2, "pour ");
l2610:  
	if (!eqp(wd1, "west ")) goto l2630;
	iwest++;
	if (iwest == 10) rspeak(17);
l2630:  
	i=vocab(wd1,-1);
	if (i == -1) goto l3000;
	k=i % 1000;
	kq=i/1000+1;
	switch (kq - 1) {
	case 0: 
		goto l8;
	case 1: 
		goto l5000;
	case 2: 
		goto l4000;
	case 3: 
		goto l2010;
	}
	bug(22);
	/* Get second word for analysis. */
l2800:  
	cpy (wd1, wd2);
	cpy (wd1x, wd2x);
	cpy (wd2, "     ");
	goto l2610;
	/* Gee, I don't understand. */
l3000:  
	spk=60;
	if (pct(20)) spk=61;
	if (pct(20)) spk=13;
	rspeak(spk);
	goto l2600;
	/*
		   Analyse a verb.  remember what it was, go back for object
		   if second word unless verb is "say", which snarfs
		   arbitrary second word.
		*/
l4000:  
	verb=k;
	spk=actspk[verb];
	if (!blankp(wd2) && verb != say) goto l2800;
	if (verb == say)
		if (blankp (wd2)) goto l4080;
		else goto l4090;
	if (obj != 0) goto l4090;
	/* Analyse an intransitive verb (ie, no object given yet). */
l4080:  
	switch (verb) {
	case 1: 
		goto l8010;       /* take */
	case 2: 
		goto l8000;       /* drop */
	case 3: 
		goto l8000;       /* say */
	case 4: 
		goto l8040;       /* open */
	case 5: 
		goto l2009;       /* noth */
	case 6: 
		goto l8040;       /* lock */
	case 7: 
		goto l9070;       /* on */
	case 8: 
		goto l9080;       /* off */
	case 9: 
		goto l8000;       /* wave */
	case 10: 
		goto l8000;       /* calm */
	case 11: 
		goto l2011;       /* walk */
	case 12: 
		goto l9120;       /* kill */
	case 13: 
		goto l9130;       /* pour */
	case 14: 
		goto l8140;       /* eat */
	case 15: 
		goto l9150;       /* drnk */
	case 16: 
		goto l8000;       /* rub */
	case 17: 
		goto l8000;       /* toss */
	case 18: 
		goto l8180;       /* quit */
	case 19: 
		goto l8000;       /* find */
	case 20: 
		goto l8200;       /* invn */
	case 21: 
		goto l8000;       /* feed */
	case 22: 
		goto l9220;       /* fill */
	case 23: 
		goto l9230;       /* blst */
	case 24: 
		goto l8240;       /* scor */
	case 25: 
		goto l8250;       /* foo */
	case 26: 
		goto l8260;       /* brf */
	case 27: 
		goto l8270;       /* read */
	case 28: 
		goto l8000;       /* brek */
	case 29: 
		goto l8000;       /* wake */
	case 30: 
		goto l8300;       /* susp */
	case 31: 
		goto l8310;       /* hour */
	case 32: 
		goto setlog;      /* log  */
	}
	bug(23);
	/* Analyse a transitive verb. */
l4090:  
	switch (verb) {
	case 1: 
		goto l9010;       /* take */
	case 2: 
		goto l9020;       /* drop */
	case 3: 
		goto l9030;       /* say */
	case 4: 
		goto l9040;       /* open */
	case 5: 
		goto l2009;       /* noth */
	case 6: 
		goto l9040;       /* lock */
	case 7: 
		goto l9070;       /* on */
	case 8: 
		goto l9080;       /* off */
	case 9: 
		goto l9090;       /* wave */
	case 10: 
		goto l2011;       /* calm */
	case 11: 
		goto l2011;       /* walk */
	case 12: 
		goto l9120;       /* kill */
	case 13: 
		goto l9130;       /* pour */
	case 14: 
		goto l9140;       /* eat */
	case 15: 
		goto l9150;       /* drnk */
	case 16: 
		goto l9160;       /* rub */
	case 17: 
		goto l9170;       /* toss */
	case 18: 
		goto l2011;       /* quit */
	case 19: 
		goto l9190;       /* find */
	case 20: 
		goto l9190;       /* invn */
	case 21: 
		goto l9210;       /* feed */
	case 22: 
		goto l9220;       /* fill */
	case 23: 
		goto l9230;       /* blst */
	case 24: 
		goto l2011;       /* scor */
	case 25: 
		goto l2011;       /* foo */
	case 26: 
		goto l2011;       /* brf */
	case 27: 
		goto l9270;       /* read */
	case 28: 
		goto l9280;       /* brek */
	case 29: 
		goto l9290;       /* wake */
	case 30: 
		goto l2011;       /* susp */
	case 31: 
		goto l2011;       /* hour */
	case 32: 
		goto l2011;       /* log  */
	}
	bug(24);
	/*
		   Analyze 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 analyzed).  Water and oil are also funny,
		   since they are never actually dropped at any location,
		   but might be here inside the bottle or as a feature of
		   the location.
		*/
l5000:  
	obj=k;
	if (fixed[k] != loc &&  ! here(k)) goto l5100;
l5010:  
	if (!blankp(wd2)) goto l2800;
	if (verb != 0) goto l4090;
	a5toa1(wd1,wd1x,tkword);
	printf ("What do you want to do with the %s?\n", tkword);
	goto l2600;
l5100:  
	if (k != grate) goto l5110;
	if (loc == 1 || loc == 4 || loc == 7) k=dprssn;
	if (loc > 9 && loc < 15) k=entrnc;
	if (k != grate) goto l8;
l5110:  
	if (k != dwarf) goto l5120;
	for (i = 1; i <= 5; i++) {
		if (dloc[i] == loc && dflag >= 2) goto l5010;
	}
l5120:  
	if ((liq() == k && here(bottle))
	    || k == liqloc(loc)) goto l5010;
	if (obj != plant ||  ! at(plant2) || prop[plant2] == 0
	    ) goto l5130;
	obj=plant2;
	goto l5010;
l5130:  
	if (obj == knife && knfloc == loc) {
		knfloc= -1;
		spk=116;
		goto l2011;
	}
	if (obj != rod ||  !here(rod2)) goto l5190;
	obj=rod2;
	goto l5010;
l5190:  
	if ((verb == find || verb == invent) && blankp (wd2)
	    ) goto l5010;
	a5toa1(wd1,wd1x,tkword);
	printf ("I see no %s here!\n", tkword);
	goto l2012;
	/*
		   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.)
		*/
l8:     
	kk=key[loc];
	newloc=loc;
	if (kk == 0) bug(26);
	if (k == nullx) goto l2;
	if (k == back) goto l20;
	if (k == look) goto l30;
	if (k == cave) goto l40;
	oldlc2=oldloc;
	oldloc=loc;
l9:     
	ll=longabs(travel[kk]);
	if (ll % 1000 == 1 || ll % 1000 == k) goto l10;
	if (travel[kk] < 0) goto l50;
	kk++;
	goto l9;
l10:    
	ll/=1000;
l11:    
	newloc=ll/1000;
	k=newloc % 100;
	if (newloc <= 300) goto l13;
	if (prop[k] != newloc/100-3) goto l16;
l12:    
	if (travel[kk] < 0) bug(25);
	kk++;
	newloc=longabs(travel[kk])/1000;
	if (newloc == ll) goto l12;
	ll=newloc;
	goto l11;
l13:    
	if (newloc <= 100) goto l14;
	if (toting(k) || (newloc > 200 && at(k))) goto l16;
	goto l12;
l14:    
	if (newloc != 0 &&  !pct((int)newloc)) goto l12;
l16:    
	newloc=ll % 1000;
	if (newloc <= 300) goto l2;
	if (newloc <= 500) goto l30000;
	rspeak((int)newloc-500);
	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).
		*/
l30000: 
	newloc=newloc-300;
	switch ((int) newloc-1) {
	case 0: 
		goto l30100;
	case 1: 
		goto l30200;
	case 2: 
		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".
		*/
l30100: 
	newloc=99+100-loc;
	if (holdng == 0 || (holdng == 1 && toting(emrald))) goto l2;
	newloc=loc;
	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.
		*/
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.
		*/
l30300: 
	if (prop[troll] != 1) goto l30310;
	pspeak(troll,1);
	prop[troll]=0;
	move(troll2,0);
	move(troll2+100,0);
	move(troll,plac[troll]);
	move(troll+100,fixd[troll]);
	juggle(chasm);
	newloc=loc;
	goto l2;
l30310: 
	newloc=plac[troll]+fixd[troll]-loc;
	if (prop[troll] == 0) prop[troll]=1;
	if (!toting(bear)) goto l2;
	rspeak(162);
	prop[chasm]=1;
	prop[troll]=2;
	drop(bear,(int)newloc);
	fixed[bear]= -1;
	prop[bear]=3;
	if (prop[spices] < 0)tally2++;
	oldlc2=newloc;
	goto l99;
	/* 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.
		*/
l20:    
	k=oldloc;
	if (forced(k)) k=oldlc2;
	oldlc2=oldloc;
	oldloc=loc;
	k2=0;
	if (k != loc) goto l21;
	rspeak(91);
	goto l2;
l21:    
	ll=(longabs(travel[kk])/1000) % 1000;
	if (ll == k) goto l25;
	if (ll > 300) goto l22;
	j=key[ll];
	if (forced((int)ll) && (longabs(travel[j])/1000) % 1000 == k
	    ) k2=kk;
l22:    
	if (travel[kk] < 0) goto l23;
	kk++;
	goto l21;
l23:    
	kk=k2;
	if (kk != 0) goto l25;
	rspeak(140);
	goto l2;
l25:    
	k=longabs(travel[kk]) % 1000;
	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.
		*/
l30:    
	if (detail < 3) rspeak(15);
	detail++;
	wzdark=0;
	abb[loc]=0;
	goto l2;
	/* Cave.  Different messages depending on whether above ground. */
l40:    
	if (loc < 8) rspeak(57);
	if (loc >= 8) rspeak(58);
	goto l2;
	/* Non-applicable motion.  Various messages depending on word given.  */
l50:    
	spk=12;
	if (k >= 43 && k <= 50) spk=9;
	if (k == 29 || k == 30) spk=9;
	if (k == 7 || k == 36 || k == 37) spk=10;
	if (k == 11 || k == 19) spk=11;
	if (verb == find || verb == invent) spk=59;
	if (k == 62 || k == 65) spk=42;
	if (k == 17) spk=80;
	rspeak(spk);
	goto l2;
	/*
		   "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.
		*/
l90:    
	rspeak(23);
	oldlc2=loc;
	/* Okay, he's dead.  Let's get on with it. */
l99:    
	if (closng) goto l95;
	yea=yes(81+numdie*2,82+numdie*2,54);
	numdie++;
	if (numdie == maxdie ||  !yea) goto l20000;
	place[water]=0;
	place[oil]=0;
	if (toting(lamp)) prop[lamp]=0;
	for (j = 1; j <= 100; j++) {
		i=101-j;
		if (!toting(i)) goto l98;
		k=oldlc2;
		if (i == lamp) k=1;
		drop(i,k);
l98:        
		;
	}
	loc=3;
	oldloc=loc;
	goto l2000;
	/* He died during closing time.  No resurrection.  tally up
		   a death and exit.  */
l95:    
	rspeak(131);
	numdie++;
	goto l20000;
	/*
		   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.
		   Random intransitive verbs come here.  Clear obj just in
		   case (see "attack").
		*/
l8000:  
	a5toa1(wd1,wd1x,tkword);
	printf ("%s what?\n", tkword);
	obj=0;
	goto l2600;
	/* Carry, no object given yet.  OK if only one object present. */
l8010:  
	if (atloc[loc] == 0 || rlink[atloc[loc]] != 0) goto l8000;
	for (i = 1; i <= 5; i++) {
		if (dloc[i] == loc && dflag >= 2) goto l8000;
	}
	obj=atloc[loc];
	/*
		   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.
		*/
l9010:  
	if (toting(obj)) goto l2011;
	spk=25;
	if (obj == plant && prop[plant] <= 0) spk=115;
	if (obj == bear && prop[bear] == 1) spk=169;
	if (obj == chain && prop[bear] != 0) spk=170;
	if (fixed[obj] != 0) goto l2011;
	if (obj != water && obj != oil) goto l9017;
	if (here(bottle) && liq() == obj) goto l9018;
	obj=bottle;
	if (toting(bottle) && prop[bottle] == 1) goto l9220;
	if (prop[bottle] != 1) spk=105;
	if (!toting(bottle)) spk=104;
	goto l2011;
l9018:  
	obj=bottle;
l9017:  
	if (holdng < 7) goto l9016;
	rspeak(92);
	goto l2012;
l9016:  
	if (obj != bird) goto l9014;
	if (prop[bird] != 0) goto l9014;
	if (!toting(rod)) goto l9013;
	rspeak(26);
	goto l2012;
l9013:  
	if (toting(cage)) goto l9015;
	rspeak(27);
	goto l2012;
l9015:  
	prop[bird]=1;
l9014:  
	if ((obj == bird || obj == cage) && prop[bird] != 0
	    ) carry(bird+cage-obj,loc);
	carry(obj,loc);
	k=liq();
	if (obj == bottle && k != 0) place[k]= -1;
	goto l2009;
	/*
		   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.
		*/
l9020:  
	if (toting(rod2) && obj == rod && ! toting(rod)) obj=rod2;
	if (!toting(obj)) goto l2011;
	if (obj != bird ||  ! here(snake)) goto l9024;
	rspeak(30);
	if (closed) goto l19000;
	dstroy(snake);
	/* Set prop for use by travel options */
	prop[snake]=1;
l9021:  
	k=liq();
	if (k == obj) obj=bottle;
	if (obj == bottle && k != 0) place[k]=0;
	if (obj == cage && prop[bird] != 0) drop(bird,loc);
	if (obj == bird) prop[bird]=0;
	drop(obj,loc);
	goto l2012;
l9024:  
	if (obj != coins ||  ! here(vend)) goto l9025;
	dstroy(coins);
	drop(batter,loc);
	pspeak(batter,0);
	goto l2012;
l9025:  
	if (obj != bird ||  ! at(dragon) || prop[dragon] != 0
	    ) goto l9026;
	rspeak(154);
	dstroy(bird);
	prop[bird]=0;
	if (place[snake] == plac[snake])tally2++;
	goto l2012;
l9026:  
	if (obj != bear ||  !at(troll)) goto l9027;
	rspeak(163);
	move(troll,0);
	move(troll+100,0);
	move(troll2,plac[troll]);
	move(troll2+100,fixd[troll]);
	juggle(chasm);
	prop[troll]=2;
	goto l9021;
l9027:  
	if (obj == vase && loc != plac[pillow]) goto l9028;
	rspeak(54);
	goto l9021;
l9028:  
	prop[vase]=2;
	if (at(pillow)) prop[vase]=0;
	pspeak(vase,prop[vase]+1);
	if (prop[vase] != 0) fixed[vase]= -1;
	goto l9021;
	/* Say.  Echo wd2 (or wd1 if no wd2 (say what?, etc.).)
		   Magic words override.  */
l9030:  
	a5toa1(wd2,wd2x,tkword);
	if (blankp(wd2)) a5toa1(wd1,wd1x,tkword);
	else cpy(wd1,wd2);
	i=vocab(wd1,-1);
	if (i == 62 || i == 65 || i == 71 || i == 2025) goto l9035;
	printf ("Okay, \"%s\"\n", tkword);
	goto l2012;
l9035:  
	cpy(wd2, "     ");
	obj=0;
	goto l2630;
	/* Lock, unlock, no object given.  Assume various things if present.  */
l8040:  
	spk=28;
	if (here(clam)) obj=clam;
	if (here(oyster)) obj=oyster;
	if (at(door)) obj=door;
	if (at(grate)) obj=grate;
	if (obj != 0 && here(chain)) goto l8000;
	if (here(chain)) obj=chain;
	if (obj == 0) goto l2011;
	/* 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;
	if (obj == door && prop[door] == 1) spk=54;
	if (obj == cage) spk=32;
	if (obj == keys) spk=55;
	if (obj == grate || obj == chain) spk=31;
	if (spk != 31 ||  ! here(keys)) goto l2011;
	if (obj == chain) goto l9048;
	if (!closng) goto l9043;
	k=130;
	if (!panic) clock2=15;
	panic=1;
	goto l2010;
l9043:  
	k=34+prop[grate];
	prop[grate]=1;
	if (verb == lock) prop[grate]=0;
	k=k+2*prop[grate];
	goto l2010;
	/* Clam/oyster. */
l9046:  
	k=0;
	if (obj == oyster) k=1;
	spk=124+k;
	if (toting(obj)) spk=120+k;
	if (!toting(tridnt)) spk=122+k;
	if (verb == lock) spk=61;
	if (spk != 124) goto l2011;
	dstroy(clam);
	drop(oyster,loc);
	drop(pearl,105);
	goto l2011;
	/* Chain. */
l9048:  
	if (verb == lock) goto l9049;
	spk=171;
	if (prop[bear] == 0) spk=41;
	if (prop[chain] == 0) spk=37;
	if (spk != 171) goto l2011;
	prop[chain]=0;
	fixed[chain]=0;
	if (prop[bear] != 3) prop[bear]=2;
	fixed[bear]=2-prop[bear];
	goto l2011;
l9049:  
	spk=172;
	if (prop[chain] != 0) spk=34;
	if (loc != plac[chain]) spk=173;
	if (spk != 172) goto l2011;
	prop[chain]=2;
	if (toting(chain)) drop(chain,loc);
	fixed[chain]= -1;
	goto l2011;
	/* Light lamp */
l9070:  
	if(!here(lamp)) goto l2011;
	spk=184;
	if(limit < 0) goto l2011;
	prop[lamp]=1;
	rspeak(39);
	if(wzdark) goto l2000;
	goto l2012;
	/* Lamp off */
l9080:  
	if(!here(lamp)) goto l2011;
	prop[lamp]=0;
	rspeak(40);
	if(dark()) rspeak(16);
	goto l2012;
	/* Wave.  No effect unless waving rod at fissure. */
l9090:  
	if ((!toting(obj)) && (obj != rod ||  ! toting(rod2))
	    ) spk=29;
	if (obj != rod ||  ! at(fissur) ||  ! toting(obj)
	    || closng) goto l2011;
	prop[fissur]=1-prop[fissur];
	pspeak(fissur,2-prop[fissur]);
	goto l2012;
	/*
		   Attack.  Assume target if unambiguous.  "throw" also
		   links here.  Attackable objects fall into two categories:
		   enemies (snake, dwarf, etc.) and others (bird, clam).
		   Ambiguous if two enemies, or if no enemies but two
		   others.
		*/
l9120:  
	for (i = 1; i <= 5; i++) {
		if(dloc[i] == loc && dflag >= 2) goto l9122;
	}
	i=0;
l9122:  
	if(obj != 0) goto l9124;
	if(i != 0) obj=dwarf;
	if(here(snake)) obj=obj*100+snake;
	if(at(dragon) && prop[dragon] == 0) obj=obj*100+dragon;
	if(at(troll)) obj=obj*100+troll;
	if(here(bear) && prop[bear] == 0) obj=obj*100+bear;
	if(obj > 100) goto l8000;
	if(obj != 0) goto l9124;
	/* Can't attack bird by throwing axe. */
	if(here(bird) && verb != throw) obj=bird;
	/* Clam and oyster both treated as clam for intransitive
		   case; no harm done.  */
	if(here(clam) || here(oyster)) obj=100*obj+clam;
	if(obj > 100) goto l8000;
l9124:  
	if(obj != bird) goto l9125;
	spk=137;
	if(closed) goto l2011;
	dstroy(bird);
	prop[bird]=0;
	if(place[snake] == plac[snake])tally2++;
	spk=45;
l9125:  
	if(obj == 0) spk=44;
	if(obj == clam || obj == oyster) spk=150;
	if(obj == snake) spk=46;
	if(obj == dwarf) spk=49;
	if(obj == dwarf && closed) goto l19000;
	if(obj == dragon) spk=167;
	if(obj == troll) spk=157;
	if(obj == bear) spk=165+(prop[bear]+1)/2;
	if(obj != dragon || prop[dragon] != 0) goto l2011;
	/*
		   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;
	getin(wd1,wd1x,wd2,wd2x);
	if (!eqp (wd1, "y") && !eqp (wd1, "yes")) goto l2608;
	pspeak(dragon,1);
	prop[dragon]=2;
	prop[rug]=0;
	k=(plac[dragon]+fixd[dragon])/2;
	move(dragon+100,-1);
	move(rug+100,0);
	move(dragon,k);
	move(rug,k);
	for (obj=1; obj<=100; obj++) {
		if (place[obj] == plac[dragon] || place[obj] == fixd[dragon]
		    ) move(obj,k);
	}
	loc=k;
	k=nullx;
	goto l8;
	/*
		   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();
	if(obj == 0) goto l8000;
	if(!toting(obj)) goto l2011;
	spk=78;
	if(obj != oil && obj != water) goto l2011;
	prop[bottle]=1;
	place[obj]=0;
	spk=77;
	if(!(at(plant) || at(door))) goto l2011;
	if(at(door)) goto l9132;
	spk=112;
	if(obj != water) goto l2011;
	pspeak(plant,prop[plant]+1);
	prop[plant]=(prop[plant]+2) % 6;
	prop[plant2]=prop[plant]/2;
	k=nullx;
	goto l8;
l9132:  
	prop[door]=0;
	if(obj == oil) prop[door]=1;
	spk=113+prop[door];
	goto l2011;
	/*
		   Eat.  Intransitive:  assume food if present, else ask
		   what.  Transitive:  food ok, some things lose appetite,
		   rest are ridiculous.
		*/
l8140:  
	if(!here(food)) goto l8000;
l8142:  
	dstroy(food);
	spk=72;
	goto l2011;
l9140:  
	if(obj == food) goto l8142;
	if (obj == bird || obj == snake || obj == clam || obj == oyster
	    || obj == dwarf || obj == dragon || obj == troll
	    || obj == bear) spk=71;
	goto l2011;
	/*
		   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() != water
	    ||  ! here(bottle))) goto l8000;
	if(obj != 0 && obj != water) spk=110;
	if (spk == 110 || liq() != water ||  ! here(bottle)
	    ) goto l2011;
	prop[bottle]=1;
	place[water]=0;
	spk=74;
	goto l2011;
	/* Rub.  Yields various snide remarks. */
l9160:  
	if(obj != lamp) spk=76;
	goto l2011;
	/*
		   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.
		*/
l9170:  
	if(toting(rod2) && obj == rod &&  ! toting(rod)) obj=rod2;
	if(!toting(obj)) goto l2011;
	if(obj >= 50 && obj <= maxtrs && at(troll)) goto l9178;
	if(obj == food && here(bear)) goto l9177;
	if(obj != axe) goto l9020;
	for (i = 1; i <= 5; i++) {
		/* Needn't check dflag if axe is here. */
		if(dloc[i] == loc) goto l9172;
	}
	spk=152;
	if(at(dragon) && prop[dragon] == 0) goto l9175;
	spk=158;
	if(at(troll)) goto l9175;
	if(here(bear) && prop[bear] == 0) goto l9176;
	obj=0;
	goto l9120;
l9172:  
	spk=48;
	if(ran(3) == 0) goto l9175;
	dseen[i]=0;
	dloc[i]=0;
	spk=47;
	dkill++;
	if(dkill == 1) spk=149;
l9175:  
	rspeak(spk);
	drop(axe,loc);
	k=nullx;
	goto l8;
	/* This'll teach him to throw the axe at the bear! */
l9176:  
	spk=164;
	drop(axe,loc);
	fixed[axe]= -1;
	prop[axe]=1;
	juggle(bear);
	goto l2011;
	/* But throwing food is another story. */
l9177:  
	obj=bear;
	goto l9210;
l9178:  
	spk=159;
	/* Snarf a treasure for the troll. */
	drop(obj,0);
	move(troll,0);
	move(troll+100,0);
	drop(troll2,plac[troll]);
	drop(troll2+100,fixd[troll]);
	juggle(chasm);
	goto l2011;
	/* Quit.  Intransitive only.  Verify intent and exit if
		   that's what he wants.  */
l8180:  
	gaveup=yes(22,54,54);
	if(gaveup) goto l20000;
	goto l2012;
	/* Find.  Might be carrying it, or it might be here.  Else give caveat. */
l9190:  
	if (at(obj) || (liq() == obj && at(bottle))
	    || k == liqloc(loc)) spk=94;
	for (i = 1; i <= 5; i++) {
		if(dloc[i] == loc && dflag >= 2 && obj == dwarf) spk=94;
	}
	if(closed) spk=138;
	if(toting(obj)) spk=24;
	goto l2011;
	/* Inventory.  If object, treat same as find.  Else report
		   on current burden.  */
l8200:  
	spk=98;
	for (i = 1; i <= 100; i++) {
		if(i == bear ||  ! toting(i)) goto l8201;
		if(spk == 98) rspeak(99);
		blklin=0;
		pspeak(i,-1);
		blklin=1;
		spk=0;
l8201:     
		;
	}
	if(toting(bear)) spk=141;
	goto l2011;
	/*
		Feed.  If bird, no seed.  snake, dragon, troll:  quip.  If
		   dwarf, make him mad.  Bear, special.
		*/
l9210:  
	if(obj != bird) goto l9212;
	spk=100;
	goto l2011;
l9212:  
	if(obj != snake && obj != dragon && obj != troll) goto l9213;
	spk=102;
	if(obj == dragon && prop[dragon] != 0) spk=110;
	if(obj == troll) spk=182;
	if(obj != snake || closed ||  ! here(bird)) goto l2011;
	spk=101;
	dstroy(bird);
	prop[bird]=0;
	tally2++;
	goto l2011;
l9213:  
	if(obj != dwarf) goto l9214;
	if(!here(food)) goto l2011;
	spk=103;
	dflag++;
	goto l2011;
l9214:  
	if(obj != bear) goto l9215;
	if(prop[bear] == 0) spk=102;
	if(prop[bear] == 3) spk=110;
	if(!here(food)) goto l2011;
	dstroy(food);
	prop[bear]=1;
	fixed[axe]=0;
	prop[axe]=0;
	spk=168;
	goto l2011;
l9215:  
	spk=14;
	goto l2011;
	/* Fill.  Bottle must be empty, and some liquid available.
		   (vase is nasty.) */
l9220:  
	if(obj == vase) goto l9222;
	if(obj != 0 && obj != bottle) goto l2011;
	if(obj == 0 &&  ! here(bottle)) goto l8000;
	spk=107;
	if(liqloc(loc) == 0) spk=106;
	if(liq() != 0) spk=105;
	if(spk != 107) goto l2011;
	prop[bottle]=(cond[loc] % 4)/2;
	prop[bottle]=prop[bottle]*2;
	k=liq();
	if(toting(bottle)) place[k]= -1;
	if(k == oil) spk=108;
	goto l2011;
l9222:  
	spk=29;
	if(liqloc(loc) == 0) spk=144;
	if(liqloc(loc) == 0 ||  !toting(vase)) goto l2011;
	rspeak(145);
	prop[vase]=2;
	fixed[vase]= -1;
	goto l9024;
	/* Blast.  No effect unless you've got dynamite, which is a
		   neat trick!  */
l9230:  
	if(prop[rod2] < 0 ||  ! closed) goto l2011;
	bonus=133;
	if(loc == 115) bonus=134;
	if(here(rod2)) bonus=135;
	rspeak(bonus);
	goto l20000;
	/* Score.  Go to scoring section, which will return to 8241
		   if scorng is true.  */
l8240:  
	scorng=1;
	goto l20000;
l8241:  
	scorng=0;
	printf ("If you were to quit now, you would score ");
	printf ("%d out of a possible %d in %d turns.\n",
	score, mxscor, turns+1);
	goto l2012;
	/*
		   Fee fie foe foo (and fum).  Advance to next state if given
		   in proper order.  Look up wd1 in section 3 of vocab to
		   determine which word we've got.  Last word zips the eggs
		   back to the giant room (unless already there).
		*/
l8250:  
	k=vocab(wd1,3);
	spk=42;
	if(foobar == 1-k) goto l8252;
	if(foobar != 0) spk=151;
	goto l2011;
l8252:  
	foobar=k;
	if(k != 4) goto l2009;
	foobar=0;
	if (place[eggs] == plac[eggs]
	    || (toting(eggs) && loc == plac[eggs])) goto l2011;
	/* 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;
	if(here(eggs)) k=1;
	if(loc == plac[eggs]) k=0;
	move(eggs,plac[eggs]);
	pspeak(eggs,k);
	goto l2012;
	/* Brief.  Intransitive only.  Suppress long descriptions
		   after first time.  */
l8260:  
	spk=156;
	abbnum=10000;
	detail=3;
	goto l2011;
	/* Read.  Magazines in dwarvish, message we've seen, and .
		   .  .  oyster?  */
l8270:  
	if(here(magzin)) obj=magzin;
	if(here(tablet)) obj=obj*100+tablet;
	if(here(messag)) obj=obj*100+messag;
	if(closed && toting(oyster)) obj=oyster;
	if(obj > 100 || obj == 0 || dark()) goto l8000;
l9270:  
	if(dark()) goto l5190;
	if(obj == magzin) spk=190;
	if(obj == tablet) spk=196;
	if(obj == messag) spk=191;
	if(obj == oyster && hinted[2] && toting(oyster)) spk=194;
	if (obj != oyster || hinted[2] ||  !toting(oyster)
	    ||  !closed) goto l2011;
	hinted[2]=yes(192,193,54);
	goto l2012;
	/* 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;
	if(obj != mirror ||  !closed) goto l2011;
	rspeak(197);
	goto l19000;
l9282:  
	spk=198;
	if(toting(vase)) drop(vase,loc);
	prop[vase]=2;
	fixed[vase]= -1;
	goto l2011;
	/* Wake.  Only use is to disturb the dwarves. */
l9290:  
	if(obj != dwarf ||  !closed) goto l2011;
	rspeak(199);
	goto l19000;
	/*
			Suspend. Exit leaving things restartable.
		*/
l8300:
	if ((suspfd = fopen (suspfile, SUSPWRITE)) == NULL) {
		printf ("Something's wrong...I can't suspend.\n");
		if (hungup) {
			hungup = 0;
			goto l20000;
		}
		goto l2012;
	}
	hungup = 0;
	printf ("OK...I'm suspending this game in %s\n", suspfile);

	/* Block interrupts to ensure completion of suspension */
	signal (SIGINT, SIG_IGN);
	signal (SIGQUIT, SIG_IGN);
	signal (SIGHUP, SIG_IGN);

	/* Write the release and level into the suspend file */
	putw (1, suspfd);
	putw (20, suspfd);

	/* Write the time to prevent premature resumption */
	tvec = time(0);
	putl (tvec, suspfd);

	/* Write the suspend data into the file */
	fwrite (&suspbeg, sizeof suspbeg, &suspend - &suspbeg, suspfd);

	/* Make sure everything went ok */
	if (ferror (suspfd))
		fatal ("I/O error during suspension");

	fclose (suspfd);
#ifdef NOTIME
	printf ("Play will resume automatically next time.\n");
#else
	printf ("You may resume play half an hour from now.\n");
#endif
	exit(0);
	/* Hours.  Report current non-prime-time hours. */
l8310:
	printf (HOURS);
	goto l2012;
	/* Log.  Toggle loggin either on or off */
setlog: 
	logon = ! logon;
	if (logon)
		printf ("Log on.\n");
	else
	    printf ("Log off.\n");
	goto l2012;
	/*
		   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.
		*/
l40000: 
	switch (hint-4) {
	case 0: 
		goto l40400;        /* cave */
	case 1: 
		goto l40500;        /* bird */
	case 2: 
		goto l40600;        /* snake */
	case 3: 
		goto l40700;        /* maze */
	case 4: 
		goto l40800;        /* dark */
	case 5: 
		goto l40900;        /* witt */
	}
	bug(27);
l40010: 
	hintlc[hint]=0;
	if(!yes(hints[hint][3],0,54)) goto l2602;
	printf ("I am prepared to give you a hint,");
	printf (" but it will cost you %d points.\n", hints[hint][2]);
	hinted[hint]=yes(175,hints[hint][4],54);
	if (hinted[hint] && limit > 30
	    ) limit=limit+30*hints[hint][2];
l40020: 
	hintlc[hint]=0;
l40030: 
	goto l2602;
	/* Now for the quick tests.  See database description for
		   one-line notes.  */
l40400: 
	if(prop[grate] == 0 &&  ! here(keys)) goto l40010;
	goto l40020;
l40500: 
	if(here(bird) && toting(rod) && obj == bird) goto l40010;
	goto l40030;
l40600: 
	if(here(snake) &&  ! here(bird)) goto l40010;
	goto l40020;
l40700: 
	if (atloc[loc] == 0 && atloc[oldloc] == 0
	    && atloc[oldlc2] == 0 && holdng > 1) goto l40010;
	goto l40020;
l40800: 
	if(prop[emrald] != -1 && prop[pyram] == -1) goto l40010;
	goto l40020;
l40900: 
	goto l40010;
	/*
		   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.
		   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 (loc<9), 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;
	for (i = 1; i <= 6; i++) {
		dseen[i]=0;
	}
	move(troll,0);
	move(troll+100,0);
	move(troll2,plac[troll]);
	move(troll2+100,fixd[troll]);
	juggle(chasm);
	if(prop[bear] != 3) dstroy(bear);
	prop[chain]=0;
	fixed[chain]=0;
	prop[axe]=0;
	fixed[axe]=0;
	rspeak(129);
	clock1= -1;
	closng=1;
	goto l19999;
	/*
		   Once he's panicked, and clock2 has run out, we come here
		   to set up the storage room.  The room has two locs,
		   hardwired as 115 (ne) and 116 (sw).  At the ne end, we
		   place empty bottles, a nursery of plants, a bed of
		   oysters, a pile of lamps, rods with stars, sleeping
		   dwarves, and him.  At the sw end we place grate over
		   treasures, snake pit, covey of caged birds, more rods,
		   and pillows.  A mirror stretches across one wall.  Many
		   of the objects come from known locations and/or states
		   (e.g.  the snake is known to have been destroyed and
		   needn't be carried away from its old "place"), making the
		   various objects be handled differently.  We also drop all
		   other objects he might be carrying (lest he have some
		   which could cause trouble, such as the keys).  We
		   describe the flash of light and trundle back.
		*/
l11000: 
	prop[bottle]=put(bottle,115,1);
	prop[plant]=put(plant,115,0);
	prop[oyster]=put(oyster,115,0);
	prop[lamp]=put(lamp,115,0);
	prop[rod]=put(rod,115,0);
	prop[dwarf]=put(dwarf,115,0);
	loc=115;
	oldloc=115;
	newloc=115;
	/* Leave the grate with normal (non-negative property). */
	foo=put(grate,116,0);
	prop[snake]=put(snake,116,1);
	prop[bird]=put(bird,116,1);
	prop[cage]=put(cage,116,0);
	prop[rod2]=put(rod2,116,0);
	prop[pillow]=put(pillow,116,0);
	prop[mirror]=put(mirror,115,0);
	fixed[mirror]=116;
	for (i = 1; i <= 100; i++) {
		if(toting(i)) dstroy(i);
	}
	rspeak(132);
	closed=1;
	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, and 12600 is if he's wandered
		   outside and the lamp is used up, in which case we force
		   him to give up.
		*/
l12000: 
	rspeak(188);
	prop[batter]=1;
	if(toting(batter)) drop(batter,loc);
	limit=limit+2500;
	lmwarn=0;
	goto l19999;
l12200: 
	if (lmwarn ||  !here(lamp)) goto l19999;
	lmwarn=1;
	spk=187;
	if (place[batter] == 0) spk=183;
	if (prop[batter] == 1) spk=189;
	rspeak(spk);
	goto l19999;
l12400: 
	limit= -1;
	prop[lamp]=0;
	if (here(lamp)) rspeak(184);
	goto l19999;
l12600: 
	rspeak(185);
	gaveup=1;
	goto l20000;
	/* Oh dear, he's disturbed the dwarves. */
l19000: 
	rspeak(136);
	/*
		   Exit code.
		   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                   144
		   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:   350
		   (points can also be deducted for using hints.)
		*/
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.
		*/
	for (i = 50; i <= maxtrs; i++) {
		if (ptext[i] != 0) {
			k=12;
			if (i == chest) k=14;
			if (i > chest) k=16;
			if (prop[i] >= 0) score=score+2;
			if (place[i] == 3 && prop[i] == 0) score=score+k-2;
			mxscor=mxscor+k;
		}
	}
	/*
		   Now look at how he finished and how far he got.  maxdie
		   and numdie tell us how well he survived.  gaveup says
		   whether he exited via quit.  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 (!(scorng || gaveup)) score=score+4;
	mxscor=mxscor+4;
	if (dflag != 0) score=score+25;
	mxscor=mxscor+25;
	if (closng) score=score+25;
	mxscor=mxscor+25;
	if (!closed) goto l20020;
	if (bonus == 0) score=score+10;
	if (bonus == 135) score=score+25;
	if (bonus == 134) score=score+30;
	if (bonus == 133) score=score+45;
l20020: 
	mxscor=mxscor+45;
	/* Did he come to Witt's End as he should? */
	if (place[magzin] == 108)score++;
	mxscor++;
	/* Round it off. */
	score=score+2;
	mxscor=mxscor+2;
	/* Deduct points for hints.  hints < 4 are special; see
		   database description.  */
	for (i = 1; i <= hntmax; i++) {
		if (hinted[i]) score=score-hints[i][2];
	}
	/* Return to score command if that's where we came from. */
	if (scorng) goto l8241;
	/* That should be good enough.  Let's tell him all about it. */
	printf ("You scored %d out of a possible %d using %d turn%s.\n",
	score, mxscor, turns, turns==1? "": "s");
	for (i = 1; i <= clsses; i++) {
		if (cval[i] >= score) goto l20210;
	}
	printf("You just went off my scale!!!\n");
	goto l25000;
l20210: 
	speak(ctext[i]);
	if (i == clsses-1) goto l20220;
	k=cval[i]+1-score;
	printf ("To achieve the next higher rating, you need %d more point%s.\n",
	k, k==1? "": "s");
	goto l25000;
l20220:
	printf ("To achieve the next higher rating would be a neat trick!\n");
	printf ("Congratulations!!\n");
l25000:
	if (logon) {
		/* Log this termination for the interest of other users */
		FILE *logfile;
		char *ctime();
		if ((logfile = fopen ("/usr/games/advlog", "a")) != NULL) {
			tvec = time((long *) 0);
			cp1 = ctime (&tvec);
			/* Assumed format "Mon Jan 99 99:99:99 1999\n\0" */
			cp1[10] = '\0';
			fprintf (logfile, "%s; %s: %d in %d\n",
			cp1 + 4, pwbuf -> pw_name,
			score, turns);
		}
	}
}

/*
 *	subroutines/functions
 *	toting(obj)  = true if the obj is being carried
 *	here(obj)    = true if the obj is at "loc" (or is being carried)
 *	at(obj)      = true if on either side of two-placed object
 *	liq(dummy)   = object number of liquid in bottle
 *	liqloc(loc)  = object number of liquid (if any) at loc
 *	bitset(l,n)  = true if cond(l) has bit n set (bit 0 is units bit)
 *	forced(loc)  = true if loc moves without asking for input (cond=2)
 *	dark(dummy)  = true if location "loc" is dark
 *	pct(n)       = true n% of the time (n integer from 0 to 100)
 */

toting(ob)
{
	return place[ob] == -1;
}

here(ob)
{
	return place[ob] == loc || toting (ob);
}

at(ob)
{
	return place[ob] == loc || fixed[ob] == loc;
}

liq2(pbotl)
{
	int liq2temp;
	liq2temp = pbotl/2;
	return (1-pbotl)*water + liq2temp * (water+oil);
}

liq()
{
	int t;
	t = prop[bottle];
	return liq2(t>-1-t? t: -1-t);
}

liqloc(where)
{
	int t1, t2;
	t1 = cond[where] / 2;
	t1 = t1 * 2;
	t2 = cond[where] / 4;
	return liq2 (((t1 % 8)-5)*(t2%2)+1);
}

bitset (mm, n)
{
	return (cond[mm] >> n) & 1;
}

forced(where)
{
	return cond[where] == 2;
}

dark()
{
	return ((cond[loc] & 1) == 0) && (prop[lamp] == 0 || !here(lamp));
}

pct (n)
{
	return ran(100) < n;
}

/*
 *	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.
 */
move (object, where) {
	int source;
	if (object <= 100)
		source = place[object];
	else
		source = fixed[object-100];
	if (source > 0 && source <= 300)
		carry (object, source);
	drop (object, where);
}

dstroy (object)
{
	move (object, 0);
}

juggle (object)
{
	register int ii, jj;
	ii = place[object];
	jj = fixed [object];
	move (object, ii);
	move (object+100, jj);
}

put (object, where, pval)
{
	move (object, where);
	return -1-pval;
}

/*
 *	Start toting an object, removing it from the list of things at
 *	its former location. Increment holding unless it was already
 *	being toted. If object>100 (moving "fixed" second loc)
 *	don't change place or holdng.
 */
carry (object, where)
{
	int tmp;
	if (object <= 100) {
		if (place[object] == -1) return;
		place[object] = -1;
		holdng++;
	}
	if (atloc[where] == object) {
		atloc[where] = rlink[object];
		return;
	}
	tmp = atloc[where];
	while (rlink[tmp] != object)
		tmp = rlink[tmp];
	rlink[tmp] = rlink[object];
}

/*
 *	Place an object at a given loc, prefixing ot onto the atloc list.
 *	Decrement holdng if the object was being toted.
 */
drop (object, where)
{
	if (object > 100)
		fixed[object-100] = where;
	else
	    {
		if (place[object] == -1) holdng--;
		place[object] = where;
	}
	if (where <= 0) return;
	rlink[object] = atloc[where];
	atloc[where] = object;
}

fatal(s)
	char *s;
{
	printf ("\nFatal error: %s\n", s);
	exit(1);
}

bug(n)
{
	printf ("Bug number %d\n", n);
	printf ("Program quits\n");
	exit(1);
}

/* Returns a random number between 0 and num-1 inclusive */
ran(num)
{
	return (((long) num * rand()) / 32768L);
}

/*
 *	return 1 if the five-character argument
 *	is entirely blank, 0 otherwise
 */
blankp(a5)
char *a5;
{
	return eqp (a5, "     ");
}

/*
 *	return 1 if a5 and b5 are equal, 0 otherwise.
 *	The lengths of a5 and b5 are limited to 5,
 *	but if either contains a null character, it is assumed
 *	to be padded out to length 5 with blanks.
 */
eqp(a5, b5)
	char *a5, *b5;
{
	register int z;
	register char *aa, *bb;
	aa = a5;
	bb = b5;
	z = 5;
	do {
		if ((*aa == '\0'? ' ': *aa++) !=
		    (*bb == '\0'? ' ': *bb++))
			return 0;
	} while (--z);
	return 1;
}

/*
 *	copy the character string from "source" to "sink". Length is limited
 *	to 5 characters, and "sink" is blank padded if "source" is shorter.
 */
cpy (sink, source)
	register char *source, *sink;
{
	register n;
	n = 5;
	do {
		if (*source == '\0')
			*sink++ = ' ';
		else
		    *sink++ = *source++;
	} while (--n);
}

/*
 *	Look up id in the vocabulary (atab) and return its "definition"
 *	(ktab), or -1 if not found. If init is positive, this is an
 *	initialization 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. It also
 *	means the ktab value is taken mod 1000.
 */
vocab (id, init)
char *id;
{
	for (i=1; i<=tabsiz; i++) {
		if (ktab[i] == -1) goto l2;
		if ((init < 0 || init == ktab[i]/1000) && eqp(atab[i], id))
			goto l3;
	}
	bug(21);
l2:
	if (init < 0) return -1;
	bug(5);
l3:
	return init<0? ktab[i]: ktab[i] % 1000;
}

/*
 *	This program catenates the characters of x and y, which are assumed to
 *	be 5-character fields, into z. The process stops at the first blank,
 *	and a null character is appended to the result.
 */
a5toa1 (x, y, z)
	char *x, *y, *z;
{
	register int n;
	n = 5;
	do {
		if (*x == ' ') {
			*z++ = '\0';
			return;
		}
		*z++ = *x++;
	} while (--n);
	n = 5;
	do {
		if (*y == ' ') {
			*z++ = '\0';
			return;
		}
		*z++ = *y++;
	} while (--n);
	*z++ = '\0';
}

/*
 *	Get a command from the terminal. The first word goes into pl and pr,
 *	and the second word goes into ql and qr. In each case the word is
 *	padded with blanks to 10 characters; the first 5 will be in the "l"
 *	variable and the second 5 will be in the "r" variable.
 *	If hungup is nonzero, indicating he hung up the phone, fudge
 *	pl, pr, ql, and qr to make it look as if he typed "suspend".
 */
getin (pl, pr, ql, qr)
	char *pl, *pr, *ql, *qr;
{
	register int p;
	cpy (pl, "");
	cpy (pr, "");
	cpy (ql, "");
	cpy (qr, "");
	fflush(stdout);
	/* Eat blank lines */
	if (!hungup) {
		while ((p = getchar()) == '\n');
		while (p == '!') {
			char pl[512];
			if (fgets (pl, sizeof(pl), stdin) == 0)
				p = EOF;
			if (strcmp (pwbuf->pw_name, "games") == 0)
				printf ("No Shell escape from \"games\"\n");
			else {
				system (pl);
				printf ("!\n");
				fflush (stdout);
			}
			if (p != EOF)
				p = getchar();
		}
		if (p == EOF) {
			cpy (pl, "suspe");
			cpy (pr, "nd");
			hungup = 1;
			return;
		}
		ungetc (p, stdin);
	}
	if (snarf (pl, pr) && snarf (ql, qr))
		while (getchar() != '\n');
}

/*
 *	This is a subroutine of getin
 */
snarf (left, right)
	char *left, *right;
{
	register int n;
	char s[10];
	register int p;
	/* Blank the array */
	for (n=0; n<10; n++)
		s[n] = ' ';
	/* If hung up phone, pretend he said 'suspend' followed by nl */
	if (hungup)
		goto susp;
	/* Skip leading blanks; if nl encountered, return immediately */
	while ((p=getchar()) == ' ');
	if (p == '\n') return 0;
	if (p == EOF) goto susp;
	/* Now eat characters until blank or newline */
	n = 0;
	do {
		if (n < 10)
			s[n++] = p;
		p = getchar();
		if (p == EOF) goto susp;
	} while (p != ' ' && p != '\n');
	/* Break up the string into two five-character components */
	cpy (left, s);
	cpy (right, s+5);
	/* Indicate to caller whether we hit a blank or newline */
	return p == ' ';
	/* Abnormal exit for EOF */
susp:
	cpy (left, "suspe");
	cpy (right, "nd");
	hungup = 1;
	return 0;
}

/*
 *	Print the n-th "random" message (section 6)
 */
rspeak(n)
{
	if (n != 0)
		speak (rtext[n]);
}

/*
 *	Print the message which starts at lines[n]
 */
speak(n)
{
	long rec;
	do {
		rec = lines[n];
		if (rec < 0)
			rec = -rec;
		fseek (caves, rec, 0);
		fgets (linebuf, sizeof linebuf, caves);
		if (linebuf[0] != '>')
			fputs (linebuf, stdout);
	} while (++n < linuse && lines[n] >= 0);
}

/*
 *	Find the skip+1st message from msg and print it. Msg should be
 *	the index of the inventory message for object
 */
pspeak (msg, skip)
{
	int n, q;
	q = ptext[msg];
	if (skip >= 0)
		for (n=0; n<=skip; n++) {
			while (lines[++q] >= 0);
		}
	speak(q);
}

/*
 *	Print message x, wait for yes/no. If yes, print message y and leave
 *	"yea" true; else print message z and leave "yea" false.
 *	If hungup is nonzero, he hung up the phone, so simulate an
 *	answer of "no".
 */
yes (x, y, z) {
	char reply[300];
	rspeak(x);
	fflush(stdout);
	if (scanf ("%s", reply) == EOF)
		hungup = 1;
	while (hungup == 0 && reply[0] != 'y' && reply[0] != 'n') {
		printf ("Please answer the question.\n");
		fflush(stdout);
		if (scanf ("%s", reply) == EOF)
			hungup = 1;
	}
	if (yea = (reply[0] == 'y' && hungup == 0)) {
		if (y != 0)
			rspeak(y);
	} else if (z != 0)
		rspeak (z);
	return yea;
}