1TBS reflow with clang-format.
authorEric S. Raymond <esr@thyrsus.com>
Sat, 27 Jan 2024 11:17:02 +0000 (06:17 -0500)
committerEric S. Raymond <esr@thyrsus.com>
Sun, 28 Jan 2024 13:09:39 +0000 (08:09 -0500)
Makefile
actions.c
advent.h
cheat.c
init.c
main.c
misc.c
saveresume.c
score.c

index 49c909ef9fde49a559fbcb0c87839f35c004c730..9c837d26e6608aae653e471e0b8ccfdd774796d9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -68,6 +68,9 @@ cheat: $(CHEAT_OBJS) dungeon.o
 check: advent cheat
        cd tests; $(MAKE) --quiet
 
+reflow:
+       @clang-format --style="{IndentWidth: 8, UseTab: ForIndentation}" -i $$(find . -name "*.[ch]")
+
 # Requires gcov, lcov, libasan6, and libubsan1
 # The last two are Ubuntu names, might vary on other distributions.
 # After this, run your browser on coverage/open-adventure/index.html
index fed70b9099531db585b436d51984d6d13f81628f..97e5a48d56da9e0c5b7d7e167e5c9d5805b2d7b6 100644 (file)
--- a/actions.c
+++ b/actions.c
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <stdlib.h>
+#include <inttypes.h>
 #include <stdbool.h>
+#include <stdlib.h>
 #include <string.h>
