Allow direct object to persist across turns.
[open-adventure.git] / main.c
1 /*
2  * There used to be a note that said this:
3  *
4  * The author - Don Woods - apologises for the style of the code; it
5  * is a result of running the original Fortran IV source through a
6  * home-brew Fortran-to-C converter.)
7  *
8  * Now that the code has been restructured into idiomatic C, the following
9  * is more appropriate:
10  *
11  * ESR apologizes for the remaing gotos (now confined to two functions in this
12  * file - they used to be *everywhere*), and the offensive globals.  Applying
13  * the Structured Program Theorem can be hard.
14  */
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <stdbool.h>
18 #include <getopt.h>
19 #include <signal.h>
20 #include <time.h>
21 #include "advent.h"
22 #include "database.h"
23 #include "linenoise/linenoise.h"
24 #include "newdb.h"
25
26 struct game_t game;
27
28 long LNLENG, LNPOSN, PARMS[MAXPARMS+1];
29 char rawbuf[LINESIZE], INLINE[LINESIZE+1];
30
31 long AMBER, AXE, BACK, BATTER, BEAR, BIRD, BLOOD,
32                 BOTTLE, CAGE, CAVE, CAVITY, CHAIN, CHASM, CHEST,
33                 CLAM, COINS, DOOR, DPRSSN, DRAGON, DWARF, EGGS,
34                 EMRALD, ENTER, ENTRNC, FIND, FISSUR, FOOD,
35                 GRATE, HINT, INVENT, JADE, KEYS,
36                 KNIFE, LAMP, LOCK, LOOK, MAGZIN,
37                 MESSAG, MIRROR, NUGGET, NUL, OGRE, OIL, OYSTER,
38                 PEARL, PILLOW, PLANT, PLANT2, PYRAM, RESER, ROD, ROD2,
39                 RUBY, RUG, SAPPH, SAY, SIGN, SNAKE,
40                 STEPS, STREAM, THROW, TRIDNT, TROLL, TROLL2,
41                 URN, VASE, VEND, VOLCAN, WATER;
42 long WD1, WD1X, WD2, WD2X;
43
44 static int K;   /* information leak, should go away */
45
46 FILE  *logfp;
47 bool oldstyle = false;
48 lcg_state lcgstate;
49
50 extern void initialise();
51 extern void score(long);
52 extern int action(FILE *, long, long, long);
53
54 void sig_handler(int signo)
55 {
56     if (signo == SIGINT)
57         if (logfp != NULL)
58             fflush(logfp);
59     exit(0);
60 }
61
62 /*
63  * MAIN PROGRAM
64  *
65  *  Adventure (rev 2: 20 treasures)
66  *
67  *  History: Original idea & 5-treasure version (adventures) by Willie Crowther
68  *           15-treasure version (adventure) by Don Woods, April-June 1977
69  *           20-treasure version (rev 2) by Don Woods, August 1978
70  *              Errata fixed: 78/12/25
71  *           Revived 2017 as Open Advebture.
72  */
73
74 static bool do_command(FILE *);
75
76 int main(int argc, char *argv[])
77 {
78     int ch;
79         
80 /*  Options. */
81
82     while ((ch = getopt(argc, argv, "l:o")) != EOF) {
83         switch (ch) {
84 case 'l':
85             logfp = fopen(optarg, "w");
86             if (logfp == NULL)
87                 fprintf(stderr,
88                         "advent: can't open logfile %s for write\n",
89                         optarg);
90             signal(SIGINT, sig_handler);
91             break;
92         case 'o':
93             oldstyle = true;
94             break;
95         }
96     }
97
98     linenoiseHistorySetMaxLen(350);
99
100     /* Logical variables:
101      *
102      *  game.closed says whether we're all the way closed
103      *  game.closng says whether it's closing time yet
104      *  game.clshnt says whether he's read the clue in the endgame
105      *  game.lmwarn says whether he's been warned about lamp going dim
106      *  game.novice says whether he asked for instructions at start-up
107      *  game.panic says whether he's found out he's trapped in the cave
108      *  game.wzdark says whether the loc he's leaving was dark */
109
110     /* Initialize our LCG PRNG with parameters tested against
111      * Knuth vol. 2. by the original authors */
112     lcgstate.a = 1093;
113     lcgstate.c = 221587;
114     lcgstate.m = 1048576;
115     srand(time(NULL));
116     long seedval = (long)rand();
117     set_seed(seedval);
118
119     /*  Initialize game variables */
120     if (!game.setup)
121         initialise();
122
123     /*  Unlike earlier versions, adventure is no longer restartable.  (This
124      *  lets us get away with modifying things such as OBJSND(BIRD) without
125      *  having to be able to undo the changes later.)  If a "used" copy is
126      *  rerun, we come here and tell the player to run a fresh copy. */
127     if (game.setup <= 0) {
128         RSPEAK(201);
129         exit(0);
130     }
131
132     /*  Start-up, dwarf stuff */
133     game.setup= -1;
134     game.zzword=RNDVOC(3,0);
135     game.novice=YES(stdin, 65,1,0);
136     game.newloc=1;
137     game.loc=1;
138     game.limit=330;
139     if (game.novice)game.limit=1000;
140
141     if (logfp)
142         fprintf(logfp, "seed %ld\n", seedval);
143
144     /* interpret commands ubtil EOF or interrupt */
145     for (;;) {
146         if (!do_command(stdin))
147             break;
148     }
149     /* show score and exit */
150     score(1);
151 }
152
153 static bool fallback_handler(char *buf)
154 /* fallback handler for commands not handled by FORTRANish parser */
155 {
156     long sv;
157     if (sscanf(buf, "seed %ld", &sv) == 1) {
158         set_seed(sv);
159         printf("Seed set to %ld\n", sv);
160         // autogenerated, so don't charge user time for it.
161         --game.turns;
162         // here we reconfigure any global game state that uses random numbers
163         game.zzword=RNDVOC(3,0);
164         return true;
165     }
166     return false;
167 }
168
169 static void dohint(FILE *cmdin, int hint)
170 /*  Come here if he's been long enough at required loc(s) for some
171  *  unused hint. */
172 {
173     int i;
174
175     switch (hint-1)
176     {
177     case 0:
178         /* cave */
179         if (game.prop[GRATE] == 0 && !HERE(KEYS))
180             break;
181         game.hintlc[hint]=0;
182         return;
183     case 1:     /* bird */
184         if (game.place[BIRD] == game.loc && TOTING(ROD) && game.oldobj == BIRD)
185             break;
186         return;
187     case 2:     /* snake */
188         if (HERE(SNAKE) && !HERE(BIRD))
189             break;
190         game.hintlc[hint]=0;
191         return;
192     case 3:     /* maze */
193         if (game.atloc[game.loc] == 0 &&
194            game.atloc[game.oldloc] == 0 &&
195            game.atloc[game.oldlc2] == 0 &&
196            game.holdng > 1)
197             break;
198         game.hintlc[hint]=0;
199         return;
200     case 4:     /* dark */
201         if (game.prop[EMRALD] != -1 && game.prop[PYRAM] == -1)
202             break;
203         game.hintlc[hint]=0;
204         return;
205     case 5:     /* witt */
206         break;
207     case 6:     /* urn */
208         if (game.dflag == 0)
209             break;
210         game.hintlc[hint]=0;
211         return;
212     case 7:     /* woods */
213         if (game.atloc[game.loc] == 0 &&
214                    game.atloc[game.oldloc] == 0 &&
215                    game.atloc[game.oldlc2] == 0)
216                 break;
217         return;
218     case 8:     /* ogre */
219         i=ATDWRF(game.loc);
220         if (i < 0) {
221             game.hintlc[hint]=0;
222             return;
223             }
224         if (HERE(OGRE) && i == 0)
225             break;
226         return;
227     case 9:     /* jade */
228         if (game.tally == 1 && game.prop[JADE] < 0)
229             break;
230         game.hintlc[hint]=0;
231         return;
232     default:
233         BUG(27);
234         break;
235     }
236     
237     /* Fall through to hint display */
238     game.hintlc[hint]=0;
239     if (!YES(cmdin,HINTS[hint][3],0,54))
240         return;
241     SETPRM(1,HINTS[hint][2],HINTS[hint][2]);
242     RSPEAK(261);
243     game.hinted[hint]=YES(cmdin,175,HINTS[hint][4],54);
244     if (game.hinted[hint] && game.limit > 30)
245         game.limit=game.limit+30*HINTS[hint][2];
246 }
247
248 static bool dwarfmove(void)
249 /* Dwarves move.  Return true if player survives, false if he dies. */
250 {
251     int kk, stick, attack;
252     long TK[21];
253
254         /*  Dwarf stuff.  See earlier comments for description of
255      *  variables.  Remember sixth dwarf is pirate and is thus
256      *  very different except for motion rules. */
257
258     /*  First off, don't let the dwarves follow him into a pit or
259      *  a wall.  Activate the whole mess the first time he gets as
260      *  far as the hall of mists (loc 15).  If game.newloc is
261      *  forbidden to pirate (in particular, if it's beyond the
262      *  troll bridge), bypass dwarf stuff.  That way pirate can't
263      *  steal return toll, and dwarves can't meet the bear.  Also
264      *  means dwarves won't follow him into dead end in maze, but
265      *  c'est la vie.  They'll wait for him outside the dead
266      *  end. */
267     if (game.loc == 0 || FORCED(game.loc) || CNDBIT(game.newloc,3))
268         return true;
269
270     /* Dwarf activity level ratchets up */
271     if (game.dflag == 0) {
272         if (INDEEP(game.loc))
273             game.dflag=1;
274         return true;
275     }
276
277     /*  When we encounter the first dwarf, we kill 0, 1, or 2 of
278      *  the 5 dwarves.  If any of the survivors is at loc,
279      *  replace him with the alternate. */
280     if (game.dflag == 1) {
281         if (!INDEEP(game.loc) || (PCT(95) && (!CNDBIT(game.loc,4) || PCT(85))))
282             return true;
283         game.dflag=2;
284         for (int i=1; i<=2; i++) {
285             int j=1+randrange(NDWARVES-1);
286             if (PCT(50))
287                 game.dloc[j]=0;
288         }
289         for (int i=1; i<=NDWARVES-1; i++) {
290             if (game.dloc[i] == game.loc)
291                 game.dloc[i]=DALTLC;
292             game.odloc[i]=game.dloc[i];
293         }
294         RSPEAK(3);
295         DROP(AXE,game.loc);
296         return true;
297     }
298
299     /*  Things are in full swing.  Move each dwarf at random,
300      *  except if he's seen us he sticks with us.  Dwarves stay
301      *  deep inside.  If wandering at random, they don't back up
302      *  unless there's no alternative.  If they don't have to
303      *  move, they attack.  And, of course, dead dwarves don't do
304      *  much of anything. */
305     game.dtotal=0;
306     attack=0;
307     stick=0;
308     for (int i=1; i<=NDWARVES; i++) {
309         int k;
310         if (game.dloc[i] == 0)
311             continue;
312         /*  Fill TK array with all the places this dwarf might go. */
313         int j=1;
314         kk=KEY[game.dloc[i]];
315         if (kk != 0)
316             do {
317                 game.newloc=MOD(labs(TRAVEL[kk])/1000,1000);
318                 /* Have we avoided a dwarf enciounter? */
319                 bool avoided = (game.newloc > 300 ||
320                                 !INDEEP(game.newloc) ||
321                                 game.newloc == game.odloc[i] ||
322                                 (j > 1 && game.newloc == TK[j-1]) ||
323                                 j >= 20 ||
324                                 game.newloc == game.dloc[i] ||
325                                 FORCED(game.newloc) ||
326                                 (i == PIRATE && CNDBIT(game.newloc,3)) ||
327                                 labs(TRAVEL[kk])/1000000 == 100);
328                 if (!avoided) {
329                     TK[j++] = game.newloc;
330                 }
331                 ++kk;
332             } while
333                 (TRAVEL[kk-1] >= 0);
334         TK[j]=game.odloc[i];
335         if (j >= 2)
336             --j;
337         j=1+randrange(j);
338         game.odloc[i]=game.dloc[i];
339         game.dloc[i]=TK[j];
340         game.dseen[i]=(game.dseen[i] && INDEEP(game.loc)) || (game.dloc[i] == game.loc || game.odloc[i] == game.loc);
341         if (!game.dseen[i]) continue;
342         game.dloc[i]=game.loc;
343         if (i == PIRATE) {
344             /*  The pirate's spotted him.  He leaves him alone once we've
345              *  found chest.  K counts if a treasure is here.  If not, and
346              *  tally=1 for an unseen chest, let the pirate be spotted.
347              *  Note that game.place(CHEST)=0 might mean that he's thrown
348              *  it to the troll, but in that case he's seen the chest
349              *  (game.prop=0). */
350             if (game.loc == game.chloc || game.prop[CHEST] >= 0)
351                 continue;
352             k=0;
353             for (int j=MINTRS; j<=MAXTRS; j++) {
354                 /*  Pirate won't take pyramid from plover room or dark
355                  *  room (too easy!). */
356                 if (j == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD])) {
357                     if (HERE(j))
358                         k=1;
359                     continue;
360                 }
361                 if (TOTING(j)) {
362                     if (game.place[CHEST] == 0) {
363                         /*  Install chest only once, to insure it is
364                          *  the last treasure in the list. */
365                         MOVE(CHEST,game.chloc);
366                         MOVE(MESSAG,game.chloc2);
367                     }
368                     RSPEAK(128);
369                     for (int j=MINTRS; j<=MAXTRS; j++) {
370                         if (!(j == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD]))) {
371                             if (AT(j) && game.fixed[j] == 0)
372                                 CARRY(j,game.loc);
373                             if (TOTING(j))
374                                 DROP(j,game.chloc);
375                         }
376                     }
377                     game.dloc[PIRATE]=game.chloc;
378                     game.odloc[PIRATE]=game.chloc;
379                     game.dseen[PIRATE]=false;
380                     goto jumpout;
381                 }
382                 if (HERE(j))
383                     k=1;
384             }
385             /* Force chest placement before player finds last treasure */
386             if (game.tally == 1 && k == 0 && game.place[CHEST] == 0 && HERE(LAMP) && game.prop[LAMP] == 1) {
387                 RSPEAK(186);
388                 MOVE(CHEST,game.chloc);
389                 MOVE(MESSAG,game.chloc2);
390                 game.dloc[PIRATE]=game.chloc;
391                 game.odloc[PIRATE]=game.chloc;
392                 game.dseen[PIRATE]=false;
393                 continue;
394             }
395             if (game.odloc[PIRATE] != game.dloc[PIRATE] && PCT(20))
396                 RSPEAK(127);
397             continue;
398         }
399
400         /* This threatening little dwarf is in the room with him! */
401         ++game.dtotal;
402         if (game.odloc[i] == game.dloc[i]) {
403             ++attack;
404             if (game.knfloc >= 0)
405                 game.knfloc=game.loc;
406             if (randrange(1000) < 95*(game.dflag-2))
407                 ++stick;
408         }
409     jumpout:;
410     }
411
412     /*  Now we know what's happening.  Let's tell the poor sucker about it.
413      *  Note that various of the "knife" messages must have specific relative
414      *  positions in the RSPEAK database. */
415     if (game.dtotal == 0)
416         return true;
417     SETPRM(1,game.dtotal,0);
418     RSPEAK(4+1/game.dtotal);
419     if (attack == 0)
420         return true;
421     if (game.dflag == 2)game.dflag=3;
422     SETPRM(1,attack,0);
423     int k=6;
424     if (attack > 1)k=250;
425     RSPEAK(k);
426     SETPRM(1,stick,0);
427     RSPEAK(k+1+2/(1+stick));
428     if (stick == 0)
429         return true;
430     game.oldlc2=game.loc;
431     return false;
432 }
433
434 /*  "You're dead, Jim."
435  *
436  *  If the current loc is zero, it means the clown got himself killed.
437  *  We'll allow this maxdie times.  MAXDIE is automatically set based
438  *  on the number of snide messages available.  Each death results in
439  *  a message (81, 83, etc.)  which offers reincarnation; if accepted,
440  *  this results in message 82, 84, etc.  The last time, if he wants
441  *  another chance, he gets a snide remark as we exit.  When
442  *  reincarnated, all objects being carried get dropped at game.oldlc2
443  *  (presumably the last place prior to being killed) without change
444  *  of props.  the loop runs backwards to assure that the bird is
445  *  dropped before the cage.  (this kluge could be changed once we're
446  *  sure all references to bird and cage are done by keywords.)  The
447  *  lamp is a special case (it wouldn't do to leave it in the cave).
448  *  It is turned off and left outside the building (only if he was
449  *  carrying it, of course).  He himself is left inside the building
450  *  (and heaven help him if he tries to xyzzy back into the cave
451  *  without the lamp!).  game.oldloc is zapped so he can't just
452  *  "retreat". */
453
454 static void croak(FILE *cmdin)
455 /*  Okay, he's dead.  Let's get on with it. */
456 {
457     if (game.closng) {
458         /*  He died during closing time.  No resurrection.  Tally up a
459          *  death and exit. */
460         RSPEAK(131);
461         ++game.numdie;
462         score(0);
463     } else {
464         ++game.numdie;
465         if (!YES(cmdin,79+game.numdie*2,80+game.numdie*2,54))
466             score(0);
467         if (game.numdie == MAXDIE)
468             score(0);
469         game.place[WATER]=0;
470         game.place[OIL]=0;
471         if (TOTING(LAMP))
472             game.prop[LAMP]=0;
473         for (int j=1; j<=NOBJECTS; j++) {
474             int i=NOBJECTS + 1 - j;
475             if (TOTING(i)) {
476                 int k=game.oldlc2;
477                 if (i == LAMP)
478                     k=1;
479                 DROP(i,k);
480             }
481         }
482         game.loc=3;
483         game.oldloc=game.loc;
484     }
485 }
486
487 /*  Given the current location in "game.loc", and a motion verb number in
488  *  "K", put the new location in "game.newloc".  The current loc is saved
489  *  in "game.oldloc" in case he wants to retreat.  The current
490  *  game.oldloc is saved in game.oldlc2, in case he dies.  (if he
491  *  does, game.newloc will be limbo, and game.oldloc will be what killed
492  *  him, so we need game.oldlc2, which is the last place he was
493  *  safe.) */
494
495 static bool playermove(FILE *cmdin, token_t verb, int motion)
496 {
497     int LL, K2, KK=KEY[game.loc];
498     game.newloc=game.loc;
499     if (KK == 0)
500         BUG(26);
501     if (motion == NUL)
502         return true;
503     else if (motion == BACK) {
504         /*  Handle "go back".  Look for verb which goes from game.loc to
505          *  game.oldloc, or to game.oldlc2 If game.oldloc has forced-motion.
506          *  K2 saves entry -> forced loc -> previous loc. */
507         motion=game.oldloc;
508         if (FORCED(motion))
509             motion=game.oldlc2;
510         game.oldlc2=game.oldloc;
511         game.oldloc=game.loc;
512         K2=0;
513         if (motion == game.loc)K2=91;
514         if (CNDBIT(game.loc,4))K2=274;
515         if (K2 == 0) {
516             for (;;) {
517                 LL=MOD((labs(TRAVEL[KK])/1000),1000);
518                 if (LL != motion) {
519                     if (LL <= 300) {
520                         if (FORCED(LL) && MOD((labs(TRAVEL[KEY[LL]])/1000),1000) == motion)
521                             K2=KK;
522                     }
523                     if (TRAVEL[KK] >= 0) {
524                         ++KK;
525                         continue;
526                     }
527                     KK=K2;
528                     if (KK == 0) {
529                         RSPEAK(140);
530                         return true;
531                     }
532                 }
533
534                 motion=MOD(labs(TRAVEL[KK]),1000);
535                 KK=KEY[game.loc];
536                 break; /* fall through to ordinary travel */
537             }
538         } else {
539             RSPEAK(K2);
540             return true;
541         }
542     }
543     else if (motion == LOOK) {
544         /*  Look.  Can't give more detail.  Pretend it wasn't dark
545          *  (though it may "now" be dark) so he won't fall into a
546          *  pit while staring into the gloom. */
547         if (game.detail < 3)RSPEAK(15);
548         ++game.detail;
549         game.wzdark=false;
550         game.abbrev[game.loc]=0;
551         return true;
552     }
553     else if (motion == CAVE) {
554         /*  Cave.  Different messages depending on whether above ground. */
555         RSPEAK((OUTSID(game.loc) && game.loc != 8) ? 57 : 58);
556         return true;
557     }
558     else {
559         /* none of the specials */
560         game.oldlc2=game.oldloc;
561         game.oldloc=game.loc;
562     }
563
564     /* ordinary travel */
565     for (;;) {
566         LL=labs(TRAVEL[KK]);
567         if (MOD(LL,1000) == 1 || MOD(LL,1000) == motion)
568             break;
569         if (TRAVEL[KK] < 0) {
570             /*  Non-applicable motion.  Various messages depending on
571              *  word given. */
572             int spk=12;
573             if (motion >= 43 && motion <= 50)spk=52;
574             if (motion == 29 || motion == 30)spk=52;
575             if (motion == 7 || motion == 36 || motion == 37)spk=10;
576             if (motion == 11 || motion == 19)spk=11;
577             if (verb == FIND || verb == INVENT)spk=59;
578             if (motion == 62 || motion == 65)spk=42;
579             if (motion == 17)spk=80;
580             RSPEAK(spk);
581             return true;
582         }
583         ++KK;
584     }
585     LL=LL/1000;
586
587     for (;;) {
588         game.newloc=LL/1000;
589         motion=MOD(game.newloc,100);
590         if (game.newloc <= 300) {
591             if (game.newloc <= 100) {
592                 if (game.newloc == 0 || PCT(game.newloc))
593                     break;
594                 /* else fall through */
595             } if (TOTING(motion) || (game.newloc > 200 && AT(motion)))
596                   break;
597             /* else fall through */
598         }
599         else if (game.prop[motion] != game.newloc/100-3)
600             break;
601     L12:
602         do {
603             if (TRAVEL[KK] < 0)BUG(25);
604             ++KK;
605             game.newloc=labs(TRAVEL[KK])/1000;
606         } while
607             (game.newloc == LL);
608         LL=game.newloc;
609     }
610
611     game.newloc=MOD(LL,1000);
612     if (game.newloc <= 300)
613         return true;
614     if (game.newloc <= 500) {
615         game.newloc=game.newloc-300;
616         switch (game.newloc)
617         {
618         case 1:
619             /*  Travel 301.  Plover-alcove passage.  Can carry only
620              *  emerald.  Note: travel table must include "useless"
621              *  entries going through passage, which can never be used for
622              *  actual motion, but can be spotted by "go back". */
623             game.newloc=99+100-game.loc;
624             if (game.holdng == 0 || (game.holdng == 1 && TOTING(EMRALD)))
625                 return true;
626             game.newloc=game.loc;
627             RSPEAK(117);
628             return true;
629         case 2:
630             /*  Travel 302.  Plover transport.  Drop the emerald (only use
631              *  special travel if toting it), so he's forced to use the
632              *  plover-passage to get it out.  Having dropped it, go back and
633              *  pretend he wasn't carrying it after all. */
634             DROP(EMRALD,game.loc);
635             goto L12;
636         case 3:
637             /*  Travel 303.  Troll bridge.  Must be done only as special
638              *  motion so that dwarves won't wander across and encounter
639              *  the bear.  (They won't follow the player there because
640              *  that region is forbidden to the pirate.)  If
641              *  game.prop(TROLL)=1, he's crossed since paying, so step out
642              *  and block him.  (standard travel entries check for
643              *  game.prop(TROLL)=0.)  Special stuff for bear. */
644             if (game.prop[TROLL] == 1) {
645                 PSPEAK(TROLL,1);
646                 game.prop[TROLL]=0;
647                 MOVE(TROLL2,0);
648                 MOVE(TROLL2+NOBJECTS,0);
649                 MOVE(TROLL,PLAC[TROLL]);
650                 MOVE(TROLL+NOBJECTS,FIXD[TROLL]);
651                 JUGGLE(CHASM);
652                 game.newloc=game.loc;
653                 return true;
654             } else {
655                 game.newloc=PLAC[TROLL]+FIXD[TROLL]-game.loc;
656                 if (game.prop[TROLL] == 0)game.prop[TROLL]=1;
657                 if (!TOTING(BEAR)) return true;
658                 RSPEAK(162);
659                 game.prop[CHASM]=1;
660                 game.prop[TROLL]=2;
661                 DROP(BEAR,game.newloc);
662                 game.fixed[BEAR]= -1;
663                 game.prop[BEAR]=3;
664                 game.oldlc2=game.newloc;
665                 croak(cmdin);
666                 return false;
667             }
668         }
669         BUG(20);
670     }
671     RSPEAK(game.newloc-500);
672     game.newloc=game.loc;
673     return true;
674 }
675
676 static bool do_command(FILE *cmdin)
677 {
678         long KQ, VERB, KK, V1, V2;
679         long i;
680         static long igo = 0;
681         static long obj = 0;
682         enum speechpart part;
683
684         /*  Can't leave cave once it's closing (except by main office). */
685         if (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
686             RSPEAK(130);
687             game.newloc=game.loc;
688             if (!game.panic)game.clock2=15;
689             game.panic=true;
690         }
691
692         /*  See if a dwarf has seen him and has come from where he
693          *  wants to go.  If so, the dwarf's blocking his way.  If
694          *  coming from place forbidden to pirate (dwarves rooted in
695          *  place) let him get out (and attacked). */
696         if (game.newloc != game.loc && !FORCED(game.loc) && !CNDBIT(game.loc,3)) {
697                 for (i=1; i<=NDWARVES-1; i++) {
698                     if (game.odloc[i] == game.newloc && game.dseen[i]) {
699                         game.newloc=game.loc;
700                         RSPEAK(2);
701                         break;
702                     }
703                 }
704         }
705         game.loc=game.newloc;
706
707         if (!dwarfmove())
708             croak(cmdin);
709
710        /*  Describe the current location and (maybe) get next command. */
711
712        /*  Print text for current loc. */
713
714 L2000:  if (game.loc == 0)
715             croak(cmdin);
716         char* msg = short_location_descriptions[game.loc];
717         if (MOD(game.abbrev[game.loc],game.abbnum) == 0 || msg == 0)
718             msg=long_location_descriptions[game.loc];
719         if (!FORCED(game.loc) && DARK(game.loc)) {
720             /*  The easiest way to get killed is to fall into a pit in
721              *  pitch darkness. */
722             if (game.wzdark && PCT(35)) {
723                 RSPEAK(23);
724                 game.oldlc2 = game.loc;
725                 croak(cmdin);
726                 goto L2000;
727             }
728             msg=arbitrary_messages[16];
729         }
730         if (TOTING(BEAR))RSPEAK(141);
731         newspeak(msg);
732         K=1;
733         if (FORCED(game.loc)) {
734             goto L8;
735         }
736         if (game.loc == 33 && PCT(25) && !game.closng)RSPEAK(7);
737
738         /*  Print out descriptions of objects at this location.  If
739          *  not closing and property value is negative, tally off
740          *  another treasure.  Rug is special case; once seen, its
741          *  game.prop is 1 (dragon on it) till dragon is killed.
742          *  Similarly for chain; game.prop is initially 1 (locked to
743          *  bear).  These hacks are because game.prop=0 is needed to
744          *  get full score. */
745
746         if (DARK(game.loc)) goto L2012;
747         ++game.abbrev[game.loc];
748         i=game.atloc[game.loc];
749 L2004:  if (i == 0) goto L2012;
750         obj=i;
751         if (obj > NOBJECTS)obj=obj-NOBJECTS;
752         if (obj == STEPS && TOTING(NUGGET)) goto L2008;
753         if (game.prop[obj] >= 0) goto L2006;
754         if (game.closed) goto L2008;
755         game.prop[obj]=0;
756         if (obj == RUG || obj == CHAIN)game.prop[obj]=1;
757         --game.tally;
758 /*  Note: There used to be a test here to see whether the player had blown it
759  *  so badly that he could never ever see the remaining treasures, and if so
760  *  the lamp was zapped to 35 turns.  But the tests were too simple-minded;
761  *  things like killing the bird before the snake was gone (can never see
762  *  jewelry), and doing it "right" was hopeless.  E.G., could cross troll
763  *  bridge several times, using up all available treasures, breaking vase,
764  *  using coins to buy batteries, etc., and eventually never be able to get
765  *  across again.  If bottle were left on far side, could then never get eggs
766  *  or trident, and the effects propagate.  So the whole thing was flushed.
767  *  anyone who makes such a gross blunder isn't likely to find everything
768  *  else anyway (so goes the rationalisation). */
769 L2006:  KK=game.prop[obj];
770         if (obj == STEPS && game.loc == game.fixed[STEPS])KK=1;
771         PSPEAK(obj,KK);
772 L2008:  i=game.link[i];
773          goto L2004;
774
775 L2012:  VERB=0;
776         game.oldobj=obj;
777         obj=0;
778
779 /*  Check if this loc is eligible for any hints.  If been here long enough,
780  *  branch to help section (on later page).  Hints all come back here eventually
781  *  to finish the loop.  Ignore "HINTS" < 4 (special stuff, see database notes).
782  */
783 L2600:  if (COND[game.loc] >= game.conds) {
784             for (int hint=1; hint<=HNTMAX; hint++) {
785                 if (game.hinted[hint])
786                     continue;
787                 if (!CNDBIT(game.loc,hint+10))
788                     game.hintlc[hint]= -1;
789                 ++game.hintlc[hint];
790                 if (game.hintlc[hint] >= HINTS[hint][1]) 
791                     dohint(cmdin, hint);
792             }
793         }
794             
795         /*  If closing time, check for any objects being toted with
796          *  game.prop < 0 and set the prop to -1-game.prop.  This way
797          *  objects won't be described until they've been picked up
798          *  and put down separate from their respective piles.  Don't
799          *  tick game.clock1 unless well into cave (and not at Y2). */
800         if (game.closed) {
801             if (game.prop[OYSTER] < 0 && TOTING(OYSTER))
802                 PSPEAK(OYSTER,1);
803             for (i=1; i<=NOBJECTS; i++) {
804                 if (TOTING(i) && game.prop[i] < 0)
805                     game.prop[i] = -1-game.prop[i];
806             }
807         }
808         game.wzdark=DARK(game.loc);
809         if (game.knfloc > 0 && game.knfloc != game.loc)
810             game.knfloc=0;
811
812         /* This is where we get a new command from the user */
813         if (!GETIN(cmdin, &WD1,&WD1X,&WD2,&WD2X))
814             return false;
815
816         /*  Every input, check "game.foobar" flag.  If zero, nothing's
817          *  going on.  If pos, make neg.  If neg, he skipped a word,
818          *  so make it zero. */
819 L2607:  game.foobar=(game.foobar>0 ? -game.foobar : 0);
820         ++game.turns;
821         if (game.turns == game.thresh) {
822         newspeak(turn_threshold_messages[game.trndex]);
823         game.trnluz=game.trnluz+TRNVAL[game.trndex]/100000;
824         ++game.trndex;
825         game.thresh = -1;
826         if (game.trndex <= TRNVLS)
827             game.thresh=MOD(TRNVAL[game.trndex],100000)+1;
828         }
829         if (VERB == SAY && WD2 > 0)VERB=0;
830         if (VERB == SAY) goto L4090;
831         if (game.tally == 0 && INDEEP(game.loc) && game.loc != 33)
832             --game.clock1;
833
834         /*  Next few sections handle the closing of the cave.  The
835          *  cave closes "clock1" turns after the last treasure has
836          *  been located (including the pirate's chest, which may of
837          *  course never show up).  Note that the treasures need not
838          *  have been taken yet, just located.  Hence clock1 must be
839          *  large enough to get out of the cave (it only ticks while
840          *  inside the cave).  When it hits zero, we branch to 10000
841          *  to start closing the cave, and then sit back and wait for
842          *  him to try to get out.  If he doesn't within clock2 turns,
843          *  we close the cave; if he does try, we assume he panics,
844          *  and give him a few additional turns to get frantic before
845          *  we close.  When clock2 hits zero, we branch to 11000 to
846          *  transport him into the final puzzle.  Note that the puzzle
847          *  depends upon all sorts of random things.  For instance,
848          *  there must be no water or oil, since there are beanstalks
849          *  which we don't want to be able to water, since the code
850          *  can't handle it.  Also, we can have no keys, since there
851          *  is a grate (having moved the fixed object!) there
852          *  separating him from all the treasures.  Most of these
853          *  problems arise from the use of negative prop numbers to
854          *  suppress the object descriptions until he's actually moved
855          *  the objects. */
856
857         /*  When the first warning comes, we lock the grate, destroy
858          *  the bridge, kill all the dwarves (and the pirate), remove
859          *  the troll and bear (unless dead), and set "closng" to
860          *  true.  Leave the dragon; too much trouble to move it.
861          *  from now until clock2 runs out, he cannot unlock the
862          *  grate, move to any location outside the cave, or create
863          *  the bridge.  Nor can he be resurrected if he dies.  Note
864          *  that the snake is already gone, since he got to the
865          *  treasure accessible only via the hall of the mountain
866          *  king. Also, he's been in giant room (to get eggs), so we
867          *  can refer to it.  Also also, he's gotten the pearl, so we
868          *  know the bivalve is an oyster.  *And*, the dwarves must
869          *  have been activated, since we've found chest. */
870         if (game.clock1 == 0)
871         {
872             game.prop[GRATE]=0;
873             game.prop[FISSUR]=0;
874             for (i=1; i<=NDWARVES; i++) {
875                 game.dseen[i]=false;
876                 game.dloc[i]=0;
877             }
878             MOVE(TROLL,0);
879             MOVE(TROLL+NOBJECTS,0);
880             MOVE(TROLL2,PLAC[TROLL]);
881             MOVE(TROLL2+NOBJECTS,FIXD[TROLL]);
882             JUGGLE(CHASM);
883             if (game.prop[BEAR] != 3)DSTROY(BEAR);
884             game.prop[CHAIN]=0;
885             game.fixed[CHAIN]=0;
886             game.prop[AXE]=0;
887             game.fixed[AXE]=0;
888             RSPEAK(129);
889             game.clock1= -1;
890             game.closng=true;
891             goto L19999;
892         } else if (game.clock1 < 0)
893             --game.clock2;
894         if (game.clock2 == 0) {
895             /*  Once he's panicked, and clock2 has run out, we come here
896              *  to set up the storage room.  The room has two locs,
897              *  hardwired as 115 (ne) and 116 (sw).  At the ne end, we
898              *  place empty bottles, a nursery of plants, a bed of
899              *  oysters, a pile of lamps, rods with stars, sleeping
900              *  dwarves, and him.  At the sw end we place grate over
901              *  treasures, snake pit, covey of caged birds, more rods, and
902              *  pillows.  A mirror stretches across one wall.  Many of the
903              *  objects come from known locations and/or states (e.g. the
904              *  snake is known to have been destroyed and needn't be
905              *  carried away from its old "place"), making the various
906              *  objects be handled differently.  We also drop all other
907              *  objects he might be carrying (lest he have some which
908              *  could cause trouble, such as the keys).  We describe the
909              *  flash of light and trundle back. */
910             game.prop[BOTTLE]=PUT(BOTTLE,115,1);
911             game.prop[PLANT]=PUT(PLANT,115,0);
912             game.prop[OYSTER]=PUT(OYSTER,115,0);
913             OBJTXT[OYSTER]=3;
914             game.prop[LAMP]=PUT(LAMP,115,0);
915             game.prop[ROD]=PUT(ROD,115,0);
916             game.prop[DWARF]=PUT(DWARF,115,0);
917             game.loc=115;
918             game.oldloc=115;
919             game.newloc=115;
920             /*  Leave the grate with normal (non-negative) property.
921              *  Reuse sign. */
922             PUT(GRATE,116,0);
923             PUT(SIGN,116,0);
924             ++OBJTXT[SIGN];
925             game.prop[SNAKE]=PUT(SNAKE,116,1);
926             game.prop[BIRD]=PUT(BIRD,116,1);
927             game.prop[CAGE]=PUT(CAGE,116,0);
928             game.prop[ROD2]=PUT(ROD2,116,0);
929             game.prop[PILLOW]=PUT(PILLOW,116,0);
930
931             game.prop[MIRROR]=PUT(MIRROR,115,0);
932             game.fixed[MIRROR]=116;
933
934             for (int i=1; i<=NOBJECTS; i++) {
935                 if (TOTING(i))
936                     DSTROY(i);
937             }
938
939             RSPEAK(132);
940             game.closed=true;
941             return true;
942         }
943         if (game.prop[LAMP] == 1)
944             --game.limit;
945
946         /*  Another way we can force an end to things is by having the
947          *  lamp give out.  When it gets close, we come here to warn
948          *  him.  First following ar, if the lamp and fresh batteries are
949          *  here, in which case we replace the batteries and continue.
950          *  Second is for other cases of lamp dying.  12400 is when it
951          *  goes out.  Even then, he can explore outside for a while
952          *  if desired. */
953         if (game.limit<=30 && HERE(BATTER) && game.prop[BATTER]==0 && HERE(LAMP))
954         {
955             RSPEAK(188);
956             game.prop[BATTER]=1;
957             if (TOTING(BATTER))DROP(BATTER,game.loc);
958             game.limit=game.limit+2500;
959             game.lmwarn=false;
960         } else if (game.limit == 0) {
961             game.limit= -1;
962             game.prop[LAMP]=0;
963             if (HERE(LAMP))RSPEAK(184);
964         } else if (game.limit <= 30) {
965             if (!game.lmwarn && HERE(LAMP)) {
966                 game.lmwarn=true;
967                 int spk=187;
968                 if (game.place[BATTER] == 0)spk=183;
969                 if (game.prop[BATTER] == 1)spk=189;
970                 RSPEAK(spk);
971             }
972         }
973 L19999: K=43;
974         if (LIQLOC(game.loc) == WATER)K=70;
975         V1=VOCAB(WD1,-1);
976         V2=VOCAB(WD2,-1);
977         if (V1 == ENTER && (V2 == STREAM || V2 == 1000+WATER)) {
978             RSPEAK(K);
979             goto L2012;
980         }
981         if (V1 == ENTER && WD2 > 0) {
982             WD1=WD2;
983             WD1X=WD2X;
984             WD2=0;
985         } else {
986             if (!((V1 != 1000+WATER && V1 != 1000+OIL) ||
987                   (V2 != 1000+PLANT && V2 != 1000+DOOR))) {
988                 if (AT(V2-1000))
989                     WD2=MAKEWD(16152118);
990             }
991             if (V1 == 1000+CAGE && V2 == 1000+BIRD && HERE(CAGE) && HERE(BIRD))
992                 WD1=MAKEWD(301200308);
993         }
994 L2620:  if (WD1 == MAKEWD(23051920)) {
995             ++game.iwest;
996             if (game.iwest == 10)
997                 RSPEAK(17);
998         }
999         if (WD1 == MAKEWD( 715) && WD2 != 0) {
1000             if (++igo == 10)
1001                 RSPEAK(276);
1002         }
1003 L2630:
1004         i=VOCAB(WD1,-1);
1005         if (i == -1) {
1006             /* Gee, I don't understand. */
1007             if (fallback_handler(rawbuf))
1008                 return true;
1009             SETPRM(1,WD1,WD1X);
1010             RSPEAK(254);
1011             goto L2600;
1012         }
1013         K=MOD(i,1000);
1014         KQ=i/1000+1;
1015         switch (KQ-1)
1016         {
1017         case 0: goto L8;
1018         case 1: goto L5000;
1019         case 2: goto L4000;
1020         case 3: RSPEAK(K); goto L2012;
1021         }
1022         BUG(22);
1023
1024 /* Verb and object analysis moved to separate module. */
1025
1026 L4000:  part=intransitive; VERB=K; goto Laction;
1027 L4090:  part=transitive; goto Laction;
1028 L5000:  part=unknown; obj = K;
1029 Laction:
1030          switch (action(cmdin, part, VERB, obj)) {
1031          case 2: return true;
1032          case 8: K=NUL; goto L8;
1033          case 2000: goto L2000;
1034          case 2012: goto L2012;
1035          case 2600: goto L2600;
1036          case 2607: goto L2607;
1037          case 2630: goto L2630;
1038          case 2800:
1039              /* Get second word for analysis. */
1040              WD1=WD2;
1041              WD1X=WD2X;
1042              WD2=0;
1043              goto L2620;
1044          case 8000:
1045              /*  Random intransitive verbs come here.  Clear obj just in case
1046               *  (see attack()). */
1047              SETPRM(1,WD1,WD1X);
1048              RSPEAK(257);
1049              obj=0;
1050              goto L2600;
1051          case 19000:
1052              /*  Oh dear, he's disturbed the dwarves. */
1053              RSPEAK(136);
1054              score(0);
1055              return true;
1056              }
1057         BUG(99);
1058
1059         /*  Figure out the new location */
1060 L8:     if (playermove(cmdin, VERB, K))
1061             return true;
1062         else
1063             goto L2000;
1064 }