OSDN Git Service

no E-word
[nethackexpress/trunk.git] / src / eat.c
1 /*      SCCS Id: @(#)eat.c      3.4     2003/02/13      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 /* #define DEBUG */     /* uncomment to enable new eat code debugging */
7
8 #ifdef DEBUG
9 # ifdef WIZARD
10 #define debugpline      if (wizard) pline
11 # else
12 #define debugpline      pline
13 # endif
14 #endif
15
16 STATIC_PTR int NDECL(eatmdone);
17 STATIC_PTR int NDECL(eatfood);
18 STATIC_PTR void FDECL(costly_tin, (const char*));
19 STATIC_PTR int NDECL(opentin);
20 STATIC_PTR int NDECL(unfaint);
21
22 #ifdef OVLB
23 STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P));
24 STATIC_DCL void FDECL(choke, (struct obj *));
25 STATIC_DCL void NDECL(recalc_wt);
26 STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
27 STATIC_DCL void NDECL(do_reset_eat);
28 STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
29 STATIC_DCL void FDECL(cprefx, (int));
30 STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *));
31 STATIC_DCL void FDECL(givit, (int,struct permonst *));
32 STATIC_DCL void FDECL(cpostfx, (int));
33 STATIC_DCL void FDECL(start_tin, (struct obj *));
34 STATIC_DCL int FDECL(eatcorpse, (struct obj *));
35 STATIC_DCL void FDECL(start_eating, (struct obj *));
36 STATIC_DCL void FDECL(fprefx, (struct obj *));
37 STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
38 STATIC_DCL void FDECL(fpostfx, (struct obj *));
39 STATIC_DCL int NDECL(bite);
40 STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
41 STATIC_DCL int FDECL(rottenfood, (struct obj *));
42 STATIC_DCL void NDECL(eatspecial);
43 STATIC_DCL void FDECL(eataccessory, (struct obj *));
44 STATIC_DCL const char *FDECL(foodword, (struct obj *));
45 STATIC_DCL boolean FDECL(maybe_cannibal, (int,BOOLEAN_P));
46
47 char msgbuf[BUFSZ];
48
49 #endif /* OVLB */
50
51 /* hunger texts used on bottom line (each 8 chars long) */
52 #define SATIATED        0
53 #define NOT_HUNGRY      1
54 #define HUNGRY          2
55 #define WEAK            3
56 #define FAINTING        4
57 #define FAINTED         5
58 #define STARVED         6
59
60 /* also used to see if you're allowed to eat cats and dogs */
61 #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
62
63 #ifndef OVLB
64
65 STATIC_DCL NEARDATA const char comestibles[];
66 STATIC_DCL NEARDATA const char allobj[];
67 STATIC_DCL boolean force_save_hs;
68
69 #else
70
71 STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
72
73 /* Gold must come first for getobj(). */
74 STATIC_OVL NEARDATA const char allobj[] = {
75         COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
76         WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS,
77         GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 };
78
79 STATIC_OVL boolean force_save_hs = FALSE;
80
81 const char *hu_stat[] = {
82         "Satiated",
83         "        ",
84         "Hungry  ",
85         "Weak    ",
86         "Fainting",
87         "Fainted ",
88         "Starved "
89 };
90
91 #endif /* OVLB */
92 #ifdef OVL1
93
94 /*
95  * Decide whether a particular object can be eaten by the possibly
96  * polymorphed character.  Not used for monster checks.
97  */
98 boolean
99 is_edible(obj)
100 register struct obj *obj;
101 {
102         /* protect invocation tools but not Rider corpses (handled elsewhere)*/
103      /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
104         if (objects[obj->otyp].oc_unique)
105                 return FALSE;
106         /* above also prevents the Amulet from being eaten, so we must never
107            allow fake amulets to be eaten either [which is already the case] */
108
109         if (metallivorous(youmonst.data) && is_metallic(obj) &&
110             (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
111                 return TRUE;
112         if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) &&
113                 /* [g.cubes can eat containers and retain all contents
114                     as engulfed items, but poly'd player can't do that] */
115             !Has_contents(obj))
116                 return TRUE;
117
118      /* return((boolean)(!!index(comestibles, obj->oclass))); */
119         return (boolean)(obj->oclass == FOOD_CLASS);
120 }
121
122 #endif /* OVL1 */
123 #ifdef OVLB
124
125 void
126 init_uhunger()
127 {
128         u.uhunger = 900;
129         u.uhs = NOT_HUNGRY;
130 }
131
132 static const struct { const char *txt; int nut; } tintxts[] = {
133         {"deep fried",   60},
134         {"pickled",      40},
135         {"soup made from", 20},
136         {"pureed",      500},
137 #define ROTTEN_TIN 4
138         {"rotten",      -50},
139 #define HOMEMADE_TIN 5
140         {"homemade",     50},
141         {"stir fried",   80},
142         {"candied",      100},
143         {"boiled",       50},
144         {"dried",        55},
145         {"szechuan",     70},
146 #define FRENCH_FRIED_TIN 11
147         {"french fried", 40},
148         {"sauteed",      95},
149         {"broiled",      80},
150         {"smoked",       50},
151         {"", 0}
152 };
153 #define TTSZ    SIZE(tintxts)
154
155 static NEARDATA struct {
156         struct  obj *tin;
157         int     usedtime, reqtime;
158 } tin;
159
160 static NEARDATA struct {
161         struct  obj *piece;     /* the thing being eaten, or last thing that
162                                  * was partially eaten, unless that thing was
163                                  * a tin, which uses the tin structure above,
164                                  * in which case this should be 0 */
165         /* doeat() initializes these when piece is valid */
166         int     usedtime,       /* turns spent eating */
167                 reqtime;        /* turns required to eat */
168         int     nmod;           /* coded nutrition per turn */
169         Bitfield(canchoke,1);   /* was satiated at beginning */
170
171         /* start_eating() initializes these */
172         Bitfield(fullwarn,1);   /* have warned about being full */
173         Bitfield(eating,1);     /* victual currently being eaten */
174         Bitfield(doreset,1);    /* stop eating at end of turn */
175 } victual;
176
177 static char *eatmbuf = 0;       /* set by cpostfx() */
178
179 STATIC_PTR
180 int
181 eatmdone()              /* called after mimicing is over */
182 {
183         /* release `eatmbuf' */
184         if (eatmbuf) {
185             if (nomovemsg == eatmbuf) nomovemsg = 0;
186             free((genericptr_t)eatmbuf),  eatmbuf = 0;
187         }
188         /* update display */
189         if (youmonst.m_ap_type) {
190             youmonst.m_ap_type = M_AP_NOTHING;
191             newsym(u.ux,u.uy);
192         }
193         return 0;
194 }
195
196 /* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */
197 STATIC_OVL const char *
198 food_xname(food, the_pfx)
199 struct obj *food;
200 boolean the_pfx;
201 {
202         const char *result;
203         int mnum = food->corpsenm;
204
205         if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) {
206             /* grab xname()'s modifiable return buffer for our own use */
207             char *bufp = xname(food);
208             Sprintf(bufp, "%s%s corpse",
209                     (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "",
210                     s_suffix(mons[mnum].mname));
211             result = bufp;
212         } else {
213             /* the ordinary case */
214             result = singular(food, xname);
215             if (the_pfx) result = the(result);
216         }
217         return result;
218 }
219
220 /* Created by GAN 01/28/87
221  * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
222  * Amended by 3.  06/12/89: if not hard, sometimes choke anyway, to keep risk.
223  *                11/10/89: if hard, rarely vomit anyway, for slim chance.
224  */
225 STATIC_OVL void
226 choke(food)     /* To a full belly all food is bad. (It.) */
227         register struct obj *food;
228 {
229         /* only happens if you were satiated */
230         if (u.uhs != SATIATED) {
231                 if (!food || food->otyp != AMULET_OF_STRANGULATION)
232                         return;
233         } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
234                         adjalign(-1);           /* gluttony is unchivalrous */
235                         You_feel("like a glutton!");
236         }
237
238         exercise(A_CON, FALSE);
239
240         if (Breathless || (!Strangled && !rn2(20))) {
241                 /* choking by eating AoS doesn't involve stuffing yourself */
242                 if (food && food->otyp == AMULET_OF_STRANGULATION) {
243                         You("choke, but recover your composure.");
244                         return;
245                 }
246                 You("stuff yourself and then vomit voluminously.");
247                 morehungry(1000);       /* you just got *very* sick! */
248                 nomovemsg = 0;
249                 vomit();
250         } else {
251                 killer_format = KILLED_BY_AN;
252                 /*
253                  * Note all "killer"s below read "Choked on %s" on the
254                  * high score list & tombstone.  So plan accordingly.
255                  */
256                 if(food) {
257                         You("choke over your %s.", foodword(food));
258                         if (food->oclass == COIN_CLASS) {
259                                 killer = "a very rich meal";
260                         } else {
261                                 killer = food_xname(food, FALSE);
262                                 if (food->otyp == CORPSE &&
263                                     (mons[food->corpsenm].geno & G_UNIQ)) {
264                                     if (!type_is_pname(&mons[food->corpsenm]))
265                                         killer = the(killer);
266                                     killer_format = KILLED_BY;
267                                 }
268                         }
269                 } else {
270                         You("choke over it.");
271                         killer = "quick snack";
272                 }
273                 You("die...");
274                 done(CHOKING);
275         }
276 }
277
278 /* modify object wt. depending on time spent consuming it */
279 STATIC_OVL void
280 recalc_wt()
281 {
282         struct obj *piece = victual.piece;
283
284 #ifdef DEBUG
285         debugpline("Old weight = %d", piece->owt);
286         debugpline("Used time = %d, Req'd time = %d",
287                 victual.usedtime, victual.reqtime);
288 #endif
289         piece->owt = weight(piece);
290 #ifdef DEBUG
291         debugpline("New weight = %d", piece->owt);
292 #endif
293 }
294
295 void
296 reset_eat()             /* called when eating interrupted by an event */
297 {
298     /* we only set a flag here - the actual reset process is done after
299      * the round is spent eating.
300      */
301         if(victual.eating && !victual.doreset) {
302 #ifdef DEBUG
303             debugpline("reset_eat...");
304 #endif
305             victual.doreset = TRUE;
306         }
307         return;
308 }
309
310 STATIC_OVL struct obj *
311 touchfood(otmp)
312 register struct obj *otmp;
313 {
314         if (otmp->quan > 1L) {
315             if(!carried(otmp))
316                 (void) splitobj(otmp, otmp->quan - 1L);
317             else
318                 otmp = splitobj(otmp, 1L);
319 #ifdef DEBUG
320             debugpline("split object,");
321 #endif
322         }
323
324         if (!otmp->oeaten) {
325             if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
326                  !otmp->no_charge)
327                  || otmp->unpaid)) {
328                 /* create a dummy duplicate to put on bill */
329                 verbalize("You bit it, you bought it!");
330                 bill_dummy_object(otmp);
331             }
332             otmp->oeaten = (otmp->otyp == CORPSE ?
333                                 mons[otmp->corpsenm].cnutrit :
334                                 objects[otmp->otyp].oc_nutrition);
335         }
336
337         if (carried(otmp)) {
338             freeinv(otmp);
339             if (inv_cnt() >= 52) {
340                 sellobj_state(SELL_DONTSELL);
341                 dropy(otmp);
342                 sellobj_state(SELL_NORMAL);
343             } else {
344                 otmp->oxlth++;          /* hack to prevent merge */
345                 otmp = addinv(otmp);
346                 otmp->oxlth--;
347             }
348         }
349         return(otmp);
350 }
351
352 /* When food decays, in the middle of your meal, we don't want to dereference
353  * any dangling pointers, so set it to null (which should still trigger
354  * do_reset_eat() at the beginning of eatfood()) and check for null pointers
355  * in do_reset_eat().
356  */
357 void
358 food_disappears(obj)
359 register struct obj *obj;
360 {
361         if (obj == victual.piece) victual.piece = (struct obj *)0;
362         if (obj->timed) obj_stop_timers(obj);
363 }
364
365 /* renaming an object usually results in it having a different address;
366    so the sequence start eating/opening, get interrupted, name the food,
367    resume eating/opening would restart from scratch */
368 void
369 food_substitution(old_obj, new_obj)
370 struct obj *old_obj, *new_obj;
371 {
372         if (old_obj == victual.piece) victual.piece = new_obj;
373         if (old_obj == tin.tin) tin.tin = new_obj;
374 }
375
376 STATIC_OVL void
377 do_reset_eat()
378 {
379 #ifdef DEBUG
380         debugpline("do_reset_eat...");
381 #endif
382         if (victual.piece) {
383                 victual.piece = touchfood(victual.piece);
384                 recalc_wt();
385         }
386         victual.fullwarn = victual.eating = victual.doreset = FALSE;
387         /* Do not set canchoke to FALSE; if we continue eating the same object
388          * we need to know if canchoke was set when they started eating it the
389          * previous time.  And if we don't continue eating the same object
390          * canchoke always gets recalculated anyway.
391          */
392         stop_occupation();
393         newuhs(FALSE);
394 }
395
396 STATIC_PTR
397 int
398 eatfood()               /* called each move during eating process */
399 {
400         if(!victual.piece ||
401          (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) {
402                 /* maybe it was stolen? */
403                 do_reset_eat();
404                 return(0);
405         }
406         if(!victual.eating) return(0);
407
408         if(++victual.usedtime <= victual.reqtime) {
409             if(bite()) return(0);
410             return(1);  /* still busy */
411         } else {        /* done */
412             done_eating(TRUE);
413             return(0);
414         }
415 }
416
417 STATIC_OVL void
418 done_eating(message)
419 boolean message;
420 {
421         victual.piece->in_use = TRUE;
422         occupation = 0; /* do this early, so newuhs() knows we're done */
423         newuhs(FALSE);
424         if (nomovemsg) {
425                 if (message) pline(nomovemsg);
426                 nomovemsg = 0;
427         } else if (message)
428                 You("finish eating %s.", food_xname(victual.piece, TRUE));
429
430         if(victual.piece->otyp == CORPSE)
431                 cpostfx(victual.piece->corpsenm);
432         else
433                 fpostfx(victual.piece);
434
435         if (carried(victual.piece)) useup(victual.piece);
436         else useupf(victual.piece, 1L);
437         victual.piece = (struct obj *) 0;
438         victual.fullwarn = victual.eating = victual.doreset = FALSE;
439 }
440
441 STATIC_OVL boolean
442 maybe_cannibal(pm, allowmsg)
443 int pm;
444 boolean allowmsg;
445 {
446         if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) {
447                 if (allowmsg) {
448                         if (Upolyd)
449                                 You("have a bad feeling deep inside.");
450                         You("cannibal!  You will regret this!");
451                 }
452                 HAggravate_monster |= FROMOUTSIDE;
453                 change_luck(-rn1(4,2));         /* -5..-2 */
454                 return TRUE;
455         }
456         return FALSE;
457 }
458
459 STATIC_OVL void
460 cprefx(pm)
461 register int pm;
462 {
463         (void) maybe_cannibal(pm,TRUE);
464         if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) {
465             if (!Stone_resistance &&
466                 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
467                 Sprintf(killer_buf, "tasting %s meat", mons[pm].mname);
468                 killer_format = KILLED_BY;
469                 killer = killer_buf;
470                 You("turn to stone.");
471                 done(STONING);
472                 if (victual.piece)
473                     victual.eating = FALSE;
474                 return; /* lifesaved */
475             }
476         }
477
478         switch(pm) {
479             case PM_LITTLE_DOG:
480             case PM_DOG:
481             case PM_LARGE_DOG:
482             case PM_KITTEN:
483             case PM_HOUSECAT:
484             case PM_LARGE_CAT:
485                 if (!CANNIBAL_ALLOWED()) {
486                     You_feel("that eating the %s was a bad idea.", mons[pm].mname);
487                     HAggravate_monster |= FROMOUTSIDE;
488                 }
489                 break;
490             case PM_LIZARD:
491                 if (Stoned) fix_petrification();
492                 break;
493             case PM_DEATH:
494             case PM_PESTILENCE:
495             case PM_FAMINE:
496                 { char buf[BUFSZ];
497                     pline("Eating that is instantly fatal.");
498                     Sprintf(buf, "unwisely ate the body of %s",
499                             mons[pm].mname);
500                     killer = buf;
501                     killer_format = NO_KILLER_PREFIX;
502                     done(DIED);
503                     /* It so happens that since we know these monsters */
504                     /* cannot appear in tins, victual.piece will always */
505                     /* be what we want, which is not generally true. */
506                     if (revive_corpse(victual.piece))
507                         victual.piece = (struct obj *)0;
508                     return;
509                 }
510             case PM_GREEN_SLIME:
511                 if (!Slimed && !Unchanging && !flaming(youmonst.data) &&
512                         youmonst.data != &mons[PM_GREEN_SLIME]) {
513                     You("don't feel very well.");
514                     Slimed = 10L;
515                     flags.botl = 1;
516                 }
517                 /* Fall through */
518             default:
519                 if (acidic(&mons[pm]) && Stoned)
520                     fix_petrification();
521                 break;
522         }
523 }
524
525 void
526 fix_petrification()
527 {
528         Stoned = 0;
529         delayed_killer = 0;
530         if (Hallucination)
531             pline("What a pity - you just ruined a future piece of %sart!",
532                   ACURR(A_CHA) > 15 ? "fine " : "");
533         else
534             You_feel("limber!");
535 }
536
537 /*
538  * If you add an intrinsic that can be gotten by eating a monster, add it
539  * to intrinsic_possible() and givit().  (It must already be in prop.h to
540  * be an intrinsic property.)
541  * It would be very easy to make the intrinsics not try to give you one
542  * that you already had by checking to see if you have it in
543  * intrinsic_possible() instead of givit().
544  */
545
546 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
547 STATIC_OVL int
548 intrinsic_possible(type, ptr)
549 int type;
550 register struct permonst *ptr;
551 {
552         switch (type) {
553             case FIRE_RES:
554 #ifdef DEBUG
555                 if (ptr->mconveys & MR_FIRE) {
556                         debugpline("can get fire resistance");
557                         return(TRUE);
558                 } else  return(FALSE);
559 #else
560                 return(ptr->mconveys & MR_FIRE);
561 #endif
562             case SLEEP_RES:
563 #ifdef DEBUG
564                 if (ptr->mconveys & MR_SLEEP) {
565                         debugpline("can get sleep resistance");
566                         return(TRUE);
567                 } else  return(FALSE);
568 #else
569                 return(ptr->mconveys & MR_SLEEP);
570 #endif
571             case COLD_RES:
572 #ifdef DEBUG
573                 if (ptr->mconveys & MR_COLD) {
574                         debugpline("can get cold resistance");
575                         return(TRUE);
576                 } else  return(FALSE);
577 #else
578                 return(ptr->mconveys & MR_COLD);
579 #endif
580             case DISINT_RES:
581 #ifdef DEBUG
582                 if (ptr->mconveys & MR_DISINT) {
583                         debugpline("can get disintegration resistance");
584                         return(TRUE);
585                 } else  return(FALSE);
586 #else
587                 return(ptr->mconveys & MR_DISINT);
588 #endif
589             case SHOCK_RES:     /* shock (electricity) resistance */
590 #ifdef DEBUG
591                 if (ptr->mconveys & MR_ELEC) {
592                         debugpline("can get shock resistance");
593                         return(TRUE);
594                 } else  return(FALSE);
595 #else
596                 return(ptr->mconveys & MR_ELEC);
597 #endif
598             case POISON_RES:
599 #ifdef DEBUG
600                 if (ptr->mconveys & MR_POISON) {
601                         debugpline("can get poison resistance");
602                         return(TRUE);
603                 } else  return(FALSE);
604 #else
605                 return(ptr->mconveys & MR_POISON);
606 #endif
607             case TELEPORT:
608 #ifdef DEBUG
609                 if (can_teleport(ptr)) {
610                         debugpline("can get teleport");
611                         return(TRUE);
612                 } else  return(FALSE);
613 #else
614                 return(can_teleport(ptr));
615 #endif
616             case TELEPORT_CONTROL:
617 #ifdef DEBUG
618                 if (control_teleport(ptr)) {
619                         debugpline("can get teleport control");
620                         return(TRUE);
621                 } else  return(FALSE);
622 #else
623                 return(control_teleport(ptr));
624 #endif
625             case TELEPAT:
626 #ifdef DEBUG
627                 if (telepathic(ptr)) {
628                         debugpline("can get telepathy");
629                         return(TRUE);
630                 } else  return(FALSE);
631 #else
632                 return(telepathic(ptr));
633 #endif
634             default:
635                 return(FALSE);
636         }
637         /*NOTREACHED*/
638 }
639
640 /* givit() tries to give you an intrinsic based on the monster's level
641  * and what type of intrinsic it is trying to give you.
642  */
643 STATIC_OVL void
644 givit(type, ptr)
645 int type;
646 register struct permonst *ptr;
647 {
648         register int chance;
649
650 #ifdef DEBUG
651         debugpline("Attempting to give intrinsic %d", type);
652 #endif
653         /* some intrinsics are easier to get than others */
654         switch (type) {
655                 case POISON_RES:
656                         if ((ptr == &mons[PM_KILLER_BEE] ||
657                                         ptr == &mons[PM_SCORPION]) && !rn2(4))
658                                 chance = 1;
659                         else
660                                 chance = 15;
661                         break;
662                 case TELEPORT:
663                         chance = 10;
664                         break;
665                 case TELEPORT_CONTROL:
666                         chance = 12;
667                         break;
668                 case TELEPAT:
669                         chance = 1;
670                         break;
671                 default:
672                         chance = 15;
673                         break;
674         }
675
676         if (ptr->mlevel <= rn2(chance))
677                 return;         /* failed die roll */
678
679         switch (type) {
680             case FIRE_RES:
681 #ifdef DEBUG
682                 debugpline("Trying to give fire resistance");
683 #endif
684                 if(!(HFire_resistance & FROMOUTSIDE)) {
685                         You(Hallucination ? "be chillin'." :
686                             "feel a momentary chill.");
687                         HFire_resistance |= FROMOUTSIDE;
688                 }
689                 break;
690             case SLEEP_RES:
691 #ifdef DEBUG
692                 debugpline("Trying to give sleep resistance");
693 #endif
694                 if(!(HSleep_resistance & FROMOUTSIDE)) {
695                         You_feel("wide awake.");
696                         HSleep_resistance |= FROMOUTSIDE;
697                 }
698                 break;
699             case COLD_RES:
700 #ifdef DEBUG
701                 debugpline("Trying to give cold resistance");
702 #endif
703                 if(!(HCold_resistance & FROMOUTSIDE)) {
704                         You_feel("full of hot air.");
705                         HCold_resistance |= FROMOUTSIDE;
706                 }
707                 break;
708             case DISINT_RES:
709 #ifdef DEBUG
710                 debugpline("Trying to give disintegration resistance");
711 #endif
712                 if(!(HDisint_resistance & FROMOUTSIDE)) {
713                         You_feel(Hallucination ?
714                             "totally together, man." :
715                             "very firm.");
716                         HDisint_resistance |= FROMOUTSIDE;
717                 }
718                 break;
719             case SHOCK_RES:     /* shock (electricity) resistance */
720 #ifdef DEBUG
721                 debugpline("Trying to give shock resistance");
722 #endif
723                 if(!(HShock_resistance & FROMOUTSIDE)) {
724                         if (Hallucination)
725                                 You_feel("grounded in reality.");
726                         else
727                                 Your("health currently feels amplified!");
728                         HShock_resistance |= FROMOUTSIDE;
729                 }
730                 break;
731             case POISON_RES:
732 #ifdef DEBUG
733                 debugpline("Trying to give poison resistance");
734 #endif
735                 if(!(HPoison_resistance & FROMOUTSIDE)) {
736                         You_feel(Poison_resistance ?
737                                  "especially healthy." : "healthy.");
738                         HPoison_resistance |= FROMOUTSIDE;
739                 }
740                 break;
741             case TELEPORT:
742 #ifdef DEBUG
743                 debugpline("Trying to give teleport");
744 #endif
745                 if(!(HTeleportation & FROMOUTSIDE)) {
746                         You_feel(Hallucination ? "diffuse." :
747                             "very jumpy.");
748                         HTeleportation |= FROMOUTSIDE;
749                 }
750                 break;
751             case TELEPORT_CONTROL:
752 #ifdef DEBUG
753                 debugpline("Trying to give teleport control");
754 #endif
755                 if(!(HTeleport_control & FROMOUTSIDE)) {
756                         You_feel(Hallucination ?
757                             "centered in your personal space." :
758                             "in control of yourself.");
759                         HTeleport_control |= FROMOUTSIDE;
760                 }
761                 break;
762             case TELEPAT:
763 #ifdef DEBUG
764                 debugpline("Trying to give telepathy");
765 #endif
766                 if(!(HTelepat & FROMOUTSIDE)) {
767                         You_feel(Hallucination ?
768                             "in touch with the cosmos." :
769                             "a strange mental acuity.");
770                         HTelepat |= FROMOUTSIDE;
771                         /* If blind, make sure monsters show up. */
772                         if (Blind) see_monsters();
773                 }
774                 break;
775             default:
776 #ifdef DEBUG
777                 debugpline("Tried to give an impossible intrinsic");
778 #endif
779                 break;
780         }
781 }
782
783 STATIC_OVL void
784 cpostfx(pm)             /* called after completely consuming a corpse */
785 register int pm;
786 {
787         register int tmp = 0;
788         boolean catch_lycanthropy = FALSE;
789
790         /* in case `afternmv' didn't get called for previously mimicking
791            gold, clean up now to avoid `eatmbuf' memory leak */
792         if (eatmbuf) (void)eatmdone();
793
794         switch(pm) {
795             case PM_NEWT:
796                 /* MRKR: "eye of newt" may give small magical energy boost */
797                 if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
798                     int old_uen = u.uen;
799                     u.uen += rnd(3);
800                     if (u.uen > u.uenmax) {
801                         if (!rn2(3)) u.uenmax++;
802                         u.uen = u.uenmax;
803                     }
804                     if (old_uen != u.uen) {
805                             You_feel("a mild buzz.");
806                             flags.botl = 1;
807                     }
808                 }
809                 break;
810             case PM_WRAITH:
811                 pluslvl(FALSE);
812                 break;
813             case PM_HUMAN_WERERAT:
814                 catch_lycanthropy = TRUE;
815                 u.ulycn = PM_WERERAT;
816                 break;
817             case PM_HUMAN_WEREJACKAL:
818                 catch_lycanthropy = TRUE;
819                 u.ulycn = PM_WEREJACKAL;
820                 break;
821             case PM_HUMAN_WEREWOLF:
822                 catch_lycanthropy = TRUE;
823                 u.ulycn = PM_WEREWOLF;
824                 break;
825             case PM_NURSE:
826                 if (Upolyd) u.mh = u.mhmax;
827                 else u.uhp = u.uhpmax;
828                 flags.botl = 1;
829                 break;
830             case PM_STALKER:
831                 if(!Invis) {
832                         set_itimeout(&HInvis, (long)rn1(100, 50));
833                         if (!Blind && !BInvis) self_invis_message();
834                 } else {
835                         if (!(HInvis & INTRINSIC)) You_feel("hidden!");
836                         HInvis |= FROMOUTSIDE;
837                         HSee_invisible |= FROMOUTSIDE;
838                 }
839                 newsym(u.ux, u.uy);
840                 /* fall into next case */
841             case PM_YELLOW_LIGHT:
842                 /* fall into next case */
843             case PM_GIANT_BAT:
844                 make_stunned(HStun + 30,FALSE);
845                 /* fall into next case */
846             case PM_BAT:
847                 make_stunned(HStun + 30,FALSE);
848                 break;
849             case PM_GIANT_MIMIC:
850                 tmp += 10;
851                 /* fall into next case */
852             case PM_LARGE_MIMIC:
853                 tmp += 20;
854                 /* fall into next case */
855             case PM_SMALL_MIMIC:
856                 tmp += 20;
857                 if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
858                     char buf[BUFSZ];
859                     You_cant("resist the temptation to mimic %s.",
860                         Hallucination ? "an orange" : "a pile of gold");
861 #ifdef STEED
862                     /* A pile of gold can't ride. */
863                     if (u.usteed) dismount_steed(DISMOUNT_FELL);
864 #endif
865                     nomul(-tmp);
866                     Sprintf(buf, Hallucination ?
867                         "You suddenly dread being peeled and mimic %s again!" :
868                         "You now prefer mimicking %s again.",
869                         an(Upolyd ? youmonst.data->mname : urace.noun));
870                     eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf);
871                     nomovemsg = eatmbuf;
872                     afternmv = eatmdone;
873                     /* ??? what if this was set before? */
874                     youmonst.m_ap_type = M_AP_OBJECT;
875                     youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
876                     newsym(u.ux,u.uy);
877                     curs_on_u();
878                     /* make gold symbol show up now */
879                     display_nhwindow(WIN_MAP, TRUE);
880                 }
881                 break;
882             case PM_QUANTUM_MECHANIC:
883                 Your("velocity suddenly seems very uncertain!");
884                 if (HFast & INTRINSIC) {
885                         HFast &= ~INTRINSIC;
886                         You("seem slower.");
887                 } else {
888                         HFast |= FROMOUTSIDE;
889                         You("seem faster.");
890                 }
891                 break;
892             case PM_LIZARD:
893                 if (HStun > 2)  make_stunned(2L,FALSE);
894                 if (HConfusion > 2)  make_confused(2L,FALSE);
895                 break;
896             case PM_CHAMELEON:
897             case PM_DOPPELGANGER:
898          /* case PM_SANDESTIN: */
899                 if (!Unchanging) {
900                     You_feel("a change coming over you.");
901                     polyself(FALSE);
902                 }
903                 break;
904             case PM_MIND_FLAYER:
905             case PM_MASTER_MIND_FLAYER:
906                 if (ABASE(A_INT) < ATTRMAX(A_INT)) {
907                         if (!rn2(2)) {
908                                 pline("Yum! That was real brain food!");
909                                 (void) adjattrib(A_INT, 1, FALSE);
910                                 break;  /* don't give them telepathy, too */
911                         }
912                 }
913                 else {
914                         pline("For some reason, that tasted bland.");
915                 }
916                 /* fall through to default case */
917             default: {
918                 register struct permonst *ptr = &mons[pm];
919                 int i, count;
920
921                 if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) ||
922                     pm == PM_VIOLET_FUNGUS) {
923                         pline ("Oh wow!  Great stuff!");
924                         make_hallucinated(HHallucination + 200,FALSE,0L);
925                 }
926                 if(is_giant(ptr)) gainstr((struct obj *)0, 0);
927
928                 /* Check the monster for all of the intrinsics.  If this
929                  * monster can give more than one, pick one to try to give
930                  * from among all it can give.
931                  *
932                  * If a monster can give 4 intrinsics then you have
933                  * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first,
934                  * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second,
935                  * a 1/3 * 3/4 = 1/4 chance of getting the third,
936                  * and a 1/4 chance of getting the fourth.
937                  *
938                  * And now a proof by induction:
939                  * it works for 1 intrinsic (1 in 1 of getting it)
940                  * for 2 you have a 1 in 2 chance of getting the second,
941                  *      otherwise you keep the first
942                  * for 3 you have a 1 in 3 chance of getting the third,
943                  *      otherwise you keep the first or the second
944                  * for n+1 you have a 1 in n+1 chance of getting the (n+1)st,
945                  *      otherwise you keep the previous one.
946                  * Elliott Kleinrock, October 5, 1990
947                  */
948
949                  count = 0;     /* number of possible intrinsics */
950                  tmp = 0;       /* which one we will try to give */
951                  for (i = 1; i <= LAST_PROP; i++) {
952                         if (intrinsic_possible(i, ptr)) {
953                                 count++;
954                                 /* a 1 in count chance of replacing the old
955                                  * one with this one, and a count-1 in count
956                                  * chance of keeping the old one.  (note
957                                  * that 1 in 1 and 0 in 1 are what we want
958                                  * for the first one
959                                  */
960                                 if (!rn2(count)) {
961 #ifdef DEBUG
962                                         debugpline("Intrinsic %d replacing %d",
963                                                                 i, tmp);
964 #endif
965                                         tmp = i;
966                                 }
967                         }
968                  }
969
970                  /* if any found try to give them one */
971                  if (count) givit(tmp, ptr);
972             }
973             break;
974         }
975
976         if (catch_lycanthropy && defends(AD_WERE, uwep)) {
977             if (!touch_artifact(uwep, &youmonst)) {
978                 dropx(uwep);
979                 uwepgone();
980             }
981         }
982
983         return;
984 }
985
986 void
987 violated_vegetarian()
988 {
989     u.uconduct.unvegetarian++;
990     if (Role_if(PM_MONK)) {
991         You_feel("guilty.");
992         adjalign(-1);
993     }
994     return;
995 }
996
997 /* common code to check and possibly charge for 1 context.tin.tin,
998  * will split() context.tin.tin if necessary */
999 STATIC_PTR
1000 void
1001 costly_tin(verb)
1002         const char* verb;               /* if 0, the verb is "open" */
1003 {
1004         if(((!carried(tin.tin) &&
1005              costly_spot(tin.tin->ox, tin.tin->oy) &&
1006              !tin.tin->no_charge)
1007             || tin.tin->unpaid)) {
1008             verbalize("You %s it, you bought it!", verb ? verb : "open");
1009             if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L);
1010             bill_dummy_object(tin.tin);
1011         }
1012 }
1013
1014 STATIC_PTR
1015 int
1016 opentin()               /* called during each move whilst opening a tin */
1017 {
1018         register int r;
1019         const char *what;
1020         int which;
1021
1022         if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy))
1023                                         /* perhaps it was stolen? */
1024                 return(0);              /* %% probably we should use tinoid */
1025         if(tin.usedtime++ >= 50) {
1026                 You("give up your attempt to open the tin.");
1027                 return(0);
1028         }
1029         if(tin.usedtime < tin.reqtime)
1030                 return(1);              /* still busy */
1031         if(tin.tin->otrapped ||
1032            (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) {
1033                 b_trapped("tin", 0);
1034                 costly_tin("destroyed");
1035                 goto use_me;
1036         }
1037         You("succeed in opening the tin.");
1038         if(tin.tin->spe != 1) {
1039             if (tin.tin->corpsenm == NON_PM) {
1040                 pline("It turns out to be empty.");
1041                 tin.tin->dknown = tin.tin->known = TRUE;
1042                 costly_tin((const char*)0);
1043                 goto use_me;
1044             }
1045             r = tin.tin->cursed ? ROTTEN_TIN :  /* always rotten if cursed */
1046                     (tin.tin->spe == -1) ? HOMEMADE_TIN :  /* player made it */
1047                         rn2(TTSZ-1);            /* else take your pick */
1048             if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD ||
1049                         tin.tin->corpsenm == PM_LICHEN))
1050                 r = HOMEMADE_TIN;               /* lizards don't rot */
1051             else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7))
1052                 r = ROTTEN_TIN;                 /* some homemade tins go bad */
1053             which = 0;  /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1054             if (Hallucination) {
1055                 what = rndmonnam();
1056             } else {
1057                 what = mons[tin.tin->corpsenm].mname;
1058                 if (mons[tin.tin->corpsenm].geno & G_UNIQ)
1059                     which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2;
1060             }
1061             if (which == 0) what = makeplural(what);
1062             pline("It smells like %s%s.", (which == 2) ? "the " : "", what);
1063             if (yn("Eat it?") == 'n') {
1064                 if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE;
1065                 if (flags.verbose) You("discard the open tin.");
1066                 costly_tin((const char*)0);
1067                 goto use_me;
1068             }
1069             /* in case stop_occupation() was called on previous meal */
1070             victual.piece = (struct obj *)0;
1071             victual.fullwarn = victual.eating = victual.doreset = FALSE;
1072
1073             You("consume %s %s.", tintxts[r].txt,
1074                         mons[tin.tin->corpsenm].mname);
1075
1076             /* KMH, conduct */
1077             u.uconduct.food++;
1078             if (!vegan(&mons[tin.tin->corpsenm]))
1079                 u.uconduct.unvegan++;
1080             if (!vegetarian(&mons[tin.tin->corpsenm]))
1081                 violated_vegetarian();
1082
1083             tin.tin->dknown = tin.tin->known = TRUE;
1084             cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm);
1085
1086             /* charge for one at pre-eating cost */
1087             costly_tin((const char*)0);
1088
1089             /* check for vomiting added by GAN 01/16/87 */
1090             if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE);
1091             else lesshungry(tintxts[r].nut);
1092
1093             if(r == 0 || r == FRENCH_FRIED_TIN) {
1094                 /* Assume !Glib, because you can't open tins when Glib. */
1095                 incr_itimeout(&Glib, rnd(15));
1096                 pline("Eating deep fried food made your %s very slippery.",
1097                       makeplural(body_part(FINGER)));
1098             }
1099         } else {
1100             if (tin.tin->cursed)
1101                 pline("It contains some decaying%s%s substance.",
1102                         Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
1103             else
1104                 pline("It contains spinach.");
1105
1106             if (yn("Eat it?") == 'n') {
1107                 if (!Hallucination && !tin.tin->cursed)
1108                     tin.tin->dknown = tin.tin->known = TRUE;
1109                 if (flags.verbose)
1110                     You("discard the open tin.");
1111                 costly_tin((const char*)0);
1112                 goto use_me;
1113             }
1114
1115             tin.tin->dknown = tin.tin->known = TRUE;
1116             costly_tin((const char*)0);
1117
1118             if (!tin.tin->cursed)
1119                 pline("This makes you feel like %s!",
1120                       Hallucination ? "Swee'pea" : "Popeye");
1121             lesshungry(600);
1122             gainstr(tin.tin, 0);
1123             u.uconduct.food++;
1124         }
1125 use_me:
1126         if (carried(tin.tin)) useup(tin.tin);
1127         else useupf(tin.tin, 1L);
1128         tin.tin = (struct obj *) 0;
1129         return(0);
1130 }
1131
1132 STATIC_OVL void
1133 start_tin(otmp)         /* called when starting to open a tin */
1134         register struct obj *otmp;
1135 {
1136         register int tmp;
1137
1138         if (metallivorous(youmonst.data)) {
1139                 You("bite right into the metal tin...");
1140                 tmp = 1;
1141         } else if (nolimbs(youmonst.data)) {
1142                 You("cannot handle the tin properly to open it.");
1143                 return;
1144         } else if (otmp->blessed) {
1145                 pline_The("tin opens like magic!");
1146                 tmp = 1;
1147         } else if(uwep) {
1148                 switch(uwep->otyp) {
1149                 case TIN_OPENER:
1150                         tmp = 1;
1151                         break;
1152                 case DAGGER:
1153                 case SILVER_DAGGER:
1154                 case ELVEN_DAGGER:
1155                 case ORCISH_DAGGER:
1156                 case ATHAME:
1157                 case CRYSKNIFE:
1158                         tmp = 3;
1159                         break;
1160                 case PICK_AXE:
1161                 case AXE:
1162                         tmp = 6;
1163                         break;
1164                 default:
1165                         goto no_opener;
1166                 }
1167                 pline("Using your %s you try to open the tin.",
1168                         aobjnam(uwep, (char *)0));
1169         } else {
1170 no_opener:
1171                 pline("It is not so easy to open this tin.");
1172                 if(Glib) {
1173                         pline_The("tin slips from your %s.",
1174                               makeplural(body_part(FINGER)));
1175                         if(otmp->quan > 1L) {
1176                             otmp = splitobj(otmp, 1L);
1177                         }
1178                         if (carried(otmp)) dropx(otmp);
1179                         else stackobj(otmp);
1180                         return;
1181                 }
1182                 tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10);
1183         }
1184         tin.reqtime = tmp;
1185         tin.usedtime = 0;
1186         tin.tin = otmp;
1187         set_occupation(opentin, "opening the tin", 0);
1188         return;
1189 }
1190
1191 int
1192 Hear_again()            /* called when waking up after fainting */
1193 {
1194         flags.soundok = 1;
1195         return 0;
1196 }
1197
1198 /* called on the "first bite" of rotten food */
1199 STATIC_OVL int
1200 rottenfood(obj)
1201 struct obj *obj;
1202 {
1203         pline("Blecch!  Rotten %s!", foodword(obj));
1204         if(!rn2(4)) {
1205                 if (Hallucination) You_feel("rather trippy.");
1206                 else You_feel("rather %s.", body_part(LIGHT_HEADED));
1207                 make_confused(HConfusion + d(2,4),FALSE);
1208         } else if(!rn2(4) && !Blind) {
1209                 pline("Everything suddenly goes dark.");
1210                 make_blinded((long)d(2,10),FALSE);
1211                 if (!Blind) Your(vision_clears);
1212         } else if(!rn2(3)) {
1213                 const char *what, *where;
1214                 if (!Blind)
1215                     what = "goes",  where = "dark";
1216                 else if (Levitation || Is_airlevel(&u.uz) ||
1217                          Is_waterlevel(&u.uz))
1218                     what = "you lose control of",  where = "yourself";
1219                 else
1220                     what = "you slap against the", where =
1221 #ifdef STEED
1222                            (u.usteed) ? "saddle" :
1223 #endif
1224                            surface(u.ux,u.uy);
1225                 pline_The("world spins and %s %s.", what, where);
1226                 flags.soundok = 0;
1227                 nomul(-rnd(10));
1228                 nomovemsg = "You are conscious again.";
1229                 afternmv = Hear_again;
1230                 return(1);
1231         }
1232         return(0);
1233 }
1234
1235 STATIC_OVL int
1236 eatcorpse(otmp)         /* called when a corpse is selected as food */
1237         register struct obj *otmp;
1238 {
1239         int tp = 0, mnum = otmp->corpsenm;
1240         long rotted = 0L;
1241         boolean uniq = !!(mons[mnum].geno & G_UNIQ);
1242         int retcode = 0;
1243         boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance &&
1244                                 !poly_when_stoned(youmonst.data));
1245
1246         /* KMH, conduct */
1247         if (!vegan(&mons[mnum])) u.uconduct.unvegan++;
1248         if (!vegetarian(&mons[mnum])) violated_vegetarian();
1249
1250         if (mnum != PM_LIZARD && mnum != PM_LICHEN) {
1251                 long age = peek_at_iced_corpse_age(otmp);
1252
1253                 rotted = (monstermoves - age)/(10L + rn2(20));
1254                 if (otmp->cursed) rotted += 2L;
1255                 else if (otmp->blessed) rotted -= 2L;
1256         }
1257
1258         if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) {
1259                 boolean cannibal = maybe_cannibal(mnum, FALSE);
1260                 pline("Ulch - that %s was tainted%s!",
1261                       mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" :
1262                       !vegetarian(&mons[mnum]) ? "meat" : "protoplasm",
1263                       cannibal ? " cannibal" : "");
1264                 if (Sick_resistance) {
1265                         pline("It doesn't seem at all sickening, though...");
1266                 } else {
1267                         char buf[BUFSZ];
1268                         long sick_time;
1269
1270                         sick_time = (long) rn1(10, 10);
1271                         /* make sure new ill doesn't result in improvement */
1272                         if (Sick && (sick_time > Sick))
1273                             sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1274                         if (!uniq)
1275                             Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE));
1276                         else
1277                             Sprintf(buf, "%s%s rotted corpse",
1278                                     !type_is_pname(&mons[mnum]) ? "the " : "",
1279                                     s_suffix(mons[mnum].mname));
1280                         make_sick(sick_time, buf, TRUE, SICK_VOMITABLE);
1281                 }
1282                 if (carried(otmp)) useup(otmp);
1283                 else useupf(otmp, 1L);
1284                 return(2);
1285         } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1286                 tp++;
1287                 You("have a very bad case of stomach acid."); /* not body_part() */
1288                 losehp(rnd(15), "acidic corpse", KILLED_BY_AN);
1289         } else if (poisonous(&mons[mnum]) && rn2(5)) {
1290                 tp++;
1291                 pline("Ecch - that must have been poisonous!");
1292                 if(!Poison_resistance) {
1293                         losestr(rnd(4));
1294                         losehp(rnd(15), "poisonous corpse", KILLED_BY_AN);
1295                 } else  You("seem unaffected by the poison.");
1296         /* now any corpse left too long will make you mildly ill */
1297         } else if ((rotted > 5L || (rotted > 3L && rn2(5)))
1298                                         && !Sick_resistance) {
1299                 tp++;
1300                 You_feel("%ssick.", (Sick) ? "very " : "");
1301                 losehp(rnd(8), "cadaver", KILLED_BY_AN);
1302         }
1303
1304         /* delay is weight dependent */
1305         victual.reqtime = 3 + (mons[mnum].cwt >> 6);
1306
1307         if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN &&
1308                         (otmp->orotten || !rn2(7))) {
1309             if (rottenfood(otmp)) {
1310                 otmp->orotten = TRUE;
1311                 (void)touchfood(otmp);
1312                 retcode = 1;
1313             }
1314
1315             if (!mons[otmp->corpsenm].cnutrit) {
1316                 /* no nutrution: rots away, no message if you passed out */
1317                 if (!retcode) pline_The("corpse rots away completely.");
1318                 if (carried(otmp)) useup(otmp);
1319                 else useupf(otmp, 1L);
1320                 retcode = 2;
1321             }
1322                     
1323             if (!retcode) consume_oeaten(otmp, 2);      /* oeaten >>= 2 */
1324         } else {
1325             pline("%s%s %s!",
1326                   !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "",
1327                   food_xname(otmp, FALSE),
1328                   (vegan(&mons[mnum]) ?
1329                    (!carnivorous(youmonst.data) && herbivorous(youmonst.data)) :
1330                    (carnivorous(youmonst.data) && !herbivorous(youmonst.data)))
1331                   ? "is delicious" : "tastes terrible");
1332         }
1333
1334         return(retcode);
1335 }
1336
1337 STATIC_OVL void
1338 start_eating(otmp)              /* called as you start to eat */
1339         register struct obj *otmp;
1340 {
1341 #ifdef DEBUG
1342         debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece);
1343         debugpline("reqtime = %d", victual.reqtime);
1344         debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1345         debugpline("nmod = %d", victual.nmod);
1346         debugpline("oeaten = %d", otmp->oeaten);
1347 #endif
1348         victual.fullwarn = victual.doreset = FALSE;
1349         victual.eating = TRUE;
1350
1351         if (otmp->otyp == CORPSE) {
1352             cprefx(victual.piece->corpsenm);
1353             if (!victual.piece || !victual.eating) {
1354                 /* rider revived, or died and lifesaved */
1355                 return;
1356             }
1357         }
1358
1359         if (bite()) return;
1360
1361         if (++victual.usedtime >= victual.reqtime) {
1362             /* print "finish eating" message if they just resumed -dlc */
1363             done_eating(victual.reqtime > 1 ? TRUE : FALSE);
1364             return;
1365         }
1366
1367         Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1368         set_occupation(eatfood, msgbuf, 0);
1369 }
1370
1371
1372 /*
1373  * called on "first bite" of (non-corpse) food.
1374  * used for non-rotten non-tin non-corpse food
1375  */
1376 STATIC_OVL void
1377 fprefx(otmp)
1378 struct obj *otmp;
1379 {
1380         switch(otmp->otyp) {
1381             case FOOD_RATION:
1382                 if(u.uhunger <= 200)
1383                     pline(Hallucination ? "Oh wow, like, superior, man!" :
1384                           "That food really hit the spot!");
1385                 else if(u.uhunger <= 700) pline("That satiated your %s!",
1386                                                 body_part(STOMACH));
1387                 break;
1388             case TRIPE_RATION:
1389                 if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1390                     pline("That tripe ration was surprisingly good!");
1391                 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
1392                     pline(Hallucination ? "Tastes great! Less filling!" :
1393                           "Mmm, tripe... not bad!");
1394                 else {
1395                     pline("Yak - dog food!");
1396                     more_experienced(1,0);
1397                     newexplevel();
1398                     /* not cannibalism, but we use similar criteria
1399                        for deciding whether to be sickened by this meal */
1400                     if (rn2(2) && !CANNIBAL_ALLOWED())
1401                         make_vomiting((long)rn1(victual.reqtime, 14), FALSE);
1402                 }
1403                 break;
1404             case MEATBALL:
1405             case MEAT_STICK:
1406             case HUGE_CHUNK_OF_MEAT:
1407             case MEAT_RING:
1408                 goto give_feedback;
1409              /* break; */
1410             case CLOVE_OF_GARLIC:
1411                 if (is_undead(youmonst.data)) {
1412                         make_vomiting((long)rn1(victual.reqtime, 5), FALSE);
1413                         break;
1414                 }
1415                 /* Fall through otherwise */
1416             default:
1417                 if (otmp->otyp==SLIME_MOLD && !otmp->cursed
1418                         && otmp->spe == current_fruit)
1419                     pline("My, that was a %s %s!",
1420                           Hallucination ? "primo" : "yummy",
1421                           singular(otmp, xname));
1422                 else
1423 #ifdef UNIX
1424                 if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1425                     if (!Hallucination) pline("Core dumped.");
1426                     else {
1427 /* This is based on an old Usenet joke, a fake a.out manual page */
1428                         int x = rnd(100);
1429                         if (x <= 75)
1430                             pline("Segmentation fault -- core dumped.");
1431                         else if (x <= 99)
1432                             pline("Bus error -- core dumped.");
1433                         else pline("Yo' mama -- core dumped.");
1434                     }
1435                 } else
1436 #endif
1437 #ifdef MAC      /* KMH -- Why should Unix have all the fun? */
1438                 if (otmp->otyp == APPLE) {
1439                         pline("Delicious!  Must be a Macintosh!");
1440                 } else
1441 #endif
1442                 if (otmp->otyp == EGG && stale_egg(otmp)) {
1443                     pline("Ugh.  Rotten egg."); /* perhaps others like it */
1444                     make_vomiting(Vomiting+d(10,4), TRUE);
1445                 } else
1446  give_feedback:
1447                     pline("This %s is %s", singular(otmp, xname),
1448                       otmp->cursed ? (Hallucination ? "grody!" : "terrible!") :
1449                       (otmp->otyp == CRAM_RATION
1450                       || otmp->otyp == K_RATION
1451                       || otmp->otyp == C_RATION)
1452                       ? "bland." :
1453                       Hallucination ? "gnarly!" : "delicious!");
1454                 break;
1455         }
1456 }
1457
1458 STATIC_OVL void
1459 accessory_has_effect(otmp)
1460 struct obj *otmp;
1461 {
1462         pline("Magic spreads through your body as you digest the %s.",
1463             otmp->oclass == RING_CLASS ? "ring" : "amulet");
1464 }
1465
1466 STATIC_OVL void
1467 eataccessory(otmp)
1468 struct obj *otmp;
1469 {
1470         int typ = otmp->otyp;
1471         long oldprop;
1472
1473         /* Note: rings are not so common that this is unbalancing. */
1474         /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1475         oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
1476         if (otmp == uleft || otmp == uright) {
1477             Ring_gone(otmp);
1478             if (u.uhp <= 0) return; /* died from sink fall */
1479         }
1480         otmp->known = otmp->dknown = 1; /* by taste */
1481         if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
1482           switch (otmp->otyp) {
1483             default:
1484                 if (!objects[typ].oc_oprop) break; /* should never happen */
1485
1486                 if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1487                     accessory_has_effect(otmp);
1488
1489                 u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1490
1491                 switch (typ) {
1492                   case RIN_SEE_INVISIBLE:
1493                     set_mimic_blocking();
1494                     see_monsters();
1495                     if (Invis && !oldprop && !ESee_invisible &&
1496                                 !perceives(youmonst.data) && !Blind) {
1497                         newsym(u.ux,u.uy);
1498                         pline("Suddenly you can see yourself.");
1499                         makeknown(typ);
1500                     }
1501                     break;
1502                   case RIN_INVISIBILITY:
1503                     if (!oldprop && !EInvis && !BInvis &&
1504                                         !See_invisible && !Blind) {
1505                         newsym(u.ux,u.uy);
1506                         Your("body takes on a %s transparency...",
1507                                 Hallucination ? "normal" : "strange");
1508                         makeknown(typ);
1509                     }
1510                     break;
1511                   case RIN_PROTECTION_FROM_SHAPE_CHAN:
1512                     rescham();
1513                     break;
1514                   case RIN_LEVITATION:
1515                     /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1516                     u.uprops[LEVITATION].intrinsic = oldprop;
1517                     if (!Levitation) {
1518                         float_up();
1519                         incr_itimeout(&HLevitation, d(10,20));
1520                         makeknown(typ);
1521                     }
1522                     break;
1523                 }
1524                 break;
1525             case RIN_ADORNMENT:
1526                 accessory_has_effect(otmp);
1527                 if (adjattrib(A_CHA, otmp->spe, -1))
1528                     makeknown(typ);
1529                 break;
1530             case RIN_GAIN_STRENGTH:
1531                 accessory_has_effect(otmp);
1532                 if (adjattrib(A_STR, otmp->spe, -1))
1533                     makeknown(typ);
1534                 break;
1535             case RIN_GAIN_CONSTITUTION:
1536                 accessory_has_effect(otmp);
1537                 if (adjattrib(A_CON, otmp->spe, -1))
1538                     makeknown(typ);
1539                 break;
1540             case RIN_INCREASE_ACCURACY:
1541                 accessory_has_effect(otmp);
1542                 u.uhitinc += otmp->spe;
1543                 break;
1544             case RIN_INCREASE_DAMAGE:
1545                 accessory_has_effect(otmp);
1546                 u.udaminc += otmp->spe;
1547                 break;
1548             case RIN_PROTECTION:
1549                 accessory_has_effect(otmp);
1550                 HProtection |= FROMOUTSIDE;
1551                 u.ublessed += otmp->spe;
1552                 flags.botl = 1;
1553                 break;
1554             case RIN_FREE_ACTION:
1555                 /* Give sleep resistance instead */
1556                 if (!(HSleep_resistance & FROMOUTSIDE))
1557                     accessory_has_effect(otmp);
1558                 if (!Sleep_resistance)
1559                     You_feel("wide awake.");
1560                 HSleep_resistance |= FROMOUTSIDE;
1561                 break;
1562             case AMULET_OF_CHANGE:
1563                 accessory_has_effect(otmp);
1564                 makeknown(typ);
1565                 change_sex();
1566                 You("are suddenly very %s!",
1567                     flags.female ? "feminine" : "masculine");
1568                 flags.botl = 1;
1569                 break;
1570             case AMULET_OF_UNCHANGING:
1571                 /* un-change: it's a pun */
1572                 if (!Unchanging && Upolyd) {
1573                     accessory_has_effect(otmp);
1574                     makeknown(typ);
1575                     rehumanize();
1576                 }
1577                 break;
1578             case AMULET_OF_STRANGULATION: /* bad idea! */
1579                 /* no message--this gives no permanent effect */
1580                 choke(otmp);
1581                 break;
1582             case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */
1583                 if (!(HSleeping & FROMOUTSIDE))
1584                     accessory_has_effect(otmp);
1585                 HSleeping = FROMOUTSIDE | rnd(100);
1586                 break;
1587             case RIN_SUSTAIN_ABILITY:
1588             case AMULET_OF_LIFE_SAVING:
1589             case AMULET_OF_REFLECTION: /* nice try */
1590             /* can't eat Amulet of Yendor or fakes,
1591              * and no oc_prop even if you could -3.
1592              */
1593                 break;
1594           }
1595         }
1596 }
1597
1598 STATIC_OVL void
1599 eatspecial() /* called after eating non-food */
1600 {
1601         register struct obj *otmp = victual.piece;
1602
1603         /* lesshungry wants an occupation to handle choke messages correctly */
1604         set_occupation(eatfood, "eating non-food", 0);
1605         lesshungry(victual.nmod);
1606         occupation = 0;
1607         victual.piece = (struct obj *)0;
1608         victual.eating = 0;
1609         if (otmp->oclass == COIN_CLASS) {
1610 #ifdef GOLDOBJ
1611                 if (carried(otmp))
1612                     useupall(otmp);
1613 #else
1614                 if (otmp->where == OBJ_FREE)
1615                     dealloc_obj(otmp);
1616 #endif
1617                 else
1618                     useupf(otmp, otmp->quan);
1619                 return;
1620         }
1621         if (otmp->oclass == POTION_CLASS) {
1622                 otmp->quan++; /* dopotion() does a useup() */
1623                 (void)dopotion(otmp);
1624         }
1625         if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS)
1626                 eataccessory(otmp);
1627         else if (otmp->otyp == LEASH && otmp->leashmon)
1628                 o_unleash(otmp);
1629
1630         /* KMH -- idea by "Tommy the Terrorist" */
1631         if ((otmp->otyp == TRIDENT) && !otmp->cursed)
1632         {
1633                 pline(Hallucination ? "Four out of five dentists agree." :
1634                                 "That was pure chewing satisfaction!");
1635                 exercise(A_WIS, TRUE);
1636         }
1637         if ((otmp->otyp == FLINT) && !otmp->cursed)
1638         {
1639                 pline("Yabba-dabba delicious!");
1640                 exercise(A_CON, TRUE);
1641         }
1642
1643         if (otmp == uwep && otmp->quan == 1L) uwepgone();
1644         if (otmp == uquiver && otmp->quan == 1L) uqwepgone();
1645         if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone();
1646
1647         if (otmp == uball) unpunish();
1648         if (otmp == uchain) unpunish(); /* but no useup() */
1649         else if (carried(otmp)) useup(otmp);
1650         else useupf(otmp, 1L);
1651 }
1652
1653 /* NOTE: the order of these words exactly corresponds to the
1654    order of oc_material values #define'd in objclass.h. */
1655 static const char *foodwords[] = {
1656         "meal", "liquid", "wax", "food", "meat",
1657         "paper", "cloth", "leather", "wood", "bone", "scale",
1658         "metal", "metal", "metal", "silver", "gold", "platinum", "mithril",
1659         "plastic", "glass", "rich food", "stone"
1660 };
1661
1662 STATIC_OVL const char *
1663 foodword(otmp)
1664 register struct obj *otmp;
1665 {
1666         if (otmp->oclass == FOOD_CLASS) return "food";
1667         if (otmp->oclass == GEM_CLASS &&
1668             objects[otmp->otyp].oc_material == GLASS &&
1669             otmp->dknown)
1670                 makeknown(otmp->otyp);
1671         return foodwords[objects[otmp->otyp].oc_material];
1672 }
1673
1674 STATIC_OVL void
1675 fpostfx(otmp)           /* called after consuming (non-corpse) food */
1676 register struct obj *otmp;
1677 {
1678         switch(otmp->otyp) {
1679             case SPRIG_OF_WOLFSBANE:
1680                 if (u.ulycn >= LOW_PM || is_were(youmonst.data))
1681                     you_unwere(TRUE);
1682                 break;
1683             case CARROT:
1684                 make_blinded((long)u.ucreamed,TRUE);
1685                 break;
1686             case FORTUNE_COOKIE:
1687                 outrumor(bcsign(otmp), BY_COOKIE);
1688                 if (!Blind) u.uconduct.literate++;
1689                 break;
1690             case LUMP_OF_ROYAL_JELLY:
1691                 /* This stuff seems to be VERY healthy! */
1692                 gainstr(otmp, 1);
1693                 if (Upolyd) {
1694                     u.mh += otmp->cursed ? -rnd(20) : rnd(20);
1695                     if (u.mh > u.mhmax) {
1696                         if (!rn2(17)) u.mhmax++;
1697                         u.mh = u.mhmax;
1698                     } else if (u.mh <= 0) {
1699                         rehumanize();
1700                     }
1701                 } else {
1702                     u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
1703                     if (u.uhp > u.uhpmax) {
1704                         if(!rn2(17)) u.uhpmax++;
1705                         u.uhp = u.uhpmax;
1706                     } else if (u.uhp <= 0) {
1707                         killer_format = KILLED_BY_AN;
1708                         killer = "rotten lump of royal jelly";
1709                         done(POISONING);
1710                     }
1711                 }
1712                 if(!otmp->cursed) heal_legs();
1713                 break;
1714             case EGG:
1715                 if (touch_petrifies(&mons[otmp->corpsenm])) {
1716                     if (!Stone_resistance &&
1717                         !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
1718                         if (!Stoned) Stoned = 5;
1719                         killer_format = KILLED_BY_AN;
1720                         Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname);
1721                         delayed_killer = killer_buf;
1722                     }
1723                 }
1724                 break;
1725             case EUCALYPTUS_LEAF:
1726                 if (Sick && !otmp->cursed)
1727                     make_sick(0L, (char *)0, TRUE, SICK_ALL);
1728                 if (Vomiting && !otmp->cursed)
1729                     make_vomiting(0L, TRUE);
1730                 break;
1731         }
1732         return;
1733 }
1734
1735 /*
1736  * return 0 if the food was not dangerous.
1737  * return 1 if the food was dangerous and you chose to stop.
1738  * return 2 if the food was dangerous and you chose to eat it anyway.
1739  */
1740 STATIC_OVL int
1741 edibility_prompts(otmp)
1742 struct obj *otmp;
1743 {
1744         /* blessed food detection granted you a one-use
1745            ability to detect food that is unfit for consumption
1746            or dangerous and avoid it. */
1747
1748         char buf[BUFSZ], foodsmell[BUFSZ],
1749              it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
1750         boolean cadaver = (otmp->otyp == CORPSE),
1751                 stoneorslime = FALSE;
1752         int material = objects[otmp->otyp].oc_material,
1753             mnum = otmp->corpsenm;
1754         long rotted = 0L;
1755
1756         Strcpy(foodsmell, Tobjnam(otmp, "smell"));
1757         Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
1758         Sprintf(eat_it_anyway, "Eat %s anyway?",
1759                 (otmp->quan == 1L) ? "it" : "one");
1760
1761         if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
1762                 /* These checks must match those in eatcorpse() */
1763                 stoneorslime = (touch_petrifies(&mons[mnum]) &&
1764                                 !Stone_resistance &&
1765                                 !poly_when_stoned(youmonst.data));
1766
1767                 if (mnum == PM_GREEN_SLIME)
1768                     stoneorslime = (!Unchanging && !flaming(youmonst.data) &&
1769                         youmonst.data != &mons[PM_GREEN_SLIME]);
1770
1771                 if (cadaver && mnum != PM_LIZARD && mnum != PM_LICHEN) {
1772                         long age = peek_at_iced_corpse_age(otmp);
1773                         /* worst case rather than random
1774                            in this calculation to force prompt */
1775                         rotted = (monstermoves - age)/(10L + 0 /* was rn2(20) */);
1776                         if (otmp->cursed) rotted += 2L;
1777                         else if (otmp->blessed) rotted -= 2L;
1778                 }
1779         }
1780
1781         /*
1782          * These problems with food should be checked in
1783          * order from most detrimental to least detrimental.
1784          */
1785
1786         if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
1787                 /* Tainted meat */
1788                 Sprintf(buf, "%s like %s could be tainted! %s",
1789                         foodsmell, it_or_they, eat_it_anyway);
1790                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1791                 else return 2;
1792         }
1793         if (stoneorslime) {
1794                 Sprintf(buf, "%s like %s could be something very dangerous! %s",
1795                         foodsmell, it_or_they, eat_it_anyway);
1796                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1797                 else return 2;
1798         }
1799         if (otmp->orotten || (cadaver && rotted > 3L)) {
1800                 /* Rotten */
1801                 Sprintf(buf, "%s like %s could be rotten! %s",
1802                         foodsmell, it_or_they, eat_it_anyway);
1803                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1804                 else return 2;
1805         }
1806         if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
1807                 /* poisonous */
1808                 Sprintf(buf, "%s like %s might be poisonous! %s",
1809                         foodsmell, it_or_they, eat_it_anyway);
1810                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1811                 else return 2;
1812         }
1813         if (cadaver && !vegetarian(&mons[mnum]) &&
1814             !u.uconduct.unvegetarian && Role_if(PM_MONK)) {
1815                 Sprintf(buf, "%s unhealthy. %s",
1816                         foodsmell, eat_it_anyway);
1817                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1818                 else return 2;
1819         }
1820         if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
1821                 Sprintf(buf, "%s rather acidic. %s",
1822                         foodsmell, eat_it_anyway);
1823                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1824                 else return 2;
1825         }
1826         if (Upolyd && u.umonnum == PM_RUST_MONSTER &&
1827             is_metallic(otmp) && otmp->oerodeproof) {
1828                 Sprintf(buf, "%s disgusting to you right now. %s",
1829                         foodsmell, eat_it_anyway);
1830                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1831                 else return 2;
1832         }
1833
1834         /*
1835          * Breaks conduct, but otherwise safe.
1836          */
1837          
1838         if (!u.uconduct.unvegan &&
1839             ((material == LEATHER || material == BONE ||
1840               material == DRAGON_HIDE || material == WAX) ||
1841              (cadaver && !vegan(&mons[mnum])))) {
1842                 Sprintf(buf, "%s foul and unfamiliar to you. %s",
1843                         foodsmell, eat_it_anyway);
1844                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1845                 else return 2;
1846         }
1847         if (!u.uconduct.unvegetarian &&
1848             ((material == LEATHER || material == BONE ||
1849               material == DRAGON_HIDE) ||
1850              (cadaver && !vegetarian(&mons[mnum])))) {
1851                 Sprintf(buf, "%s unfamiliar to you. %s",
1852                         foodsmell, eat_it_anyway);
1853                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1854                 else return 2;
1855         }
1856
1857         if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
1858                 /* Tainted meat with Sick_resistance */
1859                 Sprintf(buf, "%s like %s could be tainted! %s",
1860                         foodsmell, it_or_they, eat_it_anyway);
1861                 if (yn_function(buf,ynchars,'n')=='n') return 1;
1862                 else return 2;
1863         }
1864         return 0;
1865 }
1866
1867 int
1868 doeat()         /* generic "eat" command funtion (see cmd.c) */
1869 {
1870         register struct obj *otmp;
1871         int basenutrit;                 /* nutrition of full item */
1872         boolean dont_start = FALSE;
1873         
1874         if (Strangled) {
1875                 pline("If you can't breathe air, how can you consume solids?");
1876                 return 0;
1877         }
1878         if (!(otmp = floorfood("eat", 0))) return 0;
1879         if (check_capacity((char *)0)) return 0;
1880
1881         if (u.uedibility) {
1882                 int res = edibility_prompts(otmp);
1883                 if (res) {
1884                     Your("%s stops tingling and your sense of smell returns to normal.",
1885                         body_part(NOSE));
1886                     u.uedibility = 0;
1887                     if (res == 1) return 0;
1888                 }
1889         }
1890
1891         /* We have to make non-foods take 1 move to eat, unless we want to
1892          * do ridiculous amounts of coding to deal with partly eaten plate
1893          * mails, players who polymorph back to human in the middle of their
1894          * metallic meal, etc....
1895          */
1896         if (!is_edible(otmp)) {
1897             You("cannot eat that!");
1898             return 0;
1899         } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL
1900 #ifdef STEED
1901                         |W_SADDLE
1902 #endif
1903                         )) != 0) {
1904             /* let them eat rings */
1905             You_cant("eat %s you're wearing.", something);
1906             return 0;
1907         }
1908         if (is_metallic(otmp) &&
1909             u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) {
1910                 otmp->rknown = TRUE;
1911                 if (otmp->quan > 1L) {
1912                     if(!carried(otmp))
1913                         (void) splitobj(otmp, otmp->quan - 1L);
1914                     else
1915                         otmp = splitobj(otmp, 1L);
1916                 }
1917                 pline("Ulch - That %s was rustproofed!", xname(otmp));
1918                 /* The regurgitated object's rustproofing is gone now */
1919                 otmp->oerodeproof = 0;
1920                 make_stunned(HStun + rn2(10), TRUE);
1921                 You("spit %s out onto the %s.", the(xname(otmp)),
1922                         surface(u.ux, u.uy));
1923                 if (carried(otmp)) {
1924                         freeinv(otmp);
1925                         dropy(otmp);
1926                 }
1927                 stackobj(otmp);
1928                 return 1;
1929         }
1930         /* KMH -- Slow digestion is... indigestible */
1931         if (otmp->otyp == RIN_SLOW_DIGESTION) {
1932                 pline("This ring is indigestible!");
1933                 (void) rottenfood(otmp);
1934                 if (otmp->dknown && !objects[otmp->otyp].oc_name_known
1935                                 && !objects[otmp->otyp].oc_uname)
1936                         docall(otmp);
1937                 return (1);
1938         }
1939         if (otmp->oclass != FOOD_CLASS) {
1940             int material;
1941             victual.reqtime = 1;
1942             victual.piece = otmp;
1943                 /* Don't split it, we don't need to if it's 1 move */
1944             victual.usedtime = 0;
1945             victual.canchoke = (u.uhs == SATIATED);
1946                 /* Note: gold weighs 1 pt. for each 1000 pieces (see */
1947                 /* pickup.c) so gold and non-gold is consistent. */
1948             if (otmp->oclass == COIN_CLASS)
1949                 basenutrit = ((otmp->quan > 200000L) ? 2000
1950                         : (int)(otmp->quan/100L));
1951             else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
1952                 basenutrit = weight(otmp);
1953             /* oc_nutrition is usually weight anyway */
1954             else basenutrit = objects[otmp->otyp].oc_nutrition;
1955             victual.nmod = basenutrit;
1956             victual.eating = TRUE; /* needed for lesshungry() */
1957
1958             material = objects[otmp->otyp].oc_material;
1959             if (material == LEATHER ||
1960                 material == BONE || material == DRAGON_HIDE) {
1961                 u.uconduct.unvegan++;
1962                 violated_vegetarian();
1963             } else if (material == WAX)
1964                 u.uconduct.unvegan++;
1965             u.uconduct.food++;
1966             
1967             if (otmp->cursed)
1968                 (void) rottenfood(otmp);
1969
1970             if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
1971                 pline("Ecch - that must have been poisonous!");
1972                 if(!Poison_resistance) {
1973                     losestr(rnd(4));
1974                     losehp(rnd(15), xname(otmp), KILLED_BY_AN);
1975                 } else
1976                     You("seem unaffected by the poison.");
1977             } else if (!otmp->cursed)
1978                 pline("This %s is delicious!",
1979                       otmp->oclass == COIN_CLASS ? foodword(otmp) :
1980                       singular(otmp, xname));
1981
1982             eatspecial();
1983             return 1;
1984         }
1985
1986         if(otmp == victual.piece) {
1987         /* If they weren't able to choke, they don't suddenly become able to
1988          * choke just because they were interrupted.  On the other hand, if
1989          * they were able to choke before, if they lost food it's possible
1990          * they shouldn't be able to choke now.
1991          */
1992             if (u.uhs != SATIATED) victual.canchoke = FALSE;
1993             victual.piece = touchfood(otmp);
1994             You("resume your meal.");
1995             start_eating(victual.piece);
1996             return(1);
1997         }
1998
1999         /* nothing in progress - so try to find something. */
2000         /* tins are a special case */
2001         /* tins must also check conduct separately in case they're discarded */
2002         if(otmp->otyp == TIN) {
2003             start_tin(otmp);
2004             return(1);
2005         }
2006
2007         /* KMH, conduct */
2008         u.uconduct.food++;
2009
2010         victual.piece = otmp = touchfood(otmp);
2011         victual.usedtime = 0;
2012
2013         /* Now we need to calculate delay and nutritional info.
2014          * The base nutrition calculated here and in eatcorpse() accounts
2015          * for normal vs. rotten food.  The reqtime and nutrit values are
2016          * then adjusted in accordance with the amount of food left.
2017          */
2018         if(otmp->otyp == CORPSE) {
2019             int tmp = eatcorpse(otmp);
2020             if (tmp == 2) {
2021                 /* used up */
2022                 victual.piece = (struct obj *)0;
2023                 return(1);
2024             } else if (tmp)
2025                 dont_start = TRUE;
2026             /* if not used up, eatcorpse sets up reqtime and may modify
2027              * oeaten */
2028         } else {
2029             /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE.  These are
2030              * all handled in the != FOOD_CLASS case, above */
2031             switch (objects[otmp->otyp].oc_material) {
2032             case FLESH:
2033                 u.uconduct.unvegan++;
2034                 if (otmp->otyp != EGG) {
2035                     violated_vegetarian();
2036                 }
2037                 break;
2038
2039             default:
2040                 if (otmp->otyp == PANCAKE ||
2041                     otmp->otyp == FORTUNE_COOKIE || /* eggs */
2042                     otmp->otyp == CREAM_PIE ||
2043                     otmp->otyp == CANDY_BAR || /* milk */
2044                     otmp->otyp == LUMP_OF_ROYAL_JELLY)
2045                     u.uconduct.unvegan++;
2046                 break;
2047             }
2048
2049             victual.reqtime = objects[otmp->otyp].oc_delay;
2050             if (otmp->otyp != FORTUNE_COOKIE &&
2051                 (otmp->cursed ||
2052                  (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) &&
2053                 (otmp->orotten || !rn2(7))))) {
2054
2055                 if (rottenfood(otmp)) {
2056                     otmp->orotten = TRUE;
2057                     dont_start = TRUE;
2058                 }
2059                 consume_oeaten(otmp, 1);        /* oeaten >>= 1 */
2060             } else fprefx(otmp);
2061         }
2062
2063         /* re-calc the nutrition */
2064         if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit;
2065         else basenutrit = objects[otmp->otyp].oc_nutrition;
2066
2067 #ifdef DEBUG
2068         debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime);
2069         debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit);
2070 #endif
2071         victual.reqtime = (basenutrit == 0 ? 0 :
2072                 rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit));
2073 #ifdef DEBUG
2074         debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime);
2075 #endif
2076         /* calculate the modulo value (nutrit. units per round eating)
2077          * note: this isn't exact - you actually lose a little nutrition
2078          *       due to this method.
2079          * TODO: add in a "remainder" value to be given at the end of the
2080          *       meal.
2081          */
2082         if (victual.reqtime == 0 || otmp->oeaten == 0)
2083             /* possible if most has been eaten before */
2084             victual.nmod = 0;
2085         else if ((int)otmp->oeaten >= victual.reqtime)
2086             victual.nmod = -((int)otmp->oeaten / victual.reqtime);
2087         else
2088             victual.nmod = victual.reqtime % otmp->oeaten;
2089         victual.canchoke = (u.uhs == SATIATED);
2090
2091         if (!dont_start) start_eating(otmp);
2092         return(1);
2093 }
2094
2095 /* Take a single bite from a piece of food, checking for choking and
2096  * modifying usedtime.  Returns 1 if they choked and survived, 0 otherwise.
2097  */
2098 STATIC_OVL int
2099 bite()
2100 {
2101         if(victual.canchoke && u.uhunger >= 2000) {
2102                 choke(victual.piece);
2103                 return 1;
2104         }
2105         if (victual.doreset) {
2106                 do_reset_eat();
2107                 return 0;
2108         }
2109         force_save_hs = TRUE;
2110         if(victual.nmod < 0) {
2111                 lesshungry(-victual.nmod);
2112                 consume_oeaten(victual.piece, victual.nmod); /* -= -nmod */
2113         } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) {
2114                 lesshungry(1);
2115                 consume_oeaten(victual.piece, -1);                /* -= 1 */
2116         }
2117         force_save_hs = FALSE;
2118         recalc_wt();
2119         return 0;
2120 }
2121
2122 #endif /* OVLB */
2123 #ifdef OVL0
2124
2125 void
2126 gethungry()     /* as time goes by - called by moveloop() and domove() */
2127 {
2128         if (u.uinvulnerable) return;    /* you don't feel hungrier */
2129
2130         if ((!u.usleep || !rn2(10))     /* slow metabolic rate while asleep */
2131                 && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
2132                 && !Slow_digestion)
2133             u.uhunger--;                /* ordinary food consumption */
2134
2135         if (moves % 2) {        /* odd turns */
2136             /* Regeneration uses up food, unless due to an artifact */
2137             if (HRegeneration || ((ERegeneration & (~W_ART)) &&
2138                                 (ERegeneration != W_WEP || !uwep->oartifact)))
2139                         u.uhunger--;
2140             if (near_capacity() > SLT_ENCUMBER) u.uhunger--;
2141         } else {                /* even turns */
2142             if (Hunger) u.uhunger--;
2143             /* Conflict uses up food too */
2144             if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--;
2145             /* +0 charged rings don't do anything, so don't affect hunger */
2146             /* Slow digestion still uses ring hunger */
2147             switch ((int)(moves % 20)) {        /* note: use even cases only */
2148              case  4: if (uleft &&
2149                           (uleft->spe || !objects[uleft->otyp].oc_charged))
2150                             u.uhunger--;
2151                     break;
2152              case  8: if (uamul) u.uhunger--;
2153                     break;
2154              case 12: if (uright &&
2155                           (uright->spe || !objects[uright->otyp].oc_charged))
2156                             u.uhunger--;
2157                     break;
2158              case 16: if (u.uhave.amulet) u.uhunger--;
2159                     break;
2160              default: break;
2161             }
2162         }
2163         newuhs(TRUE);
2164 }
2165
2166 #endif /* OVL0 */
2167 #ifdef OVLB
2168
2169 void
2170 morehungry(num) /* called after vomiting and after performing feats of magic */
2171 register int num;
2172 {
2173         u.uhunger -= num;
2174         newuhs(TRUE);
2175 }
2176
2177
2178 void
2179 lesshungry(num) /* called after eating (and after drinking fruit juice) */
2180 register int num;
2181 {
2182         /* See comments in newuhs() for discussion on force_save_hs */
2183         boolean iseating = (occupation == eatfood) || force_save_hs;
2184 #ifdef DEBUG
2185         debugpline("lesshungry(%d)", num);
2186 #endif
2187         u.uhunger += num;
2188         if(u.uhunger >= 2000) {
2189             if (!iseating || victual.canchoke) {
2190                 if (iseating) {
2191                     choke(victual.piece);
2192                     reset_eat();
2193                 } else
2194                     choke(occupation == opentin ? tin.tin : (struct obj *)0);
2195                 /* no reset_eat() */
2196             }
2197         } else {
2198             /* Have lesshungry() report when you're nearly full so all eating
2199              * warns when you're about to choke.
2200              */
2201             if (u.uhunger >= 1500) {
2202                 if (!victual.eating || (victual.eating && !victual.fullwarn)) {
2203                     pline("You're having a hard time getting all of it down.");
2204                     nomovemsg = "You're finally finished.";
2205                     if (!victual.eating)
2206                         multi = -2;
2207                     else {
2208                         victual.fullwarn = TRUE;
2209                         if (victual.canchoke && victual.reqtime > 1) {
2210                             /* a one-gulp food will not survive a stop */
2211                             if (yn_function("Stop eating?",ynchars,'y')=='y') {
2212                                 reset_eat();
2213                                 nomovemsg = (char *)0;
2214                             }
2215                         }
2216                     }
2217                 }
2218             }
2219         }
2220         newuhs(FALSE);
2221 }
2222
2223 STATIC_PTR
2224 int
2225 unfaint()
2226 {
2227         (void) Hear_again();
2228         if(u.uhs > FAINTING)
2229                 u.uhs = FAINTING;
2230         stop_occupation();
2231         flags.botl = 1;
2232         return 0;
2233 }
2234
2235 #endif /* OVLB */
2236 #ifdef OVL0
2237
2238 boolean
2239 is_fainted()
2240 {
2241         return((boolean)(u.uhs == FAINTED));
2242 }
2243
2244 void
2245 reset_faint()   /* call when a faint must be prematurely terminated */
2246 {
2247         if(is_fainted()) nomul(0);
2248 }
2249
2250 #if 0
2251 void
2252 sync_hunger()
2253 {
2254
2255         if(is_fainted()) {
2256
2257                 flags.soundok = 0;
2258                 nomul(-10+(u.uhunger/10));
2259                 nomovemsg = "You regain consciousness.";
2260                 afternmv = unfaint;
2261         }
2262 }
2263 #endif
2264
2265 void
2266 newuhs(incr)            /* compute and comment on your (new?) hunger status */
2267 boolean incr;
2268 {
2269         unsigned newhs;
2270         static unsigned save_hs;
2271         static boolean saved_hs = FALSE;
2272         int h = u.uhunger;
2273
2274         newhs = (h > 1000) ? SATIATED :
2275                 (h > 150) ? NOT_HUNGRY :
2276                 (h > 50) ? HUNGRY :
2277                 (h > 0) ? WEAK : FAINTING;
2278
2279         /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2280          * This should not produce the message "you only feel hungry now";
2281          * that message should only appear if HUNGRY is an endpoint.  Therefore
2282          * we check to see if we're in the middle of eating.  If so, we save
2283          * the first hunger status, and at the end of eating we decide what
2284          * message to print based on the _entire_ meal, not on each little bit.
2285          */
2286         /* It is normally possible to check if you are in the middle of a meal
2287          * by checking occupation == eatfood, but there is one special case:
2288          * start_eating() can call bite() for your first bite before it
2289          * sets the occupation.
2290          * Anyone who wants to get that case to work _without_ an ugly static
2291          * force_save_hs variable, feel free.
2292          */
2293         /* Note: If you become a certain hunger status in the middle of the
2294          * meal, and still have that same status at the end of the meal,
2295          * this will incorrectly print the associated message at the end of
2296          * the meal instead of the middle.  Such a case is currently
2297          * impossible, but could become possible if a message for SATIATED
2298          * were added or if HUNGRY and WEAK were separated by a big enough
2299          * gap to fit two bites.
2300          */
2301         if (occupation == eatfood || force_save_hs) {
2302                 if (!saved_hs) {
2303                         save_hs = u.uhs;
2304                         saved_hs = TRUE;
2305                 }
2306                 u.uhs = newhs;
2307                 return;
2308         } else {
2309                 if (saved_hs) {
2310                         u.uhs = save_hs;
2311                         saved_hs = FALSE;
2312                 }
2313         }
2314
2315         if(newhs == FAINTING) {
2316                 if(is_fainted()) newhs = FAINTED;
2317                 if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
2318                         if(!is_fainted() && multi >= 0 /* %% */) {
2319                                 /* stop what you're doing, then faint */
2320                                 stop_occupation();
2321                                 You("faint from lack of food.");
2322                                 flags.soundok = 0;
2323                                 nomul(-10+(u.uhunger/10));
2324                                 nomovemsg = "You regain consciousness.";
2325                                 afternmv = unfaint;
2326                                 newhs = FAINTED;
2327                         }
2328                 } else
2329                 if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) {
2330                         u.uhs = STARVED;
2331                         flags.botl = 1;
2332                         bot();
2333                         You("die from starvation.");
2334                         killer_format = KILLED_BY;
2335                         killer = "starvation";
2336                         done(STARVING);
2337                         /* if we return, we lifesaved, and that calls newuhs */
2338                         return;
2339                 }
2340         }
2341
2342         if(newhs != u.uhs) {
2343                 if(newhs >= WEAK && u.uhs < WEAK)
2344                         losestr(1);     /* this may kill you -- see below */
2345                 else if(newhs < WEAK && u.uhs >= WEAK)
2346                         losestr(-1);
2347                 switch(newhs){
2348                 case HUNGRY:
2349                         if (Hallucination) {
2350                             You((!incr) ?
2351                                 "now have a lesser case of the munchies." :
2352                                 "are getting the munchies.");
2353                         } else
2354                             You((!incr) ? "only feel hungry now." :
2355                                   (u.uhunger < 145) ? "feel hungry." :
2356                                    "are beginning to feel hungry.");
2357                         if (incr && occupation &&
2358                             (occupation != eatfood && occupation != opentin))
2359                             stop_occupation();
2360                         break;
2361                 case WEAK:
2362                         if (Hallucination)
2363                             pline((!incr) ?
2364                                   "You still have the munchies." :
2365       "The munchies are interfering with your motor capabilities.");
2366                         else if (incr &&
2367                                 (Role_if(PM_WIZARD) || Race_if(PM_ELF) ||
2368                                  Role_if(PM_VALKYRIE)))
2369                             pline("%s needs food, badly!",
2370                                   (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
2371                                   urole.name.m : "Elf");
2372                         else
2373                             You((!incr) ? "feel weak now." :
2374                                   (u.uhunger < 45) ? "feel weak." :
2375                                    "are beginning to feel weak.");
2376                         if (incr && occupation &&
2377                             (occupation != eatfood && occupation != opentin))
2378                             stop_occupation();
2379                         break;
2380                 }
2381                 u.uhs = newhs;
2382                 flags.botl = 1;
2383                 bot();
2384                 if ((Upolyd ? u.mh : u.uhp) < 1) {
2385                         You("die from hunger and exhaustion.");
2386                         killer_format = KILLED_BY;
2387                         killer = "exhaustion";
2388                         done(STARVING);
2389                         return;
2390                 }
2391         }
2392 }
2393
2394 #endif /* OVL0 */
2395 #ifdef OVLB
2396
2397 /* Returns an object representing food.  Object may be either on floor or
2398  * in inventory.
2399  */
2400 struct obj *
2401 floorfood(verb,corpsecheck)     /* get food from floor or pack */
2402         const char *verb;
2403         int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
2404 {
2405         register struct obj *otmp;
2406         char qbuf[QBUFSZ];
2407         char c;
2408         boolean feeding = (!strcmp(verb, "eat"));
2409
2410         /* if we can't touch floor objects then use invent food only */
2411         if (!can_reach_floor() ||
2412 #ifdef STEED
2413                 (feeding && u.usteed) || /* can't eat off floor while riding */
2414 #endif
2415                 ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) &&
2416                     (Wwalking || is_clinger(youmonst.data) ||
2417                         (Flying && !Breathless))))
2418             goto skipfloor;
2419
2420         if (feeding && metallivorous(youmonst.data)) {
2421             struct obj *gold;
2422             struct trap *ttmp = t_at(u.ux, u.uy);
2423
2424             if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
2425                 /* If not already stuck in the trap, perhaps there should
2426                    be a chance to becoming trapped?  Probably not, because
2427                    then the trap would just get eaten on the _next_ turn... */
2428                 Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
2429                         (u.utrap && u.utraptype == TT_BEARTRAP) ?
2430                                 "holding you" : "armed");
2431                 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2432                     u.utrap = u.utraptype = 0;
2433                     deltrap(ttmp);
2434                     return mksobj(BEARTRAP, TRUE, FALSE);
2435                 } else if (c == 'q') {
2436                     return (struct obj *)0;
2437                 }
2438             }
2439
2440             if (youmonst.data != &mons[PM_RUST_MONSTER] &&
2441                 (gold = g_at(u.ux, u.uy)) != 0) {
2442                 if (gold->quan == 1L)
2443                     Sprintf(qbuf, "There is 1 gold piece here; eat it?");
2444                 else
2445                     Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
2446                             gold->quan);
2447                 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2448                     return gold;
2449                 } else if (c == 'q') {
2450                     return (struct obj *)0;
2451                 }
2452             }
2453         }
2454
2455         /* Is there some food (probably a heavy corpse) here on the ground? */
2456         for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
2457                 if(corpsecheck ?
2458                 (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) :
2459                     feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) :
2460                                                 otmp->oclass==FOOD_CLASS) {
2461                         Sprintf(qbuf, "There %s %s here; %s %s?",
2462                                 otense(otmp, "are"),
2463                                 doname(otmp), verb,
2464                                 (otmp->quan == 1L) ? "it" : "one");
2465                         if((c = yn_function(qbuf,ynqchars,'n')) == 'y')
2466                                 return(otmp);
2467                         else if(c == 'q')
2468                                 return((struct obj *) 0);
2469                 }
2470         }
2471
2472  skipfloor:
2473         /* We cannot use ALL_CLASSES since that causes getobj() to skip its
2474          * "ugly checks" and we need to check for inedible items.
2475          */
2476         otmp = getobj(feeding ? (const char *)allobj :
2477                                 (const char *)comestibles, verb);
2478         if (corpsecheck && otmp)
2479             if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
2480                 You_cant("%s that!", verb);
2481                 return (struct obj *)0;
2482             }
2483         return otmp;
2484 }
2485
2486 /* Side effects of vomiting */
2487 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
2488 void
2489 vomit()         /* A good idea from David Neves */
2490 {
2491         make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
2492         nomul(-2);
2493 }
2494
2495 int
2496 eaten_stat(base, obj)
2497 register int base;
2498 register struct obj *obj;
2499 {
2500         long uneaten_amt, full_amount;
2501
2502         uneaten_amt = (long)obj->oeaten;
2503         full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit
2504                                         : (long)objects[obj->otyp].oc_nutrition;
2505         if (uneaten_amt > full_amount) {
2506             impossible(
2507           "partly eaten food (%ld) more nutritious than untouched food (%ld)",
2508                        uneaten_amt, full_amount);
2509             uneaten_amt = full_amount;
2510         }
2511
2512         base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L);
2513         return (base < 1) ? 1 : base;
2514 }
2515
2516 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
2517 void
2518 consume_oeaten(obj, amt)
2519 struct obj *obj;
2520 int amt;
2521 {
2522     /*
2523      * This is a hack to try to squelch several long standing mystery
2524      * food bugs.  A better solution would be to rewrite the entire
2525      * victual handling mechanism from scratch using a less complex
2526      * model.  Alternatively, this routine could call done_eating()
2527      * or food_disappears() but its callers would need revisions to
2528      * cope with victual.piece unexpectedly going away.
2529      *
2530      * Multi-turn eating operates by setting the food's oeaten field
2531      * to its full nutritional value and then running a counter which
2532      * independently keeps track of whether there is any food left.
2533      * The oeaten field can reach exactly zero on the last turn, and
2534      * the object isn't removed from inventory until the next turn
2535      * when the "you finish eating" message gets delivered, so the
2536      * food would be restored to the status of untouched during that
2537      * interval.  This resulted in unexpected encumbrance messages
2538      * at the end of a meal (if near enough to a threshold) and would
2539      * yield full food if there was an interruption on the critical
2540      * turn.  Also, there have been reports over the years of food
2541      * becoming massively heavy or producing unlimited satiation;
2542      * this would occur if reducing oeaten via subtraction attempted
2543      * to drop it below 0 since its unsigned type would produce a
2544      * huge positive value instead.  So far, no one has figured out
2545      * _why_ that inappropriate subtraction might sometimes happen.
2546      */
2547
2548     if (amt > 0) {
2549         /* bit shift to divide the remaining amount of food */
2550         obj->oeaten >>= amt;
2551     } else {
2552         /* simple decrement; value is negative so we actually add it */
2553         if ((int) obj->oeaten > -amt)
2554             obj->oeaten += amt;
2555         else
2556             obj->oeaten = 0;
2557     }
2558
2559     if (obj->oeaten == 0) {
2560         if (obj == victual.piece)       /* always true unless wishing... */
2561             victual.reqtime = victual.usedtime; /* no bites left */
2562         obj->oeaten = 1;        /* smallest possible positive value */
2563     }
2564 }
2565
2566 #endif /* OVLB */
2567 #ifdef OVL1
2568
2569 /* called when eatfood occupation has been interrupted,
2570    or in the case of theft, is about to be interrupted */
2571 boolean
2572 maybe_finished_meal(stopping)
2573 boolean stopping;
2574 {
2575         /* in case consume_oeaten() has decided that the food is all gone */
2576         if (occupation == eatfood && victual.usedtime >= victual.reqtime) {
2577             if (stopping) occupation = 0;       /* for do_reset_eat */
2578             (void) eatfood(); /* calls done_eating() to use up victual.piece */
2579             return TRUE;
2580         }
2581         return FALSE;
2582 }
2583
2584 #endif /* OVL1 */
2585
2586 /*eat.c*/