-static void playermove( int motion)
-{
- int scratchloc, travel_entry = tkey[game.loc];
- game.newloc = game.loc;
- if (travel_entry == 0)
- BUG(LOCATION_HAS_NO_TRAVEL_ENTRIES); // LCOV_EXCL_LINE
- if (motion == NUL)
- return;
- else if (motion == BACK) {
- /* Handle "go back". Look for verb which goes from game.loc to
- * game.oldloc, or to game.oldlc2 If game.oldloc has forced-motion.
- * te_tmp saves entry -> forced loc -> previous loc. */
- motion = game.oldloc;
- if (FORCED(motion))
- motion = game.oldlc2;
- game.oldlc2 = game.oldloc;
- game.oldloc = game.loc;
- if (CNDBIT(game.loc, COND_NOBACK)) {
- rspeak(TWIST_TURN);
- return;
- }
- if (motion == game.loc) {
- rspeak(FORGOT_PATH);
- return;
- }
-
- int te_tmp = 0;
- for (;;) {
- enum desttype_t desttype = travel[travel_entry].desttype;
- scratchloc = travel[travel_entry].destval;
- if (desttype != dest_goto || scratchloc != motion) {
- if (desttype == dest_goto) {
- if (FORCED(scratchloc) && travel[tkey[scratchloc]].destval == motion)
- te_tmp = travel_entry;
- }
- if (!travel[travel_entry].stop) {
- ++travel_entry; /* go to next travel entry for this location */
- continue;
- }
- /* we've reached the end of travel entries for game.loc */
- travel_entry = te_tmp;
- if (travel_entry == 0) {
- rspeak(NOT_CONNECTED);
- return;
- }
- }
-
- motion = travel[travel_entry].motion;
- travel_entry = tkey[game.loc];
- break; /* fall through to ordinary travel */
- }
- } else if (motion == LOOK) {
- /* Look. Can't give more detail. Pretend it wasn't dark
- * (though it may now be dark) so he won't fall into a
- * pit while staring into the gloom. */
- if (game.detail < 3)
- rspeak(NO_MORE_DETAIL);
- ++game.detail;
- game.wzdark = false;
- game.abbrev[game.loc] = 0;
- return;
- } else if (motion == CAVE) {
- /* Cave. Different messages depending on whether above ground. */
- rspeak((OUTSID(game.loc) && game.loc != LOC_GRATE) ? FOLLOW_STREAM : NEED_DETAIL);
- return;
- } else {
- /* none of the specials */
- game.oldlc2 = game.oldloc;
- game.oldloc = game.loc;
- }
-
- /* Look for a way to fulfil the motion verb passed in - travel_entry indexes
- * the beginning of the motion entries for here (game.loc). */
- for (;;) {
- if (T_TERMINATE(travel[travel_entry]) ||
- travel[travel_entry].motion == motion)
- break;
- if (travel[travel_entry].stop) {
- /* Couldn't find an entry matching the motion word passed
- * in. Various messages depending on word given. */
- switch (motion) {
- case EAST:
- case WEST:
- case SOUTH:
- case NORTH:
- case NE:
- case NW:
- case SW:
- case SE:
- case UP:
- case DOWN:
- rspeak(BAD_DIRECTION);
- break;
- case FORWARD:
- case LEFT:
- case RIGHT:
- rspeak(UNSURE_FACING);
- break;
- case OUTSIDE:
- case INSIDE:
- rspeak(NO_INOUT_HERE);
- break;
- case XYZZY:
- case PLUGH:
- rspeak(NOTHING_HAPPENS);
- break;
- case CRAWL:
- rspeak(WHICH_WAY);
- break;
- default:
- rspeak(CANT_APPLY);
- }
- return;
- }
- ++travel_entry;
- }
-
- /* (ESR) We've found a destination that goes with the motion verb.
- * Next we need to check any conditional(s) on this destination, and
- * possibly on following entries. */
- do {
- for (;;) { /* L12 loop */
- for (;;) {
- enum condtype_t condtype = travel[travel_entry].condtype;
- long condarg1 = travel[travel_entry].condarg1;
- long condarg2 = travel[travel_entry].condarg2;
- if (condtype < cond_not) {
- /* YAML N and [pct N] conditionals */
- if (condtype == cond_goto || condtype == cond_pct) {
- if (condarg1 == 0 ||
- PCT(condarg1))
- break;
- /* else fall through */
- }
- /* YAML [with OBJ] clause */
- else if (TOTING(condarg1) ||
- (condtype == cond_with && AT(condarg1)))
- break;
- /* else fall through to check [not OBJ STATE] */
- } else if (game.prop[condarg1] != condarg2)
- break;
-
- /* We arrive here on conditional failure.
- * Skip to next non-matching destination */
- int te_tmp = travel_entry;
- do {
- if (travel[te_tmp].stop)
- BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); // LCOV_EXCL_LINE
- ++te_tmp;
- } while
- (traveleq(travel_entry, te_tmp));
- travel_entry = te_tmp;
- }
-
- /* Found an eligible rule, now execute it */
- enum desttype_t desttype = travel[travel_entry].desttype;
- game.newloc = travel[travel_entry].destval;
- if (desttype == dest_goto)
- return;
-
- if (desttype == dest_speak) {
- /* Execute a speak rule */
- rspeak(game.newloc);
- game.newloc = game.loc;
- return;
- } else {
- switch (game.newloc) {
- case 1:
- /* Special travel 1. Plover-alcove passage. Can carry only
- * emerald. Note: travel table must include "useless"
- * entries going through passage, which can never be used
- * for actual motion, but can be spotted by "go back". */
- game.newloc = (game.loc == LOC_PLOVER)
- ? LOC_ALCOVE
- : LOC_PLOVER;
- if (game.holdng > 1 ||
- (game.holdng == 1 && !TOTING(EMERALD))) {
- game.newloc = game.loc;
- rspeak(MUST_DROP);
- }
- return;
- case 2:
- /* Special travel 2. Plover transport. Drop the
- * emerald (only use special travel if toting
- * it), so he's forced to use the plover-passage
- * to get it out. Having dropped it, go back and
- * pretend he wasn't carrying it after all. */
- drop(EMERALD, game.loc);
- {
- int te_tmp = travel_entry;
- do {
- if (travel[te_tmp].stop)
- BUG(CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION); // LCOV_EXCL_LINE
- ++te_tmp;
- } while
- (traveleq(travel_entry, te_tmp));
- travel_entry = te_tmp;
- }
- continue; /* goto L12 */
- case 3:
- /* Special travel 3. Troll bridge. Must be done
- * only as special motion so that dwarves won't
- * wander across and encounter the bear. (They
- * won't follow the player there because that
- * region is forbidden to the pirate.) If
- * game.prop[TROLL]=TROLL_PAIDONCE, he's crossed
- * since paying, so step out and block him.
- * (standard travel entries check for
- * game.prop[TROLL]=TROLL_UNPAID.) Special stuff
- * for bear. */
- if (game.prop[TROLL] == TROLL_PAIDONCE) {
- pspeak(TROLL, look, TROLL_PAIDONCE, true);
- game.prop[TROLL] = TROLL_UNPAID;
- move(TROLL2, LOC_NOWHERE);
- move(TROLL2 + NOBJECTS, IS_FREE);
- move(TROLL, objects[TROLL].plac);
- move(TROLL + NOBJECTS, objects[TROLL].fixd);
- juggle(CHASM);
- game.newloc = game.loc;
- return;
- } else {
- game.newloc = objects[TROLL].plac + objects[TROLL].fixd - game.loc;
- if (game.prop[TROLL] == TROLL_UNPAID)
- game.prop[TROLL] = TROLL_PAIDONCE;
- if (!TOTING(BEAR))
- return;
- state_change(CHASM, BRIDGE_WRECKED);
- game.prop[TROLL] = TROLL_GONE;
- drop(BEAR, game.newloc);
- game.fixed[BEAR] = IS_FIXED;
- game.prop[BEAR] = BEAR_DEAD;
- game.oldlc2 = game.newloc;
- croak();
- return;
- }
- default: // LCOV_EXCL_LINE
- BUG(SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
- }
- }
- break; /* Leave L12 loop */
- }
- } while
- (false);
+static void lampcheck(void) {
+ /* Check game limit and lamp timers */
+ if (game.objects[LAMP].prop == LAMP_BRIGHT) {
+ --game.limit;
+ }
+
+ /* Another way we can force an end to things is by having the
+ * lamp give out. When it gets close, we come here to warn him.
+ * First following arm checks if the lamp and fresh batteries are
+ * here, in which case we replace the batteries and continue.
+ * Second is for other cases of lamp dying. Even after it goes
+ * out, he can explore outside for a while if desired. */
+ if (game.limit <= WARNTIME) {
+ if (HERE(BATTERY) &&
+ game.objects[BATTERY].prop == FRESH_BATTERIES &&
+ HERE(LAMP)) {
+ rspeak(REPLACE_BATTERIES);
+ game.objects[BATTERY].prop = DEAD_BATTERIES;
+#ifdef __unused__
+ /* This code from the original game seems to have been
+ * faulty. No tests ever passed the guard, and with the
+ * guard removed the game hangs when the lamp limit is
+ * reached.
+ */
+ if (TOTING(BATTERY)) {
+ drop(BATTERY, game.loc);
+ }
+#endif
+ game.limit += BATTERYLIFE;
+ game.lmwarn = false;
+ } else if (!game.lmwarn && HERE(LAMP)) {
+ game.lmwarn = true;
+ if (game.objects[BATTERY].prop == DEAD_BATTERIES) {
+ rspeak(MISSING_BATTERIES);
+ } else if (game.objects[BATTERY].place == LOC_NOWHERE) {
+ rspeak(LAMP_DIM);
+ } else {
+ rspeak(GET_BATTERIES);
+ }
+ }
+ }
+ if (game.limit == 0) {
+ game.limit = -1;
+ game.objects[LAMP].prop = LAMP_DARK;
+ if (HERE(LAMP)) {
+ rspeak(LAMP_OUT);
+ }
+ }