|
|
1.1 root 1: /* Adventure (3/6/79 17:32:41 1.20)
2: Current limits:
3: 999 lines, linsiz of message text (lines).
4: 750 travel options (travel, trvsiz).
5: 300 vocabulary words (ktab, atab, tabsiz).
6: 150 locations (ltext, stext, key, cond, abb, atloc, locsiz).
7: 100 objects (plac, place, fixd, fixed, rlink (twice), ptext,
8: prop).
9: 35 "action" verbs (actspk, vrbsiz).
10: 205 random messages (rtext, rtxsiz).
11: 12 different player classifications (ctext, cval, clsmax).
12: 20 hints, less 3 (hintlc, hinted, hints, hntsiz).
13: 35 magic messages (mtext, magsiz).
14: there are also limits which cannot be exceeded due to the
15: structure of the database. (e.g., the vocabulary uses
16: n/1000 to determine word type, so there can't be more
17: than 1000 words.) these upper limits are:
18: 1000 non-synonymous vocabulary words
19: 300 locations
20: 100 objects
21: */
22: #include <stdio.h>
23: #include <signal.h>
24:
25: long longabs(x)
26: long x;
27: {
28: return x<0? -x: x;
29: }
30:
31: long getl (file)
32: register FILE *file;
33: {
34: long l;
35: l = getw (file);
36: l <<= 16;
37: l |= getw (file);
38: return l;
39: }
40:
41: putl (l, file)
42: long l;
43: register FILE *file;
44: {
45: putw ((int) (l >> 16), file);
46: putw ((int) l, file);
47: }
48:
49: FILE *caves, *suspfd;
50: long tvec, xtime, time();
51: long ftell();
52: struct passwd *pwbuf;
53: char suspbeg; /* Start of variables to write during suspension */
54: char tkword[10];
55: char wd2x[5];
56: char wd2[5];
57: char wd1x[5];
58: char wd1[5];
59: char atab[300+1][6];
60: char linebuf[100]; /* For reading cave description, etc */
61: char chr;
62: char *cp1, *cp2;
63: int rtext[205];
64: long newloc = 0L;
65: long lines[1000]; /* Assumed initialized to zero */
66: int blklin = 1;
67: int dseen[6];
68: int odloc[6];
69: int dloc[6];
70: int tk[20+1];
71: int hinted[20+1];
72: int hinted[20+1]; /* Assumed initialized to 0 */
73: int hints[12+1][4+1]; /* Assumed initialized to 0 */
74: int cval[12+1]; /* Assumed initialized to 0 */
75: int ctext[12+1]; /* Assumed initialized to 0 */
76: int actspk[35+1]; /* Assumed initialized to 0 */
77: int prop[100+1]; /* Assumed initialized to 0 */
78: int fixd[100+1]; /* Assumed initialized to 0 */
79: int plac[100+1]; /* Assumed initialized to 0 */
80: int cond[150+1]; /* Assumed initialized to 0 */
81: int key[150+1]; /* Assumed initialized to 0 */
82: int stext[150+1]; /* Assumed initialized to 0 */
83: int ltext[150+1]; /* Assumed initialized to 0 */
84: long travel[750+1]; /* Assumed initialized to 0 */
85: int hintlc[21+1]; /* Assumed initialized to zero */
86: int abb[150+1];
87: int holdng;
88: int fixed[100+1];
89: int place[100+1];
90: int rlink[200+1];
91: int atloc[150+1];
92: int tabsiz = 300;
93: int ktab[300+1];
94: int ptext[100+1];
95: #ifdef INITBUG
96: int clssiz = 12;
97: int linsiz = 999;
98: int vrbsiz = 35;
99: #endif INITBUG
100: int trvsiz = 750;
101: int locsiz = 150;
102: int rtxsiz = 205;
103: int clsmax = 12;
104: int hntsiz = 20;
105: int wzdark;
106: int lmwarn;
107: int closng;
108: int panic;
109: int closed;
110: int gaveup;
111: int scorng;
112: int yea;
113: long ll;
114:
115: #ifdef unix
116: #include <pwd.h>
117: #define GETPWUID() pwbuf=getpwuid(getuid());cp2=pwbuf->pw_dir;while(*cp1++ = *cp2++);cp1--;
118: #define HOURS "Colossal Cave is always open\n"
119: #ifndef CAVE
120: #define CAVE "/usr/games/lib/cave"
121: #endif CAVE
122: #define SUSPREAD "r"
123: #define SUSPWRITE "w"
124: #endif
125: #ifdef gcos
126: #define CLOSED "Colossal Cave is closed weekdays between 8 AM and 6 PM.\n"
127: #define GETPWUID() if(lmsgrd()<3){printf(CLOSED);return(0);}fprompt("\r\n");
128: #define HOURS CLOSED
129: #define CAVE "cc/adve/cave$abracadabra"
130: #define SUSPREAD "ri"
131: #define SUSPWRITE "wi"
132: #endif
133:
134: #define abbnum ints[0]
135: #define iy ints[1]
136: #define axe ints[2]
137: #define back ints[3]
138: #define batter ints[4]
139: #define bear ints[5]
140: #define bird ints[6]
141: #define bonus ints[7]
142: #define bottle ints[8]
143: #define cage ints[9]
144: #define cave ints[10]
145: #define ccode ints[11]
146: #define ch ints[12]
147: #define chain ints[13]
148: #define chasm ints[14]
149: #define chest ints[15]
150: #define chloc ints[16]
151: #define chloc2 ints[17]
152: #define clam ints[18]
153: #define clock1 ints[19]
154: #define clock2 ints[20]
155: #define clsses ints[21]
156: #define coins ints[22]
157: #define daltlc ints[23]
158: #define detail ints[24]
159: #define dflag ints[25]
160: #define dkill ints[26]
161: #define door ints[27]
162: #define dprssn ints[28]
163: #define dragon ints[29]
164: #define dtotal ints[30]
165: #define dwarf ints[31]
166: #define eggs ints[32]
167: #define emrald ints[33]
168: #define entrnc ints[34]
169: #define find ints[35]
170: #define fissur ints[36]
171: #define foo ints[37]
172: #define foobar ints[38]
173: #define food ints[39]
174: #define from ints[40]
175: #define grate ints[41]
176: #define hint ints[42]
177: #define hntmax ints[43]
178: #define i ints[44]
179: #define inlen ints[45]
180: #define invent ints[46]
181: #define iwest ints[47]
182: #define j ints[48]
183: #define k ints[49]
184: #define keys ints[50]
185: #define kk ints[51]
186: #define knfloc ints[52]
187: #define knife ints[53]
188: #define kq ints[54]
189: #define k2 ints[55]
190: #define l ints[56]
191: #define lamp ints[57]
192: #define limit ints[58]
193: #define linuse ints[59]
194: #define hungup ints[60]
195: #define loc ints[61]
196: #define lock ints[62]
197: #define look ints[63]
198: #define m ints[64]
199: #define magzin ints[65]
200: #define maxdie ints[66]
201: #define maxtrs ints[67]
202: #define messag ints[68]
203: #define mirror ints[69]
204: #define mxscor ints[70]
205: #define nugget ints[71]
206: #define nullx ints[72]
207: #define numdie ints[73]
208: #define obj ints[74]
209: #define oil ints[75]
210: #define oldlc2 ints[76]
211: #define oldloc ints[77]
212: #define oyster ints[78]
213: #define pearl ints[79]
214: #define pillow ints[80]
215: #define plant ints[81]
216: #define plant2 ints[82]
217: #define posn ints[83]
218: #define pyram ints[84]
219: #define rod ints[85]
220: #define rod2 ints[86]
221: #define rug ints[87]
222: #define say ints[88]
223: #define score ints[89]
224: #define sect ints[90]
225: #define snake ints[91]
226: #define spices ints[92]
227: #define spk ints[93]
228: #define steps ints[94]
229: #define stick ints[95]
230: #define tablet ints[96]
231: #define tabndx ints[97]
232: #define tally ints[98]
233: #define tally2 ints[99]
234: #define temp ints[100]
235: #define throw ints[101]
236: #define attack ints[102]
237: #define tridnt ints[103]
238: #define troll ints[104]
239: #define troll2 ints[105]
240: #define trvs ints[106]
241: #define turns ints[107]
242: #define vase ints[108]
243: #define vend ints[109]
244: #define verb ints[110]
245: #define water ints[111]
246: #define word ints[112]
247: #define wordend ints[113]
248: #define wordsize ints[114]
249: #define wordstrt ints[115]
250: #define logon ints[116]
251: #define srel ints[117]
252: #define slev ints[118]
253: #define tleft ints[119]
254: #define tright ints[120]
255: int ints[121];
256:
257: char suspend; /* End of variables to write during suspension */
258:
259: /*
260: wzdark says whether the loc he's leaving was dark
261: lmwarn says whether he's been warned about lamp going dim
262: closng says whether its closing time yet
263: panic says whether he's found out he's trapped in the cave
264: closed says whether we're all the way closed
265: gaveup says whether he exited via "quit"
266: scorng indicates to the score routine whether we're doing
267: a "score" command
268: yea is random yes/no reply
269: hungup says whether he hung up the phone
270: */
271:
272: sethup()
273: {
274: hungup = 1;
275: signal (SIGHUP, SIG_IGN);
276:
277: #ifndef INITBUG
278: signal (SIGINT, SIG_IGN);
279: signal (SIGQUIT, SIG_IGN);
280: #endif INITBUG
281:
282: }
283:
284: main()
285: {
286: char suspfile[100];
287: static char outbuf[BUFSIZ];
288: struct passwd *getpwuid();
289:
290: setbuf(stdout, outbuf);
291: setbuf(stderr, NULL);
292: printf ("@(#)Adventure 1.20\n" + 4);
293:
294: cp1 = suspfile;
295: GETPWUID();
296: cp2 = "/adv.susp";
297: while (*cp1++ = *cp2++);
298:
299: #ifndef INITBUG
300: if (signal (SIGINT, SIG_IGN) != SIG_IGN)
301: signal (SIGINT, sethup);
302: if (signal (SIGQUIT, sethup) != SIG_IGN)
303: signal (SIGQUIT, sethup);
304: #endif INITBUG
305:
306: if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
307: signal (SIGHUP, sethup);
308:
309: #ifdef LOG
310: logon = 1;
311: #else
312: logon = 0;
313: #endif
314:
315: if ((caves = fopen (CAVE, "r")) == NULL)
316: fatal ("Couldn't open cave file\n");
317:
318: /* Description of the database format:
319: The data file contains several sections. Each begins
320: with a line containing a number identifying the section,
321: and ends with a line containing "-1".
322: Section 1: long form descriptions. Each line contains a
323: location number, a tab, and a line of text. The set
324: of (necessarily adjacent) lines whose numbers are x
325: form the long description of location x.
326: Section 2: Short form descriptions. Same format as long
327: form. Not all places have short descriptions.
328: Section 3: Travel table. Each line contains a location
329: number (x), a second location number (y), and a list
330: of motion numbers (see section 4). Each motion
331: represents a verb which will go to y if currently at
332: x. y, in turn, is interpreted as follows: Let
333: m=y/1000, n=y mod 1000.
334: If n<=300 it is the location to go to.
335: If 300<n<=500 n-300 is used in a computed
336: goto to a section of special
337: code.
338: If n>500 message n-500 from section 6
339: is printed, and he stays
340: wherever he is.
341: Meanwhile, m specifies the conditions on the motion.
342: If m=0 it's unconditional.
343: If 0<m<100 it is done with m%
344: probability.
345: If m=100 unconditional, but forbidden
346: to dwarves.
347: If 100<m<=200 he must be carrying object
348: m-100.
349: If 200<m<=300 must be carrying or in same
350: room as m-200.
351: If 300<m<=400 prop(m mod 100) must NOT be
352: 0.
353: If 400<m<=500 prop(m mod 100) must NOT be
354: 1.
355: If 500<m<=600 prop(m mod 100) must NOT be
356: 2, etc.
357: If the condition (if any) is not met, then the next
358: DIFFERENT "destination" value is used (unless it
359: fails to meet ITS conditions, in which case the
360: next is found, etc.). Typically, the next dest will
361: be for one of the same verbs, so that its only use is
362: as the alternate destination for those verbs. For
363: instance:
364: 15 110022 29 31 34 35 23 43
365: 15 14 29
366: This says that, from loc 15, any of the verbs 29, 31,
367: etc., will take him to 22 if he's carrying object 10,
368: and otherwise will go to 14.
369: 11 303008 49
370: 11 9 50
371: This says that, from 11, 49 takes him to 8 unless
372: prop(3)=0, in which case he goes to 9. Verb 50 takes
373: him to 9 regardless of prop(3).
374: Section 4: vocabulary. Each line contains a number (n),
375: a tab, and a five-letter word. Call m=n/1000. If
376: m=0, then the word is a motion verb for use in
377: travelling (see section 3). Else, if m=1, the word
378: is an object. Else, if m=2, the word is an action
379: verb (such as "carry" or "attack"). Else, if m=3,
380: the word is a special case verb (such as "dig") and n
381: mod 1000 is an index into section 6. Objects from 50
382: to (currently, anyway) 79 are considered treasures
383: (for pirate, closeout).
384: Section 5: object descriptions. Each line contains a
385: number (n), a tab, and a message. If n is from 1 to
386: 100, the message is the "inventory" message for
387: object n. Otherwise, n should be 000, 100, 200,
388: etc., and the message should be the description of
389: the preceding object when its prop value is n/100.
390: The n/100 is used only to distinguish multiple
391: messages from multi-line messages; the prop info
392: actually requires all messages for an object to be
393: present and consecutive. Properties which produce no
394: message should be given the message ">$<".
395: Section 6: arbitrary messages. Same format as sections
396: 1, 2, and 5, except the numbers bear no relation to
397: anything (except for special verbs in section 4).
398: Section 7: object locations. Each line contains an
399: object number and its initial location (zero (or
400: omitted) if none). If the object is immovable, the
401: location is followed by a "-1". If it has two
402: locations (e.g. the grate) the first location is
403: followed with the second, and the object is assumed
404: to be immovable.
405: Section 8: action defaults. Each line contains an
406: "action-verb" number and the index (in section 6) of
407: the default message for the verb.
408: Section 9: liquid assets, etc. Each line contains a
409: number (n) and up to 20 location numbers. Bit n
410: (where 0 is the units bit) is set in cond(loc) for
411: each loc given. The cond bits currently assigned
412: are:
413: 0 light
414: 1 if bit 2 is on: on for oil, off for
415: water
416: 2 liquid asset, see bit 1
417: 3 pirate doesn't go here unless
418: following player
419: Other bits are used to indicate areas of interest to
420: "hint" routines:
421: 4 trying to get into cave
422: 5 trying to catch bird
423: 6 trying to deal with snake
424: 7 lost in maze
425: 8 pondering dark room
426: 9 at Witt's end
427: cond(loc) is set to 2, overriding all other bits, if
428: loc has forced motion.
429: Section 10: class messages. Each line contains a number
430: (n), a tab, and a message describing a classification
431: of player. The scoring section selects the
432: appropriate message, where each message is considered
433: to apply to players whose scores are higher than the
434: previous n but not higher than this n. Note that
435: these scores probably change with every modification
436: (and particularly expansion) of the program.
437: Section 11: hints. Each line contains a hint number
438: (corresponding to a cond bit, see section 9), the
439: number of turns he must be at the right loc(s) before
440: triggering the hint, the points deducted for taking
441: the hint, the message number (section 6) of the
442: question, and the message number of the hint. These
443: values are stashed in the "hints" array. hntmax is
444: set to the max hint number (<= hntsiz). Numbers 1-3
445: are unusable since cond bits are otherwise assigned,
446: so 2 is used to remember if he's read the clue in the
447: repository, and 3 is used to remember whether he
448: asked for instructions (gets more turns, but loses
449: points).
450: Section 12: magic messages. Identical to section 6
451: except put in a separate section for easier
452: reference. Magic messages are used by the startup,
453: maintenance mode, and related routines.
454: Section 0: end of database.
455: */
456:
457: /* Read the database */
458:
459: printf("Initializing... ");
460: fflush(stdout);
461:
462: /*
463: Clear out the various text-pointer arrays. All text is
464: stored in array lines; each line is preceded by a word
465: pointing to the next pointer (i.e. the word following
466: the end of the line). The pointer is negative if this is
467: first line of a message. The text-pointer arrays contain
468: indices of pointer-words in lines. stext(n) is short
469: description of location n. ltext(n) is long description.
470: ptext(n) points to message for prop(n)=0. Successive
471: prop messages are found by chasing pointers. rtext
472: contains section 6's stuff. ctext(n) points to a
473: player-class message. mtext is for section 12. we also
474: clear cond. see description of section 9 for details.
475: */
476: for (i=1; i<=300; i++) {
477: if (i <= 100) ptext[i] = 0;
478: if (i <= rtxsiz) rtext[i] = 0;
479: if (i <= clsmax) ctext[i] = 0;
480: if (i <= locsiz) {
481: stext[i]=0;
482: ltext[i]=0;
483: cond[i]=0;
484: }
485: }
486: /* key=0; */
487: linuse=1;
488: trvs=1;
489: clsses=1;
490:
491: /* Start new data section. sect is the section number. */
492: l1002:
493: fscanf (caves, "%d", §);
494: oldloc= -1;
495:
496: #ifdef INITBUG
497: fprintf(stderr, "\nSect=%d\n", sect);
498: #endif INITBUG
499:
500: switch (sect) {
501: case 0:
502: goto l1100; /* (0) */
503: case 1:
504: case 2:
505: case 5:
506: case 6:
507: case 10:
508: goto l1004; /* 1, 2, 5, 6, 10 */
509: case 3:
510: goto l1030; /* (3) */
511: case 4:
512: goto l1040; /* (4) */
513: case 7:
514: goto l1050; /* (7) */
515: case 8:
516: goto l1060; /* (8) */
517: case 9:
518: goto l1070; /* (9) */
519: case 11:
520: goto l1080; /* (11) */
521: }
522:
523: bug(9);
524:
525: /* Sections 1, 2, 5, 6, 10. Read messages and set up pointers. */
526: l1004:
527: fscanf (caves, "%d", &loc);
528: #ifdef INITBUG
529: fprintf(stderr, "Sect=%d; Loc=%d\n", sect, loc);
530: #endif INITBUG
531: while ((chr = getc (caves)) == ' ' || chr == '\t')
532: ;
533: ungetc (chr, caves);
534: lines[linuse] = ftell (caves);
535: fgets (linebuf, sizeof linebuf, caves);
536: if (loc == -1) goto l1002;
537: if (loc != oldloc) {
538: lines[linuse] = -lines[linuse];
539: if (sect == 10) {
540: ctext[clsses] = linuse;
541: cval[clsses] = loc;
542: clsses++;
543: }
544: else if (sect == 6) {
545: if (loc > rtxsiz) bug(6);
546: rtext[loc] = linuse;
547: }
548: else if (sect == 5) {
549: if (loc > 0 && loc <= 100) ptext[loc] = linuse;
550: }
551: else if (sect == 1) {
552: ltext[loc] = linuse;
553: }
554: else
555: stext[loc] = linuse;
556: }
557: linuse++;
558: oldloc = loc;
559: goto l1004;
560: /*
561: The stuff for section 3 is encoded here. Each
562: "from-location" gets a contiguous section of the "travel"
563: array. Each entry in travel is newloc*1000 + keyword
564: (from section 4, motion verbs), and is negated if this is
565: the last entry for this location. key[n] is the index in
566: travel of the first option at location n.
567: */
568: l1030:
569: fscanf (caves, "%d\t%ld", &loc, &newloc);
570: #ifdef INITBUG
571: fprintf(stderr, "Sect=%d; Loc=%d; newloc=%d\n", sect, loc, newloc);
572: #endif INITBUG
573: i = 0;
574: while ((chr = getc (caves)) != '\n') {
575: ungetc (chr, caves);
576: fscanf (caves, "%d", &tk[i++]);
577: }
578: if (loc == -1) goto l1002;
579: if (key[loc])
580: travel[trvs-1] = -travel[trvs-1];
581: else
582: key[loc] = trvs;
583: for (l=0; l<i; l++) {
584: travel[trvs] = newloc * 1000L + tk[l];
585: trvs++;
586: if (trvs >= trvsiz) bug(3);
587: }
588: travel[trvs-1]= -travel[trvs-1];
589: goto l1030;
590: /*
591: Here we read in the vocabulary. ktab[n] is the word
592: number, atab[n] is the corresponding word. The -1 at the
593: end of section 4 is left in ktab as an end-marker.
594: */
595: l1040:
596: for (tabndx = 1; tabndx <= tabsiz; tabndx++) {
597: char str[6];
598: fscanf (caves, "%d\t%s", &ktab[tabndx], str);
599: #ifdef INITBUG
600: fprintf(stderr, "Sect=%d; k=%d; str=%s\n", sect, ktab[tabndx], str);
601: #endif INITBUG
602: while ((chr = getc(caves)) != '\n')
603: ;
604: cpy (&atab[tabndx][0], str);
605: if (ktab[tabndx] == -1) goto l1002;
606: }
607: bug(4);
608: /*
609: Read in the initial locations for each object. Also the
610: immovability info. plac contains initial locations of
611: objects. fixd is -1 for immovable objects (including the
612: snake), or = second loc for two-placed objects.
613: */
614: l1050:
615: while (fscanf (caves, "%d\t%d\t%d", &obj, &j, &k), obj != -1) {
616: #ifdef INITBUG
617: fprintf(stderr, "Sect=%d; obj=%d; plac=%d; fixd=%d\n", sect, obj, j, k);
618: #endif INITBUG
619: plac[obj]=j;
620: fixd[obj]=k;
621: }
622: goto l1002;
623:
624: /* Read default message numbers for action verbs, store in actspk. */
625: l1060:
626: while (fscanf (caves, "%d\t%d", &verb, &j), verb != -1) {
627: #ifdef INITBUG
628: fprintf(stderr, "Sect=%d; verb=%d; j=%d\n", sect, verb, j);
629: #endif INITBUG
630: actspk[verb]=j;
631: }
632: goto l1002;
633:
634: /* Read info about available liquids and other conditions,
635: store in cond. */
636: l1070:
637: while (fscanf (caves, "%d", &k), k != -1) {
638: #ifdef INITBUG
639: fprintf(stderr, "Sect=%d; cond=%d\n", sect, k);
640: #endif INITBUG
641: i = 0;
642: while ((chr = getc(caves)) != '\n') {
643: ungetc(chr, caves);
644: fscanf (caves, "%d", &i);
645: if (bitset (i, k)) {
646: int z;
647: for (z=0; z<10; z++)
648: printf ("cond[%d]=%d\n", z, cond[z]);
649: fatal ("Duplicate bit\n");
650: }
651: cond[i] |= (1 << k);
652: }
653: }
654: goto l1002;
655:
656: /* Read data for hints. */
657: l1080:
658: hntmax=0;
659:
660: while (fscanf (caves, "%d\t%d\t%d\t%d\t%d",
661: &k, &tk[1], &tk[2], &tk[3], &tk[4]), k != -1) {
662: #ifdef INITBUG
663: fprintf(stderr, "Sect=%d; k=%d; tk=[%d,%d,%d,%d]\n",
664: sect, k, tk[1], tk[2], tk[3], tk[4]);
665: #endif INITBUG
666: if (k != 0) {
667: if (k < 0 || k > hntsiz) bug(7);
668: for (i=1; i<=4; i++)
669: hints[k][i]=tk[i];
670: if (k > hntmax)
671: hntmax = k;
672: }
673: }
674: goto l1002;
675:
676: /*
677: Finish constructing internal data format
678: Having read in the database, certain things are now
679: constructed. Props are set to zero. We finish setting
680: up cond by checking for forced-motion travel entries.
681: The plac and fixd arrays are used to set up atloc[n] as
682: the first object at location n, and rlink[obj] as the next
683: object at the same location as obj. (obj>100 indicates
684: that fixed[obj-100]=loc; rlink[obj] is still the correct
685: link to use.) abb is zeroed; it controls whether the
686: abbreviated description is printed. Counts mod 5 unless
687: "look" is used.
688: */
689: l1100:
690:
691: printf("Linking... ");
692: fflush(stdout);
693:
694: for (i=1; i<=100; i++) {
695: place[i]=0;
696: prop[i]=0;
697: rlink[i]=0;
698: rlink[i+100]=0;
699: }
700: for (i=1; i<=locsiz; i++) {
701: abb[i]=0;
702: if (ltext[i] != 0 && key[i] != 0) {
703: k=key[i];
704: if (longabs(travel[k]) % 1000 == 1)
705: cond[i]=2;
706: }
707: atloc[i]=0;
708: }
709: /*
710: Set up the atloc and rlink arrays as described above.
711: We'll use the drop subroutine, which prefaces new objects
712: on the lists. Since we want things in the other order,
713: we'll run the loop backwards. If the object is in two
714: locs, we drop it twice. This also sets up "place" and
715: "fixed" as copies of "plac" and "fixd". Also, since
716: two-placed objects are typically best described last,
717: we'll drop them first.
718: */
719: for (i=1; i<=100; i++) {
720: k=101-i;
721: if (fixd[k] > 0) {
722: drop (k+100,fixd[k]);
723: drop (k,plac[k]);
724: }
725: }
726: for (i=1; i<=100; i++) {
727: k=101-i;
728: fixed[k]=fixd[k];
729: if (plac[k] != 0 && fixd[k] <= 0) drop(k,plac[k]);
730: }
731: /*
732: Treasures, as noted earlier, are objects 50 through
733: maxtrs (currently 79). Their props are initially -1, and
734: are set to 0 the first time they are described. Tally
735: keeps track of how many are not yet found, so we know
736: when to close the cave. Tally2 counts how many can never
737: be found (e.g. if lost bird or bridge).
738: */
739: maxtrs=79;
740: tally=0;
741: tally2=0;
742: for (i=50; i<=maxtrs; i++) {
743: if (ptext[i] != 0) prop[i]= -1;
744: tally -= prop[i];
745: }
746: /*
747: Clear the hint stuff. hintlc[i] is how long he's been at
748: loc with cond bit i. hinted(i) is true iff hint i has
749: been used.
750: */
751: for (i = 1; i<=hntmax; i++)
752: hinted[i] = hintlc[i] = 0;
753: /* Define some handy mnemonics. these correspond to object numbers. */
754: keys=vocab("keys",1);
755: lamp=vocab("lamp",1);
756: grate=vocab("grate",1);
757: cage=vocab("cage",1);
758: rod=vocab("rod",1);
759: rod2=rod+1;
760: steps=vocab("steps",1);
761: bird=vocab("bird",1);
762: door=vocab("door",1);
763: pillow=vocab("pillo",1);
764: snake=vocab("snake",1);
765: fissur=vocab("fissu",1);
766: tablet=vocab("table",1);
767: clam=vocab("clam",1);
768: oyster=vocab("oyste",1);
769: magzin=vocab("magaz",1);
770: dwarf=vocab("dwarf",1);
771: knife=vocab("knife",1);
772: food=vocab("food",1);
773: bottle=vocab("bottl",1);
774: water=vocab("water",1);
775: oil=vocab("oil",1);
776: plant=vocab("plant",1);
777: plant2=plant+1;
778: axe=vocab("axe",1);
779: mirror=vocab("mirro",1);
780: dragon=vocab("drago",1);
781: chasm=vocab("chasm",1);
782: troll=vocab("troll",1);
783: troll2=troll+1;
784: bear=vocab("bear",1);
785: messag=vocab("messa",1);
786: vend=vocab("vendi",1);
787: batter=vocab("batte",1);
788: /* Objects from 50 through whatever are treasures. here are a few. */
789: nugget=vocab("gold",1);
790: coins=vocab("coins",1);
791: chest=vocab("chest",1);
792: eggs=vocab("eggs",1);
793: tridnt=vocab("tride",1);
794: vase=vocab("vase",1);
795: emrald=vocab("emera",1);
796: pyram=vocab("pyram",1);
797: pearl=vocab("pearl",1);
798: rug=vocab("rug",1);
799: chain=vocab("chain",1);
800: /* These are motion-verb numbers. */
801: back=vocab("back",0);
802: look=vocab("look",0);
803: cave=vocab("cave",0);
804: nullx=vocab("null",0);
805: entrnc=vocab("entra",0);
806: dprssn=vocab("depre",0);
807: /* And some action verbs. */
808: say=vocab("say",2);
809: lock=vocab("lock",2);
810: throw=vocab("throw",2);
811: find=vocab("find",2);
812: invent=vocab("inven",2);
813: /*
814: Initialize the dwarves. dloc is loc of dwarves,
815: hard-wired in. odloc is prior loc of each dwarf,
816: initially garbage. daltlc is alternate initial loc for
817: dwarf, in case one of them starts out on top of the
818: adventurer. (no 2 of the 5 initial locs are adjacent.)
819: dseen is true if dwarf has seen him. dflag controls the
820: level of activation of all this:
821: 0 no dwarf stuff yet (wait until reaches hall
822: of mists)
823: 1 reached hall of mists, but hasn't met first dwarf
824: 2 met first dwarf, others start moving, no
825: knives thrown yet
826: 3 a knife has been thrown (first set always
827: misses)
828: 3+ dwarves are mad (increases their accuracy)
829: Sixth dwarf is special (the pirate). He always starts at
830: his chest's eventual location inside the maze. This loc
831: is saved in chloc for ref. The dead end in the other
832: maze has its loc stored in chloc2.
833: */
834: chloc=114;
835: chloc2=140;
836: for (i=1; i<=6; i++)
837: dseen[i] = 0;
838: dflag=0;
839: dloc[1]=19;
840: dloc[2]=27;
841: dloc[3]=33;
842: dloc[4]=44;
843: dloc[5]=64;
844: dloc[6]=chloc;
845: daltlc=18;
846: /*
847: Other random flags and counters, as follows:
848: turns tallies how many commands he's given
849: (ignores yes/no)
850: limit lifetime of lamp (not set here)
851: iwest how many times he's said "west" instead of
852: "w"
853: knfloc 0 if no knife here, loc if knife here, -1
854: after caveat
855: detail how often we've said "not allowed to give
856: more detail"
857: abbnum how often we should print non-abbreviated
858: descriptions
859: maxdie number of reincarnation messages available
860: (up to 5)
861: numdie number of times killed so far
862: holdng number of objects being carried
863: dkill number of dwarves killed (unused in scoring,
864: needed for msg)
865: foobar current progress in saying "fee fie foe
866: foo".
867: bonus used to determine amount of bonus if he
868: reaches closing
869: clock1 number of turns from finding last treasure
870: till closing
871: clock2 number of turns from first warning till
872: blinding flash
873: logicals were explained earlier
874: */
875: turns=0;
876: lmwarn=0;
877: iwest=0;
878: knfloc=0;
879: detail=0;
880: abbnum=5;
881: for (i=0; i<=4; i++)
882: if (rtext[2*i+81] != 0) maxdie=i+1;
883: numdie=0;
884: /*holdng=0; */
885: dkill=0;
886: foobar=0;
887: bonus=0;
888: clock1=30;
889: clock2=50;
890: closng=0;
891: panic=0;
892: closed=0;
893: gaveup=0;
894: scorng=0;
895: /* Report on amount of arrays actually used,
896: to permit reductions. */
897: for (kk = locsiz; kk > 0; kk--) {
898: if (ltext[kk] != 0)
899: break;
900: }
901: obj=0;
902: for (k = 1; k <= 100; k++) {
903: if (ptext[k] != 0) obj++;
904: }
905: for (k = 1; k <= tabndx; k++) {
906: if (ktab[k]/1000 == 2) verb=ktab[k]-2000;
907: }
908: for (j = rtxsiz; j > 0; j--) {
909: if (rtext[j] != 0)
910: break;
911: }
912: k=100;
913: #ifdef INITBUG
914: printf ("%d of %d messages; ", linuse, linsiz);
915: printf ("%d of %d travel options;\n", trvs, trvsiz);
916: printf ("%d of %d vocabulary words; ", tabndx, tabsiz);
917: printf ("%d of %d locations;\n", kk, locsiz);
918: printf ("%d of %d objects; ", obj, k);
919: printf ("%d of %d action verbs;\n", verb, vrbsiz);
920: printf ("%d of %d rtext messages; ", j, rtxsiz);
921: printf ("%d of %d class messages;\n", clsses, clssiz);
922: printf ("%d of %d hints.\n", hntmax, hntsiz);
923: #endif INITBUG
924: /* Finally, since we're clearly setting things up for the first time */
925: printf ("Done!\n");
926: tvec = time((long *) 0);
927: srand ((int) (tvec % 32768L));
928: if ((suspfd = fopen (suspfile, SUSPREAD)) != NULL) {
929: /* check if we suspended in this release */
930: srel = getw (suspfd);
931: slev = getw (suspfd);
932: if (srel != 1 || slev != 20) {
933: printf("I deleted a suspend file from version %d.%d\n",
934: srel, slev);
935: unlink (suspfile);
936: hinted[3] = yes (65, 1, 0);
937: loc = newloc = 1;
938: limit = hinted[3]? 1000: 330;
939: }
940: else
941: {
942: /* When did we suspend? */
943: xtime = getl (suspfd);
944: #ifndef NOTIME
945: tvec = time((long *) 0);
946: if (tvec - xtime < 1800) {
947: printf ("You cannot restart a suspended game");
948: printf ("for at least half an hour.\n");
949: exit (1);
950: }
951: #endif
952:
953: /* Delete the suspend file */
954: if (unlink (suspfile) == -1)
955: fatal ("can't unlink suspend file");
956:
957: fread (&suspbeg, sizeof suspbeg, &suspend - &suspbeg, suspfd);
958: fclose (suspfd);
959: printf ("Restarting a suspended game...\n");
960: newloc = loc;
961: }
962: }
963: else
964: {
965: hinted[3]=yes(65,1,0);
966: loc=newloc=1;
967: limit = hinted[3]? 1000: 330;
968: }
969: /* Can't leave cave once it's closing (except by main office). */
970: l2:
971: if (newloc < 9 && newloc != 0 && closng) {
972: rspeak(130);
973: newloc=loc;
974: if (!panic) clock2=15;
975: panic=1;
976: }
977: /*
978: See if a dwarf has seen him and has come from where he
979: wants to go. If so, the dwarf's blocking his way. If
980: coming from place forbidden to pirate (dwarves rooted in
981: place) let him get out (and attacked).
982: */
983: if (newloc != loc && !forced(loc) && !bitset(loc,3)) {
984: for (i = 1; i <= 5; i++) {
985: if (!(odloc[i] != newloc || !dseen[i])) {
986: newloc=loc;
987: rspeak(2);
988: break;
989: }
990: }
991: }
992: loc=newloc;
993: /*
994: Dwarf stuff. See earlier comments for description of
995: variables. Remember sixth dwarf is pirate and is thus
996: very different except for motion rules.
997: First off, don't let the dwarves follow him into a pit or
998: a wall. Activate the whole mess the first time he gets
999: as far as the hall of mists (loc 15). If newloc is
1000: forbidden to pirate (in particular, if it's beyond the
1001: troll bridge), bypass dwarf stuff. That way pirate can't
1002: steal return toll, and dwarves can't meet the bear. Also
1003: means dwarves won't follow him into dead end in maze, but
1004: c'est la vie. They'll wait for him outside the dead end.
1005: */
1006: if (loc == 0 || forced(loc) || bitset((int)newloc,3)) goto l2000;
1007: if (dflag == 0) {
1008: if (loc >= 15) dflag=1;
1009: goto l2000;
1010: }
1011: /*
1012: When we encounter the first dwarf, we kill 0, 1, or 2 of
1013: the 5 dwarves. If any of the survivors is at loc,
1014: replace him with the alternate.
1015: */
1016: if (dflag == 1) {
1017: if (loc < 15 || pct(95)) goto l2000;
1018: dflag=2;
1019: for (i = 1; i <= 2; i++) {
1020: j=1+ran(5);
1021: if (pct(50)) dloc[j]=0;
1022: }
1023: for (i = 1; i <= 5; i++) {
1024: if (dloc[i] == loc) dloc[i]=daltlc;
1025: odloc[i]=dloc[i];
1026: }
1027: rspeak(3);
1028: drop(axe,loc);
1029: goto l2000;
1030: }
1031: /*
1032: Things are in full swing. Move each dwarf at random,
1033: except if he's seen us he sticks with us. Dwarves never
1034: go to locs <15. If wandering at random, they don't back
1035: up unless there's no alternative. If they don't have to
1036: move, they attack. And, of course, dead dwarves don't do
1037: much of anything.
1038: */
1039: dtotal=0;
1040: attack=0;
1041: stick=0;
1042: for (i = 1; i <= 6; i++) {
1043: if (dloc[i] == 0) goto l6030;
1044: j=1;
1045: kk=dloc[i];
1046: kk=key[kk];
1047: if (kk != 0) {
1048: do
1049: {
1050: newloc=longabs(travel[kk])/1000 % 1000;
1051: if (newloc <= 300 && newloc >=15 && newloc != odloc[i]
1052: && !(j > 1 && newloc == tk[j-1]) && j < 20
1053: && newloc != dloc[i] && !forced((int)newloc)
1054: && !(i == 6 && bitset((int)newloc,3))
1055: && longabs(travel[kk] / 1000000) != 100) {
1056: tk[j]=newloc;
1057: j++;
1058: }
1059: kk++;
1060: }
1061: while (travel[kk-1] >= 0);
1062: }
1063: tk[j]=odloc[i];
1064: if (j >= 2) j--;
1065: j=1+ran(j);
1066: odloc[i]=dloc[i];
1067: dloc[i]=tk[j];
1068: dseen[i]=(dseen[i] && loc >= 15)
1069: || (dloc[i] == loc || odloc[i] == loc);
1070: if (!dseen[i]) goto l6030;
1071: dloc[i]=loc;
1072: if (i != 6) goto l6027;
1073: /*
1074: The pirate's spotted him. He leaves him alone once we've
1075: found chest. k counts if a treasure is here. If not,
1076: and tally=tally2 plus one for an unseen chest, let the
1077: pirate be spotted.
1078: */
1079: if (loc == chloc || prop[chest] >= 0) goto l6030;
1080: k=0;
1081: for (j = 50; j <= maxtrs; j++) {
1082: /* Pirate won't take pyramid from plover room or dark room (too easy!). */
1083: if (j != pyram || !(loc == plac[pyram]
1084: || loc == plac[emrald])) {
1085: if (toting(j)) goto l6022;
1086: }
1087: if (here(j)) k=1;
1088: }
1089: if (tally == tally2+1 && k == 0 && place[chest] == 0
1090: && here(lamp) && prop[lamp] == 1) goto l6025;
1091: if (odloc[6] != dloc[6] && pct(20)) rspeak(127);
1092: goto l6030;
1093: l6022:
1094: rspeak(128);
1095: /* Don't steal chest back from troll! */
1096: if (place[messag] == 0) move(chest,chloc);
1097: move(messag,chloc2);
1098: for (j = 50; j <= maxtrs; j++) {
1099: if (j == pyram && (loc == plac[pyram]
1100: || loc == plac[emrald])) goto l6023;
1101: if (at(j) && fixed[j] == 0) carry(j,loc);
1102: if (toting(j)) drop(j,chloc);
1103: l6023:
1104: ;
1105: }
1106: l6024:
1107: dloc[6]=chloc;
1108: odloc[6]=chloc;
1109: dseen[6]=0;
1110: goto l6030;
1111: l6025:
1112: rspeak(186);
1113: move(chest,chloc);
1114: move(messag,chloc2);
1115: goto l6024;
1116: /* This threatening little dwarf is in the room with him! */
1117: l6027:
1118: dtotal++;
1119: if (odloc[i] != dloc[i]) goto l6030;
1120: attack++;
1121: if (knfloc >= 0) knfloc=loc;
1122: if (ran(1000) < 95*(dflag-2))stick++;
1123: l6030:
1124: ;
1125: }
1126: /* Now we know what's happening. let's tell the poor sucker about it. */
1127: if (dtotal == 0) goto l2000;
1128: if (dtotal != 1) {
1129: printf ("There are %d threatening little dwarves", dtotal);
1130: printf (" in the room with you.\n");
1131: } else
1132: rspeak(4);
1133: if (attack == 0) goto l2000;
1134: if (dflag == 2) dflag=3;
1135: /*
1136: Dwarves get VERY mad!
1137: */
1138: if (attack == 1) {
1139: rspeak(5);
1140: k=52;
1141: }
1142: else {
1143: printf ("%d of them throw knives at you!\n", attack);
1144: k=6;
1145: }
1146: if (stick <= 1) {
1147: rspeak(k+stick);
1148: if (stick == 0) goto l2000;
1149: }
1150: else
1151: printf ("%d of them get you!\n", stick);
1152: oldlc2=loc;
1153: goto l99;
1154: /* Describe the current location and (maybe) get next command. */
1155: /* Print text for current loc. */
1156: l2000:
1157: if (loc == 0) goto l99;
1158: kk=stext[loc];
1159: if (abb[loc] % abbnum == 0 || kk == 0) kk=ltext[loc];
1160: if (forced(loc) || ! dark()) goto l2001;
1161: if (wzdark && pct(35)) goto l90;
1162: kk=rtext[16];
1163: l2001:
1164: if (toting(bear)) rspeak(141);
1165: speak(kk);
1166: k=1;
1167: if (forced(loc)) goto l8;
1168: if (loc == 33 && pct(25) && ! closng) rspeak(8);
1169: /*
1170: Print out descriptions of objects at this location. If
1171: not closing and property value is negative, tally off
1172: another treasure. Rug is special case; once seen, its
1173: prop is 1 (dragon on it) till dragon is killed.
1174: Similarly for chain; prop is initially 1 (locked to
1175: bear). These hacks are because prop=0 is needed to get
1176: full score.
1177: */
1178: if (dark()) goto l2012;
1179: abb[loc]++;
1180: i=atloc[loc];
1181: for(;;) {
1182: if (i == 0) goto l2012;
1183: obj=i;
1184: if (obj > 100) obj -= 100;
1185: if (obj == steps && toting(nugget)) goto l2008;
1186: if (prop[obj] < 0) {
1187: if (closed) goto l2008;
1188: prop[obj]=0;
1189: if (obj == rug || obj == chain) prop[obj]=1;
1190: tally--;
1191: /* If remaining treasures too elusive, zap his lamp. */
1192: if (tally == tally2 && tally != 0)
1193: limit = limit > 35? 35: limit;
1194: }
1195: kk=prop[obj];
1196: if (obj == steps && loc == fixed[steps]) kk=1;
1197: pspeak(obj,kk);
1198: l2008:
1199: i=rlink[i];
1200: }
1201: l2009:
1202: k=54;
1203: l2010:
1204: spk=k;
1205: l2011:
1206: rspeak(spk);
1207: l2012:
1208: verb=0;
1209: obj=0;
1210: /*
1211: Check if this loc is eligible for any hints. If been
1212: here long enough, branch to help section (on later page).
1213: Hints all come back here eventually to finish the loop.
1214: Ignore "hints" < 4 (special stuff, see database notes).
1215: */
1216: l2600:
1217: for (hint = 4; hint <= hntmax; hint++) {
1218: if (! (hinted[hint])) {
1219: if (!bitset(loc,hint)) hintlc[hint]= -1;
1220: hintlc[hint]++;
1221: if (hintlc[hint] >= hints[hint][1]) goto l40000;
1222: }
1223: }
1224: /*
1225: Kick the random number generator just to add variety to
1226: the chase. Also, if closing time, check for any objects
1227: being toted with prop < 0 and set the prop to -1-prop.
1228: This way objects won't be described until they've been
1229: picked up and put down separate from their respective
1230: piles. Don't tick clock1 unless well into cave (and not
1231: at Y2).
1232: */
1233: l2602:
1234: if (!closed) goto l2605;
1235: if (prop[oyster] < 0 && toting(oyster)
1236: ) pspeak(oyster,1);
1237: for (i = 1; i <= 100; i++) {
1238: if (toting(i) && prop[i] < 0) prop[i]= -1-prop[i];
1239: }
1240: l2605:
1241: wzdark=dark();
1242: if (knfloc > 0 && knfloc != loc) knfloc=0;
1243: i=ran(1);
1244: getin(wd1,wd1x,wd2,wd2x);
1245: /*
1246: Every input, check "foobar" flag. If zero, nothing's
1247: going on. If pos, make neg. If neg, he skipped a word,
1248: so make it zero.
1249: */
1250: l2608:
1251: foobar = foobar < 0? 0: -foobar;
1252: turns++;
1253: if (verb == say && !blankp(wd2)) verb=0;
1254: if (verb == say) goto l4090;
1255: if (tally == 0 && loc >= 15 && loc != 33) clock1--;
1256: if (clock1 == 0) goto l10000;
1257: if (clock1 < 0) clock2--;
1258: if (clock2 == 0) goto l11000;
1259: if (prop[lamp] == 1) limit--;
1260: if (limit <= 30 && here(batter) && prop[batter] == 0
1261: && here(lamp)) goto l12000;
1262: if (limit == 0) goto l12400;
1263: if (limit < 0 && loc <= 8) goto l12600;
1264: if (limit <= 30) goto l12200;
1265: l19999:
1266: k=43;
1267: if (liqloc(loc) == water) k=70;
1268: if (eqp (wd1, "enter") && (eqp (wd2, "strea") || eqp (wd2, "water")))
1269: goto l2010;
1270: if (eqp (wd1, "enter") && !blankp(wd2)) goto l2800;
1271: if (!eqp (wd1, "water") && !eqp (wd1, "oil")
1272: || (!eqp (wd2, "plant") && !eqp (wd2, "door "))) goto l2610;
1273: if (at(vocab(wd2,1))) cpy (wd2, "pour ");
1274: l2610:
1275: if (!eqp(wd1, "west ")) goto l2630;
1276: iwest++;
1277: if (iwest == 10) rspeak(17);
1278: l2630:
1279: i=vocab(wd1,-1);
1280: if (i == -1) goto l3000;
1281: k=i % 1000;
1282: kq=i/1000+1;
1283: switch (kq - 1) {
1284: case 0:
1285: goto l8;
1286: case 1:
1287: goto l5000;
1288: case 2:
1289: goto l4000;
1290: case 3:
1291: goto l2010;
1292: }
1293: bug(22);
1294: /* Get second word for analysis. */
1295: l2800:
1296: cpy (wd1, wd2);
1297: cpy (wd1x, wd2x);
1298: cpy (wd2, " ");
1299: goto l2610;
1300: /* Gee, I don't understand. */
1301: l3000:
1302: spk=60;
1303: if (pct(20)) spk=61;
1304: if (pct(20)) spk=13;
1305: rspeak(spk);
1306: goto l2600;
1307: /*
1308: Analyse a verb. remember what it was, go back for object
1309: if second word unless verb is "say", which snarfs
1310: arbitrary second word.
1311: */
1312: l4000:
1313: verb=k;
1314: spk=actspk[verb];
1315: if (!blankp(wd2) && verb != say) goto l2800;
1316: if (verb == say)
1317: if (blankp (wd2)) goto l4080;
1318: else goto l4090;
1319: if (obj != 0) goto l4090;
1320: /* Analyse an intransitive verb (ie, no object given yet). */
1321: l4080:
1322: switch (verb) {
1323: case 1:
1324: goto l8010; /* take */
1325: case 2:
1326: goto l8000; /* drop */
1327: case 3:
1328: goto l8000; /* say */
1329: case 4:
1330: goto l8040; /* open */
1331: case 5:
1332: goto l2009; /* noth */
1333: case 6:
1334: goto l8040; /* lock */
1335: case 7:
1336: goto l9070; /* on */
1337: case 8:
1338: goto l9080; /* off */
1339: case 9:
1340: goto l8000; /* wave */
1341: case 10:
1342: goto l8000; /* calm */
1343: case 11:
1344: goto l2011; /* walk */
1345: case 12:
1346: goto l9120; /* kill */
1347: case 13:
1348: goto l9130; /* pour */
1349: case 14:
1350: goto l8140; /* eat */
1351: case 15:
1352: goto l9150; /* drnk */
1353: case 16:
1354: goto l8000; /* rub */
1355: case 17:
1356: goto l8000; /* toss */
1357: case 18:
1358: goto l8180; /* quit */
1359: case 19:
1360: goto l8000; /* find */
1361: case 20:
1362: goto l8200; /* invn */
1363: case 21:
1364: goto l8000; /* feed */
1365: case 22:
1366: goto l9220; /* fill */
1367: case 23:
1368: goto l9230; /* blst */
1369: case 24:
1370: goto l8240; /* scor */
1371: case 25:
1372: goto l8250; /* foo */
1373: case 26:
1374: goto l8260; /* brf */
1375: case 27:
1376: goto l8270; /* read */
1377: case 28:
1378: goto l8000; /* brek */
1379: case 29:
1380: goto l8000; /* wake */
1381: case 30:
1382: goto l8300; /* susp */
1383: case 31:
1384: goto l8310; /* hour */
1385: case 32:
1386: goto setlog; /* log */
1387: }
1388: bug(23);
1389: /* Analyse a transitive verb. */
1390: l4090:
1391: switch (verb) {
1392: case 1:
1393: goto l9010; /* take */
1394: case 2:
1395: goto l9020; /* drop */
1396: case 3:
1397: goto l9030; /* say */
1398: case 4:
1399: goto l9040; /* open */
1400: case 5:
1401: goto l2009; /* noth */
1402: case 6:
1403: goto l9040; /* lock */
1404: case 7:
1405: goto l9070; /* on */
1406: case 8:
1407: goto l9080; /* off */
1408: case 9:
1409: goto l9090; /* wave */
1410: case 10:
1411: goto l2011; /* calm */
1412: case 11:
1413: goto l2011; /* walk */
1414: case 12:
1415: goto l9120; /* kill */
1416: case 13:
1417: goto l9130; /* pour */
1418: case 14:
1419: goto l9140; /* eat */
1420: case 15:
1421: goto l9150; /* drnk */
1422: case 16:
1423: goto l9160; /* rub */
1424: case 17:
1425: goto l9170; /* toss */
1426: case 18:
1427: goto l2011; /* quit */
1428: case 19:
1429: goto l9190; /* find */
1430: case 20:
1431: goto l9190; /* invn */
1432: case 21:
1433: goto l9210; /* feed */
1434: case 22:
1435: goto l9220; /* fill */
1436: case 23:
1437: goto l9230; /* blst */
1438: case 24:
1439: goto l2011; /* scor */
1440: case 25:
1441: goto l2011; /* foo */
1442: case 26:
1443: goto l2011; /* brf */
1444: case 27:
1445: goto l9270; /* read */
1446: case 28:
1447: goto l9280; /* brek */
1448: case 29:
1449: goto l9290; /* wake */
1450: case 30:
1451: goto l2011; /* susp */
1452: case 31:
1453: goto l2011; /* hour */
1454: case 32:
1455: goto l2011; /* log */
1456: }
1457: bug(24);
1458: /*
1459: Analyze an object word. See if the thing is here,
1460: whether we've got a verb yet, and so on. Object must be
1461: here unless verb is "find" or "invent(ory)" (and no new
1462: verb yet to be analyzed). Water and oil are also funny,
1463: since they are never actually dropped at any location,
1464: but might be here inside the bottle or as a feature of
1465: the location.
1466: */
1467: l5000:
1468: obj=k;
1469: if (fixed[k] != loc && ! here(k)) goto l5100;
1470: l5010:
1471: if (!blankp(wd2)) goto l2800;
1472: if (verb != 0) goto l4090;
1473: a5toa1(wd1,wd1x,tkword);
1474: printf ("What do you want to do with the %s?\n", tkword);
1475: goto l2600;
1476: l5100:
1477: if (k != grate) goto l5110;
1478: if (loc == 1 || loc == 4 || loc == 7) k=dprssn;
1479: if (loc > 9 && loc < 15) k=entrnc;
1480: if (k != grate) goto l8;
1481: l5110:
1482: if (k != dwarf) goto l5120;
1483: for (i = 1; i <= 5; i++) {
1484: if (dloc[i] == loc && dflag >= 2) goto l5010;
1485: }
1486: l5120:
1487: if ((liq() == k && here(bottle))
1488: || k == liqloc(loc)) goto l5010;
1489: if (obj != plant || ! at(plant2) || prop[plant2] == 0
1490: ) goto l5130;
1491: obj=plant2;
1492: goto l5010;
1493: l5130:
1494: if (obj == knife && knfloc == loc) {
1495: knfloc= -1;
1496: spk=116;
1497: goto l2011;
1498: }
1499: if (obj != rod || !here(rod2)) goto l5190;
1500: obj=rod2;
1501: goto l5010;
1502: l5190:
1503: if ((verb == find || verb == invent) && blankp (wd2)
1504: ) goto l5010;
1505: a5toa1(wd1,wd1x,tkword);
1506: printf ("I see no %s here!\n", tkword);
1507: goto l2012;
1508: /*
1509: Figure out the new location
1510: Given the current location in "loc", and a motion verb
1511: number in "k", put the new location in "newloc". The
1512: current loc is saved in "oldloc" in case he wants to
1513: retreat. The current oldloc is saved in oldlc2, in case
1514: he dies. (if he does, newloc will be limbo, and oldloc
1515: will be what killed him, so we need oldlc2, which is the
1516: last place he was safe.)
1517: */
1518: l8:
1519: kk=key[loc];
1520: newloc=loc;
1521: if (kk == 0) bug(26);
1522: if (k == nullx) goto l2;
1523: if (k == back) goto l20;
1524: if (k == look) goto l30;
1525: if (k == cave) goto l40;
1526: oldlc2=oldloc;
1527: oldloc=loc;
1528: l9:
1529: ll=longabs(travel[kk]);
1530: if (ll % 1000 == 1 || ll % 1000 == k) goto l10;
1531: if (travel[kk] < 0) goto l50;
1532: kk++;
1533: goto l9;
1534: l10:
1535: ll/=1000;
1536: l11:
1537: newloc=ll/1000;
1538: k=newloc % 100;
1539: if (newloc <= 300) goto l13;
1540: if (prop[k] != newloc/100-3) goto l16;
1541: l12:
1542: if (travel[kk] < 0) bug(25);
1543: kk++;
1544: newloc=longabs(travel[kk])/1000;
1545: if (newloc == ll) goto l12;
1546: ll=newloc;
1547: goto l11;
1548: l13:
1549: if (newloc <= 100) goto l14;
1550: if (toting(k) || (newloc > 200 && at(k))) goto l16;
1551: goto l12;
1552: l14:
1553: if (newloc != 0 && !pct((int)newloc)) goto l12;
1554: l16:
1555: newloc=ll % 1000;
1556: if (newloc <= 300) goto l2;
1557: if (newloc <= 500) goto l30000;
1558: rspeak((int)newloc-500);
1559: newloc=loc;
1560: goto l2;
1561: /*
1562: Special motions come here. Labelling convention:
1563: statement numbers nnnxx (xx=00-99) are used for special
1564: case number nnn (nnn=301-500).
1565: */
1566: l30000:
1567: newloc=newloc-300;
1568: switch ((int) newloc-1) {
1569: case 0:
1570: goto l30100;
1571: case 1:
1572: goto l30200;
1573: case 2:
1574: goto l30300;
1575: }
1576: bug(20);
1577: /*
1578: Travel 301. Plover-alcove passage. can carry only
1579: emerald. Note: travel table must include "useless"
1580: entries going through passage, which can never be used
1581: for actual motion, but can be spotted by "go back".
1582: */
1583: l30100:
1584: newloc=99+100-loc;
1585: if (holdng == 0 || (holdng == 1 && toting(emrald))) goto l2;
1586: newloc=loc;
1587: rspeak(117);
1588: goto l2;
1589: /*
1590: Travel 302. Plover transport. Drop the emerald (only
1591: use special travel if toting it), so he's forced to use
1592: the plover-passage to get it out. Having dropped it, go
1593: back and pretend he wasn't carrying it after all.
1594: */
1595: l30200:
1596: drop(emrald,loc);
1597: goto l12;
1598: /*
1599: Travel 303. Troll bridge. Must be done only as special
1600: motion so that dwarves won't wander across and encounter
1601: the bear. (They won't follow the player there because
1602: that region is forbidden to the pirate.) If
1603: prop(troll)=1, he's crossed since paying, so step out and
1604: block him. (Standard travel entries check for
1605: prop(troll)=0.) Special stuff for bear.
1606: */
1607: l30300:
1608: if (prop[troll] != 1) goto l30310;
1609: pspeak(troll,1);
1610: prop[troll]=0;
1611: move(troll2,0);
1612: move(troll2+100,0);
1613: move(troll,plac[troll]);
1614: move(troll+100,fixd[troll]);
1615: juggle(chasm);
1616: newloc=loc;
1617: goto l2;
1618: l30310:
1619: newloc=plac[troll]+fixd[troll]-loc;
1620: if (prop[troll] == 0) prop[troll]=1;
1621: if (!toting(bear)) goto l2;
1622: rspeak(162);
1623: prop[chasm]=1;
1624: prop[troll]=2;
1625: drop(bear,(int)newloc);
1626: fixed[bear]= -1;
1627: prop[bear]=3;
1628: if (prop[spices] < 0)tally2++;
1629: oldlc2=newloc;
1630: goto l99;
1631: /* End of specials. */
1632: /*
1633: Handle "go back". Look for verb which goes from loc to
1634: oldloc, or to oldlc2 if oldloc has forced-motion. k2
1635: saves entry -> forced loc -> previous loc.
1636: */
1637: l20:
1638: k=oldloc;
1639: if (forced(k)) k=oldlc2;
1640: oldlc2=oldloc;
1641: oldloc=loc;
1642: k2=0;
1643: if (k != loc) goto l21;
1644: rspeak(91);
1645: goto l2;
1646: l21:
1647: ll=(longabs(travel[kk])/1000) % 1000;
1648: if (ll == k) goto l25;
1649: if (ll > 300) goto l22;
1650: j=key[ll];
1651: if (forced((int)ll) && (longabs(travel[j])/1000) % 1000 == k
1652: ) k2=kk;
1653: l22:
1654: if (travel[kk] < 0) goto l23;
1655: kk++;
1656: goto l21;
1657: l23:
1658: kk=k2;
1659: if (kk != 0) goto l25;
1660: rspeak(140);
1661: goto l2;
1662: l25:
1663: k=longabs(travel[kk]) % 1000;
1664: kk=key[loc];
1665: goto l9;
1666: /*
1667: Look. Can't give more detail. Pretend it wasn't dark
1668: (though it may "now" be dark) so he won't fall into a pit
1669: while staring into the gloom.
1670: */
1671: l30:
1672: if (detail < 3) rspeak(15);
1673: detail++;
1674: wzdark=0;
1675: abb[loc]=0;
1676: goto l2;
1677: /* Cave. Different messages depending on whether above ground. */
1678: l40:
1679: if (loc < 8) rspeak(57);
1680: if (loc >= 8) rspeak(58);
1681: goto l2;
1682: /* Non-applicable motion. Various messages depending on word given. */
1683: l50:
1684: spk=12;
1685: if (k >= 43 && k <= 50) spk=9;
1686: if (k == 29 || k == 30) spk=9;
1687: if (k == 7 || k == 36 || k == 37) spk=10;
1688: if (k == 11 || k == 19) spk=11;
1689: if (verb == find || verb == invent) spk=59;
1690: if (k == 62 || k == 65) spk=42;
1691: if (k == 17) spk=80;
1692: rspeak(spk);
1693: goto l2;
1694: /*
1695: "You're dead, Jim."
1696: If the current loc is zero, it means the clown got
1697: himself killed. We'll allow this maxdie times. maxdie
1698: is automatically set based on the number of snide
1699: messages available. Each death results in a message (81,
1700: 83, etc.) which offers reincarnation; if accepted, this
1701: results in message 82, 84, etc. The last time, if he
1702: wants another chance, he gets a snide remark as we exit.
1703: When reincarnated, all objects being carried get dropped
1704: at oldlc2 (presumably the last place prior to being
1705: killed) without change of props. The loop runs backwards
1706: to assure that the bird is dropped before the cage.
1707: (This kluge could be changed once we're sure all
1708: references to bird and cage are done by keywords.) The
1709: lamp is a special case (it wouldn't do to leave it in the
1710: cave). It is turned off and left outside the building
1711: (only if he was carrying it, of course). He himself is
1712: left inside the building (and heaven help him if he tries
1713: to xyzzy back into the cave without the lamp!). oldloc
1714: is zapped so he can't just "retreat".
1715: The easiest way to get killed is to fall into a pit in
1716: pitch darkness.
1717: */
1718: l90:
1719: rspeak(23);
1720: oldlc2=loc;
1721: /* Okay, he's dead. Let's get on with it. */
1722: l99:
1723: if (closng) goto l95;
1724: yea=yes(81+numdie*2,82+numdie*2,54);
1725: numdie++;
1726: if (numdie == maxdie || !yea) goto l20000;
1727: place[water]=0;
1728: place[oil]=0;
1729: if (toting(lamp)) prop[lamp]=0;
1730: for (j = 1; j <= 100; j++) {
1731: i=101-j;
1732: if (!toting(i)) goto l98;
1733: k=oldlc2;
1734: if (i == lamp) k=1;
1735: drop(i,k);
1736: l98:
1737: ;
1738: }
1739: loc=3;
1740: oldloc=loc;
1741: goto l2000;
1742: /* He died during closing time. No resurrection. tally up
1743: a death and exit. */
1744: l95:
1745: rspeak(131);
1746: numdie++;
1747: goto l20000;
1748: /*
1749: Routines for performing the various action verbs
1750: Statement numbers in this section are 8000 for
1751: intransitive verbs, 9000 for transitive, plus ten times
1752: the verb number. Many intransitive verbs use the
1753: transitive code, and some verbs use code for other verbs,
1754: as noted below.
1755: Random intransitive verbs come here. Clear obj just in
1756: case (see "attack").
1757: */
1758: l8000:
1759: a5toa1(wd1,wd1x,tkword);
1760: printf ("%s what?\n", tkword);
1761: obj=0;
1762: goto l2600;
1763: /* Carry, no object given yet. OK if only one object present. */
1764: l8010:
1765: if (atloc[loc] == 0 || rlink[atloc[loc]] != 0) goto l8000;
1766: for (i = 1; i <= 5; i++) {
1767: if (dloc[i] == loc && dflag >= 2) goto l8000;
1768: }
1769: obj=atloc[loc];
1770: /*
1771: Carry an object. Special cases for bird and cage (if
1772: bird in cage, can't take one without the other. Liquids
1773: also special, since they depend on status of bottle.
1774: Also various side effects, etc.
1775: */
1776: l9010:
1777: if (toting(obj)) goto l2011;
1778: spk=25;
1779: if (obj == plant && prop[plant] <= 0) spk=115;
1780: if (obj == bear && prop[bear] == 1) spk=169;
1781: if (obj == chain && prop[bear] != 0) spk=170;
1782: if (fixed[obj] != 0) goto l2011;
1783: if (obj != water && obj != oil) goto l9017;
1784: if (here(bottle) && liq() == obj) goto l9018;
1785: obj=bottle;
1786: if (toting(bottle) && prop[bottle] == 1) goto l9220;
1787: if (prop[bottle] != 1) spk=105;
1788: if (!toting(bottle)) spk=104;
1789: goto l2011;
1790: l9018:
1791: obj=bottle;
1792: l9017:
1793: if (holdng < 7) goto l9016;
1794: rspeak(92);
1795: goto l2012;
1796: l9016:
1797: if (obj != bird) goto l9014;
1798: if (prop[bird] != 0) goto l9014;
1799: if (!toting(rod)) goto l9013;
1800: rspeak(26);
1801: goto l2012;
1802: l9013:
1803: if (toting(cage)) goto l9015;
1804: rspeak(27);
1805: goto l2012;
1806: l9015:
1807: prop[bird]=1;
1808: l9014:
1809: if ((obj == bird || obj == cage) && prop[bird] != 0
1810: ) carry(bird+cage-obj,loc);
1811: carry(obj,loc);
1812: k=liq();
1813: if (obj == bottle && k != 0) place[k]= -1;
1814: goto l2009;
1815: /*
1816: Discard object. "Throw" also comes here for most
1817: objects. Special cases for bird (might attack snake or
1818: dragon) and cage (might contain bird) and vase. Drop
1819: coins at vending machine for extra batteries.
1820: */
1821: l9020:
1822: if (toting(rod2) && obj == rod && ! toting(rod)) obj=rod2;
1823: if (!toting(obj)) goto l2011;
1824: if (obj != bird || ! here(snake)) goto l9024;
1825: rspeak(30);
1826: if (closed) goto l19000;
1827: dstroy(snake);
1828: /* Set prop for use by travel options */
1829: prop[snake]=1;
1830: l9021:
1831: k=liq();
1832: if (k == obj) obj=bottle;
1833: if (obj == bottle && k != 0) place[k]=0;
1834: if (obj == cage && prop[bird] != 0) drop(bird,loc);
1835: if (obj == bird) prop[bird]=0;
1836: drop(obj,loc);
1837: goto l2012;
1838: l9024:
1839: if (obj != coins || ! here(vend)) goto l9025;
1840: dstroy(coins);
1841: drop(batter,loc);
1842: pspeak(batter,0);
1843: goto l2012;
1844: l9025:
1845: if (obj != bird || ! at(dragon) || prop[dragon] != 0
1846: ) goto l9026;
1847: rspeak(154);
1848: dstroy(bird);
1849: prop[bird]=0;
1850: if (place[snake] == plac[snake])tally2++;
1851: goto l2012;
1852: l9026:
1853: if (obj != bear || !at(troll)) goto l9027;
1854: rspeak(163);
1855: move(troll,0);
1856: move(troll+100,0);
1857: move(troll2,plac[troll]);
1858: move(troll2+100,fixd[troll]);
1859: juggle(chasm);
1860: prop[troll]=2;
1861: goto l9021;
1862: l9027:
1863: if (obj == vase && loc != plac[pillow]) goto l9028;
1864: rspeak(54);
1865: goto l9021;
1866: l9028:
1867: prop[vase]=2;
1868: if (at(pillow)) prop[vase]=0;
1869: pspeak(vase,prop[vase]+1);
1870: if (prop[vase] != 0) fixed[vase]= -1;
1871: goto l9021;
1872: /* Say. Echo wd2 (or wd1 if no wd2 (say what?, etc.).)
1873: Magic words override. */
1874: l9030:
1875: a5toa1(wd2,wd2x,tkword);
1876: if (blankp(wd2)) a5toa1(wd1,wd1x,tkword);
1877: else cpy(wd1,wd2);
1878: i=vocab(wd1,-1);
1879: if (i == 62 || i == 65 || i == 71 || i == 2025) goto l9035;
1880: printf ("Okay, \"%s\"\n", tkword);
1881: goto l2012;
1882: l9035:
1883: cpy(wd2, " ");
1884: obj=0;
1885: goto l2630;
1886: /* Lock, unlock, no object given. Assume various things if present. */
1887: l8040:
1888: spk=28;
1889: if (here(clam)) obj=clam;
1890: if (here(oyster)) obj=oyster;
1891: if (at(door)) obj=door;
1892: if (at(grate)) obj=grate;
1893: if (obj != 0 && here(chain)) goto l8000;
1894: if (here(chain)) obj=chain;
1895: if (obj == 0) goto l2011;
1896: /* Lock, unlock object. Special stuff for opening
1897: clam/oyster and for chain. */
1898: l9040:
1899: if (obj == clam || obj == oyster) goto l9046;
1900: if (obj == door) spk=111;
1901: if (obj == door && prop[door] == 1) spk=54;
1902: if (obj == cage) spk=32;
1903: if (obj == keys) spk=55;
1904: if (obj == grate || obj == chain) spk=31;
1905: if (spk != 31 || ! here(keys)) goto l2011;
1906: if (obj == chain) goto l9048;
1907: if (!closng) goto l9043;
1908: k=130;
1909: if (!panic) clock2=15;
1910: panic=1;
1911: goto l2010;
1912: l9043:
1913: k=34+prop[grate];
1914: prop[grate]=1;
1915: if (verb == lock) prop[grate]=0;
1916: k=k+2*prop[grate];
1917: goto l2010;
1918: /* Clam/oyster. */
1919: l9046:
1920: k=0;
1921: if (obj == oyster) k=1;
1922: spk=124+k;
1923: if (toting(obj)) spk=120+k;
1924: if (!toting(tridnt)) spk=122+k;
1925: if (verb == lock) spk=61;
1926: if (spk != 124) goto l2011;
1927: dstroy(clam);
1928: drop(oyster,loc);
1929: drop(pearl,105);
1930: goto l2011;
1931: /* Chain. */
1932: l9048:
1933: if (verb == lock) goto l9049;
1934: spk=171;
1935: if (prop[bear] == 0) spk=41;
1936: if (prop[chain] == 0) spk=37;
1937: if (spk != 171) goto l2011;
1938: prop[chain]=0;
1939: fixed[chain]=0;
1940: if (prop[bear] != 3) prop[bear]=2;
1941: fixed[bear]=2-prop[bear];
1942: goto l2011;
1943: l9049:
1944: spk=172;
1945: if (prop[chain] != 0) spk=34;
1946: if (loc != plac[chain]) spk=173;
1947: if (spk != 172) goto l2011;
1948: prop[chain]=2;
1949: if (toting(chain)) drop(chain,loc);
1950: fixed[chain]= -1;
1951: goto l2011;
1952: /* Light lamp */
1953: l9070:
1954: if(!here(lamp)) goto l2011;
1955: spk=184;
1956: if(limit < 0) goto l2011;
1957: prop[lamp]=1;
1958: rspeak(39);
1959: if(wzdark) goto l2000;
1960: goto l2012;
1961: /* Lamp off */
1962: l9080:
1963: if(!here(lamp)) goto l2011;
1964: prop[lamp]=0;
1965: rspeak(40);
1966: if(dark()) rspeak(16);
1967: goto l2012;
1968: /* Wave. No effect unless waving rod at fissure. */
1969: l9090:
1970: if ((!toting(obj)) && (obj != rod || ! toting(rod2))
1971: ) spk=29;
1972: if (obj != rod || ! at(fissur) || ! toting(obj)
1973: || closng) goto l2011;
1974: prop[fissur]=1-prop[fissur];
1975: pspeak(fissur,2-prop[fissur]);
1976: goto l2012;
1977: /*
1978: Attack. Assume target if unambiguous. "throw" also
1979: links here. Attackable objects fall into two categories:
1980: enemies (snake, dwarf, etc.) and others (bird, clam).
1981: Ambiguous if two enemies, or if no enemies but two
1982: others.
1983: */
1984: l9120:
1985: for (i = 1; i <= 5; i++) {
1986: if(dloc[i] == loc && dflag >= 2) goto l9122;
1987: }
1988: i=0;
1989: l9122:
1990: if(obj != 0) goto l9124;
1991: if(i != 0) obj=dwarf;
1992: if(here(snake)) obj=obj*100+snake;
1993: if(at(dragon) && prop[dragon] == 0) obj=obj*100+dragon;
1994: if(at(troll)) obj=obj*100+troll;
1995: if(here(bear) && prop[bear] == 0) obj=obj*100+bear;
1996: if(obj > 100) goto l8000;
1997: if(obj != 0) goto l9124;
1998: /* Can't attack bird by throwing axe. */
1999: if(here(bird) && verb != throw) obj=bird;
2000: /* Clam and oyster both treated as clam for intransitive
2001: case; no harm done. */
2002: if(here(clam) || here(oyster)) obj=100*obj+clam;
2003: if(obj > 100) goto l8000;
2004: l9124:
2005: if(obj != bird) goto l9125;
2006: spk=137;
2007: if(closed) goto l2011;
2008: dstroy(bird);
2009: prop[bird]=0;
2010: if(place[snake] == plac[snake])tally2++;
2011: spk=45;
2012: l9125:
2013: if(obj == 0) spk=44;
2014: if(obj == clam || obj == oyster) spk=150;
2015: if(obj == snake) spk=46;
2016: if(obj == dwarf) spk=49;
2017: if(obj == dwarf && closed) goto l19000;
2018: if(obj == dragon) spk=167;
2019: if(obj == troll) spk=157;
2020: if(obj == bear) spk=165+(prop[bear]+1)/2;
2021: if(obj != dragon || prop[dragon] != 0) goto l2011;
2022: /*
2023: Fun stuff for dragon. If he insists on attacking it,
2024: win! Set prop to dead, move dragon to central loc (still
2025: fixed), move rug there (not fixed), and move him there,
2026: too. Then do a null motion to get new description.
2027: */
2028: rspeak(49);
2029: verb=0;
2030: obj=0;
2031: getin(wd1,wd1x,wd2,wd2x);
2032: if (!eqp (wd1, "y") && !eqp (wd1, "yes")) goto l2608;
2033: pspeak(dragon,1);
2034: prop[dragon]=2;
2035: prop[rug]=0;
2036: k=(plac[dragon]+fixd[dragon])/2;
2037: move(dragon+100,-1);
2038: move(rug+100,0);
2039: move(dragon,k);
2040: move(rug,k);
2041: for (obj=1; obj<=100; obj++) {
2042: if (place[obj] == plac[dragon] || place[obj] == fixd[dragon]
2043: ) move(obj,k);
2044: }
2045: loc=k;
2046: k=nullx;
2047: goto l8;
2048: /*
2049: Pour. If no object, or object is bottle, assume contents
2050: of bottle. Special tests for pouring water or oil on
2051: plant or rusty door.
2052: */
2053: l9130:
2054: if(obj == bottle || obj == 0) obj=liq();
2055: if(obj == 0) goto l8000;
2056: if(!toting(obj)) goto l2011;
2057: spk=78;
2058: if(obj != oil && obj != water) goto l2011;
2059: prop[bottle]=1;
2060: place[obj]=0;
2061: spk=77;
2062: if(!(at(plant) || at(door))) goto l2011;
2063: if(at(door)) goto l9132;
2064: spk=112;
2065: if(obj != water) goto l2011;
2066: pspeak(plant,prop[plant]+1);
2067: prop[plant]=(prop[plant]+2) % 6;
2068: prop[plant2]=prop[plant]/2;
2069: k=nullx;
2070: goto l8;
2071: l9132:
2072: prop[door]=0;
2073: if(obj == oil) prop[door]=1;
2074: spk=113+prop[door];
2075: goto l2011;
2076: /*
2077: Eat. Intransitive: assume food if present, else ask
2078: what. Transitive: food ok, some things lose appetite,
2079: rest are ridiculous.
2080: */
2081: l8140:
2082: if(!here(food)) goto l8000;
2083: l8142:
2084: dstroy(food);
2085: spk=72;
2086: goto l2011;
2087: l9140:
2088: if(obj == food) goto l8142;
2089: if (obj == bird || obj == snake || obj == clam || obj == oyster
2090: || obj == dwarf || obj == dragon || obj == troll
2091: || obj == bear) spk=71;
2092: goto l2011;
2093: /*
2094: Drink. If no object, assume water and look for it here.
2095: if water is in the bottle, drink that, else must be at a
2096: water loc, so drink stream.
2097: */
2098: l9150:
2099: if (obj == 0 && liqloc(loc) != water && (liq() != water
2100: || ! here(bottle))) goto l8000;
2101: if(obj != 0 && obj != water) spk=110;
2102: if (spk == 110 || liq() != water || ! here(bottle)
2103: ) goto l2011;
2104: prop[bottle]=1;
2105: place[water]=0;
2106: spk=74;
2107: goto l2011;
2108: /* Rub. Yields various snide remarks. */
2109: l9160:
2110: if(obj != lamp) spk=76;
2111: goto l2011;
2112: /*
2113: Throw. Same as discard unless axe. Then same as attack
2114: except ignore bird, and if dwarf is present then one
2115: might be killed. (only way to do so!) Axe also special
2116: for dragon, bear, and troll. Treasures special for
2117: troll.
2118: */
2119: l9170:
2120: if(toting(rod2) && obj == rod && ! toting(rod)) obj=rod2;
2121: if(!toting(obj)) goto l2011;
2122: if(obj >= 50 && obj <= maxtrs && at(troll)) goto l9178;
2123: if(obj == food && here(bear)) goto l9177;
2124: if(obj != axe) goto l9020;
2125: for (i = 1; i <= 5; i++) {
2126: /* Needn't check dflag if axe is here. */
2127: if(dloc[i] == loc) goto l9172;
2128: }
2129: spk=152;
2130: if(at(dragon) && prop[dragon] == 0) goto l9175;
2131: spk=158;
2132: if(at(troll)) goto l9175;
2133: if(here(bear) && prop[bear] == 0) goto l9176;
2134: obj=0;
2135: goto l9120;
2136: l9172:
2137: spk=48;
2138: if(ran(3) == 0) goto l9175;
2139: dseen[i]=0;
2140: dloc[i]=0;
2141: spk=47;
2142: dkill++;
2143: if(dkill == 1) spk=149;
2144: l9175:
2145: rspeak(spk);
2146: drop(axe,loc);
2147: k=nullx;
2148: goto l8;
2149: /* This'll teach him to throw the axe at the bear! */
2150: l9176:
2151: spk=164;
2152: drop(axe,loc);
2153: fixed[axe]= -1;
2154: prop[axe]=1;
2155: juggle(bear);
2156: goto l2011;
2157: /* But throwing food is another story. */
2158: l9177:
2159: obj=bear;
2160: goto l9210;
2161: l9178:
2162: spk=159;
2163: /* Snarf a treasure for the troll. */
2164: drop(obj,0);
2165: move(troll,0);
2166: move(troll+100,0);
2167: drop(troll2,plac[troll]);
2168: drop(troll2+100,fixd[troll]);
2169: juggle(chasm);
2170: goto l2011;
2171: /* Quit. Intransitive only. Verify intent and exit if
2172: that's what he wants. */
2173: l8180:
2174: gaveup=yes(22,54,54);
2175: if(gaveup) goto l20000;
2176: goto l2012;
2177: /* Find. Might be carrying it, or it might be here. Else give caveat. */
2178: l9190:
2179: if (at(obj) || (liq() == obj && at(bottle))
2180: || k == liqloc(loc)) spk=94;
2181: for (i = 1; i <= 5; i++) {
2182: if(dloc[i] == loc && dflag >= 2 && obj == dwarf) spk=94;
2183: }
2184: if(closed) spk=138;
2185: if(toting(obj)) spk=24;
2186: goto l2011;
2187: /* Inventory. If object, treat same as find. Else report
2188: on current burden. */
2189: l8200:
2190: spk=98;
2191: for (i = 1; i <= 100; i++) {
2192: if(i == bear || ! toting(i)) goto l8201;
2193: if(spk == 98) rspeak(99);
2194: blklin=0;
2195: pspeak(i,-1);
2196: blklin=1;
2197: spk=0;
2198: l8201:
2199: ;
2200: }
2201: if(toting(bear)) spk=141;
2202: goto l2011;
2203: /*
2204: Feed. If bird, no seed. snake, dragon, troll: quip. If
2205: dwarf, make him mad. Bear, special.
2206: */
2207: l9210:
2208: if(obj != bird) goto l9212;
2209: spk=100;
2210: goto l2011;
2211: l9212:
2212: if(obj != snake && obj != dragon && obj != troll) goto l9213;
2213: spk=102;
2214: if(obj == dragon && prop[dragon] != 0) spk=110;
2215: if(obj == troll) spk=182;
2216: if(obj != snake || closed || ! here(bird)) goto l2011;
2217: spk=101;
2218: dstroy(bird);
2219: prop[bird]=0;
2220: tally2++;
2221: goto l2011;
2222: l9213:
2223: if(obj != dwarf) goto l9214;
2224: if(!here(food)) goto l2011;
2225: spk=103;
2226: dflag++;
2227: goto l2011;
2228: l9214:
2229: if(obj != bear) goto l9215;
2230: if(prop[bear] == 0) spk=102;
2231: if(prop[bear] == 3) spk=110;
2232: if(!here(food)) goto l2011;
2233: dstroy(food);
2234: prop[bear]=1;
2235: fixed[axe]=0;
2236: prop[axe]=0;
2237: spk=168;
2238: goto l2011;
2239: l9215:
2240: spk=14;
2241: goto l2011;
2242: /* Fill. Bottle must be empty, and some liquid available.
2243: (vase is nasty.) */
2244: l9220:
2245: if(obj == vase) goto l9222;
2246: if(obj != 0 && obj != bottle) goto l2011;
2247: if(obj == 0 && ! here(bottle)) goto l8000;
2248: spk=107;
2249: if(liqloc(loc) == 0) spk=106;
2250: if(liq() != 0) spk=105;
2251: if(spk != 107) goto l2011;
2252: prop[bottle]=(cond[loc] % 4)/2;
2253: prop[bottle]=prop[bottle]*2;
2254: k=liq();
2255: if(toting(bottle)) place[k]= -1;
2256: if(k == oil) spk=108;
2257: goto l2011;
2258: l9222:
2259: spk=29;
2260: if(liqloc(loc) == 0) spk=144;
2261: if(liqloc(loc) == 0 || !toting(vase)) goto l2011;
2262: rspeak(145);
2263: prop[vase]=2;
2264: fixed[vase]= -1;
2265: goto l9024;
2266: /* Blast. No effect unless you've got dynamite, which is a
2267: neat trick! */
2268: l9230:
2269: if(prop[rod2] < 0 || ! closed) goto l2011;
2270: bonus=133;
2271: if(loc == 115) bonus=134;
2272: if(here(rod2)) bonus=135;
2273: rspeak(bonus);
2274: goto l20000;
2275: /* Score. Go to scoring section, which will return to 8241
2276: if scorng is true. */
2277: l8240:
2278: scorng=1;
2279: goto l20000;
2280: l8241:
2281: scorng=0;
2282: printf ("If you were to quit now, you would score ");
2283: printf ("%d out of a possible %d in %d turns.\n",
2284: score, mxscor, turns+1);
2285: goto l2012;
2286: /*
2287: Fee fie foe foo (and fum). Advance to next state if given
2288: in proper order. Look up wd1 in section 3 of vocab to
2289: determine which word we've got. Last word zips the eggs
2290: back to the giant room (unless already there).
2291: */
2292: l8250:
2293: k=vocab(wd1,3);
2294: spk=42;
2295: if(foobar == 1-k) goto l8252;
2296: if(foobar != 0) spk=151;
2297: goto l2011;
2298: l8252:
2299: foobar=k;
2300: if(k != 4) goto l2009;
2301: foobar=0;
2302: if (place[eggs] == plac[eggs]
2303: || (toting(eggs) && loc == plac[eggs])) goto l2011;
2304: /* Bring back troll if we steal the eggs back from him
2305: before crossing. */
2306: if (place[eggs] == 0 && place[troll] == 0 && prop[troll] == 0
2307: ) prop[troll]=1;
2308: k=2;
2309: if(here(eggs)) k=1;
2310: if(loc == plac[eggs]) k=0;
2311: move(eggs,plac[eggs]);
2312: pspeak(eggs,k);
2313: goto l2012;
2314: /* Brief. Intransitive only. Suppress long descriptions
2315: after first time. */
2316: l8260:
2317: spk=156;
2318: abbnum=10000;
2319: detail=3;
2320: goto l2011;
2321: /* Read. Magazines in dwarvish, message we've seen, and .
2322: . . oyster? */
2323: l8270:
2324: if(here(magzin)) obj=magzin;
2325: if(here(tablet)) obj=obj*100+tablet;
2326: if(here(messag)) obj=obj*100+messag;
2327: if(closed && toting(oyster)) obj=oyster;
2328: if(obj > 100 || obj == 0 || dark()) goto l8000;
2329: l9270:
2330: if(dark()) goto l5190;
2331: if(obj == magzin) spk=190;
2332: if(obj == tablet) spk=196;
2333: if(obj == messag) spk=191;
2334: if(obj == oyster && hinted[2] && toting(oyster)) spk=194;
2335: if (obj != oyster || hinted[2] || !toting(oyster)
2336: || !closed) goto l2011;
2337: hinted[2]=yes(192,193,54);
2338: goto l2012;
2339: /* Break. Only works for mirror in repository and, of
2340: course, the vase. */
2341: l9280:
2342: if(obj == mirror) spk=148;
2343: if(obj == vase && prop[vase] == 0) goto l9282;
2344: if(obj != mirror || !closed) goto l2011;
2345: rspeak(197);
2346: goto l19000;
2347: l9282:
2348: spk=198;
2349: if(toting(vase)) drop(vase,loc);
2350: prop[vase]=2;
2351: fixed[vase]= -1;
2352: goto l2011;
2353: /* Wake. Only use is to disturb the dwarves. */
2354: l9290:
2355: if(obj != dwarf || !closed) goto l2011;
2356: rspeak(199);
2357: goto l19000;
2358: /*
2359: Suspend. Exit leaving things restartable.
2360: */
2361: l8300:
2362: if ((suspfd = fopen (suspfile, SUSPWRITE)) == NULL) {
2363: printf ("Something's wrong...I can't suspend.\n");
2364: if (hungup) {
2365: hungup = 0;
2366: goto l20000;
2367: }
2368: goto l2012;
2369: }
2370: hungup = 0;
2371: printf ("OK...I'm suspending this game in %s\n", suspfile);
2372:
2373: /* Block interrupts to ensure completion of suspension */
2374: signal (SIGINT, SIG_IGN);
2375: signal (SIGQUIT, SIG_IGN);
2376: signal (SIGHUP, SIG_IGN);
2377:
2378: /* Write the release and level into the suspend file */
2379: putw (1, suspfd);
2380: putw (20, suspfd);
2381:
2382: /* Write the time to prevent premature resumption */
2383: tvec = time(0);
2384: putl (tvec, suspfd);
2385:
2386: /* Write the suspend data into the file */
2387: fwrite (&suspbeg, sizeof suspbeg, &suspend - &suspbeg, suspfd);
2388:
2389: /* Make sure everything went ok */
2390: if (ferror (suspfd))
2391: fatal ("I/O error during suspension");
2392:
2393: fclose (suspfd);
2394: #ifdef NOTIME
2395: printf ("Play will resume automatically next time.\n");
2396: #else
2397: printf ("You may resume play half an hour from now.\n");
2398: #endif
2399: exit(0);
2400: /* Hours. Report current non-prime-time hours. */
2401: l8310:
2402: printf (HOURS);
2403: goto l2012;
2404: /* Log. Toggle loggin either on or off */
2405: setlog:
2406: logon = ! logon;
2407: if (logon)
2408: printf ("Log on.\n");
2409: else
2410: printf ("Log off.\n");
2411: goto l2012;
2412: /*
2413: hints
2414: Come here if he's been long enough at required loc(s) for
2415: some unused hint. Hint number is in variable "hint".
2416: branch to quick test for additional conditions, then come
2417: back to do neat stuff. goto 40010 if conditions are met
2418: and we want to offer the hint. goto 40020 to clear
2419: hintlc back to zero, 40030 to take no action yet.
2420: */
2421: l40000:
2422: switch (hint-4) {
2423: case 0:
2424: goto l40400; /* cave */
2425: case 1:
2426: goto l40500; /* bird */
2427: case 2:
2428: goto l40600; /* snake */
2429: case 3:
2430: goto l40700; /* maze */
2431: case 4:
2432: goto l40800; /* dark */
2433: case 5:
2434: goto l40900; /* witt */
2435: }
2436: bug(27);
2437: l40010:
2438: hintlc[hint]=0;
2439: if(!yes(hints[hint][3],0,54)) goto l2602;
2440: printf ("I am prepared to give you a hint,");
2441: printf (" but it will cost you %d points.\n", hints[hint][2]);
2442: hinted[hint]=yes(175,hints[hint][4],54);
2443: if (hinted[hint] && limit > 30
2444: ) limit=limit+30*hints[hint][2];
2445: l40020:
2446: hintlc[hint]=0;
2447: l40030:
2448: goto l2602;
2449: /* Now for the quick tests. See database description for
2450: one-line notes. */
2451: l40400:
2452: if(prop[grate] == 0 && ! here(keys)) goto l40010;
2453: goto l40020;
2454: l40500:
2455: if(here(bird) && toting(rod) && obj == bird) goto l40010;
2456: goto l40030;
2457: l40600:
2458: if(here(snake) && ! here(bird)) goto l40010;
2459: goto l40020;
2460: l40700:
2461: if (atloc[loc] == 0 && atloc[oldloc] == 0
2462: && atloc[oldlc2] == 0 && holdng > 1) goto l40010;
2463: goto l40020;
2464: l40800:
2465: if(prop[emrald] != -1 && prop[pyram] == -1) goto l40010;
2466: goto l40020;
2467: l40900:
2468: goto l40010;
2469: /*
2470: Cave closing and scoring
2471: These sections handle the closing of the cave. The cave
2472: closes "clock1" turns after the last treasure has been
2473: located (including the pirate's chest, which may of
2474: course never show up). Note that the treasures need not
2475: have been taken yet, just located. Hence clock1 must be
2476: large enough to get out of the cave (it only ticks while
2477: inside the cave). When it hits zero, we branch to 10000
2478: to start closing the cave, and then sit back and wait for
2479: him to try to get out. If he doesn't within clock2
2480: turns, we close the cave; if he does try, we assume he
2481: panics, and give him a few additional turns to get
2482: frantic before we close. When clock2 hits zero, we
2483: branch to 11000 to transport him into the final puzzle.
2484: Note that the puzzle depends upon all sorts of random
2485: things. For instance, there must be no water or oil,
2486: since there are beanstalks which we don't want to be able
2487: to water, since the code can't handle it. Also, we can
2488: have no keys, since there is a grate (having moved the
2489: fixed object!) there separating him from all the
2490: treasures. Most of these problems arise from the use of
2491: negative prop numbers to suppress the object descriptions
2492: until he's actually moved the objects.
2493: When the first warning comes, we lock the grate, destroy
2494: the bridge, kill all the dwarves (and the pirate), remove
2495: the troll and bear (unless dead), and set "closng" to
2496: true. Leave the dragon; too much trouble to move it.
2497: From now until clock2 runs out, he cannot unlock the
2498: grate, move to any location outside the cave (loc<9), or
2499: create the bridge. Nor can he be resurrected if he dies.
2500: Note that the snake is already gone, since he got to the
2501: treasure accessible only via the hall of the mt. king.
2502: also, he's been in giant room (to get eggs), so we can
2503: refer to it. Also also, he's gotten the pearl, so we
2504: know the bivalve is an oyster. AND, the dwarves must
2505: have been activated, since we've found chest.
2506: */
2507: l10000:
2508: prop[grate]=0;
2509: prop[fissur]=0;
2510: for (i = 1; i <= 6; i++) {
2511: dseen[i]=0;
2512: }
2513: move(troll,0);
2514: move(troll+100,0);
2515: move(troll2,plac[troll]);
2516: move(troll2+100,fixd[troll]);
2517: juggle(chasm);
2518: if(prop[bear] != 3) dstroy(bear);
2519: prop[chain]=0;
2520: fixed[chain]=0;
2521: prop[axe]=0;
2522: fixed[axe]=0;
2523: rspeak(129);
2524: clock1= -1;
2525: closng=1;
2526: goto l19999;
2527: /*
2528: Once he's panicked, and clock2 has run out, we come here
2529: to set up the storage room. The room has two locs,
2530: hardwired as 115 (ne) and 116 (sw). At the ne end, we
2531: place empty bottles, a nursery of plants, a bed of
2532: oysters, a pile of lamps, rods with stars, sleeping
2533: dwarves, and him. At the sw end we place grate over
2534: treasures, snake pit, covey of caged birds, more rods,
2535: and pillows. A mirror stretches across one wall. Many
2536: of the objects come from known locations and/or states
2537: (e.g. the snake is known to have been destroyed and
2538: needn't be carried away from its old "place"), making the
2539: various objects be handled differently. We also drop all
2540: other objects he might be carrying (lest he have some
2541: which could cause trouble, such as the keys). We
2542: describe the flash of light and trundle back.
2543: */
2544: l11000:
2545: prop[bottle]=put(bottle,115,1);
2546: prop[plant]=put(plant,115,0);
2547: prop[oyster]=put(oyster,115,0);
2548: prop[lamp]=put(lamp,115,0);
2549: prop[rod]=put(rod,115,0);
2550: prop[dwarf]=put(dwarf,115,0);
2551: loc=115;
2552: oldloc=115;
2553: newloc=115;
2554: /* Leave the grate with normal (non-negative property). */
2555: foo=put(grate,116,0);
2556: prop[snake]=put(snake,116,1);
2557: prop[bird]=put(bird,116,1);
2558: prop[cage]=put(cage,116,0);
2559: prop[rod2]=put(rod2,116,0);
2560: prop[pillow]=put(pillow,116,0);
2561: prop[mirror]=put(mirror,115,0);
2562: fixed[mirror]=116;
2563: for (i = 1; i <= 100; i++) {
2564: if(toting(i)) dstroy(i);
2565: }
2566: rspeak(132);
2567: closed=1;
2568: goto l2;
2569: /*
2570: Another way we can force an end to things is by having
2571: the lamp give out. When it gets close, we come here to
2572: warn him. We go to 12000 if the lamp and fresh batteries
2573: are here, in which case we replace the batteries and
2574: continue. 12200 is for other cases of lamp dying. 12400
2575: is when it goes out, and 12600 is if he's wandered
2576: outside and the lamp is used up, in which case we force
2577: him to give up.
2578: */
2579: l12000:
2580: rspeak(188);
2581: prop[batter]=1;
2582: if(toting(batter)) drop(batter,loc);
2583: limit=limit+2500;
2584: lmwarn=0;
2585: goto l19999;
2586: l12200:
2587: if (lmwarn || !here(lamp)) goto l19999;
2588: lmwarn=1;
2589: spk=187;
2590: if (place[batter] == 0) spk=183;
2591: if (prop[batter] == 1) spk=189;
2592: rspeak(spk);
2593: goto l19999;
2594: l12400:
2595: limit= -1;
2596: prop[lamp]=0;
2597: if (here(lamp)) rspeak(184);
2598: goto l19999;
2599: l12600:
2600: rspeak(185);
2601: gaveup=1;
2602: goto l20000;
2603: /* Oh dear, he's disturbed the dwarves. */
2604: l19000:
2605: rspeak(136);
2606: /*
2607: Exit code.
2608: the present scoring algorithm is as follows:
2609: objective: points: present total possible:
2610: getting well into cave 25 25
2611: each treasure < chest 12 60
2612: treasure chest itself 14 14
2613: each treasure > chest 16 144
2614: surviving (max-num)*10 30
2615: not quitting 4 4
2616: reaching "closng" 25 25
2617: "closed": quit/killed 10
2618: klutzed 25
2619: wrong way 30
2620: success 45 45
2621: came to witt's end 1 1
2622: round out the total 2 2
2623: total: 350
2624: (points can also be deducted for using hints.)
2625: */
2626: l20000:
2627: score=0;
2628: mxscor=0;
2629: /*
2630: First tally up the treasures. Must be in building and
2631: not broken. Give the poor guy 2 points just for finding
2632: each treasure.
2633: */
2634: for (i = 50; i <= maxtrs; i++) {
2635: if (ptext[i] != 0) {
2636: k=12;
2637: if (i == chest) k=14;
2638: if (i > chest) k=16;
2639: if (prop[i] >= 0) score=score+2;
2640: if (place[i] == 3 && prop[i] == 0) score=score+k-2;
2641: mxscor=mxscor+k;
2642: }
2643: }
2644: /*
2645: Now look at how he finished and how far he got. maxdie
2646: and numdie tell us how well he survived. gaveup says
2647: whether he exited via quit. dflag will tell us if he
2648: ever got suitably deep into the cave. closng still
2649: indicates whether he reached the endgame. And if he got
2650: as far as "cave closed" (indicated by "closed"), then
2651: bonus is zero for mundane exits or 133, 134, 135 if he
2652: blew it (so to speak).
2653: */
2654: score=score+(maxdie-numdie)*10;
2655: mxscor=mxscor+maxdie*10;
2656: if (!(scorng || gaveup)) score=score+4;
2657: mxscor=mxscor+4;
2658: if (dflag != 0) score=score+25;
2659: mxscor=mxscor+25;
2660: if (closng) score=score+25;
2661: mxscor=mxscor+25;
2662: if (!closed) goto l20020;
2663: if (bonus == 0) score=score+10;
2664: if (bonus == 135) score=score+25;
2665: if (bonus == 134) score=score+30;
2666: if (bonus == 133) score=score+45;
2667: l20020:
2668: mxscor=mxscor+45;
2669: /* Did he come to Witt's End as he should? */
2670: if (place[magzin] == 108)score++;
2671: mxscor++;
2672: /* Round it off. */
2673: score=score+2;
2674: mxscor=mxscor+2;
2675: /* Deduct points for hints. hints < 4 are special; see
2676: database description. */
2677: for (i = 1; i <= hntmax; i++) {
2678: if (hinted[i]) score=score-hints[i][2];
2679: }
2680: /* Return to score command if that's where we came from. */
2681: if (scorng) goto l8241;
2682: /* That should be good enough. Let's tell him all about it. */
2683: printf ("You scored %d out of a possible %d using %d turn%s.\n",
2684: score, mxscor, turns, turns==1? "": "s");
2685: for (i = 1; i <= clsses; i++) {
2686: if (cval[i] >= score) goto l20210;
2687: }
2688: printf("You just went off my scale!!!\n");
2689: goto l25000;
2690: l20210:
2691: speak(ctext[i]);
2692: if (i == clsses-1) goto l20220;
2693: k=cval[i]+1-score;
2694: printf ("To achieve the next higher rating, you need %d more point%s.\n",
2695: k, k==1? "": "s");
2696: goto l25000;
2697: l20220:
2698: printf ("To achieve the next higher rating would be a neat trick!\n");
2699: printf ("Congratulations!!\n");
2700: l25000:
2701: if (logon) {
2702: /* Log this termination for the interest of other users */
2703: FILE *logfile;
2704: char *ctime();
2705: if ((logfile = fopen ("/usr/games/advlog", "a")) != NULL) {
2706: tvec = time((long *) 0);
2707: cp1 = ctime (&tvec);
2708: /* Assumed format "Mon Jan 99 99:99:99 1999\n\0" */
2709: cp1[10] = '\0';
2710: fprintf (logfile, "%s; %s: %d in %d\n",
2711: cp1 + 4, pwbuf -> pw_name,
2712: score, turns);
2713: }
2714: }
2715: }
2716:
2717: /*
2718: * subroutines/functions
2719: * toting(obj) = true if the obj is being carried
2720: * here(obj) = true if the obj is at "loc" (or is being carried)
2721: * at(obj) = true if on either side of two-placed object
2722: * liq(dummy) = object number of liquid in bottle
2723: * liqloc(loc) = object number of liquid (if any) at loc
2724: * bitset(l,n) = true if cond(l) has bit n set (bit 0 is units bit)
2725: * forced(loc) = true if loc moves without asking for input (cond=2)
2726: * dark(dummy) = true if location "loc" is dark
2727: * pct(n) = true n% of the time (n integer from 0 to 100)
2728: */
2729:
2730: toting(ob)
2731: {
2732: return place[ob] == -1;
2733: }
2734:
2735: here(ob)
2736: {
2737: return place[ob] == loc || toting (ob);
2738: }
2739:
2740: at(ob)
2741: {
2742: return place[ob] == loc || fixed[ob] == loc;
2743: }
2744:
2745: liq2(pbotl)
2746: {
2747: int liq2temp;
2748: liq2temp = pbotl/2;
2749: return (1-pbotl)*water + liq2temp * (water+oil);
2750: }
2751:
2752: liq()
2753: {
2754: int t;
2755: t = prop[bottle];
2756: return liq2(t>-1-t? t: -1-t);
2757: }
2758:
2759: liqloc(where)
2760: {
2761: int t1, t2;
2762: t1 = cond[where] / 2;
2763: t1 = t1 * 2;
2764: t2 = cond[where] / 4;
2765: return liq2 (((t1 % 8)-5)*(t2%2)+1);
2766: }
2767:
2768: bitset (mm, n)
2769: {
2770: return (cond[mm] >> n) & 1;
2771: }
2772:
2773: forced(where)
2774: {
2775: return cond[where] == 2;
2776: }
2777:
2778: dark()
2779: {
2780: return ((cond[loc] & 1) == 0) && (prop[lamp] == 0 || !here(lamp));
2781: }
2782:
2783: pct (n)
2784: {
2785: return ran(100) < n;
2786: }
2787:
2788: /*
2789: * Place any object anywhere by picking it up and dropping
2790: * it. May already be toting, in which case the carry is
2791: * a no-op. Mustn't pick up objects which are not at any
2792: * loc, since carry wants to remove objects from atloc chains.
2793: */
2794: move (object, where) {
2795: int source;
2796: if (object <= 100)
2797: source = place[object];
2798: else
2799: source = fixed[object-100];
2800: if (source > 0 && source <= 300)
2801: carry (object, source);
2802: drop (object, where);
2803: }
2804:
2805: dstroy (object)
2806: {
2807: move (object, 0);
2808: }
2809:
2810: juggle (object)
2811: {
2812: register int ii, jj;
2813: ii = place[object];
2814: jj = fixed [object];
2815: move (object, ii);
2816: move (object+100, jj);
2817: }
2818:
2819: put (object, where, pval)
2820: {
2821: move (object, where);
2822: return -1-pval;
2823: }
2824:
2825: /*
2826: * Start toting an object, removing it from the list of things at
2827: * its former location. Increment holding unless it was already
2828: * being toted. If object>100 (moving "fixed" second loc)
2829: * don't change place or holdng.
2830: */
2831: carry (object, where)
2832: {
2833: int tmp;
2834: if (object <= 100) {
2835: if (place[object] == -1) return;
2836: place[object] = -1;
2837: holdng++;
2838: }
2839: if (atloc[where] == object) {
2840: atloc[where] = rlink[object];
2841: return;
2842: }
2843: tmp = atloc[where];
2844: while (rlink[tmp] != object)
2845: tmp = rlink[tmp];
2846: rlink[tmp] = rlink[object];
2847: }
2848:
2849: /*
2850: * Place an object at a given loc, prefixing ot onto the atloc list.
2851: * Decrement holdng if the object was being toted.
2852: */
2853: drop (object, where)
2854: {
2855: if (object > 100)
2856: fixed[object-100] = where;
2857: else
2858: {
2859: if (place[object] == -1) holdng--;
2860: place[object] = where;
2861: }
2862: if (where <= 0) return;
2863: rlink[object] = atloc[where];
2864: atloc[where] = object;
2865: }
2866:
2867: fatal(s)
2868: char *s;
2869: {
2870: printf ("\nFatal error: %s\n", s);
2871: exit(1);
2872: }
2873:
2874: bug(n)
2875: {
2876: printf ("Bug number %d\n", n);
2877: printf ("Program quits\n");
2878: exit(1);
2879: }
2880:
2881: /* Returns a random number between 0 and num-1 inclusive */
2882: ran(num)
2883: {
2884: return (((long) num * rand()) / 32768L);
2885: }
2886:
2887: /*
2888: * return 1 if the five-character argument
2889: * is entirely blank, 0 otherwise
2890: */
2891: blankp(a5)
2892: char *a5;
2893: {
2894: return eqp (a5, " ");
2895: }
2896:
2897: /*
2898: * return 1 if a5 and b5 are equal, 0 otherwise.
2899: * The lengths of a5 and b5 are limited to 5,
2900: * but if either contains a null character, it is assumed
2901: * to be padded out to length 5 with blanks.
2902: */
2903: eqp(a5, b5)
2904: char *a5, *b5;
2905: {
2906: register int z;
2907: register char *aa, *bb;
2908: aa = a5;
2909: bb = b5;
2910: z = 5;
2911: do {
2912: if ((*aa == '\0'? ' ': *aa++) !=
2913: (*bb == '\0'? ' ': *bb++))
2914: return 0;
2915: } while (--z);
2916: return 1;
2917: }
2918:
2919: /*
2920: * copy the character string from "source" to "sink". Length is limited
2921: * to 5 characters, and "sink" is blank padded if "source" is shorter.
2922: */
2923: cpy (sink, source)
2924: register char *source, *sink;
2925: {
2926: register n;
2927: n = 5;
2928: do {
2929: if (*source == '\0')
2930: *sink++ = ' ';
2931: else
2932: *sink++ = *source++;
2933: } while (--n);
2934: }
2935:
2936: /*
2937: * Look up id in the vocabulary (atab) and return its "definition"
2938: * (ktab), or -1 if not found. If init is positive, this is an
2939: * initialization call setting up a keyword variable, and not finding
2940: * it constitutes a bug. It also means that only ktab values which taken
2941: * over 1000 equal init may be considered. Thus "steps", which is a
2942: * motion verb as well as an object, may be located as an object. It also
2943: * means the ktab value is taken mod 1000.
2944: */
2945: vocab (id, init)
2946: char *id;
2947: {
2948: for (i=1; i<=tabsiz; i++) {
2949: if (ktab[i] == -1) goto l2;
2950: if ((init < 0 || init == ktab[i]/1000) && eqp(atab[i], id))
2951: goto l3;
2952: }
2953: bug(21);
2954: l2:
2955: if (init < 0) return -1;
2956: bug(5);
2957: l3:
2958: return init<0? ktab[i]: ktab[i] % 1000;
2959: }
2960:
2961: /*
2962: * This program catenates the characters of x and y, which are assumed to
2963: * be 5-character fields, into z. The process stops at the first blank,
2964: * and a null character is appended to the result.
2965: */
2966: a5toa1 (x, y, z)
2967: char *x, *y, *z;
2968: {
2969: register int n;
2970: n = 5;
2971: do {
2972: if (*x == ' ') {
2973: *z++ = '\0';
2974: return;
2975: }
2976: *z++ = *x++;
2977: } while (--n);
2978: n = 5;
2979: do {
2980: if (*y == ' ') {
2981: *z++ = '\0';
2982: return;
2983: }
2984: *z++ = *y++;
2985: } while (--n);
2986: *z++ = '\0';
2987: }
2988:
2989: /*
2990: * Get a command from the terminal. The first word goes into pl and pr,
2991: * and the second word goes into ql and qr. In each case the word is
2992: * padded with blanks to 10 characters; the first 5 will be in the "l"
2993: * variable and the second 5 will be in the "r" variable.
2994: * If hungup is nonzero, indicating he hung up the phone, fudge
2995: * pl, pr, ql, and qr to make it look as if he typed "suspend".
2996: */
2997: getin (pl, pr, ql, qr)
2998: char *pl, *pr, *ql, *qr;
2999: {
3000: register int p;
3001: cpy (pl, "");
3002: cpy (pr, "");
3003: cpy (ql, "");
3004: cpy (qr, "");
3005: fflush(stdout);
3006: /* Eat blank lines */
3007: if (!hungup) {
3008: while ((p = getchar()) == '\n');
3009: while (p == '!') {
3010: char pl[512];
3011: if (fgets (pl, sizeof(pl), stdin) == 0)
3012: p = EOF;
3013: if (strcmp (pwbuf->pw_name, "games") == 0)
3014: printf ("No Shell escape from \"games\"\n");
3015: else {
3016: system (pl);
3017: printf ("!\n");
3018: fflush (stdout);
3019: }
3020: if (p != EOF)
3021: p = getchar();
3022: }
3023: if (p == EOF) {
3024: cpy (pl, "suspe");
3025: cpy (pr, "nd");
3026: hungup = 1;
3027: return;
3028: }
3029: ungetc (p, stdin);
3030: }
3031: if (snarf (pl, pr) && snarf (ql, qr))
3032: while (getchar() != '\n');
3033: }
3034:
3035: /*
3036: * This is a subroutine of getin
3037: */
3038: snarf (left, right)
3039: char *left, *right;
3040: {
3041: register int n;
3042: char s[10];
3043: register int p;
3044: /* Blank the array */
3045: for (n=0; n<10; n++)
3046: s[n] = ' ';
3047: /* If hung up phone, pretend he said 'suspend' followed by nl */
3048: if (hungup)
3049: goto susp;
3050: /* Skip leading blanks; if nl encountered, return immediately */
3051: while ((p=getchar()) == ' ');
3052: if (p == '\n') return 0;
3053: if (p == EOF) goto susp;
3054: /* Now eat characters until blank or newline */
3055: n = 0;
3056: do {
3057: if (n < 10)
3058: s[n++] = p;
3059: p = getchar();
3060: if (p == EOF) goto susp;
3061: } while (p != ' ' && p != '\n');
3062: /* Break up the string into two five-character components */
3063: cpy (left, s);
3064: cpy (right, s+5);
3065: /* Indicate to caller whether we hit a blank or newline */
3066: return p == ' ';
3067: /* Abnormal exit for EOF */
3068: susp:
3069: cpy (left, "suspe");
3070: cpy (right, "nd");
3071: hungup = 1;
3072: return 0;
3073: }
3074:
3075: /*
3076: * Print the n-th "random" message (section 6)
3077: */
3078: rspeak(n)
3079: {
3080: if (n != 0)
3081: speak (rtext[n]);
3082: }
3083:
3084: /*
3085: * Print the message which starts at lines[n]
3086: */
3087: speak(n)
3088: {
3089: long rec;
3090: do {
3091: rec = lines[n];
3092: if (rec < 0)
3093: rec = -rec;
3094: fseek (caves, rec, 0);
3095: fgets (linebuf, sizeof linebuf, caves);
3096: if (linebuf[0] != '>')
3097: fputs (linebuf, stdout);
3098: } while (++n < linuse && lines[n] >= 0);
3099: }
3100:
3101: /*
3102: * Find the skip+1st message from msg and print it. Msg should be
3103: * the index of the inventory message for object
3104: */
3105: pspeak (msg, skip)
3106: {
3107: int n, q;
3108: q = ptext[msg];
3109: if (skip >= 0)
3110: for (n=0; n<=skip; n++) {
3111: while (lines[++q] >= 0);
3112: }
3113: speak(q);
3114: }
3115:
3116: /*
3117: * Print message x, wait for yes/no. If yes, print message y and leave
3118: * "yea" true; else print message z and leave "yea" false.
3119: * If hungup is nonzero, he hung up the phone, so simulate an
3120: * answer of "no".
3121: */
3122: yes (x, y, z) {
3123: char reply[300];
3124: rspeak(x);
3125: fflush(stdout);
3126: if (scanf ("%s", reply) == EOF)
3127: hungup = 1;
3128: while (hungup == 0 && reply[0] != 'y' && reply[0] != 'n') {
3129: printf ("Please answer the question.\n");
3130: fflush(stdout);
3131: if (scanf ("%s", reply) == EOF)
3132: hungup = 1;
3133: }
3134: if (yea = (reply[0] == 'y' && hungup == 0)) {
3135: if (y != 0)
3136: rspeak(y);
3137: } else if (z != 0)
3138: rspeak (z);
3139: return yea;
3140: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.