- game.wzdark=DARK(0);
- if(game.knfloc > 0 && game.knfloc != game.loc)
- game.knfloc=0;
-
- /* This is where we get a new command from the user */
- if (!GETIN(cmdin, WD1,WD1X,WD2,WD2X))
- return false;
-
- /* Every input, check "game.foobar" flag. If zero, nothing's
- * going on. If pos, make neg. If neg, he skipped a word,
- * so make it zero. */
-L2607: game.foobar=(game.foobar>0 ? -game.foobar : 0);
- game.turns=game.turns+1;
- if(game.turns == game.thresh) {
- SPEAK(TTEXT[game.trndex]);
- game.trnluz=game.trnluz+TRNVAL[game.trndex]/100000;
- game.trndex=game.trndex+1;
- game.thresh= -1;
- if(game.trndex <= TRNVLS)
- game.thresh=MOD(TRNVAL[game.trndex],100000)+1;
- }
- if(VERB == SAY && WD2 > 0)VERB=0;
- if(VERB == SAY) goto L4090;
- if(game.tally == 0 && INDEEP(game.loc) && game.loc != 33)game.clock1=game.clock1-1;
- if(game.clock1 == 0) goto L10000;
- if(game.clock1 < 0)game.clock2=game.clock2-1;
- if(game.clock2 == 0) goto L11000;
- if(game.prop[LAMP] == 1)game.limit=game.limit-1;
- if(game.limit <= 30 && HERE(BATTER) && game.prop[BATTER] == 0 && HERE(LAMP)) goto
- L12000;
- if(game.limit == 0) goto L12400;
- if(game.limit <= 30) goto L12200;
-L19999: K=43;
- if(LIQLOC(game.loc) == WATER)K=70;
- V1=VOCAB(WD1,-1);
- V2=VOCAB(WD2,-1);
- if(V1 == ENTER && (V2 == STREAM || V2 == 1000+WATER)) goto L2010;
- if(V1 == ENTER && WD2 > 0) goto L2800;
- if((V1 != 1000+WATER && V1 != 1000+OIL) || (V2 != 1000+PLANT && V2 !=
- 1000+DOOR)) goto L2610;
- {long x = V2-1000; if(AT(x))WD2=MAKEWD(16152118);}
-L2610: if(V1 == 1000+CAGE && V2 == 1000+BIRD && HERE(CAGE) && HERE(BIRD))
- WD1=MAKEWD(301200308);
-L2620: if(WD1 == MAKEWD(23051920)) {
- game.iwest=game.iwest+1;
- if(game.iwest == 10)RSPEAK(17);
- }
- if(WD1 != MAKEWD( 715) || WD2 == 0) goto L2630;
- IGO=IGO+1;
- if(IGO == 10)RSPEAK(276);
-L2630: I=VOCAB(WD1,-1);
- if(I == -1) goto L3000;
- K=MOD(I,1000);
- KQ=I/1000+1;
- switch (KQ-1) { case 0: goto L8; case 1: goto L5000; case 2: goto L4000;
- case 3: goto L2010; }
- BUG(22);
-
-/* Get second word for analysis. */
-
-L2800: WD1=WD2;
- WD1X=WD2X;
- WD2=0;
- goto L2620;
-
-/* Gee, I don't understand. */
-
-L3000: SETPRM(1,WD1,WD1X);
- if (fallback_handler(rawbuf))
- return true;
- RSPEAK(254);
- goto L2600;
-
-/* Verb and object analysis moved to separate module. */
-
-L4000: I=4000; VERB=K; goto Laction;
-L4090: I=4090; goto Laction;
-L5000: I=5000;
-Laction:
- switch (action(cmdin, I, VERB, obj)) {
- case 2: return true;
- case 8: goto L8;
- case 2000: goto L2000;
- case 2009: goto L2009;
- case 2010: goto L2010;
- case 2011: goto L2011;
- case 2012: goto L2012;
- case 2600: goto L2600;
- case 2607: goto L2607;
- case 2630: goto L2630;
- case 2800: goto L2800;
- case 8000: goto L8000;
- case 18999: goto L18999;
- case 19000: goto L19000;
- }
- BUG(99);
-
-/* Random intransitive verbs come here. Clear obj just in case (see "attack").
- */
-
-L8000: SETPRM(1,WD1,WD1X);
- RSPEAK(257);
- obj=0;
- goto L2600;
-
-/* Figure out the new location
+ }
+
+ return NULL;
+}
+
+/* Check if this loc is eligible for any hints. If been here int
+ * enough, display. Ignore "HINTS" < 4 (special stuff, see database
+ * notes). */
+static void checkhints(void)
+{
+ if (conditions[game.loc] >= game.conds) {
+ for (int hint = 0; hint < NHINTS; hint++) {
+ if (game.hinted[hint])
+ continue;
+ if (!CNDBIT(game.loc, hint + 1 + COND_HBASE))
+ game.hintlc[hint] = -1;
+ ++game.hintlc[hint];
+ /* Come here if he's been int enough at required loc(s) for some
+ * unused hint. */
+ if (game.hintlc[hint] >= hints[hint].turns) {
+ int i;
+
+ switch (hint) {
+ case 0:
+ /* cave */
+ if (game.prop[GRATE] == GRATE_CLOSED && !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] == NO_OBJECT &&
+ game.atloc[game.oldloc] == NO_OBJECT &&
+ game.atloc[game.oldlc2] == NO_OBJECT &&
+ game.holdng > 1)
+ break;
+ game.hintlc[hint] = 0;
+ return;
+ case 4: /* dark */
+ if (game.prop[EMERALD] != STATE_NOTFOUND && game.prop[PYRAMID] == STATE_NOTFOUND)
+ 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] == NO_OBJECT &&
+ game.atloc[game.oldloc] == NO_OBJECT &&
+ game.atloc[game.oldlc2] == NO_OBJECT)
+ 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: // LCOV_EXCL_LINE
+ BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
+ }
+
+ /* Fall through to hint display */
+ game.hintlc[hint] = 0;
+ if (!yes(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN]))
+ return;
+ rspeak(HINT_COST, hints[hint].penalty, hints[hint].penalty);
+ game.hinted[hint] = yes(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]);
+ if (game.hinted[hint] && game.limit > WARNTIME)
+ game.limit += WARNTIME * hints[hint].penalty;
+ }
+ }
+ }
+}
+
+static bool spotted_by_pirate(int i)
+{
+ if (i != PIRATE)
+ return false;
+
+ /* The pirate's spotted him. Pirate 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] = LOC_NOWHERE might mean that he's thrown
+ * it to the troll, but in that case he's seen the chest
+ * (game.prop[CHEST] == STATE_FOUND). */
+ if (game.loc == game.chloc ||
+ game.prop[CHEST] != STATE_NOTFOUND)
+ return true;
+ int snarfed = 0;
+ bool movechest = false, robplayer = false;
+ for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
+ if (!objects[treasure].is_treasure)
+ continue;
+ /* Pirate won't take pyramid from plover room or dark
+ * room (too easy!). */
+ if (treasure == PYRAMID && (game.loc == objects[PYRAMID].plac ||
+ game.loc == objects[EMERALD].plac)) {
+ continue;
+ }
+ if (TOTING(treasure) ||
+ HERE(treasure))
+ ++snarfed;
+ if (TOTING(treasure)) {
+ movechest = true;
+ robplayer = true;
+ }
+ }
+ /* Force chest placement before player finds last treasure */
+ if (game.tally == 1 && snarfed == 0 && game.place[CHEST] == LOC_NOWHERE && HERE(LAMP) && game.prop[LAMP] == LAMP_BRIGHT) {
+ rspeak(PIRATE_SPOTTED);
+ movechest = true;
+ }
+ /* Do things in this order (chest move before robbery) so chest is listed
+ * last at the maze location. */
+ if (movechest) {
+ move(CHEST, game.chloc);
+ move(MESSAG, game.chloc2);
+ game.dloc[PIRATE] = game.chloc;
+ game.odloc[PIRATE] = game.chloc;
+ game.dseen[PIRATE] = false;
+ } else {
+ /* You might get a hint of the pirate's presence even if the
+ * chest doesn't move... */
+ if (game.odloc[PIRATE] != game.dloc[PIRATE] && PCT(20))
+ rspeak(PIRATE_RUSTLES);
+ }
+ if (robplayer) {
+ rspeak(PIRATE_POUNCES);
+ for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
+ if (!objects[treasure].is_treasure)
+ continue;
+ if (!(treasure == PYRAMID && (game.loc == objects[PYRAMID].plac ||
+ game.loc == objects[EMERALD].plac))) {
+ if (AT(treasure) && game.fixed[treasure] == IS_FREE)
+ carry(treasure, game.loc);
+ if (TOTING(treasure))
+ drop(treasure, game.chloc);
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool dwarfmove(void)
+/* Dwarves move. Return true if player survives, false if he dies. */
+{
+ int kk, stick, attack;
+ loc_t 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 (what INDEEP() tests). 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 == LOC_NOWHERE ||
+ FORCED(game.loc) ||
+ CNDBIT(game.newloc, COND_NOARRR))
+ 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 game.loc,
+ * replace him with the alternate. */
+ if (game.dflag == 1) {
+ if (!INDEEP(game.loc) ||
+ (PCT(95) && (!CNDBIT(game.loc, COND_NOBACK) ||
+ PCT(85))))
+ return true;
+ game.dflag = 2;
+ for (int i = 1; i <= 2; i++) {
+ int j = 1 + randrange(NDWARVES - 1);
+ if (PCT(50))
+ game.dloc[j] = 0;
+ }
+
+ /* Alternate initial loc for dwarf, in case one of them
+ * starts out on top of the adventurer. */
+ for (int i = 1; i <= NDWARVES - 1; i++) {
+ if (game.dloc[i] == game.loc)
+ game.dloc[i] = DALTLC; //
+ game.odloc[i] = game.dloc[i];
+ }
+ rspeak(DWARF_RAN);
+ 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 (int i = 1; i <= NDWARVES; i++) {
+ if (game.dloc[i] == 0)
+ continue;
+ /* Fill tk array with all the places this dwarf might go. */
+ unsigned int j = 1;
+ kk = tkey[game.dloc[i]];
+ if (kk != 0)
+ do {
+ enum desttype_t desttype = travel[kk].desttype;
+ game.newloc = travel[kk].destval;
+ /* Have we avoided a dwarf encounter? */
+ if (desttype != dest_goto)
+ continue;
+ else if (!INDEEP(game.newloc))
+ continue;
+ else if (game.newloc == game.odloc[i])
+ continue;
+ else if (j > 1 && game.newloc == tk[j - 1])
+ continue;
+ else if (j >= DIM(tk) - 1)
+ /* This can't actually happen. */
+ continue; // LCOV_EXCL_LINE
+ else if (game.newloc == game.dloc[i])
+ continue;
+ else if (FORCED(game.newloc))
+ continue;
+ else if (i == PIRATE && CNDBIT(game.newloc, COND_NOARRR))
+ continue;
+ else if (travel[kk].nodwarves)
+ continue;
+ tk[j++] = game.newloc;
+ } while
+ (!travel[kk++].stop);
+ 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 (spotted_by_pirate(i))
+ 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. */
+ if (game.dtotal == 0)
+ return true;
+ rspeak(game.dtotal == 1 ? DWARF_SINGLE : DWARF_PACK, game.dtotal);
+ if (attack == 0)
+ return true;
+ if (game.dflag == 2)
+ game.dflag = 3;
+ if (attack > 1) {
+ rspeak(THROWN_KNIVES, attack);
+ rspeak(stick > 1 ? MULTIPLE_HITS : (stick == 1 ? ONE_HIT : NONE_HIT), stick);
+ } else {
+ rspeak(KNIFE_THROWN);
+ rspeak(stick ? GETS_YOU : MISSES_YOU);
+ }
+ if (stick == 0)
+ return true;
+ game.oldlc2 = game.loc;
+ return false;
+}
+
+/* "You're dead, Jim."