-#include <inttypes.h>
 
 #include "advent.h"
 
 static phase_codes_t fill(verb_t, obj_t);
 
 static phase_codes_t attack(command_t command) {
-/*  Attack.  Assume target if unambiguous.  "Throw" also links here.
- *  Attackable objects fall into two categories: enemies (snake,
- *  dwarf, etc.)  and others (bird, clam, machine).  Ambiguous if 2
- *  enemies, or no enemies but 2 others. */
-    verb_t verb = command.verb;
-    obj_t obj = command.obj;
-
-    if (obj == INTRANSITIVE) {
-        int changes = 0;
-        if (atdwrf(game.loc) > 0) {
-            obj = DWARF;
-            ++changes;
-        }
-        if (HERE(SNAKE)) {
-            obj = SNAKE;
-            ++changes;
-        }
-        if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
-            obj = DRAGON;
-            ++changes;
-        }
-        if (AT(TROLL)) {
-            obj = TROLL;
-            ++changes;
-        }
-        if (AT(OGRE)) {
-            obj = OGRE;
-            ++changes;
-        }
-        if (HERE(BEAR) && game.objects[BEAR].prop == UNTAMED_BEAR) {
-            obj = BEAR;
-            ++changes;
-        }
-        /* check for low-priority targets */
-        if (obj == INTRANSITIVE) {
-            /* Can't attack bird or machine by throwing axe. */
-            if (HERE(BIRD) && verb != THROW) {
-                obj = BIRD;
-                ++changes;
-            }
-            if (HERE(VEND) && verb != THROW) {
-                obj = VEND;
-                ++changes;
-            }
-            /* Clam and oyster both treated as clam for intransitive case;
-             * no harm done. */
-            if (HERE(CLAM) || HERE(OYSTER)) {
-                obj = CLAM;
-                ++changes;
-            }
-        }
-        if (changes >= 2)
-            return GO_UNKNOWN;
-    }
-
-    if (obj == BIRD) {
-        if (game.closed) {
-            rspeak(UNHAPPY_BIRD);
-        } else {
-            DESTROY(BIRD);
-            rspeak(BIRD_DEAD);
-        }
-        return GO_CLEAROBJ;
-    }
-    if (obj == VEND) {
-        state_change(VEND,
-                     game.objects[VEND].prop == VEND_BLOCKS ? VEND_UNBLOCKS : VEND_BLOCKS);
-
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == BEAR) {
-        switch (game.objects[BEAR].prop) {
-        case UNTAMED_BEAR:
-            rspeak(BEAR_HANDS);
-            break;
-        case SITTING_BEAR:
-            rspeak(BEAR_CONFUSED);
-            break;
-        case CONTENTED_BEAR:
-            rspeak(BEAR_CONFUSED);
-            break;
-        case BEAR_DEAD:
-            rspeak(ALREADY_DEAD);
-            break;
-        }
-        return GO_CLEAROBJ;
-    }
-    if (obj == DRAGON && game.objects[DRAGON].prop == DRAGON_BARS) {
-        /*  Fun stuff for dragon.  If he insists on attacking it, win!
-         *  Set game.prop to dead, move dragon to central loc (still
-         *  fixed), move rug there (not fixed), and move him there,
-         *  too.  Then do a null motion to get new description. */
-        rspeak(BARE_HANDS_QUERY);
-        if (!silent_yes_or_no()) {
-            speak(arbitrary_messages[NASTY_DRAGON]);
-            return GO_MOVE;
-        }
-        state_change(DRAGON, DRAGON_DEAD);
-        game.objects[RUG].prop = RUG_FLOOR;
-        /* Hardcoding LOC_SECRET5 as the dragon's death location is ugly.
-         * The way it was computed before was worse; it depended on the
-         * two dragon locations being LOC_SECRET4 and LOC_SECRET6 and
-         * LOC_SECRET5 being right between them.
-         */
-        move(DRAGON + NOBJECTS, IS_FIXED);
-        move(RUG + NOBJECTS, IS_FREE);
-        move(DRAGON, LOC_SECRET5);
-        move(RUG, LOC_SECRET5);
-        drop(BLOOD, LOC_SECRET5);
-        for (obj_t i = 1; i <= NOBJECTS; i++) {
-            if (game.objects[i].place == objects[DRAGON].plac ||
-                game.objects[i].place == objects[DRAGON].fixd)
-                move(i, LOC_SECRET5);
-        }
-        game.loc = LOC_SECRET5;
-        return GO_MOVE;
-    }
-
-    if (obj == OGRE) {
-        rspeak(OGRE_DODGE);
-        if (atdwrf(game.loc) == 0) {
-            return GO_CLEAROBJ;
-       }
-        rspeak(KNIFE_THROWN);
-        DESTROY(OGRE);
-        int dwarves = 0;
-        for (int i = 1; i < PIRATE; i++) {
-            if (game.dwarves[i].loc == game.loc) {
-                ++dwarves;
-                game.dwarves[i].loc = LOC_LONGWEST;
-                game.dwarves[i].seen = false;
-            }
-        }
-        rspeak((dwarves > 1) ?
-               OGRE_PANIC1 :
-               OGRE_PANIC2);
-        return GO_CLEAROBJ;
-    }
-
-    switch (obj) {
-    case INTRANSITIVE:
-        rspeak(NO_TARGET);
-        break;
-    case CLAM:
-    case OYSTER:
-        rspeak(SHELL_IMPERVIOUS);
-        break;
-    case SNAKE:
-        rspeak(SNAKE_WARNING);
-        break;
-    case DWARF:
-        if (game.closed) {
-            return GO_DWARFWAKE;
-        }
-        rspeak(BARE_HANDS_QUERY);
-        break;
-    case DRAGON:
-        rspeak(ALREADY_DEAD);
-        break;
-    case TROLL:
-        rspeak(ROCKY_TROLL);
-        break;
-    default:
-        speak(actions[verb].message);
-    }
-    return GO_CLEAROBJ;
+       /*  Attack.  Assume target if unambiguous.  "Throw" also links here.
+        *  Attackable objects fall into two categories: enemies (snake,
+        *  dwarf, etc.)  and others (bird, clam, machine).  Ambiguous if 2
+        *  enemies, or no enemies but 2 others. */
+       verb_t verb = command.verb;
+       obj_t obj = command.obj;
+
+       if (obj == INTRANSITIVE) {
+               int changes = 0;
+               if (atdwrf(game.loc) > 0) {
+                       obj = DWARF;
+                       ++changes;
+               }
+               if (HERE(SNAKE)) {
+                       obj = SNAKE;
+                       ++changes;
+               }
+               if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
+                       obj = DRAGON;
+                       ++changes;
+               }
+               if (AT(TROLL)) {
+                       obj = TROLL;
+                       ++changes;
+               }
+               if (AT(OGRE)) {
+                       obj = OGRE;
+                       ++changes;
+               }
+               if (HERE(BEAR) && game.objects[BEAR].prop == UNTAMED_BEAR) {
+                       obj = BEAR;
+                       ++changes;
+               }
+               /* check for low-priority targets */
+               if (obj == INTRANSITIVE) {
+                       /* Can't attack bird or machine by throwing axe. */
+                       if (HERE(BIRD) && verb != THROW) {
+                               obj = BIRD;
+                               ++changes;
+                       }
+                       if (HERE(VEND) && verb != THROW) {
+                               obj = VEND;
+                               ++changes;
+                       }
+                       /* Clam and oyster both treated as clam for intransitive
+                        * case; no harm done. */
+                       if (HERE(CLAM) || HERE(OYSTER)) {
+                               obj = CLAM;
+                               ++changes;
+                       }
+               }
+               if (changes >= 2)
+                       return GO_UNKNOWN;
+       }
+
+       if (obj == BIRD) {
+               if (game.closed) {
+                       rspeak(UNHAPPY_BIRD);
+               } else {
+                       DESTROY(BIRD);
+                       rspeak(BIRD_DEAD);
+               }
+               return GO_CLEAROBJ;
+       }
+       if (obj == VEND) {
+               state_change(VEND, game.objects[VEND].prop == VEND_BLOCKS
+                                      ? VEND_UNBLOCKS
+                                      : VEND_BLOCKS);
+
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == BEAR) {
+               switch (game.objects[BEAR].prop) {
+               case UNTAMED_BEAR:
+                       rspeak(BEAR_HANDS);
+                       break;
+               case SITTING_BEAR:
+                       rspeak(BEAR_CONFUSED);
+                       break;
+               case CONTENTED_BEAR:
+                       rspeak(BEAR_CONFUSED);
+                       break;
+               case BEAR_DEAD:
+                       rspeak(ALREADY_DEAD);
+                       break;
+               }
+               return GO_CLEAROBJ;
+       }
+       if (obj == DRAGON && game.objects[DRAGON].prop == DRAGON_BARS) {
+               /*  Fun stuff for dragon.  If he insists on attacking it, win!
+                *  Set game.prop to dead, move dragon to central loc (still
+                *  fixed), move rug there (not fixed), and move him there,
+                *  too.  Then do a null motion to get new description. */
+               rspeak(BARE_HANDS_QUERY);
+               if (!silent_yes_or_no()) {
+                       speak(arbitrary_messages[NASTY_DRAGON]);
+                       return GO_MOVE;
+               }
+               state_change(DRAGON, DRAGON_DEAD);
+               game.objects[RUG].prop = RUG_FLOOR;
+               /* Hardcoding LOC_SECRET5 as the dragon's death location is
+                * ugly. The way it was computed before was worse; it depended
+                * on the two dragon locations being LOC_SECRET4 and LOC_SECRET6
+                * and LOC_SECRET5 being right between them.
+                */
+               move(DRAGON + NOBJECTS, IS_FIXED);
+               move(RUG + NOBJECTS, IS_FREE);
+               move(DRAGON, LOC_SECRET5);
+               move(RUG, LOC_SECRET5);
+               drop(BLOOD, LOC_SECRET5);
+               for (obj_t i = 1; i <= NOBJECTS; i++) {
+                       if (game.objects[i].place == objects[DRAGON].plac ||
+                           game.objects[i].place == objects[DRAGON].fixd)
+                               move(i, LOC_SECRET5);
+               }
+               game.loc = LOC_SECRET5;
+               return GO_MOVE;
+       }
+
+       if (obj == OGRE) {
+               rspeak(OGRE_DODGE);
+               if (atdwrf(game.loc) == 0) {
+                       return GO_CLEAROBJ;
+               }
+               rspeak(KNIFE_THROWN);
+               DESTROY(OGRE);
+               int dwarves = 0;
+               for (int i = 1; i < PIRATE; i++) {
+                       if (game.dwarves[i].loc == game.loc) {
+                               ++dwarves;
+                               game.dwarves[i].loc = LOC_LONGWEST;
+                               game.dwarves[i].seen = false;
+                       }
+               }
+               rspeak((dwarves > 1) ? OGRE_PANIC1 : OGRE_PANIC2);
+               return GO_CLEAROBJ;
+       }
+
+       switch (obj) {
+       case INTRANSITIVE:
+               rspeak(NO_TARGET);
+               break;
+       case CLAM:
+       case OYSTER:
+               rspeak(SHELL_IMPERVIOUS);
+               break;
+       case SNAKE:
+               rspeak(SNAKE_WARNING);
+               break;
+       case DWARF:
+               if (game.closed) {
+                       return GO_DWARFWAKE;
+               }
+               rspeak(BARE_HANDS_QUERY);
+               break;
+       case DRAGON:
+               rspeak(ALREADY_DEAD);
+               break;
+       case TROLL:
+               rspeak(ROCKY_TROLL);
+               break;
+       default:
+               speak(actions[verb].message);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t bigwords(vocab_t id) {
-/* Only called on FEE FIE FOE FOO (AND FUM).  Advance to next state if given
- * in proper order. Look up foo in special section of vocab to determine which
- * word we've got. Last word zips the eggs back to the giant room (unless
- * already there). */
-    int foobar = abs(game.foobar);
-
-    /* Only FEE can start a magic-word sequence. */
-    if ((foobar == WORD_EMPTY) && (id == FIE || id == FOE || id == FOO || id == FUM)) {
-       rspeak(NOTHING_HAPPENS);
-       return GO_CLEAROBJ;
-    }
-    
-    if ((foobar == WORD_EMPTY && id == FEE) ||
-        (foobar == FEE && id == FIE) ||
-        (foobar == FIE && id == FOE) ||
-        (foobar == FOE && id == FOO)) {
-        game.foobar = id;
-        if (id != FOO) {
-            rspeak(OK_MAN);
-            return GO_CLEAROBJ;
-        }
-        game.foobar = WORD_EMPTY;
-        if (game.objects[EGGS].place == objects[EGGS].plac ||
-            (TOTING(EGGS) && game.loc == objects[EGGS].plac)) {
-            rspeak(NOTHING_HAPPENS);
-            return GO_CLEAROBJ;
-        } else {
-            /*  Bring back troll if we steal the eggs back from him before
-             *  crossing. */
-            if (game.objects[EGGS].place == LOC_NOWHERE && game.objects[TROLL].place == LOC_NOWHERE
-               && game.objects[TROLL].prop == TROLL_UNPAID)
-                game.objects[TROLL].prop = TROLL_PAIDONCE;
-            if (HERE(EGGS)) {
-                pspeak(EGGS, look, true, EGGS_VANISHED);
-            } else if (game.loc == objects[EGGS].plac) {
-                pspeak(EGGS, look, true, EGGS_HERE);
-            } else {
-                pspeak(EGGS, look, true, EGGS_DONE);
-           }
-            move(EGGS, objects[EGGS].plac);
-
-            return GO_CLEAROBJ;
-        }
-    } else {
-       /* Magic-word sequence was started but is incorrect */
-       if (settings.oldstyle || game.seenbigwords) {
-             rspeak(START_OVER);
+       /* Only called on FEE FIE FOE FOO (AND FUM).  Advance to next state if
+        * given in proper order. Look up foo in special section of vocab to
+        * determine which word we've got. Last word zips the eggs back to the
+        * giant room (unless already there). */
+       int foobar = abs(game.foobar);
+
+       /* Only FEE can start a magic-word sequence. */
+       if ((foobar == WORD_EMPTY) &&
+           (id == FIE || id == FOE || id == FOO || id == FUM)) {
+               rspeak(NOTHING_HAPPENS);
+               return GO_CLEAROBJ;
+       }
+
+       if ((foobar == WORD_EMPTY && id == FEE) ||
+           (foobar == FEE && id == FIE) || (foobar == FIE && id == FOE) ||
+           (foobar == FOE && id == FOO)) {
+               game.foobar = id;
+               if (id != FOO) {
+                       rspeak(OK_MAN);
+                       return GO_CLEAROBJ;
+               }
+               game.foobar = WORD_EMPTY;
+               if (game.objects[EGGS].place == objects[EGGS].plac ||
+                   (TOTING(EGGS) && game.loc == objects[EGGS].plac)) {
+                       rspeak(NOTHING_HAPPENS);
+                       return GO_CLEAROBJ;
+               } else {
+                       /*  Bring back troll if we steal the eggs back from him
+                        * before crossing. */
+                       if (game.objects[EGGS].place == LOC_NOWHERE &&
+                           game.objects[TROLL].place == LOC_NOWHERE &&
+                           game.objects[TROLL].prop == TROLL_UNPAID)
+                               game.objects[TROLL].prop = TROLL_PAIDONCE;
+                       if (HERE(EGGS)) {
+                               pspeak(EGGS, look, true, EGGS_VANISHED);
+                       } else if (game.loc == objects[EGGS].plac) {
+                               pspeak(EGGS, look, true, EGGS_HERE);
+                       } else {
+                               pspeak(EGGS, look, true, EGGS_DONE);
+                       }
+                       move(EGGS, objects[EGGS].plac);
+
+                       return GO_CLEAROBJ;
+               }
        } else {
-           rspeak(WELL_POINTLESS);
+               /* Magic-word sequence was started but is incorrect */
+               if (settings.oldstyle || game.seenbigwords) {
+                       rspeak(START_OVER);
+               } else {
+                       rspeak(WELL_POINTLESS);
+               }
+               game.foobar = WORD_EMPTY;
+               return GO_CLEAROBJ;
        }
-        game.foobar = WORD_EMPTY;
-        return GO_CLEAROBJ;
-    }
 }
 
 static void blast(void) {
-/*  Blast.  No effect unless you've got dynamite, which is a neat trick! */
-    if (PROP_IS_NOTFOUND(ROD2) || !game.closed)
-        rspeak(REQUIRES_DYNAMITE);
-    else {
-        if (HERE(ROD2)) {
-            game.bonus = splatter;
-            rspeak(SPLATTER_MESSAGE);
-        } else if (game.loc == LOC_NE) {
-            game.bonus = defeat;
-            rspeak(DEFEAT_MESSAGE);
-        } else {
-            game.bonus = victory;
-            rspeak(VICTORY_MESSAGE);
-        }
-        terminate(endgame);
-    }
+       /*  Blast.  No effect unless you've got dynamite, which is a neat trick!
+        */
+       if (PROP_IS_NOTFOUND(ROD2) || !game.closed)
+               rspeak(REQUIRES_DYNAMITE);
+       else {
+               if (HERE(ROD2)) {
+                       game.bonus = splatter;
+                       rspeak(SPLATTER_MESSAGE);
+               } else if (game.loc == LOC_NE) {
+                       game.bonus = defeat;
+                       rspeak(DEFEAT_MESSAGE);
+               } else {
+                       game.bonus = victory;
+                       rspeak(VICTORY_MESSAGE);
+               }
+               terminate(endgame);
+       }
 }
 
 static phase_codes_t vbreak(verb_t verb, obj_t obj) {
-/*  Break.  Only works for mirror in repository and, of course, the vase. */
-    switch (obj) {
-    case MIRROR:
-        if (game.closed) {
-            state_change(MIRROR, MIRROR_BROKEN);
-            return GO_DWARFWAKE;
-        } else {
-            rspeak(TOO_FAR);
-            break;
-        }
-    case VASE:
-        if (game.objects[VASE].prop == VASE_WHOLE) {
-            if (TOTING(VASE))
-                drop(VASE, game.loc);
-            state_change(VASE, VASE_BROKEN);
-            game.objects[VASE].fixed = IS_FIXED;
-            break;
-        }
-    /* FALLTHRU */
-    default:
-        speak(actions[verb].message);
-    }
-    return (GO_CLEAROBJ);
+       /*  Break.  Only works for mirror in repository and, of course, the
+        * vase. */
+       switch (obj) {
+       case MIRROR:
+               if (game.closed) {
+                       state_change(MIRROR, MIRROR_BROKEN);
+                       return GO_DWARFWAKE;
+               } else {
+                       rspeak(TOO_FAR);
+                       break;
+               }
+       case VASE:
+               if (game.objects[VASE].prop == VASE_WHOLE) {
+                       if (TOTING(VASE))
+                               drop(VASE, game.loc);
+                       state_change(VASE, VASE_BROKEN);
+                       game.objects[VASE].fixed = IS_FIXED;
+                       break;
+               }
+       /* FALLTHRU */
+       default:
+               speak(actions[verb].message);
+       }
+       return (GO_CLEAROBJ);
 }
 
 static phase_codes_t brief(void) {
-/*  Brief.  Intransitive only.  Suppress full descriptions after first time. */
-    game.abbnum = 10000;
-    game.detail = 3;
-    rspeak(BRIEF_CONFIRM);
-    return GO_CLEAROBJ;
+       /*  Brief.  Intransitive only.  Suppress full descriptions after first
+        * time. */
+       game.abbnum = 10000;
+       game.detail = 3;
+       rspeak(BRIEF_CONFIRM);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t vcarry(verb_t verb, obj_t obj) {
-/*  Carry an object.  Special cases for bird and cage (if bird in cage, can't
- *  take one without the other).  Liquids also special, since they depend on
- *  status of bottle.  Also various side effects, etc. */
-    if (obj == INTRANSITIVE) {
-        /*  Carry, no object given yet.  OK if only one object present. */
-        if (game.locs[game.loc].atloc == NO_OBJECT ||
-            game.link[game.locs[game.loc].atloc] != 0 ||
-            atdwrf(game.loc) > 0) {
-            return GO_UNKNOWN;
-       }
-        obj = game.locs[game.loc].atloc;
-    }
-
-    if (TOTING(obj)) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == MESSAG) {
-        rspeak(REMOVE_MESSAGE);
-        DESTROY(MESSAG);
-        return GO_CLEAROBJ;
-    }
-
-    if (game.objects[obj].fixed != IS_FREE) {
-        switch (obj) {
-        case PLANT:
-            /* Next guard tests whether plant is tiny or stashed */
-            rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY ? DEEP_ROOTS : YOU_JOKING);
-            break;
-        case BEAR:
-            rspeak( game.objects[BEAR].prop == SITTING_BEAR ? BEAR_CHAINED : YOU_JOKING);
-            break;
-        case CHAIN:
-            rspeak( game.objects[BEAR].prop != UNTAMED_BEAR ? STILL_LOCKED : YOU_JOKING);
-            break;
-        case RUG:
-            rspeak(game.objects[RUG].prop == RUG_HOVER ? RUG_HOVERS : YOU_JOKING);
-            break;
-        case URN:
-            rspeak(URN_NOBUDGE);
-            break;
-        case CAVITY:
-            rspeak(DOUGHNUT_HOLES);
-            break;
-        case BLOOD:
-            rspeak(FEW_DROPS);
-            break;
-        case SIGN:
-            rspeak(HAND_PASSTHROUGH);
-            break;
-        default:
-            rspeak(YOU_JOKING);
-        }
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == WATER || obj == OIL) {
-        if (!HERE(BOTTLE) || LIQUID() != obj) {
-            if (!TOTING(BOTTLE)) {
-                rspeak(NO_CONTAINER);
-                return GO_CLEAROBJ;
-            }
-            if (game.objects[BOTTLE].prop == EMPTY_BOTTLE) {
-                return (fill(verb, BOTTLE));
-            } else {
-                rspeak(BOTTLE_FULL);
-           }
-            return GO_CLEAROBJ;
-        }
-        obj = BOTTLE;
-    }
-
-    if (game.holdng >= INVLIMIT) {
-        rspeak(CARRY_LIMIT);
-        return GO_CLEAROBJ;
-
-    }
-
-    if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED && !PROP_IS_STASHED(BIRD)) {
-        if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
-            DESTROY(BIRD);
-            rspeak(BIRD_CRAP);
-            return GO_CLEAROBJ;
-        }
-        if (!TOTING(CAGE)) {
-            rspeak(CANNOT_CARRY);
-            return GO_CLEAROBJ;
-        }
-        if (TOTING(ROD)) {
-            rspeak(BIRD_EVADES);
-            return GO_CLEAROBJ;
-        }
-        game.objects[BIRD].prop = BIRD_CAGED;
-    }
-    if ((obj == BIRD || obj == CAGE) &&
-        (game.objects[BIRD].prop == BIRD_CAGED || PROP_STASHED(BIRD) == BIRD_CAGED)) {
-        /* expression maps BIRD to CAGE and CAGE to BIRD */
-        carry(BIRD + CAGE - obj, game.loc);
-    }
-
-    carry(obj, game.loc);
-
-    if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
-        game.objects[LIQUID()].place = CARRIED;
-    }
-
-    if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
-        PROP_SET_FOUND(obj);
-        game.objects[CAVITY].prop = CAVITY_EMPTY;
-    }
-    rspeak(OK_MAN);
-    return GO_CLEAROBJ;
+       /*  Carry an object.  Special cases for bird and cage (if bird in cage,
+        * can't take one without the other).  Liquids also special, since they
+        * depend on status of bottle.  Also various side effects, etc. */
+       if (obj == INTRANSITIVE) {
+               /*  Carry, no object given yet.  OK if only one object present.
+                */
+               if (game.locs[game.loc].atloc == NO_OBJECT ||
+                   game.link[game.locs[game.loc].atloc] != 0 ||
+                   atdwrf(game.loc) > 0) {
+                       return GO_UNKNOWN;
+               }
+               obj = game.locs[game.loc].atloc;
+       }
+
+       if (TOTING(obj)) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == MESSAG) {
+               rspeak(REMOVE_MESSAGE);
+               DESTROY(MESSAG);
+               return GO_CLEAROBJ;
+       }
+
+       if (game.objects[obj].fixed != IS_FREE) {
+               switch (obj) {
+               case PLANT:
+                       /* Next guard tests whether plant is tiny or stashed */
+                       rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
+                                  ? DEEP_ROOTS
+                                  : YOU_JOKING);
+                       break;
+               case BEAR:
+                       rspeak(game.objects[BEAR].prop == SITTING_BEAR
+                                  ? BEAR_CHAINED
+                                  : YOU_JOKING);
+                       break;
+               case CHAIN:
+                       rspeak(game.objects[BEAR].prop != UNTAMED_BEAR
+                                  ? STILL_LOCKED
+                                  : YOU_JOKING);
+                       break;
+               case RUG:
+                       rspeak(game.objects[RUG].prop == RUG_HOVER
+                                  ? RUG_HOVERS
+                                  : YOU_JOKING);
+                       break;
+               case URN:
+                       rspeak(URN_NOBUDGE);
+                       break;
+               case CAVITY:
+                       rspeak(DOUGHNUT_HOLES);
+                       break;
+               case BLOOD:
+                       rspeak(FEW_DROPS);
+                       break;
+               case SIGN:
+                       rspeak(HAND_PASSTHROUGH);
+                       break;
+               default:
+                       rspeak(YOU_JOKING);
+               }
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == WATER || obj == OIL) {
+               if (!HERE(BOTTLE) || LIQUID() != obj) {
+                       if (!TOTING(BOTTLE)) {
+                               rspeak(NO_CONTAINER);
+                               return GO_CLEAROBJ;
+                       }
+                       if (game.objects[BOTTLE].prop == EMPTY_BOTTLE) {
+                               return (fill(verb, BOTTLE));
+                       } else {
+                               rspeak(BOTTLE_FULL);
+                       }
+                       return GO_CLEAROBJ;
+               }
+               obj = BOTTLE;
+       }
+
+       if (game.holdng >= INVLIMIT) {
+               rspeak(CARRY_LIMIT);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED &&
+           !PROP_IS_STASHED(BIRD)) {
+               if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
+                       DESTROY(BIRD);
+                       rspeak(BIRD_CRAP);
+                       return GO_CLEAROBJ;
+               }
+               if (!TOTING(CAGE)) {
+                       rspeak(CANNOT_CARRY);
+                       return GO_CLEAROBJ;
+               }
+               if (TOTING(ROD)) {
+                       rspeak(BIRD_EVADES);
+                       return GO_CLEAROBJ;
+               }
+               game.objects[BIRD].prop = BIRD_CAGED;
+       }
+       if ((obj == BIRD || obj == CAGE) &&
+           (game.objects[BIRD].prop == BIRD_CAGED ||
+            PROP_STASHED(BIRD) == BIRD_CAGED)) {
+               /* expression maps BIRD to CAGE and CAGE to BIRD */
+               carry(BIRD + CAGE - obj, game.loc);
+       }
+
+       carry(obj, game.loc);
+
+       if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
+               game.objects[LIQUID()].place = CARRIED;
+       }
+
+       if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
+               PROP_SET_FOUND(obj);
+               game.objects[CAVITY].prop = CAVITY_EMPTY;
+       }
+       rspeak(OK_MAN);
+       return GO_CLEAROBJ;
 }
 
 static int chain(verb_t verb) {
-/* Do something to the bear's chain */
-    if (verb != LOCK) {
-        if (game.objects[BEAR].prop == UNTAMED_BEAR) {
-            rspeak(BEAR_BLOCKS);
-            return GO_CLEAROBJ;
-        }
-        if (game.objects[CHAIN].prop == CHAIN_HEAP) {
-            rspeak(ALREADY_UNLOCKED);
-            return GO_CLEAROBJ;
-        }
-        game.objects[CHAIN].prop = CHAIN_HEAP;
-        game.objects[CHAIN].fixed = IS_FREE;
-        if (game.objects[BEAR].prop != BEAR_DEAD)
-            game.objects[BEAR].prop = CONTENTED_BEAR;
-
-        switch (game.objects[BEAR].prop) {
-        // LCOV_EXCL_START
-        case BEAR_DEAD:
-            /* Can't be reached until the bear can die in some way other
-             * than a bridge collapse. Leave in in case this changes, but
-             * exclude from coverage testing. */
-            game.objects[BEAR].fixed = IS_FIXED;
-            break;
-        // LCOV_EXCL_STOP
-        default:
-            game.objects[BEAR].fixed = IS_FREE;
-        }
-        rspeak(CHAIN_UNLOCKED);
-        return GO_CLEAROBJ;
-    }
-
-    if (game.objects[CHAIN].prop != CHAIN_HEAP) {
-        rspeak(ALREADY_LOCKED);
-        return GO_CLEAROBJ;
-    }
-    if (game.loc != objects[CHAIN].plac) {
-        rspeak(NO_LOCKSITE);
-        return GO_CLEAROBJ;
-    }
-
-    game.objects[CHAIN].prop = CHAIN_FIXED;
-
-    if (TOTING(CHAIN))
-        drop(CHAIN, game.loc);
-    game.objects[CHAIN].fixed = IS_FIXED;
-
-    rspeak(CHAIN_LOCKED);
-    return GO_CLEAROBJ;
+       /* Do something to the bear's chain */
+       if (verb != LOCK) {
+               if (game.objects[BEAR].prop == UNTAMED_BEAR) {
+                       rspeak(BEAR_BLOCKS);
+                       return GO_CLEAROBJ;
+               }
+               if (game.objects[CHAIN].prop == CHAIN_HEAP) {
+                       rspeak(ALREADY_UNLOCKED);
+                       return GO_CLEAROBJ;
+               }
+               game.objects[CHAIN].prop = CHAIN_HEAP;
+               game.objects[CHAIN].fixed = IS_FREE;
+               if (game.objects[BEAR].prop != BEAR_DEAD)
+                       game.objects[BEAR].prop = CONTENTED_BEAR;
+
+               switch (game.objects[BEAR].prop) {
+               // LCOV_EXCL_START
+               case BEAR_DEAD:
+                       /* Can't be reached until the bear can die in some way
+                        * other than a bridge collapse. Leave in in case this
+                        * changes, but exclude from coverage testing. */
+                       game.objects[BEAR].fixed = IS_FIXED;
+                       break;
+               // LCOV_EXCL_STOP
+               default:
+                       game.objects[BEAR].fixed = IS_FREE;
+               }
+               rspeak(CHAIN_UNLOCKED);
+               return GO_CLEAROBJ;
+       }
+
+       if (game.objects[CHAIN].prop != CHAIN_HEAP) {
+               rspeak(ALREADY_LOCKED);
+               return GO_CLEAROBJ;
+       }
+       if (game.loc != objects[CHAIN].plac) {
+               rspeak(NO_LOCKSITE);
+               return GO_CLEAROBJ;
+       }
+
+       game.objects[CHAIN].prop = CHAIN_FIXED;
+
+       if (TOTING(CHAIN))
+               drop(CHAIN, game.loc);
+       game.objects[CHAIN].fixed = IS_FIXED;
+
+       rspeak(CHAIN_LOCKED);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t discard(verb_t verb, obj_t obj) {
-/*  Discard object.  "Throw" also comes here for most objects.  Special cases for
- *  bird (might attack snake or dragon) and cage (might contain bird) and vase.
- *  Drop coins at vending machine for extra batteries. */
-    if (obj == ROD && !TOTING(ROD) && TOTING(ROD2)) {
-        obj = ROD2;
-    }
-
-    if (!TOTING(obj)) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-
-    if (GSTONE(obj) && AT(CAVITY) && game.objects[CAVITY].prop != CAVITY_FULL) {
-        rspeak(GEM_FITS);
-        game.objects[obj].prop = STATE_IN_CAVITY;
-        game.objects[CAVITY].prop = CAVITY_FULL;
-        if (HERE(RUG) && ((obj == EMERALD && game.objects[RUG].prop != RUG_HOVER) ||
-                          (obj == RUBY && game.objects[RUG].prop == RUG_HOVER))) {
-           if (obj == RUBY) {
-                 rspeak(RUG_SETTLES);
-           } else if (TOTING(RUG)) {
-                 rspeak(RUG_WIGGLES);
-           } else {
-                 rspeak(RUG_RISES);
-           }
-            if (!TOTING(RUG) || obj == RUBY) {
-                int k = (game.objects[RUG].prop == RUG_HOVER) ? RUG_FLOOR : RUG_HOVER;
-                game.objects[RUG].prop = k;
-                if (k == RUG_HOVER) {
-                    k = objects[SAPPH].plac;
-               }
-                move(RUG + NOBJECTS, k);
-            }
-        }
-        drop(obj, game.loc);
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == COINS && HERE(VEND)) {
-        DESTROY(COINS);
-        drop(BATTERY, game.loc);
-        pspeak(BATTERY, look, true, FRESH_BATTERIES);
-        return GO_CLEAROBJ;
-    }
-
-    if (LIQUID() == obj) {
-        obj = BOTTLE;
-    }
-    if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
-        game.objects[LIQUID()].place = LOC_NOWHERE;
-    }
-
-    if (obj == BEAR && AT(TROLL)) {
-        state_change(TROLL, TROLL_GONE);
-        move(TROLL, LOC_NOWHERE);
-        move(TROLL + NOBJECTS, IS_FREE);
-        move(TROLL2, objects[TROLL].plac);
-        move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
-        juggle(CHASM);
-        drop(obj, game.loc);
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == VASE) {
-        if (game.loc != objects[PILLOW].plac) {
-            state_change(VASE, AT(PILLOW)
-                         ? VASE_WHOLE
-                         : VASE_DROPPED);
-            if (game.objects[VASE].prop != VASE_WHOLE) {
-                game.objects[VASE].fixed = IS_FIXED;
-           }
-            drop(obj, game.loc);
-            return GO_CLEAROBJ;
-        }
-    }
-
-    if (obj == CAGE && game.objects[BIRD].prop == BIRD_CAGED) {
-        drop(BIRD, game.loc);
-    }
-
-    if (obj == BIRD) {
-        if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
-            rspeak(BIRD_BURNT);
-            DESTROY(BIRD);
-            return GO_CLEAROBJ;
-        }
-        if (HERE(SNAKE)) {
-            rspeak(BIRD_ATTACKS);
-            if (game.closed) {
-                return GO_DWARFWAKE;
-           }
-            DESTROY(SNAKE);
-            /* Set game.prop for use by travel options */
-            game.objects[SNAKE].prop = SNAKE_CHASED;
-        } else {
-            rspeak(OK_MAN);
-       }
-
-        game.objects[BIRD].prop = FOREST(game.loc) ? BIRD_FOREST_UNCAGED : BIRD_UNCAGED;
-        drop(obj, game.loc);
-        return GO_CLEAROBJ;
-    }
-
-    rspeak(OK_MAN);
-    drop(obj, game.loc);
-    return GO_CLEAROBJ;
+       /*  Discard object.  "Throw" also comes here for most objects.  Special
+        * cases for bird (might attack snake or dragon) and cage (might contain
+        * bird) and vase. Drop coins at vending machine for extra batteries. */
+       if (obj == ROD && !TOTING(ROD) && TOTING(ROD2)) {
+               obj = ROD2;
+       }
+
+       if (!TOTING(obj)) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+
+       if (GSTONE(obj) && AT(CAVITY) &&
+           game.objects[CAVITY].prop != CAVITY_FULL) {
+               rspeak(GEM_FITS);
+               game.objects[obj].prop = STATE_IN_CAVITY;
+               game.objects[CAVITY].prop = CAVITY_FULL;
+               if (HERE(RUG) &&
+                   ((obj == EMERALD && game.objects[RUG].prop != RUG_HOVER) ||
+                    (obj == RUBY && game.objects[RUG].prop == RUG_HOVER))) {
+                       if (obj == RUBY) {
+                               rspeak(RUG_SETTLES);
+                       } else if (TOTING(RUG)) {
+                               rspeak(RUG_WIGGLES);
+                       } else {
+                               rspeak(RUG_RISES);
+                       }
+                       if (!TOTING(RUG) || obj == RUBY) {
+                               int k = (game.objects[RUG].prop == RUG_HOVER)
+                                           ? RUG_FLOOR
+                                           : RUG_HOVER;
+                               game.objects[RUG].prop = k;
+                               if (k == RUG_HOVER) {
+                                       k = objects[SAPPH].plac;
+                               }
+                               move(RUG + NOBJECTS, k);
+                       }
+               }
+               drop(obj, game.loc);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == COINS && HERE(VEND)) {
+               DESTROY(COINS);
+               drop(BATTERY, game.loc);
+               pspeak(BATTERY, look, true, FRESH_BATTERIES);
+               return GO_CLEAROBJ;
+       }
+
+       if (LIQUID() == obj) {
+               obj = BOTTLE;
+       }
+       if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
+               game.objects[LIQUID()].place = LOC_NOWHERE;
+       }
+
+       if (obj == BEAR && AT(TROLL)) {
+               state_change(TROLL, TROLL_GONE);
+               move(TROLL, LOC_NOWHERE);
+               move(TROLL + NOBJECTS, IS_FREE);
+               move(TROLL2, objects[TROLL].plac);
+               move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
+               juggle(CHASM);
+               drop(obj, game.loc);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == VASE) {
+               if (game.loc != objects[PILLOW].plac) {
+                       state_change(VASE,
+                                    AT(PILLOW) ? VASE_WHOLE : VASE_DROPPED);
+                       if (game.objects[VASE].prop != VASE_WHOLE) {
+                               game.objects[VASE].fixed = IS_FIXED;
+                       }
+                       drop(obj, game.loc);
+                       return GO_CLEAROBJ;
+               }
+       }
+
+       if (obj == CAGE && game.objects[BIRD].prop == BIRD_CAGED) {
+               drop(BIRD, game.loc);
+       }
+
+       if (obj == BIRD) {
+               if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
+                       rspeak(BIRD_BURNT);
+                       DESTROY(BIRD);
+                       return GO_CLEAROBJ;
+               }
+               if (HERE(SNAKE)) {
+                       rspeak(BIRD_ATTACKS);
+                       if (game.closed) {
+                               return GO_DWARFWAKE;
+                       }
+                       DESTROY(SNAKE);
+                       /* Set game.prop for use by travel options */
+                       game.objects[SNAKE].prop = SNAKE_CHASED;
+               } else {
+                       rspeak(OK_MAN);
+               }
+
+               game.objects[BIRD].prop =
+                   FOREST(game.loc) ? BIRD_FOREST_UNCAGED : BIRD_UNCAGED;
+               drop(obj, game.loc);
+               return GO_CLEAROBJ;
+       }
+
+       rspeak(OK_MAN);
+       drop(obj, game.loc);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t drink(verb_t verb, obj_t obj) {
-/*  Drink.  If no object, assume water and look for it here.  If water is in
- *  the bottle, drink that, else must be at a water loc, so drink stream. */
-    if (obj == INTRANSITIVE && LIQLOC(game.loc) != WATER &&
-        (LIQUID() != WATER || !HERE(BOTTLE))) {
-        return GO_UNKNOWN;
-    }
-
-    if (obj == BLOOD) {
-        DESTROY(BLOOD);
-        state_change(DRAGON, DRAGON_BLOODLESS);
-        game.blooded = true;
-        return GO_CLEAROBJ;
-    }
-
-    if (obj != INTRANSITIVE && obj != WATER) {
-        rspeak(RIDICULOUS_ATTEMPT);
-        return GO_CLEAROBJ;
-    }
-    if (LIQUID() == WATER && HERE(BOTTLE)) {
-        game.objects[WATER].place = LOC_NOWHERE;
-        state_change(BOTTLE, EMPTY_BOTTLE);
-        return GO_CLEAROBJ;
-    }
-
-    speak(actions[verb].message);
-    return GO_CLEAROBJ;
+       /*  Drink.  If no object, assume water and look for it here.  If water
+        * is in the bottle, drink that, else must be at a water loc, so drink
+        * stream. */
+       if (obj == INTRANSITIVE && LIQLOC(game.loc) != WATER &&
+           (LIQUID() != WATER || !HERE(BOTTLE))) {
+               return GO_UNKNOWN;
+       }
+
+       if (obj == BLOOD) {
+               DESTROY(BLOOD);
+               state_change(DRAGON, DRAGON_BLOODLESS);
+               game.blooded = true;
+               return GO_CLEAROBJ;
+       }
+
+       if (obj != INTRANSITIVE && obj != WATER) {
+               rspeak(RIDICULOUS_ATTEMPT);
+               return GO_CLEAROBJ;
+       }
+       if (LIQUID() == WATER && HERE(BOTTLE)) {
+               game.objects[WATER].place = LOC_NOWHERE;
+               state_change(BOTTLE, EMPTY_BOTTLE);
+               return GO_CLEAROBJ;
+       }
+
+       speak(actions[verb].message);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t eat(verb_t verb, obj_t obj) {
-/*  Eat.  Intransitive: assume food if present, else ask what.  Transitive: food
- *  ok, some things lose appetite, rest are ridiculous. */
-    switch (obj) {
-    case INTRANSITIVE:
-        if (!HERE(FOOD))
-            return GO_UNKNOWN;
-    /* FALLTHRU */
-    case FOOD:
-        DESTROY(FOOD);
-        rspeak(THANKS_DELICIOUS);
-        break;
-    case BIRD:
-    case SNAKE:
-    case CLAM:
-    case OYSTER:
-    case DWARF:
-    case DRAGON:
-    case TROLL:
-    case BEAR:
-    case OGRE:
-        rspeak(LOST_APPETITE);
-        break;
-    default:
-        speak(actions[verb].message);
-    }
-    return GO_CLEAROBJ;
+       /*  Eat.  Intransitive: assume food if present, else ask what.
+        * Transitive: food ok, some things lose appetite, rest are ridiculous.
+        */
+       switch (obj) {
+       case INTRANSITIVE:
+               if (!HERE(FOOD))
+                       return GO_UNKNOWN;
+       /* FALLTHRU */
+       case FOOD:
+               DESTROY(FOOD);
+               rspeak(THANKS_DELICIOUS);
+               break;
+       case BIRD:
+       case SNAKE:
+       case CLAM:
+       case OYSTER:
+       case DWARF:
+       case DRAGON:
+       case TROLL:
+       case BEAR:
+       case OGRE:
+               rspeak(LOST_APPETITE);
+               break;
+       default:
+               speak(actions[verb].message);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t extinguish(verb_t verb, obj_t obj) {
-/* Extinguish.  Lamp, urn, dragon/volcano (nice try). */
-    if (obj == INTRANSITIVE) {
-       if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_BRIGHT) {
-             obj = LAMP;
+       /* Extinguish.  Lamp, urn, dragon/volcano (nice try). */
+       if (obj == INTRANSITIVE) {
+               if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_BRIGHT) {
+                       obj = LAMP;
+               }
+               if (HERE(URN) && game.objects[URN].prop == URN_LIT) {
+                       obj = URN;
+               }
+               if (obj == INTRANSITIVE) {
+                       return GO_UNKNOWN;
+               }
        }
-       if (HERE(URN) && game.objects[URN].prop == URN_LIT) {
-             obj = URN;
+
+       switch (obj) {
+       case URN:
+               if (game.objects[URN].prop != URN_EMPTY) {
+                       state_change(URN, URN_DARK);
+               } else {
+                       pspeak(URN, change, true, URN_DARK);
+               }
+               break;
+       case LAMP:
+               state_change(LAMP, LAMP_DARK);
+               rspeak(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
+               break;
+       case DRAGON:
+       case VOLCANO:
+               rspeak(BEYOND_POWER);
+               break;
+       default:
+               speak(actions[verb].message);
        }
-       if (obj == INTRANSITIVE) {
-             return GO_UNKNOWN;
-       }
-    }
-
-    switch (obj) {
-    case URN:
-        if (game.objects[URN].prop != URN_EMPTY) {
-            state_change(URN, URN_DARK);
-        } else {
-            pspeak(URN, change, true, URN_DARK);
-        }
-        break;
-    case LAMP:
-        state_change(LAMP, LAMP_DARK);
-        rspeak(DARK(game.loc) ?
-               PITCH_DARK :
-               NO_MESSAGE);
-        break;
-    case DRAGON:
-    case VOLCANO:
-        rspeak(BEYOND_POWER);
-        break;
-    default:
-        speak(actions[verb].message);
-    }
-    return GO_CLEAROBJ;
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t feed(verb_t verb, obj_t obj) {
-/*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf, make him
- *  mad.  Bear, special. */
-    switch (obj) {
-    case BIRD:
-        rspeak(BIRD_PINING);
-        break;
-    case DRAGON:
-       if (game.objects[DRAGON].prop != DRAGON_BARS) {
-             rspeak(RIDICULOUS_ATTEMPT);
-       } else {
-             rspeak(NOTHING_EDIBLE);
-       }
-        break;
-    case SNAKE:
-        if (!game.closed && HERE(BIRD)) {
-            DESTROY(BIRD);
-            rspeak(BIRD_DEVOURED);
-        } else {
-            rspeak(NOTHING_EDIBLE);
-       }
-        break;
-    case TROLL:
-        rspeak(TROLL_VICES);
-        break;
-    case DWARF:
-        if (HERE(FOOD)) {
-            game.dflag += 2;
-            rspeak(REALLY_MAD);
-        } else {
-            speak(actions[verb].message);
-       }
-        break;
-    case BEAR:
-        if (game.objects[BEAR].prop == BEAR_DEAD) {
-            rspeak(RIDICULOUS_ATTEMPT);
-            break;
-        }
-        if (game.objects[BEAR].prop == UNTAMED_BEAR) {
-            if (HERE(FOOD)) {
-                DESTROY(FOOD);
-                game.objects[AXE].fixed = IS_FREE;
-                game.objects[AXE].prop = AXE_HERE;
-                state_change(BEAR, SITTING_BEAR);
-            } else {
-                rspeak(NOTHING_EDIBLE);
-           }
-            break;
-        }
-        speak(actions[verb].message);
-        break;
-    case OGRE:
-       if (HERE(FOOD)) {
-             rspeak(OGRE_FULL);
-       } else {
-             speak(actions[verb].message);
+       /*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf,
+        * make him mad.  Bear, special. */
+       switch (obj) {
+       case BIRD:
+               rspeak(BIRD_PINING);
+               break;
+       case DRAGON:
+               if (game.objects[DRAGON].prop != DRAGON_BARS) {
+                       rspeak(RIDICULOUS_ATTEMPT);
+               } else {
+                       rspeak(NOTHING_EDIBLE);
+               }
+               break;
+       case SNAKE:
+               if (!game.closed && HERE(BIRD)) {
+                       DESTROY(BIRD);
+                       rspeak(BIRD_DEVOURED);
+               } else {
+                       rspeak(NOTHING_EDIBLE);
+               }
+               break;
+       case TROLL:
+               rspeak(TROLL_VICES);
+               break;
+       case DWARF:
+               if (HERE(FOOD)) {
+                       game.dflag += 2;
+                       rspeak(REALLY_MAD);
+               } else {
+                       speak(actions[verb].message);
+               }
+               break;
+       case BEAR:
+               if (game.objects[BEAR].prop == BEAR_DEAD) {
+                       rspeak(RIDICULOUS_ATTEMPT);
+                       break;
+               }
+               if (game.objects[BEAR].prop == UNTAMED_BEAR) {
+                       if (HERE(FOOD)) {
+                               DESTROY(FOOD);
+                               game.objects[AXE].fixed = IS_FREE;
+                               game.objects[AXE].prop = AXE_HERE;
+                               state_change(BEAR, SITTING_BEAR);
+                       } else {
+                               rspeak(NOTHING_EDIBLE);
+                       }
+                       break;
+               }
+               speak(actions[verb].message);
+               break;
+       case OGRE:
+               if (HERE(FOOD)) {
+                       rspeak(OGRE_FULL);
+               } else {
+                       speak(actions[verb].message);
+               }
+               break;
+       default:
+               rspeak(AM_GAME);
        }
-        break;
-    default:
-        rspeak(AM_GAME);
-    }
-    return GO_CLEAROBJ;
+       return GO_CLEAROBJ;
 }
 
 phase_codes_t fill(verb_t verb, obj_t obj) {
-/*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
- *  is nasty.) */
-    if (obj == VASE) {
-        if (LIQLOC(game.loc) == NO_OBJECT) {
-            rspeak(FILL_INVALID);
-            return GO_CLEAROBJ;
-        }
-        if (!TOTING(VASE)) {
-            rspeak(ARENT_CARRYING);
-            return GO_CLEAROBJ;
-        }
-        rspeak(SHATTER_VASE);
-        game.objects[VASE].prop = VASE_BROKEN;
-        game.objects[VASE].fixed = IS_FIXED;
-        drop(VASE, game.loc);
-        return GO_CLEAROBJ;
-    }
-
-    if (obj == URN) {
-        if (game.objects[URN].prop != URN_EMPTY) {
-            rspeak(FULL_URN);
-            return GO_CLEAROBJ;
-        }
-        if (!HERE(BOTTLE)) {
-            rspeak(FILL_INVALID);
-            return GO_CLEAROBJ;
-        }
-        int k = LIQUID();
-        switch (k) {
-        case WATER:
-            game.objects[BOTTLE].prop = EMPTY_BOTTLE;
-            rspeak(WATER_URN);
-            break;
-        case OIL:
-            game.objects[URN].prop = URN_DARK;
-            game.objects[BOTTLE].prop = EMPTY_BOTTLE;
-            rspeak(OIL_URN);
-            break;
-        case NO_OBJECT:
-        default:
-            rspeak(FILL_INVALID);
-            return GO_CLEAROBJ;
-        }
-        game.objects[k].place = LOC_NOWHERE;
-        return GO_CLEAROBJ;
-    }
-    if (obj != INTRANSITIVE && obj != BOTTLE) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-    if (obj == INTRANSITIVE && !HERE(BOTTLE))
-        return GO_UNKNOWN;
-
-    if (HERE(URN) && game.objects[URN].prop != URN_EMPTY) {
-        rspeak(URN_NOPOUR);
-        return GO_CLEAROBJ;
-    }
-    if (LIQUID() != NO_OBJECT) {
-        rspeak(BOTTLE_FULL);
-        return GO_CLEAROBJ;
-    }
-    if (LIQLOC(game.loc) == NO_OBJECT) {
-        rspeak(NO_LIQUID);
-        return GO_CLEAROBJ;
-    }
-
-    state_change(BOTTLE, (LIQLOC(game.loc) == OIL)
-                 ? OIL_BOTTLE
-                 : WATER_BOTTLE);
-    if (TOTING(BOTTLE)) {
-        game.objects[LIQUID()].place = CARRIED;
-    }
-    return GO_CLEAROBJ;
+       /*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
+        *  is nasty.) */
+       if (obj == VASE) {
+               if (LIQLOC(game.loc) == NO_OBJECT) {
+                       rspeak(FILL_INVALID);
+                       return GO_CLEAROBJ;
+               }
+               if (!TOTING(VASE)) {
+                       rspeak(ARENT_CARRYING);
+                       return GO_CLEAROBJ;
+               }
+               rspeak(SHATTER_VASE);
+               game.objects[VASE].prop = VASE_BROKEN;
+               game.objects[VASE].fixed = IS_FIXED;
+               drop(VASE, game.loc);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj == URN) {
+               if (game.objects[URN].prop != URN_EMPTY) {
+                       rspeak(FULL_URN);
+                       return GO_CLEAROBJ;
+               }
+               if (!HERE(BOTTLE)) {
+                       rspeak(FILL_INVALID);
+                       return GO_CLEAROBJ;
+               }
+               int k = LIQUID();
+               switch (k) {
+               case WATER:
+                       game.objects[BOTTLE].prop = EMPTY_BOTTLE;
+                       rspeak(WATER_URN);
+                       break;
+               case OIL:
+                       game.objects[URN].prop = URN_DARK;
+                       game.objects[BOTTLE].prop = EMPTY_BOTTLE;
+                       rspeak(OIL_URN);
+                       break;
+               case NO_OBJECT:
+               default:
+                       rspeak(FILL_INVALID);
+                       return GO_CLEAROBJ;
+               }
+               game.objects[k].place = LOC_NOWHERE;
+               return GO_CLEAROBJ;
+       }
+       if (obj != INTRANSITIVE && obj != BOTTLE) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+       if (obj == INTRANSITIVE && !HERE(BOTTLE))
+               return GO_UNKNOWN;
+
+       if (HERE(URN) && game.objects[URN].prop != URN_EMPTY) {
+               rspeak(URN_NOPOUR);
+               return GO_CLEAROBJ;
+       }
+       if (LIQUID() != NO_OBJECT) {
+               rspeak(BOTTLE_FULL);
+               return GO_CLEAROBJ;
+       }
+       if (LIQLOC(game.loc) == NO_OBJECT) {
+               rspeak(NO_LIQUID);
+               return GO_CLEAROBJ;
+       }
+
+       state_change(BOTTLE,
+                    (LIQLOC(game.loc) == OIL) ? OIL_BOTTLE : WATER_BOTTLE);
+       if (TOTING(BOTTLE)) {
+               game.objects[LIQUID()].place = CARRIED;
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t find(verb_t verb, obj_t obj) {
-/* Find.  Might be carrying it, or it might be here.  Else give caveat. */
-    if (TOTING(obj)) {
-        rspeak(ALREADY_CARRYING);
-        return GO_CLEAROBJ;
-    }
-
-    if (game.closed) {
-        rspeak(NEEDED_NEARBY);
-        return GO_CLEAROBJ;
-    }
-
-    if (AT(obj) || (LIQUID() == obj && AT(BOTTLE)) ||
-        obj == LIQLOC(game.loc) || (obj == DWARF && atdwrf(game.loc) > 0)) {
-        rspeak(YOU_HAVEIT);
-        return GO_CLEAROBJ;
-    }
-
-
-    speak(actions[verb].message);
-    return GO_CLEAROBJ;
+       /* Find.  Might be carrying it, or it might be here.  Else give caveat.
+        */
+       if (TOTING(obj)) {
+               rspeak(ALREADY_CARRYING);
+               return GO_CLEAROBJ;
+       }
+
+       if (game.closed) {
+               rspeak(NEEDED_NEARBY);
+               return GO_CLEAROBJ;
+       }
+
+       if (AT(obj) || (LIQUID() == obj && AT(BOTTLE)) ||
+           obj == LIQLOC(game.loc) || (obj == DWARF && atdwrf(game.loc) > 0)) {
+               rspeak(YOU_HAVEIT);
+               return GO_CLEAROBJ;
+       }
+
+       speak(actions[verb].message);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t fly(verb_t verb, obj_t obj) {
-/* Fly.  Snide remarks unless hovering rug is here. */
-    if (obj == INTRANSITIVE) {
-        if (!HERE(RUG)) {
-            rspeak(FLAP_ARMS);
-            return GO_CLEAROBJ;
-        }
-        if (game.objects[RUG].prop != RUG_HOVER) {
-            rspeak(RUG_NOTHING2);
-            return GO_CLEAROBJ;
-        }
-        obj = RUG;
-    }
-
-    if (obj != RUG) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-    if (game.objects[RUG].prop != RUG_HOVER) {
-        rspeak(RUG_NOTHING1);
-        return GO_CLEAROBJ;
-    }
-
-    if (game.loc == LOC_CLIFF) {
-        game.oldlc2 = game.oldloc;
-        game.oldloc = game.loc;
-        game.newloc = LOC_LEDGE;
-        rspeak(RUG_GOES);
-    } else if (game.loc == LOC_LEDGE) {
-        game.oldlc2 = game.oldloc;
-        game.oldloc = game.loc;
-        game.newloc = LOC_CLIFF;
-        rspeak(RUG_RETURNS);
-    } else {
-// LCOV_EXCL_START
-        /* should never happen */
-        rspeak(NOTHING_HAPPENS);
-// LCOV_EXCL_STOP
-    }
-    return GO_TERMINATE;
+       /* Fly.  Snide remarks unless hovering rug is here. */
+       if (obj == INTRANSITIVE) {
+               if (!HERE(RUG)) {
+                       rspeak(FLAP_ARMS);
+                       return GO_CLEAROBJ;
+               }
+               if (game.objects[RUG].prop != RUG_HOVER) {
+                       rspeak(RUG_NOTHING2);
+                       return GO_CLEAROBJ;
+               }
+               obj = RUG;
+       }
+
+       if (obj != RUG) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+       if (game.objects[RUG].prop != RUG_HOVER) {
+               rspeak(RUG_NOTHING1);
+               return GO_CLEAROBJ;
+       }
+
+       if (game.loc == LOC_CLIFF) {
+               game.oldlc2 = game.oldloc;
+               game.oldloc = game.loc;
+               game.newloc = LOC_LEDGE;
+               rspeak(RUG_GOES);
+       } else if (game.loc == LOC_LEDGE) {
+               game.oldlc2 = game.oldloc;
+               game.oldloc = game.loc;
+               game.newloc = LOC_CLIFF;
+               rspeak(RUG_RETURNS);
+       } else {
+               // LCOV_EXCL_START
+               /* should never happen */
+               rspeak(NOTHING_HAPPENS);
+               // LCOV_EXCL_STOP
+       }
+       return GO_TERMINATE;
 }
 
 static phase_codes_t inven(void) {
-/* Inventory. If object, treat same as find.  Else report on current burden. */
-    bool empty = true;
-    for (obj_t i = 1; i <= NOBJECTS; i++) {
-        if (i == BEAR || !TOTING(i))
-            continue;
-        if (empty) {
-            rspeak(NOW_HOLDING);
-            empty = false;
-        }
-        pspeak(i, touch, false, -1);
-    }
-    if (TOTING(BEAR))
-        rspeak(TAME_BEAR);
-    if (empty)
-        rspeak(NO_CARRY);
-    return GO_CLEAROBJ;
+       /* Inventory. If object, treat same as find.  Else report on current
+        * burden. */
+       bool empty = true;
+       for (obj_t i = 1; i <= NOBJECTS; i++) {
+               if (i == BEAR || !TOTING(i))
+                       continue;
+               if (empty) {
+                       rspeak(NOW_HOLDING);
+                       empty = false;
+               }
+               pspeak(i, touch, false, -1);
+       }
+       if (TOTING(BEAR))
+               rspeak(TAME_BEAR);
+       if (empty)
+               rspeak(NO_CARRY);
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t light(verb_t verb, obj_t obj) {
-/*  Light.  Applicable only to lamp and urn. */
-    if (obj == INTRANSITIVE) {
-        int selects = 0;
-        if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_DARK && game.limit >= 0) {
-            obj = LAMP;
-            selects++;
-        }
-        if (HERE(URN) && game.objects[URN].prop == URN_DARK) {
-            obj =  URN;
-            selects++;
-        }
-        if (selects != 1)
-            return GO_UNKNOWN;
-    }
-
-    switch (obj) {
-    case URN:
-        state_change(URN, game.objects[URN].prop == URN_EMPTY ?
-                     URN_EMPTY :
-                     URN_LIT);
-        break;
-    case LAMP:
-        if (game.limit < 0) {
-            rspeak(LAMP_OUT);
-            break;
-        }
-        state_change(LAMP, LAMP_BRIGHT);
-        if (game.wzdark) {
-            return GO_TOP;
-       }
-        break;
-    default:
-        speak(actions[verb].message);
-    }
-    return GO_CLEAROBJ;
+       /*  Light.  Applicable only to lamp and urn. */
+       if (obj == INTRANSITIVE) {
+               int selects = 0;
+               if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_DARK &&
+                   game.limit >= 0) {
+                       obj = LAMP;
+                       selects++;
+               }
+               if (HERE(URN) && game.objects[URN].prop == URN_DARK) {
+                       obj = URN;
+                       selects++;
+               }
+               if (selects != 1)
+                       return GO_UNKNOWN;
+       }
+
+       switch (obj) {
+       case URN:
+               state_change(URN, game.objects[URN].prop == URN_EMPTY
+                                     ? URN_EMPTY
+                                     : URN_LIT);
+               break;
+       case LAMP:
+               if (game.limit < 0) {
+                       rspeak(LAMP_OUT);
+                       break;
+               }
+               state_change(LAMP, LAMP_BRIGHT);
+               if (game.wzdark) {
+                       return GO_TOP;
+               }
+               break;
+       default:
+               speak(actions[verb].message);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t listen(void) {
-/*  Listen.  Intransitive only.  Print stuff based on object sound properties. */
-    bool soundlatch = false;
-    vocab_t sound = locations[game.loc].sound;
-    if (sound != SILENT) {
-        rspeak(sound);
-        if (!locations[game.loc].loud) {
-            rspeak(NO_MESSAGE);
-       }
-        soundlatch = true;
-    }
-    for (obj_t i = 1; i <= NOBJECTS; i++) {
-       if (!HERE(i) || objects[i].sounds[0] == NULL || PROP_IS_STASHED_OR_UNSEEN(i)) {
-             continue;
-       }
-        int mi =  game.objects[i].prop;
-        /* (ESR) Some unpleasant magic on object states here. Ideally
-         * we'd have liked the bird to be a normal object that we can
-         * use state_change() on; can't do it, because there are
-         * actually two different series of per-state birdsounds
-         * depending on whether player has drunk dragon's blood. */
-        if (i == BIRD) {
-            mi += 3 * game.blooded;
-       }
-        pspeak(i, hear, true, mi, game.zzword);
-        rspeak(NO_MESSAGE);
-        if (i == BIRD && mi == BIRD_ENDSTATE) {
-            DESTROY(BIRD);
-       }
-        soundlatch = true;
-    }
-    if (!soundlatch) {
-        rspeak(ALL_SILENT);
-    }
-    return GO_CLEAROBJ;
+       /*  Listen.  Intransitive only.  Print stuff based on object sound
+        * properties. */
+       bool soundlatch = false;
+       vocab_t sound = locations[game.loc].sound;
+       if (sound != SILENT) {
+               rspeak(sound);
+               if (!locations[game.loc].loud) {
+                       rspeak(NO_MESSAGE);
+               }
+               soundlatch = true;
+       }
+       for (obj_t i = 1; i <= NOBJECTS; i++) {
+               if (!HERE(i) || objects[i].sounds[0] == NULL ||
+                   PROP_IS_STASHED_OR_UNSEEN(i)) {
+                       continue;
+               }
+               int mi = game.objects[i].prop;
+               /* (ESR) Some unpleasant magic on object states here. Ideally
+                * we'd have liked the bird to be a normal object that we can
+                * use state_change() on; can't do it, because there are
+                * actually two different series of per-state birdsounds
+                * depending on whether player has drunk dragon's blood. */
+               if (i == BIRD) {
+                       mi += 3 * game.blooded;
+               }
+               pspeak(i, hear, true, mi, game.zzword);
+               rspeak(NO_MESSAGE);
+               if (i == BIRD && mi == BIRD_ENDSTATE) {
+                       DESTROY(BIRD);
+               }
+               soundlatch = true;
+       }
+       if (!soundlatch) {
+               rspeak(ALL_SILENT);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t lock(verb_t verb, obj_t obj) {
-/* Lock, unlock, no object given.  Assume various things if present. */
-    if (obj == INTRANSITIVE) {
-       if (HERE(CLAM)) {
-             obj = CLAM;
-       }
-       if (HERE(OYSTER)) {
-             obj = OYSTER;
-       }
-       if (AT(DOOR)) {
-             obj = DOOR;
-       }
-       if (AT(GRATE)) {
-             obj = GRATE;
-       }
-       if (HERE(CHAIN)) {
-             obj = CHAIN;
-       }
-        if (obj == INTRANSITIVE) {
-            rspeak(NOTHING_LOCKED);
-            return GO_CLEAROBJ;
-        }
-    }
-
-    /*  Lock, unlock object.  Special stuff for opening clam/oyster
-     *  and for chain. */
-
-    switch (obj) {
-    case CHAIN:
-        if (HERE(KEYS)) {
-            return chain(verb);
-        } else {
-            rspeak(NO_KEYS);
-       }
-        break;
-    case GRATE:
-        if (HERE(KEYS)) {
-            if (game.closng) {
-                rspeak(EXIT_CLOSED);
-                if (!game.panic) {
-                    game.clock2 = PANICTIME;
-               }
-                game.panic = true;
-            } else {
-                state_change(GRATE, (verb == LOCK) ?
-                             GRATE_CLOSED :
-                             GRATE_OPEN);
-            }
-        } else {
-            rspeak(NO_KEYS);
-       }
-        break;
-    case CLAM:
-       if (verb == LOCK) {
-             rspeak(HUH_MAN);
-       } else if (TOTING(CLAM)) {
-             rspeak(DROP_CLAM);
-       } else if (!TOTING(TRIDENT)) {
-             rspeak(CLAM_OPENER);
-       } else {
-            DESTROY(CLAM);
-            drop(OYSTER, game.loc);
-            drop(PEARL, LOC_CULDESAC);
-            rspeak(PEARL_FALLS);
-        }
-        break;
-    case OYSTER:
-       if (verb == LOCK) {
-             rspeak(HUH_MAN);
-       } else if (TOTING(OYSTER)) {
-             rspeak(DROP_OYSTER);
-       } else if (!TOTING(TRIDENT)) {
-             rspeak(OYSTER_OPENER);
-       } else {
-             rspeak(OYSTER_OPENS);
-       }
-        break;
-    case DOOR:
-        rspeak((game.objects[DOOR].prop == DOOR_UNRUSTED) ? OK_MAN : RUSTY_DOOR);
-        break;
-    case CAGE:
-        rspeak( NO_LOCK);
-        break;
-    case KEYS:
-        rspeak(CANNOT_UNLOCK);
-        break;
-    default:
-        speak(actions[verb].message);
-    }
-
-    return GO_CLEAROBJ;
+       /* Lock, unlock, no object given.  Assume various things if present. */
+       if (obj == INTRANSITIVE) {
+               if (HERE(CLAM)) {
+                       obj = CLAM;
+               }
+               if (HERE(OYSTER)) {
+                       obj = OYSTER;
+               }
+               if (AT(DOOR)) {
+                       obj = DOOR;
+               }
+               if (AT(GRATE)) {
+                       obj = GRATE;
+               }
+               if (HERE(CHAIN)) {
+                       obj = CHAIN;
+               }
+               if (obj == INTRANSITIVE) {
+                       rspeak(NOTHING_LOCKED);
+                       return GO_CLEAROBJ;
+               }
+       }
+
+       /*  Lock, unlock object.  Special stuff for opening clam/oyster
+        *  and for chain. */
+
+       switch (obj) {
+       case CHAIN:
+               if (HERE(KEYS)) {
+                       return chain(verb);
+               } else {
+                       rspeak(NO_KEYS);
+               }
+               break;
+       case GRATE:
+               if (HERE(KEYS)) {
+                       if (game.closng) {
+                               rspeak(EXIT_CLOSED);
+                               if (!game.panic) {
+                                       game.clock2 = PANICTIME;
+                               }
+                               game.panic = true;
+                       } else {
+                               state_change(GRATE, (verb == LOCK)
+                                                       ? GRATE_CLOSED
+                                                       : GRATE_OPEN);
+                       }
+               } else {
+                       rspeak(NO_KEYS);
+               }
+               break;
+       case CLAM:
+               if (verb == LOCK) {
+                       rspeak(HUH_MAN);
+               } else if (TOTING(CLAM)) {
+                       rspeak(DROP_CLAM);
+               } else if (!TOTING(TRIDENT)) {
+                       rspeak(CLAM_OPENER);
+               } else {
+                       DESTROY(CLAM);
+                       drop(OYSTER, game.loc);
+                       drop(PEARL, LOC_CULDESAC);
+                       rspeak(PEARL_FALLS);
+               }
+               break;
+       case OYSTER:
+               if (verb == LOCK) {
+                       rspeak(HUH_MAN);
+               } else if (TOTING(OYSTER)) {
+                       rspeak(DROP_OYSTER);
+               } else if (!TOTING(TRIDENT)) {
+                       rspeak(OYSTER_OPENER);
+               } else {
+                       rspeak(OYSTER_OPENS);
+               }
+               break;
+       case DOOR:
+               rspeak((game.objects[DOOR].prop == DOOR_UNRUSTED) ? OK_MAN
+                                                                 : RUSTY_DOOR);
+               break;
+       case CAGE:
+               rspeak(NO_LOCK);
+               break;
+       case KEYS:
+               rspeak(CANNOT_UNLOCK);
+               break;
+       default:
+               speak(actions[verb].message);
+       }
+
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t pour(verb_t verb, obj_t obj) {
-/*  Pour.  If no object, or object is bottle, assume contents of bottle.
- *  special tests for pouring water or oil on plant or rusty door. */
-    if (obj == BOTTLE || obj == INTRANSITIVE) {
-         obj = LIQUID();
-    }
-    if (obj == NO_OBJECT) {
-         return GO_UNKNOWN;
-    }
-    if (!TOTING(obj)) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-
-    if (obj != OIL && obj != WATER) {
-        rspeak(CANT_POUR);
-        return GO_CLEAROBJ;
-    }
-    if (HERE(URN) && game.objects[URN].prop == URN_EMPTY) {
-        return fill(verb, URN);
-    }
-    game.objects[BOTTLE].prop = EMPTY_BOTTLE;
-    game.objects[obj].place = LOC_NOWHERE;
-    if (!(AT(PLANT) || AT(DOOR))) {
-        rspeak(GROUND_WET);
-        return GO_CLEAROBJ;
-    }
-    if (!AT(DOOR)) {
-        if (obj == WATER) {
-            /* cycle through the three plant states */
-            state_change(PLANT, MOD(game.objects[PLANT].prop + 1, 3));
-            game.objects[PLANT2].prop = game.objects[PLANT].prop;
-            return GO_MOVE;
-        } else {
-            rspeak(SHAKING_LEAVES);
-            return GO_CLEAROBJ;
-        }
-    } else {
-        state_change(DOOR, (obj == OIL) ?
-                     DOOR_UNRUSTED :
-                     DOOR_RUSTED);
-        return GO_CLEAROBJ;
-    }
+       /*  Pour.  If no object, or object is bottle, assume contents of bottle.
+        *  special tests for pouring water or oil on plant or rusty door. */
+       if (obj == BOTTLE || obj == INTRANSITIVE) {
+               obj = LIQUID();
+       }
+       if (obj == NO_OBJECT) {
+               return GO_UNKNOWN;
+       }
+       if (!TOTING(obj)) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+
+       if (obj != OIL && obj != WATER) {
+               rspeak(CANT_POUR);
+               return GO_CLEAROBJ;
+       }
+       if (HERE(URN) && game.objects[URN].prop == URN_EMPTY) {
+               return fill(verb, URN);
+       }
+       game.objects[BOTTLE].prop = EMPTY_BOTTLE;
+       game.objects[obj].place = LOC_NOWHERE;
+       if (!(AT(PLANT) || AT(DOOR))) {
+               rspeak(GROUND_WET);
+               return GO_CLEAROBJ;
+       }
+       if (!AT(DOOR)) {
+               if (obj == WATER) {
+                       /* cycle through the three plant states */
+                       state_change(PLANT,
+                                    MOD(game.objects[PLANT].prop + 1, 3));
+                       game.objects[PLANT2].prop = game.objects[PLANT].prop;
+                       return GO_MOVE;
+               } else {
+                       rspeak(SHAKING_LEAVES);
+                       return GO_CLEAROBJ;
+               }
+       } else {
+               state_change(DOOR, (obj == OIL) ? DOOR_UNRUSTED : DOOR_RUSTED);
+               return GO_CLEAROBJ;
+       }
 }
 
 static phase_codes_t quit(void) {
-/*  Quit.  Intransitive only.  Verify intent and exit if that's what he wants. */
-    if (yes_or_no(arbitrary_messages[REALLY_QUIT], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN])) {
-         terminate(quitgame);
-    }
-    return GO_CLEAROBJ;
+       /*  Quit.  Intransitive only.  Verify intent and exit if that's what he
+        * wants. */
+       if (yes_or_no(arbitrary_messages[REALLY_QUIT],
+                     arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN])) {
+               terminate(quitgame);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t read(command_t command)
 /*  Read.  Print stuff based on objtxt.  Oyster (?) is special case. */
 {
-    if (command.obj == INTRANSITIVE) {
-        command.obj = NO_OBJECT;
-        for (int i = 1; i <= NOBJECTS; i++) {
-           if (HERE(i) && objects[i].texts[0] != NULL && !PROP_IS_STASHED(i)) {
-                 command.obj = command.obj * NOBJECTS + i;
-           }
-        }
-        if (command.obj > NOBJECTS || command.obj == NO_OBJECT || DARK(game.loc)) {
-            return GO_UNKNOWN;
-       }
-    }
-
-    if (DARK(game.loc)) {
-        sspeak(NO_SEE, command.word[0].raw);
-    } else if (command.obj == OYSTER) {
-        if (!TOTING(OYSTER) || !game.closed) {
-            rspeak(DONT_UNDERSTAND);
-        } else if (!game.clshnt) {
-            game.clshnt = yes_or_no(arbitrary_messages[CLUE_QUERY], arbitrary_messages[WAYOUT_CLUE], arbitrary_messages[OK_MAN]);
-        } else {
-            pspeak(OYSTER, hear, true, 1);     // Not really a sound, but oh well.
-        }
-    } else if (objects[command.obj].texts[0] == NULL || PROP_IS_NOTFOUND(command.obj)) {
-        speak(actions[command.verb].message);
-    } else {
-        pspeak(command.obj, study, true, game.objects[command.obj].prop);
-    }
-    return GO_CLEAROBJ;
+       if (command.obj == INTRANSITIVE) {
+               command.obj = NO_OBJECT;
+               for (int i = 1; i <= NOBJECTS; i++) {
+                       if (HERE(i) && objects[i].texts[0] != NULL &&
+                           !PROP_IS_STASHED(i)) {
+                               command.obj = command.obj * NOBJECTS + i;
+                       }
+               }
+               if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
+                   DARK(game.loc)) {
+                       return GO_UNKNOWN;
+               }
+       }
+
+       if (DARK(game.loc)) {
+               sspeak(NO_SEE, command.word[0].raw);
+       } else if (command.obj == OYSTER) {
+               if (!TOTING(OYSTER) || !game.closed) {
+                       rspeak(DONT_UNDERSTAND);
+               } else if (!game.clshnt) {
+                       game.clshnt = yes_or_no(arbitrary_messages[CLUE_QUERY],
+                                               arbitrary_messages[WAYOUT_CLUE],
+                                               arbitrary_messages[OK_MAN]);
+               } else {
+                       pspeak(OYSTER, hear, true,
+                              1); // Not really a sound, but oh well.
+               }
+       } else if (objects[command.obj].texts[0] == NULL ||
+                  PROP_IS_NOTFOUND(command.obj)) {
+               speak(actions[command.verb].message);
+       } else {
+               pspeak(command.obj, study, true,
+                      game.objects[command.obj].prop);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t reservoir(void) {
-/*  Z'ZZZ (word gets recomputed at startup; different each game). */
-    if (!AT(RESER) && game.loc != LOC_RESBOTTOM) {
-        rspeak(NOTHING_HAPPENS);
-        return GO_CLEAROBJ;
-    } else {
-        state_change(RESER,
-                     game.objects[RESER].prop == WATERS_PARTED ? WATERS_UNPARTED : WATERS_PARTED);
-        if (AT(RESER))
-            return GO_CLEAROBJ;
-        else {
-            game.oldlc2 = game.loc;
-            game.newloc = LOC_NOWHERE;
-            rspeak(NOT_BRIGHT);
-            return GO_TERMINATE;
-        }
-    }
+       /*  Z'ZZZ (word gets recomputed at startup; different each game). */
+       if (!AT(RESER) && game.loc != LOC_RESBOTTOM) {
+               rspeak(NOTHING_HAPPENS);
+               return GO_CLEAROBJ;
+       } else {
+               state_change(RESER, game.objects[RESER].prop == WATERS_PARTED
+                                       ? WATERS_UNPARTED
+                                       : WATERS_PARTED);
+               if (AT(RESER))
+                       return GO_CLEAROBJ;
+               else {
+                       game.oldlc2 = game.loc;
+                       game.newloc = LOC_NOWHERE;
+                       rspeak(NOT_BRIGHT);
+                       return GO_TERMINATE;
+               }
+       }
 }
 
 static phase_codes_t rub(verb_t verb, obj_t obj) {
-/* Rub.  Yields various snide remarks except for lit urn. */
-    if (obj == URN && game.objects[URN].prop == URN_LIT) {
-        DESTROY(URN);
-        drop(AMBER, game.loc);
-        game.objects[AMBER].prop = AMBER_IN_ROCK;
-        --game.tally;
-        drop(CAVITY, game.loc);
-        rspeak(URN_GENIES);
-    } else if (obj != LAMP) {
-        rspeak(PECULIAR_NOTHING);
-    } else {
-        speak(actions[verb].message);
-    }
-    return GO_CLEAROBJ;
+       /* Rub.  Yields various snide remarks except for lit urn. */
+       if (obj == URN && game.objects[URN].prop == URN_LIT) {
+               DESTROY(URN);
+               drop(AMBER, game.loc);
+               game.objects[AMBER].prop = AMBER_IN_ROCK;
+               --game.tally;
+               drop(CAVITY, game.loc);
+               rspeak(URN_GENIES);
+       } else if (obj != LAMP) {
+               rspeak(PECULIAR_NOTHING);
+       } else {
+               speak(actions[verb].message);
+       }
+       return GO_CLEAROBJ;
 }
 
 static phase_codes_t say(command_t command) {
-/* Say.  Echo WD2. Magic words override. */
-    if (command.word[1].type == MOTION &&
-        (command.word[1].id == XYZZY ||
-         command.word[1].id == PLUGH ||
-         command.word[1].id == PLOVER)) {
-        return GO_WORD2;
-    }
-    if (command.word[1].type == ACTION && command.word[1].id == PART) {
-        return reservoir();
-    }
-
-    if (command.word[1].type == ACTION &&
-        (command.word[1].id == FEE ||
-         command.word[1].id == FIE ||
-         command.word[1].id == FOE ||
-         command.word[1].id == FOO ||
-         command.word[1].id == FUM ||
-         command.word[1].id == PART)) {
-        return bigwords(command.word[1].id);
-    }
-    sspeak(OKEY_DOKEY, command.word[1].raw);
-    return GO_CLEAROBJ;
+       /* Say.  Echo WD2. Magic words override. */
+       if (command.word[1].type == MOTION &&
+           (command.word[1].id == XYZZY || command.word[1].id == PLUGH ||
+            command.word[1].id == PLOVER)) {
+               return GO_WORD2;
+       }
+       if (command.word[1].type == ACTION && command.word[1].id == PART) {
+               return reservoir();
+       }
+
+       if (command.word[1].type == ACTION &&
+           (command.word[1].id == FEE || command.word[1].id == FIE ||
+            command.word[1].id == FOE || command.word[1].id == FOO ||
+            command.word[1].id == FUM || command.word[1].id == PART)) {
+               return bigwords(command.word[1].id);
+       }
+       sspeak(OKEY_DOKEY, command.word[1].raw);
+       return GO_CLEAROBJ;
 }
 
-static phase_codes_t throw_support(vocab_t spk)
-{
-    rspeak(spk);
-    drop(AXE, game.loc);
-    return GO_MOVE;
+static phase_codes_t throw_support(vocab_t spk) {
+       rspeak(spk);
+       drop(AXE, game.loc);
+       return GO_MOVE;
 }
 
 static phase_codes_t throwit(command_t command) {
-/*  Throw.  Same as discard unless axe.  Then same as attack except
- *  ignore bird, and if dwarf is present then one might be killed.
- *  (Only way to do so!)  Axe also special for dragon, bear, and
- *  troll.  Treasures special for troll. */
-    if (!TOTING(command.obj)) {
-        speak(actions[command.verb].message);
-        return GO_CLEAROBJ;
-    }
-    if (objects[command.obj].is_treasure && AT(TROLL)) {
-        /*  Snarf a treasure for the troll. */
-        drop(command.obj, LOC_NOWHERE);
-        move(TROLL, LOC_NOWHERE);
-        move(TROLL + NOBJECTS, IS_FREE);
-        drop(TROLL2, objects[TROLL].plac);
-        drop(TROLL2 + NOBJECTS, objects[TROLL].fixd);
-        juggle(CHASM);
-        rspeak(TROLL_SATISFIED);
-        return GO_CLEAROBJ;
-    }
-    if (command.obj == FOOD && HERE(BEAR)) {
-        /* But throwing food is another story. */
-        command.obj = BEAR;
-        return (feed(command.verb, command.obj));
-    }
-    if (command.obj != AXE) {
-        return (discard(command.verb, command.obj));
-    } else {
-        if (atdwrf(game.loc) <= 0) {
-            if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS)
-                return throw_support(DRAGON_SCALES);
-            if (AT(TROLL)) {
-               return throw_support(TROLL_RETURNS);
-           }
-            if (AT(OGRE)) {
-                return throw_support(OGRE_DODGE);
-           }
-            if (HERE(BEAR) && game.objects[BEAR].prop == UNTAMED_BEAR) {
-                /* This'll teach him to throw the axe at the bear! */
-                drop(AXE, game.loc);
-                game.objects[AXE].fixed = IS_FIXED;
-                juggle(BEAR);
-                state_change(AXE, AXE_LOST);
-                return GO_CLEAROBJ;
-            }
-            command.obj = INTRANSITIVE;
-            return (attack(command));
-        }
-
-        if (randrange(NDWARVES + 1) < game.dflag) {
-            return throw_support(DWARF_DODGES);
-        } else {
-            int i = atdwrf(game.loc);
-            game.dwarves[i].seen = false;
-            game.dwarves[i].loc = LOC_NOWHERE;
-            return throw_support((++game.dkill == 1) ?
-                                 DWARF_SMOKE :
-                                 KILLED_DWARF);
-        }
-    }
+       /*  Throw.  Same as discard unless axe.  Then same as attack except
+        *  ignore bird, and if dwarf is present then one might be killed.
+        *  (Only way to do so!)  Axe also special for dragon, bear, and
+        *  troll.  Treasures special for troll. */
+       if (!TOTING(command.obj)) {
+               speak(actions[command.verb].message);
+               return GO_CLEAROBJ;
+       }
+       if (objects[command.obj].is_treasure && AT(TROLL)) {
+               /*  Snarf a treasure for the troll. */
+               drop(command.obj, LOC_NOWHERE);
+               move(TROLL, LOC_NOWHERE);
+               move(TROLL + NOBJECTS, IS_FREE);
+               drop(TROLL2, objects[TROLL].plac);
+               drop(TROLL2 + NOBJECTS, objects[TROLL].fixd);
+               juggle(CHASM);
+               rspeak(TROLL_SATISFIED);
+               return GO_CLEAROBJ;
+       }
+       if (command.obj == FOOD && HERE(BEAR)) {
+               /* But throwing food is another story. */
+               command.obj = BEAR;
+               return (feed(command.verb, command.obj));
+       }
+       if (command.obj != AXE) {
+               return (discard(command.verb, command.obj));
+       } else {
+               if (atdwrf(game.loc) <= 0) {
+                       if (AT(DRAGON) &&
+                           game.objects[DRAGON].prop == DRAGON_BARS)
+                               return throw_support(DRAGON_SCALES);
+                       if (AT(TROLL)) {
+                               return throw_support(TROLL_RETURNS);
+                       }
+                       if (AT(OGRE)) {
+                               return throw_support(OGRE_DODGE);
+                       }
+                       if (HERE(BEAR) &&
+                           game.objects[BEAR].prop == UNTAMED_BEAR) {
+                               /* This'll teach him to throw the axe at the
+                                * bear! */
+                               drop(AXE, game.loc);
+                               game.objects[AXE].fixed = IS_FIXED;
+                               juggle(BEAR);
+                               state_change(AXE, AXE_LOST);
+                               return GO_CLEAROBJ;
+                       }
+                       command.obj = INTRANSITIVE;
+                       return (attack(command));
+               }
+
+               if (randrange(NDWARVES + 1) < game.dflag) {
+                       return throw_support(DWARF_DODGES);
+               } else {
+                       int i = atdwrf(game.loc);
+                       game.dwarves[i].seen = false;
+                       game.dwarves[i].loc = LOC_NOWHERE;
+                       return throw_support(
+                           (++game.dkill == 1) ? DWARF_SMOKE : KILLED_DWARF);
+               }
+       }
 }
 
 static phase_codes_t wake(verb_t verb, obj_t obj) {
-/* Wake.  Only use is to disturb the dwarves. */
-    if (obj != DWARF || !game.closed) {
-        speak(actions[verb].message);
-        return GO_CLEAROBJ;
-    } else {
-        rspeak(PROD_DWARF);
-        return GO_DWARFWAKE;
-    }
+       /* Wake.  Only use is to disturb the dwarves. */
+       if (obj != DWARF || !game.closed) {
+               speak(actions[verb].message);
+               return GO_CLEAROBJ;
+       } else {
+               rspeak(PROD_DWARF);
+               return GO_DWARFWAKE;
+       }
 }
 
 static phase_codes_t seed(verb_t verb, const char *arg) {
-/* Set seed */
-    int32_t seed = strtol(arg, NULL, 10);
-    speak(actions[verb].message, seed);
-    set_seed(seed);
-    --game.turns;
-    return GO_TOP;
+       /* Set seed */
+       int32_t seed = strtol(arg, NULL, 10);
+       speak(actions[verb].message, seed);
+       set_seed(seed);
+       --game.turns;
+       return GO_TOP;
 }
 
 static phase_codes_t waste(verb_t verb, turn_t turns) {
-/* Burn turns */
-    game.limit -= turns;
-    speak(actions[verb].message, (int)game.limit);
-    return GO_TOP;
+       /* Burn turns */
+       game.limit -= turns;
+       speak(actions[verb].message, (int)game.limit);
+       return GO_TOP;
 }
 
 static phase_codes_t wave(verb_t verb, obj_t obj) {
-/* Wave.  No effect unless waving rod at fissure or at bird. */
-    if (obj != ROD || !TOTING(obj) || (!HERE(BIRD) && (game.closng || !AT(FISSURE)))) {
-        speak(((!TOTING(obj)) && (obj != ROD ||
-                                  !TOTING(ROD2))) ?
-              arbitrary_messages[ARENT_CARRYING] :
-              actions[verb].message);
-        return GO_CLEAROBJ;
-    }
-
-    if (game.objects[BIRD].prop == BIRD_UNCAGED && game.loc == game.objects[STEPS].place
-       && PROP_IS_NOTFOUND(JADE)) {
-        drop(JADE, game.loc);
-        PROP_SET_FOUND(JADE);
-        --game.tally;
-        rspeak(NECKLACE_FLY);
-        return GO_CLEAROBJ;
-    } else {
-        if (game.closed) {
-            rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
-                   CAGE_FLY :
-                   FREE_FLY);
-            return GO_DWARFWAKE;
-        }
-        if (game.closng || !AT(FISSURE)) {
-            rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
-                   CAGE_FLY :
-                   FREE_FLY);
-            return GO_CLEAROBJ;
-        }
-        if (HERE(BIRD))
-            rspeak((game.objects[BIRD].prop == BIRD_CAGED) ?
-                   CAGE_FLY :
-                   FREE_FLY);
-
-        state_change(FISSURE,
-                     game.objects[FISSURE].prop == BRIDGED ? UNBRIDGED : BRIDGED);
-        return GO_CLEAROBJ;
-    }
+       /* Wave.  No effect unless waving rod at fissure or at bird. */
+       if (obj != ROD || !TOTING(obj) ||
+           (!HERE(BIRD) && (game.closng || !AT(FISSURE)))) {
+               speak(((!TOTING(obj)) && (obj != ROD || !TOTING(ROD2)))
+                         ? arbitrary_messages[ARENT_CARRYING]
+                         : actions[verb].message);
+               return GO_CLEAROBJ;
+       }
+
+       if (game.objects[BIRD].prop == BIRD_UNCAGED &&
+           game.loc == game.objects[STEPS].place && PROP_IS_NOTFOUND(JADE)) {
+               drop(JADE, game.loc);
+               PROP_SET_FOUND(JADE);
+               --game.tally;
+               rspeak(NECKLACE_FLY);
+               return GO_CLEAROBJ;
+       } else {
+               if (game.closed) {
+                       rspeak((game.objects[BIRD].prop == BIRD_CAGED)
+                                  ? CAGE_FLY
+                                  : FREE_FLY);
+                       return GO_DWARFWAKE;
+               }
+               if (game.closng || !AT(FISSURE)) {
+                       rspeak((game.objects[BIRD].prop == BIRD_CAGED)
+                                  ? CAGE_FLY
+                                  : FREE_FLY);
+                       return GO_CLEAROBJ;
+               }
+               if (HERE(BIRD))
+                       rspeak((game.objects[BIRD].prop == BIRD_CAGED)
+                                  ? CAGE_FLY
+                                  : FREE_FLY);
+
+               state_change(FISSURE, game.objects[FISSURE].prop == BRIDGED
+                                         ? UNBRIDGED
+                                         : BRIDGED);
+               return GO_CLEAROBJ;
+       }
 }
 
 phase_codes_t action(command_t command) {
-/*  Analyse a verb.  Remember what it was, go back for object if second word
- *  unless verb is "say", which snarfs arbitrary second word.
- */
-    /* Previously, actions that result in a message, but don't do anything
-     * further were called "specials". Now they're handled here as normal
-     * actions. If noaction is true, then we spit out the message and return */
-    if (actions[command.verb].noaction) {
-        speak(actions[command.verb].message);
-        return GO_CLEAROBJ;
-    }
-
-    if (command.part == unknown) {
-        /*  Analyse an object word.  See if the thing is here, whether
-         *  we've got a verb yet, and so on.  Object must be here
-         *  unless verb is "find" or "invent(ory)" (and no new verb
-         *  yet to be analysed).  Water and oil are also funny, since
-         *  they are never actually dropped at any location, but might
-         *  be here inside the bottle or urn or as a feature of the
-         *  location. */
-       if (HERE(command.obj)) {
-             /* FALL THROUGH */;
-       } else if (command.obj == DWARF && atdwrf(game.loc) > 0) {
-             /* FALL THROUGH */;
-       } else if (!game.closed && ((LIQUID() == command.obj && HERE(BOTTLE)) ||
-                                   command.obj == LIQLOC(game.loc))) {
-             /* FALL THROUGH */;
-       } else if (command.obj == OIL && HERE(URN) && game.objects[URN].prop != URN_EMPTY) {
-            command.obj = URN;
-            /* FALL THROUGH */;
-        } else if (command.obj == PLANT && AT(PLANT2) && game.objects[PLANT2].prop != PLANT_THIRSTY) {
-            command.obj = PLANT2;
-            /* FALL THROUGH */;
-        } else if (command.obj == KNIFE && game.knfloc == game.loc) {
-            game.knfloc = -1;
-            rspeak(KNIVES_VANISH);
-            return GO_CLEAROBJ;
-        } else if (command.obj == ROD && HERE(ROD2)) {
-            command.obj = ROD2;
-            /* FALL THROUGH */;
-        } else if ((command.verb == FIND ||
-                    command.verb == INVENTORY) && (command.word[1].id == WORD_EMPTY || command.word[1].id == WORD_NOT_FOUND)) {
-            /* FALL THROUGH */;
-        } else {
-            sspeak(NO_SEE, command.word[0].raw);
-            return GO_CLEAROBJ;
-        }
-
-        if (command.verb != 0) {
-            command.part = transitive;
-       }
-    }
-
-    switch (command.part) {
-    case intransitive:
-       if (command.word[1].raw[0] != '\0' && command.verb != SAY) {
-             return GO_WORD2;
-       }
-       if (command.verb == SAY) {
-             /* KEYS is not special, anything not NO_OBJECT or INTRANSITIVE
-              * will do here. We're preventing interpretation as an intransitive
-              * verb when the word is unknown. */
-             command.obj = command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
-       }
-        if (command.obj == NO_OBJECT || command.obj == INTRANSITIVE) {
-            /*  Analyse an intransitive verb (ie, no object given yet). */
-            switch (command.verb) {
-            case CARRY:
-                return vcarry(command.verb, INTRANSITIVE);
-            case  DROP:
-                return GO_UNKNOWN;
-            case  SAY:
-                return GO_UNKNOWN;
-            case  UNLOCK:
-                return lock(command.verb, INTRANSITIVE);
-            case  NOTHING: {
-                rspeak(OK_MAN);
-                return (GO_CLEAROBJ);
-            }
-            case  LOCK:
-                return lock(command.verb, INTRANSITIVE);
-            case  LIGHT:
-                return light(command.verb, INTRANSITIVE);
-            case  EXTINGUISH:
-                return extinguish(command.verb, INTRANSITIVE);
-            case  WAVE:
-                return GO_UNKNOWN;
-            case  TAME:
-                return GO_UNKNOWN;
-            case GO: {
-                speak(actions[command.verb].message);
-                return GO_CLEAROBJ;
-            }
-            case ATTACK:
-                command.obj = INTRANSITIVE;
-                return attack(command);
-            case POUR:
-                return pour(command.verb, INTRANSITIVE);
-            case EAT:
-                return eat(command.verb, INTRANSITIVE);
-            case DRINK:
-                return drink(command.verb, INTRANSITIVE);
-            case RUB:
-                return GO_UNKNOWN;
-            case THROW:
-                return GO_UNKNOWN;
-            case QUIT:
-                return quit();
-            case FIND:
-                return GO_UNKNOWN;
-            case INVENTORY:
-                return inven();
-            case FEED:
-                return GO_UNKNOWN;
-            case FILL:
-                return fill(command.verb, INTRANSITIVE);
-            case BLAST:
-                blast();
-                return GO_CLEAROBJ;
-            case SCORE:
-                score(scoregame);
-                return GO_CLEAROBJ;
-            case FEE:
-            case FIE:
-            case FOE:
-            case FOO:
-            case FUM:
-                return bigwords(command.word[0].id);
-            case BRIEF:
-                return brief();
-            case READ:
-                command.obj = INTRANSITIVE;
-                return read(command);
-            case BREAK:
-                return GO_UNKNOWN;
-            case WAKE:
-                return GO_UNKNOWN;
-            case SAVE:
-                return suspend();
-            case RESUME:
-                return resume();
-            case FLY:
-                return fly(command.verb, INTRANSITIVE);
-            case LISTEN:
-                return listen();
-            case PART:
-                return reservoir();
-            case SEED:
-            case WASTE:
-                rspeak(NUMERIC_REQUIRED);
-                return GO_TOP;
-            default: // LCOV_EXCL_LINE
-                BUG(INTRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
-            }
-        }
-    /* FALLTHRU */
-    case transitive:
-        /*  Analyse a transitive verb. */
-        switch (command.verb) {
-        case  CARRY:
-            return vcarry(command.verb, command.obj);
-        case  DROP:
-            return discard(command.verb, command.obj);
-        case  SAY:
-            return say(command);
-        case  UNLOCK:
-            return lock(command.verb, command.obj);
-        case  NOTHING: {
-            rspeak(OK_MAN);
-            return (GO_CLEAROBJ);
-        }
-        case  LOCK:
-            return lock(command.verb, command.obj);
-        case LIGHT:
-            return light(command.verb, command.obj);
-        case EXTINGUISH:
-            return extinguish(command.verb, command.obj);
-        case WAVE:
-            return wave(command.verb, command.obj);
-        case TAME: {
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        }
-        case GO: {
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        }
-        case ATTACK:
-            return attack(command);
-        case POUR:
-            return pour(command.verb, command.obj);
-        case EAT:
-            return eat(command.verb, command.obj);
-        case DRINK:
-            return drink(command.verb, command.obj);
-        case RUB:
-            return rub(command.verb, command.obj);
-        case THROW:
-            return throwit(command);
-        case QUIT:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case FIND:
-            return find(command.verb, command.obj);
-        case INVENTORY:
-            return find(command.verb, command.obj);
-        case FEED:
-            return feed(command.verb, command.obj);
-        case FILL:
-            return fill(command.verb, command.obj);
-        case BLAST:
-            blast();
-            return GO_CLEAROBJ;
-        case SCORE:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case FEE:
-        case FIE:
-        case FOE:
-        case FOO:
-        case FUM:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case BRIEF:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case READ:
-            return read(command);
-        case BREAK:
-            return vbreak(command.verb, command.obj);
-        case WAKE:
-            return wake(command.verb, command.obj);
-        case SAVE:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case RESUME:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        case FLY:
-            return fly(command.verb, command.obj);
-        case LISTEN:
-            speak(actions[command.verb].message);
-            return GO_CLEAROBJ;
-        // LCOV_EXCL_START
-        // This case should never happen - here only as placeholder
-        case PART:
-            return reservoir();
-        // LCOV_EXCL_STOP
-        case SEED:
-            return seed(command.verb, command.word[1].raw);
-        case WASTE:
-            return waste(command.verb, (turn_t)atol(command.word[1].raw));
-        default: // LCOV_EXCL_LINE
-            BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
-        }
-    case unknown:
-        /* Unknown verb, couldn't deduce object - might need hint */
-        sspeak(WHAT_DO, command.word[0].raw);
-        return GO_CHECKHINT;
-    default: // LCOV_EXCL_LINE
-        BUG(SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN); // LCOV_EXCL_LINE
-    }
+       /*  Analyse a verb.  Remember what it was, go back for object if second
+        * word unless verb is "say", which snarfs arbitrary second word.
+        */
+       /* Previously, actions that result in a message, but don't do anything
+        * further were called "specials". Now they're handled here as normal
+        * actions. If noaction is true, then we spit out the message and return
+        */
+       if (actions[command.verb].noaction) {
+               speak(actions[command.verb].message);
+               return GO_CLEAROBJ;
+       }
+
+       if (command.part == unknown) {
+               /*  Analyse an object word.  See if the thing is here, whether
+                *  we've got a verb yet, and so on.  Object must be here
+                *  unless verb is "find" or "invent(ory)" (and no new verb
+                *  yet to be analysed).  Water and oil are also funny, since
+                *  they are never actually dropped at any location, but might
+                *  be here inside the bottle or urn or as a feature of the
+                *  location. */
+               if (HERE(command.obj)) {
+                       /* FALL THROUGH */;
+               } else if (command.obj == DWARF && atdwrf(game.loc) > 0) {
+                       /* FALL THROUGH */;
+               } else if (!game.closed &&
+                          ((LIQUID() == command.obj && HERE(BOTTLE)) ||
+                           command.obj == LIQLOC(game.loc))) {
+                       /* FALL THROUGH */;
+               } else if (command.obj == OIL && HERE(URN) &&
+                          game.objects[URN].prop != URN_EMPTY) {
+                       command.obj = URN;
+                       /* FALL THROUGH */;
+               } else if (command.obj == PLANT && AT(PLANT2) &&
+                          game.objects[PLANT2].prop != PLANT_THIRSTY) {
+                       command.obj = PLANT2;
+                       /* FALL THROUGH */;
+               } else if (command.obj == KNIFE && game.knfloc == game.loc) {
+                       game.knfloc = -1;
+                       rspeak(KNIVES_VANISH);
+                       return GO_CLEAROBJ;
+               } else if (command.obj == ROD && HERE(ROD2)) {
+                       command.obj = ROD2;
+                       /* FALL THROUGH */;
+               } else if ((command.verb == FIND ||
+                           command.verb == INVENTORY) &&
+                          (command.word[1].id == WORD_EMPTY ||
+                           command.word[1].id == WORD_NOT_FOUND)) {
+                       /* FALL THROUGH */;
+               } else {
+                       sspeak(NO_SEE, command.word[0].raw);
+                       return GO_CLEAROBJ;
+               }
+
+               if (command.verb != 0) {
+                       command.part = transitive;
+               }
+       }
+
+       switch (command.part) {
+       case intransitive:
+               if (command.word[1].raw[0] != '\0' && command.verb != SAY) {
+                       return GO_WORD2;
+               }
+               if (command.verb == SAY) {
+                       /* KEYS is not special, anything not NO_OBJECT or
+                        * INTRANSITIVE will do here. We're preventing
+                        * interpretation as an intransitive verb when the word
+                        * is unknown. */
+                       command.obj =
+                           command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
+               }
+               if (command.obj == NO_OBJECT || command.obj == INTRANSITIVE) {
+                       /*  Analyse an intransitive verb (ie, no object given
+                        * yet). */
+                       switch (command.verb) {
+                       case CARRY:
+                               return vcarry(command.verb, INTRANSITIVE);
+                       case DROP:
+                               return GO_UNKNOWN;
+                       case SAY:
+                               return GO_UNKNOWN;
+                       case UNLOCK:
+                               return lock(command.verb, INTRANSITIVE);
+                       case NOTHING: {
+                               rspeak(OK_MAN);
+                               return (GO_CLEAROBJ);
+                       }
+                       case LOCK:
+                               return lock(command.verb, INTRANSITIVE);
+                       case LIGHT:
+                               return light(command.verb, INTRANSITIVE);
+                       case EXTINGUISH:
+                               return extinguish(command.verb, INTRANSITIVE);
+                       case WAVE:
+                               return GO_UNKNOWN;
+                       case TAME:
+                               return GO_UNKNOWN;
+                       case GO: {
+                               speak(actions[command.verb].message);
+                               return GO_CLEAROBJ;
+                       }
+                       case ATTACK:
+                               command.obj = INTRANSITIVE;
+                               return attack(command);
+                       case POUR:
+                               return pour(command.verb, INTRANSITIVE);
+                       case EAT:
+                               return eat(command.verb, INTRANSITIVE);
+                       case DRINK:
+                               return drink(command.verb, INTRANSITIVE);
+                       case RUB:
+                               return GO_UNKNOWN;
+                       case THROW:
+                               return GO_UNKNOWN;
+                       case QUIT:
+                               return quit();
+                       case FIND:
+                               return GO_UNKNOWN;
+                       case INVENTORY:
+                               return inven();
+                       case FEED:
+                               return GO_UNKNOWN;
+                       case FILL:
+                               return fill(command.verb, INTRANSITIVE);
+                       case BLAST:
+                               blast();
+                               return GO_CLEAROBJ;
+                       case SCORE:
+                               score(scoregame);
+                               return GO_CLEAROBJ;
+                       case FEE:
+                       case FIE:
+                       case FOE:
+                       case FOO:
+                       case FUM:
+                               return bigwords(command.word[0].id);
+                       case BRIEF:
+                               return brief();
+                       case READ:
+                               command.obj = INTRANSITIVE;
+                               return read(command);
+                       case BREAK:
+                               return GO_UNKNOWN;
+                       case WAKE:
+                               return GO_UNKNOWN;
+                       case SAVE:
+                               return suspend();
+                       case RESUME:
+                               return resume();
+                       case FLY:
+                               return fly(command.verb, INTRANSITIVE);
+                       case LISTEN:
+                               return listen();
+                       case PART:
+                               return reservoir();
+                       case SEED:
+                       case WASTE:
+                               rspeak(NUMERIC_REQUIRED);
+                               return GO_TOP;
+                       default: // LCOV_EXCL_LINE
+                               BUG(INTRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
+                       }
+               }
+       /* FALLTHRU */
+       case transitive:
+               /*  Analyse a transitive verb. */
+               switch (command.verb) {
+               case CARRY:
+                       return vcarry(command.verb, command.obj);
+               case DROP:
+                       return discard(command.verb, command.obj);
+               case SAY:
+                       return say(command);
+               case UNLOCK:
+                       return lock(command.verb, command.obj);
+               case NOTHING: {
+                       rspeak(OK_MAN);
+                       return (GO_CLEAROBJ);
+               }
+               case LOCK:
+                       return lock(command.verb, command.obj);
+               case LIGHT:
+                       return light(command.verb, command.obj);
+               case EXTINGUISH:
+                       return extinguish(command.verb, command.obj);
+               case WAVE:
+                       return wave(command.verb, command.obj);
+               case TAME: {
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               }
+               case GO: {
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               }
+               case ATTACK:
+                       return attack(command);
+               case POUR:
+                       return pour(command.verb, command.obj);
+               case EAT:
+                       return eat(command.verb, command.obj);
+               case DRINK:
+                       return drink(command.verb, command.obj);
+               case RUB:
+                       return rub(command.verb, command.obj);
+               case THROW:
+                       return throwit(command);
+               case QUIT:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case FIND:
+                       return find(command.verb, command.obj);
+               case INVENTORY:
+                       return find(command.verb, command.obj);
+               case FEED:
+                       return feed(command.verb, command.obj);
+               case FILL:
+                       return fill(command.verb, command.obj);
+               case BLAST:
+                       blast();
+                       return GO_CLEAROBJ;
+               case SCORE:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case FEE:
+               case FIE:
+               case FOE:
+               case FOO:
+               case FUM:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case BRIEF:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case READ:
+                       return read(command);
+               case BREAK:
+                       return vbreak(command.verb, command.obj);
+               case WAKE:
+                       return wake(command.verb, command.obj);
+               case SAVE:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case RESUME:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               case FLY:
+                       return fly(command.verb, command.obj);
+               case LISTEN:
+                       speak(actions[command.verb].message);
+                       return GO_CLEAROBJ;
+               // LCOV_EXCL_START
+               // This case should never happen - here only as placeholder
+               case PART:
+                       return reservoir();
+               // LCOV_EXCL_STOP
+               case SEED:
+                       return seed(command.verb, command.word[1].raw);
+               case WASTE:
+                       return waste(command.verb,
+                                    (turn_t)atol(command.word[1].raw));
+               default: // LCOV_EXCL_LINE
+                       BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
+               }
+       case unknown:
+               /* Unknown verb, couldn't deduce object - might need hint */
+               sspeak(WHAT_DO, command.word[0].raw);
+               return GO_CHECKHINT;
+       default: // LCOV_EXCL_LINE
+               BUG(SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN); // LCOV_EXCL_LINE
+       }
 }
 
 // end
index 55518cbe449adbf44d2e7e45b17d85aeebe15d80..b26364511d8e8fe2ee955346cba1210c13710010 100644 (file)
--- a/advent.h
+++ b/advent.h
@@ -4,11 +4,11 @@
  * SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
  * SPDX-License-Identifier: BSD-2-Clause
  */
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <inttypes.h>
 
 #include "dungeon.h"
 
 #define LCG_C 221587L
 #define LCG_M 1048576L
 
-#define LINESIZE       1024
-#define TOKLEN         5          // # outputting characters in a token */
-#define PIRATE         NDWARVES   // must be NDWARVES-1 when zero-origin
-#define DALTLC         LOC_NUGGET // alternate dwarf location
-#define INVLIMIT       7          // inventory limit (# of objects)
-#define INTRANSITIVE   -1         // illegal object number
-#define GAMELIMIT      330        // base limit of turns
-#define NOVICELIMIT    1000       // limit of turns for novice
-#define WARNTIME       30         // late game starts at game.limit-this
-#define FLASHTIME      50         // turns from first warning till blinding flash
-#define PANICTIME      15         // time left after closing
-#define BATTERYLIFE    2500       // turn limit increment from batteries
-#define WORD_NOT_FOUND -1         // "Word not found" flag value for the vocab hash functions.
-#define WORD_EMPTY     0          // "Word empty" flag value for the vocab hash functions
-#define PIT_KILL_PROB  35        // Percentage probability of dying from fall in pit.
-#define CARRIED        -1         // Player is toting it
-#define READ_MODE      "rb"       // b is not needed for POSIX but harmless
-#define WRITE_MODE     "wb"       // b is not needed for POSIX but harmless
+#define LINESIZE 1024
+#define TOKLEN 5          // # outputting characters in a token */
+#define PIRATE NDWARVES   // must be NDWARVES-1 when zero-origin
+#define DALTLC LOC_NUGGET // alternate dwarf location
+#define INVLIMIT 7        // inventory limit (# of objects)
+#define INTRANSITIVE -1   // illegal object number
+#define GAMELIMIT 330     // base limit of turns
+#define NOVICELIMIT 1000  // limit of turns for novice
+#define WARNTIME 30       // late game starts at game.limit-this
+#define FLASHTIME 50      // turns from first warning till blinding flash
+#define PANICTIME 15      // time left after closing
+#define BATTERYLIFE 2500  // turn limit increment from batteries
+#define WORD_NOT_FOUND                                                         \
+       -1 // "Word not found" flag value for the vocab hash functions.
+#define WORD_EMPTY 0     // "Word empty" flag value for the vocab hash functions
+#define PIT_KILL_PROB 35 // Percentage probability of dying from fall in pit.
+#define CARRIED -1       // Player is toting it
+#define READ_MODE "rb"   // b is not needed for POSIX but harmless
+#define WRITE_MODE "wb"  // b is not needed for POSIX but harmless
 
 /* Special object-state values - integers > 0 are object-specific */
-#define STATE_NOTFOUND  -1       // 'Not found" state of treasures
-#define STATE_FOUND    0         // After discovered, before messed with
-#define STATE_IN_CAVITY        1         // State value common to all gemstones
+#define STATE_NOTFOUND -1 // 'Not found" state of treasures
+#define STATE_FOUND 0     // After discovered, before messed with
+#define STATE_IN_CAVITY 1 // State value common to all gemstones
 
 /* Special fixed object-state values - integers > 0 are location */
 #define IS_FIXED -1
  * and readable objects, notably the clam/oyster - but the code around
  * those test is difficult to read.
  */
-#define PROP_STASHIFY(n)       (-1 - (n))
-#define PROP_IS_STASHED(obj)   (game.objects[obj].prop < STATE_NOTFOUND)
-#define PROP_IS_NOTFOUND(obj)  (game.objects[obj].prop == STATE_NOTFOUND)
-#define PROP_IS_FOUND(obj)     (game.objects[obj].prop == STATE_FOUND)
-#define PROP_IS_STASHED_OR_UNSEEN(obj) (game.objects[obj].prop < 0)
-#define PROP_SET_FOUND(obj)    (game.objects[obj].prop = STATE_FOUND)
-#define PROP_SET_NOT_FOUND(obj)        (game.objects[obj].prop = STATE_NOTFOUND)
-#define PROP_IS_NOTFOUND2(g, o)        (g.objects[o].prop == STATE_NOTFOUND)
-#define PROP_IS_INVALID(val)   (val < -MAX_STATE - 1 || val > MAX_STATE)
+#define PROP_STASHIFY(n) (-1 - (n))
+#define PROP_IS_STASHED(obj) (game.objects[obj].prop < STATE_NOTFOUND)
+#define PROP_IS_NOTFOUND(obj) (game.objects[obj].prop == STATE_NOTFOUND)
+#define PROP_IS_FOUND(obj) (game.objects[obj].prop == STATE_FOUND)
+#define PROP_IS_STASHED_OR_UNSEEN(obj) (game.objects[obj].prop < 0)
+#define PROP_SET_FOUND(obj) (game.objects[obj].prop = STATE_FOUND)
+#define PROP_SET_NOT_FOUND(obj) (game.objects[obj].prop = STATE_NOTFOUND)
+#define PROP_IS_NOTFOUND2(g, o) (g.objects[o].prop == STATE_NOTFOUND)
+#define PROP_IS_INVALID(val) (val < -MAX_STATE - 1 || val > MAX_STATE)
 #else
 /* (ESR) Only the boldest of adventurers will explore here.  This
  * alternate set of definitions for the macros above was an attempt to
  * break from out of the state encoding a per-object "found" member
- * telling whether or not the player has seen the object. 
+ * telling whether or not the player has seen the object.
  *
  * What's broken when you try to use thus is
  * PROP_IS_STASHED_OR_UNSEEN. The symptom is game.tally getting
  * decremented on non-treasures.
  */
-#define PROP_STASHIFY(n)       (-(n))
-#define PROP_IS_STASHED(obj)   (game.objects[obj].prop < 0)
-#define PROP_IS_NOTFOUND(obj)  (!game.objects[obj].found)
-#define PROP_IS_FOUND(obj)     (game.objects[obj].found && game.objects[obj].prop == 0)
-#define PROP_IS_STASHED_OR_UNSEEN(obj) (!game.objects[obj].found || game.objects[obj].prop < 0)
-#define PROP_SET_FOUND(obj)    do {game.objects[obj].found = true; game.objects[obj].prop = STATE_FOUND;} while(0)
-#define PROP_SET_NOT_FOUND(obj)        game.objects[obj].found = false
-#define PROP_IS_NOTFOUND2(g, o)        (!g.objects[o].found)
-#define PROP_IS_INVALID(val)   (val < -MAX_STATE || val > MAX_STATE)
-#define PROP_SET_SEEN(obj)     game.objects[object].found = true
+#define PROP_STASHIFY(n) (-(n))
+#define PROP_IS_STASHED(obj) (game.objects[obj].prop < 0)
+#define PROP_IS_NOTFOUND(obj) (!game.objects[obj].found)
+#define PROP_IS_FOUND(obj)                                                     \
+       (game.objects[obj].found && game.objects[obj].prop == 0)
+#define PROP_IS_STASHED_OR_UNSEEN(obj)                                         \
+       (!game.objects[obj].found || game.objects[obj].prop < 0)
+#define PROP_SET_FOUND(obj)                                                    \
+       do {                                                                   \
+               game.objects[obj].found = true;                                \
+               game.objects[obj].prop = STATE_FOUND;                          \
+       } while (0)
+#define PROP_SET_NOT_FOUND(obj) game.objects[obj].found = false
+#define PROP_IS_NOTFOUND2(g, o) (!g.objects[o].found)
+#define PROP_IS_INVALID(val) (val < -MAX_STATE || val > MAX_STATE)
+#define PROP_SET_SEEN(obj) game.objects[object].found = true
 #endif
-#define PROP_STASHED(obj)      PROP_STASHIFY(game.objects[obj].prop)
+#define PROP_STASHED(obj) PROP_STASHIFY(game.objects[obj].prop)
 
-#define PROMPT "> "
+#define PROMPT "> "
 
 /*
  *  DESTROY(N)  = Get rid of an item by putting it in LOC_NOWHERE
  *  GSTONE(OBJ) = true if OBJ is a gemstone
  *  FOREST(LOC) = true if LOC is part of the forest
  *  OUTSID(LOC) = true if location not in the cave
- *  INSIDE(LOC) = true if location is in the cave or the building at the beginning of the game
- *  INDEEP(LOC) = true if location is in the Hall of Mists or deeper
- *  BUG(X)      = report bug and exit
+ *  INSIDE(LOC) = true if location is in the cave or the building at the
+ * beginning of the game INDEEP(LOC) = true if location is in the Hall of Mists
+ * or deeper BUG(X)      = report bug and exit
  */
-#define DESTROY(N)   move(N, LOC_NOWHERE)
-#define MOD(N,M)     ((N) % (M))
-#define TOTING(OBJ)  (game.objects[OBJ].place == CARRIED)
-#define AT(OBJ)      (game.objects[OBJ].place == game.loc || game.objects[OBJ].fixed == game.loc)
-#define HERE(OBJ)    (AT(OBJ) || TOTING(OBJ))
-#define CNDBIT(L,N)  (tstbit(conditions[L],N))
-#define LIQUID()     (game.objects[BOTTLE].prop == WATER_BOTTLE? WATER : game.objects[BOTTLE].prop == OIL_BOTTLE ? OIL : NO_OBJECT )
-#define LIQLOC(LOC)  (CNDBIT((LOC),COND_FLUID)? CNDBIT((LOC),COND_OILY) ? OIL : WATER : NO_OBJECT)
-#define FORCED(LOC)  CNDBIT(LOC, COND_FORCED)
-#define DARK(DUMMY)  (!CNDBIT(game.loc,COND_LIT) && (game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
-#define PCT(N)       (randrange(100) < (N))
-#define GSTONE(OBJ)  ((OBJ) == EMERALD || (OBJ) == RUBY || (OBJ) == AMBER || (OBJ) == SAPPH)
-#define FOREST(LOC)  CNDBIT(LOC, COND_FOREST)
-#define OUTSID(LOC)  (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
-#define INSIDE(LOC)  (!OUTSID(LOC) || LOC == LOC_BUILDING)
-#define INDEEP(LOC)  CNDBIT((LOC),COND_DEEP)
-#define BUG(x)       bug(x, #x)
+#define DESTROY(N) move(N, LOC_NOWHERE)
+#define MOD(N, M) ((N) % (M))
+#define TOTING(OBJ) (game.objects[OBJ].place == CARRIED)
+#define AT(OBJ)                                                                \
+       (game.objects[OBJ].place == game.loc ||                                \
+        game.objects[OBJ].fixed == game.loc)
+#define HERE(OBJ) (AT(OBJ) || TOTING(OBJ))
+#define CNDBIT(L, N) (tstbit(conditions[L], N))
+#define LIQUID()                                                               \
+       (game.objects[BOTTLE].prop == WATER_BOTTLE ? WATER                     \
+        : game.objects[BOTTLE].prop == OIL_BOTTLE ? OIL                       \
+                                                  : NO_OBJECT)
+#define LIQLOC(LOC)                                                            \
+       (CNDBIT((LOC), COND_FLUID) ? CNDBIT((LOC), COND_OILY) ? OIL : WATER    \
+                                  : NO_OBJECT)
+#define FORCED(LOC) CNDBIT(LOC, COND_FORCED)
+#define DARK(DUMMY)                                                            \
+       (!CNDBIT(game.loc, COND_LIT) &&                                        \
+        (game.objects[LAMP].prop == LAMP_DARK || !HERE(LAMP)))
+#define PCT(N) (randrange(100) < (N))
+#define GSTONE(OBJ)                                                            \
+       ((OBJ) == EMERALD || (OBJ) == RUBY || (OBJ) == AMBER || (OBJ) == SAPPH)
+#define FOREST(LOC) CNDBIT(LOC, COND_FOREST)
+#define OUTSID(LOC) (CNDBIT(LOC, COND_ABOVE) || FOREST(LOC))
+#define INSIDE(LOC) (!OUTSID(LOC) || LOC == LOC_BUILDING)
+#define INDEEP(LOC) CNDBIT((LOC), COND_DEEP)
+#define BUG(x) bug(x, #x)
 
 enum bugtype {
-    SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST,
-    VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3,
-    INTRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST,
-    TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST,
-    CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION,
-    LOCATION_HAS_NO_TRAVEL_ENTRIES,
-    HINT_NUMBER_EXCEEDS_GOTO_LIST,
-    SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN,
-    ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH,
+       SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST,
+       VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3,
+       INTRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST,
+       TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST,
+       CONDITIONAL_TRAVEL_ENTRY_WITH_NO_ALTERATION,
+       LOCATION_HAS_NO_TRAVEL_ENTRIES,
+       HINT_NUMBER_EXCEEDS_GOTO_LIST,
+       SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN,
+       ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH,
 };
 
-enum speaktype {touch, look, hear, study, change};
+enum speaktype { touch, look, hear, study, change };
 
-enum termination {endgame, quitgame, scoregame};
+enum termination { endgame, quitgame, scoregame };
 
-enum speechpart {unknown, intransitive, transitive};
+enum speechpart { unknown, intransitive, transitive };
 
-typedef enum {NO_WORD_TYPE, MOTION, OBJECT, ACTION, NUMERIC} word_type_t;
+typedef enum { NO_WORD_TYPE, MOTION, OBJECT, ACTION, NUMERIC } word_type_t;
 
-typedef enum scorebonus {none, splatter, defeat, victory} score_t;
+typedef enum scorebonus { none, splatter, defeat, victory } score_t;
 
 /* Phase codes for action returns.
  * These were at one time FORTRAN line numbers.
  */
 typedef enum {
-    GO_TERMINATE,
-    GO_MOVE,
-    GO_TOP,
-    GO_CLEAROBJ,
-    GO_CHECKHINT,
-    GO_WORD2,
-    GO_UNKNOWN,
-    GO_DWARFWAKE,
+       GO_TERMINATE,
+       GO_MOVE,
+       GO_TOP,
+       GO_CLEAROBJ,
+       GO_CHECKHINT,
+       GO_WORD2,
+       GO_UNKNOWN,
+       GO_DWARFWAKE,
 } phase_codes_t;
 
 /* Use fixed-lwength types to make the save format moore portable */
@@ -183,75 +200,75 @@ typedef int32_t turn_t;   // turn counter or threshold */
 typedef int32_t bool32_t; // turn counter or threshold */
 
 struct game_t {
-    int32_t lcg_x;
-    int32_t abbnum;              // How often to print int descriptions
-    score_t bonus;               // What kind of finishing bonus we are getting
-    loc_t chloc;                 // pirate chest location
-    loc_t chloc2;                // pirate chest alternate location
-    turn_t clock1;               // # turns from finding last treasure to close
-    turn_t clock2;               // # turns from warning till blinding flash
-    bool32_t clshnt;             // has player read the clue in the endgame?
-    bool32_t closed;             // whether we're all the way closed
-    bool32_t closng;             // whether it's closing time yet
-    bool32_t lmwarn;             // has player been warned about lamp going dim?
-    bool32_t novice;             // asked for instructions at start-up?
-    bool32_t panic;              // has player found out he's trapped?
-    bool32_t wzdark;             // whether the loc he's leaving was dark
-    bool32_t blooded;            // has player drunk of dragon's blood?
-    int32_t conds;               // min value for cond[loc] if loc has any hints
-    int32_t detail;              // level of detail in descriptions
+       int32_t lcg_x;
+       int32_t abbnum;   // How often to print int descriptions
+       score_t bonus;    // What kind of finishing bonus we are getting
+       loc_t chloc;      // pirate chest location
+       loc_t chloc2;     // pirate chest alternate location
+       turn_t clock1;    // # turns from finding last treasure to close
+       turn_t clock2;    // # turns from warning till blinding flash
+       bool32_t clshnt;  // has player read the clue in the endgame?
+       bool32_t closed;  // whether we're all the way closed
+       bool32_t closng;  // whether it's closing time yet
+       bool32_t lmwarn;  // has player been warned about lamp going dim?
+       bool32_t novice;  // asked for instructions at start-up?
+       bool32_t panic;   // has player found out he's trapped?
+       bool32_t wzdark;  // whether the loc he's leaving was dark
+       bool32_t blooded; // has player drunk of dragon's blood?
+       int32_t conds;    // min value for cond[loc] if loc has any hints
+       int32_t detail;   // level of detail in descriptions
 
-    /*  dflag controls the level of activation of dwarves:
-     * 0       No dwarf stuff yet (wait until reaches Hall Of Mists)
-     * 1       Reached Hall Of Mists, but hasn't met first dwarf
-     * 2       Met first dwarf, others start moving, no knives thrown yet
-     * 3       A knife has been thrown (first set always misses)
-     * 3+      Dwarves are mad (increases their accuracy) */
-    int32_t dflag;
+       /*  dflag controls the level of activation of dwarves:
+        *      0       No dwarf stuff yet (wait until reaches Hall Of Mists)
+        *      1       Reached Hall Of Mists, but hasn't met first dwarf
+        *      2       Met first dwarf, others start moving, no knives thrown
+        *yet 3 A knife has been thrown (first set always misses) 3+
+        *Dwarves are mad (increases their accuracy) */
+       int32_t dflag;
 
-    int32_t dkill;               // dwarves killed
-    int32_t dtotal;              // total dwarves (including pirate) in loc
-    int32_t foobar;              // progress in saying "FEE FIE FOE FOO".
-    int32_t holdng;              // number of objects being carried
-    int32_t igo;                 // # uses of "go" instead of a direction
-    int32_t iwest;               // # times he's said "west" instead of "w"
-    loc_t knfloc;                // knife location; LOC_NOWERE if none, -1 after caveat
-    turn_t limit;                // lifetime of lamp
-    loc_t loc;                   // where player is now
-    loc_t newloc;                // where player is going
-    turn_t numdie;               // number of times killed so far
-    loc_t oldloc;                // where player was
-    loc_t oldlc2;                // where player was two moves ago
-    obj_t oldobj;                // last object player handled
-    int32_t saved;               // point penalty for saves
-    int32_t tally;               // count of treasures gained
-    int32_t thresh;              // current threshold for endgame scoring tier
-    bool32_t seenbigwords;       // have we red the graffiti in the Giant's Room? 
-    turn_t trnluz;               // # points lost so far due to turns used
-    turn_t turns;                // counts commands given (ignores yes/no)
-    char zzword[TOKLEN + 1];     // randomly generated magic word from bird
-    struct {
-       int32_t abbrev;          // has location been seen?
-       int32_t atloc;           // head of object linked list per location
-    } locs[NLOCATIONS + 1];
-    struct {
-       int32_t seen;            // true if dwarf has seen him
-       loc_t loc;               // location of dwarves, initially hard-wired in
-       loc_t oldloc;            // prior loc of each dwarf, initially garbage
-    } dwarves[NDWARVES + 1];
-    struct {
+       int32_t dkill;  // dwarves killed
+       int32_t dtotal; // total dwarves (including pirate) in loc
+       int32_t foobar; // progress in saying "FEE FIE FOE FOO".
+       int32_t holdng; // number of objects being carried
+       int32_t igo;    // # uses of "go" instead of a direction
+       int32_t iwest;  // # times he's said "west" instead of "w"
+       loc_t knfloc;   // knife location; LOC_NOWERE if none, -1 after caveat
+       turn_t limit;   // lifetime of lamp
+       loc_t loc;      // where player is now
+       loc_t newloc;   // where player is going
+       turn_t numdie;  // number of times killed so far
+       loc_t oldloc;   // where player was
+       loc_t oldlc2;   // where player was two moves ago
+       obj_t oldobj;   // last object player handled
+       int32_t saved;  // point penalty for saves
+       int32_t tally;  // count of treasures gained
+       int32_t thresh; // current threshold for endgame scoring tier
+       bool32_t seenbigwords; // have we red the graffiti in the Giant's Room?
+       turn_t trnluz;         // # points lost so far due to turns used
+       turn_t turns;          // counts commands given (ignores yes/no)
+       char zzword[TOKLEN + 1]; // randomly generated magic word from bird
+       struct {
+               int32_t abbrev; // has location been seen?
+               int32_t atloc;  // head of object linked list per location
+       } locs[NLOCATIONS + 1];
+       struct {
+               int32_t seen; // true if dwarf has seen him
+               loc_t loc;    // location of dwarves, initially hard-wired in
+               loc_t oldloc; // prior loc of each dwarf, initially garbage
+       } dwarves[NDWARVES + 1];
+       struct {
 #ifdef FOUNDBOOL
-       bool32_t found;          // has the location of this object been found?
+               bool32_t found; // has the location of this object been found?
 #endif
-       loc_t fixed;             // fixed location of object (if not IS_FREE)
-        int32_t prop;            // object state */
-       loc_t place;             // location of object
-    } objects[NOBJECTS + 1];
-    struct { 
-       bool32_t used;           // hints[i].used = true iff hint i has been used.
-       int32_t lc;              // hints[i].lc = show int at LOC with cond bit i
-    } hints[NHINTS];
-    obj_t link[NOBJECTS * 2 + 1];// object-list links
+               loc_t fixed;  // fixed location of object (if not IS_FREE)
+               int32_t prop; // object state */
+               loc_t place;  // location of object
+       } objects[NOBJECTS + 1];
+       struct {
+               bool32_t used; // hints[i].used = true iff hint i has been used.
+               int32_t lc;    // hints[i].lc = show int at LOC with cond bit i
+       } hints[NHINTS];
+       obj_t link[NOBJECTS * 2 + 1]; // object-list links
 };
 
 /*
@@ -259,56 +276,64 @@ struct game_t {
  * This data is not saved in a saved game.
  */
 struct settings_t {
-    FILE *logfp;
-    bool oldstyle;
-    bool prompt;
-    char **argv;
-    int argc;
-    int optind;
-    FILE *scriptfp;
-    int debug;
+       FILE *logfp;
+       bool oldstyle;
+       bool prompt;
+       char **argv;
+       int argc;
+       int optind;
+       FILE *scriptfp;
+       int debug;
 };
 
 typedef struct {
-    char raw[LINESIZE];
-    vocab_t id;
-    word_type_t type;
+       char raw[LINESIZE];
+       vocab_t id;
+       word_type_t type;
 } command_word_t;
 
-typedef enum {EMPTY, RAW, TOKENIZED, GIVEN, PREPROCESSED, PROCESSING, EXECUTED} command_state_t;
+typedef enum {
+       EMPTY,
+       RAW,
+       TOKENIZED,
+       GIVEN,
+       PREPROCESSED,
+       PROCESSING,
+       EXECUTED
+} command_state_t;
 
 typedef struct {
-    enum speechpart part;
-    command_word_t word[2];
-    verb_t verb;
-    obj_t obj;
-    command_state_t state;
+       enum speechpart part;
+       command_word_t word[2];
+       verb_t verb;
+       obj_t obj;
+       command_state_t state;
 } command_t;
 
 /*
  * Bump on save format change.
  *
- * Note: Verify that the tests run clean before bumping this, then rebuild the check
- * files afterwards.  Otherwise you will get a spurious failure due to the old version
- * having been generated into a check file.
+ * Note: Verify that the tests run clean before bumping this, then rebuild the
+ * check files afterwards.  Otherwise you will get a spurious failure due to the
+ * old version having been generated into a check file.
  */
-#define SAVE_VERSION   31
+#define SAVE_VERSION 31
 
 /*
  * Goes at start of file so saves can be identified by file(1) and the like.
  */
-#define ADVENT_MAGIC   "open-adventure\n"
+#define ADVENT_MAGIC "open-adventure\n"
 
 /*
  * If you change the first three members, the resume function may not properly
- * reject saves from older versions. Later members can change, but bump the version
- * when you do that.
+ * reject saves from older versions. Later members can change, but bump the
+ * version when you do that.
  */
 struct save_t {
-    char magic[sizeof(ADVENT_MAGIC)];
-    int32_t version;
-    int32_t canary;
-    struct game_t game;
+       char magic[sizeof(ADVENT_MAGIC)];
+       int32_t version;
+       int32_t canary;
+       struct game_t game;
 };
 
 extern struct game_t game;
@@ -318,13 +343,13 @@ extern struct settings_t settings;
 extern char *myreadline(const char *);
 extern bool get_command_input(command_t *);
 extern void clear_command(command_t *);
-extern void speak(const char*, ...);
+extern void speak(const char *, ...);
 extern void sspeak(int msg, ...);
 extern void pspeak(vocab_t, enum speaktype, bool, int, ...);
 extern void rspeak(vocab_t, ...);
-extern void echo_input(FILE*, const char*, const char*);
+extern void echo_input(FILE *, const char *, const char *);
 extern bool silent_yes_or_no(void);
-extern bool yes_or_no(const char*, const char*, const char*);
+extern bool yes_or_no(const char *, const char *, const char *);
 extern void juggle(obj_t);
 extern void move(obj_t, loc_t);
 extern void put(obj_t, loc_t, int);
diff --git a/cheat.c b/cheat.c
index 279bcd9e6fc8dddabc8cb6eea798251026dd55e9..4e94025668fa367a9a584e859eef62bec061de49 100644 (file)
--- a/cheat.c
+++ b/cheat.c
@@ -7,93 +7,90 @@
  * SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
  * SPDX-License-Identifier: BSD-2-Clause
  */
+#include "advent.h"
+#include <editline/readline.h>
 #include <getopt.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <stdbool.h>
-#include <editline/readline.h>
-#include "advent.h"
-
-int main(int argc, char *argv[])
-{
-    int ch;
-    char *savefilename = NULL;
-    FILE *fp = NULL;
-
-    // Initialize game variables
-    initialise();
-
-    /* we're generating a saved game, so saved once by default,
-     * unless overridden with command-line options below.
-     */
-    game.saved = 1;
-
-    /*  Options. */
-    const char* opts = "d:l:s:t:v:o:";
-    const char* usage = "Usage: %s [-d numdie] [-s numsaves] [-v version] -o savefilename \n"
-                        "        -d number of deaths. Signed integer.\n"
-                        "        -l lifetime of lamp in turns. Signed integer.\n"
-                        "        -s number of saves. Signed integer.\n"
-                        "        -t number of turns. Signed integer.\n"
-                        "        -v version number of save format.\n"
-                        "        -o required. File name of save game to write.\n";
-
-    while ((ch = getopt(argc, argv, opts)) != EOF) {
-        switch (ch) {
-        case 'd':
-            game.numdie = (turn_t)atoi(optarg);
-            printf("cheat: game.numdie = %d\n", game.numdie);
-            break;
-        case 'l':
-            game.limit = (turn_t)atoi(optarg);
-            printf("cheat: game.limit = %d\n", game.limit);
-            break;
-        case 's':
-            game.saved = (int)atoi(optarg);
-            printf("cheat: game.saved = %d\n", game.saved);
-            break;
-        case 't':
-            game.turns = (turn_t)atoi(optarg);
-            printf("cheat: game.turns = %d\n", game.turns);
-            break;
-        case 'v':
-            save.version = atoi(optarg);
-            printf("cheat: version = %d\n", save.version);
-            break;
-        case 'o':
-            savefilename = optarg;
-            break;
-        default:
-            fprintf(stderr,
-                    usage, argv[0]);
-            exit(EXIT_FAILURE);
-            break;
-        }
-    }
-
-    // Save filename required; the point of cheat is to generate save file
-    if (savefilename == NULL) {
-        fprintf(stderr,
-                usage, argv[0]);
-        fprintf(stderr,
-                "ERROR: filename required\n");
-        exit(EXIT_FAILURE);
-    }
-
-    fp = fopen(savefilename, WRITE_MODE);
-    if (fp == NULL) {
-        fprintf(stderr,
-                "Can't open file %s. Exiting.\n", savefilename);
-        exit(EXIT_FAILURE);
-    }
-
-    savefile(fp);
-
-    fclose(fp);
-
-    printf("cheat: %s created.\n", savefilename);
+#include <stdio.h>
+#include <stdlib.h>
 
-    return EXIT_SUCCESS;
+int main(int argc, char *argv[]) {
+       int ch;
+       char *savefilename = NULL;
+       FILE *fp = NULL;
+
+       // Initialize game variables
+       initialise();
+
+       /* we're generating a saved game, so saved once by default,
+        * unless overridden with command-line options below.
+        */
+       game.saved = 1;
+
+       /*  Options. */
+       const char *opts = "d:l:s:t:v:o:";
+       const char *usage =
+           "Usage: %s [-d numdie] [-s numsaves] [-v version] -o savefilename "
+           "\n"
+           "        -d number of deaths. Signed integer.\n"
+           "        -l lifetime of lamp in turns. Signed integer.\n"
+           "        -s number of saves. Signed integer.\n"
+           "        -t number of turns. Signed integer.\n"
+           "        -v version number of save format.\n"
+           "        -o required. File name of save game to write.\n";
+
+       while ((ch = getopt(argc, argv, opts)) != EOF) {
+               switch (ch) {
+               case 'd':
+                       game.numdie = (turn_t)atoi(optarg);
+                       printf("cheat: game.numdie = %d\n", game.numdie);
+                       break;
+               case 'l':
+                       game.limit = (turn_t)atoi(optarg);
+                       printf("cheat: game.limit = %d\n", game.limit);
+                       break;
+               case 's':
+                       game.saved = (int)atoi(optarg);
+                       printf("cheat: game.saved = %d\n", game.saved);
+                       break;
+               case 't':
+                       game.turns = (turn_t)atoi(optarg);
+                       printf("cheat: game.turns = %d\n", game.turns);
+                       break;
+               case 'v':
+                       save.version = atoi(optarg);
+                       printf("cheat: version = %d\n", save.version);
+                       break;
+               case 'o':
+                       savefilename = optarg;
+                       break;
+               default:
+                       fprintf(stderr, usage, argv[0]);
+                       exit(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       // Save filename required; the point of cheat is to generate save file
+       if (savefilename == NULL) {
+               fprintf(stderr, usage, argv[0]);
+               fprintf(stderr, "ERROR: filename required\n");
+               exit(EXIT_FAILURE);
+       }
+
+       fp = fopen(savefilename, WRITE_MODE);
+       if (fp == NULL) {
+               fprintf(stderr, "Can't open file %s. Exiting.\n", savefilename);
+               exit(EXIT_FAILURE);
+       }
+
+       savefile(fp);
+
+       fclose(fp);
+
+       printf("cheat: %s created.\n", savefilename);
+
+       return EXIT_SUCCESS;
 }
 
 // LCOV_EXCL_START
@@ -102,12 +99,7 @@ int main(int argc, char *argv[])
  * See the actually useful version of this in main.c
  */
 
-char *myreadline(const char *prompt)
-{
-    return readline(prompt);
-}
+char *myreadline(const char *prompt) { return readline(prompt); }
 // LCOV_EXCL_STOP
 
 /* end */
-
-
diff --git a/init.c b/init.c
index 94c972d3d6597584e64af0d2b3562f03e3481c3d..d00255dacd6a9824286ab45928311917bc1b7f0d 100644 (file)
--- a/init.c
+++ b/init.c
@@ -5,97 +5,86 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include <assert.h>
 #include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <time.h>
-#include <assert.h>
+#include <unistd.h>
 
 #include "advent.h"
 
-struct settings_t settings = {
-    .logfp = NULL,
-    .oldstyle = false,
-    .prompt = true
-};
+struct settings_t settings = {.logfp = NULL, .oldstyle = false, .prompt = true};
 
 struct game_t game = {
     /*  Last dwarf is special (the pirate).  He always starts at his
      *  chest's eventual location inside the maze. This loc is saved
      *  in chloc for ref. The dead end in the other maze has its
      *  loc stored in chloc2. */
-    .chloc   = LOC_MAZEEND12,
-    .chloc2  = LOC_DEADEND13,
-    .abbnum  = 5,
-    .clock1  = WARNTIME,
-    .clock2  = FLASHTIME,
-    .newloc  = LOC_START,
-    .loc     = LOC_START,
-    .limit   = GAMELIMIT,
-    .foobar  = WORD_EMPTY,
+    .chloc = LOC_MAZEEND12, .chloc2 = LOC_DEADEND13, .abbnum = 5,
+    .clock1 = WARNTIME,     .clock2 = FLASHTIME,     .newloc = LOC_START,
+    .loc = LOC_START,       .limit = GAMELIMIT,      .foobar = WORD_EMPTY,
 };
 
-int initialise(void)
-{
-    if (settings.oldstyle)
-        printf("Initialising...\n");
+int initialise(void) {
+       if (settings.oldstyle)
+               printf("Initialising...\n");
 
-    srand(time(NULL));
-    int seedval = (int)rand();
-    set_seed(seedval);
+       srand(time(NULL));
+       int seedval = (int)rand();
+       set_seed(seedval);
 
-    for (int i = 1; i <= NDWARVES; i++) {
-        game.dwarves[i].loc = dwarflocs[i-1];
-    }
+       for (int i = 1; i <= NDWARVES; i++) {
+               game.dwarves[i].loc = dwarflocs[i - 1];
+       }
 
-    for (int i = 1; i <= NOBJECTS; i++) {
-        game.objects[i].place = LOC_NOWHERE;
-    }
+       for (int i = 1; i <= NOBJECTS; i++) {
+               game.objects[i].place = LOC_NOWHERE;
+       }
 
-    for (int i = 1; i <= NLOCATIONS; i++) {
-        if (!(locations[i].description.big == 0 || tkey[i] == 0)) {
-            int k = tkey[i];
-            if (travel[k].motion == HERE) {
-                conditions[i] |= (1 << COND_FORCED);
-           }
-        }
-    }
+       for (int i = 1; i <= NLOCATIONS; i++) {
+               if (!(locations[i].description.big == 0 || tkey[i] == 0)) {
+                       int k = tkey[i];
+                       if (travel[k].motion == HERE) {
+                               conditions[i] |= (1 << COND_FORCED);
+                       }
+               }
+       }
 
-    /*  Set up the game.locs atloc and game.link arrays.
-     *  We'll use the DROP subroutine, which prefaces new objects on the
-     *  lists.  Since we want things in the other order, we'll run the
-     *  loop backwards.  If the object is in two locs, we drop it twice.
-     *  Also, since two-placed objects are typically best described
-     *  last, we'll drop them first. */
-    for (int i = NOBJECTS; i >= 1; i--) {
-        if (objects[i].fixd > 0) {
-            drop(i + NOBJECTS, objects[i].fixd);
-            drop(i, objects[i].plac);
-        }
-    }
+       /*  Set up the game.locs atloc and game.link arrays.
+        *  We'll use the DROP subroutine, which prefaces new objects on the
+        *  lists.  Since we want things in the other order, we'll run the
+        *  loop backwards.  If the object is in two locs, we drop it twice.
+        *  Also, since two-placed objects are typically best described
+        *  last, we'll drop them first. */
+       for (int i = NOBJECTS; i >= 1; i--) {
+               if (objects[i].fixd > 0) {
+                       drop(i + NOBJECTS, objects[i].fixd);
+                       drop(i, objects[i].plac);
+               }
+       }
 
-    for (int i = 1; i <= NOBJECTS; i++) {
-        int k = NOBJECTS + 1 - i;
-        game.objects[k].fixed = objects[k].fixd;
-        if (objects[k].plac != 0 && objects[k].fixd <= 0) {
-            drop(k, objects[k].plac);
+       for (int i = 1; i <= NOBJECTS; i++) {
+               int k = NOBJECTS + 1 - i;
+               game.objects[k].fixed = objects[k].fixd;
+               if (objects[k].plac != 0 && objects[k].fixd <= 0) {
+                       drop(k, objects[k].plac);
+               }
        }
-    }
 
-    /*  Treasure props are initially STATE_NOTFOUND, and are set to
-     *  STATE_FOUND the first time they are described.  game.tally
-     *  keeps track of how many are not yet found, so we know when to
-     *  close the cave. */
-    for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
-        if (objects[treasure].is_treasure) {
-            ++game.tally;
-            if (objects[treasure].inventory != 0) {
-                PROP_SET_NOT_FOUND(treasure);
-           }
-        }
-    }
-    game.conds = setbit(COND_HBASE);
+       /*  Treasure props are initially STATE_NOTFOUND, and are set to
+        *  STATE_FOUND the first time they are described.  game.tally
+        *  keeps track of how many are not yet found, so we know when to
+        *  close the cave. */
+       for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
+               if (objects[treasure].is_treasure) {
+                       ++game.tally;
+                       if (objects[treasure].inventory != 0) {
+                               PROP_SET_NOT_FOUND(treasure);
+                       }
+               }
+       }
+       game.conds = setbit(COND_HBASE);
 
-    return seedval;
+       return seedval;
 }
diff --git a/main.c b/main.c
index fd0852f696172871a8ddd19e19a84cd8fdd43b2f..cff0780d2a439001cca14c31186e00f693e0000d 100644 (file)
--- a/main.c
+++ b/main.c
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
+#include "advent.h"
+#include <ctype.h>
+#include <editline/readline.h>
 #include <getopt.h>
 #include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <unistd.h>
-#include <editline/readline.h>
-#include "advent.h"
 
-#define DIM(a) (sizeof(a)/sizeof(a[0]))
+#define DIM(a) (sizeof(a) / sizeof(a[0]))
 
 #if defined ADVENT_AUTOSAVE
-static FILE* autosave_fp;
-void autosave(void)
-{
-    if (autosave_fp != NULL) {
-        rewind(autosave_fp);
-        savefile(autosave_fp);
-        fflush(autosave_fp);
-    }
+static FILE *autosave_fp;
+void autosave(void) {
+       if (autosave_fp != NULL) {
+               rewind(autosave_fp);
+               savefile(autosave_fp);
+               fflush(autosave_fp);
+       }
 }
 #endif
 
 // LCOV_EXCL_START
 // exclude from coverage analysis because it requires interactivity to test
-static void sig_handler(int signo)
-{
-    if (signo == SIGINT) {
-        if (settings.logfp != NULL)
-            fflush(settings.logfp);
-    }
+static void sig_handler(int signo) {
+       if (signo == SIGINT) {
+               if (settings.logfp != NULL)
+                       fflush(settings.logfp);
+       }
 
 #if defined ADVENT_AUTOSAVE
-    if (signo == SIGHUP || signo == SIGTERM) {
-        autosave();
-    }
+       if (signo == SIGHUP || signo == SIGTERM) {
+               autosave();
+       }
 #endif
-    exit(EXIT_FAILURE);
+       exit(EXIT_FAILURE);
 }
 // LCOV_EXCL_STOP
 
-char *myreadline(const char *prompt)
-{
-    /*
-     * This function isn't required for gameplay, readline() straight
-     * up would suffice for that.  It's where we interpret command-line
-     * logfiles for testing purposes.
-     */
-    /* Normal case - no script arguments */
-    if (settings.argc == 0) {
-       char *ln = readline(prompt);
-       if (ln == NULL) {
-           fputs(prompt, stdout);
-       }
-        return ln;
-    }
-
-    char *buf = malloc(LINESIZE + 1);
-    for (;;) {
-        if (settings.scriptfp == NULL || feof(settings.scriptfp)) {
-            if (settings.optind >= settings.argc) {
-                free(buf);
-                return NULL;
-            }
-
-            char *next = settings.argv[settings.optind++];
-
-            if (settings.scriptfp != NULL && feof(settings.scriptfp)) {
-                fclose(settings.scriptfp);
-           }
-            if (strcmp(next, "-") == 0) {
-                settings.scriptfp = stdin; // LCOV_EXCL_LINE
-            } else {
-                settings.scriptfp = fopen(next, "r");
-           }
-        }
-
-        if (isatty(fileno(settings.scriptfp))) {
-            free(buf); // LCOV_EXCL_LINE
-            return readline(prompt); // LCOV_EXCL_LINE
-        } else {
-            char *ln = fgets(buf, LINESIZE, settings.scriptfp);
-            if (ln != NULL) {
-               fputs(prompt, stdout);
-                fputs(ln, stdout);
+char *myreadline(const char *prompt) {
+       /*
+        * This function isn't required for gameplay, readline() straight
+        * up would suffice for that.  It's where we interpret command-line
+        * logfiles for testing purposes.
+        */
+       /* Normal case - no script arguments */
+       if (settings.argc == 0) {
+               char *ln = readline(prompt);
+               if (ln == NULL) {
+                       fputs(prompt, stdout);
+               }
                return ln;
-            }
-        }
-    }
+       }
+
+       char *buf = malloc(LINESIZE + 1);
+       for (;;) {
+               if (settings.scriptfp == NULL || feof(settings.scriptfp)) {
+                       if (settings.optind >= settings.argc) {
+                               free(buf);
+                               return NULL;
+                       }
+
+                       char *next = settings.argv[settings.optind++];
 
-    return NULL;
+                       if (settings.scriptfp != NULL &&
+                           feof(settings.scriptfp)) {
+                               fclose(settings.scriptfp);
+                       }
+                       if (strcmp(next, "-") == 0) {
+                               settings.scriptfp = stdin; // LCOV_EXCL_LINE
+                       } else {
+                               settings.scriptfp = fopen(next, "r");
+                       }
+               }
+
+               if (isatty(fileno(settings.scriptfp))) {
+                       free(buf);               // LCOV_EXCL_LINE
+                       return readline(prompt); // LCOV_EXCL_LINE
+               } else {
+                       char *ln = fgets(buf, LINESIZE, settings.scriptfp);
+                       if (ln != NULL) {
+                               fputs(prompt, stdout);
+                               fputs(ln, stdout);
+                               return ln;
+                       }
+               }
+       }
+
+       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.hints[hint].used) {
-                 continue;
-           }
-            if (!CNDBIT(game.loc, hint + 1 + COND_HBASE)) {
-                game.hints[hint].lc = -1;
-           }
-            ++game.hints[hint].lc;
-            /*  Come here if he's been int enough at required loc(s) for some
-             *  unused hint. */
-            if (game.hints[hint].lc >= hints[hint].turns) {
-                int i;
-
-                switch (hint) {
-                case 0:
-                    /* cave */
-                   if (game.objects[GRATE].prop == GRATE_CLOSED && !HERE(KEYS)) {
-                         break;
-                   }
-                    game.hints[hint].lc = 0;
-                    return;
-                case 1:        /* bird */
-                   if (game.objects[BIRD].place == game.loc && TOTING(ROD) && game.oldobj == BIRD) {
-                         break;
-                   }
-                    return;
-                case 2:        /* snake */
-                   if (HERE(SNAKE) && !HERE(BIRD)) {
-                         break;
-                   }
-                    game.hints[hint].lc = 0;
-                    return;
-                case 3:        /* maze */
-                    if (game.locs[game.loc].atloc == NO_OBJECT &&
-                        game.locs[game.oldloc].atloc == NO_OBJECT &&
-                        game.locs[game.oldlc2].atloc == NO_OBJECT &&
-                        game.holdng > 1)
-                        break;
-                    game.hints[hint].lc = 0;
-                    return;
-                case 4:        /* dark */
-                   if (!PROP_IS_NOTFOUND(EMERALD) && PROP_IS_NOTFOUND(PYRAMID)) {
-                         break;
-                   }
-                    game.hints[hint].lc = 0;
-                    return;
-                case 5:        /* witt */
-                    break;
-                case 6:        /* urn */
-                   if (game.dflag == 0) {
-                         break;
-                   }
-                    game.hints[hint].lc = 0;
-                    return;
-                case 7:        /* woods */
-                    if (game.locs[game.loc].atloc == NO_OBJECT &&
-                        game.locs[game.oldloc].atloc == NO_OBJECT &&
-                        game.locs[game.oldlc2].atloc == NO_OBJECT)
-                        break;
-                    return;
-                case 8:        /* ogre */
-                    i = atdwrf(game.loc);
-                    if (i < 0) {
-                        game.hints[hint].lc = 0;
-                        return;
-                    }
-                    if (HERE(OGRE) && i == 0) {
-                        break;
-                   }
-                    return;
-                case 9:        /* jade */
-                   if (game.tally == 1 && PROP_IS_STASHED_OR_UNSEEN(JADE)) {
-                         break;
-                   }
-                    game.hints[hint].lc = 0;
-                    return;
-                default: // LCOV_EXCL_LINE
-                    // Should never happen
-                    BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
-                }
-
-                /* Fall through to hint display */
-                game.hints[hint].lc = 0;
-                if (!yes_or_no(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) {
-                    return;
-               }
-                rspeak(HINT_COST, hints[hint].penalty, hints[hint].penalty);
-                game.hints[hint].used = yes_or_no(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]);
-                if (game.hints[hint].used && game.limit > WARNTIME) {
-                    game.limit += WARNTIME * hints[hint].penalty;
+static void checkhints(void) {
+       if (conditions[game.loc] >= game.conds) {
+               for (int hint = 0; hint < NHINTS; hint++) {
+                       if (game.hints[hint].used) {
+                               continue;
+                       }
+                       if (!CNDBIT(game.loc, hint + 1 + COND_HBASE)) {
+                               game.hints[hint].lc = -1;
+                       }
+                       ++game.hints[hint].lc;
+                       /*  Come here if he's been int enough at required loc(s)
+                        * for some unused hint. */
+                       if (game.hints[hint].lc >= hints[hint].turns) {
+                               int i;
+
+                               switch (hint) {
+                               case 0:
+                                       /* cave */
+                                       if (game.objects[GRATE].prop ==
+                                               GRATE_CLOSED &&
+                                           !HERE(KEYS)) {
+                                               break;
+                                       }
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               case 1: /* bird */
+                                       if (game.objects[BIRD].place ==
+                                               game.loc &&
+                                           TOTING(ROD) &&
+                                           game.oldobj == BIRD) {
+                                               break;
+                                       }
+                                       return;
+                               case 2: /* snake */
+                                       if (HERE(SNAKE) && !HERE(BIRD)) {
+                                               break;
+                                       }
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               case 3: /* maze */
+                                       if (game.locs[game.loc].atloc ==
+                                               NO_OBJECT &&
+                                           game.locs[game.oldloc].atloc ==
+                                               NO_OBJECT &&
+                                           game.locs[game.oldlc2].atloc ==
+                                               NO_OBJECT &&
+                                           game.holdng > 1)
+                                               break;
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               case 4: /* dark */
+                                       if (!PROP_IS_NOTFOUND(EMERALD) &&
+                                           PROP_IS_NOTFOUND(PYRAMID)) {
+                                               break;
+                                       }
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               case 5: /* witt */
+                                       break;
+                               case 6: /* urn */
+                                       if (game.dflag == 0) {
+                                               break;
+                                       }
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               case 7: /* woods */
+                                       if (game.locs[game.loc].atloc ==
+                                               NO_OBJECT &&
+                                           game.locs[game.oldloc].atloc ==
+                                               NO_OBJECT &&
+                                           game.locs[game.oldlc2].atloc ==
+                                               NO_OBJECT)
+                                               break;
+                                       return;
+                               case 8: /* ogre */
+                                       i = atdwrf(game.loc);
+                                       if (i < 0) {
+                                               game.hints[hint].lc = 0;
+                                               return;
+                                       }
+                                       if (HERE(OGRE) && i == 0) {
+                                               break;
+                                       }
+                                       return;
+                               case 9: /* jade */
+                                       if (game.tally == 1 &&
+                                           PROP_IS_STASHED_OR_UNSEEN(JADE)) {
+                                               break;
+                                       }
+                                       game.hints[hint].lc = 0;
+                                       return;
+                               default: // LCOV_EXCL_LINE
+                                       // Should never happen
+                                       BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
+                               }
+
+                               /* Fall through to hint display */
+                               game.hints[hint].lc = 0;
+                               if (!yes_or_no(hints[hint].question,
+                                              arbitrary_messages[NO_MESSAGE],
+                                              arbitrary_messages[OK_MAN])) {
+                                       return;
+                               }
+                               rspeak(HINT_COST, hints[hint].penalty,
+                                      hints[hint].penalty);
+                               game.hints[hint].used =
+                                   yes_or_no(arbitrary_messages[WANT_HINT],
+                                             hints[hint].hint,
+                                             arbitrary_messages[OK_MAN]);
+                               if (game.hints[hint].used &&
+                                   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.objexts,place[CHEST] = LOC_NOWHERE might mean that he's thrown
-     *  it to the troll, but in that case he's seen the chest
-     *  PROP_IS_FOUND(CHEST) == true. */
-    if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) {
-        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;
+static bool spotted_by_pirate(int i) {
+       if (i != PIRATE) {
+               return false;
        }
-        if (TOTING(treasure)) {
-            movechest = true;
-            robplayer = true;
-        }
-    }
-    /* Force chest placement before player finds last treasure */
-    if (game.tally == 1 && snarfed == 0 && game.objects[CHEST].place == LOC_NOWHERE && HERE(LAMP) && game.objects[LAMP].prop == 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.dwarves[PIRATE].loc = game.chloc;
-        game.dwarves[PIRATE].oldloc = game.chloc;
-        game.dwarves[PIRATE].seen = false;
-    } else {
-        /* You might get a hint of the pirate's presence even if the
-         * chest doesn't move... */
-       if (game.dwarves[PIRATE].oldloc != game.dwarves[PIRATE].loc && PCT(20)) {
-             rspeak(PIRATE_RUSTLES);
+
+       /*  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.objexts,place[CHEST] = LOC_NOWHERE might mean that he's
+        * thrown it to the troll, but in that case he's seen the chest
+        *  PROP_IS_FOUND(CHEST) == true. */
+       if (game.loc == game.chloc || !PROP_IS_NOTFOUND(CHEST)) {
+               return true;
        }
-    }
-    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.objects[treasure].fixed == IS_FREE) {
-                     carry(treasure, game.loc);
+       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)) {
-                     drop(treasure, game.chloc);
+                       movechest = true;
+                       robplayer = true;
+               }
+       }
+       /* Force chest placement before player finds last treasure */
+       if (game.tally == 1 && snarfed == 0 &&
+           game.objects[CHEST].place == LOC_NOWHERE && HERE(LAMP) &&
+           game.objects[LAMP].prop == 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.dwarves[PIRATE].loc = game.chloc;
+               game.dwarves[PIRATE].oldloc = game.chloc;
+               game.dwarves[PIRATE].seen = false;
+       } else {
+               /* You might get a hint of the pirate's presence even if the
+                * chest doesn't move... */
+               if (game.dwarves[PIRATE].oldloc != game.dwarves[PIRATE].loc &&
+                   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.objects[treasure].fixed == IS_FREE) {
+                                       carry(treasure, game.loc);
+                               }
+                               if (TOTING(treasure)) {
+                                       drop(treasure, game.chloc);
+                               }
+                       }
+               }
+       }
 
-    return true;
+       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;
+       /* 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.dwarves[j].loc = 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.dwarves[i].loc == game.loc) {
+                               game.dwarves[i].loc = DALTLC;
+                       }
+                       game.dwarves[i].oldloc = game.dwarves[i].loc;
+               }
+               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.dwarves[i].loc == 0) {
+                       continue;
+               }
+               /*  Fill tk array with all the places this dwarf might go. */
+               unsigned int j = 1;
+               kk = tkey[game.dwarves[i].loc];
+               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.dwarves[i].oldloc)
+                                       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.dwarves[i].loc)
+                                       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.dwarves[i].oldloc;
+               if (j >= 2) {
+                       --j;
+               }
+               j = 1 + randrange(j);
+               game.dwarves[i].oldloc = game.dwarves[i].loc;
+               game.dwarves[i].loc = tk[j];
+               game.dwarves[i].seen =
+                   (game.dwarves[i].seen && INDEEP(game.loc)) ||
+                   (game.dwarves[i].loc == game.loc ||
+                    game.dwarves[i].oldloc == game.loc);
+               if (!game.dwarves[i].seen) {
+                       continue;
+               }
+               game.dwarves[i].loc = game.loc;
+               if (spotted_by_pirate(i)) {
+                       continue;
+               }
+               /* This threatening little dwarf is in the room with him! */
+               ++game.dtotal;
+               if (game.dwarves[i].oldloc == game.dwarves[i].loc) {
+                       ++attack;
+                       if (game.knfloc >= LOC_NOWHERE) {
+                               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;
        }
-        game.dflag = 2;
-        for (int i = 1; i <= 2; i++) {
-            int j = 1 + randrange(NDWARVES - 1);
-            if (PCT(50)) {
-                game.dwarves[j].loc = 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.dwarves[i].loc == game.loc) {
-                 game.dwarves[i].loc = DALTLC;
-           }
-            game.dwarves[i].oldloc = game.dwarves[i].loc;
-        }
-        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.dwarves[i].loc == 0) {
-             continue;
+       rspeak(game.dtotal == 1 ? DWARF_SINGLE : DWARF_PACK, game.dtotal);
+       if (attack == 0) {
+               return true;
        }
-        /*  Fill tk array with all the places this dwarf might go. */
-        unsigned int j = 1;
-        kk = tkey[game.dwarves[i].loc];
-        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.dwarves[i].oldloc)
-                    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.dwarves[i].loc)
-                    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.dwarves[i].oldloc;
-        if (j >= 2) {
-            --j;
+       if (game.dflag == 2) {
+               game.dflag = 3;
        }
-        j = 1 + randrange(j);
-        game.dwarves[i].oldloc = game.dwarves[i].loc;
-        game.dwarves[i].loc = tk[j];
-        game.dwarves[i].seen = (game.dwarves[i].seen && INDEEP(game.loc)) ||
-                        (game.dwarves[i].loc == game.loc ||
-                         game.dwarves[i].oldloc == game.loc);
-        if (!game.dwarves[i].seen) {
-            continue;
+       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);
        }
-        game.dwarves[i].loc = game.loc;
-        if (spotted_by_pirate(i)) {
-            continue;
+       if (stick == 0) {
+               return true;
        }
-        /* This threatening little dwarf is in the room with him! */
-        ++game.dtotal;
-        if (game.dwarves[i].oldloc == game.dwarves[i].loc) {
-            ++attack;
-            if (game.knfloc >= LOC_NOWHERE) {
-                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;
+       game.oldlc2 = game.loc;
+       return false;
 }
 
 /*  "You're dead, Jim."
@@ -451,69 +479,73 @@ static bool dwarfmove(void) {
  *  cave without the lamp!).  game.oldloc is zapped so he can't just
  *  "retreat". */
 static void croak(void) {
-/*  Okay, he's dead.  Let's get on with it. */
-    const char* query = obituaries[game.numdie].query;
-    const char* yes_response = obituaries[game.numdie].yes_response;
-
-    ++game.numdie;
-
-    if (game.closng) {
-        /*  He died during closing time.  No resurrection.  Tally up a
-         *  death and exit. */
-        rspeak(DEATH_CLOSING);
-        terminate(endgame);
-    } else if (!yes_or_no(query, yes_response, arbitrary_messages[OK_MAN])
-               || game.numdie == NDEATHS) {
-        /* Player is asked if he wants to try again. If not, or if
-         * he's already used all of his lives, we end the game */
-        terminate(endgame);
-    } else {
-        /* If player wishes to continue, we empty the liquids in the
-         * user's inventory, turn off the lamp, and drop all items
-         * where he died. */
-        game.objects[WATER].place = game.objects[OIL].place = LOC_NOWHERE;
-        if (TOTING(LAMP))
-            game.objects[LAMP].prop = LAMP_DARK;
-        for (int j = 1; j <= NOBJECTS; j++) {
-            int i = NOBJECTS + 1 - j;
-            if (TOTING(i)) {
-                /* Always leave lamp where it's accessible aboveground */
-                drop(i, (i == LAMP) ? LOC_START : game.oldlc2);
-            }
-        }
-        game.oldloc = game.loc = game.newloc = LOC_BUILDING;
-    }
+       /*  Okay, he's dead.  Let's get on with it. */
+       const char *query = obituaries[game.numdie].query;
+       const char *yes_response = obituaries[game.numdie].yes_response;
+
+       ++game.numdie;
+
+       if (game.closng) {
+               /*  He died during closing time.  No resurrection.  Tally up a
+                *  death and exit. */
+               rspeak(DEATH_CLOSING);
+               terminate(endgame);
+       } else if (!yes_or_no(query, yes_response,
+                             arbitrary_messages[OK_MAN]) ||
+                  game.numdie == NDEATHS) {
+               /* Player is asked if he wants to try again. If not, or if
+                * he's already used all of his lives, we end the game */
+               terminate(endgame);
+       } else {
+               /* If player wishes to continue, we empty the liquids in the
+                * user's inventory, turn off the lamp, and drop all items
+                * where he died. */
+               game.objects[WATER].place = game.objects[OIL].place =
+                   LOC_NOWHERE;
+               if (TOTING(LAMP))
+                       game.objects[LAMP].prop = LAMP_DARK;
+               for (int j = 1; j <= NOBJECTS; j++) {
+                       int i = NOBJECTS + 1 - j;
+                       if (TOTING(i)) {
+                               /* Always leave lamp where it's accessible
+                                * aboveground */
+                               drop(i, (i == LAMP) ? LOC_START : game.oldlc2);
+                       }
+               }
+               game.oldloc = game.loc = game.newloc = LOC_BUILDING;
+       }
 }
 
 static void describe_location(void) {
-/* Describe the location to the user */
-    const char* msg = locations[game.loc].description.small;
+       /* Describe the location to the user */
+       const char *msg = locations[game.loc].description.small;
 
-    if (MOD(game.locs[game.loc].abbrev, game.abbnum) == 0 || msg == NO_MESSAGE)
-        msg = locations[game.loc].description.big;
+       if (MOD(game.locs[game.loc].abbrev, game.abbnum) == 0 ||
+           msg == NO_MESSAGE)
+               msg = locations[game.loc].description.big;
 
-    if (!FORCED(game.loc) && DARK(game.loc)) {
-        msg = arbitrary_messages[PITCH_DARK];
-    }
+       if (!FORCED(game.loc) && DARK(game.loc)) {
+               msg = arbitrary_messages[PITCH_DARK];
+       }
 
-    if (TOTING(BEAR)) {
-        rspeak(TAME_BEAR);
-    }
+       if (TOTING(BEAR)) {
+               rspeak(TAME_BEAR);
+       }
 
-    speak(msg);
+       speak(msg);
 
-    if (game.loc == LOC_Y2 && PCT(25) && !game.closng)
-        rspeak(SAYS_PLUGH);
+       if (game.loc == LOC_Y2 && PCT(25) && !game.closng)
+               rspeak(SAYS_PLUGH);
 }
 
-
 static bool traveleq(int a, int b) {
-/* Are two travel entries equal for purposes of skip after failed condition? */
-    return (travel[a].condtype == travel[b].condtype)
-           && (travel[a].condarg1 == travel[b].condarg1)
-           && (travel[a].condarg2 == travel[b].condarg2)
-           && (travel[a].desttype == travel[b].desttype)
-           && (travel[a].destval == travel[b].destval);
+       /* Are two travel entries equal for purposes of skip after failed
+        * condition? */
+       return (travel[a].condtype == travel[b].condtype) &&
+              (travel[a].condarg1 == travel[b].condarg1) &&
+              (travel[a].condarg2 == travel[b].condarg2) &&
+              (travel[a].desttype == travel[b].desttype) &&
+              (travel[a].destval == travel[b].destval);
 }
 
 /*  Given the current location in "game.loc", and a motion verb number in
@@ -523,297 +555,342 @@ static bool traveleq(int a, int b) {
  *  does, game.newloc will be limbo, and game.oldloc will be what killed
  *  him, so we need game.oldlc2, which is the last place he was
  *  safe.) */
-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);
+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.locs[game.loc].abbrev = 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;
        }
-        ++game.detail;
-        game.wzdark = false;
-        game.locs[game.loc].abbrev = 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 ((travel[travel_entry].motion == HERE) || 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;
-                int condarg1 = travel[travel_entry].condarg1;
-                int 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.objects[condarg1].prop != condarg2) {
-                    break;
+
+       /* 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 ((travel[travel_entry].motion == HERE) ||
+                   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;
+       }
 
-                /* 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.objects[TROLL].prop == TROLL_PAIDONCE) {
-                        pspeak(TROLL, look, true, TROLL_PAIDONCE);
-                        game.objects[TROLL].prop = TROLL_UNPAID;
-                        DESTROY(TROLL2);
-                        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.objects[TROLL].prop == TROLL_UNPAID)
-                            game.objects[TROLL].prop = TROLL_PAIDONCE;
-                        if (!TOTING(BEAR)) {
-                            return;
+       /* (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;
+                               int condarg1 = travel[travel_entry].condarg1;
+                               int 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.objects[condarg1].prop !=
+                                          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;
                        }
-                        state_change(CHASM, BRIDGE_WRECKED);
-                        game.objects[TROLL].prop = TROLL_GONE;
-                        drop(BEAR, game.newloc);
-                        game.objects[BEAR].fixed = IS_FIXED;
-                        game.objects[BEAR].prop = 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);
+
+                       /* 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.objects[TROLL].prop ==
+                                           TROLL_PAIDONCE) {
+                                               pspeak(TROLL, look, true,
+                                                      TROLL_PAIDONCE);
+                                               game.objects[TROLL].prop =
+                                                   TROLL_UNPAID;
+                                               DESTROY(TROLL2);
+                                               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.objects[TROLL].prop ==
+                                                   TROLL_UNPAID)
+                                                       game.objects[TROLL]
+                                                           .prop =
+                                                           TROLL_PAIDONCE;
+                                               if (!TOTING(BEAR)) {
+                                                       return;
+                                               }
+                                               state_change(CHASM,
+                                                            BRIDGE_WRECKED);
+                                               game.objects[TROLL].prop =
+                                                   TROLL_GONE;
+                                               drop(BEAR, game.newloc);
+                                               game.objects[BEAR].fixed =
+                                                   IS_FIXED;
+                                               game.objects[BEAR].prop =
+                                                   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;
+       /* 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);
-           }
+                       /* 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);
+                       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);
+               }
        }
-    }
 }
 
 /*  Handle the closing of the cave.  The cave closes "clock1" turns
@@ -835,464 +912,503 @@ static void lampcheck(void) {
  *  arise from the use of negative prop numbers to suppress the object
  *  descriptions until he's actually moved the objects. */
 static bool closecheck(void) {
-    /* If a turn threshold has been met, apply penalties and tell
-     * the player about it. */
-    for (int i = 0; i < NTHRESHOLDS; ++i) {
-        if (game.turns == turn_thresholds[i].threshold + 1) {
-            game.trnluz += turn_thresholds[i].point_loss;
-            speak(turn_thresholds[i].message);
-        }
-    }
-
-    /*  Don't tick game.clock1 unless well into cave (and not at Y2). */
-    if (game.tally == 0 && INDEEP(game.loc) && game.loc != LOC_Y2) {
-        --game.clock1;
-    }
-
-    /*  When the first warning comes, we lock the grate, destroy
-     *  the bridge, kill all the dwarves (and the pirate), remove
-     *  the troll and bear (unless dead), and set "closng" to
-     *  true.  Leave the dragon; too much trouble to move it.
-     *  from now until clock2 runs out, he cannot unlock the
-     *  grate, move to any location outside the cave, or create
-     *  the bridge.  Nor can he be resurrected if he dies.  Note
-     *  that the snake is already gone, since he got to the
-     *  treasure accessible only via the hall of the mountain
-     *  king. Also, he's been in giant room (to get eggs), so we
-     *  can refer to it.  Also also, he's gotten the pearl, so we
-     *  know the bivalve is an oyster.  *And*, the dwarves must
-     *  have been activated, since we've found chest. */
-    if (game.clock1 == 0) {
-        game.objects[GRATE].prop = GRATE_CLOSED;
-        game.objects[FISSURE].prop = UNBRIDGED;
-        for (int i = 1; i <= NDWARVES; i++) {
-            game.dwarves[i].seen = false;
-            game.dwarves[i].loc = LOC_NOWHERE;
-        }
-        DESTROY(TROLL);
-        move(TROLL + NOBJECTS, IS_FREE);
-        move(TROLL2, objects[TROLL].plac);
-        move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
-        juggle(CHASM);
-        if (game.objects[BEAR].prop != BEAR_DEAD) {
-            DESTROY(BEAR);
+       /* If a turn threshold has been met, apply penalties and tell
+        * the player about it. */
+       for (int i = 0; i < NTHRESHOLDS; ++i) {
+               if (game.turns == turn_thresholds[i].threshold + 1) {
+                       game.trnluz += turn_thresholds[i].point_loss;
+                       speak(turn_thresholds[i].message);
+               }
        }
-        game.objects[CHAIN].prop = CHAIN_HEAP;
-        game.objects[CHAIN].fixed = IS_FREE;
-        game.objects[AXE].prop = AXE_HERE;
-        game.objects[AXE].fixed = IS_FREE;
-        rspeak(CAVE_CLOSING);
-        game.clock1 = -1;
-        game.closng = true;
-        return game.closed;
-    } else if (game.clock1 < 0)
-        --game.clock2;
-    if (game.clock2 == 0) {
-        /*  Once he's panicked, and clock2 has run out, we come here
-         *  to set up the storage room.  The room has two locs,
-         *  hardwired as LOC_NE and LOC_SW.  At the ne end, we
-         *  place empty bottles, a nursery of plants, a bed of
-         *  oysters, a pile of lamps, rods with stars, sleeping
-         *  dwarves, and him.  At the sw end we place grate over
-         *  treasures, snake pit, covey of caged birds, more rods, and
-         *  pillows.  A mirror stretches across one wall.  Many of the
-         *  objects come from known locations and/or states (e.g. the
-         *  snake is known to have been destroyed and needn't be
-         *  carried away from its old "place"), making the various
-         *  objects be handled differently.  We also drop all other 
-         *  objects he might be carrying (lest he has some which
-         *  could cause trouble, such as the keys).  We describe the
-         *  flash of light and trundle back. */
-        put(BOTTLE, LOC_NE, EMPTY_BOTTLE);
-        put(PLANT, LOC_NE, PLANT_THIRSTY);
-        put(OYSTER, LOC_NE, STATE_FOUND);
-        put(LAMP, LOC_NE, LAMP_DARK);
-        put(ROD, LOC_NE, STATE_FOUND);
-        put(DWARF, LOC_NE, STATE_FOUND);
-        game.loc = LOC_NE;
-        game.oldloc = LOC_NE;
-        game.newloc = LOC_NE;
-        /*  Leave the grate with normal (non-negative) property.
-         *  Reuse sign. */
-        move(GRATE, LOC_SW);
-        move(SIGN, LOC_SW);
-        game.objects[SIGN].prop = ENDGAME_SIGN;
-        put(SNAKE, LOC_SW, SNAKE_CHASED);
-        put(BIRD, LOC_SW, BIRD_CAGED);
-        put(CAGE, LOC_SW, STATE_FOUND);
-        put(ROD2, LOC_SW, STATE_FOUND);
-        put(PILLOW, LOC_SW, STATE_FOUND);
-
-        put(MIRROR, LOC_NE, STATE_FOUND);
-        game.objects[MIRROR].fixed = LOC_SW;
-
-        for (int i = 1; i <= NOBJECTS; i++) {
-           if (TOTING(i)) {
-                 DESTROY(i);
-           }
-        }
-
-        rspeak(CAVE_CLOSED);
-        game.closed = true;
-        return game.closed;
-    }
-
-    lampcheck();
-    return false;
-}
 
-static void listobjects(void) {
-/*  Print out descriptions of objects at this location.  If
- *  not closing and property value is negative, tally off
- *  another treasure.  Rug is special case; once seen, its
- *  game.prop is RUG_DRAGON (dragon on it) till dragon is killed.
- *  Similarly for chain; game.prop is initially CHAINING_BEAR (locked to
- *  bear).  These hacks are because game.prop=0 is needed to
- *  get full score. */
-    if (!DARK(game.loc)) {
-        ++game.locs[game.loc].abbrev;
-        for (int i = game.locs[game.loc].atloc; i != 0; i = game.link[i]) {
-            obj_t obj = i;
-            if (obj > NOBJECTS) {
-                obj = obj - NOBJECTS;
-           }
-            if (obj == STEPS && TOTING(NUGGET)) {
-                continue;
-           }
-           /* (ESR) Warning: it looks like you could get away with
-            * running this code only on objects with the treasure
-            * property set. Nope.  There is mystery here.
-            */
-            if (PROP_IS_STASHED_OR_UNSEEN(obj)) {
-               if (game.closed) {
-                     continue;
+       /*  Don't tick game.clock1 unless well into cave (and not at Y2). */
+       if (game.tally == 0 && INDEEP(game.loc) && game.loc != LOC_Y2) {
+               --game.clock1;
+       }
+
+       /*  When the first warning comes, we lock the grate, destroy
+        *  the bridge, kill all the dwarves (and the pirate), remove
+        *  the troll and bear (unless dead), and set "closng" to
+        *  true.  Leave the dragon; too much trouble to move it.
+        *  from now until clock2 runs out, he cannot unlock the
+        *  grate, move to any location outside the cave, or create
+        *  the bridge.  Nor can he be resurrected if he dies.  Note
+        *  that the snake is already gone, since he got to the
+        *  treasure accessible only via the hall of the mountain
+        *  king. Also, he's been in giant room (to get eggs), so we
+        *  can refer to it.  Also also, he's gotten the pearl, so we
+        *  know the bivalve is an oyster.  *And*, the dwarves must
+        *  have been activated, since we've found chest. */
+       if (game.clock1 == 0) {
+               game.objects[GRATE].prop = GRATE_CLOSED;
+               game.objects[FISSURE].prop = UNBRIDGED;
+               for (int i = 1; i <= NDWARVES; i++) {
+                       game.dwarves[i].seen = false;
+                       game.dwarves[i].loc = LOC_NOWHERE;
                }
-                PROP_SET_FOUND(obj);
-                if (obj == RUG) {
-                    game.objects[RUG].prop = RUG_DRAGON;
+               DESTROY(TROLL);
+               move(TROLL + NOBJECTS, IS_FREE);
+               move(TROLL2, objects[TROLL].plac);
+               move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
+               juggle(CHASM);
+               if (game.objects[BEAR].prop != BEAR_DEAD) {
+                       DESTROY(BEAR);
                }
-                if (obj == CHAIN) {
-                    game.objects[CHAIN].prop = CHAINING_BEAR;
+               game.objects[CHAIN].prop = CHAIN_HEAP;
+               game.objects[CHAIN].fixed = IS_FREE;
+               game.objects[AXE].prop = AXE_HERE;
+               game.objects[AXE].fixed = IS_FREE;
+               rspeak(CAVE_CLOSING);
+               game.clock1 = -1;
+               game.closng = true;
+               return game.closed;
+       } else if (game.clock1 < 0)
+               --game.clock2;
+       if (game.clock2 == 0) {
+               /*  Once he's panicked, and clock2 has run out, we come here
+                *  to set up the storage room.  The room has two locs,
+                *  hardwired as LOC_NE and LOC_SW.  At the ne end, we
+                *  place empty bottles, a nursery of plants, a bed of
+                *  oysters, a pile of lamps, rods with stars, sleeping
+                *  dwarves, and him.  At the sw end we place grate over
+                *  treasures, snake pit, covey of caged birds, more rods, and
+                *  pillows.  A mirror stretches across one wall.  Many of the
+                *  objects come from known locations and/or states (e.g. the
+                *  snake is known to have been destroyed and needn't be
+                *  carried away from its old "place"), making the various
+                *  objects be handled differently.  We also drop all other
+                *  objects he might be carrying (lest he has some which
+                *  could cause trouble, such as the keys).  We describe the
+                *  flash of light and trundle back. */
+               put(BOTTLE, LOC_NE, EMPTY_BOTTLE);
+               put(PLANT, LOC_NE, PLANT_THIRSTY);
+               put(OYSTER, LOC_NE, STATE_FOUND);
+               put(LAMP, LOC_NE, LAMP_DARK);
+               put(ROD, LOC_NE, STATE_FOUND);
+               put(DWARF, LOC_NE, STATE_FOUND);
+               game.loc = LOC_NE;
+               game.oldloc = LOC_NE;
+               game.newloc = LOC_NE;
+               /*  Leave the grate with normal (non-negative) property.
+                *  Reuse sign. */
+               move(GRATE, LOC_SW);
+               move(SIGN, LOC_SW);
+               game.objects[SIGN].prop = ENDGAME_SIGN;
+               put(SNAKE, LOC_SW, SNAKE_CHASED);
+               put(BIRD, LOC_SW, BIRD_CAGED);
+               put(CAGE, LOC_SW, STATE_FOUND);
+               put(ROD2, LOC_SW, STATE_FOUND);
+               put(PILLOW, LOC_SW, STATE_FOUND);
+
+               put(MIRROR, LOC_NE, STATE_FOUND);
+               game.objects[MIRROR].fixed = LOC_SW;
+
+               for (int i = 1; i <= NOBJECTS; i++) {
+                       if (TOTING(i)) {
+                               DESTROY(i);
+                       }
                }
-               if (obj == EGGS) {
-                   game.seenbigwords = true;
+
+               rspeak(CAVE_CLOSED);
+               game.closed = true;
+               return game.closed;
+       }
+
+       lampcheck();
+       return false;
+}
+
+static void listobjects(void) {
+       /*  Print out descriptions of objects at this location.  If
+        *  not closing and property value is negative, tally off
+        *  another treasure.  Rug is special case; once seen, its
+        *  game.prop is RUG_DRAGON (dragon on it) till dragon is killed.
+        *  Similarly for chain; game.prop is initially CHAINING_BEAR (locked to
+        *  bear).  These hacks are because game.prop=0 is needed to
+        *  get full score. */
+       if (!DARK(game.loc)) {
+               ++game.locs[game.loc].abbrev;
+               for (int i = game.locs[game.loc].atloc; i != 0;
+                    i = game.link[i]) {
+                       obj_t obj = i;
+                       if (obj > NOBJECTS) {
+                               obj = obj - NOBJECTS;
+                       }
+                       if (obj == STEPS && TOTING(NUGGET)) {
+                               continue;
+                       }
+                       /* (ESR) Warning: it looks like you could get away with
+                        * running this code only on objects with the treasure
+                        * property set. Nope.  There is mystery here.
+                        */
+                       if (PROP_IS_STASHED_OR_UNSEEN(obj)) {
+                               if (game.closed) {
+                                       continue;
+                               }
+                               PROP_SET_FOUND(obj);
+                               if (obj == RUG) {
+                                       game.objects[RUG].prop = RUG_DRAGON;
+                               }
+                               if (obj == CHAIN) {
+                                       game.objects[CHAIN].prop =
+                                           CHAINING_BEAR;
+                               }
+                               if (obj == EGGS) {
+                                       game.seenbigwords = true;
+                               }
+                               --game.tally;
+                               /*  Note: There used to be a test here to see
+                                * whether the player had blown it so badly that
+                                * he could never ever see the remaining
+                                * treasures, and if so the lamp was zapped to
+                                *  35 turns.  But the tests were too
+                                * simple-minded; things like killing the bird
+                                * before the snake was gone (can never see
+                                * jewelry), and doing it "right" was hopeless.
+                                * E.G., could cross troll bridge several times,
+                                * using up all available treasures, breaking
+                                * vase, using coins to buy batteries, etc., and
+                                * eventually never be able to get across again.
+                                * If bottle were left on far side, could then
+                                *  never get eggs or trident, and the effects
+                                * propagate.  So the whole thing was flushed.
+                                * anyone who makes such a gross blunder isn't
+                                * likely to find everything else anyway (so
+                                * goes the rationalisation). */
+                       }
+                       int kk = game.objects[obj].prop;
+                       if (obj == STEPS) {
+                               kk = (game.loc == game.objects[STEPS].fixed)
+                                        ? STEPS_UP
+                                        : STEPS_DOWN;
+                       }
+                       pspeak(obj, look, true, kk);
                }
-                --game.tally;
-                /*  Note: There used to be a test here to see whether the
-                 *  player had blown it so badly that he could never ever see
-                 *  the remaining treasures, and if so the lamp was zapped to
-                 *  35 turns.  But the tests were too simple-minded; things
-                 *  like killing the bird before the snake was gone (can never
-                 *  see jewelry), and doing it "right" was hopeless.  E.G.,
-                 *  could cross troll bridge several times, using up all
-                 *  available treasures, breaking vase, using coins to buy
-                 *  batteries, etc., and eventually never be able to get
-                 *  across again.  If bottle were left on far side, could then
-                 *  never get eggs or trident, and the effects propagate.  So
-                 *  the whole thing was flushed.  anyone who makes such a
-                 *  gross blunder isn't likely to find everything else anyway
-                 *  (so goes the rationalisation). */
-            }
-            int kk = game.objects[obj].prop;
-            if (obj == STEPS) {
-                kk = (game.loc == game.objects[STEPS].fixed)
-                     ? STEPS_UP
-                     : STEPS_DOWN;
-           }
-            pspeak(obj, look, true, kk);
-        }
-    }
+       }
 }
 
-/* Pre-processes a command input to see if we need to tease out a few specific cases:
+/* Pre-processes a command input to see if we need to tease out a few specific
+ * cases:
  * - "enter water" or "enter stream":
- *   weird specific case that gets the user wet, and then kicks us back to get another command
+ *   weird specific case that gets the user wet, and then kicks us back to get
+ * another command
  * - <object> <verb>:
- *   Irregular form of input, but should be allowed. We switch back to <verb> <object> form for
- *   further processing.
+ *   Irregular form of input, but should be allowed. We switch back to <verb>
+ * <object> form for further processing.
  * - "grate":
- *   If in location with grate, we move to that grate. If we're in a number of other places,
- *   we move to the entrance.
+ *   If in location with grate, we move to that grate. If we're in a number of
+ * other places, we move to the entrance.
  * - "water plant", "oil plant", "water door", "oil door":
  *   Change to "pour water" or "pour oil" based on context
  * - "cage bird":
  *   If bird is present, we change to "carry bird"
  *
- * Returns true if pre-processing is complete, and we're ready to move to the primary command
- * processing, false otherwise. */
+ * Returns true if pre-processing is complete, and we're ready to move to the
+ * primary command processing, false otherwise. */
 static bool preprocess_command(command_t *command) {
-    if (command->word[0].type == MOTION && command->word[0].id == ENTER
-        && (command->word[1].id == STREAM || command->word[1].id == WATER)) {
-       if (LIQLOC(game.loc) == WATER) {
-             rspeak(FEET_WET);
+       if (command->word[0].type == MOTION && command->word[0].id == ENTER &&
+           (command->word[1].id == STREAM || command->word[1].id == WATER)) {
+               if (LIQLOC(game.loc) == WATER) {
+                       rspeak(FEET_WET);
+               } else {
+                       rspeak(WHERE_QUERY);
+               }
        } else {
-             rspeak(WHERE_QUERY);
+               if (command->word[0].type == OBJECT) {
+                       /* From OV to VO form */
+                       if (command->word[1].type == ACTION) {
+                               command_word_t stage = command->word[0];
+                               command->word[0] = command->word[1];
+                               command->word[1] = stage;
+                       }
+
+                       if (command->word[0].id == GRATE) {
+                               command->word[0].type = MOTION;
+                               if (game.loc == LOC_START ||
+                                   game.loc == LOC_VALLEY ||
+                                   game.loc == LOC_SLIT) {
+                                       command->word[0].id = DEPRESSION;
+                               }
+                               if (game.loc == LOC_COBBLE ||
+                                   game.loc == LOC_DEBRIS ||
+                                   game.loc == LOC_AWKWARD ||
+                                   game.loc == LOC_BIRDCHAMBER ||
+                                   game.loc == LOC_PITTOP) {
+                                       command->word[0].id = ENTRANCE;
+                               }
+                       }
+                       if ((command->word[0].id == WATER ||
+                            command->word[0].id == OIL) &&
+                           (command->word[1].id == PLANT ||
+                            command->word[1].id == DOOR)) {
+                               if (AT(command->word[1].id)) {
+                                       command->word[1] = command->word[0];
+                                       command->word[0].id = POUR;
+                                       command->word[0].type = ACTION;
+                                       strncpy(command->word[0].raw, "pour",
+                                               LINESIZE - 1);
+                               }
+                       }
+                       if (command->word[0].id == CAGE &&
+                           command->word[1].id == BIRD && HERE(CAGE) &&
+                           HERE(BIRD)) {
+                               command->word[0].id = CARRY;
+                               command->word[0].type = ACTION;
+                       }
+               }
+
+               /* If no word type is given for the first word, we assume it's a
+                * motion. */
+               if (command->word[0].type == NO_WORD_TYPE)
+                       command->word[0].type = MOTION;
+
+               command->state = PREPROCESSED;
+               return true;
        }
-    } else {
-        if (command->word[0].type == OBJECT) {
-            /* From OV to VO form */
-            if (command->word[1].type == ACTION) {
-                command_word_t stage = command->word[0];
-                command->word[0] = command->word[1];
-                command->word[1] = stage;
-            }
-
-            if (command->word[0].id == GRATE) {
-                command->word[0].type = MOTION;
-                if (game.loc == LOC_START ||
-                    game.loc == LOC_VALLEY ||
-                    game.loc == LOC_SLIT) {
-                    command->word[0].id = DEPRESSION;
-                }
-                if (game.loc == LOC_COBBLE ||
-                    game.loc == LOC_DEBRIS ||
-                    game.loc == LOC_AWKWARD ||
-                    game.loc == LOC_BIRDCHAMBER ||
-                    game.loc == LOC_PITTOP) {
-                    command->word[0].id = ENTRANCE;
-                }
-            }
-            if ((command->word[0].id == WATER || command->word[0].id == OIL) &&
-                (command->word[1].id == PLANT || command->word[1].id == DOOR)) {
-                if (AT(command->word[1].id)) {
-                    command->word[1] = command->word[0];
-                    command->word[0].id = POUR;
-                    command->word[0].type = ACTION;
-                    strncpy(command->word[0].raw, "pour", LINESIZE - 1);
-                }
-            }
-            if (command->word[0].id == CAGE && command->word[1].id == BIRD && HERE(CAGE) && HERE(BIRD)) {
-                command->word[0].id = CARRY;
-                command->word[0].type = ACTION;
-            }
-        }
-
-        /* If no word type is given for the first word, we assume it's a motion. */
-        if (command->word[0].type == NO_WORD_TYPE)
-            command->word[0].type = MOTION;
-
-        command->state = PREPROCESSED;
-        return true;
-    }
-    return false;
+       return false;
 }
 
 static bool do_move(void) {
-/* Actually execute the move to the new location and dwarf movement */
-    /*  Can't leave cave once it's closing (except by main office). */
-    if (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
-        rspeak(EXIT_CLOSED);
-        game.newloc = game.loc;
-        if (!game.panic) {
-            game.clock2 = PANICTIME;
+       /* Actually execute the move to the new location and dwarf movement */
+       /*  Can't leave cave once it's closing (except by main office). */
+       if (OUTSID(game.newloc) && game.newloc != 0 && game.closng) {
+               rspeak(EXIT_CLOSED);
+               game.newloc = game.loc;
+               if (!game.panic) {
+                       game.clock2 = PANICTIME;
+               }
+               game.panic = true;
+       }
+
+       /*  See if a dwarf has seen him and has come from where he
+        *  wants to go.  If so, the dwarf's blocking his way.  If
+        *  coming from place forbidden to pirate (dwarves rooted in
+        *  place) let him get out (and attacked). */
+       if (game.newloc != game.loc && !FORCED(game.loc) &&
+           !CNDBIT(game.loc, COND_NOARRR)) {
+               for (size_t i = 1; i <= NDWARVES - 1; i++) {
+                       if (game.dwarves[i].oldloc == game.newloc &&
+                           game.dwarves[i].seen) {
+                               game.newloc = game.loc;
+                               rspeak(DWARF_BLOCK);
+                               break;
+                       }
+               }
+       }
+       game.loc = game.newloc;
+
+       if (!dwarfmove()) {
+               croak();
        }
-        game.panic = true;
-    }
-
-    /*  See if a dwarf has seen him and has come from where he
-     *  wants to go.  If so, the dwarf's blocking his way.  If
-     *  coming from place forbidden to pirate (dwarves rooted in
-     *  place) let him get out (and attacked). */
-    if (game.newloc != game.loc && !FORCED(game.loc) && !CNDBIT(game.loc, COND_NOARRR)) {
-        for (size_t i = 1; i <= NDWARVES - 1; i++) {
-            if (game.dwarves[i].oldloc == game.newloc && game.dwarves[i].seen) {
-                game.newloc = game.loc;
-                rspeak(DWARF_BLOCK);
-                break;
-            }
-        }
-    }
-    game.loc = game.newloc;
-
-    if (!dwarfmove()) {
-        croak();
-    }
-
-    if (game.loc == LOC_NOWHERE) {
-        croak();
-    }
-
-    /* The easiest way to get killed is to fall into a pit in
-     * pitch darkness. */
-    if (!FORCED(game.loc) && DARK(game.loc) && game.wzdark && PCT(PIT_KILL_PROB)) {
-        rspeak(PIT_FALL);
-        game.oldlc2 = game.loc;
-        croak();
-        return false;
-    }
-
-    return true;
+
+       if (game.loc == LOC_NOWHERE) {
+               croak();
+       }
+
+       /* The easiest way to get killed is to fall into a pit in
+        * pitch darkness. */
+       if (!FORCED(game.loc) && DARK(game.loc) && game.wzdark &&
+           PCT(PIT_KILL_PROB)) {
+               rspeak(PIT_FALL);
+               game.oldlc2 = game.loc;
+               croak();
+               return false;
+       }
+
+       return true;
 }
 
 static bool do_command(void) {
-/* Get and execute a command */
-    static command_t command;
-    clear_command(&command);
-
-    /* Describe the current location and (maybe) get next command. */
-    while (command.state != EXECUTED) {
-        describe_location();
-
-        if (FORCED(game.loc)) {
-            playermove(HERE);
-            return true;
-        }
-
-        listobjects();
-
-        /* Command not yet given; keep getting commands from user
-         * until valid command is both given and executed. */
-        clear_command(&command);
-        while (command.state <= GIVEN) {
-
-            if (game.closed) {
-                /*  If closing time, check for any stashed objects
-                 *  being toted and unstash them.  This way objects
-                 *  won't be described until they've been picked up
-                 *  and put down separate from their respective
-                 *  piles. */
-               if ((PROP_IS_NOTFOUND(OYSTER) || PROP_IS_STASHED(OYSTER)) && TOTING(OYSTER)) {
-                     pspeak(OYSTER, look, true, 1);
-               }
-                for (size_t i = 1; i <= NOBJECTS; i++) {
-                    if (TOTING(i) && (PROP_IS_NOTFOUND(i) || PROP_IS_STASHED(i)))
-                        game.objects[i].prop = PROP_STASHED(i);
-                }
-            }
-
-            /* Check to see if the room is dark. If the knife is here,
-             * and it's dark, the knife permanently disappears */
-            game.wzdark = DARK(game.loc);
-            if (game.knfloc != LOC_NOWHERE && game.knfloc != game.loc) {
-                game.knfloc = LOC_NOWHERE;
-           }
-
-            /* Check some for hints, get input from user, increment
-             * turn, and pre-process commands. Keep going until
-             * pre-processing is done. */
-            while ( command.state < PREPROCESSED ) {
-                checkhints();
-
-                /* Get command input from user */
-                if (!get_command_input(&command)) {
-                    return false;
+       /* Get and execute a command */
+       static command_t command;
+       clear_command(&command);
+
+       /* Describe the current location and (maybe) get next command. */
+       while (command.state != EXECUTED) {
+               describe_location();
+
+               if (FORCED(game.loc)) {
+                       playermove(HERE);
+                       return true;
                }
 
-                /* Every input, check "foobar" flag. If zero, nothing's going
-                 * on. If pos, make neg. If neg, he skipped a word, so make it
-                 * zero.
-                 */
-                game.foobar = (game.foobar > WORD_EMPTY) ? -game.foobar : WORD_EMPTY;
-
-                ++game.turns;
-                preprocess_command(&command);
-            }
-
-            /* check if game is closed, and exit if it is */
-            if (closecheck()) {
-                return true;
-           }
-
-            /* loop until all words in command are processed */
-            while (command.state == PREPROCESSED ) {
-                command.state = PROCESSING;
-
-                if (command.word[0].id == WORD_NOT_FOUND) {
-                    /* Gee, I don't understand. */
-                    sspeak(DONT_KNOW, command.word[0].raw);
-                    clear_command(&command);
-                    continue;
-                }
-
-                /* Give user hints of shortcuts */
-                if (strncasecmp(command.word[0].raw, "west", sizeof("west")) == 0) {
-                   if (++game.iwest == 10) {
-                         rspeak(W_IS_WEST);
-                   }
-                }
-                if (strncasecmp(command.word[0].raw, "go", sizeof("go")) == 0 && command.word[1].id != WORD_EMPTY) {
-                   if (++game.igo == 10) {
-                         rspeak(GO_UNNEEDED);
-                   }
-                }
-
-                switch (command.word[0].type) {
-                case MOTION:
-                    playermove(command.word[0].id);
-                    command.state = EXECUTED;
-                    continue;
-                case OBJECT:
-                    command.part = unknown;
-                    command.obj = command.word[0].id;
-                    break;
-                case ACTION:
-                   if (command.word[1].type == NUMERIC) {
-                         command.part = transitive;
-                   } else {
-                         command.part = intransitive;
-                   }
-                    command.verb = command.word[0].id;
-                    break;
-                case NUMERIC:
-                    if (!settings.oldstyle) {
-                        sspeak(DONT_KNOW, command.word[0].raw);
-                        clear_command(&command);
-                        continue;
-                    }
-                    break;// LCOV_EXCL_LINE
-                default: // LCOV_EXCL_LINE
-                case NO_WORD_TYPE: // LCOV_EXCL_LINE
-                    BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE
-                }
-
-                switch (action(command)) {
-                case GO_TERMINATE:
-                    command.state = EXECUTED;
-                    break;
-                case GO_MOVE:
-                    playermove(NUL);
-                    command.state = EXECUTED;
-                    break;
-                case GO_WORD2:
+               listobjects();
+
+               /* Command not yet given; keep getting commands from user
+                * until valid command is both given and executed. */
+               clear_command(&command);
+               while (command.state <= GIVEN) {
+
+                       if (game.closed) {
+                               /*  If closing time, check for any stashed
+                                * objects being toted and unstash them.  This
+                                * way objects won't be described until they've
+                                * been picked up and put down separate from
+                                * their respective piles. */
+                               if ((PROP_IS_NOTFOUND(OYSTER) ||
+                                    PROP_IS_STASHED(OYSTER)) &&
+                                   TOTING(OYSTER)) {
+                                       pspeak(OYSTER, look, true, 1);
+                               }
+                               for (size_t i = 1; i <= NOBJECTS; i++) {
+                                       if (TOTING(i) && (PROP_IS_NOTFOUND(i) ||
+                                                         PROP_IS_STASHED(i)))
+                                               game.objects[i].prop =
+                                                   PROP_STASHED(i);
+                               }
+                       }
+
+                       /* Check to see if the room is dark. If the knife is
+                        * here, and it's dark, the knife permanently disappears
+                        */
+                       game.wzdark = DARK(game.loc);
+                       if (game.knfloc != LOC_NOWHERE &&
+                           game.knfloc != game.loc) {
+                               game.knfloc = LOC_NOWHERE;
+                       }
+
+                       /* Check some for hints, get input from user, increment
+                        * turn, and pre-process commands. Keep going until
+                        * pre-processing is done. */
+                       while (command.state < PREPROCESSED) {
+                               checkhints();
+
+                               /* Get command input from user */
+                               if (!get_command_input(&command)) {
+                                       return false;
+                               }
+
+                               /* Every input, check "foobar" flag. If zero,
+                                * nothing's going on. If pos, make neg. If neg,
+                                * he skipped a word, so make it zero.
+                                */
+                               game.foobar = (game.foobar > WORD_EMPTY)
+                                                 ? -game.foobar
+                                                 : WORD_EMPTY;
+
+                               ++game.turns;
+                               preprocess_command(&command);
+                       }
+
+                       /* check if game is closed, and exit if it is */
+                       if (closecheck()) {
+                               return true;
+                       }
+
+                       /* loop until all words in command are processed */
+                       while (command.state == PREPROCESSED) {
+                               command.state = PROCESSING;
+
+                               if (command.word[0].id == WORD_NOT_FOUND) {
+                                       /* Gee, I don't understand. */
+                                       sspeak(DONT_KNOW, command.word[0].raw);
+                                       clear_command(&command);
+                                       continue;
+                               }
+
+                               /* Give user hints of shortcuts */
+                               if (strncasecmp(command.word[0].raw, "west",
+                                               sizeof("west")) == 0) {
+                                       if (++game.iwest == 10) {
+                                               rspeak(W_IS_WEST);
+                                       }
+                               }
+                               if (strncasecmp(command.word[0].raw, "go",
+                                               sizeof("go")) == 0 &&
+                                   command.word[1].id != WORD_EMPTY) {
+                                       if (++game.igo == 10) {
+                                               rspeak(GO_UNNEEDED);
+                                       }
+                               }
+
+                               switch (command.word[0].type) {
+                               case MOTION:
+                                       playermove(command.word[0].id);
+                                       command.state = EXECUTED;
+                                       continue;
+                               case OBJECT:
+                                       command.part = unknown;
+                                       command.obj = command.word[0].id;
+                                       break;
+                               case ACTION:
+                                       if (command.word[1].type == NUMERIC) {
+                                               command.part = transitive;
+                                       } else {
+                                               command.part = intransitive;
+                                       }
+                                       command.verb = command.word[0].id;
+                                       break;
+                               case NUMERIC:
+                                       if (!settings.oldstyle) {
+                                               sspeak(DONT_KNOW,
+                                                      command.word[0].raw);
+                                               clear_command(&command);
+                                               continue;
+                                       }
+                                       break;     // LCOV_EXCL_LINE
+                               default:           // LCOV_EXCL_LINE
+                               case NO_WORD_TYPE: // LCOV_EXCL_LINE
+                                       BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE
+                               }
+
+                               switch (action(command)) {
+                               case GO_TERMINATE:
+                                       command.state = EXECUTED;
+                                       break;
+                               case GO_MOVE:
+                                       playermove(NUL);
+                                       command.state = EXECUTED;
+                                       break;
+                               case GO_WORD2:
 #ifdef GDEBUG
-                    printf("Word shift\n");
+                                       printf("Word shift\n");
 #endif /* GDEBUG */
-                    /* Get second word for analysis. */
-                    command.word[0] = command.word[1];
-                    command.word[1] = empty_command_word;
-                    command.state = PREPROCESSED;
-                    break;
-                case GO_UNKNOWN:
-                    /*  Random intransitive verbs come here.  Clear obj just in case
-                     *  (see attack()). */
-                    command.word[0].raw[0] = toupper(command.word[0].raw[0]);
-                    sspeak(DO_WHAT, command.word[0].raw);
-                    command.obj = NO_OBJECT;
-
-                    /* object cleared; we need to go back to the preprocessing step */
-                    command.state = GIVEN;
-                    break;
-                case GO_CHECKHINT: // FIXME: re-name to be more contextual; this was previously a label
-                    command.state = GIVEN;
-                    break;
-                case GO_DWARFWAKE:
-                    /*  Oh dear, he's disturbed the dwarves. */
-                    rspeak(DWARVES_AWAKEN);
-                    terminate(endgame);
-                case GO_CLEAROBJ: // FIXME: re-name to be more contextual; this was previously a label
-                    clear_command(&command);
-                    break;
-                case GO_TOP: // FIXME: re-name to be more contextual; this was previously a label
-                    break;
-                default: // LCOV_EXCL_LINE
-                    BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH); // LCOV_EXCL_LINE
-                }
-            } /* while command has not been fully processed */
-        } /* while command is not yet given */
-    } /* while command is not executed */
-
-    /* command completely executed; we return true. */
-    return true;
+                                       /* Get second word for analysis. */
+                                       command.word[0] = command.word[1];
+                                       command.word[1] = empty_command_word;
+                                       command.state = PREPROCESSED;
+                                       break;
+                               case GO_UNKNOWN:
+                                       /*  Random intransitive verbs come here.
+                                        * Clear obj just in case (see
+                                        * attack()). */
+                                       command.word[0].raw[0] =
+                                           toupper(command.word[0].raw[0]);
+                                       sspeak(DO_WHAT, command.word[0].raw);
+                                       command.obj = NO_OBJECT;
+
+                                       /* object cleared; we need to go back to
+                                        * the preprocessing step */
+                                       command.state = GIVEN;
+                                       break;
+                               case GO_CHECKHINT: // FIXME: re-name to be more
+                                                  // contextual; this was
+                                                  // previously a label
+                                       command.state = GIVEN;
+                                       break;
+                               case GO_DWARFWAKE:
+                                       /*  Oh dear, he's disturbed the dwarves.
+                                        */
+                                       rspeak(DWARVES_AWAKEN);
+                                       terminate(endgame);
+                               case GO_CLEAROBJ: // FIXME: re-name to be more
+                                                 // contextual; this was
+                                                 // previously a label
+                                       clear_command(&command);
+                                       break;
+                               case GO_TOP: // FIXME: re-name to be more
+                                            // contextual; this was previously
+                                            // a label
+                                       break;
+                               default: // LCOV_EXCL_LINE
+                                       BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH); // LCOV_EXCL_LINE
+                               }
+                       } /* while command has not been fully processed */
+               }         /* while command is not yet given */
+       }                 /* while command is not executed */
+
+       /* command completely executed; we return true. */
+       return true;
 }
 
 /*
@@ -1306,132 +1422,140 @@ static bool do_command(void) {
  *          Revived 2017 as Open Adventure.
  */
 
-int main(int argc, char *argv[])
-{
-    int ch;
+int main(int argc, char *argv[]) {
+       int ch;
 
-    /*  Options. */
+       /*  Options. */
 
 #if defined ADVENT_AUTOSAVE
-    const char* opts = "dl:oa:";
-    const char* usage = "Usage: %s [-l logfilename] [-o] [-a filename] [script...]\n";
-    FILE *rfp = NULL;
-    const char* autosave_filename = NULL;
+       const char *opts = "dl:oa:";
+       const char *usage =
+           "Usage: %s [-l logfilename] [-o] [-a filename] [script...]\n";
+       FILE *rfp = NULL;
+       const char *autosave_filename = NULL;
 #elif !defined ADVENT_NOSAVE
-    const char* opts = "dl:or:";
-    const char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename] [script...]\n";
-    FILE *rfp = NULL;
+       const char *opts = "dl:or:";
+       const char *usage = "Usage: %s [-l logfilename] [-o] [-r "
+                           "restorefilename] [script...]\n";
+       FILE *rfp = NULL;
 #else
-    const char* opts = "dl:o";
-    const char* usage = "Usage: %s [-l logfilename] [-o] [script...]\n";
+       const char *opts = "dl:o";
+       const char *usage = "Usage: %s [-l logfilename] [-o] [script...]\n";
 #endif
-    while ((ch = getopt(argc, argv, opts)) != EOF) {
-        switch (ch) {
-       case 'd': // LCOV_EXCL_LINE
-           settings.debug +=1; // LCOV_EXCL_LINE
-           break; // LCOV_EXCL_LINE
-        case 'l':
-            settings.logfp = fopen(optarg, "w");
-            if (settings.logfp == NULL) {
-                fprintf(stderr,
-                        "advent: can't open logfile %s for write\n",
-                        optarg);
-           }
-            signal(SIGINT, sig_handler);
-            break;
-        case 'o':
-            settings.oldstyle = true;
-            settings.prompt = false;
-            break;
+       while ((ch = getopt(argc, argv, opts)) != EOF) {
+               switch (ch) {
+               case 'd':                    // LCOV_EXCL_LINE
+                       settings.debug += 1; // LCOV_EXCL_LINE
+                       break;               // LCOV_EXCL_LINE
+               case 'l':
+                       settings.logfp = fopen(optarg, "w");
+                       if (settings.logfp == NULL) {
+                               fprintf(
+                                   stderr,
+                                   "advent: can't open logfile %s for write\n",
+                                   optarg);
+                       }
+                       signal(SIGINT, sig_handler);
+                       break;
+               case 'o':
+                       settings.oldstyle = true;
+                       settings.prompt = false;
+                       break;
 #ifdef ADVENT_AUTOSAVE
-        case 'a':
-            rfp = fopen(optarg, READ_MODE);
-            autosave_filename = optarg;
-            signal(SIGHUP, sig_handler);
-            signal(SIGTERM, sig_handler);
-            break;
+               case 'a':
+                       rfp = fopen(optarg, READ_MODE);
+                       autosave_filename = optarg;
+                       signal(SIGHUP, sig_handler);
+                       signal(SIGTERM, sig_handler);
+                       break;
 #elif !defined ADVENT_NOSAVE
-        case 'r':
-            rfp = fopen(optarg, "r");
-            if (rfp == NULL) {
-                fprintf(stderr,
-                        "advent: can't open save file %s for read\n",
-                        optarg);
-           }
-            break;
+               case 'r':
+                       rfp = fopen(optarg, "r");
+                       if (rfp == NULL) {
+                               fprintf(stderr,
+                                       "advent: can't open save file %s for "
+                                       "read\n",
+                                       optarg);
+                       }
+                       break;
 #endif
-        default:
-            fprintf(stderr,
-                    usage, argv[0]);
-            fprintf(stderr,
-                    "        -l create a log file of your game named as specified'\n");
-            fprintf(stderr,
-                    "        -o 'oldstyle' (no prompt, no command editing, displays 'Initialising...')\n");
+               default:
+                       fprintf(stderr, usage, argv[0]);
+                       fprintf(stderr, "        -l create a log file of your "
+                                       "game named as specified'\n");
+                       fprintf(stderr,
+                               "        -o 'oldstyle' (no prompt, no command "
+                               "editing, displays 'Initialising...')\n");
 #if defined ADVENT_AUTOSAVE
-            fprintf(stderr,
-                    "        -a automatic save/restore from specified saved game file\n");
+                       fprintf(stderr, "        -a automatic save/restore "
+                                       "from specified saved game file\n");
 #elif !defined ADVENT_NOSAVE
-            fprintf(stderr,
-                    "        -r restore from specified saved game file\n");
+                       fprintf(stderr, "        -r restore from specified "
+                                       "saved game file\n");
 #endif
-            exit(EXIT_FAILURE);
-            break;
-        }
-    }
+                       exit(EXIT_FAILURE);
+                       break;
+               }
+       }
 
-    /* copy invocation line part after switches */
-    settings.argc = argc - optind;
-    settings.argv = argv + optind;
-    settings.optind = 0;
+       /* copy invocation line part after switches */
+       settings.argc = argc - optind;
+       settings.argv = argv + optind;
+       settings.optind = 0;
 
-    /*  Initialize game variables */
-    int seedval = initialise();
+       /*  Initialize game variables */
+       int seedval = initialise();
 
 #if !defined ADVENT_NOSAVE
-    if (!rfp) {
-        game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]);
-        if (game.novice) {
-            game.limit = NOVICELIMIT;
-       }
-    } else {
-        restore(rfp);
+       if (!rfp) {
+               game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU],
+                                       arbitrary_messages[CAVE_NEARBY],
+                                       arbitrary_messages[NO_MESSAGE]);
+               if (game.novice) {
+                       game.limit = NOVICELIMIT;
+               }
+       } else {
+               restore(rfp);
 #if defined ADVENT_AUTOSAVE
-        score(scoregame);
+               score(scoregame);
 #endif
-    }
+       }
 #if defined ADVENT_AUTOSAVE
-    if (autosave_filename != NULL) {
-        if ((autosave_fp = fopen(autosave_filename, WRITE_MODE)) == NULL) {
-            perror(autosave_filename);
-            return EXIT_FAILURE;
-        }
-        autosave();
-    }
+       if (autosave_filename != NULL) {
+               if ((autosave_fp = fopen(autosave_filename, WRITE_MODE)) ==
+                   NULL) {
+                       perror(autosave_filename);
+                       return EXIT_FAILURE;
+               }
+               autosave();
+       }
 #endif
 #else
-    game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]);
-    if (game.novice)
-        game.limit = NOVICELIMIT;
+       game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU],
+                               arbitrary_messages[CAVE_NEARBY],
+                               arbitrary_messages[NO_MESSAGE]);
+       if (game.novice)
+               game.limit = NOVICELIMIT;
 #endif
 
-    if (settings.logfp) {
-        fprintf(settings.logfp, "seed %d\n", seedval);
-    }
-
-    /* interpret commands until EOF or interrupt */
-    for (;;) {
-        // if we're supposed to move, move
-       if (!do_move()) {
-             continue;
+       if (settings.logfp) {
+               fprintf(settings.logfp, "seed %d\n", seedval);
        }
 
-         // get command
-       if (!do_command()) {
-             break;
+       /* interpret commands until EOF or interrupt */
+       for (;;) {
+               // if we're supposed to move, move
+               if (!do_move()) {
+                       continue;
+               }
+
+               // get command
+               if (!do_command()) {
+                       break;
+               }
        }
-    }
-    /* show score and exit */
-    terminate(quitgame);
+       /* show score and exit */
+       terminate(quitgame);
 }
 
 /* end */
diff --git a/misc.c b/misc.c
index c853237f742195bd1a837f8779737cac5de7df64..ad110d98e5ea7c7d106a4aac0f0f068e2206883f 100644 (file)
--- a/misc.c
+++ b/misc.c
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/time.h>
 #include <ctype.h>
 #include <editline/readline.h>
 #include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
 
 #include "advent.h"
 #include "dungeon.h"
 
-static void* xcalloc(size_t size)
-{
-    void* ptr = calloc(size, 1);
-    if (ptr == NULL) {
-        // LCOV_EXCL_START
-        // exclude from coverage analysis because we can't simulate an out of memory error in testing
-        fprintf(stderr, "Out of memory!\n");
-        exit(EXIT_FAILURE);
-        // LCOV_EXCL_STOP
-    }
-    return (ptr);
+static void *xcalloc(size_t size) {
+       void *ptr = calloc(size, 1);
+       if (ptr == NULL) {
+               // LCOV_EXCL_START
+               // exclude from coverage analysis because we can't simulate an
+               // out of memory error in testing
+               fprintf(stderr, "Out of memory!\n");
+               exit(EXIT_FAILURE);
+               // LCOV_EXCL_STOP
+       }
+       return (ptr);
 }
 
 /*  I/O routines (speak, pspeak, rspeak, sspeak, get_input, yes) */
 
-static void vspeak(const char* msg, bool blank, va_list ap)
-/* Engine for various speak functions */
-{
-    // Do nothing if we got a null pointer.
-    if (msg == NULL)
-        return;
-
-    // Do nothing if we got an empty string.
-    if (strlen(msg) == 0)
-        return;
-
-    if (blank == true)
-        printf("\n");
-
-    int msglen = strlen(msg);
-
-    // Rendered string
-    ssize_t size = 2000; /* msglen > 50 ? msglen*2 : 100; */
-    char* rendered = xcalloc(size);
-    char* renderp = rendered;
-
-    // Handle format specifiers (including the custom %S) by
-    // adjusting the parameter accordingly, and replacing the
-    // specifier with %s.
-    bool pluralize = false;
-    for (int i = 0; i < msglen; i++) {
-        if (msg[i] != '%') {
-            /* Ugh.  Least obtrusive way to deal with artifacts "on the floor"
-             * being dropped outside of both cave and building. */
-            if (strncmp(msg + i, "floor", 5) == 0 && strchr(" .", msg[i + 5]) && !INSIDE(game.loc)) {
-                strcpy(renderp, "ground");
-                renderp += 6;
-                i += 4;
-                size -= 5;
-            } else {
-                *renderp++ = msg[i];
-                size--;
-            }
-        } else {
-            i++;
-            // Integer specifier.
-            if (msg[i] == 'd') {
-                int32_t arg = va_arg(ap, int32_t);
-                int ret = snprintf(renderp, size, "%" PRId32, arg);
-                if (ret < size) {
-                    renderp += ret;
-                    size -= ret;
-                }
-                pluralize = (arg != 1);
-            }
-
-            // Unmodified string specifier.
-            if (msg[i] == 's') {
-                char *arg = va_arg(ap, char *);
-                strncat(renderp, arg, size - 1);
-                size_t len = strlen(renderp);
-                renderp += len;
-                size -= len;
-            }
-
-            // Singular/plural specifier.
-            if (msg[i] == 'S') {
-                // look at the *previous* numeric parameter
-                if (pluralize) {
-                    *renderp++ = 's';
-                    size--;
-                }
-            }
-
-            // LCOV_EXCL_START - doesn't occur in test suite.
-            /* Version specifier */
-            if (msg[i] == 'V') {
-                strcpy(renderp, VERSION);
-                size_t len = strlen(VERSION);
-                renderp += len;
-                size -= len;
-            }
-            // LCOV_EXCL_STOP
-        }
-    }
-    *renderp = 0;
-
-    // Print the message.
-    printf("%s\n", rendered);
-
-    free(rendered);
-}
-
-void speak(const char* msg, ...)
-/* speak a specified string */
-{
-    va_list ap;
-    va_start(ap, msg);
-    vspeak(msg, true, ap);
-    va_end(ap);
-}
-
-void sspeak(const int msg, ...)
-/* Speak a message from the arbitrary-messages list */
-{
-    va_list ap;
-    va_start(ap, msg);
-    fputc('\n', stdout);
-    vprintf(arbitrary_messages[msg], ap);
-    fputc('\n', stdout);
-    va_end(ap);
-}
-
-void pspeak(vocab_t msg, enum speaktype mode, bool blank, int skip, ...)
-/* Find the skip+1st message from msg and print it.  Modes are:
- * feel = for inventory, what you can touch
- * look = the full description for the state the object is in
- * listen = the sound for the state the object is in
- * study = text on the object. */
-{
-    va_list ap;
-    va_start(ap, skip);
-    switch (mode) {
-    case touch:
-        vspeak(objects[msg].inventory, blank, ap);
-        break;
-    case look:
-        vspeak(objects[msg].descriptions[skip], blank, ap);
-        break;
-    case hear:
-        vspeak(objects[msg].sounds[skip], blank, ap);
-        break;
-    case study:
-        vspeak(objects[msg].texts[skip], blank, ap);
-        break;
-    case change:
-        vspeak(objects[msg].changes[skip], blank, ap);
-        break;
-    }
-    va_end(ap);
-}
-
-void rspeak(vocab_t i, ...)
-/* Print the i-th "random" message (section 6 of database). */
-{
-    va_list ap;
-    va_start(ap, i);
-    vspeak(arbitrary_messages[i], true, ap);
-    va_end(ap);
-}
-
-void echo_input(FILE* destination, const char* input_prompt, const char* input)
-{
-    size_t len = strlen(input_prompt) + strlen(input) + 1;
-    char* prompt_and_input = (char*) xcalloc(len);
-    strcpy(prompt_and_input, input_prompt);
-    strcat(prompt_and_input, input);
-    fprintf(destination, "%s\n", prompt_and_input);
-    free(prompt_and_input);
-}
-
-static int word_count(char* str)
-{
-    char delims[] = " \t";
-    int count = 0;
-    int inblanks = true;
-
-    for (char *s = str; *s; s++)
-        if (inblanks) {
-            if (strchr(delims, *s) == 0) {
-                ++count;
-                inblanks = false;
-            }
-        } else {
-            if (strchr(delims, *s) != 0) {
-                inblanks = true;
-            }
-        }
-
-    return (count);
-}
-
-static char* get_input(void)
-{
-    // Set up the prompt
-    char input_prompt[] = PROMPT;
-    if (!settings.prompt)
-        input_prompt[0] = '\0';
-
-    // Print a blank line
-    printf("\n");
-
-    char* input;
-    for (;;) {
-        input = myreadline(input_prompt);
-
-        if (input == NULL) // Got EOF; return with it.
-            return (input);
-        if (input[0] == '#') { // Ignore comments.
-            free(input);
-            continue;
-        }
-        // We have a 'normal' line; leave the loop.
-        break;
-    }
-
-    // Strip trailing newlines from the input
-    input[strcspn(input, "\n")] = 0;
-
-    add_history(input);
-
-    if (!isatty(0))
-        echo_input(stdout, input_prompt, input);
-
-    if (settings.logfp)
-        echo_input(settings.logfp, "", input);
-
-    return (input);
-}
-
-bool silent_yes_or_no(void)
-{
-    bool outcome = false;
-
-    for (;;) {
-        char* reply = get_input();
-        if (reply == NULL) {
-            // LCOV_EXCL_START
-            // Should be unreachable. Reply should never be NULL
-            free(reply);
-            exit(EXIT_SUCCESS);
-            // LCOV_EXCL_STOP
-        }
-        if (strlen(reply) == 0) {
-            free(reply);
-            rspeak(PLEASE_ANSWER);
-            continue;
-        }
-
-        char* firstword = (char*) xcalloc(strlen(reply) + 1);
-        sscanf(reply, "%s", firstword);
-
-        free(reply);
-
-        for (int i = 0; i < (int)strlen(firstword); ++i)
-            firstword[i] = tolower(firstword[i]);
-
-        int yes = strncmp("yes", firstword, sizeof("yes") - 1);
-        int y = strncmp("y", firstword, sizeof("y") - 1);
-        int no = strncmp("no", firstword, sizeof("no") - 1);
-        int n = strncmp("n", firstword, sizeof("n") - 1);
-
-        free(firstword);
-
-        if (yes == 0 || y == 0) {
-            outcome = true;
-            break;
-        } else if (no == 0 || n == 0) {
-            outcome = false;
-            break;
-        } else
-            rspeak(PLEASE_ANSWER);
-    }
-    return (outcome);
-}
-
-
-bool yes_or_no(const char* question, const char* yes_response, const char* no_response)
-/*  Print message X, wait for yes/no answer.  If yes, print Y and return true;
- *  if no, print Z and return false. */
-{
-    bool outcome = false;
-
-    for (;;) {
-        speak(question);
-
-        char* reply = get_input();
-        if (reply == NULL) {
-            // LCOV_EXCL_START
-            // Should be unreachable. Reply should never be NULL
-            free(reply);
-            exit(EXIT_SUCCESS);
-            // LCOV_EXCL_STOP
-        }
-
-        if (strlen(reply) == 0) {
-            free(reply);
-            rspeak(PLEASE_ANSWER);
-            continue;
-        }
-
-        char* firstword = (char*) xcalloc(strlen(reply) + 1);
-        sscanf(reply, "%s", firstword);
-
-        free(reply);
-
-        for (int i = 0; i < (int)strlen(firstword); ++i)
-            firstword[i] = tolower(firstword[i]);
-
-        int yes = strncmp("yes", firstword, sizeof("yes") - 1);
-        int y = strncmp("y", firstword, sizeof("y") - 1);
-        int no = strncmp("no", firstword, sizeof("no") - 1);
-        int n = strncmp("n", firstword, sizeof("n") - 1);
-
-        free(firstword);
-
-        if (yes == 0 || y == 0) {
-            speak(yes_response);
-            outcome = true;
-            break;
-        } else if (no == 0 || n == 0) {
-            speak(no_response);
-            outcome = false;
-            break;
-        } else
-            rspeak(PLEASE_ANSWER);
-
-    }
-
-    return (outcome);
-}
-
-/*  Data structure  routines */
-
-static int get_motion_vocab_id(const char* word)
-// Return the first motion number that has 'word' as one of its words.
-{
-    for (int i = 0; i < NMOTIONS; ++i) {
-        for (int j = 0; j < motions[i].words.n; ++j) {
-            if (strncasecmp(word, motions[i].words.strs[j], TOKLEN) == 0 && (strlen(word) > 1 ||
-                    strchr(ignore, word[0]) == NULL ||
-                    !settings.oldstyle))
-                return (i);
-        }
-    }
-    // If execution reaches here, we didn't find the word.
-    return (WORD_NOT_FOUND);
-}
-
-static int get_object_vocab_id(const char* word)
-// Return the first object number that has 'word' as one of its words.
-{
-    for (int i = 0; i < NOBJECTS + 1; ++i) { // FIXME: the + 1 should go when 1-indexing for objects is removed
-        for (int j = 0; j < objects[i].words.n; ++j) {
-            if (strncasecmp(word, objects[i].words.strs[j], TOKLEN) == 0)
-                return (i);
-        }
-    }
-    // If execution reaches here, we didn't find the word.
-    return (WORD_NOT_FOUND);
-}
-
-static int get_action_vocab_id(const char* word)
-// Return the first motion number that has 'word' as one of its words.
-{
-    for (int i = 0; i < NACTIONS; ++i) {
-        for (int j = 0; j < actions[i].words.n; ++j) {
-            if (strncasecmp(word, actions[i].words.strs[j], TOKLEN) == 0 && (strlen(word) > 1 ||
-                    strchr(ignore, word[0]) == NULL ||
-                    !settings.oldstyle))
-                return (i);
-        }
-    }
-    // If execution reaches here, we didn't find the word.
-    return (WORD_NOT_FOUND);
-}
-
-static bool is_valid_int(const char *str)
-/* Returns true if the string passed in is represents a valid integer,
- * that could then be parsed by atoi() */
-{
-    // Handle negative number
-    if (*str == '-')
-        ++str;
-
-    // Handle empty string or just "-". Should never reach this
-    // point, because this is only used with transitive verbs.
-    if (!*str)
-        return false; // LCOV_EXCL_LINE
-
-    // Check for non-digit chars in the rest of the string.
-    while (*str) {
-        if (!isdigit(*str))
-            return false;
-        else
-            ++str;
-    }
-
-    return true;
-}
-
-static void get_vocab_metadata(const char* word, vocab_t* id, word_type_t* type)
-{
-    /* Check for an empty string */
-    if (strncmp(word, "", sizeof("")) == 0) {
-        *id = WORD_EMPTY;
-        *type = NO_WORD_TYPE;
-        return;
-    }
-
-    vocab_t ref_num;
-
-    ref_num = get_motion_vocab_id(word);
-    // Second conjunct is because the magic-word placeholder is a bit special
-    if (ref_num != WORD_NOT_FOUND) {
-        *id = ref_num;
-        *type = MOTION;
-        return;
-    }
-
-    ref_num = get_object_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND) {
-        *id = ref_num;
-        *type = OBJECT;
-        return;
-    }
-
-    ref_num = get_action_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND && ref_num != PART) {
-        *id = ref_num;
-        *type = ACTION;
-        return;
-    }
-
-    // Check for the reservoir magic word.
-    if (strcasecmp(word, game.zzword) == 0) {
-        *id = PART;
-        *type = ACTION;
-        return;
-    }
-
-    // Check words that are actually numbers.
-    if (is_valid_int(word)) {
-        *id = WORD_EMPTY;
-        *type = NUMERIC;
-        return;
-    }
-
-    *id = WORD_NOT_FOUND;
-    *type = NO_WORD_TYPE;
-    return;
-}
-
-static void tokenize(char* raw, command_t *cmd)
-{
-    /*
-     * Be careful about modifying this. We do not want to nuke the
-     * the speech part or ID from the previous turn.
-     */
-    memset(&cmd->word[0].raw, '\0', sizeof(cmd->word[0].raw));
-    memset(&cmd->word[1].raw, '\0', sizeof(cmd->word[1].raw));
-
-    /* Bound prefix on the %s would be needed to prevent buffer
-     * overflow.  but we shortstop this more simply by making each
-     * raw-input buffer as int as the entire input buffer. */
-    sscanf(raw, "%s%s", cmd->word[0].raw, cmd->word[1].raw);
-
-    /* (ESR) In oldstyle mode, simulate the uppercasing and truncating
-     * effect on raw tokens of packing them into sixbit characters, 5
-     * to a 32-bit word.  This is something the FORTRAN version did
-     * because archaic FORTRAN had no string types.  Don Wood's
-     * mechanical translation of 2.5 to C retained the packing and
-     * thus this misfeature.
-     *
-     * It's philosophically questionable whether this is the right
-     * thing to do even in oldstyle mode.  On one hand, the text
-     * mangling was not authorial intent, but a result of limitations
-     * in their tools. On the other, not simulating this misbehavior
-     * goes against the goal of making oldstyle as accurate as
-     * possible an emulation of the original UI.
-     */
-    if (settings.oldstyle) {
-        cmd->word[0].raw[TOKLEN + TOKLEN] = cmd->word[1].raw[TOKLEN + TOKLEN] = '\0';
-        for (size_t i = 0; i < strlen(cmd->word[0].raw); i++)
-            cmd->word[0].raw[i] = toupper(cmd->word[0].raw[i]);
-        for (size_t i = 0; i < strlen(cmd->word[1].raw); i++)
-            cmd->word[1].raw[i] = toupper(cmd->word[1].raw[i]);
-    }
-
-    /* populate command with parsed vocabulary metadata */
-    get_vocab_metadata(cmd->word[0].raw, &(cmd->word[0].id), &(cmd->word[0].type));
-    get_vocab_metadata(cmd->word[1].raw, &(cmd->word[1].id), &(cmd->word[1].type));
-    cmd->state = TOKENIZED;
-}
-
-bool get_command_input(command_t *command)
-/* Get user input on stdin, parse and map to command */
-{
-    char inputbuf[LINESIZE];
-    char* input;
-
-    for (;;) {
-        input = get_input();
-        if (input == NULL)
-            return false;
-        if (word_count(input) > 2) {
-            rspeak(TWO_WORDS);
-            free(input);
-            continue;
-        }
-        if (strcmp(input, "") != 0)
-            break;
-        free(input);
-    }
-
-    strncpy(inputbuf, input, LINESIZE - 1);
-    free(input);
-
-    tokenize(inputbuf, command);
+static void vspeak(const char *msg, bool blank, va_list ap) {
+       /* Engine for various speak functions */
+       // Do nothing if we got a null pointer.
+       if (msg == NULL) {
+               return;
+       }
+
+       // Do nothing if we got an empty string.
+       if (strlen(msg) == 0) {
+               return;
+       }
+
+       if (blank == true) {
+               printf("\n");
+       }
+
+       int msglen = strlen(msg);
+
+       // Rendered string
+       ssize_t size = 2000; /* msglen > 50 ? msglen*2 : 100; */
+       char *rendered = xcalloc(size);
+       char *renderp = rendered;
+
+       // Handle format specifiers (including the custom %S) by
+       // adjusting the parameter accordingly, and replacing the
+       // specifier with %s.
+       bool pluralize = false;
+       for (int i = 0; i < msglen; i++) {
+               if (msg[i] != '%') {
+                       /* Ugh.  Least obtrusive way to deal with artifacts "on
+                        * the floor" being dropped outside of both cave and
+                        * building. */
+                       if (strncmp(msg + i, "floor", 5) == 0 &&
+                           strchr(" .", msg[i + 5]) && !INSIDE(game.loc)) {
+                               strcpy(renderp, "ground");
+                               renderp += 6;
+                               i += 4;
+                               size -= 5;
+                       } else {
+                               *renderp++ = msg[i];
+                               size--;
+                       }
+               } else {
+                       i++;
+                       // Integer specifier.
+                       if (msg[i] == 'd') {
+                               int32_t arg = va_arg(ap, int32_t);
+                               int ret =
+                                   snprintf(renderp, size, "%" PRId32, arg);
+                               if (ret < size) {
+                                       renderp += ret;
+                                       size -= ret;
+                               }
+                               pluralize = (arg != 1);
+                       }
+
+                       // Unmodified string specifier.
+                       if (msg[i] == 's') {
+                               char *arg = va_arg(ap, char *);
+                               strncat(renderp, arg, size - 1);
+                               size_t len = strlen(renderp);
+                               renderp += len;
+                               size -= len;
+                       }
+
+                       // Singular/plural specifier.
+                       if (msg[i] == 'S') {
+                               // look at the *previous* numeric parameter
+                               if (pluralize) {
+                                       *renderp++ = 's';
+                                       size--;
+                               }
+                       }
+
+                       // LCOV_EXCL_START - doesn't occur in test suite.
+                       /* Version specifier */
+                       if (msg[i] == 'V') {
+                               strcpy(renderp, VERSION);
+                               size_t len = strlen(VERSION);
+                               renderp += len;
+                               size -= len;
+                       }
+                       // LCOV_EXCL_STOP
+               }
+       }
+       *renderp = 0;
+
+       // Print the message.
+       printf("%s\n", rendered);
+
+       free(rendered);
+}
+
+void speak(const char *msg, ...) {
+       /* speak a specified string */
+       va_list ap;
+       va_start(ap, msg);
+       vspeak(msg, true, ap);
+       va_end(ap);
+}
+
+void sspeak(const int msg, ...) {
+       /* Speak a message from the arbitrary-messages list */
+       va_list ap;
+       va_start(ap, msg);
+       fputc('\n', stdout);
+       vprintf(arbitrary_messages[msg], ap);
+       fputc('\n', stdout);
+       va_end(ap);
+}
+
+void pspeak(vocab_t msg, enum speaktype mode, bool blank, int skip, ...) {
+       /* Find the skip+1st message from msg and print it.  Modes are:
+        * feel = for inventory, what you can touch
+        * look = the full description for the state the object is in
+        * listen = the sound for the state the object is in
+        * study = text on the object. */
+       va_list ap;
+       va_start(ap, skip);
+       switch (mode) {
+       case touch:
+               vspeak(objects[msg].inventory, blank, ap);
+               break;
+       case look:
+               vspeak(objects[msg].descriptions[skip], blank, ap);
+               break;
+       case hear:
+               vspeak(objects[msg].sounds[skip], blank, ap);
+               break;
+       case study:
+               vspeak(objects[msg].texts[skip], blank, ap);
+               break;
+       case change:
+               vspeak(objects[msg].changes[skip], blank, ap);
+               break;
+       }
+       va_end(ap);
+}
+
+void rspeak(vocab_t i, ...) {
+       /* Print the i-th "random" message (section 6 of database). */
+       va_list ap;
+       va_start(ap, i);
+       vspeak(arbitrary_messages[i], true, ap);
+       va_end(ap);
+}
+
+void echo_input(FILE *destination, const char *input_prompt,
+                const char *input) {
+       size_t len = strlen(input_prompt) + strlen(input) + 1;
+       char *prompt_and_input = (char *)xcalloc(len);
+       strcpy(prompt_and_input, input_prompt);
+       strcat(prompt_and_input, input);
+       fprintf(destination, "%s\n", prompt_and_input);
+       free(prompt_and_input);
+}
+
+static int word_count(char *str) {
+       char delims[] = " \t";
+       int count = 0;
+       int inblanks = true;
+
+       for (char *s = str; *s; s++)
+               if (inblanks) {
+                       if (strchr(delims, *s) == 0) {
+                               ++count;
+                               inblanks = false;
+                       }
+               } else {
+                       if (strchr(delims, *s) != 0) {
+                               inblanks = true;
+                       }
+               }
+
+       return (count);
+}
+
+static char *get_input(void) {
+       // Set up the prompt
+       char input_prompt[] = PROMPT;
+       if (!settings.prompt)
+               input_prompt[0] = '\0';
+
+       // Print a blank line
+       printf("\n");
+
+       char *input;
+       for (;;) {
+               input = myreadline(input_prompt);
+
+               if (input == NULL) // Got EOF; return with it.
+                       return (input);
+               if (input[0] == '#') { // Ignore comments.
+                       free(input);
+                       continue;
+               }
+               // We have a 'normal' line; leave the loop.
+               break;
+       }
+
+       // Strip trailing newlines from the input
+       input[strcspn(input, "\n")] = 0;
+
+       add_history(input);
+
+       if (!isatty(0))
+               echo_input(stdout, input_prompt, input);
+
+       if (settings.logfp)
+               echo_input(settings.logfp, "", input);
+
+       return (input);
+}
+
+bool silent_yes_or_no(void) {
+       bool outcome = false;
+
+       for (;;) {
+               char *reply = get_input();
+               if (reply == NULL) {
+                       // LCOV_EXCL_START
+                       // Should be unreachable. Reply should never be NULL
+                       free(reply);
+                       exit(EXIT_SUCCESS);
+                       // LCOV_EXCL_STOP
+               }
+               if (strlen(reply) == 0) {
+                       free(reply);
+                       rspeak(PLEASE_ANSWER);
+                       continue;
+               }
+
+               char *firstword = (char *)xcalloc(strlen(reply) + 1);
+               sscanf(reply, "%s", firstword);
+
+               free(reply);
+
+               for (int i = 0; i < (int)strlen(firstword); ++i)
+                       firstword[i] = tolower(firstword[i]);
+
+               int yes = strncmp("yes", firstword, sizeof("yes") - 1);
+               int y = strncmp("y", firstword, sizeof("y") - 1);
+               int no = strncmp("no", firstword, sizeof("no") - 1);
+               int n = strncmp("n", firstword, sizeof("n") - 1);
+
+               free(firstword);
+
+               if (yes == 0 || y == 0) {
+                       outcome = true;
+                       break;
+               } else if (no == 0 || n == 0) {
+                       outcome = false;
+                       break;
+               } else
+                       rspeak(PLEASE_ANSWER);
+       }
+       return (outcome);
+}
+
+bool yes_or_no(const char *question, const char *yes_response,
+               const char *no_response) {
+       /*  Print message X, wait for yes/no answer.  If yes, print Y and return
+        * true; if no, print Z and return false. */
+       bool outcome = false;
+
+       for (;;) {
+               speak(question);
+
+               char *reply = get_input();
+               if (reply == NULL) {
+                       // LCOV_EXCL_START
+                       // Should be unreachable. Reply should never be NULL
+                       free(reply);
+                       exit(EXIT_SUCCESS);
+                       // LCOV_EXCL_STOP
+               }
+
+               if (strlen(reply) == 0) {
+                       free(reply);
+                       rspeak(PLEASE_ANSWER);
+                       continue;
+               }
+
+               char *firstword = (char *)xcalloc(strlen(reply) + 1);
+               sscanf(reply, "%s", firstword);
+
+               free(reply);
+
+               for (int i = 0; i < (int)strlen(firstword); ++i) {
+                       firstword[i] = tolower(firstword[i]);
+               }
+
+               int yes = strncmp("yes", firstword, sizeof("yes") - 1);
+               int y = strncmp("y", firstword, sizeof("y") - 1);
+               int no = strncmp("no", firstword, sizeof("no") - 1);
+               int n = strncmp("n", firstword, sizeof("n") - 1);
+
+               free(firstword);
+
+               if (yes == 0 || y == 0) {
+                       speak(yes_response);
+                       outcome = true;
+                       break;
+               } else if (no == 0 || n == 0) {
+                       speak(no_response);
+                       outcome = false;
+                       break;
+               } else
+                       rspeak(PLEASE_ANSWER);
+       }
+
+       return (outcome);
+}
+
+/*  Data structure routines */
+
+static int get_motion_vocab_id(const char *word) {
+       // Return the first motion number that has 'word' as one of its words.
+       for (int i = 0; i < NMOTIONS; ++i) {
+               for (int j = 0; j < motions[i].words.n; ++j) {
+                       if (strncasecmp(word, motions[i].words.strs[j],
+                                       TOKLEN) == 0 &&
+                           (strlen(word) > 1 ||
+                            strchr(ignore, word[0]) == NULL ||
+                            !settings.oldstyle))
+                               return (i);
+               }
+       }
+       // If execution reaches here, we didn't find the word.
+       return (WORD_NOT_FOUND);
+}
+
+static int get_object_vocab_id(const char *word) {
+       // Return the first object number that has 'word' as one of its words.
+       for (int i = 0; i < NOBJECTS + 1;
+            ++i) { // FIXME: the + 1 should go when 1-indexing for objects is
+                   // removed
+               for (int j = 0; j < objects[i].words.n; ++j) {
+                       if (strncasecmp(word, objects[i].words.strs[j],
+                                       TOKLEN) == 0)
+                               return (i);
+               }
+       }
+       // If execution reaches here, we didn't find the word.
+       return (WORD_NOT_FOUND);
+}
+
+static int get_action_vocab_id(const char *word) {
+       // Return the first motion number that has 'word' as one of its words.
+       for (int i = 0; i < NACTIONS; ++i) {
+               for (int j = 0; j < actions[i].words.n; ++j) {
+                       if (strncasecmp(word, actions[i].words.strs[j],
+                                       TOKLEN) == 0 &&
+                           (strlen(word) > 1 ||
+                            strchr(ignore, word[0]) == NULL ||
+                            !settings.oldstyle)) {
+                               return (i);
+                       }
+               }
+       }
+       // If execution reaches here, we didn't find the word.
+       return (WORD_NOT_FOUND);
+}
+
+static bool is_valid_int(const char *str) {
+       /* Returns true if the string passed in is represents a valid integer,
+        * that could then be parsed by atoi() */
+       // Handle negative number
+       if (*str == '-') {
+               ++str;
+       }
+
+       // Handle empty string or just "-". Should never reach this
+       // point, because this is only used with transitive verbs.
+       if (!*str) {
+               return false; // LCOV_EXCL_LINE
+       }
+
+       // Check for non-digit chars in the rest of the string.
+       while (*str) {
+               if (!isdigit(*str)) {
+                       return false;
+               } else {
+                       ++str;
+               }
+       }
+
+       return true;
+}
+
+static void get_vocab_metadata(const char *word, vocab_t *id,
+                               word_type_t *type) {
+       /* Check for an empty string */
+       if (strncmp(word, "", sizeof("")) == 0) {
+               *id = WORD_EMPTY;
+               *type = NO_WORD_TYPE;
+               return;
+       }
+
+       vocab_t ref_num;
+
+       ref_num = get_motion_vocab_id(word);
+       // Second conjunct is because the magic-word placeholder is a bit
+       // special
+       if (ref_num != WORD_NOT_FOUND) {
+               *id = ref_num;
+               *type = MOTION;
+               return;
+       }
+
+       ref_num = get_object_vocab_id(word);
+       if (ref_num != WORD_NOT_FOUND) {
+               *id = ref_num;
+               *type = OBJECT;
+               return;
+       }
+
+       ref_num = get_action_vocab_id(word);
+       if (ref_num != WORD_NOT_FOUND && ref_num != PART) {
+               *id = ref_num;
+               *type = ACTION;
+               return;
+       }
+
+       // Check for the reservoir magic word.
+       if (strcasecmp(word, game.zzword) == 0) {
+               *id = PART;
+               *type = ACTION;
+               return;
+       }
+
+       // Check words that are actually numbers.
+       if (is_valid_int(word)) {
+               *id = WORD_EMPTY;
+               *type = NUMERIC;
+               return;
+       }
+
+       *id = WORD_NOT_FOUND;
+       *type = NO_WORD_TYPE;
+       return;
+}
+
+static void tokenize(char *raw, command_t *cmd) {
+       /*
+        * Be careful about modifying this. We do not want to nuke the
+        * the speech part or ID from the previous turn.
+        */
+       memset(&cmd->word[0].raw, '\0', sizeof(cmd->word[0].raw));
+       memset(&cmd->word[1].raw, '\0', sizeof(cmd->word[1].raw));
+
+       /* Bound prefix on the %s would be needed to prevent buffer
+        * overflow.  but we shortstop this more simply by making each
+        * raw-input buffer as int as the entire input buffer. */
+       sscanf(raw, "%s%s", cmd->word[0].raw, cmd->word[1].raw);
+
+       /* (ESR) In oldstyle mode, simulate the uppercasing and truncating
+        * effect on raw tokens of packing them into sixbit characters, 5
+        * to a 32-bit word.  This is something the FORTRAN version did
+        * because archaic FORTRAN had no string types.  Don Wood's
+        * mechanical translation of 2.5 to C retained the packing and
+        * thus this misfeature.
+        *
+        * It's philosophically questionable whether this is the right
+        * thing to do even in oldstyle mode.  On one hand, the text
+        * mangling was not authorial intent, but a result of limitations
+        * in their tools. On the other, not simulating this misbehavior
+        * goes against the goal of making oldstyle as accurate as
+        * possible an emulation of the original UI.
+        */
+       if (settings.oldstyle) {
+               cmd->word[0].raw[TOKLEN + TOKLEN] =
+                   cmd->word[1].raw[TOKLEN + TOKLEN] = '\0';
+               for (size_t i = 0; i < strlen(cmd->word[0].raw); i++) {
+                       cmd->word[0].raw[i] = toupper(cmd->word[0].raw[i]);
+               }
+               for (size_t i = 0; i < strlen(cmd->word[1].raw); i++) {
+                       cmd->word[1].raw[i] = toupper(cmd->word[1].raw[i]);
+               }
+       }
+
+       /* populate command with parsed vocabulary metadata */
+       get_vocab_metadata(cmd->word[0].raw, &(cmd->word[0].id),
+                          &(cmd->word[0].type));
+       get_vocab_metadata(cmd->word[1].raw, &(cmd->word[1].id),
+                          &(cmd->word[1].type));
+       cmd->state = TOKENIZED;
+}
+
+bool get_command_input(command_t *command) {
+       /* Get user input on stdin, parse and map to command */
+       char inputbuf[LINESIZE];
+       char *input;
+
+       for (;;) {
+               input = get_input();
+               if (input == NULL)
+                       return false;
+               if (word_count(input) > 2) {
+                       rspeak(TWO_WORDS);
+                       free(input);
+                       continue;
+               }
+               if (strcmp(input, "") != 0) {
+                       break;
+               }
+               free(input);
+       }
+
+       strncpy(inputbuf, input, LINESIZE - 1);
+       free(input);
+
+       tokenize(inputbuf, command);
 
 #ifdef GDEBUG
-    /* Needs to stay synced with enum word_type_t */
-    const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION", "NUMERIC"};
-    /* needs to stay synced with enum speechpart */
-    const char *roles[] = {"unknown", "intransitive", "transitive"};
-    printf("Command: role = %s type1 = %s, id1 = %d, type2 = %s, id2 = %d\n",
-           roles[command->part],
-           types[command->word[0].type],
-           command->word[0].id,
-           types[command->word[1].type],
-           command->word[1].id);
+       /* Needs to stay synced with enum word_type_t */
+       const char *types[] = {"NO_WORD_TYPE", "MOTION", "OBJECT", "ACTION",
+                              "NUMERIC"};
+       /* needs to stay synced with enum speechpart */
+       const char *roles[] = {"unknown", "intransitive", "transitive"};
+       printf(
+           "Command: role = %s type1 = %s, id1 = %d, type2 = %s, id2 = %d\n",
+           roles[command->part], types[command->word[0].type],
+           command->word[0].id, types[command->word[1].type],
+           command->word[1].id);
 #endif
 
-    command->state = GIVEN;
-    return true;
-}
-
-void clear_command(command_t *cmd)
-/* Resets the state of the command to empty */
-{
-    cmd->verb = ACT_NULL;
-    cmd->part = unknown;
-    game.oldobj = cmd->obj;
-    cmd->obj = NO_OBJECT;
-    cmd->state = EMPTY;
-}
-
-void juggle(obj_t object)
-/*  Juggle an object by picking it up and putting it down again, the purpose
- *  being to get the object to the front of the chain of things at its loc. */
-{
-    loc_t i, j;
-
-    i = game.objects[object].place;
-    j = game.objects[object].fixed;
-    move(object, i);
-    move(object + NOBJECTS, j);
-}
-
-void move(obj_t object, loc_t where)
-/*  Place any object anywhere by picking it up and dropping it.  May
- *  already be toting, in which case the carry is a no-op.  Mustn't
- *  pick up objects which are not at any loc, since carry wants to
- *  remove objects from game atloc chains. */
-{
-    loc_t from;
-
-    if (object > NOBJECTS)
-        from = game.objects[object - NOBJECTS].fixed;
-    else
-        from = game.objects[object].place;
-    /* (ESR) Used to check for !SPECIAL(from). I *think* that was wrong... */
-    if (from != LOC_NOWHERE && from != CARRIED)
-        carry(object, from);
-    drop(object, where);
-}
-
-void put(obj_t object, loc_t where, int pval)
-/*  put() is the same as move(), except it returns a value used to set up the
- *  negated game.prop values for the repository objects. */
-{
-    move(object, where);
-    /* (ESR) Read this in combination with the macro defintions in advebt.h.
-     */
-    game.objects[object].prop = PROP_STASHIFY(pval);
-#ifdef PROP_SET_SEEN
-    PROP_SET_SEEN(object);
-#endif
+       command->state = GIVEN;
+       return true;
 }
 
-void carry(obj_t object, loc_t where)
-/*  Start toting an object, removing it from the list of things at its former
- *  location.  Incr holdng unless it was already being toted.  If object>NOBJECTS
- *  (moving "fixed" second loc), don't change game.place or game.holdng. */
-{
-    int temp;
+void clear_command(command_t *cmd) {
+       /* Resets the state of the command to empty */
+       cmd->verb = ACT_NULL;
+       cmd->part = unknown;
+       game.oldobj = cmd->obj;
+       cmd->obj = NO_OBJECT;
+       cmd->state = EMPTY;
+}
 
-    if (object <= NOBJECTS) {
-        if (game.objects[object].place == CARRIED)
-            return;
-        game.objects[object].place = CARRIED;
+void juggle(obj_t object) {
+       /*  Juggle an object by picking it up and putting it down again, the
+        * purpose being to get the object to the front of the chain of things
+        * at its loc. */
+       loc_t i, j;
 
-       /*
-        * Without this conditional your inventory is overcounted
-        * when you pick up the bird while it's caged. This fixes
-        * a cosmetic bug in the original.
-        *
-        * Possibly this check should be skipped whwn oldstyle is on.
+       i = game.objects[object].place;
+       j = game.objects[object].fixed;
+       move(object, i);
+       move(object + NOBJECTS, j);
+}
+
+void move(obj_t object, loc_t where) {
+       /*  Place any object anywhere by picking it up and dropping it.  May
+        *  already be toting, in which case the carry is a no-op.  Mustn't
+        *  pick up objects which are not at any loc, since carry wants to
+        *  remove objects from game atloc chains. */
+       loc_t from;
+
+       if (object > NOBJECTS) {
+               from = game.objects[object - NOBJECTS].fixed;
+       } else {
+               from = game.objects[object].place;
+       }
+       /* (ESR) Used to check for !SPECIAL(from). I *think* that was wrong...
         */
-        if (object != BIRD)
-            ++game.holdng;
-    }
-    if (game.locs[where].atloc == object) {
-        game.locs[where].atloc = game.link[object];
-        return;
-    }
-    temp = game.locs[where].atloc;
-    while (game.link[temp] != object) {
-        temp = game.link[temp];
-    }
-    game.link[temp] = game.link[object];
-}
-
-void drop(obj_t object, loc_t where)
-/*  Place an object at a given loc, prefixing it onto the game atloc list.  Decr
- *  game.holdng if the object was being toted. No state change on the object. */
-{
-    if (object > NOBJECTS)
-        game.objects[object - NOBJECTS].fixed = where;
-    else {
-        if (game.objects[object].place == CARRIED)
-            if (object != BIRD)
-                /* The bird has to be weightless.  This ugly hack (and the
-                 * corresponding code in the carry function) brought to you
-                 * by the fact that when the bird is caged, we need to be able
-                 * to either 'take bird' or 'take cage' and have the right thing
-                 * happen.
-                 */
-                --game.holdng;
-        game.objects[object].place = where;
-    }
-    if (where == LOC_NOWHERE || where == CARRIED)
-        return;
-    game.link[object] = game.locs[where].atloc;
-    game.locs[where].atloc = object;
-}
-
-int atdwrf(loc_t where)
-/*  Return the index of first dwarf at the given location, zero if no dwarf is
- *  there (or if dwarves not active yet), -1 if all dwarves are dead.  Ignore
- *  the pirate (6th dwarf). */
-{
-    int at;
-
-    at = 0;
-    if (game.dflag < 2)
-        return at;
-    at = -1;
-    for (int i = 1; i <= NDWARVES - 1; i++) {
-        if (game.dwarves[i].loc == where)
-            return i;
-        if (game.dwarves[i].loc != 0)
-            at = 0;
-    }
-    return at;
+       if (from != LOC_NOWHERE && from != CARRIED) {
+               carry(object, from);
+       }
+       drop(object, where);
+}
+
+void put(obj_t object, loc_t where, int pval) {
+       /*  put() is the same as move(), except it returns a value used to set
+        * up the negated game.prop values for the repository objects. */
+       move(object, where);
+       /* (ESR) Read this in combination with the macro defintions in advebt.h.
+        */
+       game.objects[object].prop = PROP_STASHIFY(pval);
+#ifdef PROP_SET_SEEN
+       PROP_SET_SEEN(object);
+#endif
+}
+
+void carry(obj_t object, loc_t where) {
+       /*  Start toting an object, removing it from the list of things at its
+        * former location.  Incr holdng unless it was already being toted.  If
+        * object>NOBJECTS (moving "fixed" second loc), don't change game.place
+        * or game.holdng. */
+       int temp;
+
+       if (object <= NOBJECTS) {
+               if (game.objects[object].place == CARRIED) {
+                       return;
+               }
+               game.objects[object].place = CARRIED;
+
+               /*
+                * Without this conditional your inventory is overcounted
+                * when you pick up the bird while it's caged. This fixes
+                * a cosmetic bug in the original.
+                *
+                * Possibly this check should be skipped whwn oldstyle is on.
+                */
+               if (object != BIRD)
+                       ++game.holdng;
+       }
+       if (game.locs[where].atloc == object) {
+               game.locs[where].atloc = game.link[object];
+               return;
+       }
+       temp = game.locs[where].atloc;
+       while (game.link[temp] != object) {
+               temp = game.link[temp];
+       }
+       game.link[temp] = game.link[object];
+}
+
+void drop(obj_t object, loc_t where) {
+       /*  Place an object at a given loc, prefixing it onto the game atloc
+        * list.  Decr game.holdng if the object was being toted. No state
+        * change on the object. */
+       if (object > NOBJECTS) {
+               game.objects[object - NOBJECTS].fixed = where;
+       } else {
+               if (game.objects[object].place == CARRIED)
+                       if (object != BIRD)
+                               /* The bird has to be weightless.  This ugly
+                                * hack (and the corresponding code in the carry
+                                * function) brought to you by the fact that
+                                * when the bird is caged, we need to be able to
+                                * either 'take bird' or 'take cage' and have
+                                * the right thing happen.
+                                */
+                               --game.holdng;
+               game.objects[object].place = where;
+       }
+       if (where == LOC_NOWHERE || where == CARRIED) {
+               return;
+       }
+       game.link[object] = game.locs[where].atloc;
+       game.locs[where].atloc = object;
+}
+
+int atdwrf(loc_t where) {
+       /*  Return the index of first dwarf at the given location, zero if no
+        * dwarf is there (or if dwarves not active yet), -1 if all dwarves are
+        * dead.  Ignore the pirate (6th dwarf). */
+       int at;
+
+       at = 0;
+       if (game.dflag < 2) {
+               return at;
+       }
+       at = -1;
+       for (int i = 1; i <= NDWARVES - 1; i++) {
+               if (game.dwarves[i].loc == where) {
+                       return i;
+               }
+               if (game.dwarves[i].loc != 0) {
+                       at = 0;
+               }
+       }
+       return at;
 }
 
 /*  Utility routines (setbit, tstbit, set_seed, get_next_lcg_value,
  *  randrange) */
 
-int setbit(int bit)
-/*  Returns 2**bit for use in constructing bit-masks. */
-{
-    return (1L << bit);
+int setbit(int bit) {
+       /*  Returns 2**bit for use in constructing bit-masks. */
+       return (1L << bit);
 }
 
-bool tstbit(int mask, int bit)
-/*  Returns true if the specified bit is set in the mask. */
-{
-    return (mask & (1 << bit)) != 0;
+bool tstbit(int mask, int bit) {
+       /*  Returns true if the specified bit is set in the mask. */
+       return (mask & (1 << bit)) != 0;
 }
 
-void set_seed(int32_t seedval)
-/* Set the LCG1 seed */
-{
-    game.lcg_x = seedval % LCG_M;
-    if (game.lcg_x < 0) {
-        game.lcg_x = LCG_M + game.lcg_x;
-    }
-    // once seed is set, we need to generate the Z`ZZZ word
-    for (int i = 0; i < 5; ++i) {
-        game.zzword[i] = 'A' + randrange(26);
-    }
-    game.zzword[1] = '\''; // force second char to apostrophe
-    game.zzword[5] = '\0';
+void set_seed(int32_t seedval) {
+       /* Set the LCG1 seed */
+       game.lcg_x = seedval % LCG_M;
+       if (game.lcg_x < 0) {
+               game.lcg_x = LCG_M + game.lcg_x;
+       }
+       // once seed is set, we need to generate the Z`ZZZ word
+       for (int i = 0; i < 5; ++i) {
+               game.zzword[i] = 'A' + randrange(26);
+       }
+       game.zzword[1] = '\''; // force second char to apostrophe
+       game.zzword[5] = '\0';
 }
 
-static int32_t get_next_lcg_value(void)
-/* Return the LCG's current value, and then iterate it. */
-{
-    int32_t old_x = game.lcg_x;
-    game.lcg_x = (LCG_A * game.lcg_x + LCG_C) % LCG_M;
-    if (settings.debug) {
-       printf("# random %d\n", old_x); // LCOV_EXCL_LINE
-    }
-    return old_x;
+static int32_t get_next_lcg_value(void) {
+       /* Return the LCG's current value, and then iterate it. */
+       int32_t old_x = game.lcg_x;
+       game.lcg_x = (LCG_A * game.lcg_x + LCG_C) % LCG_M;
+       if (settings.debug) {
+               printf("# random %d\n", old_x); // LCOV_EXCL_LINE
+       }
+       return old_x;
 }
 
-int32_t randrange(int32_t range)
-/* Return a random integer from [0, range). */
-{
-    return range * get_next_lcg_value() / LCG_M;
+int32_t randrange(int32_t range) {
+       /* Return a random integer from [0, range). */
+       return range * get_next_lcg_value() / LCG_M;
 }
 
 // LCOV_EXCL_START
-void bug(enum bugtype num, const char *error_string)
-{
-    fprintf(stderr, "Fatal error %d, %s.\n", num, error_string);
-    exit(EXIT_FAILURE);
+void bug(enum bugtype num, const char *error_string) {
+       fprintf(stderr, "Fatal error %d, %s.\n", num, error_string);
+       exit(EXIT_FAILURE);
 }
 // LCOV_EXCL_STOP
 
-void state_change(obj_t obj, int state)
-/* Object must have a change-message list for this to be useful; only some do */
-{
-    game.objects[obj].prop = state;
-    pspeak(obj, change, true, state);
+void state_change(obj_t obj, int state) {
+       /* Object must have a change-message list for this to be useful; only
+        * some do */
+       game.objects[obj].prop = state;
+       pspeak(obj, change, true, state);
 }
 
 /* end */
index 34404c69f548b591f2e8abddf967b3ca5c5e9faf..ea30e4d09643f53ee23b72be26014294950ecec8 100644 (file)
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <ctype.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <time.h>
-#include <inttypes.h>
 
 #include "advent.h"
 
 /*
  * Use this to detect endianness mismatch.  Can't be unchanged by byte-swapping.
  */
-#define ENDIAN_MAGIC   2317
+#define ENDIAN_MAGIC 2317
 
 struct save_t save;
 
-#define IGNORE(r) do{if (r){}}while(0)
-
-int savefile(FILE *fp)
-/* Save game to file. No input or output from user. */
-{
-    memcpy(&save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC));
-    if (save.version == 0)
-       save.version = SAVE_VERSION;
-    if (save.canary == 0)
-       save.canary = ENDIAN_MAGIC;
-
-    save.game = game;
-    IGNORE(fwrite(&save, sizeof(struct save_t), 1, fp));
-    return (0);
+#define IGNORE(r)                                                              \
+       do {                                                                   \
+               if (r) {                                                       \
+               }                                                              \
+       } while (0)
+
+int savefile(FILE *fp) {
+       /* Save game to file. No input or output from user. */
+       memcpy(&save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC));
+       if (save.version == 0) {
+               save.version = SAVE_VERSION;
+       }
+       if (save.canary == 0) {
+               save.canary = ENDIAN_MAGIC;
+       }
+       save.game = game;
+       IGNORE(fwrite(&save, sizeof(struct save_t), 1, fp));
+       return (0);
 }
 
 /* Suspend and resume */
 
-static char *strip(char *name)
-{
-    // Trim leading whitespace
-    while(isspace((unsigned char)*name))
-       name++; // LCOV_EXCL_LINE
-    if(*name != '\0') {
-       // Trim trailing whitespace;
-       // might be left there by autocomplete
-       char *end = name + strlen(name) - 1;
-       while(end > name && isspace((unsigned char)*end))
-           end--;
-       // Write new null terminator character
-       end[1] = '\0';
-    }
-
-    return name;
+static char *strip(char *name) {
+       // Trim leading whitespace
+       while (isspace((unsigned char)*name)) {
+               name++; // LCOV_EXCL_LINE
+       }
+       if (*name != '\0') {
+               // Trim trailing whitespace;
+               // might be left there by autocomplete
+               char *end = name + strlen(name) - 1;
+               while (end > name && isspace((unsigned char)*end)) {
+                       end--;
+               }
+               // Write new null terminator character
+               end[1] = '\0';
+       }
+
+       return name;
 }
 
-int suspend(void)
-{
-    /*  Suspend.  Offer to save things in a file, but charging
-     *  some points (so can't win by using saved games to retry
-     *  battles or to start over after learning zzword).
-     *  If ADVENT_NOSAVE is defined, gripe instead. */
+int suspend(void) {
+       /*  Suspend.  Offer to save things in a file, but charging
+        *  some points (so can't win by using saved games to retry
+        *  battles or to start over after learning zzword).
+        *  If ADVENT_NOSAVE is defined, gripe instead. */
 
 #if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
-    rspeak(SAVERESUME_DISABLED);
-    return GO_TOP;
+       rspeak(SAVERESUME_DISABLED);
+       return GO_TOP;
 #endif
-    FILE *fp = NULL;
-
-    rspeak(SUSPEND_WARNING);
-    if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN]))
-        return GO_CLEAROBJ;
-    game.saved = game.saved + 5;
-
-    while (fp == NULL) {
-        char* name = myreadline("\nFile name: ");
-        if (name == NULL)
-            return GO_TOP;
-       name = strip(name);
-       if (strlen(name) == 0)
-            return GO_TOP;     // LCOV_EXCL_LINE
-        fp = fopen(strip(name), WRITE_MODE);
-        if (fp == NULL)
-            printf("Can't open file %s, try again.\n", name);
-        free(name);
-    }
-
-    savefile(fp);
-    fclose(fp);
-    rspeak(RESUME_HELP);
-    exit(EXIT_SUCCESS);
+       FILE *fp = NULL;
+
+       rspeak(SUSPEND_WARNING);
+       if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE],
+                      arbitrary_messages[OK_MAN],
+                      arbitrary_messages[OK_MAN])) {
+               return GO_CLEAROBJ;
+       }
+       game.saved = game.saved + 5;
+
+       while (fp == NULL) {
+               char *name = myreadline("\nFile name: ");
+               if (name == NULL) {
+                       return GO_TOP;
+               }
+               name = strip(name);
+               if (strlen(name) == 0) {
+                       return GO_TOP; // LCOV_EXCL_LINE
+               }
+               fp = fopen(strip(name), WRITE_MODE);
+               if (fp == NULL) {
+                       printf("Can't open file %s, try again.\n", name);
+               }
+               free(name);
+       }
+
+       savefile(fp);
+       fclose(fp);
+       rspeak(RESUME_HELP);
+       exit(EXIT_SUCCESS);
 }
 
-int resume(void)
-{
-    /*  Resume.  Read a suspended game back from a file.
-     *  If ADVENT_NOSAVE is defined, gripe instead. */
+int resume(void) {
+       /*  Resume.  Read a suspended game back from a file.
+        *  If ADVENT_NOSAVE is defined, gripe instead. */
 
 #if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
-    rspeak(SAVERESUME_DISABLED);
-    return GO_TOP;
+       rspeak(SAVERESUME_DISABLED);
+       return GO_TOP;
 #endif
-    FILE *fp = NULL;
-
-    if (game.loc != LOC_START || game.locs[LOC_START].abbrev != 1) {
-        rspeak(RESUME_ABANDON);
-        if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE], arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN]))
-            return GO_CLEAROBJ;
-    }
-
-    while (fp == NULL) {
-        char* name = myreadline("\nFile name: ");
-        if (name == NULL)
-            return GO_TOP;
-       name = strip(name);
-       if (strlen(name) == 0)
-            return GO_TOP;     // LCOV_EXCL_LINE
-       fp = fopen(name, READ_MODE);
-        if (fp == NULL)
-            printf("Can't open file %s, try again.\n", name);
-        free(name);
-    }
-
-    return restore(fp);
+       FILE *fp = NULL;
+
+       if (game.loc != LOC_START || game.locs[LOC_START].abbrev != 1) {
+               rspeak(RESUME_ABANDON);
+               if (!yes_or_no(arbitrary_messages[THIS_ACCEPTABLE],
+                              arbitrary_messages[OK_MAN],
+                              arbitrary_messages[OK_MAN])) {
+                       return GO_CLEAROBJ;
+               }
+       }
+
+       while (fp == NULL) {
+               char *name = myreadline("\nFile name: ");
+               if (name == NULL)
+                       return GO_TOP;
+               name = strip(name);
+               if (strlen(name) == 0)
+                       return GO_TOP; // LCOV_EXCL_LINE
+               fp = fopen(name, READ_MODE);
+               if (fp == NULL) {
+                       printf("Can't open file %s, try again.\n", name);
+               }
+               free(name);
+       }
+
+       return restore(fp);
 }
 
-int restore(FILE* fp)
-{
-    /*  Read and restore game state from file, assuming
-     *  sane initial state.
-     *  If ADVENT_NOSAVE is defined, gripe instead. */
+int restore(FILE *fp) {
+       /*  Read and restore game state from file, assuming
+        *  sane initial state.
+        *  If ADVENT_NOSAVE is defined, gripe instead. */
 #ifdef ADVENT_NOSAVE
-    rspeak(SAVERESUME_DISABLED);
-    return GO_TOP;
+       rspeak(SAVERESUME_DISABLED);
+       return GO_TOP;
 #endif
 
-    IGNORE(fread(&save, sizeof(struct save_t), 1, fp));
-    fclose(fp);
-    if (memcmp(save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC)) != 0 || save.canary != ENDIAN_MAGIC)
-       rspeak(BAD_SAVE);
-    else if (save.version != SAVE_VERSION) {
-        rspeak(VERSION_SKEW, save.version / 10, MOD(save.version, 10), SAVE_VERSION / 10, MOD(SAVE_VERSION, 10));
-    } else if (!is_valid(save.game)) {
-       rspeak(SAVE_TAMPERING);
-       exit(EXIT_SUCCESS);
-    } else {
-        game = save.game;
-    }
-    return GO_TOP;
+       IGNORE(fread(&save, sizeof(struct save_t), 1, fp));
+       fclose(fp);
+       if (memcmp(save.magic, ADVENT_MAGIC, sizeof(ADVENT_MAGIC)) != 0 ||
+           save.canary != ENDIAN_MAGIC) {
+               rspeak(BAD_SAVE);
+       } else if (save.version != SAVE_VERSION) {
+               rspeak(VERSION_SKEW, save.version / 10, MOD(save.version, 10),
+                      SAVE_VERSION / 10, MOD(SAVE_VERSION, 10));
+       } else if (!is_valid(save.game)) {
+               rspeak(SAVE_TAMPERING);
+               exit(EXIT_SUCCESS);
+       } else {
+               game = save.game;
+       }
+       return GO_TOP;
 }
 
-bool is_valid(struct game_t valgame)
-{
-    /*  Save files can be roughly grouped into three groups:
-     *  With valid, reachable state, with valid, but unreachable
-     *  state and with invalid state. We check that state is
-     *  valid: no states are outside minimal or maximal value
-     */
-
-    /* Prevent division by zero */
-    if (valgame.abbnum == 0) {
-        return false;  // LCOV_EXCL_LINE
-    }
-
-    /* Check for RNG overflow. Truncate */
-    if (valgame.lcg_x >= LCG_M) {
-        valgame.lcg_x %= LCG_M; // LCOV_EXCL_LINE
-    }
-
-    /* Check for RNG underflow. Transpose */
-    if (valgame.lcg_x < LCG_M) {
-        valgame.lcg_x = LCG_M + (valgame.lcg_x % LCG_M);
-    }
-
-    /*  Bounds check for locations */
-    if ( valgame.chloc  < -1 || valgame.chloc  > NLOCATIONS ||
-         valgame.chloc2 < -1 || valgame.chloc2 > NLOCATIONS ||
-         valgame.loc    <  0 || valgame.loc    > NLOCATIONS ||
-         valgame.newloc <  0 || valgame.newloc > NLOCATIONS ||
-         valgame.oldloc <  0 || valgame.oldloc > NLOCATIONS ||
-         valgame.oldlc2 <  0 || valgame.oldlc2 > NLOCATIONS) {
-        return false;  // LCOV_EXCL_LINE
-    }
-    /*  Bounds check for location arrays */
-    for (int i = 0; i <= NDWARVES; i++) {
-        if (valgame.dwarves[i].loc  < -1 || valgame.dwarves[i].loc  > NLOCATIONS  ||
-            valgame.dwarves[i].oldloc < -1 || valgame.dwarves[i].oldloc > NLOCATIONS) {
-            return false;      // LCOV_EXCL_LINE
-        }
-    }
-
-    for (int i = 0; i <= NOBJECTS; i++) {
-        if (valgame.objects[i].place < -1 || valgame.objects[i].place > NLOCATIONS  ||
-            valgame.objects[i].fixed < -1 || valgame.objects[i].fixed > NLOCATIONS) {
-            return false;      // LCOV_EXCL_LINE
-        }
-    }
-
-    /*  Bounds check for dwarves */
-    if (valgame.dtotal < 0 || valgame.dtotal > NDWARVES ||
-        valgame.dkill < 0  || valgame.dkill  > NDWARVES) {
-        return false;  // LCOV_EXCL_LINE
-    }
-
-    /*  Validate that we didn't die too many times in save */
-    if (valgame.numdie >= NDEATHS) {
-        return false;  // LCOV_EXCL_LINE
-    }
-
-    /* Recalculate tally, throw the towel if in disagreement */
-    int temp_tally = 0;
-    for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
-        if (objects[treasure].is_treasure) {
-            if (PROP_IS_NOTFOUND2(valgame, treasure)) {
-                ++temp_tally;
-            }
-        }
-    }
-    if (temp_tally != valgame.tally) {
-        return false;  // LCOV_EXCL_LINE
-    }
-
-    /* Check that properties of objects aren't beyond expected */
-    for (obj_t obj = 0; obj <= NOBJECTS; obj++) {
-        if (PROP_IS_INVALID(valgame.objects[obj].prop)) {
-           return false;       // LCOV_EXCL_LINE
-        }
-    }
-
-    /* Check that values in linked lists for objects in locations are inside bounds */
-    for (loc_t loc = LOC_NOWHERE; loc <= NLOCATIONS; loc++) {
-        if (valgame.locs[loc].atloc < NO_OBJECT || valgame.locs[loc].atloc > NOBJECTS * 2) {
-            return false;      // LCOV_EXCL_LINE
-        }
-    }
-    for (obj_t obj = 0; obj <= NOBJECTS * 2; obj++ ) {
-        if (valgame.link[obj] < NO_OBJECT || valgame.link[obj] > NOBJECTS * 2) {
-            return false;      // LCOV_EXCL_LINE
-        }
-    }
-
-    return true;
+bool is_valid(struct game_t valgame) {
+       /*  Save files can be roughly grouped into three groups:
+        *  With valid, reachable state, with valid, but unreachable
+        *  state and with invalid state. We check that state is
+        *  valid: no states are outside minimal or maximal value
+        */
+
+       /* Prevent division by zero */
+       if (valgame.abbnum == 0) {
+               return false; // LCOV_EXCL_LINE
+       }
+
+       /* Check for RNG overflow. Truncate */
+       if (valgame.lcg_x >= LCG_M) {
+               valgame.lcg_x %= LCG_M; // LCOV_EXCL_LINE
+       }
+
+       /* Check for RNG underflow. Transpose */
+       if (valgame.lcg_x < LCG_M) {
+               valgame.lcg_x = LCG_M + (valgame.lcg_x % LCG_M);
+       }
+
+       /*  Bounds check for locations */
+       if (valgame.chloc < -1 || valgame.chloc > NLOCATIONS ||
+           valgame.chloc2 < -1 || valgame.chloc2 > NLOCATIONS ||
+           valgame.loc < 0 || valgame.loc > NLOCATIONS || valgame.newloc < 0 ||
+           valgame.newloc > NLOCATIONS || valgame.oldloc < 0 ||
+           valgame.oldloc > NLOCATIONS || valgame.oldlc2 < 0 ||
+           valgame.oldlc2 > NLOCATIONS) {
+               return false; // LCOV_EXCL_LINE
+       }
+       /*  Bounds check for location arrays */
+       for (int i = 0; i <= NDWARVES; i++) {
+               if (valgame.dwarves[i].loc < -1 ||
+                   valgame.dwarves[i].loc > NLOCATIONS ||
+                   valgame.dwarves[i].oldloc < -1 ||
+                   valgame.dwarves[i].oldloc > NLOCATIONS) {
+                       return false; // LCOV_EXCL_LINE
+               }
+       }
+
+       for (int i = 0; i <= NOBJECTS; i++) {
+               if (valgame.objects[i].place < -1 ||
+                   valgame.objects[i].place > NLOCATIONS ||
+                   valgame.objects[i].fixed < -1 ||
+                   valgame.objects[i].fixed > NLOCATIONS) {
+                       return false; // LCOV_EXCL_LINE
+               }
+       }
+
+       /*  Bounds check for dwarves */
+       if (valgame.dtotal < 0 || valgame.dtotal > NDWARVES ||
+           valgame.dkill < 0 || valgame.dkill > NDWARVES) {
+               return false; // LCOV_EXCL_LINE
+       }
+
+       /*  Validate that we didn't die too many times in save */
+       if (valgame.numdie >= NDEATHS) {
+               return false; // LCOV_EXCL_LINE
+       }
+
+       /* Recalculate tally, throw the towel if in disagreement */
+       int temp_tally = 0;
+       for (int treasure = 1; treasure <= NOBJECTS; treasure++) {
+               if (objects[treasure].is_treasure) {
+                       if (PROP_IS_NOTFOUND2(valgame, treasure)) {
+                               ++temp_tally;
+                       }
+               }
+       }
+       if (temp_tally != valgame.tally) {
+               return false; // LCOV_EXCL_LINE
+       }
+
+       /* Check that properties of objects aren't beyond expected */
+       for (obj_t obj = 0; obj <= NOBJECTS; obj++) {
+               if (PROP_IS_INVALID(valgame.objects[obj].prop)) {
+                       return false; // LCOV_EXCL_LINE
+               }
+       }
+
+       /* Check that values in linked lists for objects in locations are inside
+        * bounds */
+       for (loc_t loc = LOC_NOWHERE; loc <= NLOCATIONS; loc++) {
+               if (valgame.locs[loc].atloc < NO_OBJECT ||
+                   valgame.locs[loc].atloc > NOBJECTS * 2) {
+                       return false; // LCOV_EXCL_LINE
+               }
+       }
+       for (obj_t obj = 0; obj <= NOBJECTS * 2; obj++) {
+               if (valgame.link[obj] < NO_OBJECT ||
+                   valgame.link[obj] > NOBJECTS * 2) {
+                       return false; // LCOV_EXCL_LINE
+               }
+       }
+
+       return true;
 }
 
 /* end */
diff --git a/score.c b/score.c
index 473ec6a0a591695ac5b7c095e41058b8d6e0e5d2..1d84c79a74fb5705f1f7ecea1e94f88ac3100ef5 100644 (file)
--- a/score.c
+++ b/score.c
  * SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
  * SPDX-License-Identifier: BSD-2-Clause
  */
-#include <stdlib.h>
 #include "advent.h"
 #include "dungeon.h"
+#include <stdlib.h>
 
-static int mxscor;     /* ugh..the price for having score() not exit. */
+static int mxscor; /* ugh..the price for having score() not exit. */
 
 int score(enum termination mode) {
-/* mode is 'scoregame' if scoring, 'quitgame' if quitting, 'endgame' if died
* or won */
-    int score = 0;
+       /* mode is 'scoregame' if scoring, 'quitgame' if quitting, 'endgame' if
       * died or won */
+       int score = 0;
 
-    /*  The present scoring algorithm is as follows:
-     *     Objective:          Points:        Present total possible:
-     *  Getting well into cave   25                    25
-     *  Each treasure < chest    12                    60
-     *  Treasure chest itself    14                    14
-     *  Each treasure > chest    16                   224
-     *  Surviving             (MAX-NUM)*10             30
-     *  Not quitting              4                     4
-     *  Reaching "game.closng"   25                    25
-     *  "Closed": Quit/Killed    10
-     *            Klutzed        25
-     *            Wrong way      30
-     *            Success        45                    45
-     *  Came to Witt's End        1                     1
-     *  Round out the total       2                     2
-     *                                       TOTAL:   430
-     *  Points can also be deducted for using hints or too many turns, or for
-      saving intermediate positions. */
+       /*  The present scoring algorithm is as follows:
+        *     Objective:          Points:        Present total possible:
+        *  Getting well into cave   25                    25
+        *  Each treasure < chest    12                    60
+        *  Treasure chest itself    14                    14
+        *  Each treasure > chest    16                   224
+        *  Surviving             (MAX-NUM)*10             30
+        *  Not quitting              4                     4
+        *  Reaching "game.closng"   25                    25
+        *  "Closed": Quit/Killed    10
+        *            Klutzed        25
+        *            Wrong way      30
+        *            Success        45                    45
+        *  Came to Witt's End        1                     1
+        *  Round out the total       2                     2
+        *                                       TOTAL:   430
+        *  Points can also be deducted for using hints or too many turns, or
+        * for saving intermediate positions. */
 
-    /*  First tally up the treasures.  Must be in building and not broken.
-     *  Give the poor guy 2 points just for finding each treasure. */
-    mxscor = 0;
-    for (int i = 1; i <= NOBJECTS; i++) {
-       if (!objects[i].is_treasure) {
-             continue;
+       /*  First tally up the treasures.  Must be in building and not broken.
+        *  Give the poor guy 2 points just for finding each treasure. */
+       mxscor = 0;
+       for (int i = 1; i <= NOBJECTS; i++) {
+               if (!objects[i].is_treasure) {
+                       continue;
+               }
+               if (objects[i].inventory != 0) {
+                       int k = 12;
+                       if (i == CHEST) {
+                               k = 14;
+                       }
+                       if (i > CHEST) {
+                               k = 16;
+                       }
+                       if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
+                               score += 2;
+                       }
+                       if (game.objects[i].place == LOC_BUILDING &&
+                           PROP_IS_FOUND(i)) {
+                               score += k - 2;
+                       }
+                       mxscor += k;
+               }
        }
-        if (objects[i].inventory != 0) {
-            int k = 12;
-            if (i == CHEST) {
-                k = 14;
-           }
-            if (i > CHEST) {
-                k = 16;
-           }
-            if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
-                score += 2;
-           }
-            if (game.objects[i].place == LOC_BUILDING && PROP_IS_FOUND(i)) {
-                score += k - 2;
-           }
-            mxscor += k;
-        }
-    }
 
-    /*  Now look at how he finished and how far he got.  NDEATHS and
-     *  game.numdie tell us how well he survived.  game.dflag will tell us
-     *  if he ever got suitably deep into the cave.  game.closng still
-     *  indicates whether he reached the endgame.  And if he got as far as
-     *  "cave closed" (indicated by "game.closed"), then bonus is zero for
-     *  mundane exits or 133, 134, 135 if he blew it (so to speak). */
-    score += (NDEATHS - game.numdie) * 10;
-    mxscor += NDEATHS * 10;
-    if (mode == endgame) {
-        score += 4;
-    }
-    mxscor += 4;
-    if (game.dflag != 0) {
-        score += 25;
-    }
-    mxscor += 25;
-    if (game.closng) {
-        score += 25;
-    }
-    mxscor += 25;
-    if (game.closed) {
-       if (game.bonus == none) {
-             score += 10;
+       /*  Now look at how he finished and how far he got.  NDEATHS and
+        *  game.numdie tell us how well he survived.  game.dflag will tell us
+        *  if he ever got suitably deep into the cave.  game.closng still
+        *  indicates whether he reached the endgame.  And if he got as far as
+        *  "cave closed" (indicated by "game.closed"), then bonus is zero for
+        *  mundane exits or 133, 134, 135 if he blew it (so to speak). */
+       score += (NDEATHS - game.numdie) * 10;
+       mxscor += NDEATHS * 10;
+       if (mode == endgame) {
+               score += 4;
        }
-       if (game.bonus == splatter) {
-             score += 25;
+       mxscor += 4;
+       if (game.dflag != 0) {
+               score += 25;
        }
-       if (game.bonus == defeat) {
-             score += 30;
+       mxscor += 25;
+       if (game.closng) {
+               score += 25;
        }
-       if (game.bonus == victory) {
-             score += 45;
+       mxscor += 25;
+       if (game.closed) {
+               if (game.bonus == none) {
+                       score += 10;
+               }
+               if (game.bonus == splatter) {
+                       score += 25;
+               }
+               if (game.bonus == defeat) {
+                       score += 30;
+               }
+               if (game.bonus == victory) {
+                       score += 45;
+               }
        }
-    }
-    mxscor += 45;
+       mxscor += 45;
 
-    /* Did he come to Witt's End as he should? */
-    if (game.objects[MAGAZINE].place == LOC_WITTSEND) {
-        score += 1;
-    }
-    mxscor += 1;
+       /* Did he come to Witt's End as he should? */
+       if (game.objects[MAGAZINE].place == LOC_WITTSEND) {
+               score += 1;
+       }
+       mxscor += 1;
 
-    /* Round it off. */
-    score += 2;
-    mxscor += 2;
+       /* Round it off. */
+       score += 2;
+       mxscor += 2;
 
-    /* Deduct for hints/turns/saves. Hints < 4 are special; see database desc. */
-    for (int i = 0; i < NHINTS; i++) {
-       if (game.hints[i].used) {
-             score = score - hints[i].penalty;
+       /* Deduct for hints/turns/saves. Hints < 4 are special; see database
+        * desc. */
+       for (int i = 0; i < NHINTS; i++) {
+               if (game.hints[i].used) {
+                       score = score - hints[i].penalty;
+               }
+       }
+       if (game.novice) {
+               score -= 5;
+       }
+       if (game.clshnt) {
+               score -= 10;
        }
-    }
-    if (game.novice) {
-        score -= 5;
-    }
-    if (game.clshnt) {
-        score -= 10;
-    }
-    score = score - game.trnluz - game.saved;
+       score = score - game.trnluz - game.saved;
 
-    /* Return to score command if that's where we came from. */
-    if (mode == scoregame) {
-        rspeak(GARNERED_POINTS, score, mxscor, game.turns, game.turns);
-    }
+       /* Return to score command if that's where we came from. */
+       if (mode == scoregame) {
+               rspeak(GARNERED_POINTS, score, mxscor, game.turns, game.turns);
+       }
 
-    return score;
+       return score;
 }
 
 void terminate(enum termination mode) {
-/* End of game.  Let's tell him all about it. */
-    int points = score(mode);
+       /* End of game.  Let's tell him all about it. */
+       int points = score(mode);
 #if defined ADVENT_AUTOSAVE
-    autosave();
+       autosave();
 #endif
 
-    if (points + game.trnluz + 1 >= mxscor && game.trnluz != 0) {
-        rspeak(TOOK_LONG);
-    }
-    if (points + game.saved + 1 >= mxscor && game.saved != 0) {
-        rspeak(WITHOUT_SUSPENDS);
-    }
-    rspeak(TOTAL_SCORE, points, mxscor, game.turns, game.turns);
-    for (int i = 1; i <= (int)NCLASSES; i++) {
-        if (classes[i].threshold >= points) {
-            speak(classes[i].message);
-           if (i < (int)NCLASSES) {
-               int nxt = classes[i].threshold + 1 - points;
-               rspeak(NEXT_HIGHER, nxt, nxt);
-           } else {
-               rspeak(NO_HIGHER);
-           }
-            exit(EXIT_SUCCESS);
-        }
-    }
-    rspeak(OFF_SCALE);
-    exit(EXIT_SUCCESS);
+       if (points + game.trnluz + 1 >= mxscor && game.trnluz != 0) {
+               rspeak(TOOK_LONG);
+       }
+       if (points + game.saved + 1 >= mxscor && game.saved != 0) {
+               rspeak(WITHOUT_SUSPENDS);
+       }
+       rspeak(TOTAL_SCORE, points, mxscor, game.turns, game.turns);
+       for (int i = 1; i <= (int)NCLASSES; i++) {
+               if (classes[i].threshold >= points) {
+                       speak(classes[i].message);
+                       if (i < (int)NCLASSES) {
+                               int nxt = classes[i].threshold + 1 - points;
+                               rspeak(NEXT_HIGHER, nxt, nxt);
+                       } else {
+                               rspeak(NO_HIGHER);
+                       }
+                       exit(EXIT_SUCCESS);
+               }
+       }
+       rspeak(OFF_SCALE);
+       exit(EXIT_SUCCESS);
 }
 
 /* end */