+static void dohint(FILE *cmdin, int hint)
+/* Come here if he's been long enough at required loc(s) for some
+ * unused hint. */
+{
+ int i;
+
+ switch (hint-1)
+ {
+ case 0:
+ /* cave */
+ if(game.prop[GRATE] == 0 && !HERE(KEYS))
+ break;
+ game.hintlc[hint]=0;
+ return;
+ case 1: /* bird */
+ if(game.place[BIRD] == game.loc && TOTING(ROD) && game.oldobj == BIRD)
+ break;
+ return;
+ case 2: /* snake */
+ if(HERE(SNAKE) && !HERE(BIRD))
+ break;
+ game.hintlc[hint]=0;
+ return;
+ case 3: /* maze */
+ if(game.atloc[game.loc] == 0 &&
+ game.atloc[game.oldloc] == 0 &&
+ game.atloc[game.oldlc2] == 0 &&
+ game.holdng > 1)
+ break;
+ game.hintlc[hint]=0;
+ return;
+ case 4: /* dark */
+ if(game.prop[EMRALD] != -1 && game.prop[PYRAM] == -1)
+ break;
+ game.hintlc[hint]=0;
+ return;
+ case 5: /* witt */
+ break;
+ case 6: /* urn */
+ if(game.dflag == 0)
+ break;
+ game.hintlc[hint]=0;
+ return;
+ case 7: /* woods */
+ if(game.atloc[game.loc] == 0 &&
+ game.atloc[game.oldloc] == 0 &&
+ game.atloc[game.oldlc2] == 0)
+ break;
+ return;
+ case 8: /* ogre */
+ i=ATDWRF(game.loc);
+ if(i < 0) {
+ game.hintlc[hint]=0;
+ return;
+ }
+ if(HERE(OGRE) && i == 0)
+ break;
+ return;
+ case 9: /* jade */
+ if(game.tally == 1 && game.prop[JADE] < 0)
+ break;
+ game.hintlc[hint]=0;
+ return;
+ default:
+ BUG(27);
+ break;
+ }
+
+ /* Fall through to hint display */
+ game.hintlc[hint]=0;
+ if(!YES(cmdin,HINTS[hint][3],0,54))
+ return;
+ SETPRM(1,HINTS[hint][2],HINTS[hint][2]);
+ RSPEAK(261);
+ game.hinted[hint]=YES(cmdin,175,HINTS[hint][4],54);
+ if(game.hinted[hint] && game.limit > 30)
+ game.limit=game.limit+30*HINTS[hint][2];
+}
+
+static bool dwarfmove(void)
+/* Dwarves move. Return true if player survives, false if he dies. */
+{
+ int kk, stick, attack;
+ long TK[21];
+
+ /* Dwarf stuff. See earlier comments for description of
+ * variables. Remember sixth dwarf is pirate and is thus
+ * very different except for motion rules. */
+
+ /* First off, don't let the dwarves follow him into a pit or
+ * a wall. Activate the whole mess the first time he gets as
+ * far as the hall of mists (loc 15). If game.newloc is
+ * forbidden to pirate (in particular, if it's beyond the
+ * troll bridge), bypass dwarf stuff. That way pirate can't
+ * steal return toll, and dwarves can't meet the bear. Also
+ * means dwarves won't follow him into dead end in maze, but
+ * c'est la vie. They'll wait for him outside the dead
+ * end. */
+ if(game.loc == 0 || FORCED(game.loc) || CNDBIT(game.newloc,3))
+ return true;
+
+ /* Dwarf activity level ratchets up */
+ if(game.dflag == 0) {
+ if(INDEEP(game.loc))
+ game.dflag=1;
+ return true;
+ }
+
+ /* When we encounter the first dwarf, we kill 0, 1, or 2 of
+ * the 5 dwarves. If any of the survivors is at loc,
+ * replace him with the alternate. */
+ if(game.dflag == 1) {
+ if(!INDEEP(game.loc) || (PCT(95) && (!CNDBIT(game.loc,4) || PCT(85))))
+ return true;
+ game.dflag=2;
+ for (I=1; I<=2; I++) {
+ J=1+randrange(NDWARVES-1);
+ if(PCT(50))
+ game.dloc[J]=0;
+ }
+ for (I=1; I<=NDWARVES-1; I++) {
+ if(game.dloc[I] == game.loc)
+ game.dloc[I]=DALTLC;
+ game.odloc[I]=game.dloc[I];
+ }
+ RSPEAK(3);
+ DROP(AXE,game.loc);
+ return true;
+ }
+
+ /* Things are in full swing. Move each dwarf at random,
+ * except if he's seen us he sticks with us. Dwarves stay
+ * deep inside. If wandering at random, they don't back up
+ * unless there's no alternative. If they don't have to
+ * move, they attack. And, of course, dead dwarves don't do
+ * much of anything. */
+ game.dtotal=0;
+ attack=0;
+ stick=0;
+ for (I=1; I<=NDWARVES; I++) {
+ if(game.dloc[I] == 0)
+ continue;
+ /* Fill TK array with all the places this dwarf might go. */
+ J=1;
+ kk=KEY[game.dloc[I]];
+ if(kk != 0)
+ do {
+ game.newloc=MOD(labs(TRAVEL[kk])/1000,1000);
+ /* Have we avoided a dwarf enciounter? */
+ bool avoided = (game.newloc > 300 ||
+ !INDEEP(game.newloc) ||
+ game.newloc == game.odloc[I] ||
+ (J > 1 && game.newloc == TK[J-1]) ||
+ J >= 20 ||
+ game.newloc == game.dloc[I] ||
+ FORCED(game.newloc) ||
+ (I == PIRATE && CNDBIT(game.newloc,3)) ||
+ labs(TRAVEL[kk])/1000000 == 100);
+ if (!avoided) {
+ TK[J++] = game.newloc;
+ }
+ ++kk;
+ } while
+ (TRAVEL[kk-1] >= 0);
+ TK[J]=game.odloc[I];
+ if(J >= 2)
+ --J;
+ J=1+randrange(J);
+ game.odloc[I]=game.dloc[I];
+ game.dloc[I]=TK[J];
+ game.dseen[I]=(game.dseen[I] && INDEEP(game.loc)) || (game.dloc[I] == game.loc || game.odloc[I] == game.loc);
+ if(!game.dseen[I]) continue;
+ game.dloc[I]=game.loc;
+ if(I == PIRATE) {
+ /* The pirate's spotted him. He leaves him alone once we've
+ * found chest. K counts if a treasure is here. If not, and
+ * tally=1 for an unseen chest, let the pirate be spotted.
+ * Note that game.place(CHEST)=0 might mean that he's thrown
+ * it to the troll, but in that case he's seen the chest
+ * (game.prop=0). */
+ if(game.loc == game.chloc || game.prop[CHEST] >= 0)
+ continue;
+ K=0;
+ for (J=MINTRS; J<=MAXTRS; J++) {
+ /* Pirate won't take pyramid from plover room or dark
+ * room (too easy!). */
+ if(J == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD]))
+ goto L6020;
+ if(TOTING(J)) {
+ goto L6021;
+ }
+ L6020:
+ if(HERE(J))
+ K=1;
+ }
+ /* Force chest placement before player finds last treasure */
+ if(game.tally == 1 && K == 0 && game.place[CHEST] == 0 && HERE(LAMP) && game.prop[LAMP] == 1) {
+ RSPEAK(186);
+ MOVE(CHEST,game.chloc);
+ MOVE(MESSAG,game.chloc2);
+ game.dloc[PIRATE]=game.chloc;
+ game.odloc[PIRATE]=game.chloc;
+ game.dseen[PIRATE]=false;
+ continue;
+ }
+ if(game.odloc[PIRATE] != game.dloc[PIRATE] && PCT(20))
+ RSPEAK(127);
+ continue;
+
+ L6021:
+ if(game.place[CHEST] == 0) {
+ /* Install chest only once, to insure it is the last treasure in
+ * the list. */
+ MOVE(CHEST,game.chloc);
+ MOVE(MESSAG,game.chloc2);
+ }
+ RSPEAK(128);
+ for (J=MINTRS; J<=MAXTRS; J++) {
+ if (!(J == PYRAM && (game.loc == PLAC[PYRAM] || game.loc == PLAC[EMRALD]))) {
+ if(AT(J) && game.fixed[J] == 0)
+ CARRY(J,game.loc);
+ if(TOTING(J))
+ DROP(J,game.chloc);
+ }
+ }
+ game.dloc[PIRATE]=game.chloc;
+ game.odloc[PIRATE]=game.chloc;
+ game.dseen[PIRATE]=false;
+ continue;
+ }
+
+ /* This threatening little dwarf is in the room with him! */
+ ++game.dtotal;
+ if(game.odloc[I] == game.dloc[I]) {
+ ++attack;
+ if(game.knfloc >= 0)
+ game.knfloc=game.loc;
+ if(randrange(1000) < 95*(game.dflag-2))
+ ++stick;
+ }
+ }
+
+ /* Now we know what's happening. Let's tell the poor sucker about it.
+ * Note that various of the "knife" messages must have specific relative
+ * positions in the RSPEAK database. */
+ if(game.dtotal == 0)
+ return true;
+ SETPRM(1,game.dtotal,0);
+ RSPEAK(4+1/game.dtotal);
+ if(attack == 0)
+ return true;
+ if(game.dflag == 2)game.dflag=3;
+ SETPRM(1,attack,0);
+ K=6;
+ if(attack > 1)K=250;
+ RSPEAK(K);
+ SETPRM(1,stick,0);
+ RSPEAK(K+1+2/(1+stick));
+ if(stick == 0)
+ return true;
+ game.oldlc2=game.loc;
+ return false;
+}
+
+static void croak(FILE *cmdin)
+/* Okay, he's dead. Let's get on with it. */
+{
+ if(game.closng) {
+ /* He died during closing time. No resurrection. Tally up a
+ * death and exit. */
+ RSPEAK(131);
+ ++game.numdie;
+ score(0);
+ } else {
+ ++game.numdie;
+ if(!YES(cmdin,79+game.numdie*2,80+game.numdie*2,54))
+ score(0);
+ if(game.numdie == MAXDIE)
+ score(0);
+ game.place[WATER]=0;
+ game.place[OIL]=0;
+ if(TOTING(LAMP))
+ game.prop[LAMP]=0;
+ for (J=1; J<=NOBJECTS; J++) {
+ I=NOBJECTS + 1 - J;
+ if(TOTING(I)) {
+ K=game.oldlc2;
+ if(I == LAMP)
+ K=1;
+ DROP(I,K);
+ }
+ }
+ game.loc=3;
+ game.oldloc=game.loc;
+ }
+}
+