LCOV - code coverage report
Current view: top level - open-adventure - actions.c (source / functions) Hit Total Coverage
Test: advent.info Lines: 1072 1073 99.9 %
Date: 2024-02-15 17:57:54 Functions: 32 32 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Actions for the dungeon-running code.
       3             :  *
       4             :  * SPDX-FileCopyrightText: (C) 1977, 2005 Will Crowther and Don Woods
       5             :  * SPDX-License-Identifier: BSD-2-Clause
       6             :  */
       7             : 
       8             : #include <inttypes.h>
       9             : #include <stdbool.h>
      10             : #include <stdlib.h>
      11             : #include <string.h>
      12             : 
      13             : #include "advent.h"
      14             : 
      15             : static phase_codes_t fill(verb_t, obj_t);
      16             : 
      17         196 : static phase_codes_t attack(command_t command) {
      18             :         /*  Attack.  Assume target if unambiguous.  "Throw" also links here.
      19             :          *  Attackable objects fall into two categories: enemies (snake,
      20             :          *  dwarf, etc.)  and others (bird, clam, machine).  Ambiguous if 2
      21             :          *  enemies, or no enemies but 2 others. */
      22         196 :         verb_t verb = command.verb;
      23         196 :         obj_t obj = command.obj;
      24             : 
      25         196 :         if (obj == INTRANSITIVE) {
      26          24 :                 int changes = 0;
      27          24 :                 if (atdwrf(game.loc) > 0) {
      28           3 :                         obj = DWARF;
      29           3 :                         ++changes;
      30             :                 }
      31          24 :                 if (HERE(SNAKE)) {
      32           1 :                         obj = SNAKE;
      33           1 :                         ++changes;
      34             :                 }
      35          24 :                 if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
      36           6 :                         obj = DRAGON;
      37           6 :                         ++changes;
      38             :                 }
      39          24 :                 if (AT(TROLL)) {
      40           1 :                         obj = TROLL;
      41           1 :                         ++changes;
      42             :                 }
      43          24 :                 if (AT(OGRE)) {
      44           3 :                         obj = OGRE;
      45           3 :                         ++changes;
      46             :                 }
      47          24 :                 if (HERE(BEAR) && game.objects[BEAR].prop == UNTAMED_BEAR) {
      48           2 :                         obj = BEAR;
      49           2 :                         ++changes;
      50             :                 }
      51             :                 /* check for low-priority targets */
      52          24 :                 if (obj == INTRANSITIVE) {
      53             :                         /* Can't attack bird or machine by throwing axe. */
      54          10 :                         if (HERE(BIRD) && verb != THROW) {
      55           2 :                                 obj = BIRD;
      56           2 :                                 ++changes;
      57             :                         }
      58          10 :                         if (HERE(VEND) && verb != THROW) {
      59           1 :                                 obj = VEND;
      60           1 :                                 ++changes;
      61             :                         }
      62             :                         /* Clam and oyster both treated as clam for intransitive
      63             :                          * case; no harm done. */
      64          10 :                         if (HERE(CLAM) || HERE(OYSTER)) {
      65           1 :                                 obj = CLAM;
      66           1 :                                 ++changes;
      67             :                         }
      68             :                 }
      69          24 :                 if (changes >= 2) {
      70           3 :                         return GO_UNKNOWN;
      71             :                 }
      72             :         }
      73             : 
      74         193 :         if (obj == BIRD) {
      75           3 :                 if (game.closed) {
      76           1 :                         rspeak(UNHAPPY_BIRD);
      77             :                 } else {
      78           2 :                         DESTROY(BIRD);
      79           2 :                         rspeak(BIRD_DEAD);
      80             :                 }
      81           3 :                 return GO_CLEAROBJ;
      82             :         }
      83         190 :         if (obj == VEND) {
      84          57 :                 state_change(VEND, game.objects[VEND].prop == VEND_BLOCKS
      85             :                                        ? VEND_UNBLOCKS
      86             :                                        : VEND_BLOCKS);
      87             : 
      88          57 :                 return GO_CLEAROBJ;
      89             :         }
      90             : 
      91         133 :         if (obj == BEAR) {
      92           9 :                 switch (game.objects[BEAR].prop) {
      93           3 :                 case UNTAMED_BEAR:
      94           3 :                         rspeak(BEAR_HANDS);
      95           3 :                         break;
      96           1 :                 case SITTING_BEAR:
      97           1 :                         rspeak(BEAR_CONFUSED);
      98           1 :                         break;
      99           4 :                 case CONTENTED_BEAR:
     100           4 :                         rspeak(BEAR_CONFUSED);
     101           4 :                         break;
     102           1 :                 case BEAR_DEAD:
     103           1 :                         rspeak(ALREADY_DEAD);
     104           1 :                         break;
     105             :                 }
     106           9 :                 return GO_CLEAROBJ;
     107             :         }
     108         124 :         if (obj == DRAGON && game.objects[DRAGON].prop == DRAGON_BARS) {
     109             :                 /*  Fun stuff for dragon.  If he insists on attacking it, win!
     110             :                  *  Set game.prop to dead, move dragon to central loc (still
     111             :                  *  fixed), move rug there (not fixed), and move him there,
     112             :                  *  too.  Then do a null motion to get new description. */
     113          61 :                 rspeak(BARE_HANDS_QUERY);
     114          61 :                 if (!silent_yes_or_no()) {
     115           1 :                         speak(arbitrary_messages[NASTY_DRAGON]);
     116           1 :                         return GO_MOVE;
     117             :                 }
     118          60 :                 state_change(DRAGON, DRAGON_DEAD);
     119          60 :                 game.objects[RUG].prop = RUG_FLOOR;
     120             :                 /* Hardcoding LOC_SECRET5 as the dragon's death location is
     121             :                  * ugly. The way it was computed before was worse; it depended
     122             :                  * on the two dragon locations being LOC_SECRET4 and LOC_SECRET6
     123             :                  * and LOC_SECRET5 being right between them.
     124             :                  */
     125          60 :                 move(DRAGON + NOBJECTS, IS_FIXED);
     126          60 :                 move(RUG + NOBJECTS, IS_FREE);
     127          60 :                 move(DRAGON, LOC_SECRET5);
     128          60 :                 move(RUG, LOC_SECRET5);
     129          60 :                 drop(BLOOD, LOC_SECRET5);
     130        4200 :                 for (obj_t i = 1; i <= NOBJECTS; i++) {
     131        4140 :                         if (game.objects[i].place == objects[DRAGON].plac ||
     132        4140 :                             game.objects[i].place == objects[DRAGON].fixd) {
     133           1 :                                 move(i, LOC_SECRET5);
     134             :                         }
     135             :                 }
     136          60 :                 game.loc = LOC_SECRET5;
     137          60 :                 return GO_MOVE;
     138             :         }
     139             : 
     140          63 :         if (obj == OGRE) {
     141          48 :                 rspeak(OGRE_DODGE);
     142          48 :                 if (atdwrf(game.loc) == 0) {
     143           2 :                         return GO_CLEAROBJ;
     144             :                 }
     145          46 :                 rspeak(KNIFE_THROWN);
     146          46 :                 DESTROY(OGRE);
     147          46 :                 int dwarves = 0;
     148         276 :                 for (int i = 1; i < PIRATE; i++) {
     149         230 :                         if (game.dwarves[i].loc == game.loc) {
     150          47 :                                 ++dwarves;
     151          47 :                                 game.dwarves[i].loc = LOC_LONGWEST;
     152          47 :                                 game.dwarves[i].seen = false;
     153             :                         }
     154             :                 }
     155          46 :                 rspeak((dwarves > 1) ? OGRE_PANIC1 : OGRE_PANIC2);
     156          46 :                 return GO_CLEAROBJ;
     157             :         }
     158             : 
     159          15 :         switch (obj) {
     160           7 :         case INTRANSITIVE:
     161           7 :                 rspeak(NO_TARGET);
     162           7 :                 break;
     163           1 :         case CLAM:
     164             :         case OYSTER:
     165           1 :                 rspeak(SHELL_IMPERVIOUS);
     166           1 :                 break;
     167           1 :         case SNAKE:
     168           1 :                 rspeak(SNAKE_WARNING);
     169           1 :                 break;
     170           3 :         case DWARF:
     171           3 :                 if (game.closed) {
     172           1 :                         return GO_DWARFWAKE;
     173             :                 }
     174           2 :                 rspeak(BARE_HANDS_QUERY);
     175           2 :                 break;
     176           1 :         case DRAGON:
     177           1 :                 rspeak(ALREADY_DEAD);
     178           1 :                 break;
     179           1 :         case TROLL:
     180           1 :                 rspeak(ROCKY_TROLL);
     181           1 :                 break;
     182           1 :         default:
     183           1 :                 speak(actions[verb].message);
     184             :         }
     185          14 :         return GO_CLEAROBJ;
     186             : }
     187             : 
     188         147 : static phase_codes_t bigwords(vocab_t id) {
     189             :         /* Only called on FEE FIE FOE FOO (AND FUM).  Advance to next state if
     190             :          * given in proper order. Look up foo in special section of vocab to
     191             :          * determine which word we've got. Last word zips the eggs back to the
     192             :          * giant room (unless already there). */
     193         147 :         int foobar = abs(game.foobar);
     194             : 
     195             :         /* Only FEE can start a magic-word sequence. */
     196         147 :         if ((foobar == WORD_EMPTY) &&
     197          39 :             (id == FIE || id == FOE || id == FOO || id == FUM)) {
     198           3 :                 rspeak(NOTHING_HAPPENS);
     199           3 :                 return GO_CLEAROBJ;
     200             :         }
     201             : 
     202         144 :         if ((foobar == WORD_EMPTY && id == FEE) ||
     203         108 :             (foobar == FEE && id == FIE) || (foobar == FIE && id == FOE) ||
     204          36 :             (foobar == FOE && id == FOO)) {
     205         140 :                 game.foobar = id;
     206         140 :                 if (id != FOO) {
     207         108 :                         rspeak(OK_MAN);
     208         108 :                         return GO_CLEAROBJ;
     209             :                 }
     210          32 :                 game.foobar = WORD_EMPTY;
     211          32 :                 if (game.objects[EGGS].place == objects[EGGS].plac ||
     212          31 :                     (TOTING(EGGS) && game.loc == objects[EGGS].plac)) {
     213           2 :                         rspeak(NOTHING_HAPPENS);
     214           2 :                         return GO_CLEAROBJ;
     215             :                 } else {
     216             :                         /*  Bring back troll if we steal the eggs back from him
     217             :                          * before crossing. */
     218          30 :                         if (game.objects[EGGS].place == LOC_NOWHERE &&
     219          28 :                             game.objects[TROLL].place == LOC_NOWHERE &&
     220          28 :                             game.objects[TROLL].prop == TROLL_UNPAID) {
     221           1 :                                 game.objects[TROLL].prop = TROLL_PAIDONCE;
     222             :                         }
     223          30 :                         if (HERE(EGGS)) {
     224           1 :                                 pspeak(EGGS, look, true, EGGS_VANISHED);
     225          29 :                         } else if (game.loc == objects[EGGS].plac) {
     226          24 :                                 pspeak(EGGS, look, true, EGGS_HERE);
     227             :                         } else {
     228           5 :                                 pspeak(EGGS, look, true, EGGS_DONE);
     229             :                         }
     230          30 :                         move(EGGS, objects[EGGS].plac);
     231             : 
     232          30 :                         return GO_CLEAROBJ;
     233             :                 }
     234             :         } else {
     235             :                 /* Magic-word sequence was started but is incorrect */
     236           4 :                 if (settings.oldstyle || game.seenbigwords) {
     237           3 :                         rspeak(START_OVER);
     238             :                 } else {
     239           1 :                         rspeak(WELL_POINTLESS);
     240             :                 }
     241           4 :                 game.foobar = WORD_EMPTY;
     242           4 :                 return GO_CLEAROBJ;
     243             :         }
     244             : }
     245             : 
     246           8 : static void blast(void) {
     247             :         /*  Blast.  No effect unless you've got dynamite, which is a neat trick!
     248             :          */
     249           8 :         if (PROP_IS_NOTFOUND(ROD2) || !game.closed) {
     250           3 :                 rspeak(REQUIRES_DYNAMITE);
     251             :         } else {
     252           5 :                 if (HERE(ROD2)) {
     253           1 :                         game.bonus = splatter;
     254           1 :                         rspeak(SPLATTER_MESSAGE);
     255           4 :                 } else if (game.loc == LOC_NE) {
     256           1 :                         game.bonus = defeat;
     257           1 :                         rspeak(DEFEAT_MESSAGE);
     258             :                 } else {
     259           3 :                         game.bonus = victory;
     260           3 :                         rspeak(VICTORY_MESSAGE);
     261             :                 }
     262           5 :                 terminate(endgame);
     263             :         }
     264           3 : }
     265             : 
     266           8 : static phase_codes_t vbreak(verb_t verb, obj_t obj) {
     267             :         /*  Break.  Only works for mirror in repository and, of course, the
     268             :          * vase. */
     269           8 :         switch (obj) {
     270           3 :         case MIRROR:
     271           3 :                 if (game.closed) {
     272           1 :                         state_change(MIRROR, MIRROR_BROKEN);
     273           1 :                         return GO_DWARFWAKE;
     274             :                 } else {
     275           2 :                         rspeak(TOO_FAR);
     276           2 :                         break;
     277             :                 }
     278           4 :         case VASE:
     279           4 :                 if (game.objects[VASE].prop == VASE_WHOLE) {
     280           2 :                         if (TOTING(VASE)) {
     281           2 :                                 drop(VASE, game.loc);
     282             :                         }
     283           2 :                         state_change(VASE, VASE_BROKEN);
     284           2 :                         game.objects[VASE].fixed = IS_FIXED;
     285           2 :                         break;
     286             :                 }
     287             :         /* FALLTHRU */
     288             :         default:
     289           3 :                 speak(actions[verb].message);
     290             :         }
     291           7 :         return (GO_CLEAROBJ);
     292             : }
     293             : 
     294           1 : static phase_codes_t brief(void) {
     295             :         /*  Brief.  Intransitive only.  Suppress full descriptions after first
     296             :          * time. */
     297           1 :         game.abbnum = 10000;
     298           1 :         game.detail = 3;
     299           1 :         rspeak(BRIEF_CONFIRM);
     300           1 :         return GO_CLEAROBJ;
     301             : }
     302             : 
     303        2414 : static phase_codes_t vcarry(verb_t verb, obj_t obj) {
     304             :         /*  Carry an object.  Special cases for bird and cage (if bird in cage,
     305             :          * can't take one without the other).  Liquids also special, since they
     306             :          * depend on status of bottle.  Also various side effects, etc. */
     307        2414 :         if (obj == INTRANSITIVE) {
     308             :                 /*  Carry, no object given yet.  OK if only one object present.
     309             :                  */
     310          36 :                 if (game.locs[game.loc].atloc == NO_OBJECT ||
     311          64 :                     game.link[game.locs[game.loc].atloc] != 0 ||
     312          30 :                     atdwrf(game.loc) > 0) {
     313           7 :                         return GO_UNKNOWN;
     314             :                 }
     315          29 :                 obj = game.locs[game.loc].atloc;
     316             :         }
     317             : 
     318        2407 :         if (TOTING(obj)) {
     319           9 :                 speak(actions[verb].message);
     320           9 :                 return GO_CLEAROBJ;
     321             :         }
     322             : 
     323        2398 :         if (obj == MESSAG) {
     324           1 :                 rspeak(REMOVE_MESSAGE);
     325           1 :                 DESTROY(MESSAG);
     326           1 :                 return GO_CLEAROBJ;
     327             :         }
     328             : 
     329        2397 :         if (game.objects[obj].fixed != IS_FREE) {
     330          16 :                 switch (obj) {
     331           2 :                 case PLANT:
     332             :                         /* Next guard tests whether plant is tiny or stashed */
     333           2 :                         rspeak(game.objects[PLANT].prop <= PLANT_THIRSTY
     334             :                                    ? DEEP_ROOTS
     335             :                                    : YOU_JOKING);
     336           2 :                         break;
     337           2 :                 case BEAR:
     338           2 :                         rspeak(game.objects[BEAR].prop == SITTING_BEAR
     339             :                                    ? BEAR_CHAINED
     340             :                                    : YOU_JOKING);
     341           2 :                         break;
     342           4 :                 case CHAIN:
     343           4 :                         rspeak(game.objects[BEAR].prop != UNTAMED_BEAR
     344             :                                    ? STILL_LOCKED
     345             :                                    : YOU_JOKING);
     346           4 :                         break;
     347           1 :                 case RUG:
     348           1 :                         rspeak(game.objects[RUG].prop == RUG_HOVER
     349             :                                    ? RUG_HOVERS
     350             :                                    : YOU_JOKING);
     351           1 :                         break;
     352           1 :                 case URN:
     353           1 :                         rspeak(URN_NOBUDGE);
     354           1 :                         break;
     355           1 :                 case CAVITY:
     356           1 :                         rspeak(DOUGHNUT_HOLES);
     357           1 :                         break;
     358           1 :                 case BLOOD:
     359           1 :                         rspeak(FEW_DROPS);
     360           1 :                         break;
     361           1 :                 case SIGN:
     362           1 :                         rspeak(HAND_PASSTHROUGH);
     363           1 :                         break;
     364           3 :                 default:
     365           3 :                         rspeak(YOU_JOKING);
     366             :                 }
     367          16 :                 return GO_CLEAROBJ;
     368             :         }
     369             : 
     370        2381 :         if (obj == WATER || obj == OIL) {
     371         173 :                 if (!HERE(BOTTLE) || LIQUID() != obj) {
     372         115 :                         if (!TOTING(BOTTLE)) {
     373           1 :                                 rspeak(NO_CONTAINER);
     374           1 :                                 return GO_CLEAROBJ;
     375             :                         }
     376         114 :                         if (game.objects[BOTTLE].prop == EMPTY_BOTTLE) {
     377         113 :                                 return (fill(verb, BOTTLE));
     378             :                         } else {
     379           1 :                                 rspeak(BOTTLE_FULL);
     380             :                         }
     381           1 :                         return GO_CLEAROBJ;
     382             :                 }
     383          58 :                 obj = BOTTLE;
     384             :         }
     385             : 
     386        2266 :         if (game.holdng >= INVLIMIT) {
     387          11 :                 rspeak(CARRY_LIMIT);
     388          11 :                 return GO_CLEAROBJ;
     389             :         }
     390             : 
     391        2255 :         if (obj == BIRD && game.objects[BIRD].prop != BIRD_CAGED &&
     392         175 :             !PROP_IS_STASHED(BIRD)) {
     393         174 :                 if (game.objects[BIRD].prop == BIRD_FOREST_UNCAGED) {
     394           1 :                         DESTROY(BIRD);
     395           1 :                         rspeak(BIRD_CRAP);
     396           1 :                         return GO_CLEAROBJ;
     397             :                 }
     398         173 :                 if (!TOTING(CAGE)) {
     399           1 :                         rspeak(CANNOT_CARRY);
     400           1 :                         return GO_CLEAROBJ;
     401             :                 }
     402         172 :                 if (TOTING(ROD)) {
     403           1 :                         rspeak(BIRD_EVADES);
     404           1 :                         return GO_CLEAROBJ;
     405             :                 }
     406         171 :                 game.objects[BIRD].prop = BIRD_CAGED;
     407             :         }
     408        2252 :         if ((obj == BIRD || obj == CAGE) &&
     409         282 :             (game.objects[BIRD].prop == BIRD_CAGED ||
     410         107 :              PROP_STASHED(BIRD) == BIRD_CAGED)) {
     411             :                 /* expression maps BIRD to CAGE and CAGE to BIRD */
     412         178 :                 carry(BIRD + CAGE - obj, game.loc);
     413             :         }
     414             : 
     415        2252 :         carry(obj, game.loc);
     416             : 
     417        2252 :         if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
     418          67 :                 game.objects[LIQUID()].place = CARRIED;
     419             :         }
     420             : 
     421        2252 :         if (GSTONE(obj) && !PROP_IS_FOUND(obj)) {
     422          73 :                 PROP_SET_FOUND(obj);
     423          73 :                 game.objects[CAVITY].prop = CAVITY_EMPTY;
     424             :         }
     425        2252 :         rspeak(OK_MAN);
     426        2252 :         return GO_CLEAROBJ;
     427             : }
     428             : 
     429          44 : static int chain(verb_t verb) {
     430             :         /* Do something to the bear's chain */
     431          44 :         if (verb != LOCK) {
     432          40 :                 if (game.objects[BEAR].prop == UNTAMED_BEAR) {
     433           2 :                         rspeak(BEAR_BLOCKS);
     434           2 :                         return GO_CLEAROBJ;
     435             :                 }
     436          38 :                 if (game.objects[CHAIN].prop == CHAIN_HEAP) {
     437           3 :                         rspeak(ALREADY_UNLOCKED);
     438           3 :                         return GO_CLEAROBJ;
     439             :                 }
     440          35 :                 game.objects[CHAIN].prop = CHAIN_HEAP;
     441          35 :                 game.objects[CHAIN].fixed = IS_FREE;
     442          35 :                 if (game.objects[BEAR].prop != BEAR_DEAD) {
     443          35 :                         game.objects[BEAR].prop = CONTENTED_BEAR;
     444             :                 }
     445             : 
     446          35 :                 switch (game.objects[BEAR].prop) {
     447             :                 // LCOV_EXCL_START
     448             :                 case BEAR_DEAD:
     449             :                         /* Can't be reached until the bear can die in some way
     450             :                          * other than a bridge collapse. Leave in in case this
     451             :                          * changes, but exclude from coverage testing. */
     452             :                         game.objects[BEAR].fixed = IS_FIXED;
     453             :                         break;
     454             :                 // LCOV_EXCL_STOP
     455          35 :                 default:
     456          35 :                         game.objects[BEAR].fixed = IS_FREE;
     457             :                 }
     458          35 :                 rspeak(CHAIN_UNLOCKED);
     459          35 :                 return GO_CLEAROBJ;
     460             :         }
     461             : 
     462           4 :         if (game.objects[CHAIN].prop != CHAIN_HEAP) {
     463           1 :                 rspeak(ALREADY_LOCKED);
     464           1 :                 return GO_CLEAROBJ;
     465             :         }
     466           3 :         if (game.loc != objects[CHAIN].plac) {
     467           1 :                 rspeak(NO_LOCKSITE);
     468           1 :                 return GO_CLEAROBJ;
     469             :         }
     470             : 
     471           2 :         game.objects[CHAIN].prop = CHAIN_FIXED;
     472             : 
     473           2 :         if (TOTING(CHAIN)) {
     474           1 :                 drop(CHAIN, game.loc);
     475             :         }
     476           2 :         game.objects[CHAIN].fixed = IS_FIXED;
     477             : 
     478           2 :         rspeak(CHAIN_LOCKED);
     479           2 :         return GO_CLEAROBJ;
     480             : }
     481             : 
     482        1691 : static phase_codes_t discard(verb_t verb, obj_t obj) {
     483             :         /*  Discard object.  "Throw" also comes here for most objects.  Special
     484             :          * cases for bird (might attack snake or dragon) and cage (might contain
     485             :          * bird) and vase. Drop coins at vending machine for extra batteries. */
     486        1691 :         if (obj == ROD && !TOTING(ROD) && TOTING(ROD2)) {
     487           3 :                 obj = ROD2;
     488             :         }
     489             : 
     490        1691 :         if (!TOTING(obj)) {
     491           1 :                 speak(actions[verb].message);
     492           1 :                 return GO_CLEAROBJ;
     493             :         }
     494             : 
     495        1690 :         if (GSTONE(obj) && AT(CAVITY) &&
     496          51 :             game.objects[CAVITY].prop != CAVITY_FULL) {
     497          51 :                 rspeak(GEM_FITS);
     498          51 :                 game.objects[obj].prop = STATE_IN_CAVITY;
     499          51 :                 game.objects[CAVITY].prop = CAVITY_FULL;
     500          51 :                 if (HERE(RUG) &&
     501          51 :                     ((obj == EMERALD && game.objects[RUG].prop != RUG_HOVER) ||
     502          23 :                      (obj == RUBY && game.objects[RUG].prop == RUG_HOVER))) {
     503          50 :                         if (obj == RUBY) {
     504          23 :                                 rspeak(RUG_SETTLES);
     505          27 :                         } else if (TOTING(RUG)) {
     506           1 :                                 rspeak(RUG_WIGGLES);
     507             :                         } else {
     508          26 :                                 rspeak(RUG_RISES);
     509             :                         }
     510          50 :                         if (!TOTING(RUG) || obj == RUBY) {
     511          49 :                                 int k = (game.objects[RUG].prop == RUG_HOVER)
     512             :                                             ? RUG_FLOOR
     513          49 :                                             : RUG_HOVER;
     514          49 :                                 game.objects[RUG].prop = k;
     515          49 :                                 if (k == RUG_HOVER) {
     516          26 :                                         k = objects[SAPPH].plac;
     517             :                                 }
     518          49 :                                 move(RUG + NOBJECTS, k);
     519             :                         }
     520             :                 }
     521          51 :                 drop(obj, game.loc);
     522          51 :                 return GO_CLEAROBJ;
     523             :         }
     524             : 
     525        1639 :         if (obj == COINS && HERE(VEND)) {
     526           3 :                 DESTROY(COINS);
     527           3 :                 drop(BATTERY, game.loc);
     528           3 :                 pspeak(BATTERY, look, true, FRESH_BATTERIES);
     529           3 :                 return GO_CLEAROBJ;
     530             :         }
     531             : 
     532        1636 :         if (LIQUID() == obj) {
     533           2 :                 obj = BOTTLE;
     534             :         }
     535        1636 :         if (obj == BOTTLE && LIQUID() != NO_OBJECT) {
     536          12 :                 game.objects[LIQUID()].place = LOC_NOWHERE;
     537             :         }
     538             : 
     539        1636 :         if (obj == BEAR && AT(TROLL)) {
     540          32 :                 state_change(TROLL, TROLL_GONE);
     541          32 :                 move(TROLL, LOC_NOWHERE);
     542          32 :                 move(TROLL + NOBJECTS, IS_FREE);
     543          32 :                 move(TROLL2, objects[TROLL].plac);
     544          32 :                 move(TROLL2 + NOBJECTS, objects[TROLL].fixd);
     545          32 :                 juggle(CHASM);
     546          32 :                 drop(obj, game.loc);
     547          32 :                 return GO_CLEAROBJ;
     548             :         }
     549             : 
     550        1604 :         if (obj == VASE) {
     551          33 :                 if (game.loc != objects[PILLOW].plac) {
     552          32 :                         state_change(VASE,
     553          32 :                                      AT(PILLOW) ? VASE_WHOLE : VASE_DROPPED);
     554          32 :                         if (game.objects[VASE].prop != VASE_WHOLE) {
     555           1 :                                 game.objects[VASE].fixed = IS_FIXED;
     556             :                         }
     557          32 :                         drop(obj, game.loc);
     558          32 :                         return GO_CLEAROBJ;
     559             :                 }
     560             :         }
     561             : 
     562        1572 :         if (obj == CAGE && game.objects[BIRD].prop == BIRD_CAGED) {
     563           5 :                 drop(BIRD, game.loc);
     564             :         }
     565             : 
     566        1572 :         if (obj == BIRD) {
     567         163 :                 if (AT(DRAGON) && game.objects[DRAGON].prop == DRAGON_BARS) {
     568           1 :                         rspeak(BIRD_BURNT);
     569           1 :                         DESTROY(BIRD);
     570           1 :                         return GO_CLEAROBJ;
     571             :                 }
     572         162 :                 if (HERE(SNAKE)) {
     573          67 :                         rspeak(BIRD_ATTACKS);
     574          67 :                         if (game.closed) {
     575           1 :                                 return GO_DWARFWAKE;
     576             :                         }
     577          66 :                         DESTROY(SNAKE);
     578             :                         /* Set game.prop for use by travel options */
     579          66 :                         game.objects[SNAKE].prop = SNAKE_CHASED;
     580             :                 } else {
     581          95 :                         rspeak(OK_MAN);
     582             :                 }
     583             : 
     584         161 :                 game.objects[BIRD].prop =
     585         161 :                     FOREST(game.loc) ? BIRD_FOREST_UNCAGED : BIRD_UNCAGED;
     586         161 :                 drop(obj, game.loc);
     587         161 :                 return GO_CLEAROBJ;
     588             :         }
     589             : 
     590        1409 :         rspeak(OK_MAN);
     591        1409 :         drop(obj, game.loc);
     592        1409 :         return GO_CLEAROBJ;
     593             : }
     594             : 
     595          56 : static phase_codes_t drink(verb_t verb, obj_t obj) {
     596             :         /*  Drink.  If no object, assume water and look for it here.  If water
     597             :          * is in the bottle, drink that, else must be at a water loc, so drink
     598             :          * stream. */
     599          56 :         if (obj == INTRANSITIVE && LIQLOC(game.loc) != WATER &&
     600           1 :             (LIQUID() != WATER || !HERE(BOTTLE))) {
     601           1 :                 return GO_UNKNOWN;
     602             :         }
     603             : 
     604          55 :         if (obj == BLOOD) {
     605          44 :                 DESTROY(BLOOD);
     606          44 :                 state_change(DRAGON, DRAGON_BLOODLESS);
     607          44 :                 game.blooded = true;
     608          44 :                 return GO_CLEAROBJ;
     609             :         }
     610             : 
     611          11 :         if (obj != INTRANSITIVE && obj != WATER) {
     612           6 :                 rspeak(RIDICULOUS_ATTEMPT);
     613           6 :                 return GO_CLEAROBJ;
     614             :         }
     615           5 :         if (LIQUID() == WATER && HERE(BOTTLE)) {
     616           3 :                 game.objects[WATER].place = LOC_NOWHERE;
     617           3 :                 state_change(BOTTLE, EMPTY_BOTTLE);
     618           3 :                 return GO_CLEAROBJ;
     619             :         }
     620             : 
     621           2 :         speak(actions[verb].message);
     622           2 :         return GO_CLEAROBJ;
     623             : }
     624             : 
     625          10 : static phase_codes_t eat(verb_t verb, obj_t obj) {
     626             :         /*  Eat.  Intransitive: assume food if present, else ask what.
     627             :          * Transitive: food ok, some things lose appetite, rest are ridiculous.
     628             :          */
     629          10 :         switch (obj) {
     630           2 :         case INTRANSITIVE:
     631           2 :                 if (!HERE(FOOD)) {
     632           1 :                         return GO_UNKNOWN;
     633             :                 }
     634             :         /* FALLTHRU */
     635             :         case FOOD:
     636           2 :                 DESTROY(FOOD);
     637           2 :                 rspeak(THANKS_DELICIOUS);
     638           2 :                 break;
     639           2 :         case BIRD:
     640             :         case SNAKE:
     641             :         case CLAM:
     642             :         case OYSTER:
     643             :         case DWARF:
     644             :         case DRAGON:
     645             :         case TROLL:
     646             :         case BEAR:
     647             :         case OGRE:
     648           2 :                 rspeak(LOST_APPETITE);
     649           2 :                 break;
     650           5 :         default:
     651           5 :                 speak(actions[verb].message);
     652             :         }
     653           9 :         return GO_CLEAROBJ;
     654             : }
     655             : 
     656         233 : static phase_codes_t extinguish(verb_t verb, obj_t obj) {
     657             :         /* Extinguish.  Lamp, urn, dragon/volcano (nice try). */
     658         233 :         if (obj == INTRANSITIVE) {
     659         197 :                 if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_BRIGHT) {
     660         195 :                         obj = LAMP;
     661             :                 }
     662         197 :                 if (HERE(URN) && game.objects[URN].prop == URN_LIT) {
     663           1 :                         obj = URN;
     664             :                 }
     665         197 :                 if (obj == INTRANSITIVE) {
     666           1 :                         return GO_UNKNOWN;
     667             :                 }
     668             :         }
     669             : 
     670         232 :         switch (obj) {
     671           3 :         case URN:
     672           3 :                 if (game.objects[URN].prop != URN_EMPTY) {
     673           2 :                         state_change(URN, URN_DARK);
     674             :                 } else {
     675           1 :                         pspeak(URN, change, true, URN_DARK);
     676             :                 }
     677           3 :                 break;
     678         225 :         case LAMP:
     679         225 :                 state_change(LAMP, LAMP_DARK);
     680         225 :                 rspeak(DARK(game.loc) ? PITCH_DARK : NO_MESSAGE);
     681         225 :                 break;
     682           2 :         case DRAGON:
     683             :         case VOLCANO:
     684           2 :                 rspeak(BEYOND_POWER);
     685           2 :                 break;
     686           2 :         default:
     687           2 :                 speak(actions[verb].message);
     688             :         }
     689         232 :         return GO_CLEAROBJ;
     690             : }
     691             : 
     692          52 : static phase_codes_t feed(verb_t verb, obj_t obj) {
     693             :         /*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf,
     694             :          * make him mad.  Bear, special. */
     695          52 :         switch (obj) {
     696           1 :         case BIRD:
     697           1 :                 rspeak(BIRD_PINING);
     698           1 :                 break;
     699           4 :         case DRAGON:
     700           4 :                 if (game.objects[DRAGON].prop != DRAGON_BARS) {
     701           2 :                         rspeak(RIDICULOUS_ATTEMPT);
     702             :                 } else {
     703           2 :                         rspeak(NOTHING_EDIBLE);
     704             :                 }
     705           4 :                 break;
     706           2 :         case SNAKE:
     707           2 :                 if (!game.closed && HERE(BIRD)) {
     708           1 :                         DESTROY(BIRD);
     709           1 :                         rspeak(BIRD_DEVOURED);
     710             :                 } else {
     711           1 :                         rspeak(NOTHING_EDIBLE);
     712             :                 }
     713           2 :                 break;
     714           1 :         case TROLL:
     715           1 :                 rspeak(TROLL_VICES);
     716           1 :                 break;
     717           2 :         case DWARF:
     718           2 :                 if (HERE(FOOD)) {
     719           1 :                         game.dflag += 2;
     720           1 :                         rspeak(REALLY_MAD);
     721             :                 } else {
     722           1 :                         speak(actions[verb].message);
     723             :                 }
     724           2 :                 break;
     725          39 :         case BEAR:
     726          39 :                 if (game.objects[BEAR].prop == BEAR_DEAD) {
     727           1 :                         rspeak(RIDICULOUS_ATTEMPT);
     728           1 :                         break;
     729             :                 }
     730          38 :                 if (game.objects[BEAR].prop == UNTAMED_BEAR) {
     731          36 :                         if (HERE(FOOD)) {
     732          34 :                                 DESTROY(FOOD);
     733          34 :                                 game.objects[AXE].fixed = IS_FREE;
     734          34 :                                 game.objects[AXE].prop = AXE_HERE;
     735          34 :                                 state_change(BEAR, SITTING_BEAR);
     736             :                         } else {
     737           2 :                                 rspeak(NOTHING_EDIBLE);
     738             :                         }
     739          36 :                         break;
     740             :                 }
     741           2 :                 speak(actions[verb].message);
     742           2 :                 break;
     743           2 :         case OGRE:
     744           2 :                 if (HERE(FOOD)) {
     745           1 :                         rspeak(OGRE_FULL);
     746             :                 } else {
     747           1 :                         speak(actions[verb].message);
     748             :                 }
     749           2 :                 break;
     750           1 :         default:
     751           1 :                 rspeak(AM_GAME);
     752             :         }
     753          52 :         return GO_CLEAROBJ;
     754             : }
     755             : 
     756         165 : phase_codes_t fill(verb_t verb, obj_t obj) {
     757             :         /*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
     758             :          *  is nasty.) */
     759         165 :         if (obj == VASE) {
     760           3 :                 if (LIQLOC(game.loc) == NO_OBJECT) {
     761           1 :                         rspeak(FILL_INVALID);
     762           1 :                         return GO_CLEAROBJ;
     763             :                 }
     764           2 :                 if (!TOTING(VASE)) {
     765           1 :                         rspeak(ARENT_CARRYING);
     766           1 :                         return GO_CLEAROBJ;
     767             :                 }
     768           1 :                 rspeak(SHATTER_VASE);
     769           1 :                 game.objects[VASE].prop = VASE_BROKEN;
     770           1 :                 game.objects[VASE].fixed = IS_FIXED;
     771           1 :                 drop(VASE, game.loc);
     772           1 :                 return GO_CLEAROBJ;
     773             :         }
     774             : 
     775         162 :         if (obj == URN) {
     776          31 :                 if (game.objects[URN].prop != URN_EMPTY) {
     777           1 :                         rspeak(FULL_URN);
     778           1 :                         return GO_CLEAROBJ;
     779             :                 }
     780          30 :                 if (!HERE(BOTTLE)) {
     781           1 :                         rspeak(FILL_INVALID);
     782           1 :                         return GO_CLEAROBJ;
     783             :                 }
     784          29 :                 int k = LIQUID();
     785          29 :                 switch (k) {
     786           1 :                 case WATER:
     787           1 :                         game.objects[BOTTLE].prop = EMPTY_BOTTLE;
     788           1 :                         rspeak(WATER_URN);
     789           1 :                         break;
     790          27 :                 case OIL:
     791          27 :                         game.objects[URN].prop = URN_DARK;
     792          27 :                         game.objects[BOTTLE].prop = EMPTY_BOTTLE;
     793          27 :                         rspeak(OIL_URN);
     794          27 :                         break;
     795           1 :                 case NO_OBJECT:
     796             :                 default:
     797           1 :                         rspeak(FILL_INVALID);
     798           1 :                         return GO_CLEAROBJ;
     799             :                 }
     800          28 :                 game.objects[k].place = LOC_NOWHERE;
     801          28 :                 return GO_CLEAROBJ;
     802             :         }
     803         131 :         if (obj != INTRANSITIVE && obj != BOTTLE) {
     804           1 :                 speak(actions[verb].message);
     805           1 :                 return GO_CLEAROBJ;
     806             :         }
     807         130 :         if (obj == INTRANSITIVE && !HERE(BOTTLE)) {
     808           1 :                 return GO_UNKNOWN;
     809             :         }
     810             : 
     811         129 :         if (HERE(URN) && game.objects[URN].prop != URN_EMPTY) {
     812           1 :                 rspeak(URN_NOPOUR);
     813           1 :                 return GO_CLEAROBJ;
     814             :         }
     815         128 :         if (LIQUID() != NO_OBJECT) {
     816           1 :                 rspeak(BOTTLE_FULL);
     817           1 :                 return GO_CLEAROBJ;
     818             :         }
     819         127 :         if (LIQLOC(game.loc) == NO_OBJECT) {
     820           1 :                 rspeak(NO_LIQUID);
     821           1 :                 return GO_CLEAROBJ;
     822             :         }
     823             : 
     824         252 :         state_change(BOTTLE,
     825         252 :                      (LIQLOC(game.loc) == OIL) ? OIL_BOTTLE : WATER_BOTTLE);
     826         126 :         if (TOTING(BOTTLE)) {
     827         126 :                 game.objects[LIQUID()].place = CARRIED;
     828             :         }
     829         126 :         return GO_CLEAROBJ;
     830             : }
     831             : 
     832           8 : static phase_codes_t find(verb_t verb, obj_t obj) {
     833             :         /* Find.  Might be carrying it, or it might be here.  Else give caveat.
     834             :          */
     835           8 :         if (TOTING(obj)) {
     836           2 :                 rspeak(ALREADY_CARRYING);
     837           2 :                 return GO_CLEAROBJ;
     838             :         }
     839             : 
     840           6 :         if (game.closed) {
     841           1 :                 rspeak(NEEDED_NEARBY);
     842           1 :                 return GO_CLEAROBJ;
     843             :         }
     844             : 
     845           9 :         if (AT(obj) || (LIQUID() == obj && AT(BOTTLE)) ||
     846           8 :             obj == LIQLOC(game.loc) || (obj == DWARF && atdwrf(game.loc) > 0)) {
     847           2 :                 rspeak(YOU_HAVEIT);
     848           2 :                 return GO_CLEAROBJ;
     849             :         }
     850             : 
     851           3 :         speak(actions[verb].message);
     852           3 :         return GO_CLEAROBJ;
     853             : }
     854             : 
     855          57 : static phase_codes_t fly(verb_t verb, obj_t obj) {
     856             :         /* Fly.  Snide remarks unless hovering rug is here. */
     857          57 :         if (obj == INTRANSITIVE) {
     858          13 :                 if (!HERE(RUG)) {
     859           1 :                         rspeak(FLAP_ARMS);
     860           1 :                         return GO_CLEAROBJ;
     861             :                 }
     862          12 :                 if (game.objects[RUG].prop != RUG_HOVER) {
     863           1 :                         rspeak(RUG_NOTHING2);
     864           1 :                         return GO_CLEAROBJ;
     865             :                 }
     866          11 :                 obj = RUG;
     867             :         }
     868             : 
     869          55 :         if (obj != RUG) {
     870           1 :                 speak(actions[verb].message);
     871           1 :                 return GO_CLEAROBJ;
     872             :         }
     873          54 :         if (game.objects[RUG].prop != RUG_HOVER) {
     874           1 :                 rspeak(RUG_NOTHING1);
     875           1 :                 return GO_CLEAROBJ;
     876             :         }
     877             : 
     878          53 :         if (game.loc == LOC_CLIFF) {
     879          27 :                 game.oldlc2 = game.oldloc;
     880          27 :                 game.oldloc = game.loc;
     881          27 :                 game.newloc = LOC_LEDGE;
     882          27 :                 rspeak(RUG_GOES);
     883          26 :         } else if (game.loc == LOC_LEDGE) {
     884          26 :                 game.oldlc2 = game.oldloc;
     885          26 :                 game.oldloc = game.loc;
     886          26 :                 game.newloc = LOC_CLIFF;
     887          26 :                 rspeak(RUG_RETURNS);
     888             :         } else {
     889             :                 // LCOV_EXCL_START
     890             :                 /* should never happen */
     891             :                 rspeak(NOTHING_HAPPENS);
     892             :                 // LCOV_EXCL_STOP
     893             :         }
     894          53 :         return GO_TERMINATE;
     895             : }
     896             : 
     897         102 : static phase_codes_t inven(void) {
     898             :         /* Inventory. If object, treat same as find.  Else report on current
     899             :          * burden. */
     900         102 :         bool empty = true;
     901        7140 :         for (obj_t i = 1; i <= NOBJECTS; i++) {
     902        7038 :                 if (i == BEAR || !TOTING(i)) {
     903        6515 :                         continue;
     904             :                 }
     905         523 :                 if (empty) {
     906         101 :                         rspeak(NOW_HOLDING);
     907         101 :                         empty = false;
     908             :                 }
     909         523 :                 pspeak(i, touch, false, -1);
     910             :         }
     911         102 :         if (TOTING(BEAR)) {
     912           1 :                 rspeak(TAME_BEAR);
     913             :         }
     914         102 :         if (empty) {
     915           1 :                 rspeak(NO_CARRY);
     916             :         }
     917         102 :         return GO_CLEAROBJ;
     918             : }
     919             : 
     920         333 : static phase_codes_t light(verb_t verb, obj_t obj) {
     921             :         /*  Light.  Applicable only to lamp and urn. */
     922         333 :         if (obj == INTRANSITIVE) {
     923         296 :                 int selects = 0;
     924         296 :                 if (HERE(LAMP) && game.objects[LAMP].prop == LAMP_DARK &&
     925         295 :                     game.limit >= 0) {
     926         295 :                         obj = LAMP;
     927         295 :                         selects++;
     928             :                 }
     929         296 :                 if (HERE(URN) && game.objects[URN].prop == URN_DARK) {
     930           2 :                         obj = URN;
     931           2 :                         selects++;
     932             :                 }
     933         296 :                 if (selects != 1) {
     934           1 :                         return GO_UNKNOWN;
     935             :                 }
     936             :         }
     937             : 
     938         332 :         switch (obj) {
     939          29 :         case URN:
     940          29 :                 state_change(URN, game.objects[URN].prop == URN_EMPTY
     941             :                                       ? URN_EMPTY
     942             :                                       : URN_LIT);
     943          29 :                 break;
     944         301 :         case LAMP:
     945         301 :                 if (game.limit < 0) {
     946           1 :                         rspeak(LAMP_OUT);
     947           1 :                         break;
     948             :                 }
     949         300 :                 state_change(LAMP, LAMP_BRIGHT);
     950         300 :                 if (game.wzdark) {
     951         293 :                         return GO_TOP;
     952             :                 }
     953           7 :                 break;
     954           2 :         default:
     955           2 :                 speak(actions[verb].message);
     956             :         }
     957          39 :         return GO_CLEAROBJ;
     958             : }
     959             : 
     960          59 : static phase_codes_t listen(void) {
     961             :         /*  Listen.  Intransitive only.  Print stuff based on object sound
     962             :          * properties. */
     963          59 :         bool soundlatch = false;
     964          59 :         vocab_t sound = locations[game.loc].sound;
     965          59 :         if (sound != SILENT) {
     966          13 :                 rspeak(sound);
     967          13 :                 if (!locations[game.loc].loud) {
     968          12 :                         rspeak(NO_MESSAGE);
     969             :                 }
     970          13 :                 soundlatch = true;
     971             :         }
     972        4130 :         for (obj_t i = 1; i <= NOBJECTS; i++) {
     973        4071 :                 if (!HERE(i) || objects[i].sounds[0] == NULL ||
     974          52 :                     PROP_IS_STASHED_OR_UNSEEN(i)) {
     975        4022 :                         continue;
     976             :                 }
     977          49 :                 int mi = game.objects[i].prop;
     978             :                 /* (ESR) Some unpleasant magic on object states here. Ideally
     979             :                  * we'd have liked the bird to be a normal object that we can
     980             :                  * use state_change() on; can't do it, because there are
     981             :                  * actually two different series of per-state birdsounds
     982             :                  * depending on whether player has drunk dragon's blood. */
     983          49 :                 if (i == BIRD) {
     984          46 :                         mi += 3 * game.blooded;
     985             :                 }
     986          49 :                 pspeak(i, hear, true, mi, game.zzword);
     987          49 :                 rspeak(NO_MESSAGE);
     988          49 :                 if (i == BIRD && mi == BIRD_ENDSTATE) {
     989          43 :                         DESTROY(BIRD);
     990             :                 }
     991          49 :                 soundlatch = true;
     992             :         }
     993          59 :         if (!soundlatch) {
     994           1 :                 rspeak(ALL_SILENT);
     995             :         }
     996          59 :         return GO_CLEAROBJ;
     997             : }
     998             : 
     999         118 : static phase_codes_t lock(verb_t verb, obj_t obj) {
    1000             :         /* Lock, unlock, no object given.  Assume various things if present. */
    1001         118 :         if (obj == INTRANSITIVE) {
    1002          15 :                 if (HERE(CLAM)) {
    1003           2 :                         obj = CLAM;
    1004             :                 }
    1005          15 :                 if (HERE(OYSTER)) {
    1006           1 :                         obj = OYSTER;
    1007             :                 }
    1008          15 :                 if (AT(DOOR)) {
    1009           2 :                         obj = DOOR;
    1010             :                 }
    1011          15 :                 if (AT(GRATE)) {
    1012           2 :                         obj = GRATE;
    1013             :                 }
    1014          15 :                 if (HERE(CHAIN)) {
    1015           5 :                         obj = CHAIN;
    1016             :                 }
    1017          15 :                 if (obj == INTRANSITIVE) {
    1018           3 :                         rspeak(NOTHING_LOCKED);
    1019           3 :                         return GO_CLEAROBJ;
    1020             :                 }
    1021             :         }
    1022             : 
    1023             :         /*  Lock, unlock object.  Special stuff for opening clam/oyster
    1024             :          *  and for chain. */
    1025             : 
    1026         115 :         switch (obj) {
    1027          45 :         case CHAIN:
    1028          45 :                 if (HERE(KEYS)) {
    1029          44 :                         return chain(verb);
    1030             :                 } else {
    1031           1 :                         rspeak(NO_KEYS);
    1032             :                 }
    1033           1 :                 break;
    1034          12 :         case GRATE:
    1035          12 :                 if (HERE(KEYS)) {
    1036           9 :                         if (game.closng) {
    1037           1 :                                 rspeak(EXIT_CLOSED);
    1038           1 :                                 if (!game.panic) {
    1039           1 :                                         game.clock2 = PANICTIME;
    1040             :                                 }
    1041           1 :                                 game.panic = true;
    1042             :                         } else {
    1043           8 :                                 state_change(GRATE, (verb == LOCK)
    1044             :                                                         ? GRATE_CLOSED
    1045             :                                                         : GRATE_OPEN);
    1046             :                         }
    1047             :                 } else {
    1048           3 :                         rspeak(NO_KEYS);
    1049             :                 }
    1050          12 :                 break;
    1051          41 :         case CLAM:
    1052          41 :                 if (verb == LOCK) {
    1053           1 :                         rspeak(HUH_MAN);
    1054          40 :                 } else if (TOTING(CLAM)) {
    1055           2 :                         rspeak(DROP_CLAM);
    1056          38 :                 } else if (!TOTING(TRIDENT)) {
    1057           1 :                         rspeak(CLAM_OPENER);
    1058             :                 } else {
    1059          37 :                         DESTROY(CLAM);
    1060          37 :                         drop(OYSTER, game.loc);
    1061          37 :                         drop(PEARL, LOC_CULDESAC);
    1062          37 :                         rspeak(PEARL_FALLS);
    1063             :                 }
    1064          41 :                 break;
    1065           6 :         case OYSTER:
    1066           6 :                 if (verb == LOCK) {
    1067           2 :                         rspeak(HUH_MAN);
    1068           4 :                 } else if (TOTING(OYSTER)) {
    1069           1 :                         rspeak(DROP_OYSTER);
    1070           3 :                 } else if (!TOTING(TRIDENT)) {
    1071           2 :                         rspeak(OYSTER_OPENER);
    1072             :                 } else {
    1073           1 :                         rspeak(OYSTER_OPENS);
    1074             :                 }
    1075           6 :                 break;
    1076           6 :         case DOOR:
    1077           6 :                 rspeak((game.objects[DOOR].prop == DOOR_UNRUSTED) ? OK_MAN
    1078             :                                                                   : RUSTY_DOOR);
    1079           6 :                 break;
    1080           2 :         case CAGE:
    1081           2 :                 rspeak(NO_LOCK);
    1082           2 :                 break;
    1083           1 :         case KEYS:
    1084           1 :                 rspeak(CANNOT_UNLOCK);
    1085           1 :                 break;
    1086           2 :         default:
    1087           2 :                 speak(actions[verb].message);
    1088             :         }
    1089             : 
    1090          71 :         return GO_CLEAROBJ;
    1091             : }
    1092             : 
    1093         149 : static phase_codes_t pour(verb_t verb, obj_t obj) {
    1094             :         /*  Pour.  If no object, or object is bottle, assume contents of bottle.
    1095             :          *  special tests for pouring water or oil on plant or rusty door. */
    1096         149 :         if (obj == BOTTLE || obj == INTRANSITIVE) {
    1097           5 :                 obj = LIQUID();
    1098             :         }
    1099         149 :         if (obj == NO_OBJECT) {
    1100           1 :                 return GO_UNKNOWN;
    1101             :         }
    1102         148 :         if (!TOTING(obj)) {
    1103           1 :                 speak(actions[verb].message);
    1104           1 :                 return GO_CLEAROBJ;
    1105             :         }
    1106             : 
    1107         147 :         if (obj != OIL && obj != WATER) {
    1108           1 :                 rspeak(CANT_POUR);
    1109           1 :                 return GO_CLEAROBJ;
    1110             :         }
    1111         146 :         if (HERE(URN) && game.objects[URN].prop == URN_EMPTY) {
    1112           1 :                 return fill(verb, URN);
    1113             :         }
    1114         145 :         game.objects[BOTTLE].prop = EMPTY_BOTTLE;
    1115         145 :         game.objects[obj].place = LOC_NOWHERE;
    1116         145 :         if (!(AT(PLANT) || AT(DOOR))) {
    1117           2 :                 rspeak(GROUND_WET);
    1118           2 :                 return GO_CLEAROBJ;
    1119             :         }
    1120         143 :         if (!AT(DOOR)) {
    1121          99 :                 if (obj == WATER) {
    1122             :                         /* cycle through the three plant states */
    1123          98 :                         state_change(PLANT,
    1124          98 :                                      MOD(game.objects[PLANT].prop + 1, 3));
    1125          98 :                         game.objects[PLANT2].prop = game.objects[PLANT].prop;
    1126          98 :                         return GO_MOVE;
    1127             :                 } else {
    1128           1 :                         rspeak(SHAKING_LEAVES);
    1129           1 :                         return GO_CLEAROBJ;
    1130             :                 }
    1131             :         } else {
    1132          44 :                 state_change(DOOR, (obj == OIL) ? DOOR_UNRUSTED : DOOR_RUSTED);
    1133          44 :                 return GO_CLEAROBJ;
    1134             :         }
    1135             : }
    1136             : 
    1137           6 : static phase_codes_t quit(void) {
    1138             :         /*  Quit.  Intransitive only.  Verify intent and exit if that's what he
    1139             :          * wants. */
    1140           6 :         if (yes_or_no(arbitrary_messages[REALLY_QUIT],
    1141             :                       arbitrary_messages[OK_MAN], arbitrary_messages[OK_MAN])) {
    1142           5 :                 terminate(quitgame);
    1143             :         }
    1144           1 :         return GO_CLEAROBJ;
    1145             : }
    1146             : 
    1147          15 : static phase_codes_t read(command_t command)
    1148             : /*  Read.  Print stuff based on objtxt.  Oyster (?) is special case. */
    1149             : {
    1150          15 :         if (command.obj == INTRANSITIVE) {
    1151           3 :                 command.obj = NO_OBJECT;
    1152         210 :                 for (int i = 1; i <= NOBJECTS; i++) {
    1153         207 :                         if (HERE(i) && objects[i].texts[0] != NULL &&
    1154           3 :                             !PROP_IS_STASHED(i)) {
    1155           3 :                                 command.obj = command.obj * NOBJECTS + i;
    1156             :                         }
    1157             :                 }
    1158           3 :                 if (command.obj > NOBJECTS || command.obj == NO_OBJECT ||
    1159           3 :                     DARK(game.loc)) {
    1160           2 :                         return GO_UNKNOWN;
    1161             :                 }
    1162             :         }
    1163             : 
    1164          13 :         if (DARK(game.loc)) {
    1165           1 :                 sspeak(NO_SEE, command.word[0].raw);
    1166          12 :         } else if (command.obj == OYSTER) {
    1167           4 :                 if (!TOTING(OYSTER) || !game.closed) {
    1168           1 :                         rspeak(DONT_UNDERSTAND);
    1169           3 :                 } else if (!game.clshnt) {
    1170           2 :                         game.clshnt = yes_or_no(arbitrary_messages[CLUE_QUERY],
    1171             :                                                 arbitrary_messages[WAYOUT_CLUE],
    1172             :                                                 arbitrary_messages[OK_MAN]);
    1173             :                 } else {
    1174           1 :                         pspeak(OYSTER, hear, true,
    1175             :                                1); // Not really a sound, but oh well.
    1176             :                 }
    1177           8 :         } else if (objects[command.obj].texts[0] == NULL ||
    1178           5 :                    PROP_IS_NOTFOUND(command.obj)) {
    1179           3 :                 speak(actions[command.verb].message);
    1180             :         } else {
    1181           5 :                 pspeak(command.obj, study, true,
    1182           5 :                        game.objects[command.obj].prop);
    1183             :         }
    1184          13 :         return GO_CLEAROBJ;
    1185             : }
    1186             : 
    1187          54 : static phase_codes_t reservoir(void) {
    1188             :         /*  Z'ZZZ (word gets recomputed at startup; different each game). */
    1189          54 :         if (!AT(RESER) && game.loc != LOC_RESBOTTOM) {
    1190           4 :                 rspeak(NOTHING_HAPPENS);
    1191           4 :                 return GO_CLEAROBJ;
    1192             :         } else {
    1193          50 :                 state_change(RESER, game.objects[RESER].prop == WATERS_PARTED
    1194             :                                         ? WATERS_UNPARTED
    1195             :                                         : WATERS_PARTED);
    1196          50 :                 if (AT(RESER)) {
    1197          49 :                         return GO_CLEAROBJ;
    1198             :                 } else {
    1199           1 :                         game.oldlc2 = game.loc;
    1200           1 :                         game.newloc = LOC_NOWHERE;
    1201           1 :                         rspeak(NOT_BRIGHT);
    1202           1 :                         return GO_TERMINATE;
    1203             :                 }
    1204             :         }
    1205             : }
    1206             : 
    1207          28 : static phase_codes_t rub(verb_t verb, obj_t obj) {
    1208             :         /* Rub.  Yields various snide remarks except for lit urn. */
    1209          28 :         if (obj == URN && game.objects[URN].prop == URN_LIT) {
    1210          26 :                 DESTROY(URN);
    1211          26 :                 drop(AMBER, game.loc);
    1212          26 :                 game.objects[AMBER].prop = AMBER_IN_ROCK;
    1213          26 :                 --game.tally;
    1214          26 :                 drop(CAVITY, game.loc);
    1215          26 :                 rspeak(URN_GENIES);
    1216           2 :         } else if (obj != LAMP) {
    1217           1 :                 rspeak(PECULIAR_NOTHING);
    1218             :         } else {
    1219           1 :                 speak(actions[verb].message);
    1220             :         }
    1221          28 :         return GO_CLEAROBJ;
    1222             : }
    1223             : 
    1224          36 : static phase_codes_t say(command_t command) {
    1225             :         /* Say.  Echo WD2. Magic words override. */
    1226          36 :         if (command.word[1].type == MOTION &&
    1227          17 :             (command.word[1].id == XYZZY || command.word[1].id == PLUGH ||
    1228           3 :              command.word[1].id == PLOVER)) {
    1229          17 :                 return GO_WORD2;
    1230             :         }
    1231          19 :         if (command.word[1].type == ACTION && command.word[1].id == PART) {
    1232           3 :                 return reservoir();
    1233             :         }
    1234             : 
    1235          16 :         if (command.word[1].type == ACTION &&
    1236          11 :             (command.word[1].id == FEE || command.word[1].id == FIE ||
    1237           7 :              command.word[1].id == FOE || command.word[1].id == FOO ||
    1238           3 :              command.word[1].id == FUM || command.word[1].id == PART)) {
    1239           9 :                 return bigwords(command.word[1].id);
    1240             :         }
    1241           7 :         sspeak(OKEY_DOKEY, command.word[1].raw);
    1242           7 :         return GO_CLEAROBJ;
    1243             : }
    1244             : 
    1245         147 : static phase_codes_t throw_support(vocab_t spk) {
    1246         147 :         rspeak(spk);
    1247         147 :         drop(AXE, game.loc);
    1248         147 :         return GO_MOVE;
    1249             : }
    1250             : 
    1251         199 : static phase_codes_t throwit(command_t command) {
    1252             :         /*  Throw.  Same as discard unless axe.  Then same as attack except
    1253             :          *  ignore bird, and if dwarf is present then one might be killed.
    1254             :          *  (Only way to do so!)  Axe also special for dragon, bear, and
    1255             :          *  troll.  Treasures special for troll. */
    1256         199 :         if (!TOTING(command.obj)) {
    1257           2 :                 speak(actions[command.verb].message);
    1258           2 :                 return GO_CLEAROBJ;
    1259             :         }
    1260         197 :         if (objects[command.obj].is_treasure && AT(TROLL)) {
    1261             :                 /*  Snarf a treasure for the troll. */
    1262          36 :                 drop(command.obj, LOC_NOWHERE);
    1263          36 :                 move(TROLL, LOC_NOWHERE);
    1264          36 :                 move(TROLL + NOBJECTS, IS_FREE);
    1265          36 :                 drop(TROLL2, objects[TROLL].plac);
    1266          36 :                 drop(TROLL2 + NOBJECTS, objects[TROLL].fixd);
    1267          36 :                 juggle(CHASM);
    1268          36 :                 rspeak(TROLL_SATISFIED);
    1269          36 :                 return GO_CLEAROBJ;
    1270             :         }
    1271         161 :         if (command.obj == FOOD && HERE(BEAR)) {
    1272             :                 /* But throwing food is another story. */
    1273           4 :                 command.obj = BEAR;
    1274           4 :                 return (feed(command.verb, command.obj));
    1275             :         }
    1276         157 :         if (command.obj != AXE) {
    1277           3 :                 return (discard(command.verb, command.obj));
    1278             :         } else {
    1279         154 :                 if (atdwrf(game.loc) <= 0) {
    1280          10 :                         if (AT(DRAGON) &&
    1281           1 :                             game.objects[DRAGON].prop == DRAGON_BARS) {
    1282           1 :                                 return throw_support(DRAGON_SCALES);
    1283             :                         }
    1284           9 :                         if (AT(TROLL)) {
    1285           1 :                                 return throw_support(TROLL_RETURNS);
    1286             :                         }
    1287           8 :                         if (AT(OGRE)) {
    1288           1 :                                 return throw_support(OGRE_DODGE);
    1289             :                         }
    1290           7 :                         if (HERE(BEAR) &&
    1291           2 :                             game.objects[BEAR].prop == UNTAMED_BEAR) {
    1292             :                                 /* This'll teach him to throw the axe at the
    1293             :                                  * bear! */
    1294           2 :                                 drop(AXE, game.loc);
    1295           2 :                                 game.objects[AXE].fixed = IS_FIXED;
    1296           2 :                                 juggle(BEAR);
    1297           2 :                                 state_change(AXE, AXE_LOST);
    1298           2 :                                 return GO_CLEAROBJ;
    1299             :                         }
    1300           5 :                         command.obj = INTRANSITIVE;
    1301           5 :                         return (attack(command));
    1302             :                 }
    1303             : 
    1304         144 :                 if (randrange(NDWARVES + 1) < game.dflag) {
    1305           9 :                         return throw_support(DWARF_DODGES);
    1306             :                 } else {
    1307         135 :                         int i = atdwrf(game.loc);
    1308         135 :                         game.dwarves[i].seen = false;
    1309         135 :                         game.dwarves[i].loc = LOC_NOWHERE;
    1310         135 :                         return throw_support(
    1311         135 :                             (++game.dkill == 1) ? DWARF_SMOKE : KILLED_DWARF);
    1312             :                 }
    1313             :         }
    1314             : }
    1315             : 
    1316           2 : static phase_codes_t wake(verb_t verb, obj_t obj) {
    1317             :         /* Wake.  Only use is to disturb the dwarves. */
    1318           2 :         if (obj != DWARF || !game.closed) {
    1319           1 :                 speak(actions[verb].message);
    1320           1 :                 return GO_CLEAROBJ;
    1321             :         } else {
    1322           1 :                 rspeak(PROD_DWARF);
    1323           1 :                 return GO_DWARFWAKE;
    1324             :         }
    1325             : }
    1326             : 
    1327          98 : static phase_codes_t seed(verb_t verb, const char *arg) {
    1328             :         /* Set seed */
    1329          98 :         int32_t seed = strtol(arg, NULL, 10);
    1330          98 :         speak(actions[verb].message, seed);
    1331          98 :         set_seed(seed);
    1332          98 :         --game.turns;
    1333          98 :         return GO_TOP;
    1334             : }
    1335             : 
    1336           1 : static phase_codes_t waste(verb_t verb, turn_t turns) {
    1337             :         /* Burn turns */
    1338           1 :         game.limit -= turns;
    1339           1 :         speak(actions[verb].message, (int)game.limit);
    1340           1 :         return GO_TOP;
    1341             : }
    1342             : 
    1343         123 : static phase_codes_t wave(verb_t verb, obj_t obj) {
    1344             :         /* Wave.  No effect unless waving rod at fissure or at bird. */
    1345         123 :         if (obj != ROD || !TOTING(obj) ||
    1346         119 :             (!HERE(BIRD) && (game.closng || !AT(FISSURE)))) {
    1347           5 :                 speak(((!TOTING(obj)) && (obj != ROD || !TOTING(ROD2)))
    1348             :                           ? arbitrary_messages[ARENT_CARRYING]
    1349             :                           : actions[verb].message);
    1350           5 :                 return GO_CLEAROBJ;
    1351             :         }
    1352             : 
    1353         118 :         if (game.objects[BIRD].prop == BIRD_UNCAGED &&
    1354          65 :             game.loc == game.objects[STEPS].place && PROP_IS_NOTFOUND(JADE)) {
    1355          51 :                 drop(JADE, game.loc);
    1356          51 :                 PROP_SET_FOUND(JADE);
    1357          51 :                 --game.tally;
    1358          51 :                 rspeak(NECKLACE_FLY);
    1359          51 :                 return GO_CLEAROBJ;
    1360             :         } else {
    1361          67 :                 if (game.closed) {
    1362           1 :                         rspeak((game.objects[BIRD].prop == BIRD_CAGED)
    1363             :                                    ? CAGE_FLY
    1364             :                                    : FREE_FLY);
    1365           1 :                         return GO_DWARFWAKE;
    1366             :                 }
    1367          66 :                 if (game.closng || !AT(FISSURE)) {
    1368           2 :                         rspeak((game.objects[BIRD].prop == BIRD_CAGED)
    1369             :                                    ? CAGE_FLY
    1370             :                                    : FREE_FLY);
    1371           2 :                         return GO_CLEAROBJ;
    1372             :                 }
    1373          64 :                 if (HERE(BIRD)) {
    1374          17 :                         rspeak((game.objects[BIRD].prop == BIRD_CAGED)
    1375             :                                    ? CAGE_FLY
    1376             :                                    : FREE_FLY);
    1377             :                 }
    1378             : 
    1379          64 :                 state_change(FISSURE, game.objects[FISSURE].prop == BRIDGED
    1380             :                                           ? UNBRIDGED
    1381             :                                           : BRIDGED);
    1382          64 :                 return GO_CLEAROBJ;
    1383             :         }
    1384             : }
    1385             : 
    1386       11685 : phase_codes_t action(command_t command) {
    1387             :         /*  Analyse a verb.  Remember what it was, go back for object if second
    1388             :          * word unless verb is "say", which snarfs arbitrary second word.
    1389             :          */
    1390             :         /* Previously, actions that result in a message, but don't do anything
    1391             :          * further were called "specials". Now they're handled here as normal
    1392             :          * actions. If noaction is true, then we spit out the message and return
    1393             :          */
    1394       11685 :         if (actions[command.verb].noaction) {
    1395          18 :                 speak(actions[command.verb].message);
    1396          18 :                 return GO_CLEAROBJ;
    1397             :         }
    1398             : 
    1399       11667 :         if (command.part == unknown) {
    1400             :                 /*  Analyse an object word.  See if the thing is here, whether
    1401             :                  *  we've got a verb yet, and so on.  Object must be here
    1402             :                  *  unless verb is "find" or "invent(ory)" (and no new verb
    1403             :                  *  yet to be analysed).  Water and oil are also funny, since
    1404             :                  *  they are never actually dropped at any location, but might
    1405             :                  *  be here inside the bottle or urn or as a feature of the
    1406             :                  *  location. */
    1407        5184 :                 if (HERE(command.obj)) {
    1408             :                         /* FALL THROUGH */;
    1409         217 :                 } else if (command.obj == DWARF && atdwrf(game.loc) > 0) {
    1410             :                         /* FALL THROUGH */;
    1411         211 :                 } else if (!game.closed &&
    1412         350 :                            ((LIQUID() == command.obj && HERE(BOTTLE)) ||
    1413         146 :                             command.obj == LIQLOC(game.loc))) {
    1414             :                         /* FALL THROUGH */;
    1415          37 :                 } else if (command.obj == OIL && HERE(URN) &&
    1416           1 :                            game.objects[URN].prop != URN_EMPTY) {
    1417           1 :                         command.obj = URN;
    1418             :                         /* FALL THROUGH */;
    1419          36 :                 } else if (command.obj == PLANT && AT(PLANT2) &&
    1420           2 :                            game.objects[PLANT2].prop != PLANT_THIRSTY) {
    1421           2 :                         command.obj = PLANT2;
    1422             :                         /* FALL THROUGH */;
    1423          34 :                 } else if (command.obj == KNIFE && game.knfloc == game.loc) {
    1424           1 :                         game.knfloc = -1;
    1425           1 :                         rspeak(KNIVES_VANISH);
    1426           1 :                         return GO_CLEAROBJ;
    1427          33 :                 } else if (command.obj == ROD && HERE(ROD2)) {
    1428           6 :                         command.obj = ROD2;
    1429             :                         /* FALL THROUGH */;
    1430          27 :                 } else if ((command.verb == FIND ||
    1431          25 :                             command.verb == INVENTORY) &&
    1432           3 :                            (command.word[1].id == WORD_EMPTY ||
    1433           0 :                             command.word[1].id == WORD_NOT_FOUND)) {
    1434             :                         /* FALL THROUGH */;
    1435             :                 } else {
    1436          24 :                         sspeak(NO_SEE, command.word[0].raw);
    1437          24 :                         return GO_CLEAROBJ;
    1438             :                 }
    1439             : 
    1440        5159 :                 if (command.verb != 0) {
    1441        5155 :                         command.part = transitive;
    1442             :                 }
    1443             :         }
    1444             : 
    1445       11642 :         switch (command.part) {
    1446        6384 :         case intransitive:
    1447        6384 :                 if (command.word[1].raw[0] != '\0' && command.verb != SAY) {
    1448        5207 :                         return GO_WORD2;
    1449             :                 }
    1450        1177 :                 if (command.verb == SAY) {
    1451             :                         /* KEYS is not special, anything not NO_OBJECT or
    1452             :                          * INTRANSITIVE will do here. We're preventing
    1453             :                          * interpretation as an intransitive verb when the word
    1454             :                          * is unknown. */
    1455          37 :                         command.obj =
    1456          37 :                             command.word[1].raw[0] != '\0' ? KEYS : NO_OBJECT;
    1457             :                 }
    1458        1177 :                 if (command.obj == NO_OBJECT || command.obj == INTRANSITIVE) {
    1459             :                         /*  Analyse an intransitive verb (ie, no object given
    1460             :                          * yet). */
    1461        1140 :                         switch (command.verb) {
    1462          36 :                         case CARRY:
    1463          36 :                                 return vcarry(command.verb, INTRANSITIVE);
    1464           1 :                         case DROP:
    1465           1 :                                 return GO_UNKNOWN;
    1466           1 :                         case SAY:
    1467           1 :                                 return GO_UNKNOWN;
    1468          11 :                         case UNLOCK:
    1469          11 :                                 return lock(command.verb, INTRANSITIVE);
    1470         158 :                         case NOTHING: {
    1471         158 :                                 rspeak(OK_MAN);
    1472         158 :                                 return (GO_CLEAROBJ);
    1473             :                         }
    1474           4 :                         case LOCK:
    1475           4 :                                 return lock(command.verb, INTRANSITIVE);
    1476         296 :                         case LIGHT:
    1477         296 :                                 return light(command.verb, INTRANSITIVE);
    1478         197 :                         case EXTINGUISH:
    1479         197 :                                 return extinguish(command.verb, INTRANSITIVE);
    1480           1 :                         case WAVE:
    1481           1 :                                 return GO_UNKNOWN;
    1482           1 :                         case TAME:
    1483           1 :                                 return GO_UNKNOWN;
    1484           2 :                         case GO: {
    1485           2 :                                 speak(actions[command.verb].message);
    1486           2 :                                 return GO_CLEAROBJ;
    1487             :                         }
    1488          19 :                         case ATTACK:
    1489          19 :                                 command.obj = INTRANSITIVE;
    1490          19 :                                 return attack(command);
    1491           1 :                         case POUR:
    1492           1 :                                 return pour(command.verb, INTRANSITIVE);
    1493           2 :                         case EAT:
    1494           2 :                                 return eat(command.verb, INTRANSITIVE);
    1495           4 :                         case DRINK:
    1496           4 :                                 return drink(command.verb, INTRANSITIVE);
    1497           1 :                         case RUB:
    1498           1 :                                 return GO_UNKNOWN;
    1499           1 :                         case THROW:
    1500           1 :                                 return GO_UNKNOWN;
    1501           6 :                         case QUIT:
    1502           6 :                                 return quit();
    1503           1 :                         case FIND:
    1504           1 :                                 return GO_UNKNOWN;
    1505         102 :                         case INVENTORY:
    1506         102 :                                 return inven();
    1507           1 :                         case FEED:
    1508           1 :                                 return GO_UNKNOWN;
    1509           1 :                         case FILL:
    1510           1 :                                 return fill(command.verb, INTRANSITIVE);
    1511           6 :                         case BLAST:
    1512           6 :                                 blast();
    1513           2 :                                 return GO_CLEAROBJ;
    1514           5 :                         case SCORE:
    1515           5 :                                 score(scoregame);
    1516           5 :                                 return GO_CLEAROBJ;
    1517         138 :                         case FEE:
    1518             :                         case FIE:
    1519             :                         case FOE:
    1520             :                         case FOO:
    1521             :                         case FUM:
    1522         138 :                                 return bigwords(command.word[0].id);
    1523           1 :                         case BRIEF:
    1524           1 :                                 return brief();
    1525           3 :                         case READ:
    1526           3 :                                 command.obj = INTRANSITIVE;
    1527           3 :                                 return read(command);
    1528           1 :                         case BREAK:
    1529           1 :                                 return GO_UNKNOWN;
    1530           1 :                         case WAKE:
    1531           1 :                                 return GO_UNKNOWN;
    1532           4 :                         case SAVE:
    1533           4 :                                 return suspend();
    1534           9 :                         case RESUME:
    1535           9 :                                 return resume();
    1536          13 :                         case FLY:
    1537          13 :                                 return fly(command.verb, INTRANSITIVE);
    1538          59 :                         case LISTEN:
    1539          59 :                                 return listen();
    1540          51 :                         case PART:
    1541          51 :                                 return reservoir();
    1542           2 :                         case SEED:
    1543             :                         case WASTE:
    1544           2 :                                 rspeak(NUMERIC_REQUIRED);
    1545           2 :                                 return GO_TOP;
    1546             :                         default: // LCOV_EXCL_LINE
    1547             :                                 BUG(INTRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
    1548             :                         }
    1549             :                 }
    1550             :         /* FALLTHRU */
    1551             :         case transitive:
    1552             :                 /*  Analyse a transitive verb. */
    1553        5291 :                 switch (command.verb) {
    1554        2378 :                 case CARRY:
    1555        2378 :                         return vcarry(command.verb, command.obj);
    1556        1688 :                 case DROP:
    1557        1688 :                         return discard(command.verb, command.obj);
    1558          36 :                 case SAY:
    1559          36 :                         return say(command);
    1560          92 :                 case UNLOCK:
    1561          92 :                         return lock(command.verb, command.obj);
    1562           1 :                 case NOTHING: {
    1563           1 :                         rspeak(OK_MAN);
    1564           1 :                         return (GO_CLEAROBJ);
    1565             :                 }
    1566          11 :                 case LOCK:
    1567          11 :                         return lock(command.verb, command.obj);
    1568          37 :                 case LIGHT:
    1569          37 :                         return light(command.verb, command.obj);
    1570          36 :                 case EXTINGUISH:
    1571          36 :                         return extinguish(command.verb, command.obj);
    1572         123 :                 case WAVE:
    1573         123 :                         return wave(command.verb, command.obj);
    1574           1 :                 case TAME: {
    1575           1 :                         speak(actions[command.verb].message);
    1576           1 :                         return GO_CLEAROBJ;
    1577             :                 }
    1578           1 :                 case GO: {
    1579           1 :                         speak(actions[command.verb].message);
    1580           1 :                         return GO_CLEAROBJ;
    1581             :                 }
    1582         172 :                 case ATTACK:
    1583         172 :                         return attack(command);
    1584         148 :                 case POUR:
    1585         148 :                         return pour(command.verb, command.obj);
    1586           8 :                 case EAT:
    1587           8 :                         return eat(command.verb, command.obj);
    1588          52 :                 case DRINK:
    1589          52 :                         return drink(command.verb, command.obj);
    1590          28 :                 case RUB:
    1591          28 :                         return rub(command.verb, command.obj);
    1592         199 :                 case THROW:
    1593         199 :                         return throwit(command);
    1594           1 :                 case QUIT:
    1595           1 :                         speak(actions[command.verb].message);
    1596           1 :                         return GO_CLEAROBJ;
    1597           7 :                 case FIND:
    1598           7 :                         return find(command.verb, command.obj);
    1599           1 :                 case INVENTORY:
    1600           1 :                         return find(command.verb, command.obj);
    1601          48 :                 case FEED:
    1602          48 :                         return feed(command.verb, command.obj);
    1603          50 :                 case FILL:
    1604          50 :                         return fill(command.verb, command.obj);
    1605           2 :                 case BLAST:
    1606           2 :                         blast();
    1607           1 :                         return GO_CLEAROBJ;
    1608           1 :                 case SCORE:
    1609           1 :                         speak(actions[command.verb].message);
    1610           1 :                         return GO_CLEAROBJ;
    1611           1 :                 case FEE:
    1612             :                 case FIE:
    1613             :                 case FOE:
    1614             :                 case FOO:
    1615             :                 case FUM:
    1616           1 :                         speak(actions[command.verb].message);
    1617           1 :                         return GO_CLEAROBJ;
    1618           1 :                 case BRIEF:
    1619           1 :                         speak(actions[command.verb].message);
    1620           1 :                         return GO_CLEAROBJ;
    1621          12 :                 case READ:
    1622          12 :                         return read(command);
    1623           8 :                 case BREAK:
    1624           8 :                         return vbreak(command.verb, command.obj);
    1625           2 :                 case WAKE:
    1626           2 :                         return wake(command.verb, command.obj);
    1627           1 :                 case SAVE:
    1628           1 :                         speak(actions[command.verb].message);
    1629           1 :                         return GO_CLEAROBJ;
    1630           1 :                 case RESUME:
    1631           1 :                         speak(actions[command.verb].message);
    1632           1 :                         return GO_CLEAROBJ;
    1633          44 :                 case FLY:
    1634          44 :                         return fly(command.verb, command.obj);
    1635           1 :                 case LISTEN:
    1636           1 :                         speak(actions[command.verb].message);
    1637           1 :                         return GO_CLEAROBJ;
    1638             :                 // LCOV_EXCL_START
    1639             :                 // This case should never happen - here only as placeholder
    1640             :                 case PART:
    1641             :                         return reservoir();
    1642             :                 // LCOV_EXCL_STOP
    1643          98 :                 case SEED:
    1644          98 :                         return seed(command.verb, command.word[1].raw);
    1645           1 :                 case WASTE:
    1646           1 :                         return waste(command.verb,
    1647           1 :                                      (turn_t)atol(command.word[1].raw));
    1648             :                 default: // LCOV_EXCL_LINE
    1649             :                         BUG(TRANSITIVE_ACTION_VERB_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE
    1650             :                 }
    1651           4 :         case unknown:
    1652             :                 /* Unknown verb, couldn't deduce object - might need hint */
    1653           4 :                 sspeak(WHAT_DO, command.word[0].raw);
    1654           4 :                 return GO_CHECKHINT;
    1655             :         default: // LCOV_EXCL_LINE
    1656             :                 BUG(SPEECHPART_NOT_TRANSITIVE_OR_INTRANSITIVE_OR_UNKNOWN); // LCOV_EXCL_LINE
    1657             :         }
    1658             : }
    1659             : 
    1660             : // end

Generated by: LCOV version 1.14