Magic-number elimination.
[open-adventure.git] / actions.c
1 #include <stdlib.h>
2 #include <stdbool.h>
3 #include "advent.h"
4 #include "database.h"
5 #include "newdb.h"
6
7 /* Limit visibility of ugly globals.  Eventually these should go away. */
8 extern long WD1, WD1X, WD2, WD2X;
9
10 /*
11  * Action handlers.  Eventually we'll do lookup through a method table
12  * that calls these.
13  */
14
15 static int fill(token_t verb, token_t);
16
17 static int attack(FILE *input, long verb, token_t obj)
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 {
23     int spk = ACTSPK[verb];
24     int d = ATDWRF(game.loc);
25     if (obj == 0) {
26         if (d > 0)
27             obj=DWARF;
28         if (HERE(SNAKE))obj=obj*NOBJECTS+SNAKE;
29         if (AT(DRAGON) && game.prop[DRAGON] == 0)obj=obj*NOBJECTS+DRAGON;
30         if (AT(TROLL))obj=obj*NOBJECTS+TROLL;
31         if (AT(OGRE))obj=obj*NOBJECTS+OGRE;
32         if (HERE(BEAR) && game.prop[BEAR] == 0)obj=obj*NOBJECTS+BEAR;
33         if (obj > NOBJECTS) return GO_UNKNOWN;
34         if (obj == 0) {
35             /* Can't attack bird or machine by throwing axe. */
36             if (HERE(BIRD) && verb != THROW)obj=BIRD;
37             if (HERE(VEND) && verb != THROW)obj=obj*NOBJECTS+VEND;
38             /* Clam and oyster both treated as clam for intransitive case;
39              * no harm done. */
40             if (HERE(CLAM) || HERE(OYSTER))obj=NOBJECTS*obj+CLAM;
41             if (obj > NOBJECTS) return GO_UNKNOWN;
42         }
43     }
44     if (obj == BIRD) {
45         spk=UNHAPPY_BIRD;
46         if (game.closed)
47         {
48             RSPEAK(spk);
49             return GO_CLEAROBJ;
50         }
51         DSTROY(BIRD);
52         game.prop[BIRD]=0;
53         spk=BIRD_DEAD;
54     }
55     if (obj == VEND) {
56         PSPEAK(VEND,game.prop[VEND]+2);
57         game.prop[VEND]=3-game.prop[VEND];
58         return GO_CLEAROBJ;
59     }
60
61     if (obj == 0)spk=NO_TARGET;
62     if (obj == CLAM || obj == OYSTER)spk=SHELL_IMPERVIOUS;
63     if (obj == SNAKE)spk=SNAKE_WARNING;
64     if (obj == DWARF)spk=BARE_HANDS_QUERY;
65     if (obj == DWARF && game.closed) return GO_DWARFWAKE;
66     if (obj == DRAGON)spk=ALREADY_DEAD;
67     if (obj == TROLL)spk=ROCKY_TROLL;
68     if (obj == OGRE)spk=OGRE_DODGE;
69     if (obj == OGRE && d > 0) {
70         RSPEAK(spk);
71         RSPEAK(KNIFE_THROWN);
72         DSTROY(OGRE);
73         int dwarves=0;
74         for (int i=1; i < PIRATE; i++) {
75             if (game.dloc[i] == game.loc) {
76                 ++dwarves;
77                 game.dloc[i] = LOC_LONGWEST;
78                 game.dseen[i]=false;
79             }
80         }
81         spk=spk+1+1/dwarves;    /* FIXME: Arithmetic on message numbers */
82     }
83     else if (obj == BEAR)
84         /* FIXME: Arithmetic on message numbers */
85         spk = BEAR_HANDS+(game.prop[BEAR]+1)/2;
86     else if (obj == DRAGON && game.prop[DRAGON] == 0) {
87         /*  Fun stuff for dragon.  If he insists on attacking it, win!
88          *  Set game.prop to dead, move dragon to central loc (still
89          *  fixed), move rug there (not fixed), and move him there,
90          *  too.  Then do a null motion to get new description. */
91         RSPEAK(BARE_HANDS_QUERY);
92         GETIN(input,&WD1,&WD1X,&WD2,&WD2X);
93         if (WD1 != MAKEWD(25) && WD1 != MAKEWD(250519))
94             return GO_CHECKFOO;
95         PSPEAK(DRAGON,3);
96         game.prop[DRAGON]=1;
97         game.prop[RUG]=0;
98         int k=(PLAC[DRAGON]+FIXD[DRAGON])/2;
99         MOVE(DRAGON+NOBJECTS,-1);
100         MOVE(RUG+NOBJECTS,0);
101         MOVE(DRAGON,k);
102         MOVE(RUG,k);
103         DROP(BLOOD,k);
104         for (obj=1; obj<=NOBJECTS; obj++) {
105             if (game.place[obj] == PLAC[DRAGON] || game.place[obj] == FIXD[DRAGON])
106                 MOVE(obj,k);
107         }
108         game.loc=k;
109         return GO_MOVE;
110     }
111
112     RSPEAK(spk);
113     return GO_CLEAROBJ;
114 }
115
116 static int bigwords(long foo)
117 /*  FEE FIE FOE FOO (AND FUM).  Advance to next state if given in proper order.
118  *  Look up WD1 in section 3 of vocab to determine which word we've got.  Last
119  *  word zips the eggs back to the giant room (unless already there). */
120 {
121     int k=VOCAB(foo,3);
122     int spk=NOTHING_HAPPENS;
123     if (game.foobar != 1-k) {
124         if (game.foobar != 0)spk=START_OVER;
125         RSPEAK(spk);
126         return GO_CLEAROBJ;
127     } else {
128         game.foobar=k;
129         if (k != 4) {
130             RSPEAK(OK_MAN);
131             return GO_CLEAROBJ;
132         }
133         game.foobar=0;
134         if (game.place[EGGS]==PLAC[EGGS] || (TOTING(EGGS) && game.loc==PLAC[EGGS])) {
135             RSPEAK(spk);
136             return GO_CLEAROBJ;
137         } else {
138             /*  Bring back troll if we steal the eggs back from him before
139              *  crossing. */
140             if (game.place[EGGS]==0 && game.place[TROLL]==0 && game.prop[TROLL]==0)
141                 game.prop[TROLL]=1;
142             k=2;
143             if (HERE(EGGS))k=1;
144             if (game.loc == PLAC[EGGS])k=0;
145             MOVE(EGGS,PLAC[EGGS]);
146             PSPEAK(EGGS,k);
147             return GO_CLEAROBJ;
148         }
149     }
150 }
151
152 static int bivalve(token_t verb, token_t obj)
153 /* Clam/oyster actions */
154 {
155     int spk;
156     bool is_oyster = (obj == OYSTER);
157     spk= is_oyster ? OYSTER_OPENS : PEARL_FALLS;
158     if (TOTING(obj))spk= is_oyster ? DROP_OYSTER : DROP_CLAM;
159     if (!TOTING(TRIDNT))spk= is_oyster ? OYSTER_OPENER : CLAM_OPENER;
160     if (verb == LOCK)spk=HUH_MAN;
161     if (spk == PEARL_FALLS) {
162         DSTROY(CLAM);
163         DROP(OYSTER,game.loc);
164         DROP(PEARL,LOC_CULDESAC);
165     }
166     RSPEAK(spk);
167     return GO_CLEAROBJ;
168 }
169
170 static int blast(void)
171 /*  Blast.  No effect unless you've got dynamite, which is a neat trick! */
172 {
173     if (game.prop[ROD2] < 0 || !game.closed)
174     {
175         RSPEAK(REQUIRES_DYNAMITE);
176         return GO_CLEAROBJ;
177     }
178     game.bonus=133;
179     if (game.loc == LOC_NE)
180         game.bonus=134;
181     if (HERE(ROD2))
182         game.bonus=135;
183     RSPEAK(game.bonus);
184     score(endgame);
185     return GO_CLEAROBJ; /* pacify compiler - we never get here */
186 }
187
188 static int vbreak(token_t verb, token_t obj)
189 /*  Break.  Only works for mirror in repository and, of course, the vase. */
190 {
191     int spk = ACTSPK[verb];
192     if (obj == MIRROR)spk=TOO_FAR;
193     if (obj == VASE && game.prop[VASE] == 0) {
194         if (TOTING(VASE))DROP(VASE,game.loc);
195         game.prop[VASE]=2;
196         game.fixed[VASE]= -1;
197         spk=BREAK_VASE;
198     } else {
199         if (obj == MIRROR && game.closed) {
200             RSPEAK(BREAK_MIRROR);
201             return GO_DWARFWAKE;
202         }
203     }
204     RSPEAK(spk);
205     return GO_CLEAROBJ;
206 }
207
208 static int brief(void)
209 /*  Brief.  Intransitive only.  Suppress long descriptions after first time. */
210 {
211     game.abbnum=10000;
212     game.detail=3;
213     RSPEAK(BRIEF_CONFIRM);
214     return GO_CLEAROBJ;
215 }
216
217 static int carry(token_t verb, token_t obj)
218 /*  Carry an object.  Special cases for bird and cage (if bird in cage, can't
219  *  take one without the other).  Liquids also special, since they depend on
220  *  status of bottle.  Also various side effects, etc. */
221 {
222     int spk;
223     if (obj == INTRANSITIVE) {
224         /*  Carry, no object given yet.  OK if only one object present. */
225         if(game.atloc[game.loc] == 0 ||
226            game.link[game.atloc[game.loc]] != 0 ||
227            ATDWRF(game.loc) > 0)
228             return GO_UNKNOWN;
229         obj=game.atloc[game.loc];
230     }
231
232     if (TOTING(obj)) {RSPEAK(ALREADY_CARRYING); return GO_CLEAROBJ;}
233     spk=YOU_JOKING;
234     if (obj == PLANT && game.prop[PLANT] <= 0)spk=DEEP_ROOTS;
235     if (obj == BEAR && game.prop[BEAR] == 1)spk=BEAR_CHAINED;
236     if (obj == CHAIN && game.prop[BEAR] != 0)spk=STILL_LOCKED;
237     if (obj == URN)spk=URN_NOBUDGE;
238     if (obj == CAVITY)spk=DOUGHNUT_HOLES;
239     if (obj == BLOOD)spk=FEW_DROPS;
240     if (obj == RUG && game.prop[RUG] == 2)spk=RUG_HOVERS;
241     if (obj == SIGN)spk=HAND_PASSTHROUGH;
242     if (obj == MESSAG) {
243         RSPEAK(REMOVE_MESSAGE);
244         DSTROY(MESSAG);
245         return GO_CLEAROBJ;
246     }
247     if (game.fixed[obj] != 0) {
248         RSPEAK(spk);
249         return GO_CLEAROBJ;
250     }
251     if (obj == WATER || obj == OIL) {
252         if (!HERE(BOTTLE) || LIQUID() != obj) {
253             if (TOTING(BOTTLE) && game.prop[BOTTLE] == 1)
254                 return(fill(verb, BOTTLE));
255             if (game.prop[BOTTLE] != 1)spk=BOTTLE_FULL;
256             if (!TOTING(BOTTLE))spk=NO_CONTAINER;
257             RSPEAK(spk);
258             return GO_CLEAROBJ;
259         }
260         obj = BOTTLE;
261     }
262
263     spk=CARRY_LIMIT;
264     if (game.holdng >= INVLIMIT) {
265         RSPEAK(spk);
266         return GO_CLEAROBJ;
267     }
268     else if (obj == BIRD && game.prop[BIRD] != 1 && -1-game.prop[BIRD] != 1) {
269         if (game.prop[BIRD] == 2) {
270             DSTROY(BIRD);
271             RSPEAK(BIRD_CRAP);
272             return GO_CLEAROBJ;
273         }
274         if (!TOTING(CAGE))spk=CANNOT_CARRY;
275         if (TOTING(ROD))spk=BIRD_EVADES;
276         if (spk == CANNOT_CARRY || spk == BIRD_EVADES) {
277             RSPEAK(spk);
278             return GO_CLEAROBJ;
279         }
280         game.prop[BIRD]=1;
281     }
282     if ((obj==BIRD || obj==CAGE) && (game.prop[BIRD]==1 || -1-game.prop[BIRD]==1))
283         CARRY(BIRD+CAGE-obj,game.loc);
284     CARRY(obj,game.loc);
285     if (obj == BOTTLE && LIQUID() != 0)
286         game.place[LIQUID()] = CARRIED;
287     if (GSTONE(obj) && game.prop[obj] != 0) {
288         game.prop[obj]=0;
289         game.prop[CAVITY]=1;
290     }
291     RSPEAK(OK_MAN);
292     return GO_CLEAROBJ;
293 }
294
295 static int chain(token_t verb)
296 /* Do something to the bear's chain */
297 {
298     int spk;
299     if (verb != LOCK) {
300         spk=CHAIN_UNLOCKED;
301         if (game.prop[BEAR] == 0)spk=BEAR_BLOCKS;
302         if (game.prop[CHAIN] == 0)spk=ALREADY_UNLOCKED;
303         if (spk != CHAIN_UNLOCKED) {RSPEAK(spk); return GO_CLEAROBJ;}
304         game.prop[CHAIN]=0;
305         game.fixed[CHAIN]=0;
306         if (game.prop[BEAR] != 3)game.prop[BEAR]=2;
307         game.fixed[BEAR]=2-game.prop[BEAR];
308     } else {
309         spk=CHAIN_LOCKED;
310         if (game.prop[CHAIN] != 0)spk=ALREADY_LOCKED;
311         if (game.loc != PLAC[CHAIN])spk=NO_LOCKSITE;
312         if (spk != CHAIN_LOCKED) {
313             RSPEAK(spk);
314             return GO_CLEAROBJ;
315         }
316         game.prop[CHAIN]=2;
317         if (TOTING(CHAIN))DROP(CHAIN,game.loc);
318         game.fixed[CHAIN]= -1;
319     }
320     RSPEAK(spk);
321     return GO_CLEAROBJ;
322 }
323
324 static int discard(token_t verb, token_t obj, bool just_do_it)
325 /*  Discard object.  "Throw" also comes here for most objects.  Special cases for
326  *  bird (might attack snake or dragon) and cage (might contain bird) and vase.
327  *  Drop coins at vending machine for extra batteries. */
328 {
329     int spk = ACTSPK[verb];
330     if (!just_do_it) {
331         if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj=ROD2;
332         if (!TOTING(obj)) {RSPEAK(spk); return GO_CLEAROBJ;}
333         if (obj == BIRD && HERE(SNAKE)) {
334             RSPEAK(BIRD_ATTACKS);
335             if (game.closed) return GO_DWARFWAKE;
336             DSTROY(SNAKE);
337             /* Set game.prop for use by travel options */
338             game.prop[SNAKE]=1;
339
340         } else if ((GSTONE(obj) && AT(CAVITY) && game.prop[CAVITY] != 0)) {
341             RSPEAK(GEM_FITS);
342             game.prop[obj]=1;
343             game.prop[CAVITY]=0;
344             if (HERE(RUG) && ((obj == EMRALD && game.prop[RUG] != 2) || (obj == RUBY &&
345                                                                          game.prop[RUG] == 2))) {
346                 spk=RUG_RISES;
347                 if (TOTING(RUG))spk=RUG_WIGGLES;
348                 if (obj == RUBY)spk=RUG_SETTLES;
349                 RSPEAK(spk);
350                 if (spk != RUG_WIGGLES) {
351                     int k = 2-game.prop[RUG];
352                     game.prop[RUG] = k;
353                     if (k == 2) k = PLAC[SAPPH];
354                     MOVE(RUG+NOBJECTS, k);
355                 }
356             }
357         } else if (obj == COINS && HERE(VEND)) {
358             DSTROY(COINS);
359             DROP(BATTER,game.loc);
360             PSPEAK(BATTER,0);
361             return GO_CLEAROBJ;
362         } else if (obj == BIRD && AT(DRAGON) && game.prop[DRAGON] == 0) {
363             RSPEAK(BIRD_BURNT);
364             DSTROY(BIRD);
365             game.prop[BIRD]=0;
366             return GO_CLEAROBJ;
367         } else if (obj == BEAR && AT(TROLL)) {
368             RSPEAK(TROLL_SCAMPERS);
369             MOVE(TROLL,0);
370             MOVE(TROLL+NOBJECTS,0);
371             MOVE(TROLL2,PLAC[TROLL]);
372             MOVE(TROLL2+NOBJECTS,FIXD[TROLL]);
373             JUGGLE(CHASM);
374             game.prop[TROLL]=2;
375         } else if (obj != VASE || game.loc == PLAC[PILLOW]) {
376             RSPEAK(OK_MAN);
377         } else {
378             game.prop[VASE]=2;
379             if (AT(PILLOW))game.prop[VASE]=0;
380             PSPEAK(VASE,game.prop[VASE]+1);
381             if (game.prop[VASE] != 0)game.fixed[VASE]= -1;
382         }
383     }
384     int k = LIQUID();
385     if (k == obj)obj=BOTTLE;
386     if (obj == BOTTLE && k != 0)
387         game.place[k] = NOWHERE;
388     if (obj == CAGE && game.prop[BIRD] == 1)DROP(BIRD,game.loc);
389     DROP(obj,game.loc);
390     if (obj != BIRD) return GO_CLEAROBJ;
391     game.prop[BIRD]=0;
392     if (FOREST(game.loc))game.prop[BIRD]=2;
393     return GO_CLEAROBJ;
394 }
395
396 static int drink(token_t verb, token_t obj)
397 /*  Drink.  If no object, assume water and look for it here.  If water is in
398  *  the bottle, drink that, else must be at a water loc, so drink stream. */
399 {
400     int spk = ACTSPK[verb];
401     if (obj == 0 && LIQLOC(game.loc) != WATER && (LIQUID() != WATER || !HERE(BOTTLE)))
402         return GO_UNKNOWN;
403     if (obj != BLOOD) {
404         if (obj != 0 && obj != WATER)spk=RIDICULOUS_ATTEMPT;
405         if (spk != RIDICULOUS_ATTEMPT && LIQUID() == WATER && HERE(BOTTLE)) {
406             game.prop[BOTTLE] = 1;
407             game.place[WATER] = NOWHERE;
408             spk=BOTTLE_EMPTY;
409         }
410     } else {
411         DSTROY(BLOOD);
412         game.prop[DRAGON]=2;
413         OBJSND[BIRD]=OBJSND[BIRD]+3;
414         spk=HEAD_BUZZES;
415     }
416     RSPEAK(spk);
417     return GO_CLEAROBJ;
418 }
419
420 static int eat(token_t verb, token_t obj)
421 /*  Eat.  Intransitive: assume food if present, else ask what.  Transitive: food
422  *  ok, some things lose appetite, rest are ridiculous. */
423 {
424     int spk = ACTSPK[verb];
425     if (obj == INTRANSITIVE) {
426         if (!HERE(FOOD))
427             return GO_UNKNOWN;
428         DSTROY(FOOD);
429         spk=THANKS_DELICIOUS;
430     } else {
431         if (obj == FOOD) {
432             DSTROY(FOOD);
433             spk=THANKS_DELICIOUS;
434         }
435         if (obj == BIRD || obj == SNAKE || obj == CLAM || obj == OYSTER || obj ==
436            DWARF || obj == DRAGON || obj == TROLL || obj == BEAR || obj ==
437            OGRE)spk=LOST_APPETITE;
438     }
439     RSPEAK(spk);
440     return GO_CLEAROBJ;
441 }
442
443 static int extinguish(token_t verb, int obj)
444 /* Extinguish.  Lamp, urn, dragon/volcano (nice try). */
445 {
446     int spk = ACTSPK[verb];
447     if (obj == INTRANSITIVE) {
448         if (HERE(LAMP) && game.prop[LAMP] == 1)obj=LAMP;
449         if (HERE(URN) && game.prop[URN] == 2)obj=obj*NOBJECTS+URN;
450         if (obj == INTRANSITIVE || obj == 0 || obj > NOBJECTS) return GO_UNKNOWN;
451     }
452
453     if (obj == URN) {
454         game.prop[URN]=game.prop[URN]/2;
455         spk=URN_DARK;
456     }
457     else if (obj == LAMP) {
458         game.prop[LAMP]=0;
459         RSPEAK(LAMP_OFF);
460         spk = DARK(game.loc) ? PITCH_DARK : ARB_0;
461     }
462     else if (obj == DRAGON || obj == VOLCAN)
463         spk=BEYOND_POWER;
464     RSPEAK(spk);
465     return GO_CLEAROBJ;
466 }
467
468 static int feed(token_t verb, token_t obj)
469 /*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf, make him
470  *  mad.  Bear, special. */
471 {
472     int spk = ACTSPK[verb];
473     if (obj == BIRD) {
474         RSPEAK(BIRD_PINING);
475         return GO_CLEAROBJ;
476     }
477     else if (obj == SNAKE || obj == DRAGON || obj == TROLL) {
478         spk=NOTHING_EDIBLE;
479         if (obj == DRAGON && game.prop[DRAGON] != 0)spk=RIDICULOUS_ATTEMPT;
480         if (obj == TROLL)spk=TROLL_VICES;
481         if (obj == SNAKE && !game.closed && HERE(BIRD)) {
482             DSTROY(BIRD);
483             game.prop[BIRD]=0;
484             spk = BIRD_DEVOURED;
485         }
486     }
487     else if (obj == DWARF) {
488         if (HERE(FOOD)) {
489             game.dflag += 2;
490             spk = REALLY_MAD;
491         }
492     }
493     else if (obj == BEAR) {
494         if (game.prop[BEAR] == 0)spk=NOTHING_EDIBLE;
495         if (game.prop[BEAR] == 3)spk=RIDICULOUS_ATTEMPT;
496         if (HERE(FOOD)) {
497             DSTROY(FOOD);
498             game.prop[BEAR]=1;
499             game.fixed[AXE]=0;
500             game.prop[AXE]=0;
501             spk=BEAR_TAMED;
502         }
503     }
504     else if (obj == OGRE) {
505         if (HERE(FOOD))
506             spk=OGRE_FULL;
507     } else {
508         spk=AM_GAME;
509     }
510     RSPEAK(spk);
511     return GO_CLEAROBJ;
512 }
513
514 int fill(token_t verb, token_t obj)
515 /*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
516  *  is nasty.) */
517 {
518     int k;
519     int spk = ACTSPK[verb];
520     if (obj == VASE) {
521         spk=ARENT_CARRYING;
522         if (LIQLOC(game.loc) == 0)spk=FILL_INVALID;
523         if (LIQLOC(game.loc) == 0 || !TOTING(VASE)) {
524             RSPEAK(spk);
525             return GO_CLEAROBJ;
526         }
527         RSPEAK(SHATTER_VASE);
528         game.prop[VASE] = 2;
529         game.fixed[VASE]= -1;
530         return(discard(verb, obj, true));
531     }
532     else if (obj == URN) {
533         spk=FULL_URN;
534         if (game.prop[URN] != 0) {RSPEAK(spk); return GO_CLEAROBJ;}
535         spk=FILL_INVALID;
536         k=LIQUID();
537         if (k == 0 || !HERE(BOTTLE)) {RSPEAK(spk); return GO_CLEAROBJ;}
538         game.place[k] = NOWHERE;
539         game.prop[BOTTLE] = 1;
540         if (k == OIL)game.prop[URN]=1;
541         spk=WATER_URN+game.prop[URN];
542         RSPEAK(spk);
543         return GO_CLEAROBJ;
544     }
545     else if (obj != 0 && obj != BOTTLE) {
546         RSPEAK(spk);
547         return GO_CLEAROBJ;
548     }
549     else if (obj == 0 && !HERE(BOTTLE))
550         return GO_UNKNOWN;
551     spk=BOTTLED_WATER;
552     if (LIQLOC(game.loc) == 0)
553         spk=NO_LIQUID;
554     if (HERE(URN) && game.prop[URN] != 0)
555         spk=URN_NOPOUR;
556     if (LIQUID() != 0)
557         spk=BOTTLE_FULL;
558     if (spk == 107) {
559         game.prop[BOTTLE]=MOD(COND[game.loc],4)/2*2;
560         k=LIQUID();
561         if (TOTING(BOTTLE))
562             game.place[k] = CARRIED;
563         if (k == OIL)
564             spk=BOTTLED_OIL;
565     }
566     RSPEAK(spk);
567     return GO_CLEAROBJ;
568 }
569
570 static int find(token_t verb, token_t obj)
571 /* Find.  Might be carrying it, or it might be here.  Else give caveat. */
572 {
573     int spk = ACTSPK[verb];
574     if (AT(obj) ||
575        (LIQUID() == obj && AT(BOTTLE)) ||
576        obj == LIQLOC(game.loc) ||
577        (obj == DWARF && ATDWRF(game.loc) > 0))
578         spk=YOU_HAVEIT;
579     if (game.closed)spk=NEEDED_NEreplace;
580     if (TOTING(obj))spk=ALREADY_CARRYING;
581     RSPEAK(spk);
582     return GO_CLEAROBJ;
583 }
584
585 static int fly(token_t verb, token_t obj)
586 /* Fly.  Snide remarks unless hovering rug is here. */
587 {
588     int spk = ACTSPK[verb];
589     if (obj == INTRANSITIVE) {
590         if (game.prop[RUG] != 2)spk=RUG_NOTHING2;
591         if (!HERE(RUG))spk=FLAP_ARMS;
592         if (spk == RUG_NOTHING2 || spk == FLAP_ARMS) {
593             RSPEAK(spk);
594             return GO_CLEAROBJ;
595         }
596         obj=RUG;
597     }
598
599     if (obj != RUG) {
600         RSPEAK(spk);
601         return GO_CLEAROBJ;
602     }
603     spk=RUG_NOTHING1;
604     if (game.prop[RUG] != 2) {RSPEAK(spk); return GO_CLEAROBJ;}
605     game.oldlc2=game.oldloc;
606     game.oldloc=game.loc;
607     game.newloc=game.place[RUG]+game.fixed[RUG]-game.loc;
608     spk=RUG_GOES;
609     if (game.prop[SAPPH] >= 0)
610         spk=RUG_RETURNS;
611     RSPEAK(spk);
612     return GO_TERMINATE;
613 }
614
615 static int inven(void)
616 /* Inventory. If object, treat same as find.  Else report on current burden. */
617 {
618     int spk=NO_CARRY;
619     for (int i=1; i<=NOBJECTS; i++) {
620         if (i == BEAR || !TOTING(i))
621             continue;
622         if (spk == NO_CARRY)
623             RSPEAK(NOW_HOLDING);
624         game.blklin=false;
625         PSPEAK(i,-1);
626         game.blklin=true;
627         spk=ARB_0;
628     }
629     if (TOTING(BEAR))
630         spk=TAME_BEAR;
631     RSPEAK(spk);
632     return GO_CLEAROBJ;
633 }
634
635 int light(token_t verb, token_t obj)
636 /*  Light.  Applicable only to lamp and urn. */
637 {
638     int spk = ACTSPK[verb];
639     if (obj == INTRANSITIVE) {
640         if (HERE(LAMP) && game.prop[LAMP] == 0 && game.limit >= 0)obj=LAMP;
641         if (HERE(URN) && game.prop[URN] == 1)obj=obj*NOBJECTS+URN;
642         if (obj == INTRANSITIVE || obj == 0 || obj > NOBJECTS) return GO_UNKNOWN;
643     }
644
645     if (obj == URN) {
646         spk=URN_EMPTY;
647         if (game.prop[URN] == 0)
648             {RSPEAK(spk); return GO_CLEAROBJ;}
649         spk=URN_LIT;
650         game.prop[URN]=2;
651         RSPEAK(spk);
652         return GO_CLEAROBJ;
653     } else {
654         if (obj != LAMP)
655         {
656             RSPEAK(spk);
657             return GO_CLEAROBJ;
658         }
659         spk=LAMP_OUT;
660         if (game.limit < 0) {
661             RSPEAK(spk);
662             return GO_CLEAROBJ;
663         }
664         game.prop[LAMP]=1;
665         RSPEAK(LAMP_ON);
666         if (game.wzdark)
667             return GO_TOP;
668         else
669             return GO_CLEAROBJ;
670     }
671 }
672
673 static int listen(void)
674 /*  Listen.  Intransitive only.  Print stuff based on objsnd/locsnd. */
675 {
676     int k;
677     int spk=ALL_SILENT;
678     k=LOCSND[game.loc];
679     if (k != 0) {
680         RSPEAK(labs(k));
681         if (k < 0) return GO_CLEAROBJ;
682         spk=ARB_0;
683     }
684     SETPRM(1,game.zzword,0);
685     for (int i=1; i<=NOBJECTS; i++) {
686         if (!HERE(i) || OBJSND[i] == 0 || game.prop[i] < 0)
687             continue;
688         PSPEAK(i,OBJSND[i]+game.prop[i]);
689         spk=ARB_0;
690         if (i == BIRD && OBJSND[i]+game.prop[i] == 8)
691             DSTROY(BIRD);
692     }
693     RSPEAK(spk);
694     return GO_CLEAROBJ;
695 }
696
697 static int lock(token_t verb, token_t obj)
698 /* Lock, unlock, no object given.  Assume various things if present. */
699 {
700     int spk = ACTSPK[verb];
701     if (obj == INTRANSITIVE) {
702         spk=NOTHING_LOCKED;
703         if (HERE(CLAM))obj=CLAM;
704         if (HERE(OYSTER))obj=OYSTER;
705         if (AT(DOOR))obj=DOOR;
706         if (AT(GRATE))obj=GRATE;
707         if (obj != 0 && HERE(CHAIN)) return GO_UNKNOWN;
708         if (HERE(CHAIN))obj=CHAIN;
709         if (obj == 0) {RSPEAK(spk); return GO_CLEAROBJ;}
710     }
711         
712     /*  Lock, unlock object.  Special stuff for opening clam/oyster
713      *  and for chain. */
714     if (obj == CLAM || obj == OYSTER)
715         return bivalve(verb, obj);
716     if (obj == DOOR)spk=RUSTY_DOOR;
717     if (obj == DOOR && game.prop[DOOR] == 1)spk=OK_MAN;
718     if (obj == CAGE)spk=NO_LOCK;
719     if (obj == KEYS)spk=CANNOT_UNLOCK;
720     if (obj == GRATE || obj == CHAIN) {
721         spk=NO_KEYS;
722         if (HERE(KEYS)) {
723             if (obj == CHAIN)
724                 return chain(verb);
725             if (game.closng) {
726                 spk=EXIT_CLOSED;
727                 if (!game.panic)game.clock2=15;
728                 game.panic=true;
729             } else {
730                 spk=game.prop[GRATE] ? GRATE_LOCKED : ALREADY_LOCKED;
731                 game.prop[GRATE]=1;
732                 if (verb == LOCK)game.prop[GRATE]=0;
733                 spk=game.prop[GRATE] ? GRATE_UNLOCKED : GRATE_LOCKED;
734             }
735         }
736     }
737     RSPEAK(spk);
738     return GO_CLEAROBJ;
739 }
740
741 static int pour(token_t verb, token_t obj)
742 /*  Pour.  If no object, or object is bottle, assume contents of bottle.
743  *  special tests for pouring water or oil on plant or rusty door. */
744 {
745     int spk = ACTSPK[verb];
746     if (obj == BOTTLE || obj == 0)obj=LIQUID();
747     if (obj == 0) return GO_UNKNOWN;
748     if (!TOTING(obj)) {RSPEAK(spk); return GO_CLEAROBJ;}
749     spk=CANT_POUR;
750     if (obj != OIL && obj != WATER) {RSPEAK(spk); return GO_CLEAROBJ;}
751     if (HERE(URN) && game.prop[URN] == 0)
752         return fill(verb, URN);
753     game.prop[BOTTLE] = 1;
754     game.place[obj] = NOWHERE;
755     spk=GROUND_WET;
756     if (!(AT(PLANT) || AT(DOOR)))
757         {RSPEAK(spk); return GO_CLEAROBJ;}
758     if (!AT(DOOR)) {
759         spk=SHAKING_LEAVES;
760         if (obj != WATER) {RSPEAK(spk); return GO_CLEAROBJ;}
761         PSPEAK(PLANT,game.prop[PLANT]+3);
762         game.prop[PLANT]=MOD(game.prop[PLANT]+1,3);
763         game.prop[PLANT2]=game.prop[PLANT];
764         return GO_MOVE;
765     } else {
766         game.prop[DOOR]=0;
767         if (obj == OIL)game.prop[DOOR]=1;
768         spk=RUSTED_HINGES+game.prop[DOOR];
769         RSPEAK(spk);
770         return GO_CLEAROBJ;
771     }
772 }
773
774 static int quit(FILE *input)
775 /*  Quit.  Intransitive only.  Verify intent and exit if that's what he wants. */
776 {
777     if (YES(input,REALLY_QUIT,OK_MAN,OK_MAN))
778         score(quitgame);
779     return GO_CLEAROBJ;
780 }
781
782 static int read(FILE *input, token_t verb, token_t obj)
783 /*  Read.  Print stuff based on objtxt.  Oyster (?) is special case. */
784 {
785     int spk = ACTSPK[verb];
786     if (obj == INTRANSITIVE) {
787         obj = 0;
788         for (int i=1; i<=NOBJECTS; i++) {
789             if (HERE(i) && OBJTXT[i] != 0 && game.prop[i] >= 0)
790                 obj = obj * NOBJECTS + i;
791         }
792         if (obj > NOBJECTS || obj == 0 || DARK(game.loc)) return GO_UNKNOWN;
793     }
794         
795     if (DARK(game.loc)) {
796         SETPRM(1,WD1,WD1X);
797         RSPEAK(NO_SEE);
798         return GO_CLEAROBJ;
799     }
800     if (OBJTXT[obj] == 0 || game.prop[obj] < 0) {
801         RSPEAK(spk);
802         return GO_CLEAROBJ;
803     }
804     if (obj == OYSTER && !game.clshnt) {
805         game.clshnt=YES(input,CLUE_QUERY,WAYOUT_CLUE,OK_MAN);
806         return GO_CLEAROBJ;
807     }
808     PSPEAK(obj,OBJTXT[obj]+game.prop[obj]);
809     return GO_CLEAROBJ;
810 }
811
812 static int reservoir(void)
813 /*  Z'ZZZ (word gets recomputed at startup; different each game). */
814 {
815     if (!AT(RESER) && game.loc != game.fixed[RESER]-1) {
816         RSPEAK(RUB_NOGO);
817         return GO_CLEAROBJ;
818     } else {
819         PSPEAK(RESER,game.prop[RESER]+1);
820         game.prop[RESER]=1-game.prop[RESER];
821         if (AT(RESER))
822             return GO_CLEAROBJ;
823         else {
824             game.oldlc2=game.loc;
825             game.newloc=0;
826             RSPEAK(NOT_BRIGHT);
827             return GO_TERMINATE;
828         }
829     }
830 }
831
832 static int rub(token_t verb, token_t obj)
833 /* Rub.  Yields various snide remarks except for lit urn. */
834 {
835     int spk = ACTSPK[verb];
836     if (obj != LAMP)
837         spk=PECULIAR_NOTHING;
838     if (obj == URN && game.prop[URN] == 2) {
839         DSTROY(URN);
840         DROP(AMBER,game.loc);
841         game.prop[AMBER]=1;
842         --game.tally;
843         DROP(CAVITY,game.loc);
844         spk=URN_GENIES;
845     }
846     RSPEAK(spk);
847     return GO_CLEAROBJ;
848 }
849
850 static int say(void)
851 /* Say.  Echo WD2 (or WD1 if no WD2 (SAY WHAT?, etc.).)  Magic words override. */
852 {
853     /* FIXME: ugly use of globals */
854     SETPRM(1,WD2,WD2X);
855     if (WD2 <= 0)
856         SETPRM(1,WD1,WD1X);
857     if (WD2 > 0)
858         WD1=WD2;
859     int wd=VOCAB(WD1,-1);
860     /* FIXME: Magic numbers */
861     if (wd == 62 || wd == 65 || wd == 71 || wd == 2025 || wd == 2034) {
862         WD2=0;
863         return GO_LOOKUP;
864     }
865     RSPEAK(OKEY_DOKEY);
866     return GO_CLEAROBJ;
867
868 }
869
870 static int throw_support(long spk)
871 {
872     RSPEAK(spk);
873     DROP(AXE,game.loc);
874     return GO_MOVE;
875 }
876
877 static int throw(FILE *cmdin, long verb, token_t obj)
878 /*  Throw.  Same as discard unless axe.  Then same as attack except
879  *  ignore bird, and if dwarf is present then one might be killed.
880  *  (Only way to do so!)  Axe also special for dragon, bear, and
881  *  troll.  Treasures special for troll. */
882 {
883     int spk = ACTSPK[verb];
884     if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj=ROD2;
885     if (!TOTING(obj)) {
886         RSPEAK(spk);
887         return GO_CLEAROBJ;
888     }
889     if (obj >= MINTRS && obj <= MAXTRS && AT(TROLL)) {
890         spk=TROLL_SATISFIED;
891         /*  Snarf a treasure for the troll. */
892         DROP(obj,0);
893         MOVE(TROLL,0);
894         MOVE(TROLL+NOBJECTS,0);
895         DROP(TROLL2,PLAC[TROLL]);
896         DROP(TROLL2+NOBJECTS,FIXD[TROLL]);
897         JUGGLE(CHASM);
898         RSPEAK(spk);
899         return GO_CLEAROBJ;
900     }
901     if (obj == FOOD && HERE(BEAR)) {
902     /* But throwing food is another story. */
903         obj=BEAR;
904         return(feed(verb, obj));
905     }
906     if (obj != AXE)
907         return(discard(verb, obj, false));
908     int i=ATDWRF(game.loc);
909     if (i <= 0) {
910         if (AT(DRAGON) && game.prop[DRAGON] == 0) {
911             spk=DRAGON_SCALES;
912             return throw_support(spk);
913         }
914         if (AT(TROLL)) {
915             spk=TROLL_RETURNS;
916             return throw_support(spk);
917         }
918         if (AT(OGRE)) {
919             spk=OGRE_DODGE;
920             return throw_support(spk);
921         }
922         if (HERE(BEAR) && game.prop[BEAR] == 0) {
923             /* This'll teach him to throw the axe at the bear! */
924             spk=AXE_LOST;
925             DROP(AXE,game.loc);
926             game.fixed[AXE]= -1;
927             game.prop[AXE]=1;
928             JUGGLE(BEAR);
929             {RSPEAK(spk); return GO_CLEAROBJ;}
930         }
931         return(attack(cmdin, verb, 0));
932     }
933
934     if (randrange(NDWARVES+1) < game.dflag) {
935         spk=DWARF_DODGES;
936         return throw_support(spk);
937     }
938     game.dseen[i]=false;
939     game.dloc[i]=0;
940     spk=KILLED_DWARF;
941     ++game.dkill;
942     if (game.dkill == 1)spk=DWARF_SMOKE;
943
944     return throw_support(spk);
945 }
946
947 static int vscore(void)
948 /* Score.  Call scoring routine but tell it to return. */
949 {
950     score(scoregame);
951     return GO_CLEAROBJ;
952 }
953
954 static int wake(token_t verb, token_t obj)
955 /* Wake.  Only use is to disturb the dwarves. */
956 {
957     if (obj != DWARF || !game.closed)
958     {
959         RSPEAK(ACTSPK[verb]);
960         return GO_CLEAROBJ;
961     }
962     RSPEAK(PROD_DWARF);
963     return GO_DWARFWAKE;
964 }
965
966 static int wave(token_t verb, token_t obj)
967 /* Wave.  No effect unless waving rod at fissure or at bird. */
968 {
969     int spk = ACTSPK[verb];
970     if ((!TOTING(obj)) && (obj != ROD || !TOTING(ROD2)))spk=ARENT_CARRYING;
971     if (obj != ROD ||
972        !TOTING(obj) ||
973        (!HERE(BIRD) && (game.closng || !AT(FISSUR)))) {
974         RSPEAK(spk);
975         return GO_CLEAROBJ;
976     }
977     if (HERE(BIRD))spk=FREE_FLY+MOD(game.prop[BIRD],2);
978     if (spk == 206 && game.loc == game.place[STEPS] && game.prop[JADE] < 0) {
979         DROP(JADE,game.loc);
980         game.prop[JADE]=0;
981         --game.tally;
982         spk=NECKLACE_FLY;
983         RSPEAK(spk);
984         return GO_CLEAROBJ;
985     } else {
986         if (game.closed) {
987             RSPEAK(spk);
988             return GO_DWARFWAKE;
989         }
990         if (game.closng || !AT(FISSUR)) {RSPEAK(spk); return GO_CLEAROBJ;}
991         if (HERE(BIRD))RSPEAK(spk);
992         game.prop[FISSUR]=1-game.prop[FISSUR];
993         PSPEAK(FISSUR,2-game.prop[FISSUR]);
994         return GO_CLEAROBJ;
995     }
996 }
997
998 int action(FILE *input, enum speechpart part, long verb, token_t obj)
999 /*  Analyse a verb.  Remember what it was, go back for object if second word
1000  *  unless verb is "say", which snarfs arbitrary second word.
1001  */
1002 {
1003     token_t spk=ACTSPK[verb];
1004
1005     if (part == unknown)
1006     {
1007         /*  Analyse an object word.  See if the thing is here, whether
1008          *  we've got a verb yet, and so on.  Object must be here
1009          *  unless verb is "find" or "invent(ory)" (and no new verb
1010          *  yet to be analysed).  Water and oil are also funny, since
1011          *  they are never actually dropped at any location, but might
1012          *  be here inside the bottle or urn or as a feature of the
1013          *  location. */
1014         if (HERE(obj))
1015             /* FALL THROUGH */;
1016         else if (obj == GRATE) {
1017             if (game.loc == LOC_START || game.loc == LOC_VALLEY || game.loc == LOC_SLIT)
1018                 obj=DPRSSN;
1019             /* FIXME: Arithmetic on location numbers */
1020             if (game.loc > LOC_BELOWGRATE && game.loc < LOC_MISTHALL)
1021                 obj=ENTRNC;
1022             if (obj != GRATE)
1023                 return GO_MOVE;
1024         }
1025         else if (obj == DWARF && ATDWRF(game.loc) > 0)
1026             /* FALL THROUGH */;
1027         else if ((LIQUID() == obj && HERE(BOTTLE)) || obj == LIQLOC(game.loc))
1028             /* FALL THROUGH */;
1029         else if (obj == OIL && HERE(URN) && game.prop[URN] != 0) {
1030             obj=URN;
1031             /* FALL THROUGH */;
1032         }
1033         else if (obj == PLANT && AT(PLANT2) && game.prop[PLANT2] != 0) {
1034             obj=PLANT2;
1035             /* FALL THROUGH */;
1036         }
1037         else if (obj == KNIFE && game.knfloc == game.loc) {
1038             game.knfloc= -1;
1039             spk=KNIVES_VANISH;
1040             RSPEAK(spk);
1041             return GO_CLEAROBJ;
1042         }
1043         else if (obj == ROD && HERE(ROD2)) {
1044             obj=ROD2;
1045             /* FALL THROUGH */;
1046         }
1047         else if ((verb == FIND || verb == INVENT) && WD2 <= 0)
1048             /* FALL THROUGH */;
1049         else {
1050             SETPRM(1,WD1,WD1X);
1051             RSPEAK(NO_SEE);
1052             return GO_CLEAROBJ;
1053         }
1054
1055         if (WD2 > 0)
1056             return GO_WORD2;
1057         if (verb != 0)
1058             part = transitive;
1059     }
1060
1061     switch(part)
1062     {
1063         case intransitive:
1064             if (WD2 > 0 && verb != SAY) return(2800);
1065             if (verb == SAY)obj=WD2;
1066             if (obj == 0 || obj == INTRANSITIVE) {
1067                 /*  Analyse an intransitive verb (ie, no object given yet). */
1068                     switch (verb-1) {
1069                     case  0: /* CARRY */ return carry(verb, INTRANSITIVE);
1070                     case  1: /* DROP  */ return GO_UNKNOWN; 
1071                     case  2: /* SAY   */ return GO_UNKNOWN; 
1072                     case  3: /* UNLOC */ return lock(verb, INTRANSITIVE);    
1073                     case  4: /* NOTHI */ {RSPEAK(OK_MAN); return(GO_CLEAROBJ);}
1074                     case  5: /* LOCK  */ return lock(verb, INTRANSITIVE);    
1075                     case  6: /* LIGHT */ return light(verb, INTRANSITIVE);    
1076                     case  7: /* EXTIN */ return extinguish(verb, INTRANSITIVE);    
1077                     case  8: /* WAVE  */ return GO_UNKNOWN; 
1078                     case  9: /* CALM  */ return GO_UNKNOWN; 
1079                     case 10: /* WALK  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1080                     case 11: /* ATTAC */ return attack(input, verb, obj);   
1081                     case 12: /* POUR  */ return pour(verb, obj);   
1082                     case 13: /* EAT   */ return eat(verb, INTRANSITIVE);   
1083                     case 14: /* DRINK */ return drink(verb, obj);   
1084                     case 15: /* RUB   */ return GO_UNKNOWN; 
1085                     case 16: /* TOSS  */ return GO_UNKNOWN; 
1086                     case 17: /* QUIT  */ return quit(input);   
1087                     case 18: /* FIND  */ return GO_UNKNOWN; 
1088                     case 19: /* INVEN */ return inven();
1089                     case 20: /* FEED  */ return GO_UNKNOWN; 
1090                     case 21: /* FILL  */ return fill(verb, obj);   
1091                     case 22: /* BLAST */ return blast();   
1092                     case 23: /* SCOR  */ return vscore();   
1093                     case 24: /* FOO   */ return bigwords(WD1);   
1094                     case 25: /* BRIEF */ return brief();   
1095                     case 26: /* READ  */ return read(input, verb, INTRANSITIVE);
1096                     case 27: /* BREAK */ return GO_UNKNOWN; 
1097                     case 28: /* WAKE  */ return GO_UNKNOWN; 
1098                     case 29: /* SUSP  */ return saveresume(input, false);   
1099                     case 30: /* RESU  */ return saveresume(input, true);   
1100                     case 31: /* FLY   */ return fly(verb, INTRANSITIVE);   
1101                     case 32: /* LISTE */ return listen();   
1102                     case 33: /* ZZZZ  */ return reservoir();   
1103                 }
1104                 BUG(23);
1105             }
1106             /* FALLTHRU */
1107         case transitive:
1108             /*  Analyse a transitive verb. */
1109             switch (verb-1) {
1110             case  0: /* CARRY */ return carry(verb, obj);    
1111                 case  1: /* DROP  */ return discard(verb, obj, false);    
1112                 case  2: /* SAY   */ return say();    
1113                 case  3: /* UNLOC */ return lock(verb, obj);    
1114                 case  4: /* NOTHI */ {RSPEAK(OK_MAN); return(GO_CLEAROBJ);}
1115                 case  5: /* LOCK  */ return lock(verb, obj);    
1116                 case  6: /* LIGHT */ return light(verb, obj);    
1117                 case  7: /* EXTI  */ return extinguish(verb, obj);    
1118                 case  8: /* WAVE  */ return wave(verb, obj);    
1119                 case  9: /* CALM  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1120                 case 10: /* WALK  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1121                 case 11: /* ATTAC */ return attack(input, verb, obj);   
1122                 case 12: /* POUR  */ return pour(verb, obj);   
1123                 case 13: /* EAT   */ return eat(verb, obj);   
1124                 case 14: /* DRINK */ return drink(verb, obj);   
1125                 case 15: /* RUB   */ return rub(verb, obj);   
1126                 case 16: /* TOSS  */ return throw(input, verb, obj);   
1127                 case 17: /* QUIT  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1128                 case 18: /* FIND  */ return find(verb, obj);   
1129                 case 19: /* INVEN */ return find(verb, obj);   
1130                 case 20: /* FEED  */ return feed(verb, obj);   
1131                 case 21: /* FILL  */ return fill(verb, obj);   
1132                 case 22: /* BLAST */ return blast();   
1133                 case 23: /* SCOR  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1134                 case 24: /* FOO   */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1135                 case 25: /* BRIEF */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1136                 case 26: /* READ  */ return read(input, verb, obj);   
1137                 case 27: /* BREAK */ return vbreak(verb, obj);   
1138                 case 28: /* WAKE  */ return wake(verb, obj);   
1139                 case 29: /* SUSP  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1140                 case 30: /* RESU  */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1141                 case 31: /* FLY   */ return fly(verb, obj);   
1142                 case 32: /* LISTE */ {RSPEAK(spk); return GO_CLEAROBJ;} 
1143                 case 33: /* ZZZZ  */ return reservoir();   
1144             }
1145             BUG(24);
1146         case unknown:
1147             /* Unknown verb, couldn't deduce object - might need hint */
1148             SETPRM(1,WD1,WD1X);
1149             RSPEAK(WHAT_DO);
1150             return GO_CHECKHINT;
1151     default:
1152             BUG(99);
1153     }
1154 }