mplayer.c formatting
[aNetHack.git] / src / eat.c
blob4c69cf14786d9b6da92ddc9997f5f07616474305
1 /* NetHack 3.6 eat.c $NHDT-Date: 1454715969 2016/02/05 23:46:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 STATIC_PTR int NDECL(eatmdone);
8 STATIC_PTR int NDECL(eatfood);
9 STATIC_PTR void FDECL(costly_tin, (int));
10 STATIC_PTR int NDECL(opentin);
11 STATIC_PTR int NDECL(unfaint);
13 STATIC_DCL const char *FDECL(food_xname, (struct obj *, BOOLEAN_P));
14 STATIC_DCL void FDECL(choke, (struct obj *));
15 STATIC_DCL void NDECL(recalc_wt);
16 STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
17 STATIC_DCL void NDECL(do_reset_eat);
18 STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
19 STATIC_DCL void FDECL(cprefx, (int));
20 STATIC_DCL int FDECL(intrinsic_possible, (int, struct permonst *));
21 STATIC_DCL void FDECL(givit, (int, struct permonst *));
22 STATIC_DCL void FDECL(cpostfx, (int));
23 STATIC_DCL void FDECL(consume_tin, (const char *));
24 STATIC_DCL void FDECL(start_tin, (struct obj *));
25 STATIC_DCL int FDECL(eatcorpse, (struct obj *));
26 STATIC_DCL void FDECL(start_eating, (struct obj *));
27 STATIC_DCL void FDECL(fprefx, (struct obj *));
28 STATIC_DCL void FDECL(fpostfx, (struct obj *));
29 STATIC_DCL int NDECL(bite);
30 STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
31 STATIC_DCL int FDECL(rottenfood, (struct obj *));
32 STATIC_DCL void NDECL(eatspecial);
33 STATIC_DCL int FDECL(bounded_increase, (int, int, int));
34 STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
35 STATIC_DCL void FDECL(eataccessory, (struct obj *));
36 STATIC_DCL const char *FDECL(foodword, (struct obj *));
37 STATIC_DCL int FDECL(tin_variety, (struct obj *, BOOLEAN_P));
38 STATIC_DCL boolean FDECL(maybe_cannibal, (int, BOOLEAN_P));
40 char msgbuf[BUFSZ];
42 /* also used to see if you're allowed to eat cats and dogs */
43 #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
45 /* monster types that cause hero to be turned into stone if eaten */
46 #define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA])
48 /* Rider corpses are treated as non-rotting so that attempting to eat one
49 will be sure to reach the stage of eating where that meal is fatal */
50 #define nonrotting_corpse(mnum) \
51 ((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum]))
53 /* non-rotting non-corpses; unlike lizard corpses, these items will behave
54 as if rotten if they are cursed (fortune cookies handled elsewhere) */
55 #define nonrotting_food(otyp) \
56 ((otyp) == LEMBAS_WAFER || (otyp) == CRAM_RATION)
58 STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
59 STATIC_OVL NEARDATA const char offerfodder[] = { FOOD_CLASS, AMULET_CLASS,
60 0 };
62 /* Gold must come first for getobj(). */
63 STATIC_OVL NEARDATA const char allobj[] = {
64 COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS,
65 SCROLL_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
66 FOOD_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS,
67 BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0
70 STATIC_OVL boolean force_save_hs = FALSE;
72 /* see hunger states in hack.h - texts used on bottom line */
73 const char *hu_stat[] = { "Satiated", " ", "Hungry ", "Weak ",
74 "Fainting", "Fainted ", "Starved " };
77 * Decide whether a particular object can be eaten by the possibly
78 * polymorphed character. Not used for monster checks.
80 boolean
81 is_edible(obj)
82 register struct obj *obj;
84 /* protect invocation tools but not Rider corpses (handled elsewhere)*/
85 /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
86 if (objects[obj->otyp].oc_unique)
87 return FALSE;
88 /* above also prevents the Amulet from being eaten, so we must never
89 allow fake amulets to be eaten either [which is already the case] */
91 if (metallivorous(youmonst.data) && is_metallic(obj)
92 && (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
93 return TRUE;
95 if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj)
96 /* [g.cubes can eat containers and retain all contents
97 as engulfed items, but poly'd player can't do that] */
98 && !Has_contents(obj))
99 return TRUE;
101 /* return (boolean) !!index(comestibles, obj->oclass); */
102 return (boolean) (obj->oclass == FOOD_CLASS);
105 void
106 init_uhunger()
108 u.uhunger = 900;
109 u.uhs = NOT_HUNGRY;
112 /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */
113 static const struct {
114 const char *txt; /* description */
115 int nut; /* nutrition */
116 Bitfield(fodder, 1); /* stocked by health food shops */
117 Bitfield(greasy, 1); /* causes slippery fingers */
118 } tintxts[] = { { "rotten", -50, 0, 0 }, /* ROTTEN_TIN = 0 */
119 { "homemade", 50, 1, 0 }, /* HOMEMADE_TIN = 1 */
120 { "soup made from", 20, 1, 0 },
121 { "french fried", 40, 0, 1 },
122 { "pickled", 40, 1, 0 },
123 { "boiled", 50, 1, 0 },
124 { "smoked", 50, 1, 0 },
125 { "dried", 55, 1, 0 },
126 { "deep fried", 60, 0, 1 },
127 { "szechuan", 70, 1, 0 },
128 { "broiled", 80, 0, 0 },
129 { "stir fried", 80, 0, 1 },
130 { "sauteed", 95, 0, 0 },
131 { "candied", 100, 1, 0 },
132 { "pureed", 500, 1, 0 },
133 { "", 0, 0, 0 } };
134 #define TTSZ SIZE(tintxts)
136 static char *eatmbuf = 0; /* set by cpostfx() */
138 /* called after mimicing is over */
139 STATIC_PTR int
140 eatmdone(VOID_ARGS)
142 /* release `eatmbuf' */
143 if (eatmbuf) {
144 if (nomovemsg == eatmbuf)
145 nomovemsg = 0;
146 free((genericptr_t) eatmbuf), eatmbuf = 0;
148 /* update display */
149 if (youmonst.m_ap_type) {
150 youmonst.m_ap_type = M_AP_NOTHING;
151 newsym(u.ux, u.uy);
153 return 0;
156 /* called when hallucination is toggled */
157 void
158 eatmupdate()
160 const char *altmsg = 0;
161 int altapp = 0; /* lint suppression */
163 if (!eatmbuf || nomovemsg != eatmbuf)
164 return;
166 if (is_obj_mappear(&youmonst,ORANGE) && !Hallucination) {
167 /* revert from hallucinatory to "normal" mimicking */
168 altmsg = "You now prefer mimicking yourself.";
169 altapp = GOLD_PIECE;
170 } else if (is_obj_mappear(&youmonst,GOLD_PIECE) && Hallucination) {
171 /* won't happen; anything which might make immobilized
172 hero begin hallucinating (black light attack, theft
173 of Grayswandir) will terminate the mimicry first */
174 altmsg = "Your rind escaped intact.";
175 altapp = ORANGE;
178 if (altmsg) {
179 /* replace end-of-mimicking message */
180 if (strlen(altmsg) > strlen(eatmbuf)) {
181 free((genericptr_t) eatmbuf);
182 eatmbuf = (char *) alloc(strlen(altmsg) + 1);
184 nomovemsg = strcpy(eatmbuf, altmsg);
185 /* update current image */
186 youmonst.mappearance = altapp;
187 newsym(u.ux, u.uy);
191 /* ``[the(] singular(food, xname) [)]'' */
192 STATIC_OVL const char *
193 food_xname(food, the_pfx)
194 struct obj *food;
195 boolean the_pfx;
197 const char *result;
199 if (food->otyp == CORPSE) {
200 result = corpse_xname(food, (const char *) 0,
201 CXN_SINGULAR | (the_pfx ? CXN_PFX_THE : 0));
202 /* not strictly needed since pname values are capitalized
203 and the() is a no-op for them */
204 if (type_is_pname(&mons[food->corpsenm]))
205 the_pfx = FALSE;
206 } else {
207 /* the ordinary case */
208 result = singular(food, xname);
210 if (the_pfx)
211 result = the(result);
212 return result;
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.
220 * To a full belly all food is bad. (It.)
222 STATIC_OVL void
223 choke(food)
224 struct obj *food;
226 /* only happens if you were satiated */
227 if (u.uhs != SATIATED) {
228 if (!food || food->otyp != AMULET_OF_STRANGULATION)
229 return;
230 } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
231 adjalign(-1); /* gluttony is unchivalrous */
232 You_feel("like a glutton!");
235 exercise(A_CON, FALSE);
237 if (Breathless || (!Strangled && !rn2(20))) {
238 /* choking by eating AoS doesn't involve stuffing yourself */
239 if (food && food->otyp == AMULET_OF_STRANGULATION) {
240 You("choke, but recover your composure.");
241 return;
243 You("stuff yourself and then vomit voluminously.");
244 morehungry(1000); /* you just got *very* sick! */
245 vomit();
246 } else {
247 killer.format = KILLED_BY_AN;
249 * Note all "killer"s below read "Choked on %s" on the
250 * high score list & tombstone. So plan accordingly.
252 if (food) {
253 You("choke over your %s.", foodword(food));
254 if (food->oclass == COIN_CLASS) {
255 Strcpy(killer.name, "very rich meal");
256 } else {
257 killer.format = KILLED_BY;
258 Strcpy(killer.name, killer_xname(food));
260 } else {
261 You("choke over it.");
262 Strcpy(killer.name, "quick snack");
264 You("die...");
265 done(CHOKING);
269 /* modify object wt. depending on time spent consuming it */
270 STATIC_OVL void
271 recalc_wt()
273 struct obj *piece = context.victual.piece;
274 if (!piece) {
275 impossible("recalc_wt without piece");
276 return;
278 debugpline1("Old weight = %d", piece->owt);
279 debugpline2("Used time = %d, Req'd time = %d", context.victual.usedtime,
280 context.victual.reqtime);
281 piece->owt = weight(piece);
282 debugpline1("New weight = %d", piece->owt);
285 /* called when eating interrupted by an event */
286 void
287 reset_eat()
289 /* we only set a flag here - the actual reset process is done after
290 * the round is spent eating.
292 if (context.victual.eating && !context.victual.doreset) {
293 debugpline0("reset_eat...");
294 context.victual.doreset = TRUE;
296 return;
299 STATIC_OVL struct obj *
300 touchfood(otmp)
301 struct obj *otmp;
303 if (otmp->quan > 1L) {
304 if (!carried(otmp))
305 (void) splitobj(otmp, otmp->quan - 1L);
306 else
307 otmp = splitobj(otmp, 1L);
308 debugpline0("split object,");
311 if (!otmp->oeaten) {
312 costly_alteration(otmp, COST_BITE);
313 otmp->oeaten = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
314 : otmp->globby ? otmp->owt
315 : (unsigned) objects[otmp->otyp].oc_nutrition;
318 if (carried(otmp)) {
319 freeinv(otmp);
320 if (inv_cnt(FALSE) >= 52) {
321 sellobj_state(SELL_DONTSELL);
322 dropy(otmp);
323 sellobj_state(SELL_NORMAL);
324 } else {
325 otmp->nomerge = 1; /* used to prevent merge */
326 otmp = addinv(otmp);
327 otmp->nomerge = 0;
330 return otmp;
333 /* When food decays, in the middle of your meal, we don't want to dereference
334 * any dangling pointers, so set it to null (which should still trigger
335 * do_reset_eat() at the beginning of eatfood()) and check for null pointers
336 * in do_reset_eat().
338 void
339 food_disappears(obj)
340 struct obj *obj;
342 if (obj == context.victual.piece) {
343 context.victual.piece = (struct obj *) 0;
344 context.victual.o_id = 0;
346 if (obj->timed)
347 obj_stop_timers(obj);
350 /* renaming an object used to result 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;
357 if (old_obj == context.victual.piece) {
358 context.victual.piece = new_obj;
359 context.victual.o_id = new_obj->o_id;
361 if (old_obj == context.tin.tin) {
362 context.tin.tin = new_obj;
363 context.tin.o_id = new_obj->o_id;
367 STATIC_OVL void
368 do_reset_eat()
370 debugpline0("do_reset_eat...");
371 if (context.victual.piece) {
372 context.victual.o_id = 0;
373 context.victual.piece = touchfood(context.victual.piece);
374 if (context.victual.piece)
375 context.victual.o_id = context.victual.piece->o_id;
376 recalc_wt();
378 context.victual.fullwarn = context.victual.eating =
379 context.victual.doreset = FALSE;
380 /* Do not set canchoke to FALSE; if we continue eating the same object
381 * we need to know if canchoke was set when they started eating it the
382 * previous time. And if we don't continue eating the same object
383 * canchoke always gets recalculated anyway.
385 stop_occupation();
386 newuhs(FALSE);
389 /* called each move during eating process */
390 STATIC_PTR int
391 eatfood(VOID_ARGS)
393 if (!context.victual.piece
394 || (!carried(context.victual.piece)
395 && !obj_here(context.victual.piece, u.ux, u.uy))) {
396 /* maybe it was stolen? */
397 do_reset_eat();
398 return 0;
400 if (!context.victual.eating)
401 return 0;
403 if (++context.victual.usedtime <= context.victual.reqtime) {
404 if (bite())
405 return 0;
406 return 1; /* still busy */
407 } else { /* done */
408 done_eating(TRUE);
409 return 0;
413 STATIC_OVL void
414 done_eating(message)
415 boolean message;
417 struct obj *piece = context.victual.piece;
419 piece->in_use = TRUE;
420 occupation = 0; /* do this early, so newuhs() knows we're done */
421 newuhs(FALSE);
422 if (nomovemsg) {
423 if (message)
424 pline1(nomovemsg);
425 nomovemsg = 0;
426 } else if (message)
427 You("finish eating %s.", food_xname(piece, TRUE));
429 if (piece->otyp == CORPSE || piece->globby)
430 cpostfx(piece->corpsenm);
431 else
432 fpostfx(piece);
434 if (carried(piece))
435 useup(piece);
436 else
437 useupf(piece, 1L);
438 context.victual.piece = (struct obj *) 0;
439 context.victual.o_id = 0;
440 context.victual.fullwarn = context.victual.eating =
441 context.victual.doreset = FALSE;
444 void
445 eating_conducts(pd)
446 struct permonst *pd;
448 u.uconduct.food++;
449 if (!vegan(pd))
450 u.uconduct.unvegan++;
451 if (!vegetarian(pd))
452 violated_vegetarian();
455 /* handle side-effects of mind flayer's tentacle attack */
457 eat_brains(magr, mdef, visflag, dmg_p)
458 struct monst *magr, *mdef;
459 boolean visflag;
460 int *dmg_p; /* for dishing out extra damage in lieu of Int loss */
462 struct permonst *pd = mdef->data;
463 boolean give_nutrit = FALSE;
464 int result = MM_HIT, xtra_dmg = rnd(10);
466 if (noncorporeal(pd)) {
467 if (visflag)
468 pline("%s brain is unharmed.",
469 (mdef == &youmonst) ? "Your" : s_suffix(Monnam(mdef)));
470 return MM_MISS; /* side-effects can't occur */
471 } else if (magr == &youmonst) {
472 You("eat %s brain!", s_suffix(mon_nam(mdef)));
473 } else if (mdef == &youmonst) {
474 Your("brain is eaten!");
475 } else { /* monster against monster */
476 if (visflag)
477 pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
480 if (flesh_petrifies(pd)) {
481 /* mind flayer has attempted to eat the brains of a petrification
482 inducing critter (most likely Medusa; attacking a cockatrice via
483 tentacle-touch should have been caught before reaching this far) */
484 if (magr == &youmonst) {
485 if (!Stone_resistance && !Stoned)
486 make_stoned(5L, (char *) 0, KILLED_BY_AN, pd->mname);
487 } else {
488 /* no need to check for poly_when_stoned or Stone_resistance;
489 mind flayers don't have those capabilities */
490 if (visflag)
491 pline("%s turns to stone!", Monnam(magr));
492 monstone(magr);
493 if (magr->mhp > 0) {
494 /* life-saved; don't continue eating the brains */
495 return MM_MISS;
496 } else {
497 if (magr->mtame && !visflag)
498 /* parallels mhitm.c's brief_feeling */
499 You("have a sad thought for a moment, then it passes.");
500 return MM_AGR_DIED;
505 if (magr == &youmonst) {
507 * player mind flayer is eating something's brain
509 eating_conducts(pd);
510 if (mindless(pd)) { /* (cannibalism not possible here) */
511 pline("%s doesn't notice.", Monnam(mdef));
512 /* all done; no extra harm inflicted upon target */
513 return MM_MISS;
514 } else if (is_rider(pd)) {
515 pline("Ingesting that is fatal.");
516 Sprintf(killer.name, "unwisely ate the brain of %s", pd->mname);
517 killer.format = NO_KILLER_PREFIX;
518 done(DIED);
519 /* life-saving needed to reach here */
520 exercise(A_WIS, FALSE);
521 *dmg_p += xtra_dmg; /* Rider takes extra damage */
522 } else {
523 morehungry(-rnd(30)); /* cannot choke */
524 if (ABASE(A_INT) < AMAX(A_INT)) {
525 /* recover lost Int; won't increase current max */
526 ABASE(A_INT) += rnd(4);
527 if (ABASE(A_INT) > AMAX(A_INT))
528 ABASE(A_INT) = AMAX(A_INT);
529 context.botl = 1;
531 exercise(A_WIS, TRUE);
532 *dmg_p += xtra_dmg;
534 /* targetting another mind flayer or your own underlying species
535 is cannibalism */
536 (void) maybe_cannibal(monsndx(pd), TRUE);
538 } else if (mdef == &youmonst) {
540 * monster mind flayer is eating hero's brain
542 /* no such thing as mindless players */
543 if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
544 static NEARDATA const char brainlessness[] = "brainlessness";
546 if (Lifesaved) {
547 Strcpy(killer.name, brainlessness);
548 killer.format = KILLED_BY;
549 done(DIED);
550 /* amulet of life saving has now been used up */
551 pline("Unfortunately your brain is still gone.");
552 /* sanity check against adding other forms of life-saving */
553 u.uprops[LIFESAVED].extrinsic =
554 u.uprops[LIFESAVED].intrinsic = 0L;
555 } else {
556 Your("last thought fades away.");
558 Strcpy(killer.name, brainlessness);
559 killer.format = KILLED_BY;
560 done(DIED);
561 /* can only get here when in wizard or explore mode and user has
562 explicitly chosen not to die; arbitrarily boost intelligence */
563 ABASE(A_INT) = ATTRMIN(A_INT) + 2;
564 You_feel("like a scarecrow.");
566 give_nutrit = TRUE; /* in case a conflicted pet is doing this */
567 exercise(A_WIS, FALSE);
568 /* caller handles Int and memory loss */
570 } else { /* mhitm */
572 * monster mind flayer is eating another monster's brain
574 if (mindless(pd)) {
575 if (visflag)
576 pline("%s doesn't notice.", Monnam(mdef));
577 return MM_MISS;
578 } else if (is_rider(pd)) {
579 mondied(magr);
580 if (magr->mhp <= 0)
581 result = MM_AGR_DIED;
582 /* Rider takes extra damage regardless of whether attacker dies */
583 *dmg_p += xtra_dmg;
584 } else {
585 *dmg_p += xtra_dmg;
586 give_nutrit = TRUE;
587 if (*dmg_p >= mdef->mhp && visflag)
588 pline("%s last thought fades away...",
589 s_suffix(Monnam(mdef)));
593 if (give_nutrit && magr->mtame && !magr->isminion) {
594 EDOG(magr)->hungrytime += rnd(60);
595 magr->mconf = 0;
598 return result;
601 /* eating a corpse or egg of one's own species is usually naughty */
602 STATIC_OVL boolean
603 maybe_cannibal(pm, allowmsg)
604 int pm;
605 boolean allowmsg;
607 static NEARDATA long ate_brains = 0L;
608 struct permonst *fptr = &mons[pm]; /* food type */
610 /* when poly'd into a mind flayer, multiple tentacle hits in one
611 turn cause multiple digestion checks to occur; avoid giving
612 multiple luck penalties for the same attack */
613 if (moves == ate_brains)
614 return FALSE;
615 ate_brains = moves; /* ate_anything, not just brains... */
617 if (!CANNIBAL_ALLOWED()
618 /* non-cannibalistic heroes shouldn't eat own species ever
619 and also shouldn't eat current species when polymorphed
620 (even if having the form of something which doesn't care
621 about cannibalism--hero's innate traits aren't altered) */
622 && (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) {
623 if (allowmsg) {
624 if (Upolyd && your_race(fptr))
625 You("have a bad feeling deep inside.");
626 You("cannibal! You will regret this!");
628 HAggravate_monster |= FROMOUTSIDE;
629 change_luck(-rn1(4, 2)); /* -5..-2 */
630 return TRUE;
632 return FALSE;
635 STATIC_OVL void
636 cprefx(pm)
637 register int pm;
639 (void) maybe_cannibal(pm, TRUE);
640 if (flesh_petrifies(&mons[pm])) {
641 if (!Stone_resistance
642 && !(poly_when_stoned(youmonst.data)
643 && polymon(PM_STONE_GOLEM))) {
644 Sprintf(killer.name, "tasting %s meat", mons[pm].mname);
645 killer.format = KILLED_BY;
646 You("turn to stone.");
647 done(STONING);
648 if (context.victual.piece)
649 context.victual.eating = FALSE;
650 return; /* lifesaved */
654 switch (pm) {
655 case PM_LITTLE_DOG:
656 case PM_DOG:
657 case PM_LARGE_DOG:
658 case PM_KITTEN:
659 case PM_HOUSECAT:
660 case PM_LARGE_CAT:
661 /* cannibals are allowed to eat domestic animals without penalty */
662 if (!CANNIBAL_ALLOWED()) {
663 You_feel("that eating the %s was a bad idea.", mons[pm].mname);
664 HAggravate_monster |= FROMOUTSIDE;
666 break;
667 case PM_LIZARD:
668 if (Stoned)
669 fix_petrification();
670 break;
671 case PM_DEATH:
672 case PM_PESTILENCE:
673 case PM_FAMINE: {
674 pline("Eating that is instantly fatal.");
675 Sprintf(killer.name, "unwisely ate the body of %s", mons[pm].mname);
676 killer.format = NO_KILLER_PREFIX;
677 done(DIED);
678 /* life-saving needed to reach here */
679 exercise(A_WIS, FALSE);
680 /* It so happens that since we know these monsters */
681 /* cannot appear in tins, context.victual.piece will always */
682 /* be what we want, which is not generally true. */
683 if (revive_corpse(context.victual.piece)) {
684 context.victual.piece = (struct obj *) 0;
685 context.victual.o_id = 0;
687 return;
689 case PM_GREEN_SLIME:
690 if (!Slimed && !Unchanging && !slimeproof(youmonst.data)) {
691 You("don't feel very well.");
692 make_slimed(10L, (char *) 0);
693 delayed_killer(SLIMED, KILLED_BY_AN, "");
695 /* Fall through */
696 default:
697 if (acidic(&mons[pm]) && Stoned)
698 fix_petrification();
699 break;
703 void
704 fix_petrification()
706 char buf[BUFSZ];
708 if (Hallucination)
709 Sprintf(buf, "What a pity--you just ruined a future piece of %sart!",
710 ACURR(A_CHA) > 15 ? "fine " : "");
711 else
712 Strcpy(buf, "You feel limber!");
713 make_stoned(0L, buf, 0, (char *) 0);
717 * If you add an intrinsic that can be gotten by eating a monster, add it
718 * to intrinsic_possible() and givit(). (It must already be in prop.h to
719 * be an intrinsic property.)
720 * It would be very easy to make the intrinsics not try to give you one
721 * that you already had by checking to see if you have it in
722 * intrinsic_possible() instead of givit(), but we're not that nice.
725 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
726 STATIC_OVL int
727 intrinsic_possible(type, ptr)
728 int type;
729 register struct permonst *ptr;
731 int res = 0;
733 #ifdef DEBUG
734 #define ifdebugresist(Msg) \
735 do { \
736 if (res) \
737 debugpline0(Msg); \
738 } while (0)
739 #else
740 #define ifdebugresist(Msg) /*empty*/
741 #endif
742 switch (type) {
743 case FIRE_RES:
744 res = (ptr->mconveys & MR_FIRE) != 0;
745 ifdebugresist("can get fire resistance");
746 break;
747 case SLEEP_RES:
748 res = (ptr->mconveys & MR_SLEEP) != 0;
749 ifdebugresist("can get sleep resistance");
750 break;
751 case COLD_RES:
752 res = (ptr->mconveys & MR_COLD) != 0;
753 ifdebugresist("can get cold resistance");
754 break;
755 case DISINT_RES:
756 res = (ptr->mconveys & MR_DISINT) != 0;
757 ifdebugresist("can get disintegration resistance");
758 break;
759 case SHOCK_RES: /* shock (electricity) resistance */
760 res = (ptr->mconveys & MR_ELEC) != 0;
761 ifdebugresist("can get shock resistance");
762 break;
763 case POISON_RES:
764 res = (ptr->mconveys & MR_POISON) != 0;
765 ifdebugresist("can get poison resistance");
766 break;
767 case TELEPORT:
768 res = can_teleport(ptr);
769 ifdebugresist("can get teleport");
770 break;
771 case TELEPORT_CONTROL:
772 res = control_teleport(ptr);
773 ifdebugresist("can get teleport control");
774 break;
775 case TELEPAT:
776 res = telepathic(ptr);
777 ifdebugresist("can get telepathy");
778 break;
779 default:
780 /* res stays 0 */
781 break;
783 #undef ifdebugresist
784 return res;
787 /* givit() tries to give you an intrinsic based on the monster's level
788 * and what type of intrinsic it is trying to give you.
790 STATIC_OVL void
791 givit(type, ptr)
792 int type;
793 register struct permonst *ptr;
795 register int chance;
797 debugpline1("Attempting to give intrinsic %d", type);
798 /* some intrinsics are easier to get than others */
799 switch (type) {
800 case POISON_RES:
801 if ((ptr == &mons[PM_KILLER_BEE] || ptr == &mons[PM_SCORPION])
802 && !rn2(4))
803 chance = 1;
804 else
805 chance = 15;
806 break;
807 case TELEPORT:
808 chance = 10;
809 break;
810 case TELEPORT_CONTROL:
811 chance = 12;
812 break;
813 case TELEPAT:
814 chance = 1;
815 break;
816 default:
817 chance = 15;
818 break;
821 if (ptr->mlevel <= rn2(chance))
822 return; /* failed die roll */
824 switch (type) {
825 case FIRE_RES:
826 debugpline0("Trying to give fire resistance");
827 if (!(HFire_resistance & FROMOUTSIDE)) {
828 You(Hallucination ? "be chillin'." : "feel a momentary chill.");
829 HFire_resistance |= FROMOUTSIDE;
831 break;
832 case SLEEP_RES:
833 debugpline0("Trying to give sleep resistance");
834 if (!(HSleep_resistance & FROMOUTSIDE)) {
835 You_feel("wide awake.");
836 HSleep_resistance |= FROMOUTSIDE;
838 break;
839 case COLD_RES:
840 debugpline0("Trying to give cold resistance");
841 if (!(HCold_resistance & FROMOUTSIDE)) {
842 You_feel("full of hot air.");
843 HCold_resistance |= FROMOUTSIDE;
845 break;
846 case DISINT_RES:
847 debugpline0("Trying to give disintegration resistance");
848 if (!(HDisint_resistance & FROMOUTSIDE)) {
849 You_feel(Hallucination ? "totally together, man." : "very firm.");
850 HDisint_resistance |= FROMOUTSIDE;
852 break;
853 case SHOCK_RES: /* shock (electricity) resistance */
854 debugpline0("Trying to give shock resistance");
855 if (!(HShock_resistance & FROMOUTSIDE)) {
856 if (Hallucination)
857 You_feel("grounded in reality.");
858 else
859 Your("health currently feels amplified!");
860 HShock_resistance |= FROMOUTSIDE;
862 break;
863 case POISON_RES:
864 debugpline0("Trying to give poison resistance");
865 if (!(HPoison_resistance & FROMOUTSIDE)) {
866 You_feel(Poison_resistance ? "especially healthy." : "healthy.");
867 HPoison_resistance |= FROMOUTSIDE;
869 break;
870 case TELEPORT:
871 debugpline0("Trying to give teleport");
872 if (!(HTeleportation & FROMOUTSIDE)) {
873 You_feel(Hallucination ? "diffuse." : "very jumpy.");
874 HTeleportation |= FROMOUTSIDE;
876 break;
877 case TELEPORT_CONTROL:
878 debugpline0("Trying to give teleport control");
879 if (!(HTeleport_control & FROMOUTSIDE)) {
880 You_feel(Hallucination ? "centered in your personal space."
881 : "in control of yourself.");
882 HTeleport_control |= FROMOUTSIDE;
884 break;
885 case TELEPAT:
886 debugpline0("Trying to give telepathy");
887 if (!(HTelepat & FROMOUTSIDE)) {
888 You_feel(Hallucination ? "in touch with the cosmos."
889 : "a strange mental acuity.");
890 HTelepat |= FROMOUTSIDE;
891 /* If blind, make sure monsters show up. */
892 if (Blind)
893 see_monsters();
895 break;
896 default:
897 debugpline0("Tried to give an impossible intrinsic");
898 break;
902 /* called after completely consuming a corpse */
903 STATIC_OVL void
904 cpostfx(pm)
905 register int pm;
907 register int tmp = 0;
908 int catch_lycanthropy = NON_PM;
910 /* in case `afternmv' didn't get called for previously mimicking
911 gold, clean up now to avoid `eatmbuf' memory leak */
912 if (eatmbuf)
913 (void) eatmdone();
915 switch (pm) {
916 case PM_NEWT:
917 /* MRKR: "eye of newt" may give small magical energy boost */
918 if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
919 int old_uen = u.uen;
920 u.uen += rnd(3);
921 if (u.uen > u.uenmax) {
922 if (!rn2(3))
923 u.uenmax++;
924 u.uen = u.uenmax;
926 if (old_uen != u.uen) {
927 You_feel("a mild buzz.");
928 context.botl = 1;
931 break;
932 case PM_WRAITH:
933 pluslvl(FALSE);
934 break;
935 case PM_HUMAN_WERERAT:
936 catch_lycanthropy = PM_WERERAT;
937 break;
938 case PM_HUMAN_WEREJACKAL:
939 catch_lycanthropy = PM_WEREJACKAL;
940 break;
941 case PM_HUMAN_WEREWOLF:
942 catch_lycanthropy = PM_WEREWOLF;
943 break;
944 case PM_NURSE:
945 if (Upolyd)
946 u.mh = u.mhmax;
947 else
948 u.uhp = u.uhpmax;
949 context.botl = 1;
950 break;
951 case PM_STALKER:
952 if (!Invis) {
953 set_itimeout(&HInvis, (long) rn1(100, 50));
954 if (!Blind && !BInvis)
955 self_invis_message();
956 } else {
957 if (!(HInvis & INTRINSIC))
958 You_feel("hidden!");
959 HInvis |= FROMOUTSIDE;
960 HSee_invisible |= FROMOUTSIDE;
962 newsym(u.ux, u.uy);
963 /*FALLTHRU*/
964 case PM_YELLOW_LIGHT:
965 case PM_GIANT_BAT:
966 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
967 /*FALLTHRU*/
968 case PM_BAT:
969 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
970 break;
971 case PM_GIANT_MIMIC:
972 tmp += 10;
973 /*FALLTHRU*/
974 case PM_LARGE_MIMIC:
975 tmp += 20;
976 /*FALLTHRU*/
977 case PM_SMALL_MIMIC:
978 tmp += 20;
979 if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
980 char buf[BUFSZ];
982 u.uconduct.polyselfs++; /* you're changing form */
983 You_cant("resist the temptation to mimic %s.",
984 Hallucination ? "an orange" : "a pile of gold");
985 /* A pile of gold can't ride. */
986 if (u.usteed)
987 dismount_steed(DISMOUNT_FELL);
988 nomul(-tmp);
989 multi_reason = "pretending to be a pile of gold";
990 Sprintf(buf,
991 Hallucination
992 ? "You suddenly dread being peeled and mimic %s again!"
993 : "You now prefer mimicking %s again.",
994 an(Upolyd ? youmonst.data->mname : urace.noun));
995 eatmbuf = dupstr(buf);
996 nomovemsg = eatmbuf;
997 afternmv = eatmdone;
998 /* ??? what if this was set before? */
999 youmonst.m_ap_type = M_AP_OBJECT;
1000 youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
1001 newsym(u.ux, u.uy);
1002 curs_on_u();
1003 /* make gold symbol show up now */
1004 display_nhwindow(WIN_MAP, TRUE);
1006 break;
1007 case PM_QUANTUM_MECHANIC:
1008 Your("velocity suddenly seems very uncertain!");
1009 if (HFast & INTRINSIC) {
1010 HFast &= ~INTRINSIC;
1011 You("seem slower.");
1012 } else {
1013 HFast |= FROMOUTSIDE;
1014 You("seem faster.");
1016 break;
1017 case PM_LIZARD:
1018 if ((HStun & TIMEOUT) > 2)
1019 make_stunned(2L, FALSE);
1020 if ((HConfusion & TIMEOUT) > 2)
1021 make_confused(2L, FALSE);
1022 break;
1023 case PM_CHAMELEON:
1024 case PM_DOPPELGANGER:
1025 case PM_SANDESTIN: /* moot--they don't leave corpses */
1026 if (Unchanging) {
1027 You_feel("momentarily different."); /* same as poly trap */
1028 } else {
1029 You_feel("a change coming over you.");
1030 polyself(0);
1032 break;
1033 case PM_DISENCHANTER:
1034 /* picks an intrinsic at random and removes it; there's
1035 no feedback if hero already lacks the chosen ability */
1036 debugpline0("using attrcurse to strip an intrinsic");
1037 attrcurse();
1038 break;
1039 case PM_MIND_FLAYER:
1040 case PM_MASTER_MIND_FLAYER:
1041 if (ABASE(A_INT) < ATTRMAX(A_INT)) {
1042 if (!rn2(2)) {
1043 pline("Yum! That was real brain food!");
1044 (void) adjattrib(A_INT, 1, FALSE);
1045 break; /* don't give them telepathy, too */
1047 } else {
1048 pline("For some reason, that tasted bland.");
1050 /*FALLTHRU*/
1051 default: {
1052 struct permonst *ptr = &mons[pm];
1053 boolean conveys_STR = is_giant(ptr);
1054 int i, count;
1056 if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU)
1057 || pm == PM_VIOLET_FUNGUS) {
1058 pline("Oh wow! Great stuff!");
1059 (void) make_hallucinated((HHallucination & TIMEOUT) + 200L, FALSE,
1060 0L);
1063 /* Check the monster for all of the intrinsics. If this
1064 * monster can give more than one, pick one to try to give
1065 * from among all it can give.
1067 * Strength from giants is now treated like an intrinsic
1068 * rather than being given unconditionally.
1070 count = 0; /* number of possible intrinsics */
1071 tmp = 0; /* which one we will try to give */
1072 if (conveys_STR) {
1073 count = 1;
1074 tmp = -1; /* use -1 as fake prop index for STR */
1075 debugpline1("\"Intrinsic\" strength, %d", tmp);
1077 for (i = 1; i <= LAST_PROP; i++) {
1078 if (!intrinsic_possible(i, ptr))
1079 continue;
1080 ++count;
1081 /* a 1 in count chance of replacing the old choice
1082 with this one, and a count-1 in count chance
1083 of keeping the old choice (note that 1 in 1 and
1084 0 in 1 are what we want for the first candidate) */
1085 if (!rn2(count)) {
1086 debugpline2("Intrinsic %d replacing %d", i, tmp);
1087 tmp = i;
1090 /* if strength is the only candidate, give it 50% chance */
1091 if (conveys_STR && count == 1 && !rn2(2))
1092 tmp = 0;
1093 /* if something was chosen, give it now (givit() might fail) */
1094 if (tmp == -1)
1095 gainstr((struct obj *) 0, 0, TRUE);
1096 else if (tmp > 0)
1097 givit(tmp, ptr);
1098 break;
1099 } /* default case */
1100 } /* switch */
1102 if (catch_lycanthropy >= LOW_PM) {
1103 set_ulycn(catch_lycanthropy);
1104 retouch_equipment(2);
1106 return;
1109 void
1110 violated_vegetarian()
1112 u.uconduct.unvegetarian++;
1113 if (Role_if(PM_MONK)) {
1114 You_feel("guilty.");
1115 adjalign(-1);
1117 return;
1120 /* common code to check and possibly charge for 1 context.tin.tin,
1121 * will split() context.tin.tin if necessary */
1122 STATIC_PTR void
1123 costly_tin(alter_type)
1124 int alter_type; /* COST_xxx */
1126 struct obj *tin = context.tin.tin;
1128 if (carried(tin) ? tin->unpaid
1129 : (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) {
1130 if (tin->quan > 1L) {
1131 tin = context.tin.tin = splitobj(tin, 1L);
1132 context.tin.o_id = tin->o_id;
1134 costly_alteration(tin, alter_type);
1139 tin_variety_txt(s, tinvariety)
1140 char *s;
1141 int *tinvariety;
1143 int k, l;
1145 if (s && tinvariety) {
1146 *tinvariety = -1;
1147 for (k = 0; k < TTSZ - 1; ++k) {
1148 l = (int) strlen(tintxts[k].txt);
1149 if (!strncmpi(s, tintxts[k].txt, l) && ((int) strlen(s) > l)
1150 && s[l] == ' ') {
1151 *tinvariety = k;
1152 return (l + 1);
1156 return 0;
1160 * This assumes that buf already contains the word "tin",
1161 * as is the case with caller xname().
1163 void
1164 tin_details(obj, mnum, buf)
1165 struct obj *obj;
1166 int mnum;
1167 char *buf;
1169 char buf2[BUFSZ];
1170 int r = tin_variety(obj, TRUE);
1172 if (obj && buf) {
1173 if (r == SPINACH_TIN)
1174 Strcat(buf, " of spinach");
1175 else if (mnum == NON_PM)
1176 Strcpy(buf, "empty tin");
1177 else {
1178 if ((obj->cknown || iflags.override_ID) && obj->spe < 0) {
1179 if (r == ROTTEN_TIN || r == HOMEMADE_TIN) {
1180 /* put these before the word tin */
1181 Sprintf(buf2, "%s %s of ", tintxts[r].txt, buf);
1182 Strcpy(buf, buf2);
1183 } else {
1184 Sprintf(eos(buf), " of %s ", tintxts[r].txt);
1186 } else {
1187 Strcpy(eos(buf), " of ");
1189 if (vegetarian(&mons[mnum]))
1190 Sprintf(eos(buf), "%s", mons[mnum].mname);
1191 else
1192 Sprintf(eos(buf), "%s meat", mons[mnum].mname);
1197 void
1198 set_tin_variety(obj, forcetype)
1199 struct obj *obj;
1200 int forcetype;
1202 register int r;
1204 if (forcetype == SPINACH_TIN
1205 || (forcetype == HEALTHY_TIN
1206 && (obj->corpsenm == NON_PM /* empty or already spinach */
1207 || !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */
1208 obj->corpsenm = NON_PM; /* not based on any monster */
1209 obj->spe = 1; /* spinach */
1210 return;
1211 } else if (forcetype == HEALTHY_TIN) {
1212 r = tin_variety(obj, FALSE);
1213 if (r < 0 || r >= TTSZ)
1214 r = ROTTEN_TIN; /* shouldn't happen */
1215 while ((r == ROTTEN_TIN && !obj->cursed) || !tintxts[r].fodder)
1216 r = rn2(TTSZ - 1);
1217 } else if (forcetype >= 0 && forcetype < TTSZ - 1) {
1218 r = forcetype;
1219 } else { /* RANDOM_TIN */
1220 r = rn2(TTSZ - 1); /* take your pick */
1221 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1222 r = HOMEMADE_TIN; /* lizards don't rot */
1224 obj->spe = -(r + 1); /* offset by 1 to allow index 0 */
1227 STATIC_OVL int
1228 tin_variety(obj, disp)
1229 struct obj *obj;
1230 boolean disp; /* we're just displaying so leave things alone */
1232 register int r;
1234 if (obj->spe == 1) {
1235 r = SPINACH_TIN;
1236 } else if (obj->cursed) {
1237 r = ROTTEN_TIN; /* always rotten if cursed */
1238 } else if (obj->spe < 0) {
1239 r = -(obj->spe);
1240 --r; /* get rid of the offset */
1241 } else
1242 r = rn2(TTSZ - 1);
1244 if (!disp && r == HOMEMADE_TIN && !obj->blessed && !rn2(7))
1245 r = ROTTEN_TIN; /* some homemade tins go bad */
1247 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1248 r = HOMEMADE_TIN; /* lizards don't rot */
1249 return r;
1252 STATIC_OVL void
1253 consume_tin(mesg)
1254 const char *mesg;
1256 const char *what;
1257 int which, mnum, r;
1258 struct obj *tin = context.tin.tin;
1260 r = tin_variety(tin, FALSE);
1261 if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) {
1262 b_trapped("tin", 0);
1263 costly_tin(COST_DSTROY);
1264 goto use_up_tin;
1267 pline1(mesg); /* "You succeed in opening the tin." */
1269 if (r != SPINACH_TIN) {
1270 mnum = tin->corpsenm;
1271 if (mnum == NON_PM) {
1272 pline("It turns out to be empty.");
1273 tin->dknown = tin->known = 1;
1274 costly_tin(COST_OPEN);
1275 goto use_up_tin;
1278 which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1279 if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1280 && (Stone_resistance || Hallucination)) {
1281 what = "chicken";
1282 which = 1; /* suppress pluralization */
1283 } else if (Hallucination) {
1284 what = rndmonnam(NULL);
1285 } else {
1286 what = mons[mnum].mname;
1287 if (the_unique_pm(&mons[mnum]))
1288 which = 2;
1289 else if (type_is_pname(&mons[mnum]))
1290 which = 1;
1292 if (which == 0)
1293 what = makeplural(what);
1294 else if (which == 2)
1295 what = the(what);
1297 pline("It smells like %s.", what);
1298 if (yn("Eat it?") == 'n') {
1299 if (flags.verbose)
1300 You("discard the open tin.");
1301 if (!Hallucination)
1302 tin->dknown = tin->known = 1;
1303 costly_tin(COST_OPEN);
1304 goto use_up_tin;
1307 /* in case stop_occupation() was called on previous meal */
1308 context.victual.piece = (struct obj *) 0;
1309 context.victual.o_id = 0;
1310 context.victual.fullwarn = context.victual.eating =
1311 context.victual.doreset = FALSE;
1313 You("consume %s %s.", tintxts[r].txt, mons[mnum].mname);
1315 eating_conducts(&mons[mnum]);
1317 tin->dknown = tin->known = 1;
1318 cprefx(mnum);
1319 cpostfx(mnum);
1321 /* charge for one at pre-eating cost */
1322 costly_tin(COST_OPEN);
1324 if (tintxts[r].nut < 0) /* rotten */
1325 make_vomiting((long) rn1(15, 10), FALSE);
1326 else
1327 lesshungry(tintxts[r].nut);
1329 if (tintxts[r].greasy) {
1330 /* Assume !Glib, because you can't open tins when Glib. */
1331 incr_itimeout(&Glib, rnd(15));
1332 pline("Eating %s food made your %s very slippery.",
1333 tintxts[r].txt, makeplural(body_part(FINGER)));
1336 } else { /* spinach... */
1337 if (tin->cursed) {
1338 pline("It contains some decaying%s%s substance.",
1339 Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
1340 } else {
1341 pline("It contains spinach.");
1342 tin->dknown = tin->known = 1;
1345 if (yn("Eat it?") == 'n') {
1346 if (flags.verbose)
1347 You("discard the open tin.");
1348 costly_tin(COST_OPEN);
1349 goto use_up_tin;
1353 * Same order as with non-spinach above:
1354 * conduct update, side-effects, shop handling, and nutrition.
1356 u.uconduct
1357 .food++; /* don't need vegan/vegetarian checks for spinach */
1358 if (!tin->cursed)
1359 pline("This makes you feel like %s!",
1360 Hallucination ? "Swee'pea" : "Popeye");
1361 gainstr(tin, 0, FALSE);
1363 costly_tin(COST_OPEN);
1365 lesshungry(tin->blessed
1366 ? 600 /* blessed */
1367 : !tin->cursed
1368 ? (400 + rnd(200)) /* uncursed */
1369 : (200 + rnd(400))); /* cursed */
1372 use_up_tin:
1373 if (carried(tin))
1374 useup(tin);
1375 else
1376 useupf(tin, 1L);
1377 context.tin.tin = (struct obj *) 0;
1378 context.tin.o_id = 0;
1381 /* called during each move whilst opening a tin */
1382 STATIC_PTR int
1383 opentin(VOID_ARGS)
1385 /* perhaps it was stolen (although that should cause interruption) */
1386 if (!carried(context.tin.tin)
1387 && (!obj_here(context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE)))
1388 return 0; /* %% probably we should use tinoid */
1389 if (context.tin.usedtime++ >= 50) {
1390 You("give up your attempt to open the tin.");
1391 return 0;
1393 if (context.tin.usedtime < context.tin.reqtime)
1394 return 1; /* still busy */
1396 consume_tin("You succeed in opening the tin.");
1397 return 0;
1400 /* called when starting to open a tin */
1401 STATIC_OVL void
1402 start_tin(otmp)
1403 struct obj *otmp;
1405 const char *mesg = 0;
1406 register int tmp;
1408 if (metallivorous(youmonst.data)) {
1409 mesg = "You bite right into the metal tin...";
1410 tmp = 0;
1411 } else if (cantwield(youmonst.data)) { /* nohands || verysmall */
1412 You("cannot handle the tin properly to open it.");
1413 return;
1414 } else if (otmp->blessed) {
1415 /* 50/50 chance for immediate access vs 1 turn delay (unless
1416 wielding blessed tin opener which always yields immediate
1417 access); 1 turn delay case is non-deterministic: getting
1418 interrupted and retrying might yield another 1 turn delay
1419 or might open immediately on 2nd (or 3rd, 4th, ...) try */
1420 tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : rn2(2);
1421 if (!tmp)
1422 mesg = "The tin opens like magic!";
1423 else
1424 pline_The("tin seems easy to open.");
1425 } else if (uwep) {
1426 switch (uwep->otyp) {
1427 case TIN_OPENER:
1428 mesg = "You easily open the tin."; /* iff tmp==0 */
1429 tmp = rn2(uwep->cursed ? 3 : !uwep->blessed ? 2 : 1);
1430 break;
1431 case DAGGER:
1432 case SILVER_DAGGER:
1433 case ELVEN_DAGGER:
1434 case ORCISH_DAGGER:
1435 case ATHAME:
1436 case KNIFE:
1437 case STILETTO:
1438 case CRYSKNIFE:
1439 tmp = 3;
1440 break;
1441 case PICK_AXE:
1442 case AXE:
1443 tmp = 6;
1444 break;
1445 default:
1446 goto no_opener;
1448 pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0));
1449 } else {
1450 no_opener:
1451 pline("It is not so easy to open this tin.");
1452 if (Glib) {
1453 pline_The("tin slips from your %s.",
1454 makeplural(body_part(FINGER)));
1455 if (otmp->quan > 1L) {
1456 otmp = splitobj(otmp, 1L);
1458 if (carried(otmp))
1459 dropx(otmp);
1460 else
1461 stackobj(otmp);
1462 return;
1464 tmp = rn1(1 + 500 / ((int) (ACURR(A_DEX) + ACURRSTR)), 10);
1467 context.tin.tin = otmp;
1468 context.tin.o_id = otmp->o_id;
1469 if (!tmp) {
1470 consume_tin(mesg); /* begin immediately */
1471 } else {
1472 context.tin.reqtime = tmp;
1473 context.tin.usedtime = 0;
1474 set_occupation(opentin, "opening the tin", 0);
1476 return;
1479 /* called when waking up after fainting */
1481 Hear_again(VOID_ARGS)
1483 /* Chance of deafness going away while fainted/sleeping/etc. */
1484 if (!rn2(2)) {
1485 make_deaf(0L, FALSE);
1486 context.botl = TRUE;
1488 return 0;
1491 /* called on the "first bite" of rotten food */
1492 STATIC_OVL int
1493 rottenfood(obj)
1494 struct obj *obj;
1496 pline("Blecch! Rotten %s!", foodword(obj));
1497 if (!rn2(4)) {
1498 if (Hallucination)
1499 You_feel("rather trippy.");
1500 else
1501 You_feel("rather %s.", body_part(LIGHT_HEADED));
1502 make_confused(HConfusion + d(2, 4), FALSE);
1503 } else if (!rn2(4) && !Blind) {
1504 pline("Everything suddenly goes dark.");
1505 /* hero is not Blind, but Blinded timer might be nonzero if
1506 blindness is being overridden by the Eyes of the Overworld */
1507 make_blinded((Blinded & TIMEOUT) + (long) d(2, 10), FALSE);
1508 if (!Blind)
1509 Your1(vision_clears);
1510 } else if (!rn2(3)) {
1511 const char *what, *where;
1512 int duration = rnd(10);
1514 if (!Blind)
1515 what = "goes", where = "dark";
1516 else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
1517 what = "you lose control of", where = "yourself";
1518 else
1519 what = "you slap against the",
1520 where = (u.usteed) ? "saddle" : surface(u.ux, u.uy);
1521 pline_The("world spins and %s %s.", what, where);
1522 incr_itimeout(&HDeaf, duration);
1523 context.botl = TRUE;
1524 nomul(-duration);
1525 multi_reason = "unconscious from rotten food";
1526 nomovemsg = "You are conscious again.";
1527 afternmv = Hear_again;
1528 return 1;
1530 return 0;
1533 /* called when a corpse is selected as food */
1534 STATIC_OVL int
1535 eatcorpse(otmp)
1536 struct obj *otmp;
1538 int retcode = 0, tp = 0, mnum = otmp->corpsenm;
1539 long rotted = 0L;
1540 boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
1541 && !poly_when_stoned(youmonst.data)),
1542 slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging
1543 && !slimeproof(youmonst.data)),
1544 glob = otmp->globby ? TRUE : FALSE;
1546 /* KMH, conduct */
1547 if (!vegan(&mons[mnum]))
1548 u.uconduct.unvegan++;
1549 if (!vegetarian(&mons[mnum]))
1550 violated_vegetarian();
1552 if (!nonrotting_corpse(mnum)) {
1553 long age = peek_at_iced_corpse_age(otmp);
1555 rotted = (monstermoves - age) / (10L + rn2(20));
1556 if (otmp->cursed)
1557 rotted += 2L;
1558 else if (otmp->blessed)
1559 rotted -= 2L;
1562 if (mnum != PM_ACID_BLOB && !stoneable && !slimeable && rotted > 5L) {
1563 boolean cannibal = maybe_cannibal(mnum, FALSE);
1565 pline("Ulch - that %s was tainted%s!",
1566 (mons[mnum].mlet == S_FUNGUS) ? "fungoid vegetation"
1567 : glob ? "glob"
1568 : vegetarian(&mons[mnum]) ? "protoplasm"
1569 : "meat",
1570 cannibal ? ", you cannibal" : "");
1571 if (Sick_resistance) {
1572 pline("It doesn't seem at all sickening, though...");
1573 } else {
1574 long sick_time;
1576 sick_time = (long) rn1(10, 10);
1577 /* make sure new ill doesn't result in improvement */
1578 if (Sick && (sick_time > Sick))
1579 sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1580 make_sick(sick_time, corpse_xname(otmp, "rotted", CXN_NORMAL),
1581 TRUE, SICK_VOMITABLE);
1583 if (carried(otmp))
1584 useup(otmp);
1585 else
1586 useupf(otmp, 1L);
1587 return 2;
1588 } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1589 tp++;
1590 You("have a very bad case of stomach acid."); /* not body_part() */
1591 losehp(rnd(15), !glob ? "acidic corpse" : "acidic glob",
1592 KILLED_BY_AN); /* acid damage */
1593 } else if (poisonous(&mons[mnum]) && rn2(5)) {
1594 tp++;
1595 pline("Ecch - that must have been poisonous!");
1596 if (!Poison_resistance) {
1597 losestr(rnd(4));
1598 losehp(rnd(15), !glob ? "poisonous corpse" : "posionous glob",
1599 KILLED_BY_AN);
1600 } else
1601 You("seem unaffected by the poison.");
1602 /* now any corpse left too long will make you mildly ill */
1603 } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) {
1604 tp++;
1605 You_feel("%ssick.", (Sick) ? "very " : "");
1606 losehp(rnd(8), !glob ? "cadaver" : "rotted glob", KILLED_BY_AN);
1609 /* delay is weight dependent */
1610 context.victual.reqtime = 3 + ((!glob ? mons[mnum].cwt : otmp->owt) >> 6);
1612 if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) {
1613 if (rottenfood(otmp)) {
1614 otmp->orotten = TRUE;
1615 (void) touchfood(otmp);
1616 retcode = 1;
1619 if (!mons[otmp->corpsenm].cnutrit) {
1620 /* no nutrition: rots away, no message if you passed out */
1621 if (!retcode)
1622 pline_The("corpse rots away completely.");
1623 if (carried(otmp))
1624 useup(otmp);
1625 else
1626 useupf(otmp, 1L);
1627 retcode = 2;
1630 if (!retcode)
1631 consume_oeaten(otmp, 2); /* oeaten >>= 2 */
1632 } else if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1633 && (Stone_resistance || Hallucination)) {
1634 pline("This tastes just like chicken!");
1635 } else if (mnum == PM_FLOATING_EYE && u.umonnum == PM_RAVEN) {
1636 You("peck the eyeball with delight.");
1637 } else {
1638 /* [is this right? omnivores end up always disliking the taste] */
1639 boolean yummy = vegan(&mons[mnum])
1640 ? (!carnivorous(youmonst.data)
1641 && herbivorous(youmonst.data))
1642 : (carnivorous(youmonst.data)
1643 && !herbivorous(youmonst.data));
1645 pline("%s%s %s!",
1646 type_is_pname(&mons[mnum])
1647 ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ",
1648 food_xname(otmp, FALSE),
1649 Hallucination
1650 ? (yummy ? ((u.umonnum == PM_TIGER) ? "is gr-r-reat"
1651 : "is gnarly")
1652 : "is grody")
1653 : (yummy ? "is delicious" : "tastes terrible"));
1656 return retcode;
1659 /* called as you start to eat */
1660 STATIC_OVL void
1661 start_eating(otmp)
1662 struct obj *otmp;
1664 const char *old_nomovemsg, *save_nomovemsg;
1666 debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp,
1667 (unsigned long) context.victual.piece);
1668 debugpline1("reqtime = %d", context.victual.reqtime);
1669 debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1670 debugpline1("nmod = %d", context.victual.nmod);
1671 debugpline1("oeaten = %d", otmp->oeaten);
1672 context.victual.fullwarn = context.victual.doreset = FALSE;
1673 context.victual.eating = TRUE;
1675 if (otmp->otyp == CORPSE || otmp->globby) {
1676 cprefx(context.victual.piece->corpsenm);
1677 if (!context.victual.piece || !context.victual.eating) {
1678 /* rider revived, or died and lifesaved */
1679 return;
1683 old_nomovemsg = nomovemsg;
1684 if (bite()) {
1685 /* survived choking, finish off food that's nearly done;
1686 need this to handle cockatrice eggs, fortune cookies, etc */
1687 if (++context.victual.usedtime >= context.victual.reqtime) {
1688 /* don't want done_eating() to issue nomovemsg if it
1689 is due to vomit() called by bite() */
1690 save_nomovemsg = nomovemsg;
1691 if (!old_nomovemsg)
1692 nomovemsg = 0;
1693 done_eating(FALSE);
1694 if (!old_nomovemsg)
1695 nomovemsg = save_nomovemsg;
1697 return;
1700 if (++context.victual.usedtime >= context.victual.reqtime) {
1701 /* print "finish eating" message if they just resumed -dlc */
1702 done_eating(context.victual.reqtime > 1 ? TRUE : FALSE);
1703 return;
1706 Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1707 set_occupation(eatfood, msgbuf, 0);
1711 * called on "first bite" of (non-corpse) food.
1712 * used for non-rotten non-tin non-corpse food
1714 STATIC_OVL void
1715 fprefx(otmp)
1716 struct obj *otmp;
1718 switch (otmp->otyp) {
1719 case FOOD_RATION:
1720 if (u.uhunger <= 200)
1721 pline(Hallucination ? "Oh wow, like, superior, man!"
1722 : "That food really hit the spot!");
1723 else if (u.uhunger <= 700)
1724 pline("That satiated your %s!", body_part(STOMACH));
1725 break;
1726 case TRIPE_RATION:
1727 if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1728 pline("That tripe ration was surprisingly good!");
1729 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
1730 pline(Hallucination ? "Tastes great! Less filling!"
1731 : "Mmm, tripe... not bad!");
1732 else {
1733 pline("Yak - dog food!");
1734 more_experienced(1, 0);
1735 newexplevel();
1736 /* not cannibalism, but we use similar criteria
1737 for deciding whether to be sickened by this meal */
1738 if (rn2(2) && !CANNIBAL_ALLOWED())
1739 make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE);
1741 break;
1742 case MEATBALL:
1743 case MEAT_STICK:
1744 case HUGE_CHUNK_OF_MEAT:
1745 case MEAT_RING:
1746 goto give_feedback;
1747 case CLOVE_OF_GARLIC:
1748 if (is_undead(youmonst.data)) {
1749 make_vomiting((long) rn1(context.victual.reqtime, 5), FALSE);
1750 break;
1752 /* else FALLTHRU */
1753 default:
1754 if (otmp->otyp == SLIME_MOLD && !otmp->cursed
1755 && otmp->spe == context.current_fruit) {
1756 pline("My, that was a %s %s!",
1757 Hallucination ? "primo" : "yummy",
1758 singular(otmp, xname));
1759 } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
1760 ; /* skip core joke; feedback deferred til fpostfx() */
1762 #if defined(MAC) || defined(MACOSX)
1763 /* KMH -- Why should Unix have all the fun?
1764 We check MACOSX before UNIX to get the Apple-specific apple
1765 message; the '#if UNIX' code will still kick in for pear. */
1766 } else if (otmp->otyp == APPLE) {
1767 pline("Delicious! Must be a Macintosh!");
1768 #endif
1770 #ifdef UNIX
1771 } else if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1772 if (!Hallucination) {
1773 pline("Core dumped.");
1774 } else {
1775 /* This is based on an old Usenet joke, a fake a.out manual
1776 * page
1778 int x = rnd(100);
1780 pline("%s -- core dumped.",
1781 (x <= 75)
1782 ? "Segmentation fault"
1783 : (x <= 99)
1784 ? "Bus error"
1785 : "Yo' mama");
1787 #endif
1788 } else if (otmp->otyp == EGG && stale_egg(otmp)) {
1789 pline("Ugh. Rotten egg."); /* perhaps others like it */
1790 /* increasing existing nausea means that it will take longer
1791 before eventual vomit, but also means that constitution
1792 will be abused more times before illness completes */
1793 make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE);
1794 } else {
1795 give_feedback:
1796 pline("This %s is %s", singular(otmp, xname),
1797 otmp->cursed
1798 ? (Hallucination ? "grody!" : "terrible!")
1799 : (otmp->otyp == CRAM_RATION
1800 || otmp->otyp == K_RATION
1801 || otmp->otyp == C_RATION)
1802 ? "bland."
1803 : Hallucination ? "gnarly!" : "delicious!");
1805 break; /* default */
1806 } /* switch */
1809 /* increment a combat intrinsic with limits on its growth */
1810 STATIC_OVL int
1811 bounded_increase(old, inc, typ)
1812 int old, inc, typ;
1814 int absold, absinc, sgnold, sgninc;
1816 /* don't include any amount coming from worn rings */
1817 if (uright && uright->otyp == typ)
1818 old -= uright->spe;
1819 if (uleft && uleft->otyp == typ)
1820 old -= uleft->spe;
1821 absold = abs(old), absinc = abs(inc);
1822 sgnold = sgn(old), sgninc = sgn(inc);
1824 if (absinc == 0 || sgnold != sgninc || absold + absinc < 10) {
1825 ; /* use inc as-is */
1826 } else if (absold + absinc < 20) {
1827 absinc = rnd(absinc); /* 1..n */
1828 if (absold + absinc < 10)
1829 absinc = 10 - absold;
1830 inc = sgninc * absinc;
1831 } else if (absold + absinc < 40) {
1832 absinc = rn2(absinc) ? 1 : 0;
1833 if (absold + absinc < 20)
1834 absinc = rnd(20 - absold);
1835 inc = sgninc * absinc;
1836 } else {
1837 inc = 0; /* no further increase allowed via this method */
1839 return old + inc;
1842 STATIC_OVL void
1843 accessory_has_effect(otmp)
1844 struct obj *otmp;
1846 pline("Magic spreads through your body as you digest the %s.",
1847 otmp->oclass == RING_CLASS ? "ring" : "amulet");
1850 STATIC_OVL void
1851 eataccessory(otmp)
1852 struct obj *otmp;
1854 int typ = otmp->otyp;
1855 long oldprop;
1857 /* Note: rings are not so common that this is unbalancing. */
1858 /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1859 oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
1860 if (otmp == uleft || otmp == uright) {
1861 Ring_gone(otmp);
1862 if (u.uhp <= 0)
1863 return; /* died from sink fall */
1865 otmp->known = otmp->dknown = 1; /* by taste */
1866 if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
1867 switch (otmp->otyp) {
1868 default:
1869 if (!objects[typ].oc_oprop)
1870 break; /* should never happen */
1872 if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1873 accessory_has_effect(otmp);
1875 u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1877 switch (typ) {
1878 case RIN_SEE_INVISIBLE:
1879 set_mimic_blocking();
1880 see_monsters();
1881 if (Invis && !oldprop && !ESee_invisible
1882 && !perceives(youmonst.data) && !Blind) {
1883 newsym(u.ux, u.uy);
1884 pline("Suddenly you can see yourself.");
1885 makeknown(typ);
1887 break;
1888 case RIN_INVISIBILITY:
1889 if (!oldprop && !EInvis && !BInvis && !See_invisible
1890 && !Blind) {
1891 newsym(u.ux, u.uy);
1892 Your("body takes on a %s transparency...",
1893 Hallucination ? "normal" : "strange");
1894 makeknown(typ);
1896 break;
1897 case RIN_PROTECTION_FROM_SHAPE_CHAN:
1898 rescham();
1899 break;
1900 case RIN_LEVITATION:
1901 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1902 u.uprops[LEVITATION].intrinsic = oldprop;
1903 if (!Levitation) {
1904 float_up();
1905 incr_itimeout(&HLevitation, d(10, 20));
1906 makeknown(typ);
1908 break;
1909 } /* inner switch */
1910 break; /* default case of outer switch */
1912 case RIN_ADORNMENT:
1913 accessory_has_effect(otmp);
1914 if (adjattrib(A_CHA, otmp->spe, -1))
1915 makeknown(typ);
1916 break;
1917 case RIN_GAIN_STRENGTH:
1918 accessory_has_effect(otmp);
1919 if (adjattrib(A_STR, otmp->spe, -1))
1920 makeknown(typ);
1921 break;
1922 case RIN_GAIN_CONSTITUTION:
1923 accessory_has_effect(otmp);
1924 if (adjattrib(A_CON, otmp->spe, -1))
1925 makeknown(typ);
1926 break;
1927 case RIN_INCREASE_ACCURACY:
1928 accessory_has_effect(otmp);
1929 u.uhitinc = (schar) bounded_increase((int) u.uhitinc, otmp->spe,
1930 RIN_INCREASE_ACCURACY);
1931 break;
1932 case RIN_INCREASE_DAMAGE:
1933 accessory_has_effect(otmp);
1934 u.udaminc = (schar) bounded_increase((int) u.udaminc, otmp->spe,
1935 RIN_INCREASE_DAMAGE);
1936 break;
1937 case RIN_PROTECTION:
1938 accessory_has_effect(otmp);
1939 HProtection |= FROMOUTSIDE;
1940 u.ublessed = bounded_increase(u.ublessed, otmp->spe,
1941 RIN_PROTECTION);
1942 context.botl = 1;
1943 break;
1944 case RIN_FREE_ACTION:
1945 /* Give sleep resistance instead */
1946 if (!(HSleep_resistance & FROMOUTSIDE))
1947 accessory_has_effect(otmp);
1948 if (!Sleep_resistance)
1949 You_feel("wide awake.");
1950 HSleep_resistance |= FROMOUTSIDE;
1951 break;
1952 case AMULET_OF_CHANGE:
1953 accessory_has_effect(otmp);
1954 makeknown(typ);
1955 change_sex();
1956 You("are suddenly very %s!",
1957 flags.female ? "feminine" : "masculine");
1958 context.botl = 1;
1959 break;
1960 case AMULET_OF_UNCHANGING:
1961 /* un-change: it's a pun */
1962 if (!Unchanging && Upolyd) {
1963 accessory_has_effect(otmp);
1964 makeknown(typ);
1965 rehumanize();
1967 break;
1968 case AMULET_OF_STRANGULATION: /* bad idea! */
1969 /* no message--this gives no permanent effect */
1970 choke(otmp);
1971 break;
1972 case AMULET_OF_RESTFUL_SLEEP: { /* another bad idea! */
1973 long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT);
1975 if (!(HSleepy & FROMOUTSIDE))
1976 accessory_has_effect(otmp);
1977 HSleepy |= FROMOUTSIDE;
1978 /* might also be wearing one; use shorter of two timeouts */
1979 if (newnap < oldnap || oldnap == 0L)
1980 HSleepy = (HSleepy & ~TIMEOUT) | newnap;
1981 break;
1983 case RIN_SUSTAIN_ABILITY:
1984 case AMULET_OF_LIFE_SAVING:
1985 case AMULET_OF_REFLECTION: /* nice try */
1986 /* can't eat Amulet of Yendor or fakes,
1987 * and no oc_prop even if you could -3.
1989 break;
1994 /* called after eating non-food */
1995 STATIC_OVL void
1996 eatspecial()
1998 struct obj *otmp = context.victual.piece;
2000 /* lesshungry wants an occupation to handle choke messages correctly */
2001 set_occupation(eatfood, "eating non-food", 0);
2002 lesshungry(context.victual.nmod);
2003 occupation = 0;
2004 context.victual.piece = (struct obj *) 0;
2005 context.victual.o_id = 0;
2006 context.victual.eating = 0;
2007 if (otmp->oclass == COIN_CLASS) {
2008 if (carried(otmp))
2009 useupall(otmp);
2010 else
2011 useupf(otmp, otmp->quan);
2012 vault_gd_watching(GD_EATGOLD);
2013 return;
2015 #ifdef MAIL
2016 if (otmp->otyp == SCR_MAIL) {
2017 /* no nutrition */
2018 pline("This junk mail is less than satisfying.");
2020 #endif
2021 if (otmp->oclass == POTION_CLASS) {
2022 otmp->quan++; /* dopotion() does a useup() */
2023 (void) dopotion(otmp);
2024 } else if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) {
2025 eataccessory(otmp);
2026 } else if (otmp->otyp == LEASH && otmp->leashmon) {
2027 o_unleash(otmp);
2030 /* KMH -- idea by "Tommy the Terrorist" */
2031 if (otmp->otyp == TRIDENT && !otmp->cursed) {
2032 /* sugarless chewing gum which used to be heavily advertised on TV */
2033 pline(Hallucination ? "Four out of five dentists agree."
2034 : "That was pure chewing satisfaction!");
2035 exercise(A_WIS, TRUE);
2037 if (otmp->otyp == FLINT && !otmp->cursed) {
2038 /* chewable vitamin for kids based on "The Flintstones" TV cartoon */
2039 pline("Yabba-dabba delicious!");
2040 exercise(A_CON, TRUE);
2043 if (otmp == uwep && otmp->quan == 1L)
2044 uwepgone();
2045 if (otmp == uquiver && otmp->quan == 1L)
2046 uqwepgone();
2047 if (otmp == uswapwep && otmp->quan == 1L)
2048 uswapwepgone();
2050 if (otmp == uball)
2051 unpunish();
2052 if (otmp == uchain)
2053 unpunish(); /* but no useup() */
2054 else if (carried(otmp))
2055 useup(otmp);
2056 else
2057 useupf(otmp, 1L);
2060 /* NOTE: the order of these words exactly corresponds to the
2061 order of oc_material values #define'd in objclass.h. */
2062 static const char *foodwords[] = {
2063 "meal", "liquid", "wax", "food", "meat", "paper",
2064 "cloth", "leather", "wood", "bone", "scale", "metal",
2065 "metal", "metal", "silver", "gold", "platinum", "mithril",
2066 "plastic", "glass", "rich food", "stone"
2069 STATIC_OVL const char *
2070 foodword(otmp)
2071 struct obj *otmp;
2073 if (otmp->oclass == FOOD_CLASS)
2074 return "food";
2075 if (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS
2076 && otmp->dknown)
2077 makeknown(otmp->otyp);
2078 return foodwords[objects[otmp->otyp].oc_material];
2081 /* called after consuming (non-corpse) food */
2082 STATIC_OVL void
2083 fpostfx(otmp)
2084 struct obj *otmp;
2086 switch (otmp->otyp) {
2087 case SPRIG_OF_WOLFSBANE:
2088 if (u.ulycn >= LOW_PM || is_were(youmonst.data))
2089 you_unwere(TRUE);
2090 break;
2091 case CARROT:
2092 if (!u.uswallow
2093 || !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))
2094 make_blinded((long) u.ucreamed, TRUE);
2095 break;
2096 case FORTUNE_COOKIE:
2097 outrumor(bcsign(otmp), BY_COOKIE);
2098 if (!Blind)
2099 u.uconduct.literate++;
2100 break;
2101 case LUMP_OF_ROYAL_JELLY:
2102 /* This stuff seems to be VERY healthy! */
2103 gainstr(otmp, 1, TRUE);
2104 if (Upolyd) {
2105 u.mh += otmp->cursed ? -rnd(20) : rnd(20);
2106 if (u.mh > u.mhmax) {
2107 if (!rn2(17))
2108 u.mhmax++;
2109 u.mh = u.mhmax;
2110 } else if (u.mh <= 0) {
2111 rehumanize();
2113 } else {
2114 u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
2115 if (u.uhp > u.uhpmax) {
2116 if (!rn2(17))
2117 u.uhpmax++;
2118 u.uhp = u.uhpmax;
2119 } else if (u.uhp <= 0) {
2120 killer.format = KILLED_BY_AN;
2121 Strcpy(killer.name, "rotten lump of royal jelly");
2122 done(POISONING);
2125 if (!otmp->cursed)
2126 heal_legs();
2127 break;
2128 case EGG:
2129 if (flesh_petrifies(&mons[otmp->corpsenm])) {
2130 if (!Stone_resistance
2131 && !(poly_when_stoned(youmonst.data)
2132 && polymon(PM_STONE_GOLEM))) {
2133 if (!Stoned) {
2134 Sprintf(killer.name, "%s egg",
2135 mons[otmp->corpsenm].mname);
2136 make_stoned(5L, (char *) 0, KILLED_BY_AN, killer.name);
2139 /* note: no "tastes like chicken" message for eggs */
2141 break;
2142 case EUCALYPTUS_LEAF:
2143 if (Sick && !otmp->cursed)
2144 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
2145 if (Vomiting && !otmp->cursed)
2146 make_vomiting(0L, TRUE);
2147 break;
2148 case APPLE:
2149 if (otmp->cursed && !Sleep_resistance) {
2150 /* Snow White; 'poisoned' applies to [a subset of] weapons,
2151 not food, so we substitute cursed; fortunately our hero
2152 won't have to wait for a prince to be rescued/revived */
2153 if (Race_if(PM_DWARF) && Hallucination)
2154 verbalize("Heigh-ho, ho-hum, I think I'll skip work today.");
2155 else if (Deaf || !flags.acoustics)
2156 You("fall asleep.");
2157 else
2158 You_hear("sinister laughter as you fall asleep...");
2159 fall_asleep(-rn1(11, 20), TRUE);
2161 break;
2163 return;
2166 #if 0
2167 /* intended for eating a spellbook while polymorphed, but not used;
2168 "leather" applied to appearance, not composition, and has been
2169 changed to "leathery" to reflect that */
2170 STATIC_DCL boolean FDECL(leather_cover, (struct obj *));
2172 STATIC_OVL boolean
2173 leather_cover(otmp)
2174 struct obj *otmp;
2176 const char *odesc = OBJ_DESCR(objects[otmp->otyp]);
2178 if (odesc && (otmp->oclass == SPBOOK_CLASS)) {
2179 if (!strcmp(odesc, "leather"))
2180 return TRUE;
2182 return FALSE;
2184 #endif
2187 * return 0 if the food was not dangerous.
2188 * return 1 if the food was dangerous and you chose to stop.
2189 * return 2 if the food was dangerous and you chose to eat it anyway.
2191 STATIC_OVL int
2192 edibility_prompts(otmp)
2193 struct obj *otmp;
2195 /* Blessed food detection grants hero a one-use
2196 * ability to detect food that is unfit for consumption
2197 * or dangerous and avoid it.
2199 char buf[BUFSZ], foodsmell[BUFSZ],
2200 it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
2201 boolean cadaver = (otmp->otyp == CORPSE || otmp->globby),
2202 stoneorslime = FALSE;
2203 int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm;
2204 long rotted = 0L;
2206 Strcpy(foodsmell, Tobjnam(otmp, "smell"));
2207 Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
2208 Sprintf(eat_it_anyway, "Eat %s anyway?",
2209 (otmp->quan == 1L) ? "it" : "one");
2211 if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
2212 /* These checks must match those in eatcorpse() */
2213 stoneorslime = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
2214 && !poly_when_stoned(youmonst.data));
2216 if (mnum == PM_GREEN_SLIME || otmp->otyp == GLOB_OF_GREEN_SLIME)
2217 stoneorslime = (!Unchanging && !slimeproof(youmonst.data));
2219 if (cadaver && !nonrotting_corpse(mnum)) {
2220 long age = peek_at_iced_corpse_age(otmp);
2222 /* worst case rather than random
2223 in this calculation to force prompt */
2224 rotted = (monstermoves - age) / (10L + 0 /* was rn2(20) */);
2225 if (otmp->cursed)
2226 rotted += 2L;
2227 else if (otmp->blessed)
2228 rotted -= 2L;
2233 * These problems with food should be checked in
2234 * order from most detrimental to least detrimental.
2236 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
2237 /* Tainted meat */
2238 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2239 eat_it_anyway);
2240 if (yn_function(buf, ynchars, 'n') == 'n')
2241 return 1;
2242 else
2243 return 2;
2245 if (stoneorslime) {
2246 Sprintf(buf, "%s like %s could be something very dangerous! %s",
2247 foodsmell, it_or_they, eat_it_anyway);
2248 if (yn_function(buf, ynchars, 'n') == 'n')
2249 return 1;
2250 else
2251 return 2;
2253 if (otmp->orotten || (cadaver && rotted > 3L)) {
2254 /* Rotten */
2255 Sprintf(buf, "%s like %s could be rotten! %s", foodsmell, it_or_they,
2256 eat_it_anyway);
2257 if (yn_function(buf, ynchars, 'n') == 'n')
2258 return 1;
2259 else
2260 return 2;
2262 if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
2263 /* poisonous */
2264 Sprintf(buf, "%s like %s might be poisonous! %s", foodsmell,
2265 it_or_they, eat_it_anyway);
2266 if (yn_function(buf, ynchars, 'n') == 'n')
2267 return 1;
2268 else
2269 return 2;
2271 if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
2272 /* causes sleep, for long enough to be dangerous */
2273 Sprintf(buf, "%s like %s might have been poisoned. %s", foodsmell,
2274 it_or_they, eat_it_anyway);
2275 return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
2277 if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian
2278 && Role_if(PM_MONK)) {
2279 Sprintf(buf, "%s unhealthy. %s", foodsmell, eat_it_anyway);
2280 if (yn_function(buf, ynchars, 'n') == 'n')
2281 return 1;
2282 else
2283 return 2;
2285 if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
2286 Sprintf(buf, "%s rather acidic. %s", foodsmell, eat_it_anyway);
2287 if (yn_function(buf, ynchars, 'n') == 'n')
2288 return 1;
2289 else
2290 return 2;
2292 if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
2293 && otmp->oerodeproof) {
2294 Sprintf(buf, "%s disgusting to you right now. %s", foodsmell,
2295 eat_it_anyway);
2296 if (yn_function(buf, ynchars, 'n') == 'n')
2297 return 1;
2298 else
2299 return 2;
2303 * Breaks conduct, but otherwise safe.
2305 if (!u.uconduct.unvegan
2306 && ((material == LEATHER || material == BONE
2307 || material == DRAGON_HIDE || material == WAX)
2308 || (cadaver && !vegan(&mons[mnum])))) {
2309 Sprintf(buf, "%s foul and unfamiliar to you. %s", foodsmell,
2310 eat_it_anyway);
2311 if (yn_function(buf, ynchars, 'n') == 'n')
2312 return 1;
2313 else
2314 return 2;
2316 if (!u.uconduct.unvegetarian
2317 && ((material == LEATHER || material == BONE
2318 || material == DRAGON_HIDE)
2319 || (cadaver && !vegetarian(&mons[mnum])))) {
2320 Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway);
2321 if (yn_function(buf, ynchars, 'n') == 'n')
2322 return 1;
2323 else
2324 return 2;
2327 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
2328 /* Tainted meat with Sick_resistance */
2329 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2330 eat_it_anyway);
2331 if (yn_function(buf, ynchars, 'n') == 'n')
2332 return 1;
2333 else
2334 return 2;
2336 return 0;
2339 /* 'e' command */
2341 doeat()
2343 struct obj *otmp;
2344 int basenutrit; /* nutrition of full item */
2345 boolean dont_start = FALSE, nodelicious = FALSE;
2347 if (Strangled) {
2348 pline("If you can't breathe air, how can you consume solids?");
2349 return 0;
2351 if (!(otmp = floorfood("eat", 0)))
2352 return 0;
2353 if (check_capacity((char *) 0))
2354 return 0;
2356 if (u.uedibility) {
2357 int res = edibility_prompts(otmp);
2358 if (res) {
2359 Your(
2360 "%s stops tingling and your sense of smell returns to normal.",
2361 body_part(NOSE));
2362 u.uedibility = 0;
2363 if (res == 1)
2364 return 0;
2368 /* We have to make non-foods take 1 move to eat, unless we want to
2369 * do ridiculous amounts of coding to deal with partly eaten plate
2370 * mails, players who polymorph back to human in the middle of their
2371 * metallic meal, etc....
2373 if (!(carried(otmp) ? retouch_object(&otmp, FALSE)
2374 : touch_artifact(otmp, &youmonst))) {
2375 return 1;
2376 } else if (!is_edible(otmp)) {
2377 You("cannot eat that!");
2378 return 0;
2379 } else if ((otmp->owornmask & (W_ARMOR | W_TOOL | W_AMUL | W_SADDLE))
2380 != 0) {
2381 /* let them eat rings */
2382 You_cant("eat %s you're wearing.", something);
2383 return 0;
2385 if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER
2386 && otmp->oerodeproof) {
2387 otmp->rknown = TRUE;
2388 if (otmp->quan > 1L) {
2389 if (!carried(otmp))
2390 (void) splitobj(otmp, otmp->quan - 1L);
2391 else
2392 otmp = splitobj(otmp, 1L);
2394 pline("Ulch - that %s was rustproofed!", xname(otmp));
2395 /* The regurgitated object's rustproofing is gone now */
2396 otmp->oerodeproof = 0;
2397 make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE);
2398 You("spit %s out onto the %s.", the(xname(otmp)),
2399 surface(u.ux, u.uy));
2400 if (carried(otmp)) {
2401 freeinv(otmp);
2402 dropy(otmp);
2404 stackobj(otmp);
2405 return 1;
2407 /* KMH -- Slow digestion is... indigestible */
2408 if (otmp->otyp == RIN_SLOW_DIGESTION) {
2409 pline("This ring is indigestible!");
2410 (void) rottenfood(otmp);
2411 if (otmp->dknown && !objects[otmp->otyp].oc_name_known
2412 && !objects[otmp->otyp].oc_uname)
2413 docall(otmp);
2414 return 1;
2416 if (otmp->oclass != FOOD_CLASS) {
2417 int material;
2419 context.victual.reqtime = 1;
2420 context.victual.piece = otmp;
2421 context.victual.o_id = otmp->o_id;
2422 /* Don't split it, we don't need to if it's 1 move */
2423 context.victual.usedtime = 0;
2424 context.victual.canchoke = (u.uhs == SATIATED);
2425 /* Note: gold weighs 1 pt. for each 1000 pieces (see
2426 pickup.c) so gold and non-gold is consistent. */
2427 if (otmp->oclass == COIN_CLASS)
2428 basenutrit = ((otmp->quan > 200000L)
2429 ? 2000
2430 : (int) (otmp->quan / 100L));
2431 else if (otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
2432 basenutrit = weight(otmp);
2433 /* oc_nutrition is usually weight anyway */
2434 else
2435 basenutrit = objects[otmp->otyp].oc_nutrition;
2436 #ifdef MAIL
2437 if (otmp->otyp == SCR_MAIL) {
2438 basenutrit = 0;
2439 nodelicious = TRUE;
2441 #endif
2442 context.victual.nmod = basenutrit;
2443 context.victual.eating = TRUE; /* needed for lesshungry() */
2445 material = objects[otmp->otyp].oc_material;
2446 if (material == LEATHER || material == BONE
2447 || material == DRAGON_HIDE) {
2448 u.uconduct.unvegan++;
2449 violated_vegetarian();
2450 } else if (material == WAX)
2451 u.uconduct.unvegan++;
2452 u.uconduct.food++;
2454 if (otmp->cursed)
2455 (void) rottenfood(otmp);
2457 if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
2458 pline("Ecch - that must have been poisonous!");
2459 if (!Poison_resistance) {
2460 losestr(rnd(4));
2461 losehp(rnd(15), xname(otmp), KILLED_BY_AN);
2462 } else
2463 You("seem unaffected by the poison.");
2464 } else if (!otmp->cursed && !nodelicious) {
2465 pline("%s%s is delicious!",
2466 (obj_is_pname(otmp)
2467 && otmp->oartifact < ART_ORB_OF_DETECTION)
2468 ? ""
2469 : "This ",
2470 (otmp->oclass == COIN_CLASS)
2471 ? foodword(otmp)
2472 : singular(otmp, xname));
2474 eatspecial();
2475 return 1;
2478 if (otmp == context.victual.piece) {
2479 /* If they weren't able to choke, they don't suddenly become able to
2480 * choke just because they were interrupted. On the other hand, if
2481 * they were able to choke before, if they lost food it's possible
2482 * they shouldn't be able to choke now.
2484 if (u.uhs != SATIATED)
2485 context.victual.canchoke = FALSE;
2486 context.victual.o_id = 0;
2487 context.victual.piece = touchfood(otmp);
2488 if (context.victual.piece)
2489 context.victual.o_id = context.victual.piece->o_id;
2490 You("resume your meal.");
2491 start_eating(context.victual.piece);
2492 return 1;
2495 /* nothing in progress - so try to find something. */
2496 /* tins are a special case */
2497 /* tins must also check conduct separately in case they're discarded */
2498 if (otmp->otyp == TIN) {
2499 start_tin(otmp);
2500 return 1;
2503 /* KMH, conduct */
2504 u.uconduct.food++;
2506 context.victual.o_id = 0;
2507 context.victual.piece = otmp = touchfood(otmp);
2508 if (context.victual.piece)
2509 context.victual.o_id = context.victual.piece->o_id;
2510 context.victual.usedtime = 0;
2512 /* Now we need to calculate delay and nutritional info.
2513 * The base nutrition calculated here and in eatcorpse() accounts
2514 * for normal vs. rotten food. The reqtime and nutrit values are
2515 * then adjusted in accordance with the amount of food left.
2517 if (otmp->otyp == CORPSE || otmp->globby) {
2518 int tmp = eatcorpse(otmp);
2520 if (tmp == 2) {
2521 /* used up */
2522 context.victual.piece = (struct obj *) 0;
2523 context.victual.o_id = 0;
2524 return 1;
2525 } else if (tmp)
2526 dont_start = TRUE;
2527 /* if not used up, eatcorpse sets up reqtime and may modify oeaten */
2528 } else {
2529 /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are
2530 * all handled in the != FOOD_CLASS case, above.
2532 switch (objects[otmp->otyp].oc_material) {
2533 case FLESH:
2534 u.uconduct.unvegan++;
2535 if (otmp->otyp != EGG) {
2536 violated_vegetarian();
2538 break;
2540 default:
2541 if (otmp->otyp == PANCAKE || otmp->otyp == FORTUNE_COOKIE /*eggs*/
2542 || otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR /*milk*/
2543 || otmp->otyp == LUMP_OF_ROYAL_JELLY)
2544 u.uconduct.unvegan++;
2545 break;
2548 context.victual.reqtime = objects[otmp->otyp].oc_delay;
2549 if (otmp->otyp != FORTUNE_COOKIE
2550 && (otmp->cursed || (!nonrotting_food(otmp->otyp)
2551 && (monstermoves - otmp->age)
2552 > (otmp->blessed ? 50L : 30L)
2553 && (otmp->orotten || !rn2(7))))) {
2554 if (rottenfood(otmp)) {
2555 otmp->orotten = TRUE;
2556 dont_start = TRUE;
2558 consume_oeaten(otmp, 1); /* oeaten >>= 1 */
2559 } else
2560 fprefx(otmp);
2563 /* re-calc the nutrition */
2564 basenutrit = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
2565 : otmp->globby ? otmp->owt
2566 : (unsigned) objects[otmp->otyp].oc_nutrition;
2568 debugpline3(
2569 "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d",
2570 context.victual.reqtime, otmp->oeaten, basenutrit);
2572 context.victual.reqtime = (basenutrit == 0) ? 0
2573 : rounddiv(context.victual.reqtime * (long) otmp->oeaten, basenutrit);
2575 debugpline1("after rounddiv: victual.reqtime == %d",
2576 context.victual.reqtime);
2578 * calculate the modulo value (nutrit. units per round eating)
2579 * note: this isn't exact - you actually lose a little nutrition due
2580 * to this method.
2581 * TODO: add in a "remainder" value to be given at the end of the meal.
2583 if (context.victual.reqtime == 0 || otmp->oeaten == 0)
2584 /* possible if most has been eaten before */
2585 context.victual.nmod = 0;
2586 else if ((int) otmp->oeaten >= context.victual.reqtime)
2587 context.victual.nmod = -((int) otmp->oeaten
2588 / context.victual.reqtime);
2589 else
2590 context.victual.nmod = context.victual.reqtime % otmp->oeaten;
2591 context.victual.canchoke = (u.uhs == SATIATED);
2593 if (!dont_start)
2594 start_eating(otmp);
2595 return 1;
2599 use_tin_opener(obj)
2600 struct obj *obj;
2602 struct obj *otmp;
2603 int res = 0;
2605 if (!carrying(TIN)) {
2606 You("have no tin to open.");
2607 return 0;
2610 if (obj != uwep) {
2611 if (obj->cursed && obj->bknown) {
2612 char qbuf[QBUFSZ];
2614 if (ynq(safe_qbuf(qbuf, "Really wield ", "?",
2615 obj, doname, thesimpleoname, "that")) != 'y')
2616 return 0;
2618 if (!wield_tool(obj, "use"))
2619 return 0;
2620 res = 1;
2623 otmp = getobj(comestibles, "open");
2624 if (!otmp)
2625 return res;
2627 start_tin(otmp);
2628 return 1;
2631 /* Take a single bite from a piece of food, checking for choking and
2632 * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
2634 STATIC_OVL int
2635 bite()
2637 if (context.victual.canchoke && u.uhunger >= 2000) {
2638 choke(context.victual.piece);
2639 return 1;
2641 if (context.victual.doreset) {
2642 do_reset_eat();
2643 return 0;
2645 force_save_hs = TRUE;
2646 if (context.victual.nmod < 0) {
2647 lesshungry(-context.victual.nmod);
2648 consume_oeaten(context.victual.piece,
2649 context.victual.nmod); /* -= -nmod */
2650 } else if (context.victual.nmod > 0
2651 && (context.victual.usedtime % context.victual.nmod)) {
2652 lesshungry(1);
2653 consume_oeaten(context.victual.piece, -1); /* -= 1 */
2655 force_save_hs = FALSE;
2656 recalc_wt();
2657 return 0;
2660 /* as time goes by - called by moveloop() and domove() */
2661 void
2662 gethungry()
2664 if (u.uinvulnerable)
2665 return; /* you don't feel hungrier */
2667 if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */
2668 && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
2669 && !Slow_digestion)
2670 u.uhunger--; /* ordinary food consumption */
2672 if (moves % 2) { /* odd turns */
2673 /* Regeneration uses up food, unless due to an artifact */
2674 if ((HRegeneration & ~FROMFORM)
2675 || (ERegeneration & ~(W_ARTI | W_WEP)))
2676 u.uhunger--;
2677 if (near_capacity() > SLT_ENCUMBER)
2678 u.uhunger--;
2679 } else { /* even turns */
2680 if (Hunger)
2681 u.uhunger--;
2682 /* Conflict uses up food too */
2683 if (HConflict || (EConflict & (~W_ARTI)))
2684 u.uhunger--;
2685 /* +0 charged rings don't do anything, so don't affect hunger */
2686 /* Slow digestion still uses ring hunger */
2687 switch ((int) (moves % 20)) { /* note: use even cases only */
2688 case 4:
2689 if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged))
2690 u.uhunger--;
2691 break;
2692 case 8:
2693 if (uamul)
2694 u.uhunger--;
2695 break;
2696 case 12:
2697 if (uright && (uright->spe || !objects[uright->otyp].oc_charged))
2698 u.uhunger--;
2699 break;
2700 case 16:
2701 if (u.uhave.amulet)
2702 u.uhunger--;
2703 break;
2704 default:
2705 break;
2708 newuhs(TRUE);
2711 /* called after vomiting and after performing feats of magic */
2712 void
2713 morehungry(num)
2714 int num;
2716 u.uhunger -= num;
2717 newuhs(TRUE);
2720 /* called after eating (and after drinking fruit juice) */
2721 void
2722 lesshungry(num)
2723 int num;
2725 /* See comments in newuhs() for discussion on force_save_hs */
2726 boolean iseating = (occupation == eatfood) || force_save_hs;
2728 debugpline1("lesshungry(%d)", num);
2729 u.uhunger += num;
2730 if (u.uhunger >= 2000) {
2731 if (!iseating || context.victual.canchoke) {
2732 if (iseating) {
2733 choke(context.victual.piece);
2734 reset_eat();
2735 } else
2736 choke(occupation == opentin ? context.tin.tin
2737 : (struct obj *) 0);
2738 /* no reset_eat() */
2740 } else {
2741 /* Have lesshungry() report when you're nearly full so all eating
2742 * warns when you're about to choke.
2744 if (u.uhunger >= 1500) {
2745 if (!context.victual.eating
2746 || (context.victual.eating && !context.victual.fullwarn)) {
2747 pline("You're having a hard time getting all of it down.");
2748 nomovemsg = "You're finally finished.";
2749 if (!context.victual.eating) {
2750 multi = -2;
2751 } else {
2752 context.victual.fullwarn = TRUE;
2753 if (context.victual.canchoke
2754 && context.victual.reqtime > 1) {
2755 /* a one-gulp food will not survive a stop */
2756 if (yn_function("Continue eating?", ynchars, 'n')
2757 != 'y') {
2758 reset_eat();
2759 nomovemsg = (char *) 0;
2766 newuhs(FALSE);
2769 STATIC_PTR
2771 unfaint(VOID_ARGS)
2773 (void) Hear_again();
2774 if (u.uhs > FAINTING)
2775 u.uhs = FAINTING;
2776 stop_occupation();
2777 context.botl = 1;
2778 return 0;
2781 boolean
2782 is_fainted()
2784 return (boolean) (u.uhs == FAINTED);
2787 /* call when a faint must be prematurely terminated */
2788 void
2789 reset_faint()
2791 if (afternmv == unfaint)
2792 unmul("You revive.");
2795 /* compute and comment on your (new?) hunger status */
2796 void
2797 newuhs(incr)
2798 boolean incr;
2800 unsigned newhs;
2801 static unsigned save_hs;
2802 static boolean saved_hs = FALSE;
2803 int h = u.uhunger;
2805 newhs = (h > 1000)
2806 ? SATIATED
2807 : (h > 150) ? NOT_HUNGRY
2808 : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING;
2810 /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2811 * This should not produce the message "you only feel hungry now";
2812 * that message should only appear if HUNGRY is an endpoint. Therefore
2813 * we check to see if we're in the middle of eating. If so, we save
2814 * the first hunger status, and at the end of eating we decide what
2815 * message to print based on the _entire_ meal, not on each little bit.
2817 /* It is normally possible to check if you are in the middle of a meal
2818 * by checking occupation == eatfood, but there is one special case:
2819 * start_eating() can call bite() for your first bite before it
2820 * sets the occupation.
2821 * Anyone who wants to get that case to work _without_ an ugly static
2822 * force_save_hs variable, feel free.
2824 /* Note: If you become a certain hunger status in the middle of the
2825 * meal, and still have that same status at the end of the meal,
2826 * this will incorrectly print the associated message at the end of
2827 * the meal instead of the middle. Such a case is currently
2828 * impossible, but could become possible if a message for SATIATED
2829 * were added or if HUNGRY and WEAK were separated by a big enough
2830 * gap to fit two bites.
2832 if (occupation == eatfood || force_save_hs) {
2833 if (!saved_hs) {
2834 save_hs = u.uhs;
2835 saved_hs = TRUE;
2837 u.uhs = newhs;
2838 return;
2839 } else {
2840 if (saved_hs) {
2841 u.uhs = save_hs;
2842 saved_hs = FALSE;
2846 if (newhs == FAINTING) {
2847 if (is_fainted())
2848 newhs = FAINTED;
2849 if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) {
2850 if (!is_fainted() && multi >= 0 /* %% */) {
2851 int duration = 10 - (u.uhunger / 10);
2853 /* stop what you're doing, then faint */
2854 stop_occupation();
2855 You("faint from lack of food.");
2856 incr_itimeout(&HDeaf, duration);
2857 context.botl = TRUE;
2858 nomul(-duration);
2859 multi_reason = "fainted from lack of food";
2860 nomovemsg = "You regain consciousness.";
2861 afternmv = unfaint;
2862 newhs = FAINTED;
2863 if (!Levitation)
2864 selftouch("Falling, you");
2866 } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) {
2867 u.uhs = STARVED;
2868 context.botl = 1;
2869 bot();
2870 You("die from starvation.");
2871 killer.format = KILLED_BY;
2872 Strcpy(killer.name, "starvation");
2873 done(STARVING);
2874 /* if we return, we lifesaved, and that calls newuhs */
2875 return;
2879 if (newhs != u.uhs) {
2880 if (newhs >= WEAK && u.uhs < WEAK)
2881 losestr(1); /* this may kill you -- see below */
2882 else if (newhs < WEAK && u.uhs >= WEAK)
2883 losestr(-1);
2884 switch (newhs) {
2885 case HUNGRY:
2886 if (Hallucination) {
2887 You((!incr) ? "now have a lesser case of the munchies."
2888 : "are getting the munchies.");
2889 } else
2890 You((!incr) ? "only feel hungry now."
2891 : (u.uhunger < 145)
2892 ? "feel hungry."
2893 : "are beginning to feel hungry.");
2894 if (incr && occupation
2895 && (occupation != eatfood && occupation != opentin))
2896 stop_occupation();
2897 context.travel = context.travel1 = context.mv = context.run = 0;
2898 break;
2899 case WEAK:
2900 if (Hallucination)
2901 pline((!incr) ? "You still have the munchies."
2902 : "The munchies are interfering with your motor capabilities.");
2903 else if (incr && (Role_if(PM_WIZARD) || Race_if(PM_ELF)
2904 || Role_if(PM_VALKYRIE)))
2905 pline("%s needs food, badly!",
2906 (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE))
2907 ? urole.name.m
2908 : "Elf");
2909 else
2910 You((!incr)
2911 ? "feel weak now."
2912 : (u.uhunger < 45) ? "feel weak."
2913 : "are beginning to feel weak.");
2914 if (incr && occupation
2915 && (occupation != eatfood && occupation != opentin))
2916 stop_occupation();
2917 context.travel = context.travel1 = context.mv = context.run = 0;
2918 break;
2920 u.uhs = newhs;
2921 context.botl = 1;
2922 bot();
2923 if ((Upolyd ? u.mh : u.uhp) < 1) {
2924 You("die from hunger and exhaustion.");
2925 killer.format = KILLED_BY;
2926 Strcpy(killer.name, "exhaustion");
2927 done(STARVING);
2928 return;
2933 /* Returns an object representing food.
2934 * Object may be either on floor or in inventory.
2936 struct obj *
2937 floorfood(verb, corpsecheck)
2938 const char *verb;
2939 int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
2941 register struct obj *otmp;
2942 char qbuf[QBUFSZ];
2943 char c;
2944 boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */
2945 offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */
2947 /* if we can't touch floor objects then use invent food only */
2948 if (!can_reach_floor(TRUE) || (feeding && u.usteed)
2949 || (is_pool_or_lava(u.ux, u.uy)
2950 && (Wwalking || is_clinger(youmonst.data)
2951 || (Flying && !Breathless))))
2952 goto skipfloor;
2954 if (feeding && metallivorous(youmonst.data)) {
2955 struct obj *gold;
2956 struct trap *ttmp = t_at(u.ux, u.uy);
2958 if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
2959 /* If not already stuck in the trap, perhaps there should
2960 be a chance to becoming trapped? Probably not, because
2961 then the trap would just get eaten on the _next_ turn... */
2962 Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
2963 (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you"
2964 : "armed");
2965 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2966 u.utrap = u.utraptype = 0;
2967 deltrap(ttmp);
2968 return mksobj(BEARTRAP, TRUE, FALSE);
2969 } else if (c == 'q') {
2970 return (struct obj *) 0;
2974 if (youmonst.data != &mons[PM_RUST_MONSTER]
2975 && (gold = g_at(u.ux, u.uy)) != 0) {
2976 if (gold->quan == 1L)
2977 Sprintf(qbuf, "There is 1 gold piece here; eat it?");
2978 else
2979 Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
2980 gold->quan);
2981 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2982 return gold;
2983 } else if (c == 'q') {
2984 return (struct obj *) 0;
2989 /* Is there some food (probably a heavy corpse) here on the ground? */
2990 for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
2991 if (corpsecheck
2992 ? (otmp->otyp == CORPSE
2993 && (corpsecheck == 1 || tinnable(otmp)))
2994 : feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp))
2995 : otmp->oclass == FOOD_CLASS) {
2996 char qsfx[QBUFSZ];
2997 boolean one = (otmp->quan == 1L);
2999 /* "There is <an object> here; <verb> it?" or
3000 "There are <N objects> here; <verb> one?" */
3001 Sprintf(qbuf, "There %s ", otense(otmp, "are"));
3002 Sprintf(qsfx, " here; %s %s?", verb, one ? "it" : "one");
3003 (void) safe_qbuf(qbuf, qbuf, qsfx, otmp, doname, ansimpleoname,
3004 one ? something : (const char *) "things");
3005 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y')
3006 return otmp;
3007 else if (c == 'q')
3008 return (struct obj *) 0;
3012 skipfloor:
3013 /* We cannot use ALL_CLASSES since that causes getobj() to skip its
3014 * "ugly checks" and we need to check for inedible items.
3016 otmp =
3017 getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb);
3018 if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS))
3019 if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
3020 You_cant("%s that!", verb);
3021 return (struct obj *) 0;
3023 return otmp;
3026 /* Side effects of vomiting */
3027 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
3028 void
3029 vomit() /* A good idea from David Neves */
3031 if (cantvomit(youmonst.data))
3032 /* doesn't cure food poisoning; message assumes that we aren't
3033 dealing with some esoteric body_part() */
3034 Your("jaw gapes convulsively.");
3035 else
3036 make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
3037 nomul(-2);
3038 multi_reason = "vomiting";
3039 nomovemsg = You_can_move_again;
3043 eaten_stat(base, obj)
3044 int base;
3045 struct obj *obj;
3047 long uneaten_amt, full_amount;
3049 uneaten_amt = (long) obj->oeaten;
3050 full_amount = (long) ((obj->otyp == CORPSE) ? mons[obj->corpsenm].cnutrit
3051 : obj->globby ? obj->owt
3052 : (unsigned) objects[obj->otyp].oc_nutrition);
3053 if (uneaten_amt > full_amount) {
3054 impossible(
3055 "partly eaten food (%ld) more nutritious than untouched food (%ld)",
3056 uneaten_amt, full_amount);
3057 uneaten_amt = full_amount;
3060 base = (int) (full_amount ? (long) base * uneaten_amt / full_amount : 0L);
3061 return (base < 1) ? 1 : base;
3064 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
3065 void
3066 consume_oeaten(obj, amt)
3067 struct obj *obj;
3068 int amt;
3071 * This is a hack to try to squelch several long standing mystery
3072 * food bugs. A better solution would be to rewrite the entire
3073 * victual handling mechanism from scratch using a less complex
3074 * model. Alternatively, this routine could call done_eating()
3075 * or food_disappears() but its callers would need revisions to
3076 * cope with context.victual.piece unexpectedly going away.
3078 * Multi-turn eating operates by setting the food's oeaten field
3079 * to its full nutritional value and then running a counter which
3080 * independently keeps track of whether there is any food left.
3081 * The oeaten field can reach exactly zero on the last turn, and
3082 * the object isn't removed from inventory until the next turn
3083 * when the "you finish eating" message gets delivered, so the
3084 * food would be restored to the status of untouched during that
3085 * interval. This resulted in unexpected encumbrance messages
3086 * at the end of a meal (if near enough to a threshold) and would
3087 * yield full food if there was an interruption on the critical
3088 * turn. Also, there have been reports over the years of food
3089 * becoming massively heavy or producing unlimited satiation;
3090 * this would occur if reducing oeaten via subtraction attempted
3091 * to drop it below 0 since its unsigned type would produce a
3092 * huge positive value instead. So far, no one has figured out
3093 * _why_ that inappropriate subtraction might sometimes happen.
3096 if (amt > 0) {
3097 /* bit shift to divide the remaining amount of food */
3098 obj->oeaten >>= amt;
3099 } else {
3100 /* simple decrement; value is negative so we actually add it */
3101 if ((int) obj->oeaten > -amt)
3102 obj->oeaten += amt;
3103 else
3104 obj->oeaten = 0;
3107 if (obj->oeaten == 0) {
3108 if (obj == context.victual.piece) /* always true unless wishing... */
3109 context.victual.reqtime =
3110 context.victual.usedtime; /* no bites left */
3111 obj->oeaten = 1; /* smallest possible positive value */
3115 /* called when eatfood occupation has been interrupted,
3116 or in the case of theft, is about to be interrupted */
3117 boolean
3118 maybe_finished_meal(stopping)
3119 boolean stopping;
3121 /* in case consume_oeaten() has decided that the food is all gone */
3122 if (occupation == eatfood
3123 && context.victual.usedtime >= context.victual.reqtime) {
3124 if (stopping)
3125 occupation = 0; /* for do_reset_eat */
3126 (void) eatfood(); /* calls done_eating() to use up
3127 context.victual.piece */
3128 return TRUE;
3130 return FALSE;
3133 /* Tin of <something> to the rescue? Decide whether current occupation
3134 is an attempt to eat a tin of something capable of saving hero's life.
3135 We don't care about consumption of non-tinned food here because special
3136 effects there take place on first bite rather than at end of occupation.
3137 [Popeye the Sailor gets out of trouble by eating tins of spinach. :-] */
3138 boolean
3139 Popeye(threat)
3140 int threat;
3142 struct obj *otin;
3143 int mndx;
3145 if (occupation != opentin)
3146 return FALSE;
3147 otin = context.tin.tin;
3148 /* make sure hero still has access to tin */
3149 if (!carried(otin)
3150 && (!obj_here(otin, u.ux, u.uy) || !can_reach_floor(TRUE)))
3151 return FALSE;
3152 /* unknown tin is assumed to be helpful */
3153 if (!otin->known)
3154 return TRUE;
3155 /* known tin is helpful if it will stop life-threatening problem */
3156 mndx = otin->corpsenm;
3157 switch (threat) {
3158 /* note: not used; hunger code bypasses stop_occupation() when eating */
3159 case HUNGER:
3160 return (boolean) (mndx != NON_PM || otin->spe == 1);
3161 /* flesh from lizards and acidic critters stops petrification */
3162 case STONED:
3163 return (boolean) (mndx >= LOW_PM
3164 && (mndx == PM_LIZARD || acidic(&mons[mndx])));
3165 /* no tins can cure these (yet?) */
3166 case SLIMED:
3167 case SICK:
3168 case VOMITING:
3169 break;
3170 default:
3171 break;
3173 return FALSE;
3176 /*eat.c*/