1 /* NetHack 3.6 eat.c $NHDT-Date: 1449269916 2015/12/04 22:58:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.154 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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));
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,
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.
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)
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)))
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))
101 /* return (boolean) !!index(comestibles, obj->oclass); */
102 return (boolean) (obj->oclass == FOOD_CLASS);
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 },
134 #define TTSZ SIZE(tintxts)
136 static char *eatmbuf = 0; /* set by cpostfx() */
138 /* called after mimicing is over */
142 /* release `eatmbuf' */
144 if (nomovemsg == eatmbuf)
146 free((genericptr_t) eatmbuf), eatmbuf = 0;
149 if (youmonst.m_ap_type) {
150 youmonst.m_ap_type = M_AP_NOTHING;
156 /* called when hallucination is toggled */
160 const char *altmsg = 0;
161 int altapp = 0; /* lint suppression */
163 if (!eatmbuf || nomovemsg != eatmbuf)
166 if (is_obj_mappear(&youmonst,ORANGE) && !Hallucination) {
167 /* revert from hallucinatory to "normal" mimicking */
168 altmsg = "You now prefer mimicking yourself.";
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.";
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;
191 /* ``[the(] singular(food, xname) [)]'' */
192 STATIC_OVL const char *
193 food_xname(food, the_pfx)
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]))
207 /* the ordinary case */
208 result = singular(food, xname);
211 result = the(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.)
226 /* only happens if you were satiated */
227 if (u.uhs != SATIATED) {
228 if (!food || food->otyp != AMULET_OF_STRANGULATION)
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.");
243 You("stuff yourself and then vomit voluminously.");
244 morehungry(1000); /* you just got *very* sick! */
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.
253 You("choke over your %s.", foodword(food));
254 if (food->oclass == COIN_CLASS) {
255 Strcpy(killer.name, "very rich meal");
257 killer.format = KILLED_BY;
258 Strcpy(killer.name, killer_xname(food));
261 You("choke over it.");
262 Strcpy(killer.name, "quick snack");
269 /* modify object wt. depending on time spent consuming it */
273 struct obj *piece = context.victual.piece;
275 impossible("recalc_wt without piece");
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 */
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;
299 STATIC_OVL struct obj *
303 if (otmp->quan > 1L) {
305 (void) splitobj(otmp, otmp->quan - 1L);
307 otmp = splitobj(otmp, 1L);
308 debugpline0("split object,");
312 costly_alteration(otmp, COST_BITE);
314 (otmp->otyp == CORPSE ? mons[otmp->corpsenm].cnutrit
315 : objects[otmp->otyp].oc_nutrition);
320 if (inv_cnt(FALSE) >= 52) {
321 sellobj_state(SELL_DONTSELL);
323 sellobj_state(SELL_NORMAL);
325 otmp->nomerge = 1; /* used to prevent merge */
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
342 if (obj == context.victual.piece) {
343 context.victual.piece = (struct obj *) 0;
344 context.victual.o_id = 0;
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 */
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;
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;
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.
389 /* called each move during eating process */
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? */
400 if (!context.victual.eating)
403 if (++context.victual.usedtime <= context.victual.reqtime) {
406 return 1; /* still busy */
417 context.victual.piece->in_use = TRUE;
418 occupation = 0; /* do this early, so newuhs() knows we're done */
425 You("finish eating %s.", food_xname(context.victual.piece, TRUE));
427 if (context.victual.piece->otyp == CORPSE)
428 cpostfx(context.victual.piece->corpsenm);
430 fpostfx(context.victual.piece);
432 if (carried(context.victual.piece))
433 useup(context.victual.piece);
435 useupf(context.victual.piece, 1L);
436 context.victual.piece = (struct obj *) 0;
437 context.victual.o_id = 0;
438 context.victual.fullwarn = context.victual.eating =
439 context.victual.doreset = FALSE;
448 u.uconduct.unvegan++;
450 violated_vegetarian();
453 /* handle side-effects of mind flayer's tentacle attack */
455 eat_brains(magr, mdef, visflag, dmg_p)
456 struct monst *magr, *mdef;
458 int *dmg_p; /* for dishing out extra damage in lieu of Int loss */
460 struct permonst *pd = mdef->data;
461 boolean give_nutrit = FALSE;
462 int result = MM_HIT, xtra_dmg = rnd(10);
464 if (noncorporeal(pd)) {
466 pline("%s brain is unharmed.",
467 (mdef == &youmonst) ? "Your" : s_suffix(Monnam(mdef)));
468 return MM_MISS; /* side-effects can't occur */
469 } else if (magr == &youmonst) {
470 You("eat %s brain!", s_suffix(mon_nam(mdef)));
471 } else if (mdef == &youmonst) {
472 Your("brain is eaten!");
473 } else { /* monster against monster */
475 pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
478 if (flesh_petrifies(pd)) {
479 /* mind flayer has attempted to eat the brains of a petrification
480 inducing critter (most likely Medusa; attacking a cockatrice via
481 tentacle-touch should have been caught before reaching this far) */
482 if (magr == &youmonst) {
483 if (!Stone_resistance && !Stoned)
484 make_stoned(5L, (char *) 0, KILLED_BY_AN, pd->mname);
486 /* no need to check for poly_when_stoned or Stone_resistance;
487 mind flayers don't have those capabilities */
489 pline("%s turns to stone!", Monnam(magr));
492 /* life-saved; don't continue eating the brains */
495 if (magr->mtame && !visflag)
496 /* parallels mhitm.c's brief_feeling */
497 You("have a sad thought for a moment, then is passes.");
503 if (magr == &youmonst) {
505 * player mind flayer is eating something's brain
508 if (mindless(pd)) { /* (cannibalism not possible here) */
509 pline("%s doesn't notice.", Monnam(mdef));
510 /* all done; no extra harm inflicted upon target */
512 } else if (is_rider(pd)) {
513 pline("Ingesting that is fatal.");
514 Sprintf(killer.name, "unwisely ate the brain of %s", pd->mname);
515 killer.format = NO_KILLER_PREFIX;
517 /* life-saving needed to reach here */
518 exercise(A_WIS, FALSE);
519 *dmg_p += xtra_dmg; /* Rider takes extra damage */
521 morehungry(-rnd(30)); /* cannot choke */
522 if (ABASE(A_INT) < AMAX(A_INT)) {
523 /* recover lost Int; won't increase current max */
524 ABASE(A_INT) += rnd(4);
525 if (ABASE(A_INT) > AMAX(A_INT))
526 ABASE(A_INT) = AMAX(A_INT);
529 exercise(A_WIS, TRUE);
532 /* targetting another mind flayer or your own underlying species
534 (void) maybe_cannibal(monsndx(pd), TRUE);
536 } else if (mdef == &youmonst) {
538 * monster mind flayer is eating hero's brain
540 /* no such thing as mindless players */
541 if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
542 static NEARDATA const char brainlessness[] = "brainlessness";
545 Strcpy(killer.name, brainlessness);
546 killer.format = KILLED_BY;
548 /* amulet of life saving has now been used up */
549 pline("Unfortunately your brain is still gone.");
550 /* sanity check against adding other forms of life-saving */
551 u.uprops[LIFESAVED].extrinsic =
552 u.uprops[LIFESAVED].intrinsic = 0L;
554 Your("last thought fades away.");
556 Strcpy(killer.name, brainlessness);
557 killer.format = KILLED_BY;
559 /* can only get here when in wizard or explore mode and user has
560 explicitly chosen not to die; arbitrarily boost intelligence */
561 ABASE(A_INT) = ATTRMIN(A_INT) + 2;
562 You_feel("like a scarecrow.");
564 give_nutrit = TRUE; /* in case a conflicted pet is doing this */
565 exercise(A_WIS, FALSE);
566 /* caller handles Int and memory loss */
570 * monster mind flayer is eating another monster's brain
574 pline("%s doesn't notice.", Monnam(mdef));
576 } else if (is_rider(pd)) {
579 result = MM_AGR_DIED;
580 /* Rider takes extra damage regardless of whether attacker dies */
585 if (*dmg_p >= mdef->mhp && visflag)
586 pline("%s last thought fades away...",
587 s_suffix(Monnam(mdef)));
591 if (give_nutrit && magr->mtame && !magr->isminion) {
592 EDOG(magr)->hungrytime += rnd(60);
599 /* eating a corpse or egg of one's own species is usually naughty */
601 maybe_cannibal(pm, allowmsg)
605 static NEARDATA long ate_brains = 0L;
606 struct permonst *fptr = &mons[pm]; /* food type */
608 /* when poly'd into a mind flayer, multiple tentacle hits in one
609 turn cause multiple digestion checks to occur; avoid giving
610 multiple luck penalties for the same attack */
611 if (moves == ate_brains)
613 ate_brains = moves; /* ate_anything, not just brains... */
615 if (!CANNIBAL_ALLOWED()
616 /* non-cannibalistic heroes shouldn't eat own species ever
617 and also shouldn't eat current species when polymorphed
618 (even if having the form of something which doesn't care
619 about cannibalism--hero's innate traits aren't altered) */
620 && (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) {
622 if (Upolyd && your_race(fptr))
623 You("have a bad feeling deep inside.");
624 You("cannibal! You will regret this!");
626 HAggravate_monster |= FROMOUTSIDE;
627 change_luck(-rn1(4, 2)); /* -5..-2 */
637 (void) maybe_cannibal(pm, TRUE);
638 if (flesh_petrifies(&mons[pm])) {
639 if (!Stone_resistance
640 && !(poly_when_stoned(youmonst.data)
641 && polymon(PM_STONE_GOLEM))) {
642 Sprintf(killer.name, "tasting %s meat", mons[pm].mname);
643 killer.format = KILLED_BY;
644 You("turn to stone.");
646 if (context.victual.piece)
647 context.victual.eating = FALSE;
648 return; /* lifesaved */
659 /* cannibals are allowed to eat domestic animals without penalty */
660 if (!CANNIBAL_ALLOWED()) {
661 You_feel("that eating the %s was a bad idea.", mons[pm].mname);
662 HAggravate_monster |= FROMOUTSIDE;
672 pline("Eating that is instantly fatal.");
673 Sprintf(killer.name, "unwisely ate the body of %s", mons[pm].mname);
674 killer.format = NO_KILLER_PREFIX;
676 /* life-saving needed to reach here */
677 exercise(A_WIS, FALSE);
678 /* It so happens that since we know these monsters */
679 /* cannot appear in tins, context.victual.piece will always */
680 /* be what we want, which is not generally true. */
681 if (revive_corpse(context.victual.piece)) {
682 context.victual.piece = (struct obj *) 0;
683 context.victual.o_id = 0;
688 if (!Slimed && !Unchanging && !slimeproof(youmonst.data)) {
689 You("don't feel very well.");
690 make_slimed(10L, (char *) 0);
691 delayed_killer(SLIMED, KILLED_BY_AN, "");
695 if (acidic(&mons[pm]) && Stoned)
707 Sprintf(buf, "What a pity--you just ruined a future piece of %sart!",
708 ACURR(A_CHA) > 15 ? "fine " : "");
710 Strcpy(buf, "You feel limber!");
711 make_stoned(0L, buf, 0, (char *) 0);
715 * If you add an intrinsic that can be gotten by eating a monster, add it
716 * to intrinsic_possible() and givit(). (It must already be in prop.h to
717 * be an intrinsic property.)
718 * It would be very easy to make the intrinsics not try to give you one
719 * that you already had by checking to see if you have it in
720 * intrinsic_possible() instead of givit(), but we're not that nice.
723 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
725 intrinsic_possible(type, ptr)
727 register struct permonst *ptr;
732 #define ifdebugresist(Msg) \
738 #define ifdebugresist(Msg) /*empty*/
742 res = (ptr->mconveys & MR_FIRE) != 0;
743 ifdebugresist("can get fire resistance");
746 res = (ptr->mconveys & MR_SLEEP) != 0;
747 ifdebugresist("can get sleep resistance");
750 res = (ptr->mconveys & MR_COLD) != 0;
751 ifdebugresist("can get cold resistance");
754 res = (ptr->mconveys & MR_DISINT) != 0;
755 ifdebugresist("can get disintegration resistance");
757 case SHOCK_RES: /* shock (electricity) resistance */
758 res = (ptr->mconveys & MR_ELEC) != 0;
759 ifdebugresist("can get shock resistance");
762 res = (ptr->mconveys & MR_POISON) != 0;
763 ifdebugresist("can get poison resistance");
766 res = can_teleport(ptr);
767 ifdebugresist("can get teleport");
769 case TELEPORT_CONTROL:
770 res = control_teleport(ptr);
771 ifdebugresist("can get teleport control");
774 res = telepathic(ptr);
775 ifdebugresist("can get telepathy");
785 /* givit() tries to give you an intrinsic based on the monster's level
786 * and what type of intrinsic it is trying to give you.
791 register struct permonst *ptr;
795 debugpline1("Attempting to give intrinsic %d", type);
796 /* some intrinsics are easier to get than others */
799 if ((ptr == &mons[PM_KILLER_BEE] || ptr == &mons[PM_SCORPION])
808 case TELEPORT_CONTROL:
819 if (ptr->mlevel <= rn2(chance))
820 return; /* failed die roll */
824 debugpline0("Trying to give fire resistance");
825 if (!(HFire_resistance & FROMOUTSIDE)) {
826 You(Hallucination ? "be chillin'." : "feel a momentary chill.");
827 HFire_resistance |= FROMOUTSIDE;
831 debugpline0("Trying to give sleep resistance");
832 if (!(HSleep_resistance & FROMOUTSIDE)) {
833 You_feel("wide awake.");
834 HSleep_resistance |= FROMOUTSIDE;
838 debugpline0("Trying to give cold resistance");
839 if (!(HCold_resistance & FROMOUTSIDE)) {
840 You_feel("full of hot air.");
841 HCold_resistance |= FROMOUTSIDE;
845 debugpline0("Trying to give disintegration resistance");
846 if (!(HDisint_resistance & FROMOUTSIDE)) {
847 You_feel(Hallucination ? "totally together, man." : "very firm.");
848 HDisint_resistance |= FROMOUTSIDE;
851 case SHOCK_RES: /* shock (electricity) resistance */
852 debugpline0("Trying to give shock resistance");
853 if (!(HShock_resistance & FROMOUTSIDE)) {
855 You_feel("grounded in reality.");
857 Your("health currently feels amplified!");
858 HShock_resistance |= FROMOUTSIDE;
862 debugpline0("Trying to give poison resistance");
863 if (!(HPoison_resistance & FROMOUTSIDE)) {
864 You_feel(Poison_resistance ? "especially healthy." : "healthy.");
865 HPoison_resistance |= FROMOUTSIDE;
869 debugpline0("Trying to give teleport");
870 if (!(HTeleportation & FROMOUTSIDE)) {
871 You_feel(Hallucination ? "diffuse." : "very jumpy.");
872 HTeleportation |= FROMOUTSIDE;
875 case TELEPORT_CONTROL:
876 debugpline0("Trying to give teleport control");
877 if (!(HTeleport_control & FROMOUTSIDE)) {
878 You_feel(Hallucination ? "centered in your personal space."
879 : "in control of yourself.");
880 HTeleport_control |= FROMOUTSIDE;
884 debugpline0("Trying to give telepathy");
885 if (!(HTelepat & FROMOUTSIDE)) {
886 You_feel(Hallucination ? "in touch with the cosmos."
887 : "a strange mental acuity.");
888 HTelepat |= FROMOUTSIDE;
889 /* If blind, make sure monsters show up. */
895 debugpline0("Tried to give an impossible intrinsic");
900 /* called after completely consuming a corpse */
905 register int tmp = 0;
906 boolean catch_lycanthropy = FALSE;
908 /* in case `afternmv' didn't get called for previously mimicking
909 gold, clean up now to avoid `eatmbuf' memory leak */
915 /* MRKR: "eye of newt" may give small magical energy boost */
916 if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
919 if (u.uen > u.uenmax) {
924 if (old_uen != u.uen) {
925 You_feel("a mild buzz.");
933 case PM_HUMAN_WERERAT:
934 catch_lycanthropy = TRUE;
935 u.ulycn = PM_WERERAT;
937 case PM_HUMAN_WEREJACKAL:
938 catch_lycanthropy = TRUE;
939 u.ulycn = PM_WEREJACKAL;
941 case PM_HUMAN_WEREWOLF:
942 catch_lycanthropy = TRUE;
943 u.ulycn = PM_WEREWOLF;
954 set_itimeout(&HInvis, (long) rn1(100, 50));
955 if (!Blind && !BInvis)
956 self_invis_message();
958 if (!(HInvis & INTRINSIC))
960 HInvis |= FROMOUTSIDE;
961 HSee_invisible |= FROMOUTSIDE;
965 case PM_YELLOW_LIGHT:
967 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
970 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
980 if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
983 u.uconduct.polyselfs++; /* you're changing form */
984 You_cant("resist the temptation to mimic %s.",
985 Hallucination ? "an orange" : "a pile of gold");
986 /* A pile of gold can't ride. */
988 dismount_steed(DISMOUNT_FELL);
990 multi_reason = "pretending to be a pile of gold";
993 ? "You suddenly dread being peeled and mimic %s again!"
994 : "You now prefer mimicking %s again.",
995 an(Upolyd ? youmonst.data->mname : urace.noun));
996 eatmbuf = dupstr(buf);
999 /* ??? what if this was set before? */
1000 youmonst.m_ap_type = M_AP_OBJECT;
1001 youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
1004 /* make gold symbol show up now */
1005 display_nhwindow(WIN_MAP, TRUE);
1008 case PM_QUANTUM_MECHANIC:
1009 Your("velocity suddenly seems very uncertain!");
1010 if (HFast & INTRINSIC) {
1011 HFast &= ~INTRINSIC;
1012 You("seem slower.");
1014 HFast |= FROMOUTSIDE;
1015 You("seem faster.");
1019 if ((HStun & TIMEOUT) > 2)
1020 make_stunned(2L, FALSE);
1021 if ((HConfusion & TIMEOUT) > 2)
1022 make_confused(2L, FALSE);
1025 case PM_DOPPELGANGER:
1026 case PM_SANDESTIN: /* moot--they don't leave corpses */
1028 You_feel("momentarily different."); /* same as poly trap */
1030 You_feel("a change coming over you.");
1034 case PM_DISENCHANTER:
1035 /* picks an intrinsic at random and removes it; there's
1036 no feedback if hero already lacks the chosen ability */
1037 debugpline0("using attrcurse to strip an intrinsic");
1040 case PM_MIND_FLAYER:
1041 case PM_MASTER_MIND_FLAYER:
1042 if (ABASE(A_INT) < ATTRMAX(A_INT)) {
1044 pline("Yum! That was real brain food!");
1045 (void) adjattrib(A_INT, 1, FALSE);
1046 break; /* don't give them telepathy, too */
1049 pline("For some reason, that tasted bland.");
1053 struct permonst *ptr = &mons[pm];
1054 boolean conveys_STR = is_giant(ptr);
1057 if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU)
1058 || pm == PM_VIOLET_FUNGUS) {
1059 pline("Oh wow! Great stuff!");
1060 (void) make_hallucinated((HHallucination & TIMEOUT) + 200L, FALSE,
1064 /* Check the monster for all of the intrinsics. If this
1065 * monster can give more than one, pick one to try to give
1066 * from among all it can give.
1068 * Strength from giants is now treated like an intrinsic
1069 * rather than being given unconditionally.
1071 count = 0; /* number of possible intrinsics */
1072 tmp = 0; /* which one we will try to give */
1075 tmp = -1; /* use -1 as fake prop index for STR */
1076 debugpline1("\"Intrinsic\" strength, %d", tmp);
1078 for (i = 1; i <= LAST_PROP; i++) {
1079 if (!intrinsic_possible(i, ptr))
1082 /* a 1 in count chance of replacing the old choice
1083 with this one, and a count-1 in count chance
1084 of keeping the old choice (note that 1 in 1 and
1085 0 in 1 are what we want for the first candidate) */
1087 debugpline2("Intrinsic %d replacing %d", i, tmp);
1091 /* if strength is the only candidate, give it 50% chance */
1092 if (conveys_STR && count == 1 && !rn2(2))
1094 /* if something was chosen, give it now (givit() might fail) */
1096 gainstr((struct obj *) 0, 0, TRUE);
1102 if (catch_lycanthropy)
1103 retouch_equipment(2);
1109 violated_vegetarian()
1111 u.uconduct.unvegetarian++;
1112 if (Role_if(PM_MONK)) {
1113 You_feel("guilty.");
1119 /* common code to check and possibly charge for 1 context.tin.tin,
1120 * will split() context.tin.tin if necessary */
1122 costly_tin(alter_type)
1123 int alter_type; /* COST_xxx */
1125 struct obj *tin = context.tin.tin;
1127 if (carried(tin) ? tin->unpaid
1128 : (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) {
1129 if (tin->quan > 1L) {
1130 tin = context.tin.tin = splitobj(tin, 1L);
1131 context.tin.o_id = tin->o_id;
1133 costly_alteration(tin, alter_type);
1138 tin_variety_txt(s, tinvariety)
1144 if (s && tinvariety) {
1146 for (k = 0; k < TTSZ - 1; ++k) {
1147 l = (int) strlen(tintxts[k].txt);
1148 if (!strncmpi(s, tintxts[k].txt, l) && ((int) strlen(s) > l)
1159 * This assumes that buf already contains the word "tin",
1160 * as is the case with caller xname().
1163 tin_details(obj, mnum, buf)
1169 int r = tin_variety(obj, TRUE);
1172 if (r == SPINACH_TIN)
1173 Strcat(buf, " of spinach");
1174 else if (mnum == NON_PM)
1175 Strcpy(buf, "empty tin");
1177 if ((obj->cknown || iflags.override_ID) && obj->spe < 0) {
1178 if (r == ROTTEN_TIN || r == HOMEMADE_TIN) {
1179 /* put these before the word tin */
1180 Sprintf(buf2, "%s %s of ", tintxts[r].txt, buf);
1183 Sprintf(eos(buf), " of %s ", tintxts[r].txt);
1186 Strcpy(eos(buf), " of ");
1188 if (vegetarian(&mons[mnum]))
1189 Sprintf(eos(buf), "%s", mons[mnum].mname);
1191 Sprintf(eos(buf), "%s meat", mons[mnum].mname);
1197 set_tin_variety(obj, forcetype)
1203 if (forcetype == SPINACH_TIN
1204 || (forcetype == HEALTHY_TIN
1205 && (obj->corpsenm == NON_PM /* empty or already spinach */
1206 || !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */
1207 obj->corpsenm = NON_PM; /* not based on any monster */
1208 obj->spe = 1; /* spinach */
1210 } else if (forcetype == HEALTHY_TIN) {
1211 r = tin_variety(obj, FALSE);
1212 if (r < 0 || r >= TTSZ)
1213 r = ROTTEN_TIN; /* shouldn't happen */
1214 while ((r == ROTTEN_TIN && !obj->cursed) || !tintxts[r].fodder)
1216 } else if (forcetype >= 0 && forcetype < TTSZ - 1) {
1218 } else { /* RANDOM_TIN */
1219 r = rn2(TTSZ - 1); /* take your pick */
1220 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1221 r = HOMEMADE_TIN; /* lizards don't rot */
1223 obj->spe = -(r + 1); /* offset by 1 to allow index 0 */
1227 tin_variety(obj, disp)
1229 boolean disp; /* we're just displaying so leave things alone */
1233 if (obj->spe == 1) {
1235 } else if (obj->cursed) {
1236 r = ROTTEN_TIN; /* always rotten if cursed */
1237 } else if (obj->spe < 0) {
1239 --r; /* get rid of the offset */
1243 if (!disp && r == HOMEMADE_TIN && !obj->blessed && !rn2(7))
1244 r = ROTTEN_TIN; /* some homemade tins go bad */
1246 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1247 r = HOMEMADE_TIN; /* lizards don't rot */
1257 struct obj *tin = context.tin.tin;
1259 r = tin_variety(tin, FALSE);
1260 if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) {
1261 b_trapped("tin", 0);
1262 costly_tin(COST_DSTROY);
1266 pline1(mesg); /* "You succeed in opening the tin." */
1268 if (r != SPINACH_TIN) {
1269 mnum = tin->corpsenm;
1270 if (mnum == NON_PM) {
1271 pline("It turns out to be empty.");
1272 tin->dknown = tin->known = 1;
1273 costly_tin(COST_OPEN);
1277 which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1278 if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1279 && (Stone_resistance || Hallucination)) {
1281 which = 1; /* suppress pluralization */
1282 } else if (Hallucination) {
1283 what = rndmonnam(NULL);
1285 what = mons[mnum].mname;
1286 if (the_unique_pm(&mons[mnum]))
1288 else if (type_is_pname(&mons[mnum]))
1292 what = makeplural(what);
1293 else if (which == 2)
1296 pline("It smells like %s.", what);
1297 if (yn("Eat it?") == 'n') {
1299 You("discard the open tin.");
1301 tin->dknown = tin->known = 1;
1302 costly_tin(COST_OPEN);
1306 /* in case stop_occupation() was called on previous meal */
1307 context.victual.piece = (struct obj *) 0;
1308 context.victual.o_id = 0;
1309 context.victual.fullwarn = context.victual.eating =
1310 context.victual.doreset = FALSE;
1312 You("consume %s %s.", tintxts[r].txt, mons[mnum].mname);
1314 eating_conducts(&mons[mnum]);
1316 tin->dknown = tin->known = 1;
1320 /* charge for one at pre-eating cost */
1321 costly_tin(COST_OPEN);
1323 if (tintxts[r].nut < 0) /* rotten */
1324 make_vomiting((long) rn1(15, 10), FALSE);
1326 lesshungry(tintxts[r].nut);
1328 if (tintxts[r].greasy) {
1329 /* Assume !Glib, because you can't open tins when Glib. */
1330 incr_itimeout(&Glib, rnd(15));
1331 pline("Eating %s food made your %s very slippery.",
1332 tintxts[r].txt, makeplural(body_part(FINGER)));
1335 } else { /* spinach... */
1337 pline("It contains some decaying%s%s substance.",
1338 Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
1340 pline("It contains spinach.");
1341 tin->dknown = tin->known = 1;
1344 if (yn("Eat it?") == 'n') {
1346 You("discard the open tin.");
1347 costly_tin(COST_OPEN);
1352 * Same order as with non-spinach above:
1353 * conduct update, side-effects, shop handling, and nutrition.
1356 .food++; /* don't need vegan/vegetarian checks for spinach */
1358 pline("This makes you feel like %s!",
1359 Hallucination ? "Swee'pea" : "Popeye");
1360 gainstr(tin, 0, FALSE);
1362 costly_tin(COST_OPEN);
1364 lesshungry(tin->blessed
1367 ? (400 + rnd(200)) /* uncursed */
1368 : (200 + rnd(400))); /* cursed */
1376 context.tin.tin = (struct obj *) 0;
1377 context.tin.o_id = 0;
1380 /* called during each move whilst opening a tin */
1384 /* perhaps it was stolen (although that should cause interruption) */
1385 if (!carried(context.tin.tin)
1386 && (!obj_here(context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE)))
1387 return 0; /* %% probably we should use tinoid */
1388 if (context.tin.usedtime++ >= 50) {
1389 You("give up your attempt to open the tin.");
1392 if (context.tin.usedtime < context.tin.reqtime)
1393 return 1; /* still busy */
1395 consume_tin("You succeed in opening the tin.");
1399 /* called when starting to open a tin */
1404 const char *mesg = 0;
1407 if (metallivorous(youmonst.data)) {
1408 mesg = "You bite right into the metal tin...";
1410 } else if (cantwield(youmonst.data)) { /* nohands || verysmall */
1411 You("cannot handle the tin properly to open it.");
1413 } else if (otmp->blessed) {
1414 /* 50/50 chance for immediate access vs 1 turn delay (unless
1415 wielding blessed tin opener which always yields immediate
1416 access); 1 turn delay case is non-deterministic: getting
1417 interrupted and retrying might yield another 1 turn delay
1418 or might open immediately on 2nd (or 3rd, 4th, ...) try */
1419 tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : rn2(2);
1421 mesg = "The tin opens like magic!";
1423 pline_The("tin seems easy to open.");
1425 switch (uwep->otyp) {
1427 mesg = "You easily open the tin."; /* iff tmp==0 */
1428 tmp = rn2(uwep->cursed ? 3 : !uwep->blessed ? 2 : 1);
1445 pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0));
1448 pline("It is not so easy to open this tin.");
1450 pline_The("tin slips from your %s.",
1451 makeplural(body_part(FINGER)));
1452 if (otmp->quan > 1L) {
1453 otmp = splitobj(otmp, 1L);
1461 tmp = rn1(1 + 500 / ((int) (ACURR(A_DEX) + ACURRSTR)), 10);
1464 context.tin.tin = otmp;
1465 context.tin.o_id = otmp->o_id;
1467 consume_tin(mesg); /* begin immediately */
1469 context.tin.reqtime = tmp;
1470 context.tin.usedtime = 0;
1471 set_occupation(opentin, "opening the tin", 0);
1476 /* called when waking up after fainting */
1478 Hear_again(VOID_ARGS)
1480 /* Chance of deafness going away while fainted/sleeping/etc. */
1482 make_deaf(0L, FALSE);
1486 /* called on the "first bite" of rotten food */
1491 pline("Blecch! Rotten %s!", foodword(obj));
1494 You_feel("rather trippy.");
1496 You_feel("rather %s.", body_part(LIGHT_HEADED));
1497 make_confused(HConfusion + d(2, 4), FALSE);
1498 } else if (!rn2(4) && !Blind) {
1499 pline("Everything suddenly goes dark.");
1500 make_blinded((long) d(2, 10), FALSE);
1502 Your1(vision_clears);
1503 } else if (!rn2(3)) {
1504 const char *what, *where;
1505 int duration = rnd(10);
1508 what = "goes", where = "dark";
1509 else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
1510 what = "you lose control of", where = "yourself";
1512 what = "you slap against the",
1513 where = (u.usteed) ? "saddle" : surface(u.ux, u.uy);
1514 pline_The("world spins and %s %s.", what, where);
1515 incr_itimeout(&HDeaf, duration);
1517 multi_reason = "unconscious from rotten food";
1518 nomovemsg = "You are conscious again.";
1519 afternmv = Hear_again;
1525 /* called when a corpse is selected as food */
1530 int tp = 0, mnum = otmp->corpsenm;
1533 boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
1534 && !poly_when_stoned(youmonst.data));
1537 if (!vegan(&mons[mnum]))
1538 u.uconduct.unvegan++;
1539 if (!vegetarian(&mons[mnum]))
1540 violated_vegetarian();
1542 if (!nonrotting_corpse(mnum)) {
1543 long age = peek_at_iced_corpse_age(otmp);
1545 rotted = (monstermoves - age) / (10L + rn2(20));
1548 else if (otmp->blessed)
1552 if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) {
1553 boolean cannibal = maybe_cannibal(mnum, FALSE);
1555 pline("Ulch - that %s was tainted%s!",
1556 mons[mnum].mlet == S_FUNGUS
1557 ? "fungoid vegetation"
1558 : !vegetarian(&mons[mnum]) ? "meat" : "protoplasm",
1559 cannibal ? ", you cannibal" : "");
1560 if (Sick_resistance) {
1561 pline("It doesn't seem at all sickening, though...");
1565 sick_time = (long) rn1(10, 10);
1566 /* make sure new ill doesn't result in improvement */
1567 if (Sick && (sick_time > Sick))
1568 sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1569 make_sick(sick_time, corpse_xname(otmp, "rotted", CXN_NORMAL),
1570 TRUE, SICK_VOMITABLE);
1577 } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1579 You("have a very bad case of stomach acid."); /* not body_part() */
1580 losehp(rnd(15), "acidic corpse", KILLED_BY_AN); /* acid damage */
1581 } else if (poisonous(&mons[mnum]) && rn2(5)) {
1583 pline("Ecch - that must have been poisonous!");
1584 if (!Poison_resistance) {
1586 losehp(rnd(15), "poisonous corpse", KILLED_BY_AN);
1588 You("seem unaffected by the poison.");
1589 /* now any corpse left too long will make you mildly ill */
1590 } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) {
1592 You_feel("%ssick.", (Sick) ? "very " : "");
1593 losehp(rnd(8), "cadaver", KILLED_BY_AN);
1596 /* delay is weight dependent */
1597 context.victual.reqtime = 3 + (mons[mnum].cwt >> 6);
1599 if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) {
1600 if (rottenfood(otmp)) {
1601 otmp->orotten = TRUE;
1602 (void) touchfood(otmp);
1606 if (!mons[otmp->corpsenm].cnutrit) {
1607 /* no nutrition: rots away, no message if you passed out */
1609 pline_The("corpse rots away completely.");
1618 consume_oeaten(otmp, 2); /* oeaten >>= 2 */
1619 } else if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1620 && (Stone_resistance || Hallucination)) {
1621 pline("This tastes just like chicken!");
1622 } else if (mnum == PM_FLOATING_EYE && u.umonnum == PM_RAVEN) {
1623 You("peck the eyeball with delight.");
1625 /* [is this right? omnivores end up always disliking the taste] */
1626 boolean yummy = vegan(&mons[mnum])
1627 ? (!carnivorous(youmonst.data)
1628 && herbivorous(youmonst.data))
1629 : (carnivorous(youmonst.data)
1630 && !herbivorous(youmonst.data));
1633 type_is_pname(&mons[mnum])
1634 ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ",
1635 food_xname(otmp, FALSE),
1637 ? (yummy ? ((u.umonnum == PM_TIGER) ? "is gr-r-reat"
1640 : (yummy ? "is delicious" : "tastes terrible"));
1646 /* called as you start to eat */
1651 const char *old_nomovemsg, *save_nomovemsg;
1653 debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp,
1654 (unsigned long) context.victual.piece);
1655 debugpline1("reqtime = %d", context.victual.reqtime);
1656 debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1657 debugpline1("nmod = %d", context.victual.nmod);
1658 debugpline1("oeaten = %d", otmp->oeaten);
1659 context.victual.fullwarn = context.victual.doreset = FALSE;
1660 context.victual.eating = TRUE;
1662 if (otmp->otyp == CORPSE || otmp->globby) {
1663 cprefx(context.victual.piece->corpsenm);
1664 if (!context.victual.piece || !context.victual.eating) {
1665 /* rider revived, or died and lifesaved */
1670 old_nomovemsg = nomovemsg;
1672 /* survived choking, finish off food that's nearly done;
1673 need this to handle cockatrice eggs, fortune cookies, etc */
1674 if (++context.victual.usedtime >= context.victual.reqtime) {
1675 /* don't want done_eating() to issue nomovemsg if it
1676 is due to vomit() called by bite() */
1677 save_nomovemsg = nomovemsg;
1682 nomovemsg = save_nomovemsg;
1687 if (++context.victual.usedtime >= context.victual.reqtime) {
1688 /* print "finish eating" message if they just resumed -dlc */
1689 done_eating(context.victual.reqtime > 1 ? TRUE : FALSE);
1693 Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1694 set_occupation(eatfood, msgbuf, 0);
1698 * called on "first bite" of (non-corpse) food.
1699 * used for non-rotten non-tin non-corpse food
1705 switch (otmp->otyp) {
1707 if (u.uhunger <= 200)
1708 pline(Hallucination ? "Oh wow, like, superior, man!"
1709 : "That food really hit the spot!");
1710 else if (u.uhunger <= 700)
1711 pline("That satiated your %s!", body_part(STOMACH));
1714 if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1715 pline("That tripe ration was surprisingly good!");
1716 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
1717 pline(Hallucination ? "Tastes great! Less filling!"
1718 : "Mmm, tripe... not bad!");
1720 pline("Yak - dog food!");
1721 more_experienced(1, 0);
1723 /* not cannibalism, but we use similar criteria
1724 for deciding whether to be sickened by this meal */
1725 if (rn2(2) && !CANNIBAL_ALLOWED())
1726 make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE);
1731 case HUGE_CHUNK_OF_MEAT:
1734 case CLOVE_OF_GARLIC:
1735 if (is_undead(youmonst.data)) {
1736 make_vomiting((long) rn1(context.victual.reqtime, 5), FALSE);
1741 if (otmp->otyp == SLIME_MOLD && !otmp->cursed
1742 && otmp->spe == context.current_fruit) {
1743 pline("My, that was a %s %s!",
1744 Hallucination ? "primo" : "yummy",
1745 singular(otmp, xname));
1746 } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
1747 ; /* skip core joke; feedback deferred til fpostfx() */
1749 #if defined(MAC) || defined(MACOSX)
1750 /* KMH -- Why should Unix have all the fun?
1751 We check MACOSX before UNIX to get the Apple-specific apple
1752 message; the '#if UNIX' code will still kick in for pear. */
1753 } else if (otmp->otyp == APPLE) {
1754 pline("Delicious! Must be a Macintosh!");
1758 } else if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1759 if (!Hallucination) {
1760 pline("Core dumped.");
1762 /* This is based on an old Usenet joke, a fake a.out manual
1767 pline("%s -- core dumped.",
1769 ? "Segmentation fault"
1775 } else if (otmp->otyp == EGG && stale_egg(otmp)) {
1776 pline("Ugh. Rotten egg."); /* perhaps others like it */
1777 make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE);
1780 pline("This %s is %s", singular(otmp, xname),
1782 ? (Hallucination ? "grody!" : "terrible!")
1783 : (otmp->otyp == CRAM_RATION
1784 || otmp->otyp == K_RATION
1785 || otmp->otyp == C_RATION)
1787 : Hallucination ? "gnarly!" : "delicious!");
1789 break; /* default */
1793 /* increment a combat intrinsic with limits on its growth */
1795 bounded_increase(old, inc, typ)
1798 int absold, absinc, sgnold, sgninc;
1800 /* don't include any amount coming from worn rings */
1801 if (uright && uright->otyp == typ)
1803 if (uleft && uleft->otyp == typ)
1805 absold = abs(old), absinc = abs(inc);
1806 sgnold = sgn(old), sgninc = sgn(inc);
1808 if (absinc == 0 || sgnold != sgninc || absold + absinc < 10) {
1809 ; /* use inc as-is */
1810 } else if (absold + absinc < 20) {
1811 absinc = rnd(absinc); /* 1..n */
1812 if (absold + absinc < 10)
1813 absinc = 10 - absold;
1814 inc = sgninc * absinc;
1815 } else if (absold + absinc < 40) {
1816 absinc = rn2(absinc) ? 1 : 0;
1817 if (absold + absinc < 20)
1818 absinc = rnd(20 - absold);
1819 inc = sgninc * absinc;
1821 inc = 0; /* no further increase allowed via this method */
1827 accessory_has_effect(otmp)
1830 pline("Magic spreads through your body as you digest the %s.",
1831 otmp->oclass == RING_CLASS ? "ring" : "amulet");
1838 int typ = otmp->otyp;
1841 /* Note: rings are not so common that this is unbalancing. */
1842 /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1843 oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
1844 if (otmp == uleft || otmp == uright) {
1847 return; /* died from sink fall */
1849 otmp->known = otmp->dknown = 1; /* by taste */
1850 if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
1851 switch (otmp->otyp) {
1853 if (!objects[typ].oc_oprop)
1854 break; /* should never happen */
1856 if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1857 accessory_has_effect(otmp);
1859 u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1862 case RIN_SEE_INVISIBLE:
1863 set_mimic_blocking();
1865 if (Invis && !oldprop && !ESee_invisible
1866 && !perceives(youmonst.data) && !Blind) {
1868 pline("Suddenly you can see yourself.");
1872 case RIN_INVISIBILITY:
1873 if (!oldprop && !EInvis && !BInvis && !See_invisible
1876 Your("body takes on a %s transparency...",
1877 Hallucination ? "normal" : "strange");
1881 case RIN_PROTECTION_FROM_SHAPE_CHAN:
1884 case RIN_LEVITATION:
1885 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1886 u.uprops[LEVITATION].intrinsic = oldprop;
1889 incr_itimeout(&HLevitation, d(10, 20));
1893 } /* inner switch */
1894 break; /* default case of outer switch */
1897 accessory_has_effect(otmp);
1898 if (adjattrib(A_CHA, otmp->spe, -1))
1901 case RIN_GAIN_STRENGTH:
1902 accessory_has_effect(otmp);
1903 if (adjattrib(A_STR, otmp->spe, -1))
1906 case RIN_GAIN_CONSTITUTION:
1907 accessory_has_effect(otmp);
1908 if (adjattrib(A_CON, otmp->spe, -1))
1911 case RIN_INCREASE_ACCURACY:
1912 accessory_has_effect(otmp);
1913 u.uhitinc = (schar) bounded_increase((int) u.uhitinc, otmp->spe,
1914 RIN_INCREASE_ACCURACY);
1916 case RIN_INCREASE_DAMAGE:
1917 accessory_has_effect(otmp);
1918 u.udaminc = (schar) bounded_increase((int) u.udaminc, otmp->spe,
1919 RIN_INCREASE_DAMAGE);
1921 case RIN_PROTECTION:
1922 accessory_has_effect(otmp);
1923 HProtection |= FROMOUTSIDE;
1924 u.ublessed = bounded_increase(u.ublessed, otmp->spe,
1928 case RIN_FREE_ACTION:
1929 /* Give sleep resistance instead */
1930 if (!(HSleep_resistance & FROMOUTSIDE))
1931 accessory_has_effect(otmp);
1932 if (!Sleep_resistance)
1933 You_feel("wide awake.");
1934 HSleep_resistance |= FROMOUTSIDE;
1936 case AMULET_OF_CHANGE:
1937 accessory_has_effect(otmp);
1940 You("are suddenly very %s!",
1941 flags.female ? "feminine" : "masculine");
1944 case AMULET_OF_UNCHANGING:
1945 /* un-change: it's a pun */
1946 if (!Unchanging && Upolyd) {
1947 accessory_has_effect(otmp);
1952 case AMULET_OF_STRANGULATION: /* bad idea! */
1953 /* no message--this gives no permanent effect */
1956 case AMULET_OF_RESTFUL_SLEEP: { /* another bad idea! */
1957 long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT);
1959 if (!(HSleepy & FROMOUTSIDE))
1960 accessory_has_effect(otmp);
1961 HSleepy |= FROMOUTSIDE;
1962 /* might also be wearing one; use shorter of two timeouts */
1963 if (newnap < oldnap || oldnap == 0L)
1964 HSleepy = (HSleepy & ~TIMEOUT) | newnap;
1967 case RIN_SUSTAIN_ABILITY:
1968 case AMULET_OF_LIFE_SAVING:
1969 case AMULET_OF_REFLECTION: /* nice try */
1970 /* can't eat Amulet of Yendor or fakes,
1971 * and no oc_prop even if you could -3.
1978 /* called after eating non-food */
1982 struct obj *otmp = context.victual.piece;
1984 /* lesshungry wants an occupation to handle choke messages correctly */
1985 set_occupation(eatfood, "eating non-food", 0);
1986 lesshungry(context.victual.nmod);
1988 context.victual.piece = (struct obj *) 0;
1989 context.victual.o_id = 0;
1990 context.victual.eating = 0;
1991 if (otmp->oclass == COIN_CLASS) {
1995 useupf(otmp, otmp->quan);
1996 vault_gd_watching(GD_EATGOLD);
2000 if (otmp->otyp == SCR_MAIL) {
2002 pline("This junk mail is less than satisfying.");
2005 if (otmp->oclass == POTION_CLASS) {
2006 otmp->quan++; /* dopotion() does a useup() */
2007 (void) dopotion(otmp);
2008 } else if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) {
2010 } else if (otmp->otyp == LEASH && otmp->leashmon) {
2014 /* KMH -- idea by "Tommy the Terrorist" */
2015 if (otmp->otyp == TRIDENT && !otmp->cursed) {
2016 /* sugarless chewing gum which used to be heavily advertised on TV */
2017 pline(Hallucination ? "Four out of five dentists agree."
2018 : "That was pure chewing satisfaction!");
2019 exercise(A_WIS, TRUE);
2021 if (otmp->otyp == FLINT && !otmp->cursed) {
2022 /* chewable vitamin for kids based on "The Flintstones" TV cartoon */
2023 pline("Yabba-dabba delicious!");
2024 exercise(A_CON, TRUE);
2027 if (otmp == uwep && otmp->quan == 1L)
2029 if (otmp == uquiver && otmp->quan == 1L)
2031 if (otmp == uswapwep && otmp->quan == 1L)
2037 unpunish(); /* but no useup() */
2038 else if (carried(otmp))
2044 /* NOTE: the order of these words exactly corresponds to the
2045 order of oc_material values #define'd in objclass.h. */
2046 static const char *foodwords[] = {
2047 "meal", "liquid", "wax", "food", "meat", "paper",
2048 "cloth", "leather", "wood", "bone", "scale", "metal",
2049 "metal", "metal", "silver", "gold", "platinum", "mithril",
2050 "plastic", "glass", "rich food", "stone"
2053 STATIC_OVL const char *
2057 if (otmp->oclass == FOOD_CLASS)
2059 if (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS
2061 makeknown(otmp->otyp);
2062 return foodwords[objects[otmp->otyp].oc_material];
2065 /* called after consuming (non-corpse) food */
2070 switch (otmp->otyp) {
2071 case SPRIG_OF_WOLFSBANE:
2072 if (u.ulycn >= LOW_PM || is_were(youmonst.data))
2077 || !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))
2078 make_blinded((long) u.ucreamed, TRUE);
2080 case FORTUNE_COOKIE:
2081 outrumor(bcsign(otmp), BY_COOKIE);
2083 u.uconduct.literate++;
2085 case LUMP_OF_ROYAL_JELLY:
2086 /* This stuff seems to be VERY healthy! */
2087 gainstr(otmp, 1, TRUE);
2089 u.mh += otmp->cursed ? -rnd(20) : rnd(20);
2090 if (u.mh > u.mhmax) {
2094 } else if (u.mh <= 0) {
2098 u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
2099 if (u.uhp > u.uhpmax) {
2103 } else if (u.uhp <= 0) {
2104 killer.format = KILLED_BY_AN;
2105 Strcpy(killer.name, "rotten lump of royal jelly");
2113 if (flesh_petrifies(&mons[otmp->corpsenm])) {
2114 if (!Stone_resistance
2115 && !(poly_when_stoned(youmonst.data)
2116 && polymon(PM_STONE_GOLEM))) {
2118 Sprintf(killer.name, "%s egg",
2119 mons[otmp->corpsenm].mname);
2120 make_stoned(5L, (char *) 0, KILLED_BY_AN, killer.name);
2123 /* note: no "tastes like chicken" message for eggs */
2126 case EUCALYPTUS_LEAF:
2127 if (Sick && !otmp->cursed)
2128 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
2129 if (Vomiting && !otmp->cursed)
2130 make_vomiting(0L, TRUE);
2133 if (otmp->cursed && !Sleep_resistance) {
2134 /* Snow White; 'poisoned' applies to [a subset of] weapons,
2135 not food, so we substitute cursed; fortunately our hero
2136 won't have to wait for a prince to be rescued/revived */
2137 if (Race_if(PM_DWARF) && Hallucination)
2138 verbalize("Heigh-ho, ho-hum, I think I'll skip work today.");
2139 else if (Deaf || !flags.acoustics)
2140 You("fall asleep.");
2142 You_hear("sinister laughter as you fall asleep...");
2143 fall_asleep(-rn1(11, 20), TRUE);
2151 /* intended for eating a spellbook while polymorphed, but not used;
2152 "leather" applied to appearance, not composition, and has been
2153 changed to "leathery" to reflect that */
2154 STATIC_DCL boolean FDECL(leather_cover, (struct obj *));
2160 const char *odesc = OBJ_DESCR(objects[otmp->otyp]);
2162 if (odesc && (otmp->oclass == SPBOOK_CLASS)) {
2163 if (!strcmp(odesc, "leather"))
2171 * return 0 if the food was not dangerous.
2172 * return 1 if the food was dangerous and you chose to stop.
2173 * return 2 if the food was dangerous and you chose to eat it anyway.
2176 edibility_prompts(otmp)
2179 /* Blessed food detection grants hero a one-use
2180 * ability to detect food that is unfit for consumption
2181 * or dangerous and avoid it.
2183 char buf[BUFSZ], foodsmell[BUFSZ],
2184 it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
2185 boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE;
2186 int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm;
2189 Strcpy(foodsmell, Tobjnam(otmp, "smell"));
2190 Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
2191 Sprintf(eat_it_anyway, "Eat %s anyway?",
2192 (otmp->quan == 1L) ? "it" : "one");
2194 if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
2195 /* These checks must match those in eatcorpse() */
2196 stoneorslime = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
2197 && !poly_when_stoned(youmonst.data));
2199 if (mnum == PM_GREEN_SLIME || otmp->otyp == GLOB_OF_GREEN_SLIME)
2200 stoneorslime = (!Unchanging && !slimeproof(youmonst.data));
2202 if (cadaver && !nonrotting_corpse(mnum)) {
2203 long age = peek_at_iced_corpse_age(otmp);
2204 /* worst case rather than random
2205 in this calculation to force prompt */
2206 rotted = (monstermoves - age) / (10L + 0 /* was rn2(20) */);
2209 else if (otmp->blessed)
2215 * These problems with food should be checked in
2216 * order from most detrimental to least detrimental.
2218 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
2220 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2222 if (yn_function(buf, ynchars, 'n') == 'n')
2228 Sprintf(buf, "%s like %s could be something very dangerous! %s",
2229 foodsmell, it_or_they, eat_it_anyway);
2230 if (yn_function(buf, ynchars, 'n') == 'n')
2235 if (otmp->orotten || (cadaver && rotted > 3L)) {
2237 Sprintf(buf, "%s like %s could be rotten! %s", foodsmell, it_or_they,
2239 if (yn_function(buf, ynchars, 'n') == 'n')
2244 if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
2246 Sprintf(buf, "%s like %s might be poisonous! %s", foodsmell,
2247 it_or_they, eat_it_anyway);
2248 if (yn_function(buf, ynchars, 'n') == 'n')
2253 if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
2254 /* causes sleep, for long enough to be dangerous */
2255 Sprintf(buf, "%s like %s might have been poisoned. %s", foodsmell,
2256 it_or_they, eat_it_anyway);
2257 return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
2259 if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian
2260 && Role_if(PM_MONK)) {
2261 Sprintf(buf, "%s unhealthy. %s", foodsmell, eat_it_anyway);
2262 if (yn_function(buf, ynchars, 'n') == 'n')
2267 if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
2268 Sprintf(buf, "%s rather acidic. %s", foodsmell, eat_it_anyway);
2269 if (yn_function(buf, ynchars, 'n') == 'n')
2274 if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
2275 && otmp->oerodeproof) {
2276 Sprintf(buf, "%s disgusting to you right now. %s", foodsmell,
2278 if (yn_function(buf, ynchars, 'n') == 'n')
2285 * Breaks conduct, but otherwise safe.
2287 if (!u.uconduct.unvegan
2288 && ((material == LEATHER || material == BONE
2289 || material == DRAGON_HIDE || material == WAX)
2290 || (cadaver && !vegan(&mons[mnum])))) {
2291 Sprintf(buf, "%s foul and unfamiliar to you. %s", foodsmell,
2293 if (yn_function(buf, ynchars, 'n') == 'n')
2298 if (!u.uconduct.unvegetarian
2299 && ((material == LEATHER || material == BONE
2300 || material == DRAGON_HIDE)
2301 || (cadaver && !vegetarian(&mons[mnum])))) {
2302 Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway);
2303 if (yn_function(buf, ynchars, 'n') == 'n')
2309 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
2310 /* Tainted meat with Sick_resistance */
2311 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2313 if (yn_function(buf, ynchars, 'n') == 'n')
2326 int basenutrit; /* nutrition of full item */
2327 boolean dont_start = FALSE, nodelicious = FALSE;
2330 pline("If you can't breathe air, how can you consume solids?");
2333 if (!(otmp = floorfood("eat", 0)))
2335 if (check_capacity((char *) 0))
2339 int res = edibility_prompts(otmp);
2342 "%s stops tingling and your sense of smell returns to normal.",
2350 /* We have to make non-foods take 1 move to eat, unless we want to
2351 * do ridiculous amounts of coding to deal with partly eaten plate
2352 * mails, players who polymorph back to human in the middle of their
2353 * metallic meal, etc....
2355 if (!(carried(otmp) ? retouch_object(&otmp, FALSE)
2356 : touch_artifact(otmp, &youmonst))) {
2358 } else if (!is_edible(otmp)) {
2359 You("cannot eat that!");
2361 } else if ((otmp->owornmask & (W_ARMOR | W_TOOL | W_AMUL | W_SADDLE))
2363 /* let them eat rings */
2364 You_cant("eat %s you're wearing.", something);
2367 if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER
2368 && otmp->oerodeproof) {
2369 otmp->rknown = TRUE;
2370 if (otmp->quan > 1L) {
2372 (void) splitobj(otmp, otmp->quan - 1L);
2374 otmp = splitobj(otmp, 1L);
2376 pline("Ulch - that %s was rustproofed!", xname(otmp));
2377 /* The regurgitated object's rustproofing is gone now */
2378 otmp->oerodeproof = 0;
2379 make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE);
2380 You("spit %s out onto the %s.", the(xname(otmp)),
2381 surface(u.ux, u.uy));
2382 if (carried(otmp)) {
2389 /* KMH -- Slow digestion is... indigestible */
2390 if (otmp->otyp == RIN_SLOW_DIGESTION) {
2391 pline("This ring is indigestible!");
2392 (void) rottenfood(otmp);
2393 if (otmp->dknown && !objects[otmp->otyp].oc_name_known
2394 && !objects[otmp->otyp].oc_uname)
2398 if (otmp->oclass != FOOD_CLASS) {
2401 context.victual.reqtime = 1;
2402 context.victual.piece = otmp;
2403 context.victual.o_id = otmp->o_id;
2404 /* Don't split it, we don't need to if it's 1 move */
2405 context.victual.usedtime = 0;
2406 context.victual.canchoke = (u.uhs == SATIATED);
2407 /* Note: gold weighs 1 pt. for each 1000 pieces (see
2408 pickup.c) so gold and non-gold is consistent. */
2409 if (otmp->oclass == COIN_CLASS)
2410 basenutrit = ((otmp->quan > 200000L)
2412 : (int) (otmp->quan / 100L));
2413 else if (otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
2414 basenutrit = weight(otmp);
2415 /* oc_nutrition is usually weight anyway */
2417 basenutrit = objects[otmp->otyp].oc_nutrition;
2419 if (otmp->otyp == SCR_MAIL) {
2424 context.victual.nmod = basenutrit;
2425 context.victual.eating = TRUE; /* needed for lesshungry() */
2427 material = objects[otmp->otyp].oc_material;
2428 if (material == LEATHER || material == BONE
2429 || material == DRAGON_HIDE) {
2430 u.uconduct.unvegan++;
2431 violated_vegetarian();
2432 } else if (material == WAX)
2433 u.uconduct.unvegan++;
2437 (void) rottenfood(otmp);
2439 if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
2440 pline("Ecch - that must have been poisonous!");
2441 if (!Poison_resistance) {
2443 losehp(rnd(15), xname(otmp), KILLED_BY_AN);
2445 You("seem unaffected by the poison.");
2446 } else if (!otmp->cursed && !nodelicious) {
2447 pline("%s%s is delicious!",
2449 && otmp->oartifact < ART_ORB_OF_DETECTION)
2452 (otmp->oclass == COIN_CLASS)
2454 : singular(otmp, xname));
2460 if (otmp == context.victual.piece) {
2461 /* If they weren't able to choke, they don't suddenly become able to
2462 * choke just because they were interrupted. On the other hand, if
2463 * they were able to choke before, if they lost food it's possible
2464 * they shouldn't be able to choke now.
2466 if (u.uhs != SATIATED)
2467 context.victual.canchoke = FALSE;
2468 context.victual.o_id = 0;
2469 context.victual.piece = touchfood(otmp);
2470 if (context.victual.piece)
2471 context.victual.o_id = context.victual.piece->o_id;
2472 You("resume your meal.");
2473 start_eating(context.victual.piece);
2477 /* nothing in progress - so try to find something. */
2478 /* tins are a special case */
2479 /* tins must also check conduct separately in case they're discarded */
2480 if (otmp->otyp == TIN) {
2488 context.victual.o_id = 0;
2489 context.victual.piece = otmp = touchfood(otmp);
2490 if (context.victual.piece)
2491 context.victual.o_id = context.victual.piece->o_id;
2492 context.victual.usedtime = 0;
2494 /* Now we need to calculate delay and nutritional info.
2495 * The base nutrition calculated here and in eatcorpse() accounts
2496 * for normal vs. rotten food. The reqtime and nutrit values are
2497 * then adjusted in accordance with the amount of food left.
2499 if (otmp->otyp == CORPSE || otmp->globby) {
2500 int tmp = eatcorpse(otmp);
2504 context.victual.piece = (struct obj *) 0;
2505 context.victual.o_id = 0;
2509 /* if not used up, eatcorpse sets up reqtime and may modify oeaten */
2511 /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are
2512 * all handled in the != FOOD_CLASS case, above.
2514 switch (objects[otmp->otyp].oc_material) {
2516 u.uconduct.unvegan++;
2517 if (otmp->otyp != EGG) {
2518 violated_vegetarian();
2523 if (otmp->otyp == PANCAKE || otmp->otyp == FORTUNE_COOKIE /*eggs*/
2524 || otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR /*milk*/
2525 || otmp->otyp == LUMP_OF_ROYAL_JELLY)
2526 u.uconduct.unvegan++;
2530 context.victual.reqtime = objects[otmp->otyp].oc_delay;
2531 if (otmp->otyp != FORTUNE_COOKIE
2532 && (otmp->cursed || (!nonrotting_food(otmp->otyp)
2533 && (monstermoves - otmp->age)
2534 > (otmp->blessed ? 50L : 30L)
2535 && (otmp->orotten || !rn2(7))))) {
2536 if (rottenfood(otmp)) {
2537 otmp->orotten = TRUE;
2540 consume_oeaten(otmp, 1); /* oeaten >>= 1 */
2545 /* re-calc the nutrition */
2546 if (otmp->otyp == CORPSE)
2547 basenutrit = mons[otmp->corpsenm].cnutrit;
2549 basenutrit = objects[otmp->otyp].oc_nutrition;
2551 debugpline1("before rounddiv: context.victual.reqtime == %d",
2552 context.victual.reqtime);
2553 debugpline2("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit);
2554 context.victual.reqtime = (basenutrit == 0)
2556 : rounddiv(context.victual.reqtime
2557 * (long) otmp->oeaten,
2559 debugpline1("after rounddiv: context.victual.reqtime == %d",
2560 context.victual.reqtime);
2562 * calculate the modulo value (nutrit. units per round eating)
2563 * note: this isn't exact - you actually lose a little nutrition due
2565 * TODO: add in a "remainder" value to be given at the end of the meal.
2567 if (context.victual.reqtime == 0 || otmp->oeaten == 0)
2568 /* possible if most has been eaten before */
2569 context.victual.nmod = 0;
2570 else if ((int) otmp->oeaten >= context.victual.reqtime)
2571 context.victual.nmod = -((int) otmp->oeaten
2572 / context.victual.reqtime);
2574 context.victual.nmod = context.victual.reqtime % otmp->oeaten;
2575 context.victual.canchoke = (u.uhs == SATIATED);
2582 /* Take a single bite from a piece of food, checking for choking and
2583 * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
2588 if (context.victual.canchoke && u.uhunger >= 2000) {
2589 choke(context.victual.piece);
2592 if (context.victual.doreset) {
2596 force_save_hs = TRUE;
2597 if (context.victual.nmod < 0) {
2598 lesshungry(-context.victual.nmod);
2599 consume_oeaten(context.victual.piece,
2600 context.victual.nmod); /* -= -nmod */
2601 } else if (context.victual.nmod > 0
2602 && (context.victual.usedtime % context.victual.nmod)) {
2604 consume_oeaten(context.victual.piece, -1); /* -= 1 */
2606 force_save_hs = FALSE;
2611 /* as time goes by - called by moveloop() and domove() */
2615 if (u.uinvulnerable)
2616 return; /* you don't feel hungrier */
2618 if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */
2619 && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
2621 u.uhunger--; /* ordinary food consumption */
2623 if (moves % 2) { /* odd turns */
2624 /* Regeneration uses up food, unless due to an artifact */
2625 if ((HRegeneration & ~FROMFORM)
2626 || (ERegeneration & ~(W_ARTI | W_WEP)))
2628 if (near_capacity() > SLT_ENCUMBER)
2630 } else { /* even turns */
2633 /* Conflict uses up food too */
2634 if (HConflict || (EConflict & (~W_ARTI)))
2636 /* +0 charged rings don't do anything, so don't affect hunger */
2637 /* Slow digestion still uses ring hunger */
2638 switch ((int) (moves % 20)) { /* note: use even cases only */
2640 if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged))
2648 if (uright && (uright->spe || !objects[uright->otyp].oc_charged))
2662 /* called after vomiting and after performing feats of magic */
2671 /* called after eating (and after drinking fruit juice) */
2676 /* See comments in newuhs() for discussion on force_save_hs */
2677 boolean iseating = (occupation == eatfood) || force_save_hs;
2679 debugpline1("lesshungry(%d)", num);
2681 if (u.uhunger >= 2000) {
2682 if (!iseating || context.victual.canchoke) {
2684 choke(context.victual.piece);
2687 choke(occupation == opentin ? context.tin.tin
2688 : (struct obj *) 0);
2689 /* no reset_eat() */
2692 /* Have lesshungry() report when you're nearly full so all eating
2693 * warns when you're about to choke.
2695 if (u.uhunger >= 1500) {
2696 if (!context.victual.eating
2697 || (context.victual.eating && !context.victual.fullwarn)) {
2698 pline("You're having a hard time getting all of it down.");
2699 nomovemsg = "You're finally finished.";
2700 if (!context.victual.eating) {
2703 context.victual.fullwarn = TRUE;
2704 if (context.victual.canchoke
2705 && context.victual.reqtime > 1) {
2706 /* a one-gulp food will not survive a stop */
2707 if (yn_function("Continue eating?", ynchars, 'n')
2710 nomovemsg = (char *) 0;
2724 (void) Hear_again();
2725 if (u.uhs > FAINTING)
2735 return (boolean) (u.uhs == FAINTED);
2738 /* call when a faint must be prematurely terminated */
2742 if (afternmv == unfaint)
2743 unmul("You revive.");
2746 /* compute and comment on your (new?) hunger status */
2752 static unsigned save_hs;
2753 static boolean saved_hs = FALSE;
2758 : (h > 150) ? NOT_HUNGRY
2759 : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING;
2761 /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2762 * This should not produce the message "you only feel hungry now";
2763 * that message should only appear if HUNGRY is an endpoint. Therefore
2764 * we check to see if we're in the middle of eating. If so, we save
2765 * the first hunger status, and at the end of eating we decide what
2766 * message to print based on the _entire_ meal, not on each little bit.
2768 /* It is normally possible to check if you are in the middle of a meal
2769 * by checking occupation == eatfood, but there is one special case:
2770 * start_eating() can call bite() for your first bite before it
2771 * sets the occupation.
2772 * Anyone who wants to get that case to work _without_ an ugly static
2773 * force_save_hs variable, feel free.
2775 /* Note: If you become a certain hunger status in the middle of the
2776 * meal, and still have that same status at the end of the meal,
2777 * this will incorrectly print the associated message at the end of
2778 * the meal instead of the middle. Such a case is currently
2779 * impossible, but could become possible if a message for SATIATED
2780 * were added or if HUNGRY and WEAK were separated by a big enough
2781 * gap to fit two bites.
2783 if (occupation == eatfood || force_save_hs) {
2797 if (newhs == FAINTING) {
2800 if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) {
2801 if (!is_fainted() && multi >= 0 /* %% */) {
2802 int duration = 10 - (u.uhunger / 10);
2804 /* stop what you're doing, then faint */
2806 You("faint from lack of food.");
2808 selftouch("Falling, you");
2809 incr_itimeout(&HDeaf, duration);
2811 multi_reason = "fainted from lack of food";
2812 nomovemsg = "You regain consciousness.";
2816 } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) {
2820 You("die from starvation.");
2821 killer.format = KILLED_BY;
2822 Strcpy(killer.name, "starvation");
2824 /* if we return, we lifesaved, and that calls newuhs */
2829 if (newhs != u.uhs) {
2830 if (newhs >= WEAK && u.uhs < WEAK)
2831 losestr(1); /* this may kill you -- see below */
2832 else if (newhs < WEAK && u.uhs >= WEAK)
2836 if (Hallucination) {
2837 You((!incr) ? "now have a lesser case of the munchies."
2838 : "are getting the munchies.");
2840 You((!incr) ? "only feel hungry now."
2843 : "are beginning to feel hungry.");
2844 if (incr && occupation
2845 && (occupation != eatfood && occupation != opentin))
2847 context.travel = context.travel1 = context.mv = context.run = 0;
2851 pline((!incr) ? "You still have the munchies."
2852 : "The munchies are interfering with your motor capabilities.");
2853 else if (incr && (Role_if(PM_WIZARD) || Race_if(PM_ELF)
2854 || Role_if(PM_VALKYRIE)))
2855 pline("%s needs food, badly!",
2856 (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE))
2862 : (u.uhunger < 45) ? "feel weak."
2863 : "are beginning to feel weak.");
2864 if (incr && occupation
2865 && (occupation != eatfood && occupation != opentin))
2867 context.travel = context.travel1 = context.mv = context.run = 0;
2873 if ((Upolyd ? u.mh : u.uhp) < 1) {
2874 You("die from hunger and exhaustion.");
2875 killer.format = KILLED_BY;
2876 Strcpy(killer.name, "exhaustion");
2883 /* Returns an object representing food.
2884 * Object may be either on floor or in inventory.
2887 floorfood(verb, corpsecheck)
2889 int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
2891 register struct obj *otmp;
2894 boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */
2895 offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */
2897 /* if we can't touch floor objects then use invent food only */
2898 if (!can_reach_floor(TRUE) || (feeding && u.usteed)
2899 || (is_pool_or_lava(u.ux, u.uy)
2900 && (Wwalking || is_clinger(youmonst.data)
2901 || (Flying && !Breathless))))
2904 if (feeding && metallivorous(youmonst.data)) {
2906 struct trap *ttmp = t_at(u.ux, u.uy);
2908 if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
2909 /* If not already stuck in the trap, perhaps there should
2910 be a chance to becoming trapped? Probably not, because
2911 then the trap would just get eaten on the _next_ turn... */
2912 Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
2913 (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you"
2915 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2916 u.utrap = u.utraptype = 0;
2918 return mksobj(BEARTRAP, TRUE, FALSE);
2919 } else if (c == 'q') {
2920 return (struct obj *) 0;
2924 if (youmonst.data != &mons[PM_RUST_MONSTER]
2925 && (gold = g_at(u.ux, u.uy)) != 0) {
2926 if (gold->quan == 1L)
2927 Sprintf(qbuf, "There is 1 gold piece here; eat it?");
2929 Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
2931 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2933 } else if (c == 'q') {
2934 return (struct obj *) 0;
2939 /* Is there some food (probably a heavy corpse) here on the ground? */
2940 for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
2942 ? (otmp->otyp == CORPSE
2943 && (corpsecheck == 1 || tinnable(otmp)))
2944 : feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp))
2945 : otmp->oclass == FOOD_CLASS) {
2947 boolean one = (otmp->quan == 1L);
2949 /* "There is <an object> here; <verb> it?" or
2950 "There are <N objects> here; <verb> one?" */
2951 Sprintf(qbuf, "There %s ", otense(otmp, "are"));
2952 Sprintf(qsfx, " here; %s %s?", verb, one ? "it" : "one");
2953 (void) safe_qbuf(qbuf, qbuf, qsfx, otmp, doname, ansimpleoname,
2954 one ? something : (const char *) "things");
2955 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y')
2958 return (struct obj *) 0;
2963 /* We cannot use ALL_CLASSES since that causes getobj() to skip its
2964 * "ugly checks" and we need to check for inedible items.
2967 getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb);
2968 if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS))
2969 if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
2970 You_cant("%s that!", verb);
2971 return (struct obj *) 0;
2976 /* Side effects of vomiting */
2977 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
2979 vomit() /* A good idea from David Neves */
2981 if (cantvomit(youmonst.data))
2982 /* doesn't cure food poisoning; message assumes that we aren't
2983 dealing with some esoteric body_part() */
2984 Your("jaw gapes convulsively.");
2986 make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
2988 multi_reason = "vomiting";
2989 nomovemsg = You_can_move_again;
2993 eaten_stat(base, obj)
2997 long uneaten_amt, full_amount;
2999 uneaten_amt = (long) obj->oeaten;
3000 full_amount = (obj->otyp == CORPSE)
3001 ? (long) mons[obj->corpsenm].cnutrit
3002 : (long) objects[obj->otyp].oc_nutrition;
3003 if (uneaten_amt > full_amount) {
3005 "partly eaten food (%ld) more nutritious than untouched food (%ld)",
3006 uneaten_amt, full_amount);
3007 uneaten_amt = full_amount;
3010 base = (int) (full_amount ? (long) base * uneaten_amt / full_amount : 0L);
3011 return (base < 1) ? 1 : base;
3014 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
3016 consume_oeaten(obj, amt)
3021 * This is a hack to try to squelch several long standing mystery
3022 * food bugs. A better solution would be to rewrite the entire
3023 * victual handling mechanism from scratch using a less complex
3024 * model. Alternatively, this routine could call done_eating()
3025 * or food_disappears() but its callers would need revisions to
3026 * cope with context.victual.piece unexpectedly going away.
3028 * Multi-turn eating operates by setting the food's oeaten field
3029 * to its full nutritional value and then running a counter which
3030 * independently keeps track of whether there is any food left.
3031 * The oeaten field can reach exactly zero on the last turn, and
3032 * the object isn't removed from inventory until the next turn
3033 * when the "you finish eating" message gets delivered, so the
3034 * food would be restored to the status of untouched during that
3035 * interval. This resulted in unexpected encumbrance messages
3036 * at the end of a meal (if near enough to a threshold) and would
3037 * yield full food if there was an interruption on the critical
3038 * turn. Also, there have been reports over the years of food
3039 * becoming massively heavy or producing unlimited satiation;
3040 * this would occur if reducing oeaten via subtraction attempted
3041 * to drop it below 0 since its unsigned type would produce a
3042 * huge positive value instead. So far, no one has figured out
3043 * _why_ that inappropriate subtraction might sometimes happen.
3047 /* bit shift to divide the remaining amount of food */
3048 obj->oeaten >>= amt;
3050 /* simple decrement; value is negative so we actually add it */
3051 if ((int) obj->oeaten > -amt)
3057 if (obj->oeaten == 0) {
3058 if (obj == context.victual.piece) /* always true unless wishing... */
3059 context.victual.reqtime =
3060 context.victual.usedtime; /* no bites left */
3061 obj->oeaten = 1; /* smallest possible positive value */
3065 /* called when eatfood occupation has been interrupted,
3066 or in the case of theft, is about to be interrupted */
3068 maybe_finished_meal(stopping)
3071 /* in case consume_oeaten() has decided that the food is all gone */
3072 if (occupation == eatfood
3073 && context.victual.usedtime >= context.victual.reqtime) {
3075 occupation = 0; /* for do_reset_eat */
3076 (void) eatfood(); /* calls done_eating() to use up
3077 context.victual.piece */
3083 /* Tin of <something> to the rescue? Decide whether current occupation
3084 is an attempt to eat a tin of something capable of saving hero's life.
3085 We don't care about consumption of non-tinned food here because special
3086 effects there take place on first bite rather than at end of occupation.
3087 [Popeye the Sailor gets out of trouble by eating tins of spinach. :-] */
3095 if (occupation != opentin)
3097 otin = context.tin.tin;
3098 /* make sure hero still has access to tin */
3100 && (!obj_here(otin, u.ux, u.uy) || !can_reach_floor(TRUE)))
3102 /* unknown tin is assumed to be helpful */
3105 /* known tin is helpful if it will stop life-threatening problem */
3106 mndx = otin->corpsenm;
3108 /* note: not used; hunger code bypasses stop_occupation() when eating */
3110 return (boolean) (mndx != NON_PM || otin->spe == 1);
3111 /* flesh from lizards and acidic critters stops petrification */
3113 return (boolean) (mndx >= LOW_PM
3114 && (mndx == PM_LIZARD || acidic(&mons[mndx])));
3115 /* no tins can cure these (yet?) */