miscellaneous formatting
[aNetHack.git] / src / eat.c
blob2c748ef066c522898b0c184fe93c09da48adceed
1 /* NetHack 3.6 eat.c $NHDT-Date: 1470272344 2016/08/04 00:59:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.172 $ */
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 unsigned FDECL(obj_nutrition, (struct obj *));
17 STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
18 STATIC_DCL void NDECL(do_reset_eat);
19 STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
20 STATIC_DCL void FDECL(cprefx, (int));
21 STATIC_DCL int FDECL(intrinsic_possible, (int, struct permonst *));
22 STATIC_DCL void FDECL(givit, (int, struct permonst *));
23 STATIC_DCL void FDECL(cpostfx, (int));
24 STATIC_DCL void FDECL(consume_tin, (const char *));
25 STATIC_DCL void FDECL(start_tin, (struct obj *));
26 STATIC_DCL int FDECL(eatcorpse, (struct obj *));
27 STATIC_DCL void FDECL(start_eating, (struct obj *));
28 STATIC_DCL void FDECL(fprefx, (struct obj *));
29 STATIC_DCL void FDECL(fpostfx, (struct obj *));
30 STATIC_DCL int NDECL(bite);
31 STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
32 STATIC_DCL int FDECL(rottenfood, (struct obj *));
33 STATIC_DCL void NDECL(eatspecial);
34 STATIC_DCL int FDECL(bounded_increase, (int, int, int));
35 STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
36 STATIC_DCL void FDECL(eataccessory, (struct obj *));
37 STATIC_DCL const char *FDECL(foodword, (struct obj *));
38 STATIC_DCL int FDECL(tin_variety, (struct obj *, BOOLEAN_P));
39 STATIC_DCL boolean FDECL(maybe_cannibal, (int, BOOLEAN_P));
41 char msgbuf[BUFSZ];
43 /* also used to see if you're allowed to eat cats and dogs */
44 #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
46 /* monster types that cause hero to be turned into stone if eaten */
47 #define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA])
49 /* Rider corpses are treated as non-rotting so that attempting to eat one
50 will be sure to reach the stage of eating where that meal is fatal */
51 #define nonrotting_corpse(mnum) \
52 ((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum]))
54 /* non-rotting non-corpses; unlike lizard corpses, these items will behave
55 as if rotten if they are cursed (fortune cookies handled elsewhere) */
56 #define nonrotting_food(otyp) \
57 ((otyp) == LEMBAS_WAFER || (otyp) == CRAM_RATION)
59 STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
60 STATIC_OVL NEARDATA const char offerfodder[] = { FOOD_CLASS, AMULET_CLASS,
61 0 };
63 /* Gold must come first for getobj(). */
64 STATIC_OVL NEARDATA const char allobj[] = {
65 COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS,
66 SCROLL_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
67 FOOD_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS,
68 BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0
71 STATIC_OVL boolean force_save_hs = FALSE;
73 /* see hunger states in hack.h - texts used on bottom line */
74 const char *hu_stat[] = { "Satiated", " ", "Hungry ", "Weak ",
75 "Fainting", "Fainted ", "Starved " };
78 * Decide whether a particular object can be eaten by the possibly
79 * polymorphed character. Not used for monster checks.
81 boolean
82 is_edible(obj)
83 register struct obj *obj;
85 /* protect invocation tools but not Rider corpses (handled elsewhere)*/
86 /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
87 if (objects[obj->otyp].oc_unique)
88 return FALSE;
89 /* above also prevents the Amulet from being eaten, so we must never
90 allow fake amulets to be eaten either [which is already the case] */
92 if (metallivorous(youmonst.data) && is_metallic(obj)
93 && (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
94 return TRUE;
96 /* Ghouls only eat non-veggy corpses or eggs (see dogfood()) */
97 if (u.umonnum == PM_GHOUL)
98 return (boolean)((obj->otyp == CORPSE
99 && !vegan(&mons[obj->corpsenm]))
100 || (obj->otyp == EGG));
102 if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj)
103 /* [g.cubes can eat containers and retain all contents
104 as engulfed items, but poly'd player can't do that] */
105 && !Has_contents(obj))
106 return TRUE;
108 /* return (boolean) !!index(comestibles, obj->oclass); */
109 return (boolean) (obj->oclass == FOOD_CLASS);
112 void
113 init_uhunger()
115 u.uhunger = 900;
116 u.uhs = NOT_HUNGRY;
119 /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */
120 static const struct {
121 const char *txt; /* description */
122 int nut; /* nutrition */
123 Bitfield(fodder, 1); /* stocked by health food shops */
124 Bitfield(greasy, 1); /* causes slippery fingers */
125 } tintxts[] = { { "rotten", -50, 0, 0 }, /* ROTTEN_TIN = 0 */
126 { "homemade", 50, 1, 0 }, /* HOMEMADE_TIN = 1 */
127 { "soup made from", 20, 1, 0 },
128 { "french fried", 40, 0, 1 },
129 { "pickled", 40, 1, 0 },
130 { "boiled", 50, 1, 0 },
131 { "smoked", 50, 1, 0 },
132 { "dried", 55, 1, 0 },
133 { "deep fried", 60, 0, 1 },
134 { "szechuan", 70, 1, 0 },
135 { "broiled", 80, 0, 0 },
136 { "stir fried", 80, 0, 1 },
137 { "sauteed", 95, 0, 0 },
138 { "candied", 100, 1, 0 },
139 { "pureed", 500, 1, 0 },
140 { "", 0, 0, 0 } };
141 #define TTSZ SIZE(tintxts)
143 static char *eatmbuf = 0; /* set by cpostfx() */
145 /* called after mimicing is over */
146 STATIC_PTR int
147 eatmdone(VOID_ARGS)
149 /* release `eatmbuf' */
150 if (eatmbuf) {
151 if (nomovemsg == eatmbuf)
152 nomovemsg = 0;
153 free((genericptr_t) eatmbuf), eatmbuf = 0;
155 /* update display */
156 if (youmonst.m_ap_type) {
157 youmonst.m_ap_type = M_AP_NOTHING;
158 newsym(u.ux, u.uy);
160 return 0;
163 /* called when hallucination is toggled */
164 void
165 eatmupdate()
167 const char *altmsg = 0;
168 int altapp = 0; /* lint suppression */
170 if (!eatmbuf || nomovemsg != eatmbuf)
171 return;
173 if (is_obj_mappear(&youmonst,ORANGE) && !Hallucination) {
174 /* revert from hallucinatory to "normal" mimicking */
175 altmsg = "You now prefer mimicking yourself.";
176 altapp = GOLD_PIECE;
177 } else if (is_obj_mappear(&youmonst,GOLD_PIECE) && Hallucination) {
178 /* won't happen; anything which might make immobilized
179 hero begin hallucinating (black light attack, theft
180 of Grayswandir) will terminate the mimicry first */
181 altmsg = "Your rind escaped intact.";
182 altapp = ORANGE;
185 if (altmsg) {
186 /* replace end-of-mimicking message */
187 if (strlen(altmsg) > strlen(eatmbuf)) {
188 free((genericptr_t) eatmbuf);
189 eatmbuf = (char *) alloc(strlen(altmsg) + 1);
191 nomovemsg = strcpy(eatmbuf, altmsg);
192 /* update current image */
193 youmonst.mappearance = altapp;
194 newsym(u.ux, u.uy);
198 /* ``[the(] singular(food, xname) [)]'' */
199 STATIC_OVL const char *
200 food_xname(food, the_pfx)
201 struct obj *food;
202 boolean the_pfx;
204 const char *result;
206 if (food->otyp == CORPSE) {
207 result = corpse_xname(food, (const char *) 0,
208 CXN_SINGULAR | (the_pfx ? CXN_PFX_THE : 0));
209 /* not strictly needed since pname values are capitalized
210 and the() is a no-op for them */
211 if (type_is_pname(&mons[food->corpsenm]))
212 the_pfx = FALSE;
213 } else {
214 /* the ordinary case */
215 result = singular(food, xname);
217 if (the_pfx)
218 result = the(result);
219 return result;
222 /* Created by GAN 01/28/87
223 * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
224 * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk.
225 * 11/10/89: if hard, rarely vomit anyway, for slim chance.
227 * To a full belly all food is bad. (It.)
229 STATIC_OVL void
230 choke(food)
231 struct obj *food;
233 /* only happens if you were satiated */
234 if (u.uhs != SATIATED) {
235 if (!food || food->otyp != AMULET_OF_STRANGULATION)
236 return;
237 } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
238 adjalign(-1); /* gluttony is unchivalrous */
239 You_feel("like a glutton!");
242 exercise(A_CON, FALSE);
244 if (Breathless || (!Strangled && !rn2(20))) {
245 /* choking by eating AoS doesn't involve stuffing yourself */
246 if (food && food->otyp == AMULET_OF_STRANGULATION) {
247 You("choke, but recover your composure.");
248 return;
250 You("stuff yourself and then vomit voluminously.");
251 morehungry(1000); /* you just got *very* sick! */
252 vomit();
253 } else {
254 killer.format = KILLED_BY_AN;
256 * Note all "killer"s below read "Choked on %s" on the
257 * high score list & tombstone. So plan accordingly.
259 if (food) {
260 You("choke over your %s.", foodword(food));
261 if (food->oclass == COIN_CLASS) {
262 Strcpy(killer.name, "very rich meal");
263 } else {
264 killer.format = KILLED_BY;
265 Strcpy(killer.name, killer_xname(food));
267 } else {
268 You("choke over it.");
269 Strcpy(killer.name, "quick snack");
271 You("die...");
272 done(CHOKING);
276 /* modify object wt. depending on time spent consuming it */
277 STATIC_OVL void
278 recalc_wt()
280 struct obj *piece = context.victual.piece;
281 if (!piece) {
282 impossible("recalc_wt without piece");
283 return;
285 debugpline1("Old weight = %d", piece->owt);
286 debugpline2("Used time = %d, Req'd time = %d", context.victual.usedtime,
287 context.victual.reqtime);
288 piece->owt = weight(piece);
289 debugpline1("New weight = %d", piece->owt);
292 /* called when eating interrupted by an event */
293 void
294 reset_eat()
296 /* we only set a flag here - the actual reset process is done after
297 * the round is spent eating.
299 if (context.victual.eating && !context.victual.doreset) {
300 debugpline0("reset_eat...");
301 context.victual.doreset = TRUE;
303 return;
306 /* base nutrition of a food-class object */
307 STATIC_OVL unsigned
308 obj_nutrition(otmp)
309 struct obj *otmp;
311 unsigned nut = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit
312 : otmp->globby ? otmp->owt
313 : (unsigned) objects[otmp->otyp].oc_nutrition;
315 if (otmp->otyp == LEMBAS_WAFER) {
316 if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
317 nut += nut / 4; /* 800 -> 1000 */
318 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
319 nut -= nut / 4; /* 800 -> 600 */
320 /* prevent polymorph making a partly eaten wafer
321 become more nutritious than an untouched one */
322 if (otmp->oeaten >= nut)
323 otmp->oeaten = (otmp->oeaten < objects[LEMBAS_WAFER].oc_nutrition)
324 ? (nut - 1) : nut;
325 } else if (otmp->otyp == CRAM_RATION) {
326 if (maybe_polyd(is_dwarf(youmonst.data), Race_if(PM_DWARF)))
327 nut += nut / 6; /* 600 -> 700 */
329 return nut;
332 STATIC_OVL struct obj *
333 touchfood(otmp)
334 struct obj *otmp;
336 if (otmp->quan > 1L) {
337 if (!carried(otmp))
338 (void) splitobj(otmp, otmp->quan - 1L);
339 else
340 otmp = splitobj(otmp, 1L);
341 debugpline0("split object,");
344 if (!otmp->oeaten) {
345 costly_alteration(otmp, COST_BITE);
346 otmp->oeaten = obj_nutrition(otmp);
349 if (carried(otmp)) {
350 freeinv(otmp);
351 if (inv_cnt(FALSE) >= 52) {
352 sellobj_state(SELL_DONTSELL);
353 dropy(otmp);
354 sellobj_state(SELL_NORMAL);
355 } else {
356 otmp->nomerge = 1; /* used to prevent merge */
357 otmp = addinv(otmp);
358 otmp->nomerge = 0;
361 return otmp;
364 /* When food decays, in the middle of your meal, we don't want to dereference
365 * any dangling pointers, so set it to null (which should still trigger
366 * do_reset_eat() at the beginning of eatfood()) and check for null pointers
367 * in do_reset_eat().
369 void
370 food_disappears(obj)
371 struct obj *obj;
373 if (obj == context.victual.piece) {
374 context.victual.piece = (struct obj *) 0;
375 context.victual.o_id = 0;
377 if (obj->timed)
378 obj_stop_timers(obj);
381 /* renaming an object used to result in it having a different address,
382 so the sequence start eating/opening, get interrupted, name the food,
383 resume eating/opening would restart from scratch */
384 void
385 food_substitution(old_obj, new_obj)
386 struct obj *old_obj, *new_obj;
388 if (old_obj == context.victual.piece) {
389 context.victual.piece = new_obj;
390 context.victual.o_id = new_obj->o_id;
392 if (old_obj == context.tin.tin) {
393 context.tin.tin = new_obj;
394 context.tin.o_id = new_obj->o_id;
398 STATIC_OVL void
399 do_reset_eat()
401 debugpline0("do_reset_eat...");
402 if (context.victual.piece) {
403 context.victual.o_id = 0;
404 context.victual.piece = touchfood(context.victual.piece);
405 if (context.victual.piece)
406 context.victual.o_id = context.victual.piece->o_id;
407 recalc_wt();
409 context.victual.fullwarn = context.victual.eating =
410 context.victual.doreset = FALSE;
411 /* Do not set canchoke to FALSE; if we continue eating the same object
412 * we need to know if canchoke was set when they started eating it the
413 * previous time. And if we don't continue eating the same object
414 * canchoke always gets recalculated anyway.
416 stop_occupation();
417 newuhs(FALSE);
420 /* called each move during eating process */
421 STATIC_PTR int
422 eatfood(VOID_ARGS)
424 if (!context.victual.piece
425 || (!carried(context.victual.piece)
426 && !obj_here(context.victual.piece, u.ux, u.uy))) {
427 /* maybe it was stolen? */
428 do_reset_eat();
429 return 0;
431 if (!context.victual.eating)
432 return 0;
434 if (++context.victual.usedtime <= context.victual.reqtime) {
435 if (bite())
436 return 0;
437 return 1; /* still busy */
438 } else { /* done */
439 done_eating(TRUE);
440 return 0;
444 STATIC_OVL void
445 done_eating(message)
446 boolean message;
448 struct obj *piece = context.victual.piece;
450 piece->in_use = TRUE;
451 occupation = 0; /* do this early, so newuhs() knows we're done */
452 newuhs(FALSE);
453 if (nomovemsg) {
454 if (message)
455 pline1(nomovemsg);
456 nomovemsg = 0;
457 } else if (message)
458 You("finish eating %s.", food_xname(piece, TRUE));
460 if (piece->otyp == CORPSE || piece->globby)
461 cpostfx(piece->corpsenm);
462 else
463 fpostfx(piece);
465 if (carried(piece))
466 useup(piece);
467 else
468 useupf(piece, 1L);
469 context.victual.piece = (struct obj *) 0;
470 context.victual.o_id = 0;
471 context.victual.fullwarn = context.victual.eating =
472 context.victual.doreset = FALSE;
475 void
476 eating_conducts(pd)
477 struct permonst *pd;
479 u.uconduct.food++;
480 if (!vegan(pd))
481 u.uconduct.unvegan++;
482 if (!vegetarian(pd))
483 violated_vegetarian();
486 /* handle side-effects of mind flayer's tentacle attack */
488 eat_brains(magr, mdef, visflag, dmg_p)
489 struct monst *magr, *mdef;
490 boolean visflag;
491 int *dmg_p; /* for dishing out extra damage in lieu of Int loss */
493 struct permonst *pd = mdef->data;
494 boolean give_nutrit = FALSE;
495 int result = MM_HIT, xtra_dmg = rnd(10);
497 if (noncorporeal(pd)) {
498 if (visflag)
499 pline("%s brain is unharmed.",
500 (mdef == &youmonst) ? "Your" : s_suffix(Monnam(mdef)));
501 return MM_MISS; /* side-effects can't occur */
502 } else if (magr == &youmonst) {
503 You("eat %s brain!", s_suffix(mon_nam(mdef)));
504 } else if (mdef == &youmonst) {
505 Your("brain is eaten!");
506 } else { /* monster against monster */
507 if (visflag && canspotmon(mdef))
508 pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
511 if (flesh_petrifies(pd)) {
512 /* mind flayer has attempted to eat the brains of a petrification
513 inducing critter (most likely Medusa; attacking a cockatrice via
514 tentacle-touch should have been caught before reaching this far) */
515 if (magr == &youmonst) {
516 if (!Stone_resistance && !Stoned)
517 make_stoned(5L, (char *) 0, KILLED_BY_AN, pd->mname);
518 } else {
519 /* no need to check for poly_when_stoned or Stone_resistance;
520 mind flayers don't have those capabilities */
521 if (visflag && canseemon(magr))
522 pline("%s turns to stone!", Monnam(magr));
523 monstone(magr);
524 if (magr->mhp > 0) {
525 /* life-saved; don't continue eating the brains */
526 return MM_MISS;
527 } else {
528 if (magr->mtame && !visflag)
529 /* parallels mhitm.c's brief_feeling */
530 You("have a sad thought for a moment, then it passes.");
531 return MM_AGR_DIED;
536 if (magr == &youmonst) {
538 * player mind flayer is eating something's brain
540 eating_conducts(pd);
541 if (mindless(pd)) { /* (cannibalism not possible here) */
542 pline("%s doesn't notice.", Monnam(mdef));
543 /* all done; no extra harm inflicted upon target */
544 return MM_MISS;
545 } else if (is_rider(pd)) {
546 pline("Ingesting that is fatal.");
547 Sprintf(killer.name, "unwisely ate the brain of %s", pd->mname);
548 killer.format = NO_KILLER_PREFIX;
549 done(DIED);
550 /* life-saving needed to reach here */
551 exercise(A_WIS, FALSE);
552 *dmg_p += xtra_dmg; /* Rider takes extra damage */
553 } else {
554 morehungry(-rnd(30)); /* cannot choke */
555 if (ABASE(A_INT) < AMAX(A_INT)) {
556 /* recover lost Int; won't increase current max */
557 ABASE(A_INT) += rnd(4);
558 if (ABASE(A_INT) > AMAX(A_INT))
559 ABASE(A_INT) = AMAX(A_INT);
560 context.botl = 1;
562 exercise(A_WIS, TRUE);
563 *dmg_p += xtra_dmg;
565 /* targetting another mind flayer or your own underlying species
566 is cannibalism */
567 (void) maybe_cannibal(monsndx(pd), TRUE);
569 } else if (mdef == &youmonst) {
571 * monster mind flayer is eating hero's brain
573 /* no such thing as mindless players */
574 if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
575 static NEARDATA const char brainlessness[] = "brainlessness";
577 if (Lifesaved) {
578 Strcpy(killer.name, brainlessness);
579 killer.format = KILLED_BY;
580 done(DIED);
581 /* amulet of life saving has now been used up */
582 pline("Unfortunately your brain is still gone.");
583 /* sanity check against adding other forms of life-saving */
584 u.uprops[LIFESAVED].extrinsic =
585 u.uprops[LIFESAVED].intrinsic = 0L;
586 } else {
587 Your("last thought fades away.");
589 Strcpy(killer.name, brainlessness);
590 killer.format = KILLED_BY;
591 done(DIED);
592 /* can only get here when in wizard or explore mode and user has
593 explicitly chosen not to die; arbitrarily boost intelligence */
594 ABASE(A_INT) = ATTRMIN(A_INT) + 2;
595 You_feel("like a scarecrow.");
597 give_nutrit = TRUE; /* in case a conflicted pet is doing this */
598 exercise(A_WIS, FALSE);
599 /* caller handles Int and memory loss */
601 } else { /* mhitm */
603 * monster mind flayer is eating another monster's brain
605 if (mindless(pd)) {
606 if (visflag && canspotmon(mdef))
607 pline("%s doesn't notice.", Monnam(mdef));
608 return MM_MISS;
609 } else if (is_rider(pd)) {
610 mondied(magr);
611 if (magr->mhp <= 0)
612 result = MM_AGR_DIED;
613 /* Rider takes extra damage regardless of whether attacker dies */
614 *dmg_p += xtra_dmg;
615 } else {
616 *dmg_p += xtra_dmg;
617 give_nutrit = TRUE;
618 if (*dmg_p >= mdef->mhp && visflag && canspotmon(mdef))
619 pline("%s last thought fades away...",
620 s_suffix(Monnam(mdef)));
624 if (give_nutrit && magr->mtame && !magr->isminion) {
625 EDOG(magr)->hungrytime += rnd(60);
626 magr->mconf = 0;
629 return result;
632 /* eating a corpse or egg of one's own species is usually naughty */
633 STATIC_OVL boolean
634 maybe_cannibal(pm, allowmsg)
635 int pm;
636 boolean allowmsg;
638 static NEARDATA long ate_brains = 0L;
639 struct permonst *fptr = &mons[pm]; /* food type */
641 /* when poly'd into a mind flayer, multiple tentacle hits in one
642 turn cause multiple digestion checks to occur; avoid giving
643 multiple luck penalties for the same attack */
644 if (moves == ate_brains)
645 return FALSE;
646 ate_brains = moves; /* ate_anything, not just brains... */
648 if (!CANNIBAL_ALLOWED()
649 /* non-cannibalistic heroes shouldn't eat own species ever
650 and also shouldn't eat current species when polymorphed
651 (even if having the form of something which doesn't care
652 about cannibalism--hero's innate traits aren't altered) */
653 && (your_race(fptr)
654 || (Upolyd && same_race(youmonst.data, fptr))
655 || (u.ulycn >= LOW_PM && were_beastie(pm) == u.ulycn))) {
656 if (allowmsg) {
657 if (Upolyd && your_race(fptr))
658 You("have a bad feeling deep inside.");
659 You("cannibal! You will regret this!");
661 HAggravate_monster |= FROMOUTSIDE;
662 change_luck(-rn1(4, 2)); /* -5..-2 */
663 return TRUE;
665 return FALSE;
668 STATIC_OVL void
669 cprefx(pm)
670 register int pm;
672 (void) maybe_cannibal(pm, TRUE);
673 if (flesh_petrifies(&mons[pm])) {
674 if (!Stone_resistance
675 && !(poly_when_stoned(youmonst.data)
676 && polymon(PM_STONE_GOLEM))) {
677 Sprintf(killer.name, "tasting %s meat", mons[pm].mname);
678 killer.format = KILLED_BY;
679 You("turn to stone.");
680 done(STONING);
681 if (context.victual.piece)
682 context.victual.eating = FALSE;
683 return; /* lifesaved */
687 switch (pm) {
688 case PM_LITTLE_DOG:
689 case PM_DOG:
690 case PM_LARGE_DOG:
691 case PM_KITTEN:
692 case PM_HOUSECAT:
693 case PM_LARGE_CAT:
694 /* cannibals are allowed to eat domestic animals without penalty */
695 if (!CANNIBAL_ALLOWED()) {
696 You_feel("that eating the %s was a bad idea.", mons[pm].mname);
697 HAggravate_monster |= FROMOUTSIDE;
699 break;
700 case PM_LIZARD:
701 if (Stoned)
702 fix_petrification();
703 break;
704 case PM_DEATH:
705 case PM_PESTILENCE:
706 case PM_FAMINE: {
707 pline("Eating that is instantly fatal.");
708 Sprintf(killer.name, "unwisely ate the body of %s", mons[pm].mname);
709 killer.format = NO_KILLER_PREFIX;
710 done(DIED);
711 /* life-saving needed to reach here */
712 exercise(A_WIS, FALSE);
713 /* It so happens that since we know these monsters */
714 /* cannot appear in tins, context.victual.piece will always */
715 /* be what we want, which is not generally true. */
716 if (revive_corpse(context.victual.piece)) {
717 context.victual.piece = (struct obj *) 0;
718 context.victual.o_id = 0;
720 return;
722 case PM_GREEN_SLIME:
723 if (!Slimed && !Unchanging && !slimeproof(youmonst.data)) {
724 You("don't feel very well.");
725 make_slimed(10L, (char *) 0);
726 delayed_killer(SLIMED, KILLED_BY_AN, "");
728 /* Fall through */
729 default:
730 if (acidic(&mons[pm]) && Stoned)
731 fix_petrification();
732 break;
736 void
737 fix_petrification()
739 char buf[BUFSZ];
741 if (Hallucination)
742 Sprintf(buf, "What a pity--you just ruined a future piece of %sart!",
743 ACURR(A_CHA) > 15 ? "fine " : "");
744 else
745 Strcpy(buf, "You feel limber!");
746 make_stoned(0L, buf, 0, (char *) 0);
750 * If you add an intrinsic that can be gotten by eating a monster, add it
751 * to intrinsic_possible() and givit(). (It must already be in prop.h to
752 * be an intrinsic property.)
753 * It would be very easy to make the intrinsics not try to give you one
754 * that you already had by checking to see if you have it in
755 * intrinsic_possible() instead of givit(), but we're not that nice.
758 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
759 STATIC_OVL int
760 intrinsic_possible(type, ptr)
761 int type;
762 register struct permonst *ptr;
764 int res = 0;
766 #ifdef DEBUG
767 #define ifdebugresist(Msg) \
768 do { \
769 if (res) \
770 debugpline0(Msg); \
771 } while (0)
772 #else
773 #define ifdebugresist(Msg) /*empty*/
774 #endif
775 switch (type) {
776 case FIRE_RES:
777 res = (ptr->mconveys & MR_FIRE) != 0;
778 ifdebugresist("can get fire resistance");
779 break;
780 case SLEEP_RES:
781 res = (ptr->mconveys & MR_SLEEP) != 0;
782 ifdebugresist("can get sleep resistance");
783 break;
784 case COLD_RES:
785 res = (ptr->mconveys & MR_COLD) != 0;
786 ifdebugresist("can get cold resistance");
787 break;
788 case DISINT_RES:
789 res = (ptr->mconveys & MR_DISINT) != 0;
790 ifdebugresist("can get disintegration resistance");
791 break;
792 case SHOCK_RES: /* shock (electricity) resistance */
793 res = (ptr->mconveys & MR_ELEC) != 0;
794 ifdebugresist("can get shock resistance");
795 break;
796 case POISON_RES:
797 res = (ptr->mconveys & MR_POISON) != 0;
798 ifdebugresist("can get poison resistance");
799 break;
800 case TELEPORT:
801 res = can_teleport(ptr);
802 ifdebugresist("can get teleport");
803 break;
804 case TELEPORT_CONTROL:
805 res = control_teleport(ptr);
806 ifdebugresist("can get teleport control");
807 break;
808 case TELEPAT:
809 res = telepathic(ptr);
810 ifdebugresist("can get telepathy");
811 break;
812 default:
813 /* res stays 0 */
814 break;
816 #undef ifdebugresist
817 return res;
820 /* givit() tries to give you an intrinsic based on the monster's level
821 * and what type of intrinsic it is trying to give you.
823 STATIC_OVL void
824 givit(type, ptr)
825 int type;
826 register struct permonst *ptr;
828 register int chance;
830 debugpline1("Attempting to give intrinsic %d", type);
831 /* some intrinsics are easier to get than others */
832 switch (type) {
833 case POISON_RES:
834 if ((ptr == &mons[PM_KILLER_BEE] || ptr == &mons[PM_SCORPION])
835 && !rn2(4))
836 chance = 1;
837 else
838 chance = 15;
839 break;
840 case TELEPORT:
841 chance = 10;
842 break;
843 case TELEPORT_CONTROL:
844 chance = 12;
845 break;
846 case TELEPAT:
847 chance = 1;
848 break;
849 default:
850 chance = 15;
851 break;
854 if (ptr->mlevel <= rn2(chance))
855 return; /* failed die roll */
857 switch (type) {
858 case FIRE_RES:
859 debugpline0("Trying to give fire resistance");
860 if (!(HFire_resistance & FROMOUTSIDE)) {
861 You(Hallucination ? "be chillin'." : "feel a momentary chill.");
862 HFire_resistance |= FROMOUTSIDE;
864 break;
865 case SLEEP_RES:
866 debugpline0("Trying to give sleep resistance");
867 if (!(HSleep_resistance & FROMOUTSIDE)) {
868 You_feel("wide awake.");
869 HSleep_resistance |= FROMOUTSIDE;
871 break;
872 case COLD_RES:
873 debugpline0("Trying to give cold resistance");
874 if (!(HCold_resistance & FROMOUTSIDE)) {
875 You_feel("full of hot air.");
876 HCold_resistance |= FROMOUTSIDE;
878 break;
879 case DISINT_RES:
880 debugpline0("Trying to give disintegration resistance");
881 if (!(HDisint_resistance & FROMOUTSIDE)) {
882 You_feel(Hallucination ? "totally together, man." : "very firm.");
883 HDisint_resistance |= FROMOUTSIDE;
885 break;
886 case SHOCK_RES: /* shock (electricity) resistance */
887 debugpline0("Trying to give shock resistance");
888 if (!(HShock_resistance & FROMOUTSIDE)) {
889 if (Hallucination)
890 You_feel("grounded in reality.");
891 else
892 Your("health currently feels amplified!");
893 HShock_resistance |= FROMOUTSIDE;
895 break;
896 case POISON_RES:
897 debugpline0("Trying to give poison resistance");
898 if (!(HPoison_resistance & FROMOUTSIDE)) {
899 You_feel(Poison_resistance ? "especially healthy." : "healthy.");
900 HPoison_resistance |= FROMOUTSIDE;
902 break;
903 case TELEPORT:
904 debugpline0("Trying to give teleport");
905 if (!(HTeleportation & FROMOUTSIDE)) {
906 You_feel(Hallucination ? "diffuse." : "very jumpy.");
907 HTeleportation |= FROMOUTSIDE;
909 break;
910 case TELEPORT_CONTROL:
911 debugpline0("Trying to give teleport control");
912 if (!(HTeleport_control & FROMOUTSIDE)) {
913 You_feel(Hallucination ? "centered in your personal space."
914 : "in control of yourself.");
915 HTeleport_control |= FROMOUTSIDE;
917 break;
918 case TELEPAT:
919 debugpline0("Trying to give telepathy");
920 if (!(HTelepat & FROMOUTSIDE)) {
921 You_feel(Hallucination ? "in touch with the cosmos."
922 : "a strange mental acuity.");
923 HTelepat |= FROMOUTSIDE;
924 /* If blind, make sure monsters show up. */
925 if (Blind)
926 see_monsters();
928 break;
929 default:
930 debugpline0("Tried to give an impossible intrinsic");
931 break;
935 /* called after completely consuming a corpse */
936 STATIC_OVL void
937 cpostfx(pm)
938 register int pm;
940 register int tmp = 0;
941 int catch_lycanthropy = NON_PM;
943 /* in case `afternmv' didn't get called for previously mimicking
944 gold, clean up now to avoid `eatmbuf' memory leak */
945 if (eatmbuf)
946 (void) eatmdone();
948 switch (pm) {
949 case PM_NEWT:
950 /* MRKR: "eye of newt" may give small magical energy boost */
951 if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
952 int old_uen = u.uen;
953 u.uen += rnd(3);
954 if (u.uen > u.uenmax) {
955 if (!rn2(3))
956 u.uenmax++;
957 u.uen = u.uenmax;
959 if (old_uen != u.uen) {
960 You_feel("a mild buzz.");
961 context.botl = 1;
964 break;
965 case PM_WRAITH:
966 pluslvl(FALSE);
967 break;
968 case PM_HUMAN_WERERAT:
969 catch_lycanthropy = PM_WERERAT;
970 break;
971 case PM_HUMAN_WEREJACKAL:
972 catch_lycanthropy = PM_WEREJACKAL;
973 break;
974 case PM_HUMAN_WEREWOLF:
975 catch_lycanthropy = PM_WEREWOLF;
976 break;
977 case PM_NURSE:
978 if (Upolyd)
979 u.mh = u.mhmax;
980 else
981 u.uhp = u.uhpmax;
982 context.botl = 1;
983 break;
984 case PM_STALKER:
985 if (!Invis) {
986 set_itimeout(&HInvis, (long) rn1(100, 50));
987 if (!Blind && !BInvis)
988 self_invis_message();
989 } else {
990 if (!(HInvis & INTRINSIC))
991 You_feel("hidden!");
992 HInvis |= FROMOUTSIDE;
993 HSee_invisible |= FROMOUTSIDE;
995 newsym(u.ux, u.uy);
996 /*FALLTHRU*/
997 case PM_YELLOW_LIGHT:
998 case PM_GIANT_BAT:
999 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
1000 /*FALLTHRU*/
1001 case PM_BAT:
1002 make_stunned((HStun & TIMEOUT) + 30L, FALSE);
1003 break;
1004 case PM_GIANT_MIMIC:
1005 tmp += 10;
1006 /*FALLTHRU*/
1007 case PM_LARGE_MIMIC:
1008 tmp += 20;
1009 /*FALLTHRU*/
1010 case PM_SMALL_MIMIC:
1011 tmp += 20;
1012 if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
1013 char buf[BUFSZ];
1015 u.uconduct.polyselfs++; /* you're changing form */
1016 You_cant("resist the temptation to mimic %s.",
1017 Hallucination ? "an orange" : "a pile of gold");
1018 /* A pile of gold can't ride. */
1019 if (u.usteed)
1020 dismount_steed(DISMOUNT_FELL);
1021 nomul(-tmp);
1022 multi_reason = "pretending to be a pile of gold";
1023 Sprintf(buf,
1024 Hallucination
1025 ? "You suddenly dread being peeled and mimic %s again!"
1026 : "You now prefer mimicking %s again.",
1027 an(Upolyd ? youmonst.data->mname : urace.noun));
1028 eatmbuf = dupstr(buf);
1029 nomovemsg = eatmbuf;
1030 afternmv = eatmdone;
1031 /* ??? what if this was set before? */
1032 youmonst.m_ap_type = M_AP_OBJECT;
1033 youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
1034 newsym(u.ux, u.uy);
1035 curs_on_u();
1036 /* make gold symbol show up now */
1037 display_nhwindow(WIN_MAP, TRUE);
1039 break;
1040 case PM_QUANTUM_MECHANIC:
1041 Your("velocity suddenly seems very uncertain!");
1042 if (HFast & INTRINSIC) {
1043 HFast &= ~INTRINSIC;
1044 You("seem slower.");
1045 } else {
1046 HFast |= FROMOUTSIDE;
1047 You("seem faster.");
1049 break;
1050 case PM_LIZARD:
1051 if ((HStun & TIMEOUT) > 2)
1052 make_stunned(2L, FALSE);
1053 if ((HConfusion & TIMEOUT) > 2)
1054 make_confused(2L, FALSE);
1055 break;
1056 case PM_CHAMELEON:
1057 case PM_DOPPELGANGER:
1058 case PM_SANDESTIN: /* moot--they don't leave corpses */
1059 if (Unchanging) {
1060 You_feel("momentarily different."); /* same as poly trap */
1061 } else {
1062 You_feel("a change coming over you.");
1063 polyself(0);
1065 break;
1066 case PM_DISENCHANTER:
1067 /* picks an intrinsic at random and removes it; there's
1068 no feedback if hero already lacks the chosen ability */
1069 debugpline0("using attrcurse to strip an intrinsic");
1070 attrcurse();
1071 break;
1072 case PM_MIND_FLAYER:
1073 case PM_MASTER_MIND_FLAYER:
1074 if (ABASE(A_INT) < ATTRMAX(A_INT)) {
1075 if (!rn2(2)) {
1076 pline("Yum! That was real brain food!");
1077 (void) adjattrib(A_INT, 1, FALSE);
1078 break; /* don't give them telepathy, too */
1080 } else {
1081 pline("For some reason, that tasted bland.");
1083 /*FALLTHRU*/
1084 default: {
1085 struct permonst *ptr = &mons[pm];
1086 boolean conveys_STR = is_giant(ptr);
1087 int i, count;
1089 if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU)
1090 || pm == PM_VIOLET_FUNGUS) {
1091 pline("Oh wow! Great stuff!");
1092 (void) make_hallucinated((HHallucination & TIMEOUT) + 200L, FALSE,
1093 0L);
1096 /* Check the monster for all of the intrinsics. If this
1097 * monster can give more than one, pick one to try to give
1098 * from among all it can give.
1100 * Strength from giants is now treated like an intrinsic
1101 * rather than being given unconditionally.
1103 count = 0; /* number of possible intrinsics */
1104 tmp = 0; /* which one we will try to give */
1105 if (conveys_STR) {
1106 count = 1;
1107 tmp = -1; /* use -1 as fake prop index for STR */
1108 debugpline1("\"Intrinsic\" strength, %d", tmp);
1110 for (i = 1; i <= LAST_PROP; i++) {
1111 if (!intrinsic_possible(i, ptr))
1112 continue;
1113 ++count;
1114 /* a 1 in count chance of replacing the old choice
1115 with this one, and a count-1 in count chance
1116 of keeping the old choice (note that 1 in 1 and
1117 0 in 1 are what we want for the first candidate) */
1118 if (!rn2(count)) {
1119 debugpline2("Intrinsic %d replacing %d", i, tmp);
1120 tmp = i;
1123 /* if strength is the only candidate, give it 50% chance */
1124 if (conveys_STR && count == 1 && !rn2(2))
1125 tmp = 0;
1126 /* if something was chosen, give it now (givit() might fail) */
1127 if (tmp == -1)
1128 gainstr((struct obj *) 0, 0, TRUE);
1129 else if (tmp > 0)
1130 givit(tmp, ptr);
1131 break;
1132 } /* default case */
1133 } /* switch */
1135 if (catch_lycanthropy >= LOW_PM) {
1136 set_ulycn(catch_lycanthropy);
1137 retouch_equipment(2);
1139 return;
1142 void
1143 violated_vegetarian()
1145 u.uconduct.unvegetarian++;
1146 if (Role_if(PM_MONK)) {
1147 You_feel("guilty.");
1148 adjalign(-1);
1150 return;
1153 /* common code to check and possibly charge for 1 context.tin.tin,
1154 * will split() context.tin.tin if necessary */
1155 STATIC_PTR void
1156 costly_tin(alter_type)
1157 int alter_type; /* COST_xxx */
1159 struct obj *tin = context.tin.tin;
1161 if (carried(tin) ? tin->unpaid
1162 : (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) {
1163 if (tin->quan > 1L) {
1164 tin = context.tin.tin = splitobj(tin, 1L);
1165 context.tin.o_id = tin->o_id;
1167 costly_alteration(tin, alter_type);
1172 tin_variety_txt(s, tinvariety)
1173 char *s;
1174 int *tinvariety;
1176 int k, l;
1178 if (s && tinvariety) {
1179 *tinvariety = -1;
1180 for (k = 0; k < TTSZ - 1; ++k) {
1181 l = (int) strlen(tintxts[k].txt);
1182 if (!strncmpi(s, tintxts[k].txt, l) && ((int) strlen(s) > l)
1183 && s[l] == ' ') {
1184 *tinvariety = k;
1185 return (l + 1);
1189 return 0;
1193 * This assumes that buf already contains the word "tin",
1194 * as is the case with caller xname().
1196 void
1197 tin_details(obj, mnum, buf)
1198 struct obj *obj;
1199 int mnum;
1200 char *buf;
1202 char buf2[BUFSZ];
1203 int r = tin_variety(obj, TRUE);
1205 if (obj && buf) {
1206 if (r == SPINACH_TIN)
1207 Strcat(buf, " of spinach");
1208 else if (mnum == NON_PM)
1209 Strcpy(buf, "empty tin");
1210 else {
1211 if ((obj->cknown || iflags.override_ID) && obj->spe < 0) {
1212 if (r == ROTTEN_TIN || r == HOMEMADE_TIN) {
1213 /* put these before the word tin */
1214 Sprintf(buf2, "%s %s of ", tintxts[r].txt, buf);
1215 Strcpy(buf, buf2);
1216 } else {
1217 Sprintf(eos(buf), " of %s ", tintxts[r].txt);
1219 } else {
1220 Strcpy(eos(buf), " of ");
1222 if (vegetarian(&mons[mnum]))
1223 Sprintf(eos(buf), "%s", mons[mnum].mname);
1224 else
1225 Sprintf(eos(buf), "%s meat", mons[mnum].mname);
1230 void
1231 set_tin_variety(obj, forcetype)
1232 struct obj *obj;
1233 int forcetype;
1235 register int r;
1237 if (forcetype == SPINACH_TIN
1238 || (forcetype == HEALTHY_TIN
1239 && (obj->corpsenm == NON_PM /* empty or already spinach */
1240 || !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */
1241 obj->corpsenm = NON_PM; /* not based on any monster */
1242 obj->spe = 1; /* spinach */
1243 return;
1244 } else if (forcetype == HEALTHY_TIN) {
1245 r = tin_variety(obj, FALSE);
1246 if (r < 0 || r >= TTSZ)
1247 r = ROTTEN_TIN; /* shouldn't happen */
1248 while ((r == ROTTEN_TIN && !obj->cursed) || !tintxts[r].fodder)
1249 r = rn2(TTSZ - 1);
1250 } else if (forcetype >= 0 && forcetype < TTSZ - 1) {
1251 r = forcetype;
1252 } else { /* RANDOM_TIN */
1253 r = rn2(TTSZ - 1); /* take your pick */
1254 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1255 r = HOMEMADE_TIN; /* lizards don't rot */
1257 obj->spe = -(r + 1); /* offset by 1 to allow index 0 */
1260 STATIC_OVL int
1261 tin_variety(obj, disp)
1262 struct obj *obj;
1263 boolean disp; /* we're just displaying so leave things alone */
1265 register int r;
1267 if (obj->spe == 1) {
1268 r = SPINACH_TIN;
1269 } else if (obj->cursed) {
1270 r = ROTTEN_TIN; /* always rotten if cursed */
1271 } else if (obj->spe < 0) {
1272 r = -(obj->spe);
1273 --r; /* get rid of the offset */
1274 } else
1275 r = rn2(TTSZ - 1);
1277 if (!disp && r == HOMEMADE_TIN && !obj->blessed && !rn2(7))
1278 r = ROTTEN_TIN; /* some homemade tins go bad */
1280 if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm))
1281 r = HOMEMADE_TIN; /* lizards don't rot */
1282 return r;
1285 STATIC_OVL void
1286 consume_tin(mesg)
1287 const char *mesg;
1289 const char *what;
1290 int which, mnum, r;
1291 struct obj *tin = context.tin.tin;
1293 r = tin_variety(tin, FALSE);
1294 if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) {
1295 b_trapped("tin", 0);
1296 costly_tin(COST_DSTROY);
1297 goto use_up_tin;
1300 pline1(mesg); /* "You succeed in opening the tin." */
1302 if (r != SPINACH_TIN) {
1303 mnum = tin->corpsenm;
1304 if (mnum == NON_PM) {
1305 pline("It turns out to be empty.");
1306 tin->dknown = tin->known = 1;
1307 costly_tin(COST_OPEN);
1308 goto use_up_tin;
1311 which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1312 if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1313 && (Stone_resistance || Hallucination)) {
1314 what = "chicken";
1315 which = 1; /* suppress pluralization */
1316 } else if (Hallucination) {
1317 what = rndmonnam(NULL);
1318 } else {
1319 what = mons[mnum].mname;
1320 if (the_unique_pm(&mons[mnum]))
1321 which = 2;
1322 else if (type_is_pname(&mons[mnum]))
1323 which = 1;
1325 if (which == 0)
1326 what = makeplural(what);
1327 else if (which == 2)
1328 what = the(what);
1330 pline("It smells like %s.", what);
1331 if (yn("Eat it?") == 'n') {
1332 if (flags.verbose)
1333 You("discard the open tin.");
1334 if (!Hallucination)
1335 tin->dknown = tin->known = 1;
1336 costly_tin(COST_OPEN);
1337 goto use_up_tin;
1340 /* in case stop_occupation() was called on previous meal */
1341 context.victual.piece = (struct obj *) 0;
1342 context.victual.o_id = 0;
1343 context.victual.fullwarn = context.victual.eating =
1344 context.victual.doreset = FALSE;
1346 You("consume %s %s.", tintxts[r].txt, mons[mnum].mname);
1348 eating_conducts(&mons[mnum]);
1350 tin->dknown = tin->known = 1;
1351 cprefx(mnum);
1352 cpostfx(mnum);
1354 /* charge for one at pre-eating cost */
1355 costly_tin(COST_OPEN);
1357 if (tintxts[r].nut < 0) /* rotten */
1358 make_vomiting((long) rn1(15, 10), FALSE);
1359 else
1360 lesshungry(tintxts[r].nut);
1362 if (tintxts[r].greasy) {
1363 /* Assume !Glib, because you can't open tins when Glib. */
1364 incr_itimeout(&Glib, rnd(15));
1365 pline("Eating %s food made your %s very slippery.",
1366 tintxts[r].txt, makeplural(body_part(FINGER)));
1369 } else { /* spinach... */
1370 if (tin->cursed) {
1371 pline("It contains some decaying%s%s substance.",
1372 Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
1373 } else {
1374 pline("It contains spinach.");
1375 tin->dknown = tin->known = 1;
1378 if (yn("Eat it?") == 'n') {
1379 if (flags.verbose)
1380 You("discard the open tin.");
1381 costly_tin(COST_OPEN);
1382 goto use_up_tin;
1386 * Same order as with non-spinach above:
1387 * conduct update, side-effects, shop handling, and nutrition.
1389 u.uconduct
1390 .food++; /* don't need vegan/vegetarian checks for spinach */
1391 if (!tin->cursed)
1392 pline("This makes you feel like %s!",
1393 Hallucination ? "Swee'pea" : "Popeye");
1394 gainstr(tin, 0, FALSE);
1396 costly_tin(COST_OPEN);
1398 lesshungry(tin->blessed
1399 ? 600 /* blessed */
1400 : !tin->cursed
1401 ? (400 + rnd(200)) /* uncursed */
1402 : (200 + rnd(400))); /* cursed */
1405 use_up_tin:
1406 if (carried(tin))
1407 useup(tin);
1408 else
1409 useupf(tin, 1L);
1410 context.tin.tin = (struct obj *) 0;
1411 context.tin.o_id = 0;
1414 /* called during each move whilst opening a tin */
1415 STATIC_PTR int
1416 opentin(VOID_ARGS)
1418 /* perhaps it was stolen (although that should cause interruption) */
1419 if (!carried(context.tin.tin)
1420 && (!obj_here(context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE)))
1421 return 0; /* %% probably we should use tinoid */
1422 if (context.tin.usedtime++ >= 50) {
1423 You("give up your attempt to open the tin.");
1424 return 0;
1426 if (context.tin.usedtime < context.tin.reqtime)
1427 return 1; /* still busy */
1429 consume_tin("You succeed in opening the tin.");
1430 return 0;
1433 /* called when starting to open a tin */
1434 STATIC_OVL void
1435 start_tin(otmp)
1436 struct obj *otmp;
1438 const char *mesg = 0;
1439 register int tmp;
1441 if (metallivorous(youmonst.data)) {
1442 mesg = "You bite right into the metal tin...";
1443 tmp = 0;
1444 } else if (cantwield(youmonst.data)) { /* nohands || verysmall */
1445 You("cannot handle the tin properly to open it.");
1446 return;
1447 } else if (otmp->blessed) {
1448 /* 50/50 chance for immediate access vs 1 turn delay (unless
1449 wielding blessed tin opener which always yields immediate
1450 access); 1 turn delay case is non-deterministic: getting
1451 interrupted and retrying might yield another 1 turn delay
1452 or might open immediately on 2nd (or 3rd, 4th, ...) try */
1453 tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : rn2(2);
1454 if (!tmp)
1455 mesg = "The tin opens like magic!";
1456 else
1457 pline_The("tin seems easy to open.");
1458 } else if (uwep) {
1459 switch (uwep->otyp) {
1460 case TIN_OPENER:
1461 mesg = "You easily open the tin."; /* iff tmp==0 */
1462 tmp = rn2(uwep->cursed ? 3 : !uwep->blessed ? 2 : 1);
1463 break;
1464 case DAGGER:
1465 case SILVER_DAGGER:
1466 case ELVEN_DAGGER:
1467 case ORCISH_DAGGER:
1468 case ATHAME:
1469 case KNIFE:
1470 case STILETTO:
1471 case CRYSKNIFE:
1472 tmp = 3;
1473 break;
1474 case PICK_AXE:
1475 case AXE:
1476 tmp = 6;
1477 break;
1478 default:
1479 goto no_opener;
1481 pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0));
1482 } else {
1483 no_opener:
1484 pline("It is not so easy to open this tin.");
1485 if (Glib) {
1486 pline_The("tin slips from your %s.",
1487 makeplural(body_part(FINGER)));
1488 if (otmp->quan > 1L) {
1489 otmp = splitobj(otmp, 1L);
1491 if (carried(otmp))
1492 dropx(otmp);
1493 else
1494 stackobj(otmp);
1495 return;
1497 tmp = rn1(1 + 500 / ((int) (ACURR(A_DEX) + ACURRSTR)), 10);
1500 context.tin.tin = otmp;
1501 context.tin.o_id = otmp->o_id;
1502 if (!tmp) {
1503 consume_tin(mesg); /* begin immediately */
1504 } else {
1505 context.tin.reqtime = tmp;
1506 context.tin.usedtime = 0;
1507 set_occupation(opentin, "opening the tin", 0);
1509 return;
1512 /* called when waking up after fainting */
1514 Hear_again(VOID_ARGS)
1516 /* Chance of deafness going away while fainted/sleeping/etc. */
1517 if (!rn2(2)) {
1518 make_deaf(0L, FALSE);
1519 context.botl = TRUE;
1521 return 0;
1524 /* called on the "first bite" of rotten food */
1525 STATIC_OVL int
1526 rottenfood(obj)
1527 struct obj *obj;
1529 pline("Blecch! Rotten %s!", foodword(obj));
1530 if (!rn2(4)) {
1531 if (Hallucination)
1532 You_feel("rather trippy.");
1533 else
1534 You_feel("rather %s.", body_part(LIGHT_HEADED));
1535 make_confused(HConfusion + d(2, 4), FALSE);
1536 } else if (!rn2(4) && !Blind) {
1537 pline("Everything suddenly goes dark.");
1538 /* hero is not Blind, but Blinded timer might be nonzero if
1539 blindness is being overridden by the Eyes of the Overworld */
1540 make_blinded((Blinded & TIMEOUT) + (long) d(2, 10), FALSE);
1541 if (!Blind)
1542 Your1(vision_clears);
1543 } else if (!rn2(3)) {
1544 const char *what, *where;
1545 int duration = rnd(10);
1547 if (!Blind)
1548 what = "goes", where = "dark";
1549 else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
1550 what = "you lose control of", where = "yourself";
1551 else
1552 what = "you slap against the",
1553 where = (u.usteed) ? "saddle" : surface(u.ux, u.uy);
1554 pline_The("world spins and %s %s.", what, where);
1555 incr_itimeout(&HDeaf, duration);
1556 context.botl = TRUE;
1557 nomul(-duration);
1558 multi_reason = "unconscious from rotten food";
1559 nomovemsg = "You are conscious again.";
1560 afternmv = Hear_again;
1561 return 1;
1563 return 0;
1566 /* called when a corpse is selected as food */
1567 STATIC_OVL int
1568 eatcorpse(otmp)
1569 struct obj *otmp;
1571 int retcode = 0, tp = 0, mnum = otmp->corpsenm;
1572 long rotted = 0L;
1573 boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
1574 && !poly_when_stoned(youmonst.data)),
1575 slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging
1576 && !slimeproof(youmonst.data)),
1577 glob = otmp->globby ? TRUE : FALSE;
1579 /* KMH, conduct */
1580 if (!vegan(&mons[mnum]))
1581 u.uconduct.unvegan++;
1582 if (!vegetarian(&mons[mnum]))
1583 violated_vegetarian();
1585 if (!nonrotting_corpse(mnum)) {
1586 long age = peek_at_iced_corpse_age(otmp);
1588 rotted = (monstermoves - age) / (10L + rn2(20));
1589 if (otmp->cursed)
1590 rotted += 2L;
1591 else if (otmp->blessed)
1592 rotted -= 2L;
1595 if (mnum != PM_ACID_BLOB && !stoneable && !slimeable && rotted > 5L) {
1596 boolean cannibal = maybe_cannibal(mnum, FALSE);
1598 pline("Ulch - that %s was tainted%s!",
1599 (mons[mnum].mlet == S_FUNGUS) ? "fungoid vegetation"
1600 : glob ? "glob"
1601 : vegetarian(&mons[mnum]) ? "protoplasm"
1602 : "meat",
1603 cannibal ? ", you cannibal" : "");
1604 if (Sick_resistance) {
1605 pline("It doesn't seem at all sickening, though...");
1606 } else {
1607 long sick_time;
1609 sick_time = (long) rn1(10, 10);
1610 /* make sure new ill doesn't result in improvement */
1611 if (Sick && (sick_time > Sick))
1612 sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1613 make_sick(sick_time, corpse_xname(otmp, "rotted", CXN_NORMAL),
1614 TRUE, SICK_VOMITABLE);
1616 if (carried(otmp))
1617 useup(otmp);
1618 else
1619 useupf(otmp, 1L);
1620 return 2;
1621 } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1622 tp++;
1623 You("have a very bad case of stomach acid."); /* not body_part() */
1624 losehp(rnd(15), !glob ? "acidic corpse" : "acidic glob",
1625 KILLED_BY_AN); /* acid damage */
1626 } else if (poisonous(&mons[mnum]) && rn2(5)) {
1627 tp++;
1628 pline("Ecch - that must have been poisonous!");
1629 if (!Poison_resistance) {
1630 losestr(rnd(4));
1631 losehp(rnd(15), !glob ? "poisonous corpse" : "poisonous glob",
1632 KILLED_BY_AN);
1633 } else
1634 You("seem unaffected by the poison.");
1635 /* now any corpse left too long will make you mildly ill */
1636 } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) {
1637 tp++;
1638 You_feel("%ssick.", (Sick) ? "very " : "");
1639 losehp(rnd(8), !glob ? "cadaver" : "rotted glob", KILLED_BY_AN);
1642 /* delay is weight dependent */
1643 context.victual.reqtime = 3 + ((!glob ? mons[mnum].cwt : otmp->owt) >> 6);
1645 if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) {
1646 if (rottenfood(otmp)) {
1647 otmp->orotten = TRUE;
1648 (void) touchfood(otmp);
1649 retcode = 1;
1652 if (!mons[otmp->corpsenm].cnutrit) {
1653 /* no nutrition: rots away, no message if you passed out */
1654 if (!retcode)
1655 pline_The("corpse rots away completely.");
1656 if (carried(otmp))
1657 useup(otmp);
1658 else
1659 useupf(otmp, 1L);
1660 retcode = 2;
1663 if (!retcode)
1664 consume_oeaten(otmp, 2); /* oeaten >>= 2 */
1665 } else if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE)
1666 && (Stone_resistance || Hallucination)) {
1667 pline("This tastes just like chicken!");
1668 } else if (mnum == PM_FLOATING_EYE && u.umonnum == PM_RAVEN) {
1669 You("peck the eyeball with delight.");
1670 } else {
1671 /* yummy is always False for omnivores, palatable always True */
1672 boolean yummy = (vegan(&mons[mnum])
1673 ? (!carnivorous(youmonst.data)
1674 && herbivorous(youmonst.data))
1675 : (carnivorous(youmonst.data)
1676 && !herbivorous(youmonst.data))),
1677 palatable = ((vegetarian(&mons[mnum])
1678 ? herbivorous(youmonst.data)
1679 : carnivorous(youmonst.data))
1680 && rn2(10)
1681 && ((rotted < 1) ? TRUE : !rn2(rotted+1)));
1682 const char *pmxnam = food_xname(otmp, FALSE);
1684 if (!strncmpi(pmxnam, "the ", 4))
1685 pmxnam += 4;
1686 pline("%s%s %s %s%c",
1687 type_is_pname(&mons[mnum])
1688 ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ",
1689 pmxnam,
1690 Hallucination ? "is" : "tastes",
1691 /* tiger reference is to TV ads for "Frosted Flakes",
1692 breakfast cereal targeted at kids by "Tony the tiger" */
1693 Hallucination
1694 ? (yummy ? ((u.umonnum == PM_TIGER) ? "gr-r-reat" : "gnarly")
1695 : palatable ? "copacetic" : "grody")
1696 : (yummy ? "delicious" : palatable ? "okay" : "terrible"),
1697 (yummy || !palatable) ? '!' : '.');
1700 return retcode;
1703 /* called as you start to eat */
1704 STATIC_OVL void
1705 start_eating(otmp)
1706 struct obj *otmp;
1708 const char *old_nomovemsg, *save_nomovemsg;
1710 debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp,
1711 (unsigned long) context.victual.piece);
1712 debugpline1("reqtime = %d", context.victual.reqtime);
1713 debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1714 debugpline1("nmod = %d", context.victual.nmod);
1715 debugpline1("oeaten = %d", otmp->oeaten);
1716 context.victual.fullwarn = context.victual.doreset = FALSE;
1717 context.victual.eating = TRUE;
1719 if (otmp->otyp == CORPSE || otmp->globby) {
1720 cprefx(context.victual.piece->corpsenm);
1721 if (!context.victual.piece || !context.victual.eating) {
1722 /* rider revived, or died and lifesaved */
1723 return;
1727 old_nomovemsg = nomovemsg;
1728 if (bite()) {
1729 /* survived choking, finish off food that's nearly done;
1730 need this to handle cockatrice eggs, fortune cookies, etc */
1731 if (++context.victual.usedtime >= context.victual.reqtime) {
1732 /* don't want done_eating() to issue nomovemsg if it
1733 is due to vomit() called by bite() */
1734 save_nomovemsg = nomovemsg;
1735 if (!old_nomovemsg)
1736 nomovemsg = 0;
1737 done_eating(FALSE);
1738 if (!old_nomovemsg)
1739 nomovemsg = save_nomovemsg;
1741 return;
1744 if (++context.victual.usedtime >= context.victual.reqtime) {
1745 /* print "finish eating" message if they just resumed -dlc */
1746 done_eating(context.victual.reqtime > 1 ? TRUE : FALSE);
1747 return;
1750 Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1751 set_occupation(eatfood, msgbuf, 0);
1755 * called on "first bite" of (non-corpse) food.
1756 * used for non-rotten non-tin non-corpse food
1758 STATIC_OVL void
1759 fprefx(otmp)
1760 struct obj *otmp;
1762 switch (otmp->otyp) {
1763 case FOOD_RATION:
1764 if (u.uhunger <= 200)
1765 pline(Hallucination ? "Oh wow, like, superior, man!"
1766 : "That food really hit the spot!");
1767 else if (u.uhunger <= 700)
1768 pline("That satiated your %s!", body_part(STOMACH));
1769 break;
1770 case TRIPE_RATION:
1771 if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1772 pline("That tripe ration was surprisingly good!");
1773 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
1774 pline(Hallucination ? "Tastes great! Less filling!"
1775 : "Mmm, tripe... not bad!");
1776 else {
1777 pline("Yak - dog food!");
1778 more_experienced(1, 0);
1779 newexplevel();
1780 /* not cannibalism, but we use similar criteria
1781 for deciding whether to be sickened by this meal */
1782 if (rn2(2) && !CANNIBAL_ALLOWED())
1783 make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE);
1785 break;
1786 case LEMBAS_WAFER:
1787 if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) {
1788 pline("%s", "!#?&* elf kibble!");
1789 break;
1790 } else if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) {
1791 pline("A little goes a long way.");
1792 break;
1794 goto give_feedback;
1795 case MEATBALL:
1796 case MEAT_STICK:
1797 case HUGE_CHUNK_OF_MEAT:
1798 case MEAT_RING:
1799 goto give_feedback;
1800 case CLOVE_OF_GARLIC:
1801 if (is_undead(youmonst.data)) {
1802 make_vomiting((long) rn1(context.victual.reqtime, 5), FALSE);
1803 break;
1805 /* else FALLTHRU */
1806 default:
1807 if (otmp->otyp == SLIME_MOLD && !otmp->cursed
1808 && otmp->spe == context.current_fruit) {
1809 pline("My, that was a %s %s!",
1810 Hallucination ? "primo" : "yummy",
1811 singular(otmp, xname));
1812 } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
1813 ; /* skip core joke; feedback deferred til fpostfx() */
1815 #if defined(MAC) || defined(MACOSX)
1816 /* KMH -- Why should Unix have all the fun?
1817 We check MACOSX before UNIX to get the Apple-specific apple
1818 message; the '#if UNIX' code will still kick in for pear. */
1819 } else if (otmp->otyp == APPLE) {
1820 pline("Delicious! Must be a Macintosh!");
1821 #endif
1823 #ifdef UNIX
1824 } else if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1825 if (!Hallucination) {
1826 pline("Core dumped.");
1827 } else {
1828 /* This is based on an old Usenet joke, a fake a.out manual
1829 * page
1831 int x = rnd(100);
1833 pline("%s -- core dumped.",
1834 (x <= 75)
1835 ? "Segmentation fault"
1836 : (x <= 99)
1837 ? "Bus error"
1838 : "Yo' mama");
1840 #endif
1841 } else if (otmp->otyp == EGG && stale_egg(otmp)) {
1842 pline("Ugh. Rotten egg."); /* perhaps others like it */
1843 /* increasing existing nausea means that it will take longer
1844 before eventual vomit, but also means that constitution
1845 will be abused more times before illness completes */
1846 make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE);
1847 } else {
1848 give_feedback:
1849 pline("This %s is %s", singular(otmp, xname),
1850 otmp->cursed
1851 ? (Hallucination ? "grody!" : "terrible!")
1852 : (otmp->otyp == CRAM_RATION
1853 || otmp->otyp == K_RATION
1854 || otmp->otyp == C_RATION)
1855 ? "bland."
1856 : Hallucination ? "gnarly!" : "delicious!");
1858 break; /* default */
1859 } /* switch */
1862 /* increment a combat intrinsic with limits on its growth */
1863 STATIC_OVL int
1864 bounded_increase(old, inc, typ)
1865 int old, inc, typ;
1867 int absold, absinc, sgnold, sgninc;
1869 /* don't include any amount coming from worn rings */
1870 if (uright && uright->otyp == typ)
1871 old -= uright->spe;
1872 if (uleft && uleft->otyp == typ)
1873 old -= uleft->spe;
1874 absold = abs(old), absinc = abs(inc);
1875 sgnold = sgn(old), sgninc = sgn(inc);
1877 if (absinc == 0 || sgnold != sgninc || absold + absinc < 10) {
1878 ; /* use inc as-is */
1879 } else if (absold + absinc < 20) {
1880 absinc = rnd(absinc); /* 1..n */
1881 if (absold + absinc < 10)
1882 absinc = 10 - absold;
1883 inc = sgninc * absinc;
1884 } else if (absold + absinc < 40) {
1885 absinc = rn2(absinc) ? 1 : 0;
1886 if (absold + absinc < 20)
1887 absinc = rnd(20 - absold);
1888 inc = sgninc * absinc;
1889 } else {
1890 inc = 0; /* no further increase allowed via this method */
1892 return old + inc;
1895 STATIC_OVL void
1896 accessory_has_effect(otmp)
1897 struct obj *otmp;
1899 pline("Magic spreads through your body as you digest the %s.",
1900 otmp->oclass == RING_CLASS ? "ring" : "amulet");
1903 STATIC_OVL void
1904 eataccessory(otmp)
1905 struct obj *otmp;
1907 int typ = otmp->otyp;
1908 long oldprop;
1910 /* Note: rings are not so common that this is unbalancing. */
1911 /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1912 oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
1913 if (otmp == uleft || otmp == uright) {
1914 Ring_gone(otmp);
1915 if (u.uhp <= 0)
1916 return; /* died from sink fall */
1918 otmp->known = otmp->dknown = 1; /* by taste */
1919 if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
1920 switch (otmp->otyp) {
1921 default:
1922 if (!objects[typ].oc_oprop)
1923 break; /* should never happen */
1925 if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1926 accessory_has_effect(otmp);
1928 u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1930 switch (typ) {
1931 case RIN_SEE_INVISIBLE:
1932 set_mimic_blocking();
1933 see_monsters();
1934 if (Invis && !oldprop && !ESee_invisible
1935 && !perceives(youmonst.data) && !Blind) {
1936 newsym(u.ux, u.uy);
1937 pline("Suddenly you can see yourself.");
1938 makeknown(typ);
1940 break;
1941 case RIN_INVISIBILITY:
1942 if (!oldprop && !EInvis && !BInvis && !See_invisible
1943 && !Blind) {
1944 newsym(u.ux, u.uy);
1945 Your("body takes on a %s transparency...",
1946 Hallucination ? "normal" : "strange");
1947 makeknown(typ);
1949 break;
1950 case RIN_PROTECTION_FROM_SHAPE_CHAN:
1951 rescham();
1952 break;
1953 case RIN_LEVITATION:
1954 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1955 u.uprops[LEVITATION].intrinsic = oldprop;
1956 if (!Levitation) {
1957 float_up();
1958 incr_itimeout(&HLevitation, d(10, 20));
1959 makeknown(typ);
1961 break;
1962 } /* inner switch */
1963 break; /* default case of outer switch */
1965 case RIN_ADORNMENT:
1966 accessory_has_effect(otmp);
1967 if (adjattrib(A_CHA, otmp->spe, -1))
1968 makeknown(typ);
1969 break;
1970 case RIN_GAIN_STRENGTH:
1971 accessory_has_effect(otmp);
1972 if (adjattrib(A_STR, otmp->spe, -1))
1973 makeknown(typ);
1974 break;
1975 case RIN_GAIN_CONSTITUTION:
1976 accessory_has_effect(otmp);
1977 if (adjattrib(A_CON, otmp->spe, -1))
1978 makeknown(typ);
1979 break;
1980 case RIN_INCREASE_ACCURACY:
1981 accessory_has_effect(otmp);
1982 u.uhitinc = (schar) bounded_increase((int) u.uhitinc, otmp->spe,
1983 RIN_INCREASE_ACCURACY);
1984 break;
1985 case RIN_INCREASE_DAMAGE:
1986 accessory_has_effect(otmp);
1987 u.udaminc = (schar) bounded_increase((int) u.udaminc, otmp->spe,
1988 RIN_INCREASE_DAMAGE);
1989 break;
1990 case RIN_PROTECTION:
1991 accessory_has_effect(otmp);
1992 HProtection |= FROMOUTSIDE;
1993 u.ublessed = bounded_increase(u.ublessed, otmp->spe,
1994 RIN_PROTECTION);
1995 context.botl = 1;
1996 break;
1997 case RIN_FREE_ACTION:
1998 /* Give sleep resistance instead */
1999 if (!(HSleep_resistance & FROMOUTSIDE))
2000 accessory_has_effect(otmp);
2001 if (!Sleep_resistance)
2002 You_feel("wide awake.");
2003 HSleep_resistance |= FROMOUTSIDE;
2004 break;
2005 case AMULET_OF_CHANGE:
2006 accessory_has_effect(otmp);
2007 makeknown(typ);
2008 change_sex();
2009 You("are suddenly very %s!",
2010 flags.female ? "feminine" : "masculine");
2011 context.botl = 1;
2012 break;
2013 case AMULET_OF_UNCHANGING:
2014 /* un-change: it's a pun */
2015 if (!Unchanging && Upolyd) {
2016 accessory_has_effect(otmp);
2017 makeknown(typ);
2018 rehumanize();
2020 break;
2021 case AMULET_OF_STRANGULATION: /* bad idea! */
2022 /* no message--this gives no permanent effect */
2023 choke(otmp);
2024 break;
2025 case AMULET_OF_RESTFUL_SLEEP: { /* another bad idea! */
2026 long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT);
2028 if (!(HSleepy & FROMOUTSIDE))
2029 accessory_has_effect(otmp);
2030 HSleepy |= FROMOUTSIDE;
2031 /* might also be wearing one; use shorter of two timeouts */
2032 if (newnap < oldnap || oldnap == 0L)
2033 HSleepy = (HSleepy & ~TIMEOUT) | newnap;
2034 break;
2036 case RIN_SUSTAIN_ABILITY:
2037 case AMULET_OF_LIFE_SAVING:
2038 case AMULET_OF_REFLECTION: /* nice try */
2039 /* can't eat Amulet of Yendor or fakes,
2040 * and no oc_prop even if you could -3.
2042 break;
2047 /* called after eating non-food */
2048 STATIC_OVL void
2049 eatspecial()
2051 struct obj *otmp = context.victual.piece;
2053 /* lesshungry wants an occupation to handle choke messages correctly */
2054 set_occupation(eatfood, "eating non-food", 0);
2055 lesshungry(context.victual.nmod);
2056 occupation = 0;
2057 context.victual.piece = (struct obj *) 0;
2058 context.victual.o_id = 0;
2059 context.victual.eating = 0;
2060 if (otmp->oclass == COIN_CLASS) {
2061 if (carried(otmp))
2062 useupall(otmp);
2063 else
2064 useupf(otmp, otmp->quan);
2065 vault_gd_watching(GD_EATGOLD);
2066 return;
2068 if (objects[otmp->otyp].oc_material == PAPER) {
2069 #ifdef MAIL
2070 if (otmp->otyp == SCR_MAIL)
2071 /* no nutrition */
2072 pline("This junk mail is less than satisfying.");
2073 else
2074 #endif
2075 if (otmp->otyp == SCR_SCARE_MONSTER)
2076 /* to eat scroll, hero is currently polymorphed into a monster */
2077 pline("Yuck%c", otmp->blessed ? '!' : '.');
2078 else if (otmp->oclass == SCROLL_CLASS
2079 /* check description after checking for specific scrolls */
2080 && !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM"))
2081 pline("Yum%c", otmp->blessed ? '!' : '.');
2082 else
2083 pline("Needs salt...");
2085 if (otmp->oclass == POTION_CLASS) {
2086 otmp->quan++; /* dopotion() does a useup() */
2087 (void) dopotion(otmp);
2088 } else if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) {
2089 eataccessory(otmp);
2090 } else if (otmp->otyp == LEASH && otmp->leashmon) {
2091 o_unleash(otmp);
2094 /* KMH -- idea by "Tommy the Terrorist" */
2095 if (otmp->otyp == TRIDENT && !otmp->cursed) {
2096 /* sugarless chewing gum which used to be heavily advertised on TV */
2097 pline(Hallucination ? "Four out of five dentists agree."
2098 : "That was pure chewing satisfaction!");
2099 exercise(A_WIS, TRUE);
2101 if (otmp->otyp == FLINT && !otmp->cursed) {
2102 /* chewable vitamin for kids based on "The Flintstones" TV cartoon */
2103 pline("Yabba-dabba delicious!");
2104 exercise(A_CON, TRUE);
2107 if (otmp == uwep && otmp->quan == 1L)
2108 uwepgone();
2109 if (otmp == uquiver && otmp->quan == 1L)
2110 uqwepgone();
2111 if (otmp == uswapwep && otmp->quan == 1L)
2112 uswapwepgone();
2114 if (otmp == uball)
2115 unpunish();
2116 if (otmp == uchain)
2117 unpunish(); /* but no useup() */
2118 else if (carried(otmp))
2119 useup(otmp);
2120 else
2121 useupf(otmp, 1L);
2124 /* NOTE: the order of these words exactly corresponds to the
2125 order of oc_material values #define'd in objclass.h. */
2126 static const char *foodwords[] = {
2127 "meal", "liquid", "wax", "food", "meat", "paper",
2128 "cloth", "leather", "wood", "bone", "scale", "metal",
2129 "metal", "metal", "silver", "gold", "platinum", "mithril",
2130 "plastic", "glass", "rich food", "stone"
2133 STATIC_OVL const char *
2134 foodword(otmp)
2135 struct obj *otmp;
2137 if (otmp->oclass == FOOD_CLASS)
2138 return "food";
2139 if (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS
2140 && otmp->dknown)
2141 makeknown(otmp->otyp);
2142 return foodwords[objects[otmp->otyp].oc_material];
2145 /* called after consuming (non-corpse) food */
2146 STATIC_OVL void
2147 fpostfx(otmp)
2148 struct obj *otmp;
2150 switch (otmp->otyp) {
2151 case SPRIG_OF_WOLFSBANE:
2152 if (u.ulycn >= LOW_PM || is_were(youmonst.data))
2153 you_unwere(TRUE);
2154 break;
2155 case CARROT:
2156 if (!u.uswallow
2157 || !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))
2158 make_blinded((long) u.ucreamed, TRUE);
2159 break;
2160 case FORTUNE_COOKIE:
2161 outrumor(bcsign(otmp), BY_COOKIE);
2162 if (!Blind)
2163 u.uconduct.literate++;
2164 break;
2165 case LUMP_OF_ROYAL_JELLY:
2166 /* This stuff seems to be VERY healthy! */
2167 gainstr(otmp, 1, TRUE);
2168 if (Upolyd) {
2169 u.mh += otmp->cursed ? -rnd(20) : rnd(20);
2170 if (u.mh > u.mhmax) {
2171 if (!rn2(17))
2172 u.mhmax++;
2173 u.mh = u.mhmax;
2174 } else if (u.mh <= 0) {
2175 rehumanize();
2177 } else {
2178 u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
2179 if (u.uhp > u.uhpmax) {
2180 if (!rn2(17))
2181 u.uhpmax++;
2182 u.uhp = u.uhpmax;
2183 } else if (u.uhp <= 0) {
2184 killer.format = KILLED_BY_AN;
2185 Strcpy(killer.name, "rotten lump of royal jelly");
2186 done(POISONING);
2189 if (!otmp->cursed)
2190 heal_legs();
2191 break;
2192 case EGG:
2193 if (flesh_petrifies(&mons[otmp->corpsenm])) {
2194 if (!Stone_resistance
2195 && !(poly_when_stoned(youmonst.data)
2196 && polymon(PM_STONE_GOLEM))) {
2197 if (!Stoned) {
2198 Sprintf(killer.name, "%s egg",
2199 mons[otmp->corpsenm].mname);
2200 make_stoned(5L, (char *) 0, KILLED_BY_AN, killer.name);
2203 /* note: no "tastes like chicken" message for eggs */
2205 break;
2206 case EUCALYPTUS_LEAF:
2207 if (Sick && !otmp->cursed)
2208 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
2209 if (Vomiting && !otmp->cursed)
2210 make_vomiting(0L, TRUE);
2211 break;
2212 case APPLE:
2213 if (otmp->cursed && !Sleep_resistance) {
2214 /* Snow White; 'poisoned' applies to [a subset of] weapons,
2215 not food, so we substitute cursed; fortunately our hero
2216 won't have to wait for a prince to be rescued/revived */
2217 if (Race_if(PM_DWARF) && Hallucination)
2218 verbalize("Heigh-ho, ho-hum, I think I'll skip work today.");
2219 else if (Deaf || !flags.acoustics)
2220 You("fall asleep.");
2221 else
2222 You_hear("sinister laughter as you fall asleep...");
2223 fall_asleep(-rn1(11, 20), TRUE);
2225 break;
2227 return;
2230 #if 0
2231 /* intended for eating a spellbook while polymorphed, but not used;
2232 "leather" applied to appearance, not composition, and has been
2233 changed to "leathery" to reflect that */
2234 STATIC_DCL boolean FDECL(leather_cover, (struct obj *));
2236 STATIC_OVL boolean
2237 leather_cover(otmp)
2238 struct obj *otmp;
2240 const char *odesc = OBJ_DESCR(objects[otmp->otyp]);
2242 if (odesc && (otmp->oclass == SPBOOK_CLASS)) {
2243 if (!strcmp(odesc, "leather"))
2244 return TRUE;
2246 return FALSE;
2248 #endif
2251 * return 0 if the food was not dangerous.
2252 * return 1 if the food was dangerous and you chose to stop.
2253 * return 2 if the food was dangerous and you chose to eat it anyway.
2255 STATIC_OVL int
2256 edibility_prompts(otmp)
2257 struct obj *otmp;
2259 /* Blessed food detection grants hero a one-use
2260 * ability to detect food that is unfit for consumption
2261 * or dangerous and avoid it.
2263 char buf[BUFSZ], foodsmell[BUFSZ],
2264 it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
2265 boolean cadaver = (otmp->otyp == CORPSE || otmp->globby),
2266 stoneorslime = FALSE;
2267 int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm;
2268 long rotted = 0L;
2270 Strcpy(foodsmell, Tobjnam(otmp, "smell"));
2271 Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
2272 Sprintf(eat_it_anyway, "Eat %s anyway?",
2273 (otmp->quan == 1L) ? "it" : "one");
2275 if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
2276 /* These checks must match those in eatcorpse() */
2277 stoneorslime = (flesh_petrifies(&mons[mnum]) && !Stone_resistance
2278 && !poly_when_stoned(youmonst.data));
2280 if (mnum == PM_GREEN_SLIME || otmp->otyp == GLOB_OF_GREEN_SLIME)
2281 stoneorslime = (!Unchanging && !slimeproof(youmonst.data));
2283 if (cadaver && !nonrotting_corpse(mnum)) {
2284 long age = peek_at_iced_corpse_age(otmp);
2286 /* worst case rather than random
2287 in this calculation to force prompt */
2288 rotted = (monstermoves - age) / (10L + 0 /* was rn2(20) */);
2289 if (otmp->cursed)
2290 rotted += 2L;
2291 else if (otmp->blessed)
2292 rotted -= 2L;
2297 * These problems with food should be checked in
2298 * order from most detrimental to least detrimental.
2300 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
2301 /* Tainted meat */
2302 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2303 eat_it_anyway);
2304 if (yn_function(buf, ynchars, 'n') == 'n')
2305 return 1;
2306 else
2307 return 2;
2309 if (stoneorslime) {
2310 Sprintf(buf, "%s like %s could be something very dangerous! %s",
2311 foodsmell, it_or_they, eat_it_anyway);
2312 if (yn_function(buf, ynchars, 'n') == 'n')
2313 return 1;
2314 else
2315 return 2;
2317 if (otmp->orotten || (cadaver && rotted > 3L)) {
2318 /* Rotten */
2319 Sprintf(buf, "%s like %s could be rotten! %s", foodsmell, it_or_they,
2320 eat_it_anyway);
2321 if (yn_function(buf, ynchars, 'n') == 'n')
2322 return 1;
2323 else
2324 return 2;
2326 if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
2327 /* poisonous */
2328 Sprintf(buf, "%s like %s might be poisonous! %s", foodsmell,
2329 it_or_they, eat_it_anyway);
2330 if (yn_function(buf, ynchars, 'n') == 'n')
2331 return 1;
2332 else
2333 return 2;
2335 if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
2336 /* causes sleep, for long enough to be dangerous */
2337 Sprintf(buf, "%s like %s might have been poisoned. %s", foodsmell,
2338 it_or_they, eat_it_anyway);
2339 return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2;
2341 if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian
2342 && Role_if(PM_MONK)) {
2343 Sprintf(buf, "%s unhealthy. %s", foodsmell, eat_it_anyway);
2344 if (yn_function(buf, ynchars, 'n') == 'n')
2345 return 1;
2346 else
2347 return 2;
2349 if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
2350 Sprintf(buf, "%s rather acidic. %s", foodsmell, eat_it_anyway);
2351 if (yn_function(buf, ynchars, 'n') == 'n')
2352 return 1;
2353 else
2354 return 2;
2356 if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp)
2357 && otmp->oerodeproof) {
2358 Sprintf(buf, "%s disgusting to you right now. %s", foodsmell,
2359 eat_it_anyway);
2360 if (yn_function(buf, ynchars, 'n') == 'n')
2361 return 1;
2362 else
2363 return 2;
2367 * Breaks conduct, but otherwise safe.
2369 if (!u.uconduct.unvegan
2370 && ((material == LEATHER || material == BONE
2371 || material == DRAGON_HIDE || material == WAX)
2372 || (cadaver && !vegan(&mons[mnum])))) {
2373 Sprintf(buf, "%s foul and unfamiliar to you. %s", foodsmell,
2374 eat_it_anyway);
2375 if (yn_function(buf, ynchars, 'n') == 'n')
2376 return 1;
2377 else
2378 return 2;
2380 if (!u.uconduct.unvegetarian
2381 && ((material == LEATHER || material == BONE
2382 || material == DRAGON_HIDE)
2383 || (cadaver && !vegetarian(&mons[mnum])))) {
2384 Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway);
2385 if (yn_function(buf, ynchars, 'n') == 'n')
2386 return 1;
2387 else
2388 return 2;
2391 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
2392 /* Tainted meat with Sick_resistance */
2393 Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they,
2394 eat_it_anyway);
2395 if (yn_function(buf, ynchars, 'n') == 'n')
2396 return 1;
2397 else
2398 return 2;
2400 return 0;
2403 /* 'e' command */
2405 doeat()
2407 struct obj *otmp;
2408 int basenutrit; /* nutrition of full item */
2409 boolean dont_start = FALSE, nodelicious = FALSE;
2411 if (Strangled) {
2412 pline("If you can't breathe air, how can you consume solids?");
2413 return 0;
2415 if (!(otmp = floorfood("eat", 0)))
2416 return 0;
2417 if (check_capacity((char *) 0))
2418 return 0;
2420 if (u.uedibility) {
2421 int res = edibility_prompts(otmp);
2423 if (res) {
2424 Your(
2425 "%s stops tingling and your sense of smell returns to normal.",
2426 body_part(NOSE));
2427 u.uedibility = 0;
2428 if (res == 1)
2429 return 0;
2433 /* We have to make non-foods take 1 move to eat, unless we want to
2434 * do ridiculous amounts of coding to deal with partly eaten plate
2435 * mails, players who polymorph back to human in the middle of their
2436 * metallic meal, etc....
2438 if (!(carried(otmp) ? retouch_object(&otmp, FALSE)
2439 : touch_artifact(otmp, &youmonst))) {
2440 return 1;
2441 } else if (!is_edible(otmp)) {
2442 You("cannot eat that!");
2443 return 0;
2444 } else if ((otmp->owornmask & (W_ARMOR | W_TOOL | W_AMUL | W_SADDLE))
2445 != 0) {
2446 /* let them eat rings */
2447 You_cant("eat %s you're wearing.", something);
2448 return 0;
2450 if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER
2451 && otmp->oerodeproof) {
2452 otmp->rknown = TRUE;
2453 if (otmp->quan > 1L) {
2454 if (!carried(otmp))
2455 (void) splitobj(otmp, otmp->quan - 1L);
2456 else
2457 otmp = splitobj(otmp, 1L);
2459 pline("Ulch - that %s was rustproofed!", xname(otmp));
2460 /* The regurgitated object's rustproofing is gone now */
2461 otmp->oerodeproof = 0;
2462 make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE);
2463 You("spit %s out onto the %s.", the(xname(otmp)),
2464 surface(u.ux, u.uy));
2465 if (carried(otmp)) {
2466 freeinv(otmp);
2467 dropy(otmp);
2469 stackobj(otmp);
2470 return 1;
2472 /* KMH -- Slow digestion is... indigestible */
2473 if (otmp->otyp == RIN_SLOW_DIGESTION) {
2474 pline("This ring is indigestible!");
2475 (void) rottenfood(otmp);
2476 if (otmp->dknown && !objects[otmp->otyp].oc_name_known
2477 && !objects[otmp->otyp].oc_uname)
2478 docall(otmp);
2479 return 1;
2481 if (otmp->oclass != FOOD_CLASS) {
2482 int material;
2484 context.victual.reqtime = 1;
2485 context.victual.piece = otmp;
2486 context.victual.o_id = otmp->o_id;
2487 /* Don't split it, we don't need to if it's 1 move */
2488 context.victual.usedtime = 0;
2489 context.victual.canchoke = (u.uhs == SATIATED);
2490 /* Note: gold weighs 1 pt. for each 1000 pieces (see
2491 pickup.c) so gold and non-gold is consistent. */
2492 if (otmp->oclass == COIN_CLASS)
2493 basenutrit = ((otmp->quan > 200000L)
2494 ? 2000
2495 : (int) (otmp->quan / 100L));
2496 else if (otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
2497 basenutrit = weight(otmp);
2498 /* oc_nutrition is usually weight anyway */
2499 else
2500 basenutrit = objects[otmp->otyp].oc_nutrition;
2501 #ifdef MAIL
2502 if (otmp->otyp == SCR_MAIL) {
2503 basenutrit = 0;
2504 nodelicious = TRUE;
2506 #endif
2507 context.victual.nmod = basenutrit;
2508 context.victual.eating = TRUE; /* needed for lesshungry() */
2510 material = objects[otmp->otyp].oc_material;
2511 if (material == LEATHER || material == BONE
2512 || material == DRAGON_HIDE) {
2513 u.uconduct.unvegan++;
2514 violated_vegetarian();
2515 } else if (material == WAX)
2516 u.uconduct.unvegan++;
2517 u.uconduct.food++;
2519 if (otmp->cursed) {
2520 (void) rottenfood(otmp);
2521 nodelicious = TRUE;
2522 } else if (objects[otmp->otyp].oc_material == PAPER)
2523 nodelicious = TRUE;
2525 if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
2526 pline("Ecch - that must have been poisonous!");
2527 if (!Poison_resistance) {
2528 losestr(rnd(4));
2529 losehp(rnd(15), xname(otmp), KILLED_BY_AN);
2530 } else
2531 You("seem unaffected by the poison.");
2532 } else if (!nodelicious) {
2533 pline("%s%s is delicious!",
2534 (obj_is_pname(otmp)
2535 && otmp->oartifact < ART_ORB_OF_DETECTION)
2536 ? ""
2537 : "This ",
2538 (otmp->oclass == COIN_CLASS)
2539 ? foodword(otmp)
2540 : singular(otmp, xname));
2542 eatspecial();
2543 return 1;
2546 if (otmp == context.victual.piece) {
2547 /* If they weren't able to choke, they don't suddenly become able to
2548 * choke just because they were interrupted. On the other hand, if
2549 * they were able to choke before, if they lost food it's possible
2550 * they shouldn't be able to choke now.
2552 if (u.uhs != SATIATED)
2553 context.victual.canchoke = FALSE;
2554 context.victual.o_id = 0;
2555 context.victual.piece = touchfood(otmp);
2556 if (context.victual.piece)
2557 context.victual.o_id = context.victual.piece->o_id;
2558 You("resume your meal.");
2559 start_eating(context.victual.piece);
2560 return 1;
2563 /* nothing in progress - so try to find something. */
2564 /* tins are a special case */
2565 /* tins must also check conduct separately in case they're discarded */
2566 if (otmp->otyp == TIN) {
2567 start_tin(otmp);
2568 return 1;
2571 /* KMH, conduct */
2572 u.uconduct.food++;
2574 context.victual.o_id = 0;
2575 context.victual.piece = otmp = touchfood(otmp);
2576 if (context.victual.piece)
2577 context.victual.o_id = context.victual.piece->o_id;
2578 context.victual.usedtime = 0;
2580 /* Now we need to calculate delay and nutritional info.
2581 * The base nutrition calculated here and in eatcorpse() accounts
2582 * for normal vs. rotten food. The reqtime and nutrit values are
2583 * then adjusted in accordance with the amount of food left.
2585 if (otmp->otyp == CORPSE || otmp->globby) {
2586 int tmp = eatcorpse(otmp);
2588 if (tmp == 2) {
2589 /* used up */
2590 context.victual.piece = (struct obj *) 0;
2591 context.victual.o_id = 0;
2592 return 1;
2593 } else if (tmp)
2594 dont_start = TRUE;
2595 /* if not used up, eatcorpse sets up reqtime and may modify oeaten */
2596 } else {
2597 /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are
2598 * all handled in the != FOOD_CLASS case, above.
2600 switch (objects[otmp->otyp].oc_material) {
2601 case FLESH:
2602 u.uconduct.unvegan++;
2603 if (otmp->otyp != EGG) {
2604 violated_vegetarian();
2606 break;
2608 default:
2609 if (otmp->otyp == PANCAKE || otmp->otyp == FORTUNE_COOKIE /*eggs*/
2610 || otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR /*milk*/
2611 || otmp->otyp == LUMP_OF_ROYAL_JELLY)
2612 u.uconduct.unvegan++;
2613 break;
2616 context.victual.reqtime = objects[otmp->otyp].oc_delay;
2617 if (otmp->otyp != FORTUNE_COOKIE
2618 && (otmp->cursed || (!nonrotting_food(otmp->otyp)
2619 && (monstermoves - otmp->age)
2620 > (otmp->blessed ? 50L : 30L)
2621 && (otmp->orotten || !rn2(7))))) {
2622 if (rottenfood(otmp)) {
2623 otmp->orotten = TRUE;
2624 dont_start = TRUE;
2626 consume_oeaten(otmp, 1); /* oeaten >>= 1 */
2627 } else
2628 fprefx(otmp);
2631 /* re-calc the nutrition */
2632 basenutrit = (int) obj_nutrition(otmp);
2634 debugpline3(
2635 "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d",
2636 context.victual.reqtime, otmp->oeaten, basenutrit);
2638 context.victual.reqtime = (basenutrit == 0) ? 0
2639 : rounddiv(context.victual.reqtime * (long) otmp->oeaten, basenutrit);
2641 debugpline1("after rounddiv: victual.reqtime == %d",
2642 context.victual.reqtime);
2644 * calculate the modulo value (nutrit. units per round eating)
2645 * note: this isn't exact - you actually lose a little nutrition due
2646 * to this method.
2647 * TODO: add in a "remainder" value to be given at the end of the meal.
2649 if (context.victual.reqtime == 0 || otmp->oeaten == 0)
2650 /* possible if most has been eaten before */
2651 context.victual.nmod = 0;
2652 else if ((int) otmp->oeaten >= context.victual.reqtime)
2653 context.victual.nmod = -((int) otmp->oeaten
2654 / context.victual.reqtime);
2655 else
2656 context.victual.nmod = context.victual.reqtime % otmp->oeaten;
2657 context.victual.canchoke = (u.uhs == SATIATED);
2659 if (!dont_start)
2660 start_eating(otmp);
2661 return 1;
2665 use_tin_opener(obj)
2666 struct obj *obj;
2668 struct obj *otmp;
2669 int res = 0;
2671 if (!carrying(TIN)) {
2672 You("have no tin to open.");
2673 return 0;
2676 if (obj != uwep) {
2677 if (obj->cursed && obj->bknown) {
2678 char qbuf[QBUFSZ];
2680 if (ynq(safe_qbuf(qbuf, "Really wield ", "?",
2681 obj, doname, thesimpleoname, "that")) != 'y')
2682 return 0;
2684 if (!wield_tool(obj, "use"))
2685 return 0;
2686 res = 1;
2689 otmp = getobj(comestibles, "open");
2690 if (!otmp)
2691 return res;
2693 start_tin(otmp);
2694 return 1;
2697 /* Take a single bite from a piece of food, checking for choking and
2698 * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
2700 STATIC_OVL int
2701 bite()
2703 if (context.victual.canchoke && u.uhunger >= 2000) {
2704 choke(context.victual.piece);
2705 return 1;
2707 if (context.victual.doreset) {
2708 do_reset_eat();
2709 return 0;
2711 force_save_hs = TRUE;
2712 if (context.victual.nmod < 0) {
2713 lesshungry(-context.victual.nmod);
2714 consume_oeaten(context.victual.piece,
2715 context.victual.nmod); /* -= -nmod */
2716 } else if (context.victual.nmod > 0
2717 && (context.victual.usedtime % context.victual.nmod)) {
2718 lesshungry(1);
2719 consume_oeaten(context.victual.piece, -1); /* -= 1 */
2721 force_save_hs = FALSE;
2722 recalc_wt();
2723 return 0;
2726 /* as time goes by - called by moveloop(every move) & domove(melee attack) */
2727 void
2728 gethungry()
2730 if (u.uinvulnerable)
2731 return; /* you don't feel hungrier */
2733 /* being polymorphed into a creature which doesn't eat prevents
2734 this first uhunger decrement, but to stay in such form the hero
2735 will need to wear an Amulet of Unchanging so still burn a small
2736 amount of nutrition in the 'moves % 20' ring/amulet check below */
2737 if ((!Unaware || !rn2(10)) /* slow metabolic rate while asleep */
2738 && (carnivorous(youmonst.data)
2739 || herbivorous(youmonst.data)
2740 || metallivorous(youmonst.data))
2741 && !Slow_digestion)
2742 u.uhunger--; /* ordinary food consumption */
2744 if (moves % 2) { /* odd turns */
2745 /* Regeneration uses up food, unless due to an artifact */
2746 if ((HRegeneration & ~FROMFORM)
2747 || (ERegeneration & ~(W_ARTI | W_WEP)))
2748 u.uhunger--;
2749 if (near_capacity() > SLT_ENCUMBER)
2750 u.uhunger--;
2751 } else { /* even turns */
2752 if (Hunger)
2753 u.uhunger--;
2754 /* Conflict uses up food too */
2755 if (HConflict || (EConflict & (~W_ARTI)))
2756 u.uhunger--;
2757 /* +0 charged rings don't do anything, so don't affect hunger.
2758 Slow digestion cancels move hunger but still causes ring hunger. */
2759 switch ((int) (moves % 20)) { /* note: use even cases only */
2760 case 4:
2761 if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged))
2762 u.uhunger--;
2763 break;
2764 case 8:
2765 if (uamul)
2766 u.uhunger--;
2767 break;
2768 case 12:
2769 if (uright && (uright->spe || !objects[uright->otyp].oc_charged))
2770 u.uhunger--;
2771 break;
2772 case 16:
2773 if (u.uhave.amulet)
2774 u.uhunger--;
2775 break;
2776 default:
2777 break;
2780 newuhs(TRUE);
2783 /* called after vomiting and after performing feats of magic */
2784 void
2785 morehungry(num)
2786 int num;
2788 u.uhunger -= num;
2789 newuhs(TRUE);
2792 /* called after eating (and after drinking fruit juice) */
2793 void
2794 lesshungry(num)
2795 int num;
2797 /* See comments in newuhs() for discussion on force_save_hs */
2798 boolean iseating = (occupation == eatfood) || force_save_hs;
2800 debugpline1("lesshungry(%d)", num);
2801 u.uhunger += num;
2802 if (u.uhunger >= 2000) {
2803 if (!iseating || context.victual.canchoke) {
2804 if (iseating) {
2805 choke(context.victual.piece);
2806 reset_eat();
2807 } else
2808 choke(occupation == opentin ? context.tin.tin
2809 : (struct obj *) 0);
2810 /* no reset_eat() */
2812 } else {
2813 /* Have lesshungry() report when you're nearly full so all eating
2814 * warns when you're about to choke.
2816 if (u.uhunger >= 1500) {
2817 if (!context.victual.eating
2818 || (context.victual.eating && !context.victual.fullwarn)) {
2819 pline("You're having a hard time getting all of it down.");
2820 nomovemsg = "You're finally finished.";
2821 if (!context.victual.eating) {
2822 multi = -2;
2823 } else {
2824 context.victual.fullwarn = TRUE;
2825 if (context.victual.canchoke
2826 && context.victual.reqtime > 1) {
2827 /* a one-gulp food will not survive a stop */
2828 if (yn_function("Continue eating?", ynchars, 'n')
2829 != 'y') {
2830 reset_eat();
2831 nomovemsg = (char *) 0;
2838 newuhs(FALSE);
2841 STATIC_PTR
2843 unfaint(VOID_ARGS)
2845 (void) Hear_again();
2846 if (u.uhs > FAINTING)
2847 u.uhs = FAINTING;
2848 stop_occupation();
2849 context.botl = 1;
2850 return 0;
2853 boolean
2854 is_fainted()
2856 return (boolean) (u.uhs == FAINTED);
2859 /* call when a faint must be prematurely terminated */
2860 void
2861 reset_faint()
2863 if (afternmv == unfaint)
2864 unmul("You revive.");
2867 /* compute and comment on your (new?) hunger status */
2868 void
2869 newuhs(incr)
2870 boolean incr;
2872 unsigned newhs;
2873 static unsigned save_hs;
2874 static boolean saved_hs = FALSE;
2875 int h = u.uhunger;
2877 newhs = (h > 1000)
2878 ? SATIATED
2879 : (h > 150) ? NOT_HUNGRY
2880 : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING;
2882 /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2883 * This should not produce the message "you only feel hungry now";
2884 * that message should only appear if HUNGRY is an endpoint. Therefore
2885 * we check to see if we're in the middle of eating. If so, we save
2886 * the first hunger status, and at the end of eating we decide what
2887 * message to print based on the _entire_ meal, not on each little bit.
2889 /* It is normally possible to check if you are in the middle of a meal
2890 * by checking occupation == eatfood, but there is one special case:
2891 * start_eating() can call bite() for your first bite before it
2892 * sets the occupation.
2893 * Anyone who wants to get that case to work _without_ an ugly static
2894 * force_save_hs variable, feel free.
2896 /* Note: If you become a certain hunger status in the middle of the
2897 * meal, and still have that same status at the end of the meal,
2898 * this will incorrectly print the associated message at the end of
2899 * the meal instead of the middle. Such a case is currently
2900 * impossible, but could become possible if a message for SATIATED
2901 * were added or if HUNGRY and WEAK were separated by a big enough
2902 * gap to fit two bites.
2904 if (occupation == eatfood || force_save_hs) {
2905 if (!saved_hs) {
2906 save_hs = u.uhs;
2907 saved_hs = TRUE;
2909 u.uhs = newhs;
2910 return;
2911 } else {
2912 if (saved_hs) {
2913 u.uhs = save_hs;
2914 saved_hs = FALSE;
2918 if (newhs == FAINTING) {
2919 /* u,uhunger is likely to be negative at this point */
2920 int uhunger_div_by_10 = sgn(u.uhunger) * ((abs(u.uhunger) + 5) / 10);
2922 if (is_fainted())
2923 newhs = FAINTED;
2924 if (u.uhs <= WEAK || rn2(20 - uhunger_div_by_10) >= 19) {
2925 if (!is_fainted() && multi >= 0 /* %% */) {
2926 int duration = 10 - uhunger_div_by_10;
2928 /* stop what you're doing, then faint */
2929 stop_occupation();
2930 You("faint from lack of food.");
2931 incr_itimeout(&HDeaf, duration);
2932 context.botl = TRUE;
2933 nomul(-duration);
2934 multi_reason = "fainted from lack of food";
2935 nomovemsg = "You regain consciousness.";
2936 afternmv = unfaint;
2937 newhs = FAINTED;
2938 if (!Levitation)
2939 selftouch("Falling, you");
2942 /* this used to be -(200 + 20 * Con) but that was when being asleep
2943 suppressed per-turn uhunger decrement but being fainted didn't;
2944 now uhunger becomes more negative at a slower rate */
2945 } else if (u.uhunger < -(100 + 10 * (int) ACURR(A_CON))) {
2946 u.uhs = STARVED;
2947 context.botl = 1;
2948 bot();
2949 You("die from starvation.");
2950 killer.format = KILLED_BY;
2951 Strcpy(killer.name, "starvation");
2952 done(STARVING);
2953 /* if we return, we lifesaved, and that calls newuhs */
2954 return;
2958 if (newhs != u.uhs) {
2959 if (newhs >= WEAK && u.uhs < WEAK)
2960 losestr(1); /* this may kill you -- see below */
2961 else if (newhs < WEAK && u.uhs >= WEAK)
2962 losestr(-1);
2963 switch (newhs) {
2964 case HUNGRY:
2965 if (Hallucination) {
2966 You((!incr) ? "now have a lesser case of the munchies."
2967 : "are getting the munchies.");
2968 } else
2969 You((!incr) ? "only feel hungry now."
2970 : (u.uhunger < 145)
2971 ? "feel hungry."
2972 : "are beginning to feel hungry.");
2973 if (incr && occupation
2974 && (occupation != eatfood && occupation != opentin))
2975 stop_occupation();
2976 context.travel = context.travel1 = context.mv = context.run = 0;
2977 break;
2978 case WEAK:
2979 if (Hallucination)
2980 pline((!incr) ? "You still have the munchies."
2981 : "The munchies are interfering with your motor capabilities.");
2982 else if (incr && (Role_if(PM_WIZARD) || Race_if(PM_ELF)
2983 || Role_if(PM_VALKYRIE)))
2984 pline("%s needs food, badly!",
2985 (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE))
2986 ? urole.name.m
2987 : "Elf");
2988 else
2989 You((!incr)
2990 ? "feel weak now."
2991 : (u.uhunger < 45) ? "feel weak."
2992 : "are beginning to feel weak.");
2993 if (incr && occupation
2994 && (occupation != eatfood && occupation != opentin))
2995 stop_occupation();
2996 context.travel = context.travel1 = context.mv = context.run = 0;
2997 break;
2999 u.uhs = newhs;
3000 context.botl = 1;
3001 bot();
3002 if ((Upolyd ? u.mh : u.uhp) < 1) {
3003 You("die from hunger and exhaustion.");
3004 killer.format = KILLED_BY;
3005 Strcpy(killer.name, "exhaustion");
3006 done(STARVING);
3007 return;
3012 /* Returns an object representing food.
3013 * Object may be either on floor or in inventory.
3015 struct obj *
3016 floorfood(verb, corpsecheck)
3017 const char *verb;
3018 int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
3020 register struct obj *otmp;
3021 char qbuf[QBUFSZ];
3022 char c;
3023 boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */
3024 offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */
3026 /* if we can't touch floor objects then use invent food only */
3027 if (iflags.menu_requested /* command was preceded by 'm' prefix */
3028 || !can_reach_floor(TRUE) || (feeding && u.usteed)
3029 || (is_pool_or_lava(u.ux, u.uy)
3030 && (Wwalking || is_clinger(youmonst.data)
3031 || (Flying && !Breathless))))
3032 goto skipfloor;
3034 if (feeding && metallivorous(youmonst.data)) {
3035 struct obj *gold;
3036 struct trap *ttmp = t_at(u.ux, u.uy);
3038 if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
3039 /* If not already stuck in the trap, perhaps there should
3040 be a chance to becoming trapped? Probably not, because
3041 then the trap would just get eaten on the _next_ turn... */
3042 Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
3043 (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you"
3044 : "armed");
3045 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
3046 u.utrap = u.utraptype = 0;
3047 deltrap(ttmp);
3048 return mksobj(BEARTRAP, TRUE, FALSE);
3049 } else if (c == 'q') {
3050 return (struct obj *) 0;
3054 if (youmonst.data != &mons[PM_RUST_MONSTER]
3055 && (gold = g_at(u.ux, u.uy)) != 0) {
3056 if (gold->quan == 1L)
3057 Sprintf(qbuf, "There is 1 gold piece here; eat it?");
3058 else
3059 Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
3060 gold->quan);
3061 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
3062 return gold;
3063 } else if (c == 'q') {
3064 return (struct obj *) 0;
3069 /* Is there some food (probably a heavy corpse) here on the ground? */
3070 for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
3071 if (corpsecheck
3072 ? (otmp->otyp == CORPSE
3073 && (corpsecheck == 1 || tinnable(otmp)))
3074 : feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp))
3075 : otmp->oclass == FOOD_CLASS) {
3076 char qsfx[QBUFSZ];
3077 boolean one = (otmp->quan == 1L);
3079 /* if blind and without gloves, attempting to eat (or tin or
3080 offer) a cockatrice corpse is fatal before asking whether
3081 or not to use it; otherwise, 'm<dir>' followed by 'e' could
3082 be used to locate cockatrice corpses without touching them */
3083 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
3084 feel_cockatrice(otmp, FALSE);
3085 /* if life-saved (or poly'd into stone golem), terminate
3086 attempt to eat off floor */
3087 return (struct obj *) 0;
3089 /* "There is <an object> here; <verb> it?" or
3090 "There are <N objects> here; <verb> one?" */
3091 Sprintf(qbuf, "There %s ", otense(otmp, "are"));
3092 Sprintf(qsfx, " here; %s %s?", verb, one ? "it" : "one");
3093 (void) safe_qbuf(qbuf, qbuf, qsfx, otmp, doname, ansimpleoname,
3094 one ? something : (const char *) "things");
3095 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y')
3096 return otmp;
3097 else if (c == 'q')
3098 return (struct obj *) 0;
3102 skipfloor:
3103 /* We cannot use ALL_CLASSES since that causes getobj() to skip its
3104 * "ugly checks" and we need to check for inedible items.
3106 otmp = getobj(feeding ? allobj : offering ? offerfodder : comestibles,
3107 verb);
3108 if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS))
3109 if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
3110 You_cant("%s that!", verb);
3111 return (struct obj *) 0;
3113 return otmp;
3116 /* Side effects of vomiting */
3117 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
3118 void
3119 vomit() /* A good idea from David Neves */
3121 if (cantvomit(youmonst.data))
3122 /* doesn't cure food poisoning; message assumes that we aren't
3123 dealing with some esoteric body_part() */
3124 Your("jaw gapes convulsively.");
3125 else
3126 make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
3127 nomul(-2);
3128 multi_reason = "vomiting";
3129 nomovemsg = You_can_move_again;
3133 eaten_stat(base, obj)
3134 int base;
3135 struct obj *obj;
3137 long uneaten_amt, full_amount;
3139 /* get full_amount first; obj_nutrition() might modify obj->oeaten */
3140 full_amount = (long) obj_nutrition(obj);
3141 uneaten_amt = (long) obj->oeaten;
3142 if (uneaten_amt > full_amount) {
3143 impossible(
3144 "partly eaten food (%ld) more nutritious than untouched food (%ld)",
3145 uneaten_amt, full_amount);
3146 uneaten_amt = full_amount;
3149 base = (int) (full_amount ? (long) base * uneaten_amt / full_amount : 0L);
3150 return (base < 1) ? 1 : base;
3153 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
3154 void
3155 consume_oeaten(obj, amt)
3156 struct obj *obj;
3157 int amt;
3160 * This is a hack to try to squelch several long standing mystery
3161 * food bugs. A better solution would be to rewrite the entire
3162 * victual handling mechanism from scratch using a less complex
3163 * model. Alternatively, this routine could call done_eating()
3164 * or food_disappears() but its callers would need revisions to
3165 * cope with context.victual.piece unexpectedly going away.
3167 * Multi-turn eating operates by setting the food's oeaten field
3168 * to its full nutritional value and then running a counter which
3169 * independently keeps track of whether there is any food left.
3170 * The oeaten field can reach exactly zero on the last turn, and
3171 * the object isn't removed from inventory until the next turn
3172 * when the "you finish eating" message gets delivered, so the
3173 * food would be restored to the status of untouched during that
3174 * interval. This resulted in unexpected encumbrance messages
3175 * at the end of a meal (if near enough to a threshold) and would
3176 * yield full food if there was an interruption on the critical
3177 * turn. Also, there have been reports over the years of food
3178 * becoming massively heavy or producing unlimited satiation;
3179 * this would occur if reducing oeaten via subtraction attempted
3180 * to drop it below 0 since its unsigned type would produce a
3181 * huge positive value instead. So far, no one has figured out
3182 * _why_ that inappropriate subtraction might sometimes happen.
3185 if (amt > 0) {
3186 /* bit shift to divide the remaining amount of food */
3187 obj->oeaten >>= amt;
3188 } else {
3189 /* simple decrement; value is negative so we actually add it */
3190 if ((int) obj->oeaten > -amt)
3191 obj->oeaten += amt;
3192 else
3193 obj->oeaten = 0;
3196 if (obj->oeaten == 0) {
3197 if (obj == context.victual.piece) /* always true unless wishing... */
3198 context.victual.reqtime =
3199 context.victual.usedtime; /* no bites left */
3200 obj->oeaten = 1; /* smallest possible positive value */
3204 /* called when eatfood occupation has been interrupted,
3205 or in the case of theft, is about to be interrupted */
3206 boolean
3207 maybe_finished_meal(stopping)
3208 boolean stopping;
3210 /* in case consume_oeaten() has decided that the food is all gone */
3211 if (occupation == eatfood
3212 && context.victual.usedtime >= context.victual.reqtime) {
3213 if (stopping)
3214 occupation = 0; /* for do_reset_eat */
3215 (void) eatfood(); /* calls done_eating() to use up
3216 context.victual.piece */
3217 return TRUE;
3219 return FALSE;
3222 /* Tin of <something> to the rescue? Decide whether current occupation
3223 is an attempt to eat a tin of something capable of saving hero's life.
3224 We don't care about consumption of non-tinned food here because special
3225 effects there take place on first bite rather than at end of occupation.
3226 [Popeye the Sailor gets out of trouble by eating tins of spinach. :-] */
3227 boolean
3228 Popeye(threat)
3229 int threat;
3231 struct obj *otin;
3232 int mndx;
3234 if (occupation != opentin)
3235 return FALSE;
3236 otin = context.tin.tin;
3237 /* make sure hero still has access to tin */
3238 if (!carried(otin)
3239 && (!obj_here(otin, u.ux, u.uy) || !can_reach_floor(TRUE)))
3240 return FALSE;
3241 /* unknown tin is assumed to be helpful */
3242 if (!otin->known)
3243 return TRUE;
3244 /* known tin is helpful if it will stop life-threatening problem */
3245 mndx = otin->corpsenm;
3246 switch (threat) {
3247 /* note: not used; hunger code bypasses stop_occupation() when eating */
3248 case HUNGER:
3249 return (boolean) (mndx != NON_PM || otin->spe == 1);
3250 /* flesh from lizards and acidic critters stops petrification */
3251 case STONED:
3252 return (boolean) (mndx >= LOW_PM
3253 && (mndx == PM_LIZARD || acidic(&mons[mndx])));
3254 /* no tins can cure these (yet?) */
3255 case SLIMED:
3256 case SICK:
3257 case VOMITING:
3258 break;
3259 default:
3260 break;
3262 return FALSE;
3265 /*eat.c*/