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