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. */
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
));
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
,
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.
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
)
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
)))
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
))
108 /* return (boolean) !!index(comestibles, obj->oclass); */
109 return (boolean
) (obj
->oclass
== FOOD_CLASS
);
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 },
141 #define TTSZ SIZE(tintxts)
143 static char *eatmbuf
= 0; /* set by cpostfx() */
145 /* called after mimicing is over */
149 /* release `eatmbuf' */
151 if (nomovemsg
== eatmbuf
)
153 free((genericptr_t
) eatmbuf
), eatmbuf
= 0;
156 if (youmonst
.m_ap_type
) {
157 youmonst
.m_ap_type
= M_AP_NOTHING
;
163 /* called when hallucination is toggled */
167 const char *altmsg
= 0;
168 int altapp
= 0; /* lint suppression */
170 if (!eatmbuf
|| nomovemsg
!= eatmbuf
)
173 if (is_obj_mappear(&youmonst
,ORANGE
) && !Hallucination
) {
174 /* revert from hallucinatory to "normal" mimicking */
175 altmsg
= "You now prefer mimicking yourself.";
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.";
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
;
198 /* ``[the(] singular(food, xname) [)]'' */
199 STATIC_OVL
const char *
200 food_xname(food
, the_pfx
)
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
]))
214 /* the ordinary case */
215 result
= singular(food
, xname
);
218 result
= the(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.)
233 /* only happens if you were satiated */
234 if (u
.uhs
!= SATIATED
) {
235 if (!food
|| food
->otyp
!= AMULET_OF_STRANGULATION
)
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.");
250 You("stuff yourself and then vomit voluminously.");
251 morehungry(1000); /* you just got *very* sick! */
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.
260 You("choke over your %s.", foodword(food
));
261 if (food
->oclass
== COIN_CLASS
) {
262 Strcpy(killer
.name
, "very rich meal");
264 killer
.format
= KILLED_BY
;
265 Strcpy(killer
.name
, killer_xname(food
));
268 You("choke over it.");
269 Strcpy(killer
.name
, "quick snack");
276 /* modify object wt. depending on time spent consuming it */
280 struct obj
*piece
= context
.victual
.piece
;
282 impossible("recalc_wt without piece");
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 */
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
;
306 /* base nutrition of a food-class object */
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
)
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 */
332 STATIC_OVL
struct obj
*
336 if (otmp
->quan
> 1L) {
338 (void) splitobj(otmp
, otmp
->quan
- 1L);
340 otmp
= splitobj(otmp
, 1L);
341 debugpline0("split object,");
345 costly_alteration(otmp
, COST_BITE
);
346 otmp
->oeaten
= obj_nutrition(otmp
);
351 if (inv_cnt(FALSE
) >= 52) {
352 sellobj_state(SELL_DONTSELL
);
354 sellobj_state(SELL_NORMAL
);
356 otmp
->nomerge
= 1; /* used to prevent merge */
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
373 if (obj
== context
.victual
.piece
) {
374 context
.victual
.piece
= (struct obj
*) 0;
375 context
.victual
.o_id
= 0;
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 */
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
;
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
;
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.
420 /* called each move during eating process */
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? */
431 if (!context
.victual
.eating
)
434 if (++context
.victual
.usedtime
<= context
.victual
.reqtime
) {
437 return 1; /* still busy */
448 struct obj
*piece
= context
.victual
.piece
;
450 piece
->in_use
= TRUE
;
451 occupation
= 0; /* do this early, so newuhs() knows we're done */
458 You("finish eating %s.", food_xname(piece
, TRUE
));
460 if (piece
->otyp
== CORPSE
|| piece
->globby
)
461 cpostfx(piece
->corpsenm
);
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
;
481 u
.uconduct
.unvegan
++;
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
;
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
)) {
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
);
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
));
525 /* life-saved; don't continue eating the brains */
528 if (magr
->mtame
&& !visflag
)
529 /* parallels mhitm.c's brief_feeling */
530 You("have a sad thought for a moment, then it passes.");
536 if (magr
== &youmonst
) {
538 * player mind flayer is eating something's brain
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 */
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
;
550 /* life-saving needed to reach here */
551 exercise(A_WIS
, FALSE
);
552 *dmg_p
+= xtra_dmg
; /* Rider takes extra damage */
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
);
562 exercise(A_WIS
, TRUE
);
565 /* targetting another mind flayer or your own underlying species
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";
578 Strcpy(killer
.name
, brainlessness
);
579 killer
.format
= KILLED_BY
;
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;
587 Your("last thought fades away.");
589 Strcpy(killer
.name
, brainlessness
);
590 killer
.format
= KILLED_BY
;
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 */
603 * monster mind flayer is eating another monster's brain
606 if (visflag
&& canspotmon(mdef
))
607 pline("%s doesn't notice.", Monnam(mdef
));
609 } else if (is_rider(pd
)) {
612 result
= MM_AGR_DIED
;
613 /* Rider takes extra damage regardless of whether attacker dies */
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);
632 /* eating a corpse or egg of one's own species is usually naughty */
634 maybe_cannibal(pm
, 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
)
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) */
654 || (Upolyd
&& same_race(youmonst
.data
, fptr
))
655 || (u
.ulycn
>= LOW_PM
&& were_beastie(pm
) == u
.ulycn
))) {
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 */
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.");
681 if (context
.victual
.piece
)
682 context
.victual
.eating
= FALSE
;
683 return; /* lifesaved */
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
;
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
;
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;
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
, "");
730 if (acidic(&mons
[pm
]) && Stoned
)
742 Sprintf(buf
, "What a pity--you just ruined a future piece of %sart!",
743 ACURR(A_CHA
) > 15 ? "fine " : "");
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. */
760 intrinsic_possible(type
, ptr
)
762 register struct permonst
*ptr
;
767 #define ifdebugresist(Msg) \
773 #define ifdebugresist(Msg) /*empty*/
777 res
= (ptr
->mconveys
& MR_FIRE
) != 0;
778 ifdebugresist("can get fire resistance");
781 res
= (ptr
->mconveys
& MR_SLEEP
) != 0;
782 ifdebugresist("can get sleep resistance");
785 res
= (ptr
->mconveys
& MR_COLD
) != 0;
786 ifdebugresist("can get cold resistance");
789 res
= (ptr
->mconveys
& MR_DISINT
) != 0;
790 ifdebugresist("can get disintegration resistance");
792 case SHOCK_RES
: /* shock (electricity) resistance */
793 res
= (ptr
->mconveys
& MR_ELEC
) != 0;
794 ifdebugresist("can get shock resistance");
797 res
= (ptr
->mconveys
& MR_POISON
) != 0;
798 ifdebugresist("can get poison resistance");
801 res
= can_teleport(ptr
);
802 ifdebugresist("can get teleport");
804 case TELEPORT_CONTROL
:
805 res
= control_teleport(ptr
);
806 ifdebugresist("can get teleport control");
809 res
= telepathic(ptr
);
810 ifdebugresist("can get telepathy");
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.
826 register struct permonst
*ptr
;
830 debugpline1("Attempting to give intrinsic %d", type
);
831 /* some intrinsics are easier to get than others */
834 if ((ptr
== &mons
[PM_KILLER_BEE
] || ptr
== &mons
[PM_SCORPION
])
843 case TELEPORT_CONTROL
:
854 if (ptr
->mlevel
<= rn2(chance
))
855 return; /* failed die roll */
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
;
866 debugpline0("Trying to give sleep resistance");
867 if (!(HSleep_resistance
& FROMOUTSIDE
)) {
868 You_feel("wide awake.");
869 HSleep_resistance
|= FROMOUTSIDE
;
873 debugpline0("Trying to give cold resistance");
874 if (!(HCold_resistance
& FROMOUTSIDE
)) {
875 You_feel("full of hot air.");
876 HCold_resistance
|= FROMOUTSIDE
;
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
;
886 case SHOCK_RES
: /* shock (electricity) resistance */
887 debugpline0("Trying to give shock resistance");
888 if (!(HShock_resistance
& FROMOUTSIDE
)) {
890 You_feel("grounded in reality.");
892 Your("health currently feels amplified!");
893 HShock_resistance
|= FROMOUTSIDE
;
897 debugpline0("Trying to give poison resistance");
898 if (!(HPoison_resistance
& FROMOUTSIDE
)) {
899 You_feel(Poison_resistance
? "especially healthy." : "healthy.");
900 HPoison_resistance
|= FROMOUTSIDE
;
904 debugpline0("Trying to give teleport");
905 if (!(HTeleportation
& FROMOUTSIDE
)) {
906 You_feel(Hallucination
? "diffuse." : "very jumpy.");
907 HTeleportation
|= FROMOUTSIDE
;
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
;
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. */
930 debugpline0("Tried to give an impossible intrinsic");
935 /* called after completely consuming a corpse */
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 */
950 /* MRKR: "eye of newt" may give small magical energy boost */
951 if (rn2(3) || 3 * u
.uen
<= 2 * u
.uenmax
) {
954 if (u
.uen
> u
.uenmax
) {
959 if (old_uen
!= u
.uen
) {
960 You_feel("a mild buzz.");
968 case PM_HUMAN_WERERAT
:
969 catch_lycanthropy
= PM_WERERAT
;
971 case PM_HUMAN_WEREJACKAL
:
972 catch_lycanthropy
= PM_WEREJACKAL
;
974 case PM_HUMAN_WEREWOLF
:
975 catch_lycanthropy
= PM_WEREWOLF
;
986 set_itimeout(&HInvis
, (long) rn1(100, 50));
987 if (!Blind
&& !BInvis
)
988 self_invis_message();
990 if (!(HInvis
& INTRINSIC
))
992 HInvis
|= FROMOUTSIDE
;
993 HSee_invisible
|= FROMOUTSIDE
;
997 case PM_YELLOW_LIGHT
:
999 make_stunned((HStun
& TIMEOUT
) + 30L, FALSE
);
1002 make_stunned((HStun
& TIMEOUT
) + 30L, FALSE
);
1004 case PM_GIANT_MIMIC
:
1007 case PM_LARGE_MIMIC
:
1010 case PM_SMALL_MIMIC
:
1012 if (youmonst
.data
->mlet
!= S_MIMIC
&& !Unchanging
) {
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. */
1020 dismount_steed(DISMOUNT_FELL
);
1022 multi_reason
= "pretending to be a pile of gold";
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
;
1036 /* make gold symbol show up now */
1037 display_nhwindow(WIN_MAP
, TRUE
);
1040 case PM_QUANTUM_MECHANIC
:
1041 Your("velocity suddenly seems very uncertain!");
1042 if (HFast
& INTRINSIC
) {
1043 HFast
&= ~INTRINSIC
;
1044 You("seem slower.");
1046 HFast
|= FROMOUTSIDE
;
1047 You("seem faster.");
1051 if ((HStun
& TIMEOUT
) > 2)
1052 make_stunned(2L, FALSE
);
1053 if ((HConfusion
& TIMEOUT
) > 2)
1054 make_confused(2L, FALSE
);
1057 case PM_DOPPELGANGER
:
1058 case PM_SANDESTIN
: /* moot--they don't leave corpses */
1060 You_feel("momentarily different."); /* same as poly trap */
1062 You_feel("a change coming over you.");
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");
1072 case PM_MIND_FLAYER
:
1073 case PM_MASTER_MIND_FLAYER
:
1074 if (ABASE(A_INT
) < ATTRMAX(A_INT
)) {
1076 pline("Yum! That was real brain food!");
1077 (void) adjattrib(A_INT
, 1, FALSE
);
1078 break; /* don't give them telepathy, too */
1081 pline("For some reason, that tasted bland.");
1085 struct permonst
*ptr
= &mons
[pm
];
1086 boolean conveys_STR
= is_giant(ptr
);
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
,
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 */
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
))
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) */
1119 debugpline2("Intrinsic %d replacing %d", i
, tmp
);
1123 /* if strength is the only candidate, give it 50% chance */
1124 if (conveys_STR
&& count
== 1 && !rn2(2))
1126 /* if something was chosen, give it now (givit() might fail) */
1128 gainstr((struct obj
*) 0, 0, TRUE
);
1132 } /* default case */
1135 if (catch_lycanthropy
>= LOW_PM
) {
1136 set_ulycn(catch_lycanthropy
);
1137 retouch_equipment(2);
1143 violated_vegetarian()
1145 u
.uconduct
.unvegetarian
++;
1146 if (Role_if(PM_MONK
)) {
1147 You_feel("guilty.");
1153 /* common code to check and possibly charge for 1 context.tin.tin,
1154 * will split() context.tin.tin if necessary */
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
)
1178 if (s
&& tinvariety
) {
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
)
1193 * This assumes that buf already contains the word "tin",
1194 * as is the case with caller xname().
1197 tin_details(obj
, mnum
, buf
)
1203 int r
= tin_variety(obj
, TRUE
);
1206 if (r
== SPINACH_TIN
)
1207 Strcat(buf
, " of spinach");
1208 else if (mnum
== NON_PM
)
1209 Strcpy(buf
, "empty tin");
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
);
1217 Sprintf(eos(buf
), " of %s ", tintxts
[r
].txt
);
1220 Strcpy(eos(buf
), " of ");
1222 if (vegetarian(&mons
[mnum
]))
1223 Sprintf(eos(buf
), "%s", mons
[mnum
].mname
);
1225 Sprintf(eos(buf
), "%s meat", mons
[mnum
].mname
);
1231 set_tin_variety(obj
, forcetype
)
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 */
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
)
1250 } else if (forcetype
>= 0 && forcetype
< TTSZ
- 1) {
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 */
1261 tin_variety(obj
, disp
)
1263 boolean disp
; /* we're just displaying so leave things alone */
1267 if (obj
->spe
== 1) {
1269 } else if (obj
->cursed
) {
1270 r
= ROTTEN_TIN
; /* always rotten if cursed */
1271 } else if (obj
->spe
< 0) {
1273 --r
; /* get rid of the offset */
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 */
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
);
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
);
1311 which
= 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1312 if ((mnum
== PM_COCKATRICE
|| mnum
== PM_CHICKATRICE
)
1313 && (Stone_resistance
|| Hallucination
)) {
1315 which
= 1; /* suppress pluralization */
1316 } else if (Hallucination
) {
1317 what
= rndmonnam(NULL
);
1319 what
= mons
[mnum
].mname
;
1320 if (the_unique_pm(&mons
[mnum
]))
1322 else if (type_is_pname(&mons
[mnum
]))
1326 what
= makeplural(what
);
1327 else if (which
== 2)
1330 pline("It smells like %s.", what
);
1331 if (yn("Eat it?") == 'n') {
1333 You("discard the open tin.");
1335 tin
->dknown
= tin
->known
= 1;
1336 costly_tin(COST_OPEN
);
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;
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
);
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... */
1371 pline("It contains some decaying%s%s substance.",
1372 Blind
? "" : " ", Blind
? "" : hcolor(NH_GREEN
));
1374 pline("It contains spinach.");
1375 tin
->dknown
= tin
->known
= 1;
1378 if (yn("Eat it?") == 'n') {
1380 You("discard the open tin.");
1381 costly_tin(COST_OPEN
);
1386 * Same order as with non-spinach above:
1387 * conduct update, side-effects, shop handling, and nutrition.
1390 .food
++; /* don't need vegan/vegetarian checks for spinach */
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
1401 ? (400 + rnd(200)) /* uncursed */
1402 : (200 + rnd(400))); /* cursed */
1410 context
.tin
.tin
= (struct obj
*) 0;
1411 context
.tin
.o_id
= 0;
1414 /* called during each move whilst opening a tin */
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.");
1426 if (context
.tin
.usedtime
< context
.tin
.reqtime
)
1427 return 1; /* still busy */
1429 consume_tin("You succeed in opening the tin.");
1433 /* called when starting to open a tin */
1438 const char *mesg
= 0;
1441 if (metallivorous(youmonst
.data
)) {
1442 mesg
= "You bite right into the metal tin...";
1444 } else if (cantwield(youmonst
.data
)) { /* nohands || verysmall */
1445 You("cannot handle the tin properly to open it.");
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);
1455 mesg
= "The tin opens like magic!";
1457 pline_The("tin seems easy to open.");
1459 switch (uwep
->otyp
) {
1461 mesg
= "You easily open the tin."; /* iff tmp==0 */
1462 tmp
= rn2(uwep
->cursed
? 3 : !uwep
->blessed
? 2 : 1);
1481 pline("Using %s you try to open the tin.", yobjnam(uwep
, (char *) 0));
1484 pline("It is not so easy to open this tin.");
1486 pline_The("tin slips from your %s.",
1487 makeplural(body_part(FINGER
)));
1488 if (otmp
->quan
> 1L) {
1489 otmp
= splitobj(otmp
, 1L);
1497 tmp
= rn1(1 + 500 / ((int) (ACURR(A_DEX
) + ACURRSTR
)), 10);
1500 context
.tin
.tin
= otmp
;
1501 context
.tin
.o_id
= otmp
->o_id
;
1503 consume_tin(mesg
); /* begin immediately */
1505 context
.tin
.reqtime
= tmp
;
1506 context
.tin
.usedtime
= 0;
1507 set_occupation(opentin
, "opening the tin", 0);
1512 /* called when waking up after fainting */
1514 Hear_again(VOID_ARGS
)
1516 /* Chance of deafness going away while fainted/sleeping/etc. */
1518 make_deaf(0L, FALSE
);
1519 context
.botl
= TRUE
;
1524 /* called on the "first bite" of rotten food */
1529 pline("Blecch! Rotten %s!", foodword(obj
));
1532 You_feel("rather trippy.");
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
);
1542 Your1(vision_clears
);
1543 } else if (!rn2(3)) {
1544 const char *what
, *where
;
1545 int duration
= rnd(10);
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";
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
;
1558 multi_reason
= "unconscious from rotten food";
1559 nomovemsg
= "You are conscious again.";
1560 afternmv
= Hear_again
;
1566 /* called when a corpse is selected as food */
1571 int retcode
= 0, tp
= 0, mnum
= otmp
->corpsenm
;
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
;
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));
1591 else if (otmp
->blessed
)
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"
1601 : vegetarian(&mons
[mnum
]) ? "protoplasm"
1603 cannibal
? ", you cannibal" : "");
1604 if (Sick_resistance
) {
1605 pline("It doesn't seem at all sickening, though...");
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
);
1621 } else if (acidic(&mons
[mnum
]) && !Acid_resistance
) {
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)) {
1628 pline("Ecch - that must have been poisonous!");
1629 if (!Poison_resistance
) {
1631 losehp(rnd(15), !glob
? "poisonous corpse" : "poisonous glob",
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
) {
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
);
1652 if (!mons
[otmp
->corpsenm
].cnutrit
) {
1653 /* no nutrition: rots away, no message if you passed out */
1655 pline_The("corpse rots away completely.");
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.");
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
))
1681 && ((rotted
< 1) ? TRUE
: !rn2(rotted
+1)));
1682 const char *pmxnam
= food_xname(otmp
, FALSE
);
1684 if (!strncmpi(pmxnam
, "the ", 4))
1686 pline("%s%s %s %s%c",
1687 type_is_pname(&mons
[mnum
])
1688 ? "" : the_unique_pm(&mons
[mnum
]) ? "The " : "This ",
1690 Hallucination
? "is" : "tastes",
1691 /* tiger reference is to TV ads for "Frosted Flakes",
1692 breakfast cereal targeted at kids by "Tony the tiger" */
1694 ? (yummy
? ((u
.umonnum
== PM_TIGER
) ? "gr-r-reat" : "gnarly")
1695 : palatable
? "copacetic" : "grody")
1696 : (yummy
? "delicious" : palatable
? "okay" : "terrible"),
1697 (yummy
|| !palatable
) ? '!' : '.');
1703 /* called as you start to eat */
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 */
1727 old_nomovemsg
= nomovemsg
;
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
;
1739 nomovemsg
= save_nomovemsg
;
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
);
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
1762 switch (otmp
->otyp
) {
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
));
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!");
1777 pline("Yak - dog food!");
1778 more_experienced(1, 0);
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
);
1787 if (maybe_polyd(is_orc(youmonst
.data
), Race_if(PM_ORC
))) {
1788 pline("%s", "!#?&* elf kibble!");
1790 } else if (maybe_polyd(is_elf(youmonst
.data
), Race_if(PM_ELF
))) {
1791 pline("A little goes a long way.");
1797 case HUGE_CHUNK_OF_MEAT
:
1800 case CLOVE_OF_GARLIC
:
1801 if (is_undead(youmonst
.data
)) {
1802 make_vomiting((long) rn1(context
.victual
.reqtime
, 5), FALSE
);
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!");
1824 } else if (otmp
->otyp
== APPLE
|| otmp
->otyp
== PEAR
) {
1825 if (!Hallucination
) {
1826 pline("Core dumped.");
1828 /* This is based on an old Usenet joke, a fake a.out manual
1833 pline("%s -- core dumped.",
1835 ? "Segmentation fault"
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
);
1849 pline("This %s is %s", singular(otmp
, xname
),
1851 ? (Hallucination
? "grody!" : "terrible!")
1852 : (otmp
->otyp
== CRAM_RATION
1853 || otmp
->otyp
== K_RATION
1854 || otmp
->otyp
== C_RATION
)
1856 : Hallucination
? "gnarly!" : "delicious!");
1858 break; /* default */
1862 /* increment a combat intrinsic with limits on its growth */
1864 bounded_increase(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
)
1872 if (uleft
&& uleft
->otyp
== typ
)
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
;
1890 inc
= 0; /* no further increase allowed via this method */
1896 accessory_has_effect(otmp
)
1899 pline("Magic spreads through your body as you digest the %s.",
1900 otmp
->oclass
== RING_CLASS
? "ring" : "amulet");
1907 int typ
= otmp
->otyp
;
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
) {
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
) {
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
;
1931 case RIN_SEE_INVISIBLE
:
1932 set_mimic_blocking();
1934 if (Invis
&& !oldprop
&& !ESee_invisible
1935 && !perceives(youmonst
.data
) && !Blind
) {
1937 pline("Suddenly you can see yourself.");
1941 case RIN_INVISIBILITY
:
1942 if (!oldprop
&& !EInvis
&& !BInvis
&& !See_invisible
1945 Your("body takes on a %s transparency...",
1946 Hallucination
? "normal" : "strange");
1950 case RIN_PROTECTION_FROM_SHAPE_CHAN
:
1953 case RIN_LEVITATION
:
1954 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1955 u
.uprops
[LEVITATION
].intrinsic
= oldprop
;
1958 incr_itimeout(&HLevitation
, d(10, 20));
1962 } /* inner switch */
1963 break; /* default case of outer switch */
1966 accessory_has_effect(otmp
);
1967 if (adjattrib(A_CHA
, otmp
->spe
, -1))
1970 case RIN_GAIN_STRENGTH
:
1971 accessory_has_effect(otmp
);
1972 if (adjattrib(A_STR
, otmp
->spe
, -1))
1975 case RIN_GAIN_CONSTITUTION
:
1976 accessory_has_effect(otmp
);
1977 if (adjattrib(A_CON
, otmp
->spe
, -1))
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
);
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
);
1990 case RIN_PROTECTION
:
1991 accessory_has_effect(otmp
);
1992 HProtection
|= FROMOUTSIDE
;
1993 u
.ublessed
= bounded_increase(u
.ublessed
, otmp
->spe
,
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
;
2005 case AMULET_OF_CHANGE
:
2006 accessory_has_effect(otmp
);
2009 You("are suddenly very %s!",
2010 flags
.female
? "feminine" : "masculine");
2013 case AMULET_OF_UNCHANGING
:
2014 /* un-change: it's a pun */
2015 if (!Unchanging
&& Upolyd
) {
2016 accessory_has_effect(otmp
);
2021 case AMULET_OF_STRANGULATION
: /* bad idea! */
2022 /* no message--this gives no permanent effect */
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
;
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.
2047 /* called after eating non-food */
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
);
2057 context
.victual
.piece
= (struct obj
*) 0;
2058 context
.victual
.o_id
= 0;
2059 context
.victual
.eating
= 0;
2060 if (otmp
->oclass
== COIN_CLASS
) {
2064 useupf(otmp
, otmp
->quan
);
2065 vault_gd_watching(GD_EATGOLD
);
2068 if (objects
[otmp
->otyp
].oc_material
== PAPER
) {
2070 if (otmp
->otyp
== SCR_MAIL
)
2072 pline("This junk mail is less than satisfying.");
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
? '!' : '.');
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
) {
2090 } else if (otmp
->otyp
== LEASH
&& otmp
->leashmon
) {
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)
2109 if (otmp
== uquiver
&& otmp
->quan
== 1L)
2111 if (otmp
== uswapwep
&& otmp
->quan
== 1L)
2117 unpunish(); /* but no useup() */
2118 else if (carried(otmp
))
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 *
2137 if (otmp
->oclass
== FOOD_CLASS
)
2139 if (otmp
->oclass
== GEM_CLASS
&& objects
[otmp
->otyp
].oc_material
== GLASS
2141 makeknown(otmp
->otyp
);
2142 return foodwords
[objects
[otmp
->otyp
].oc_material
];
2145 /* called after consuming (non-corpse) food */
2150 switch (otmp
->otyp
) {
2151 case SPRIG_OF_WOLFSBANE
:
2152 if (u
.ulycn
>= LOW_PM
|| is_were(youmonst
.data
))
2157 || !attacktype_fordmg(u
.ustuck
->data
, AT_ENGL
, AD_BLND
))
2158 make_blinded((long) u
.ucreamed
, TRUE
);
2160 case FORTUNE_COOKIE
:
2161 outrumor(bcsign(otmp
), BY_COOKIE
);
2163 u
.uconduct
.literate
++;
2165 case LUMP_OF_ROYAL_JELLY
:
2166 /* This stuff seems to be VERY healthy! */
2167 gainstr(otmp
, 1, TRUE
);
2169 u
.mh
+= otmp
->cursed
? -rnd(20) : rnd(20);
2170 if (u
.mh
> u
.mhmax
) {
2174 } else if (u
.mh
<= 0) {
2178 u
.uhp
+= otmp
->cursed
? -rnd(20) : rnd(20);
2179 if (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");
2193 if (flesh_petrifies(&mons
[otmp
->corpsenm
])) {
2194 if (!Stone_resistance
2195 && !(poly_when_stoned(youmonst
.data
)
2196 && polymon(PM_STONE_GOLEM
))) {
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 */
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
);
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.");
2222 You_hear("sinister laughter as you fall asleep...");
2223 fall_asleep(-rn1(11, 20), TRUE
);
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
*));
2240 const char *odesc
= OBJ_DESCR(objects
[otmp
->otyp
]);
2242 if (odesc
&& (otmp
->oclass
== SPBOOK_CLASS
)) {
2243 if (!strcmp(odesc
, "leather"))
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.
2256 edibility_prompts(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
;
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) */);
2291 else if (otmp
->blessed
)
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
) {
2302 Sprintf(buf
, "%s like %s could be tainted! %s", foodsmell
, it_or_they
,
2304 if (yn_function(buf
, ynchars
, 'n') == 'n')
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')
2317 if (otmp
->orotten
|| (cadaver
&& rotted
> 3L)) {
2319 Sprintf(buf
, "%s like %s could be rotten! %s", foodsmell
, it_or_they
,
2321 if (yn_function(buf
, ynchars
, 'n') == 'n')
2326 if (cadaver
&& poisonous(&mons
[mnum
]) && !Poison_resistance
) {
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')
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')
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')
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
,
2360 if (yn_function(buf
, ynchars
, 'n') == 'n')
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
,
2375 if (yn_function(buf
, ynchars
, 'n') == 'n')
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')
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
,
2395 if (yn_function(buf
, ynchars
, 'n') == 'n')
2408 int basenutrit
; /* nutrition of full item */
2409 boolean dont_start
= FALSE
, nodelicious
= FALSE
;
2412 pline("If you can't breathe air, how can you consume solids?");
2415 if (!(otmp
= floorfood("eat", 0)))
2417 if (check_capacity((char *) 0))
2421 int res
= edibility_prompts(otmp
);
2425 "%s stops tingling and your sense of smell returns to normal.",
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
))) {
2441 } else if (!is_edible(otmp
)) {
2442 You("cannot eat that!");
2444 } else if ((otmp
->owornmask
& (W_ARMOR
| W_TOOL
| W_AMUL
| W_SADDLE
))
2446 /* let them eat rings */
2447 You_cant("eat %s you're wearing.", something
);
2450 if (is_metallic(otmp
) && u
.umonnum
== PM_RUST_MONSTER
2451 && otmp
->oerodeproof
) {
2452 otmp
->rknown
= TRUE
;
2453 if (otmp
->quan
> 1L) {
2455 (void) splitobj(otmp
, otmp
->quan
- 1L);
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
)) {
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
)
2481 if (otmp
->oclass
!= FOOD_CLASS
) {
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)
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 */
2500 basenutrit
= objects
[otmp
->otyp
].oc_nutrition
;
2502 if (otmp
->otyp
== SCR_MAIL
) {
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
++;
2520 (void) rottenfood(otmp
);
2522 } else if (objects
[otmp
->otyp
].oc_material
== PAPER
)
2525 if (otmp
->oclass
== WEAPON_CLASS
&& otmp
->opoisoned
) {
2526 pline("Ecch - that must have been poisonous!");
2527 if (!Poison_resistance
) {
2529 losehp(rnd(15), xname(otmp
), KILLED_BY_AN
);
2531 You("seem unaffected by the poison.");
2532 } else if (!nodelicious
) {
2533 pline("%s%s is delicious!",
2535 && otmp
->oartifact
< ART_ORB_OF_DETECTION
)
2538 (otmp
->oclass
== COIN_CLASS
)
2540 : singular(otmp
, xname
));
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
);
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
) {
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
);
2590 context
.victual
.piece
= (struct obj
*) 0;
2591 context
.victual
.o_id
= 0;
2595 /* if not used up, eatcorpse sets up reqtime and may modify oeaten */
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
) {
2602 u
.uconduct
.unvegan
++;
2603 if (otmp
->otyp
!= EGG
) {
2604 violated_vegetarian();
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
++;
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
;
2626 consume_oeaten(otmp
, 1); /* oeaten >>= 1 */
2631 /* re-calc the nutrition */
2632 basenutrit
= (int) obj_nutrition(otmp
);
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
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
);
2656 context
.victual
.nmod
= context
.victual
.reqtime
% otmp
->oeaten
;
2657 context
.victual
.canchoke
= (u
.uhs
== SATIATED
);
2671 if (!carrying(TIN
)) {
2672 You("have no tin to open.");
2677 if (obj
->cursed
&& obj
->bknown
) {
2680 if (ynq(safe_qbuf(qbuf
, "Really wield ", "?",
2681 obj
, doname
, thesimpleoname
, "that")) != 'y')
2684 if (!wield_tool(obj
, "use"))
2689 otmp
= getobj(comestibles
, "open");
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.
2703 if (context
.victual
.canchoke
&& u
.uhunger
>= 2000) {
2704 choke(context
.victual
.piece
);
2707 if (context
.victual
.doreset
) {
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
)) {
2719 consume_oeaten(context
.victual
.piece
, -1); /* -= 1 */
2721 force_save_hs
= FALSE
;
2726 /* as time goes by - called by moveloop(every move) & domove(melee attack) */
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
))
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
)))
2749 if (near_capacity() > SLT_ENCUMBER
)
2751 } else { /* even turns */
2754 /* Conflict uses up food too */
2755 if (HConflict
|| (EConflict
& (~W_ARTI
)))
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 */
2761 if (uleft
&& (uleft
->spe
|| !objects
[uleft
->otyp
].oc_charged
))
2769 if (uright
&& (uright
->spe
|| !objects
[uright
->otyp
].oc_charged
))
2783 /* called after vomiting and after performing feats of magic */
2792 /* called after eating (and after drinking fruit juice) */
2797 /* See comments in newuhs() for discussion on force_save_hs */
2798 boolean iseating
= (occupation
== eatfood
) || force_save_hs
;
2800 debugpline1("lesshungry(%d)", num
);
2802 if (u
.uhunger
>= 2000) {
2803 if (!iseating
|| context
.victual
.canchoke
) {
2805 choke(context
.victual
.piece
);
2808 choke(occupation
== opentin
? context
.tin
.tin
2809 : (struct obj
*) 0);
2810 /* no reset_eat() */
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
) {
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')
2831 nomovemsg
= (char *) 0;
2845 (void) Hear_again();
2846 if (u
.uhs
> FAINTING
)
2856 return (boolean
) (u
.uhs
== FAINTED
);
2859 /* call when a faint must be prematurely terminated */
2863 if (afternmv
== unfaint
)
2864 unmul("You revive.");
2867 /* compute and comment on your (new?) hunger status */
2873 static unsigned save_hs
;
2874 static boolean saved_hs
= FALSE
;
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
) {
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);
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 */
2930 You("faint from lack of food.");
2931 incr_itimeout(&HDeaf
, duration
);
2932 context
.botl
= TRUE
;
2934 multi_reason
= "fainted from lack of food";
2935 nomovemsg
= "You regain consciousness.";
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
))) {
2949 You("die from starvation.");
2950 killer
.format
= KILLED_BY
;
2951 Strcpy(killer
.name
, "starvation");
2953 /* if we return, we lifesaved, and that calls newuhs */
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
)
2965 if (Hallucination
) {
2966 You((!incr
) ? "now have a lesser case of the munchies."
2967 : "are getting the munchies.");
2969 You((!incr
) ? "only feel hungry now."
2972 : "are beginning to feel hungry.");
2973 if (incr
&& occupation
2974 && (occupation
!= eatfood
&& occupation
!= opentin
))
2976 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
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
))
2991 : (u
.uhunger
< 45) ? "feel weak."
2992 : "are beginning to feel weak.");
2993 if (incr
&& occupation
2994 && (occupation
!= eatfood
&& occupation
!= opentin
))
2996 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
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");
3012 /* Returns an object representing food.
3013 * Object may be either on floor or in inventory.
3016 floorfood(verb
, corpsecheck
)
3018 int corpsecheck
; /* 0, no check, 1, corpses, 2, tinnable corpses */
3020 register struct obj
*otmp
;
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
))))
3034 if (feeding
&& metallivorous(youmonst
.data
)) {
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"
3045 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
3046 u
.utrap
= u
.utraptype
= 0;
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?");
3059 Sprintf(qbuf
, "There are %ld gold pieces here; eat them?",
3061 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
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
) {
3072 ? (otmp
->otyp
== CORPSE
3073 && (corpsecheck
== 1 || tinnable(otmp
)))
3074 : feeding
? (otmp
->oclass
!= COIN_CLASS
&& is_edible(otmp
))
3075 : otmp
->oclass
== FOOD_CLASS
) {
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')
3098 return (struct obj
*) 0;
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
,
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;
3116 /* Side effects of vomiting */
3117 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
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.");
3126 make_sick(0L, (char *) 0, TRUE
, SICK_VOMITABLE
);
3128 multi_reason
= "vomiting";
3129 nomovemsg
= You_can_move_again
;
3133 eaten_stat(base
, 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
) {
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 */
3155 consume_oeaten(obj
, 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.
3186 /* bit shift to divide the remaining amount of food */
3187 obj
->oeaten
>>= amt
;
3189 /* simple decrement; value is negative so we actually add it */
3190 if ((int) obj
->oeaten
> -amt
)
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 */
3207 maybe_finished_meal(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
) {
3214 occupation
= 0; /* for do_reset_eat */
3215 (void) eatfood(); /* calls done_eating() to use up
3216 context.victual.piece */
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. :-] */
3234 if (occupation
!= opentin
)
3236 otin
= context
.tin
.tin
;
3237 /* make sure hero still has access to tin */
3239 && (!obj_here(otin
, u
.ux
, u
.uy
) || !can_reach_floor(TRUE
)))
3241 /* unknown tin is assumed to be helpful */
3244 /* known tin is helpful if it will stop life-threatening problem */
3245 mndx
= otin
->corpsenm
;
3247 /* note: not used; hunger code bypasses stop_occupation() when eating */
3249 return (boolean
) (mndx
!= NON_PM
|| otin
->spe
== 1);
3250 /* flesh from lizards and acidic critters stops petrification */
3252 return (boolean
) (mndx
>= LOW_PM
3253 && (mndx
== PM_LIZARD
|| acidic(&mons
[mndx
])));
3254 /* no tins can cure these (yet?) */