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
is_edible(obj)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
init_uhunger()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
eatmdone()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 *
food_xname(food,the_pfx)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
choke(food)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
recalc_wt()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
reset_eat()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 *
touchfood(otmp)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
food_disappears(obj)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
food_substitution(old_obj,new_obj)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
do_reset_eat()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
eatfood()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
done_eating(message)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
maybe_cannibal(pm,allowmsg)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
cprefx(pm)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
fix_petrification()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
intrinsic_possible(type,ptr)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
givit(type,ptr)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
cpostfx(pm)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
violated_vegetarian()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
costly_tin(verb)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
opentin()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
start_tin(otmp)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
Hear_again()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
rottenfood(obj)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
eatcorpse(otmp)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
start_eating(otmp)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
fprefx(otmp)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
accessory_has_effect(otmp)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
eataccessory(otmp)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
eatspecial()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 *
foodword(otmp)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
fpostfx(otmp)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
edibility_prompts(otmp)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
doeat()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
bite()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
gethungry()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
morehungry(num)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
lesshungry(num)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
unfaint()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
is_fainted()2239 is_fainted()
2240 {
2241 	return((boolean)(u.uhs == FAINTED));
2242 }
2243 
2244 void
reset_faint()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
newuhs(incr)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 *
floorfood(verb,corpsecheck)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
vomit()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
eaten_stat(base,obj)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
consume_oeaten(obj,amt)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
maybe_finished_meal(stopping)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*/
2587