1 /* NetHack 3.6 eat.c $NHDT-Date: 1454715969 2016/02/05 23:46:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_PTR
int NDECL(eatmdone
);
8 STATIC_PTR
int NDECL(eatfood
);
9 STATIC_PTR
void FDECL(costly_tin
, (int));
10 STATIC_PTR
int NDECL(opentin
);
11 STATIC_PTR
int NDECL(unfaint
);
13 STATIC_DCL
const char *FDECL(food_xname
, (struct obj
*, BOOLEAN_P
));
14 STATIC_DCL
void FDECL(choke
, (struct obj
*));
15 STATIC_DCL
void NDECL(recalc_wt
);
16 STATIC_DCL
struct obj
*FDECL(touchfood
, (struct obj
*));
17 STATIC_DCL
void NDECL(do_reset_eat
);
18 STATIC_DCL
void FDECL(done_eating
, (BOOLEAN_P
));
19 STATIC_DCL
void FDECL(cprefx
, (int));
20 STATIC_DCL
int FDECL(intrinsic_possible
, (int, struct permonst
*));
21 STATIC_DCL
void FDECL(givit
, (int, struct permonst
*));
22 STATIC_DCL
void FDECL(cpostfx
, (int));
23 STATIC_DCL
void FDECL(consume_tin
, (const char *));
24 STATIC_DCL
void FDECL(start_tin
, (struct obj
*));
25 STATIC_DCL
int FDECL(eatcorpse
, (struct obj
*));
26 STATIC_DCL
void FDECL(start_eating
, (struct obj
*));
27 STATIC_DCL
void FDECL(fprefx
, (struct obj
*));
28 STATIC_DCL
void FDECL(fpostfx
, (struct obj
*));
29 STATIC_DCL
int NDECL(bite
);
30 STATIC_DCL
int FDECL(edibility_prompts
, (struct obj
*));
31 STATIC_DCL
int FDECL(rottenfood
, (struct obj
*));
32 STATIC_DCL
void NDECL(eatspecial
);
33 STATIC_DCL
int FDECL(bounded_increase
, (int, int, int));
34 STATIC_DCL
void FDECL(accessory_has_effect
, (struct obj
*));
35 STATIC_DCL
void FDECL(eataccessory
, (struct obj
*));
36 STATIC_DCL
const char *FDECL(foodword
, (struct obj
*));
37 STATIC_DCL
int FDECL(tin_variety
, (struct obj
*, BOOLEAN_P
));
38 STATIC_DCL boolean
FDECL(maybe_cannibal
, (int, BOOLEAN_P
));
42 /* also used to see if you're allowed to eat cats and dogs */
43 #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
45 /* monster types that cause hero to be turned into stone if eaten */
46 #define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA])
48 /* Rider corpses are treated as non-rotting so that attempting to eat one
49 will be sure to reach the stage of eating where that meal is fatal */
50 #define nonrotting_corpse(mnum) \
51 ((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum]))
53 /* non-rotting non-corpses; unlike lizard corpses, these items will behave
54 as if rotten if they are cursed (fortune cookies handled elsewhere) */
55 #define nonrotting_food(otyp) \
56 ((otyp) == LEMBAS_WAFER || (otyp) == CRAM_RATION)
58 STATIC_OVL NEARDATA
const char comestibles
[] = { FOOD_CLASS
, 0 };
59 STATIC_OVL NEARDATA
const char offerfodder
[] = { FOOD_CLASS
, AMULET_CLASS
,
62 /* Gold must come first for getobj(). */
63 STATIC_OVL NEARDATA
const char allobj
[] = {
64 COIN_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
, POTION_CLASS
,
65 SCROLL_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
66 FOOD_CLASS
, TOOL_CLASS
, GEM_CLASS
, ROCK_CLASS
,
67 BALL_CLASS
, CHAIN_CLASS
, SPBOOK_CLASS
, 0
70 STATIC_OVL boolean force_save_hs
= FALSE
;
72 /* see hunger states in hack.h - texts used on bottom line */
73 const char *hu_stat
[] = { "Satiated", " ", "Hungry ", "Weak ",
74 "Fainting", "Fainted ", "Starved " };
77 * Decide whether a particular object can be eaten by the possibly
78 * polymorphed character. Not used for monster checks.
82 register struct obj
*obj
;
84 /* protect invocation tools but not Rider corpses (handled elsewhere)*/
85 /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
86 if (objects
[obj
->otyp
].oc_unique
)
88 /* above also prevents the Amulet from being eaten, so we must never
89 allow fake amulets to be eaten either [which is already the case] */
91 if (metallivorous(youmonst
.data
) && is_metallic(obj
)
92 && (youmonst
.data
!= &mons
[PM_RUST_MONSTER
] || is_rustprone(obj
)))
95 if (u
.umonnum
== PM_GELATINOUS_CUBE
&& is_organic(obj
)
96 /* [g.cubes can eat containers and retain all contents
97 as engulfed items, but poly'd player can't do that] */
98 && !Has_contents(obj
))
101 /* return (boolean) !!index(comestibles, obj->oclass); */
102 return (boolean
) (obj
->oclass
== FOOD_CLASS
);
112 /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */
113 static const struct {
114 const char *txt
; /* description */
115 int nut
; /* nutrition */
116 Bitfield(fodder
, 1); /* stocked by health food shops */
117 Bitfield(greasy
, 1); /* causes slippery fingers */
118 } tintxts
[] = { { "rotten", -50, 0, 0 }, /* ROTTEN_TIN = 0 */
119 { "homemade", 50, 1, 0 }, /* HOMEMADE_TIN = 1 */
120 { "soup made from", 20, 1, 0 },
121 { "french fried", 40, 0, 1 },
122 { "pickled", 40, 1, 0 },
123 { "boiled", 50, 1, 0 },
124 { "smoked", 50, 1, 0 },
125 { "dried", 55, 1, 0 },
126 { "deep fried", 60, 0, 1 },
127 { "szechuan", 70, 1, 0 },
128 { "broiled", 80, 0, 0 },
129 { "stir fried", 80, 0, 1 },
130 { "sauteed", 95, 0, 0 },
131 { "candied", 100, 1, 0 },
132 { "pureed", 500, 1, 0 },
134 #define TTSZ SIZE(tintxts)
136 static char *eatmbuf
= 0; /* set by cpostfx() */
138 /* called after mimicing is over */
142 /* release `eatmbuf' */
144 if (nomovemsg
== eatmbuf
)
146 free((genericptr_t
) eatmbuf
), eatmbuf
= 0;
149 if (youmonst
.m_ap_type
) {
150 youmonst
.m_ap_type
= M_AP_NOTHING
;
156 /* called when hallucination is toggled */
160 const char *altmsg
= 0;
161 int altapp
= 0; /* lint suppression */
163 if (!eatmbuf
|| nomovemsg
!= eatmbuf
)
166 if (is_obj_mappear(&youmonst
,ORANGE
) && !Hallucination
) {
167 /* revert from hallucinatory to "normal" mimicking */
168 altmsg
= "You now prefer mimicking yourself.";
170 } else if (is_obj_mappear(&youmonst
,GOLD_PIECE
) && Hallucination
) {
171 /* won't happen; anything which might make immobilized
172 hero begin hallucinating (black light attack, theft
173 of Grayswandir) will terminate the mimicry first */
174 altmsg
= "Your rind escaped intact.";
179 /* replace end-of-mimicking message */
180 if (strlen(altmsg
) > strlen(eatmbuf
)) {
181 free((genericptr_t
) eatmbuf
);
182 eatmbuf
= (char *) alloc(strlen(altmsg
) + 1);
184 nomovemsg
= strcpy(eatmbuf
, altmsg
);
185 /* update current image */
186 youmonst
.mappearance
= altapp
;
191 /* ``[the(] singular(food, xname) [)]'' */
192 STATIC_OVL
const char *
193 food_xname(food
, the_pfx
)
199 if (food
->otyp
== CORPSE
) {
200 result
= corpse_xname(food
, (const char *) 0,
201 CXN_SINGULAR
| (the_pfx
? CXN_PFX_THE
: 0));
202 /* not strictly needed since pname values are capitalized
203 and the() is a no-op for them */
204 if (type_is_pname(&mons
[food
->corpsenm
]))
207 /* the ordinary case */
208 result
= singular(food
, xname
);
211 result
= the(result
);
215 /* Created by GAN 01/28/87
216 * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
217 * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk.
218 * 11/10/89: if hard, rarely vomit anyway, for slim chance.
220 * To a full belly all food is bad. (It.)
226 /* only happens if you were satiated */
227 if (u
.uhs
!= SATIATED
) {
228 if (!food
|| food
->otyp
!= AMULET_OF_STRANGULATION
)
230 } else if (Role_if(PM_KNIGHT
) && u
.ualign
.type
== A_LAWFUL
) {
231 adjalign(-1); /* gluttony is unchivalrous */
232 You_feel("like a glutton!");
235 exercise(A_CON
, FALSE
);
237 if (Breathless
|| (!Strangled
&& !rn2(20))) {
238 /* choking by eating AoS doesn't involve stuffing yourself */
239 if (food
&& food
->otyp
== AMULET_OF_STRANGULATION
) {
240 You("choke, but recover your composure.");
243 You("stuff yourself and then vomit voluminously.");
244 morehungry(1000); /* you just got *very* sick! */
247 killer
.format
= KILLED_BY_AN
;
249 * Note all "killer"s below read "Choked on %s" on the
250 * high score list & tombstone. So plan accordingly.
253 You("choke over your %s.", foodword(food
));
254 if (food
->oclass
== COIN_CLASS
) {
255 Strcpy(killer
.name
, "very rich meal");
257 killer
.format
= KILLED_BY
;
258 Strcpy(killer
.name
, killer_xname(food
));
261 You("choke over it.");
262 Strcpy(killer
.name
, "quick snack");
269 /* modify object wt. depending on time spent consuming it */
273 struct obj
*piece
= context
.victual
.piece
;
275 impossible("recalc_wt without piece");
278 debugpline1("Old weight = %d", piece
->owt
);
279 debugpline2("Used time = %d, Req'd time = %d", context
.victual
.usedtime
,
280 context
.victual
.reqtime
);
281 piece
->owt
= weight(piece
);
282 debugpline1("New weight = %d", piece
->owt
);
285 /* called when eating interrupted by an event */
289 /* we only set a flag here - the actual reset process is done after
290 * the round is spent eating.
292 if (context
.victual
.eating
&& !context
.victual
.doreset
) {
293 debugpline0("reset_eat...");
294 context
.victual
.doreset
= TRUE
;
299 STATIC_OVL
struct obj
*
303 if (otmp
->quan
> 1L) {
305 (void) splitobj(otmp
, otmp
->quan
- 1L);
307 otmp
= splitobj(otmp
, 1L);
308 debugpline0("split object,");
312 costly_alteration(otmp
, COST_BITE
);
313 otmp
->oeaten
= (otmp
->otyp
== CORPSE
) ? mons
[otmp
->corpsenm
].cnutrit
314 : otmp
->globby
? otmp
->owt
315 : (unsigned) objects
[otmp
->otyp
].oc_nutrition
;
320 if (inv_cnt(FALSE
) >= 52) {
321 sellobj_state(SELL_DONTSELL
);
323 sellobj_state(SELL_NORMAL
);
325 otmp
->nomerge
= 1; /* used to prevent merge */
333 /* When food decays, in the middle of your meal, we don't want to dereference
334 * any dangling pointers, so set it to null (which should still trigger
335 * do_reset_eat() at the beginning of eatfood()) and check for null pointers
342 if (obj
== context
.victual
.piece
) {
343 context
.victual
.piece
= (struct obj
*) 0;
344 context
.victual
.o_id
= 0;
347 obj_stop_timers(obj
);
350 /* renaming an object used to result in it having a different address,
351 so the sequence start eating/opening, get interrupted, name the food,
352 resume eating/opening would restart from scratch */
354 food_substitution(old_obj
, new_obj
)
355 struct obj
*old_obj
, *new_obj
;
357 if (old_obj
== context
.victual
.piece
) {
358 context
.victual
.piece
= new_obj
;
359 context
.victual
.o_id
= new_obj
->o_id
;
361 if (old_obj
== context
.tin
.tin
) {
362 context
.tin
.tin
= new_obj
;
363 context
.tin
.o_id
= new_obj
->o_id
;
370 debugpline0("do_reset_eat...");
371 if (context
.victual
.piece
) {
372 context
.victual
.o_id
= 0;
373 context
.victual
.piece
= touchfood(context
.victual
.piece
);
374 if (context
.victual
.piece
)
375 context
.victual
.o_id
= context
.victual
.piece
->o_id
;
378 context
.victual
.fullwarn
= context
.victual
.eating
=
379 context
.victual
.doreset
= FALSE
;
380 /* Do not set canchoke to FALSE; if we continue eating the same object
381 * we need to know if canchoke was set when they started eating it the
382 * previous time. And if we don't continue eating the same object
383 * canchoke always gets recalculated anyway.
389 /* called each move during eating process */
393 if (!context
.victual
.piece
394 || (!carried(context
.victual
.piece
)
395 && !obj_here(context
.victual
.piece
, u
.ux
, u
.uy
))) {
396 /* maybe it was stolen? */
400 if (!context
.victual
.eating
)
403 if (++context
.victual
.usedtime
<= context
.victual
.reqtime
) {
406 return 1; /* still busy */
417 struct obj
*piece
= context
.victual
.piece
;
419 piece
->in_use
= TRUE
;
420 occupation
= 0; /* do this early, so newuhs() knows we're done */
427 You("finish eating %s.", food_xname(piece
, TRUE
));
429 if (piece
->otyp
== CORPSE
|| piece
->globby
)
430 cpostfx(piece
->corpsenm
);
438 context
.victual
.piece
= (struct obj
*) 0;
439 context
.victual
.o_id
= 0;
440 context
.victual
.fullwarn
= context
.victual
.eating
=
441 context
.victual
.doreset
= FALSE
;
450 u
.uconduct
.unvegan
++;
452 violated_vegetarian();
455 /* handle side-effects of mind flayer's tentacle attack */
457 eat_brains(magr
, mdef
, visflag
, dmg_p
)
458 struct monst
*magr
, *mdef
;
460 int *dmg_p
; /* for dishing out extra damage in lieu of Int loss */
462 struct permonst
*pd
= mdef
->data
;
463 boolean give_nutrit
= FALSE
;
464 int result
= MM_HIT
, xtra_dmg
= rnd(10);
466 if (noncorporeal(pd
)) {
468 pline("%s brain is unharmed.",
469 (mdef
== &youmonst
) ? "Your" : s_suffix(Monnam(mdef
)));
470 return MM_MISS
; /* side-effects can't occur */
471 } else if (magr
== &youmonst
) {
472 You("eat %s brain!", s_suffix(mon_nam(mdef
)));
473 } else if (mdef
== &youmonst
) {
474 Your("brain is eaten!");
475 } else { /* monster against monster */
477 pline("%s brain is eaten!", s_suffix(Monnam(mdef
)));
480 if (flesh_petrifies(pd
)) {
481 /* mind flayer has attempted to eat the brains of a petrification
482 inducing critter (most likely Medusa; attacking a cockatrice via
483 tentacle-touch should have been caught before reaching this far) */
484 if (magr
== &youmonst
) {
485 if (!Stone_resistance
&& !Stoned
)
486 make_stoned(5L, (char *) 0, KILLED_BY_AN
, pd
->mname
);
488 /* no need to check for poly_when_stoned or Stone_resistance;
489 mind flayers don't have those capabilities */
491 pline("%s turns to stone!", Monnam(magr
));
494 /* life-saved; don't continue eating the brains */
497 if (magr
->mtame
&& !visflag
)
498 /* parallels mhitm.c's brief_feeling */
499 You("have a sad thought for a moment, then it passes.");
505 if (magr
== &youmonst
) {
507 * player mind flayer is eating something's brain
510 if (mindless(pd
)) { /* (cannibalism not possible here) */
511 pline("%s doesn't notice.", Monnam(mdef
));
512 /* all done; no extra harm inflicted upon target */
514 } else if (is_rider(pd
)) {
515 pline("Ingesting that is fatal.");
516 Sprintf(killer
.name
, "unwisely ate the brain of %s", pd
->mname
);
517 killer
.format
= NO_KILLER_PREFIX
;
519 /* life-saving needed to reach here */
520 exercise(A_WIS
, FALSE
);
521 *dmg_p
+= xtra_dmg
; /* Rider takes extra damage */
523 morehungry(-rnd(30)); /* cannot choke */
524 if (ABASE(A_INT
) < AMAX(A_INT
)) {
525 /* recover lost Int; won't increase current max */
526 ABASE(A_INT
) += rnd(4);
527 if (ABASE(A_INT
) > AMAX(A_INT
))
528 ABASE(A_INT
) = AMAX(A_INT
);
531 exercise(A_WIS
, TRUE
);
534 /* targetting another mind flayer or your own underlying species
536 (void) maybe_cannibal(monsndx(pd
), TRUE
);
538 } else if (mdef
== &youmonst
) {
540 * monster mind flayer is eating hero's brain
542 /* no such thing as mindless players */
543 if (ABASE(A_INT
) <= ATTRMIN(A_INT
)) {
544 static NEARDATA
const char brainlessness
[] = "brainlessness";
547 Strcpy(killer
.name
, brainlessness
);
548 killer
.format
= KILLED_BY
;
550 /* amulet of life saving has now been used up */
551 pline("Unfortunately your brain is still gone.");
552 /* sanity check against adding other forms of life-saving */
553 u
.uprops
[LIFESAVED
].extrinsic
=
554 u
.uprops
[LIFESAVED
].intrinsic
= 0L;
556 Your("last thought fades away.");
558 Strcpy(killer
.name
, brainlessness
);
559 killer
.format
= KILLED_BY
;
561 /* can only get here when in wizard or explore mode and user has
562 explicitly chosen not to die; arbitrarily boost intelligence */
563 ABASE(A_INT
) = ATTRMIN(A_INT
) + 2;
564 You_feel("like a scarecrow.");
566 give_nutrit
= TRUE
; /* in case a conflicted pet is doing this */
567 exercise(A_WIS
, FALSE
);
568 /* caller handles Int and memory loss */
572 * monster mind flayer is eating another monster's brain
576 pline("%s doesn't notice.", Monnam(mdef
));
578 } else if (is_rider(pd
)) {
581 result
= MM_AGR_DIED
;
582 /* Rider takes extra damage regardless of whether attacker dies */
587 if (*dmg_p
>= mdef
->mhp
&& visflag
)
588 pline("%s last thought fades away...",
589 s_suffix(Monnam(mdef
)));
593 if (give_nutrit
&& magr
->mtame
&& !magr
->isminion
) {
594 EDOG(magr
)->hungrytime
+= rnd(60);
601 /* eating a corpse or egg of one's own species is usually naughty */
603 maybe_cannibal(pm
, allowmsg
)
607 static NEARDATA
long ate_brains
= 0L;
608 struct permonst
*fptr
= &mons
[pm
]; /* food type */
610 /* when poly'd into a mind flayer, multiple tentacle hits in one
611 turn cause multiple digestion checks to occur; avoid giving
612 multiple luck penalties for the same attack */
613 if (moves
== ate_brains
)
615 ate_brains
= moves
; /* ate_anything, not just brains... */
617 if (!CANNIBAL_ALLOWED()
618 /* non-cannibalistic heroes shouldn't eat own species ever
619 and also shouldn't eat current species when polymorphed
620 (even if having the form of something which doesn't care
621 about cannibalism--hero's innate traits aren't altered) */
622 && (your_race(fptr
) || (Upolyd
&& same_race(youmonst
.data
, fptr
)))) {
624 if (Upolyd
&& your_race(fptr
))
625 You("have a bad feeling deep inside.");
626 You("cannibal! You will regret this!");
628 HAggravate_monster
|= FROMOUTSIDE
;
629 change_luck(-rn1(4, 2)); /* -5..-2 */
639 (void) maybe_cannibal(pm
, TRUE
);
640 if (flesh_petrifies(&mons
[pm
])) {
641 if (!Stone_resistance
642 && !(poly_when_stoned(youmonst
.data
)
643 && polymon(PM_STONE_GOLEM
))) {
644 Sprintf(killer
.name
, "tasting %s meat", mons
[pm
].mname
);
645 killer
.format
= KILLED_BY
;
646 You("turn to stone.");
648 if (context
.victual
.piece
)
649 context
.victual
.eating
= FALSE
;
650 return; /* lifesaved */
661 /* cannibals are allowed to eat domestic animals without penalty */
662 if (!CANNIBAL_ALLOWED()) {
663 You_feel("that eating the %s was a bad idea.", mons
[pm
].mname
);
664 HAggravate_monster
|= FROMOUTSIDE
;
674 pline("Eating that is instantly fatal.");
675 Sprintf(killer
.name
, "unwisely ate the body of %s", mons
[pm
].mname
);
676 killer
.format
= NO_KILLER_PREFIX
;
678 /* life-saving needed to reach here */
679 exercise(A_WIS
, FALSE
);
680 /* It so happens that since we know these monsters */
681 /* cannot appear in tins, context.victual.piece will always */
682 /* be what we want, which is not generally true. */
683 if (revive_corpse(context
.victual
.piece
)) {
684 context
.victual
.piece
= (struct obj
*) 0;
685 context
.victual
.o_id
= 0;
690 if (!Slimed
&& !Unchanging
&& !slimeproof(youmonst
.data
)) {
691 You("don't feel very well.");
692 make_slimed(10L, (char *) 0);
693 delayed_killer(SLIMED
, KILLED_BY_AN
, "");
697 if (acidic(&mons
[pm
]) && Stoned
)
709 Sprintf(buf
, "What a pity--you just ruined a future piece of %sart!",
710 ACURR(A_CHA
) > 15 ? "fine " : "");
712 Strcpy(buf
, "You feel limber!");
713 make_stoned(0L, buf
, 0, (char *) 0);
717 * If you add an intrinsic that can be gotten by eating a monster, add it
718 * to intrinsic_possible() and givit(). (It must already be in prop.h to
719 * be an intrinsic property.)
720 * It would be very easy to make the intrinsics not try to give you one
721 * that you already had by checking to see if you have it in
722 * intrinsic_possible() instead of givit(), but we're not that nice.
725 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
727 intrinsic_possible(type
, ptr
)
729 register struct permonst
*ptr
;
734 #define ifdebugresist(Msg) \
740 #define ifdebugresist(Msg) /*empty*/
744 res
= (ptr
->mconveys
& MR_FIRE
) != 0;
745 ifdebugresist("can get fire resistance");
748 res
= (ptr
->mconveys
& MR_SLEEP
) != 0;
749 ifdebugresist("can get sleep resistance");
752 res
= (ptr
->mconveys
& MR_COLD
) != 0;
753 ifdebugresist("can get cold resistance");
756 res
= (ptr
->mconveys
& MR_DISINT
) != 0;
757 ifdebugresist("can get disintegration resistance");
759 case SHOCK_RES
: /* shock (electricity) resistance */
760 res
= (ptr
->mconveys
& MR_ELEC
) != 0;
761 ifdebugresist("can get shock resistance");
764 res
= (ptr
->mconveys
& MR_POISON
) != 0;
765 ifdebugresist("can get poison resistance");
768 res
= can_teleport(ptr
);
769 ifdebugresist("can get teleport");
771 case TELEPORT_CONTROL
:
772 res
= control_teleport(ptr
);
773 ifdebugresist("can get teleport control");
776 res
= telepathic(ptr
);
777 ifdebugresist("can get telepathy");
787 /* givit() tries to give you an intrinsic based on the monster's level
788 * and what type of intrinsic it is trying to give you.
793 register struct permonst
*ptr
;
797 debugpline1("Attempting to give intrinsic %d", type
);
798 /* some intrinsics are easier to get than others */
801 if ((ptr
== &mons
[PM_KILLER_BEE
] || ptr
== &mons
[PM_SCORPION
])
810 case TELEPORT_CONTROL
:
821 if (ptr
->mlevel
<= rn2(chance
))
822 return; /* failed die roll */
826 debugpline0("Trying to give fire resistance");
827 if (!(HFire_resistance
& FROMOUTSIDE
)) {
828 You(Hallucination
? "be chillin'." : "feel a momentary chill.");
829 HFire_resistance
|= FROMOUTSIDE
;
833 debugpline0("Trying to give sleep resistance");
834 if (!(HSleep_resistance
& FROMOUTSIDE
)) {
835 You_feel("wide awake.");
836 HSleep_resistance
|= FROMOUTSIDE
;
840 debugpline0("Trying to give cold resistance");
841 if (!(HCold_resistance
& FROMOUTSIDE
)) {
842 You_feel("full of hot air.");
843 HCold_resistance
|= FROMOUTSIDE
;
847 debugpline0("Trying to give disintegration resistance");
848 if (!(HDisint_resistance
& FROMOUTSIDE
)) {
849 You_feel(Hallucination
? "totally together, man." : "very firm.");
850 HDisint_resistance
|= FROMOUTSIDE
;
853 case SHOCK_RES
: /* shock (electricity) resistance */
854 debugpline0("Trying to give shock resistance");
855 if (!(HShock_resistance
& FROMOUTSIDE
)) {
857 You_feel("grounded in reality.");
859 Your("health currently feels amplified!");
860 HShock_resistance
|= FROMOUTSIDE
;
864 debugpline0("Trying to give poison resistance");
865 if (!(HPoison_resistance
& FROMOUTSIDE
)) {
866 You_feel(Poison_resistance
? "especially healthy." : "healthy.");
867 HPoison_resistance
|= FROMOUTSIDE
;
871 debugpline0("Trying to give teleport");
872 if (!(HTeleportation
& FROMOUTSIDE
)) {
873 You_feel(Hallucination
? "diffuse." : "very jumpy.");
874 HTeleportation
|= FROMOUTSIDE
;
877 case TELEPORT_CONTROL
:
878 debugpline0("Trying to give teleport control");
879 if (!(HTeleport_control
& FROMOUTSIDE
)) {
880 You_feel(Hallucination
? "centered in your personal space."
881 : "in control of yourself.");
882 HTeleport_control
|= FROMOUTSIDE
;
886 debugpline0("Trying to give telepathy");
887 if (!(HTelepat
& FROMOUTSIDE
)) {
888 You_feel(Hallucination
? "in touch with the cosmos."
889 : "a strange mental acuity.");
890 HTelepat
|= FROMOUTSIDE
;
891 /* If blind, make sure monsters show up. */
897 debugpline0("Tried to give an impossible intrinsic");
902 /* called after completely consuming a corpse */
907 register int tmp
= 0;
908 int catch_lycanthropy
= NON_PM
;
910 /* in case `afternmv' didn't get called for previously mimicking
911 gold, clean up now to avoid `eatmbuf' memory leak */
917 /* MRKR: "eye of newt" may give small magical energy boost */
918 if (rn2(3) || 3 * u
.uen
<= 2 * u
.uenmax
) {
921 if (u
.uen
> u
.uenmax
) {
926 if (old_uen
!= u
.uen
) {
927 You_feel("a mild buzz.");
935 case PM_HUMAN_WERERAT
:
936 catch_lycanthropy
= PM_WERERAT
;
938 case PM_HUMAN_WEREJACKAL
:
939 catch_lycanthropy
= PM_WEREJACKAL
;
941 case PM_HUMAN_WEREWOLF
:
942 catch_lycanthropy
= PM_WEREWOLF
;
953 set_itimeout(&HInvis
, (long) rn1(100, 50));
954 if (!Blind
&& !BInvis
)
955 self_invis_message();
957 if (!(HInvis
& INTRINSIC
))
959 HInvis
|= FROMOUTSIDE
;
960 HSee_invisible
|= FROMOUTSIDE
;
964 case PM_YELLOW_LIGHT
:
966 make_stunned((HStun
& TIMEOUT
) + 30L, FALSE
);
969 make_stunned((HStun
& TIMEOUT
) + 30L, FALSE
);
979 if (youmonst
.data
->mlet
!= S_MIMIC
&& !Unchanging
) {
982 u
.uconduct
.polyselfs
++; /* you're changing form */
983 You_cant("resist the temptation to mimic %s.",
984 Hallucination
? "an orange" : "a pile of gold");
985 /* A pile of gold can't ride. */
987 dismount_steed(DISMOUNT_FELL
);
989 multi_reason
= "pretending to be a pile of gold";
992 ? "You suddenly dread being peeled and mimic %s again!"
993 : "You now prefer mimicking %s again.",
994 an(Upolyd
? youmonst
.data
->mname
: urace
.noun
));
995 eatmbuf
= dupstr(buf
);
998 /* ??? what if this was set before? */
999 youmonst
.m_ap_type
= M_AP_OBJECT
;
1000 youmonst
.mappearance
= Hallucination
? ORANGE
: GOLD_PIECE
;
1003 /* make gold symbol show up now */
1004 display_nhwindow(WIN_MAP
, TRUE
);
1007 case PM_QUANTUM_MECHANIC
:
1008 Your("velocity suddenly seems very uncertain!");
1009 if (HFast
& INTRINSIC
) {
1010 HFast
&= ~INTRINSIC
;
1011 You("seem slower.");
1013 HFast
|= FROMOUTSIDE
;
1014 You("seem faster.");
1018 if ((HStun
& TIMEOUT
) > 2)
1019 make_stunned(2L, FALSE
);
1020 if ((HConfusion
& TIMEOUT
) > 2)
1021 make_confused(2L, FALSE
);
1024 case PM_DOPPELGANGER
:
1025 case PM_SANDESTIN
: /* moot--they don't leave corpses */
1027 You_feel("momentarily different."); /* same as poly trap */
1029 You_feel("a change coming over you.");
1033 case PM_DISENCHANTER
:
1034 /* picks an intrinsic at random and removes it; there's
1035 no feedback if hero already lacks the chosen ability */
1036 debugpline0("using attrcurse to strip an intrinsic");
1039 case PM_MIND_FLAYER
:
1040 case PM_MASTER_MIND_FLAYER
:
1041 if (ABASE(A_INT
) < ATTRMAX(A_INT
)) {
1043 pline("Yum! That was real brain food!");
1044 (void) adjattrib(A_INT
, 1, FALSE
);
1045 break; /* don't give them telepathy, too */
1048 pline("For some reason, that tasted bland.");
1052 struct permonst
*ptr
= &mons
[pm
];
1053 boolean conveys_STR
= is_giant(ptr
);
1056 if (dmgtype(ptr
, AD_STUN
) || dmgtype(ptr
, AD_HALU
)
1057 || pm
== PM_VIOLET_FUNGUS
) {
1058 pline("Oh wow! Great stuff!");
1059 (void) make_hallucinated((HHallucination
& TIMEOUT
) + 200L, FALSE
,
1063 /* Check the monster for all of the intrinsics. If this
1064 * monster can give more than one, pick one to try to give
1065 * from among all it can give.
1067 * Strength from giants is now treated like an intrinsic
1068 * rather than being given unconditionally.
1070 count
= 0; /* number of possible intrinsics */
1071 tmp
= 0; /* which one we will try to give */
1074 tmp
= -1; /* use -1 as fake prop index for STR */
1075 debugpline1("\"Intrinsic\" strength, %d", tmp
);
1077 for (i
= 1; i
<= LAST_PROP
; i
++) {
1078 if (!intrinsic_possible(i
, ptr
))
1081 /* a 1 in count chance of replacing the old choice
1082 with this one, and a count-1 in count chance
1083 of keeping the old choice (note that 1 in 1 and
1084 0 in 1 are what we want for the first candidate) */
1086 debugpline2("Intrinsic %d replacing %d", i
, tmp
);
1090 /* if strength is the only candidate, give it 50% chance */
1091 if (conveys_STR
&& count
== 1 && !rn2(2))
1093 /* if something was chosen, give it now (givit() might fail) */
1095 gainstr((struct obj
*) 0, 0, TRUE
);
1099 } /* default case */
1102 if (catch_lycanthropy
>= LOW_PM
) {
1103 set_ulycn(catch_lycanthropy
);
1104 retouch_equipment(2);
1110 violated_vegetarian()
1112 u
.uconduct
.unvegetarian
++;
1113 if (Role_if(PM_MONK
)) {
1114 You_feel("guilty.");
1120 /* common code to check and possibly charge for 1 context.tin.tin,
1121 * will split() context.tin.tin if necessary */
1123 costly_tin(alter_type
)
1124 int alter_type
; /* COST_xxx */
1126 struct obj
*tin
= context
.tin
.tin
;
1128 if (carried(tin
) ? tin
->unpaid
1129 : (costly_spot(tin
->ox
, tin
->oy
) && !tin
->no_charge
)) {
1130 if (tin
->quan
> 1L) {
1131 tin
= context
.tin
.tin
= splitobj(tin
, 1L);
1132 context
.tin
.o_id
= tin
->o_id
;
1134 costly_alteration(tin
, alter_type
);
1139 tin_variety_txt(s
, tinvariety
)
1145 if (s
&& tinvariety
) {
1147 for (k
= 0; k
< TTSZ
- 1; ++k
) {
1148 l
= (int) strlen(tintxts
[k
].txt
);
1149 if (!strncmpi(s
, tintxts
[k
].txt
, l
) && ((int) strlen(s
) > l
)
1160 * This assumes that buf already contains the word "tin",
1161 * as is the case with caller xname().
1164 tin_details(obj
, mnum
, buf
)
1170 int r
= tin_variety(obj
, TRUE
);
1173 if (r
== SPINACH_TIN
)
1174 Strcat(buf
, " of spinach");
1175 else if (mnum
== NON_PM
)
1176 Strcpy(buf
, "empty tin");
1178 if ((obj
->cknown
|| iflags
.override_ID
) && obj
->spe
< 0) {
1179 if (r
== ROTTEN_TIN
|| r
== HOMEMADE_TIN
) {
1180 /* put these before the word tin */
1181 Sprintf(buf2
, "%s %s of ", tintxts
[r
].txt
, buf
);
1184 Sprintf(eos(buf
), " of %s ", tintxts
[r
].txt
);
1187 Strcpy(eos(buf
), " of ");
1189 if (vegetarian(&mons
[mnum
]))
1190 Sprintf(eos(buf
), "%s", mons
[mnum
].mname
);
1192 Sprintf(eos(buf
), "%s meat", mons
[mnum
].mname
);
1198 set_tin_variety(obj
, forcetype
)
1204 if (forcetype
== SPINACH_TIN
1205 || (forcetype
== HEALTHY_TIN
1206 && (obj
->corpsenm
== NON_PM
/* empty or already spinach */
1207 || !vegetarian(&mons
[obj
->corpsenm
])))) { /* replace meat */
1208 obj
->corpsenm
= NON_PM
; /* not based on any monster */
1209 obj
->spe
= 1; /* spinach */
1211 } else if (forcetype
== HEALTHY_TIN
) {
1212 r
= tin_variety(obj
, FALSE
);
1213 if (r
< 0 || r
>= TTSZ
)
1214 r
= ROTTEN_TIN
; /* shouldn't happen */
1215 while ((r
== ROTTEN_TIN
&& !obj
->cursed
) || !tintxts
[r
].fodder
)
1217 } else if (forcetype
>= 0 && forcetype
< TTSZ
- 1) {
1219 } else { /* RANDOM_TIN */
1220 r
= rn2(TTSZ
- 1); /* take your pick */
1221 if (r
== ROTTEN_TIN
&& nonrotting_corpse(obj
->corpsenm
))
1222 r
= HOMEMADE_TIN
; /* lizards don't rot */
1224 obj
->spe
= -(r
+ 1); /* offset by 1 to allow index 0 */
1228 tin_variety(obj
, disp
)
1230 boolean disp
; /* we're just displaying so leave things alone */
1234 if (obj
->spe
== 1) {
1236 } else if (obj
->cursed
) {
1237 r
= ROTTEN_TIN
; /* always rotten if cursed */
1238 } else if (obj
->spe
< 0) {
1240 --r
; /* get rid of the offset */
1244 if (!disp
&& r
== HOMEMADE_TIN
&& !obj
->blessed
&& !rn2(7))
1245 r
= ROTTEN_TIN
; /* some homemade tins go bad */
1247 if (r
== ROTTEN_TIN
&& nonrotting_corpse(obj
->corpsenm
))
1248 r
= HOMEMADE_TIN
; /* lizards don't rot */
1258 struct obj
*tin
= context
.tin
.tin
;
1260 r
= tin_variety(tin
, FALSE
);
1261 if (tin
->otrapped
|| (tin
->cursed
&& r
!= HOMEMADE_TIN
&& !rn2(8))) {
1262 b_trapped("tin", 0);
1263 costly_tin(COST_DSTROY
);
1267 pline1(mesg
); /* "You succeed in opening the tin." */
1269 if (r
!= SPINACH_TIN
) {
1270 mnum
= tin
->corpsenm
;
1271 if (mnum
== NON_PM
) {
1272 pline("It turns out to be empty.");
1273 tin
->dknown
= tin
->known
= 1;
1274 costly_tin(COST_OPEN
);
1278 which
= 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1279 if ((mnum
== PM_COCKATRICE
|| mnum
== PM_CHICKATRICE
)
1280 && (Stone_resistance
|| Hallucination
)) {
1282 which
= 1; /* suppress pluralization */
1283 } else if (Hallucination
) {
1284 what
= rndmonnam(NULL
);
1286 what
= mons
[mnum
].mname
;
1287 if (the_unique_pm(&mons
[mnum
]))
1289 else if (type_is_pname(&mons
[mnum
]))
1293 what
= makeplural(what
);
1294 else if (which
== 2)
1297 pline("It smells like %s.", what
);
1298 if (yn("Eat it?") == 'n') {
1300 You("discard the open tin.");
1302 tin
->dknown
= tin
->known
= 1;
1303 costly_tin(COST_OPEN
);
1307 /* in case stop_occupation() was called on previous meal */
1308 context
.victual
.piece
= (struct obj
*) 0;
1309 context
.victual
.o_id
= 0;
1310 context
.victual
.fullwarn
= context
.victual
.eating
=
1311 context
.victual
.doreset
= FALSE
;
1313 You("consume %s %s.", tintxts
[r
].txt
, mons
[mnum
].mname
);
1315 eating_conducts(&mons
[mnum
]);
1317 tin
->dknown
= tin
->known
= 1;
1321 /* charge for one at pre-eating cost */
1322 costly_tin(COST_OPEN
);
1324 if (tintxts
[r
].nut
< 0) /* rotten */
1325 make_vomiting((long) rn1(15, 10), FALSE
);
1327 lesshungry(tintxts
[r
].nut
);
1329 if (tintxts
[r
].greasy
) {
1330 /* Assume !Glib, because you can't open tins when Glib. */
1331 incr_itimeout(&Glib
, rnd(15));
1332 pline("Eating %s food made your %s very slippery.",
1333 tintxts
[r
].txt
, makeplural(body_part(FINGER
)));
1336 } else { /* spinach... */
1338 pline("It contains some decaying%s%s substance.",
1339 Blind
? "" : " ", Blind
? "" : hcolor(NH_GREEN
));
1341 pline("It contains spinach.");
1342 tin
->dknown
= tin
->known
= 1;
1345 if (yn("Eat it?") == 'n') {
1347 You("discard the open tin.");
1348 costly_tin(COST_OPEN
);
1353 * Same order as with non-spinach above:
1354 * conduct update, side-effects, shop handling, and nutrition.
1357 .food
++; /* don't need vegan/vegetarian checks for spinach */
1359 pline("This makes you feel like %s!",
1360 Hallucination
? "Swee'pea" : "Popeye");
1361 gainstr(tin
, 0, FALSE
);
1363 costly_tin(COST_OPEN
);
1365 lesshungry(tin
->blessed
1368 ? (400 + rnd(200)) /* uncursed */
1369 : (200 + rnd(400))); /* cursed */
1377 context
.tin
.tin
= (struct obj
*) 0;
1378 context
.tin
.o_id
= 0;
1381 /* called during each move whilst opening a tin */
1385 /* perhaps it was stolen (although that should cause interruption) */
1386 if (!carried(context
.tin
.tin
)
1387 && (!obj_here(context
.tin
.tin
, u
.ux
, u
.uy
) || !can_reach_floor(TRUE
)))
1388 return 0; /* %% probably we should use tinoid */
1389 if (context
.tin
.usedtime
++ >= 50) {
1390 You("give up your attempt to open the tin.");
1393 if (context
.tin
.usedtime
< context
.tin
.reqtime
)
1394 return 1; /* still busy */
1396 consume_tin("You succeed in opening the tin.");
1400 /* called when starting to open a tin */
1405 const char *mesg
= 0;
1408 if (metallivorous(youmonst
.data
)) {
1409 mesg
= "You bite right into the metal tin...";
1411 } else if (cantwield(youmonst
.data
)) { /* nohands || verysmall */
1412 You("cannot handle the tin properly to open it.");
1414 } else if (otmp
->blessed
) {
1415 /* 50/50 chance for immediate access vs 1 turn delay (unless
1416 wielding blessed tin opener which always yields immediate
1417 access); 1 turn delay case is non-deterministic: getting
1418 interrupted and retrying might yield another 1 turn delay
1419 or might open immediately on 2nd (or 3rd, 4th, ...) try */
1420 tmp
= (uwep
&& uwep
->blessed
&& uwep
->otyp
== TIN_OPENER
) ? 0 : rn2(2);
1422 mesg
= "The tin opens like magic!";
1424 pline_The("tin seems easy to open.");
1426 switch (uwep
->otyp
) {
1428 mesg
= "You easily open the tin."; /* iff tmp==0 */
1429 tmp
= rn2(uwep
->cursed
? 3 : !uwep
->blessed
? 2 : 1);
1448 pline("Using %s you try to open the tin.", yobjnam(uwep
, (char *) 0));
1451 pline("It is not so easy to open this tin.");
1453 pline_The("tin slips from your %s.",
1454 makeplural(body_part(FINGER
)));
1455 if (otmp
->quan
> 1L) {
1456 otmp
= splitobj(otmp
, 1L);
1464 tmp
= rn1(1 + 500 / ((int) (ACURR(A_DEX
) + ACURRSTR
)), 10);
1467 context
.tin
.tin
= otmp
;
1468 context
.tin
.o_id
= otmp
->o_id
;
1470 consume_tin(mesg
); /* begin immediately */
1472 context
.tin
.reqtime
= tmp
;
1473 context
.tin
.usedtime
= 0;
1474 set_occupation(opentin
, "opening the tin", 0);
1479 /* called when waking up after fainting */
1481 Hear_again(VOID_ARGS
)
1483 /* Chance of deafness going away while fainted/sleeping/etc. */
1485 make_deaf(0L, FALSE
);
1486 context
.botl
= TRUE
;
1491 /* called on the "first bite" of rotten food */
1496 pline("Blecch! Rotten %s!", foodword(obj
));
1499 You_feel("rather trippy.");
1501 You_feel("rather %s.", body_part(LIGHT_HEADED
));
1502 make_confused(HConfusion
+ d(2, 4), FALSE
);
1503 } else if (!rn2(4) && !Blind
) {
1504 pline("Everything suddenly goes dark.");
1505 /* hero is not Blind, but Blinded timer might be nonzero if
1506 blindness is being overridden by the Eyes of the Overworld */
1507 make_blinded((Blinded
& TIMEOUT
) + (long) d(2, 10), FALSE
);
1509 Your1(vision_clears
);
1510 } else if (!rn2(3)) {
1511 const char *what
, *where
;
1512 int duration
= rnd(10);
1515 what
= "goes", where
= "dark";
1516 else if (Levitation
|| Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
))
1517 what
= "you lose control of", where
= "yourself";
1519 what
= "you slap against the",
1520 where
= (u
.usteed
) ? "saddle" : surface(u
.ux
, u
.uy
);
1521 pline_The("world spins and %s %s.", what
, where
);
1522 incr_itimeout(&HDeaf
, duration
);
1523 context
.botl
= TRUE
;
1525 multi_reason
= "unconscious from rotten food";
1526 nomovemsg
= "You are conscious again.";
1527 afternmv
= Hear_again
;
1533 /* called when a corpse is selected as food */
1538 int retcode
= 0, tp
= 0, mnum
= otmp
->corpsenm
;
1540 boolean stoneable
= (flesh_petrifies(&mons
[mnum
]) && !Stone_resistance
1541 && !poly_when_stoned(youmonst
.data
)),
1542 slimeable
= (mnum
== PM_GREEN_SLIME
&& !Slimed
&& !Unchanging
1543 && !slimeproof(youmonst
.data
)),
1544 glob
= otmp
->globby
? TRUE
: FALSE
;
1547 if (!vegan(&mons
[mnum
]))
1548 u
.uconduct
.unvegan
++;
1549 if (!vegetarian(&mons
[mnum
]))
1550 violated_vegetarian();
1552 if (!nonrotting_corpse(mnum
)) {
1553 long age
= peek_at_iced_corpse_age(otmp
);
1555 rotted
= (monstermoves
- age
) / (10L + rn2(20));
1558 else if (otmp
->blessed
)
1562 if (mnum
!= PM_ACID_BLOB
&& !stoneable
&& !slimeable
&& rotted
> 5L) {
1563 boolean cannibal
= maybe_cannibal(mnum
, FALSE
);
1565 pline("Ulch - that %s was tainted%s!",
1566 (mons
[mnum
].mlet
== S_FUNGUS
) ? "fungoid vegetation"
1568 : vegetarian(&mons
[mnum
]) ? "protoplasm"
1570 cannibal
? ", you cannibal" : "");
1571 if (Sick_resistance
) {
1572 pline("It doesn't seem at all sickening, though...");
1576 sick_time
= (long) rn1(10, 10);
1577 /* make sure new ill doesn't result in improvement */
1578 if (Sick
&& (sick_time
> Sick
))
1579 sick_time
= (Sick
> 1L) ? Sick
- 1L : 1L;
1580 make_sick(sick_time
, corpse_xname(otmp
, "rotted", CXN_NORMAL
),
1581 TRUE
, SICK_VOMITABLE
);
1588 } else if (acidic(&mons
[mnum
]) && !Acid_resistance
) {
1590 You("have a very bad case of stomach acid."); /* not body_part() */
1591 losehp(rnd(15), !glob
? "acidic corpse" : "acidic glob",
1592 KILLED_BY_AN
); /* acid damage */
1593 } else if (poisonous(&mons
[mnum
]) && rn2(5)) {
1595 pline("Ecch - that must have been poisonous!");
1596 if (!Poison_resistance
) {
1598 losehp(rnd(15), !glob
? "poisonous corpse" : "posionous glob",
1601 You("seem unaffected by the poison.");
1602 /* now any corpse left too long will make you mildly ill */
1603 } else if ((rotted
> 5L || (rotted
> 3L && rn2(5))) && !Sick_resistance
) {
1605 You_feel("%ssick.", (Sick
) ? "very " : "");
1606 losehp(rnd(8), !glob
? "cadaver" : "rotted glob", KILLED_BY_AN
);
1609 /* delay is weight dependent */
1610 context
.victual
.reqtime
= 3 + ((!glob
? mons
[mnum
].cwt
: otmp
->owt
) >> 6);
1612 if (!tp
&& !nonrotting_corpse(mnum
) && (otmp
->orotten
|| !rn2(7))) {
1613 if (rottenfood(otmp
)) {
1614 otmp
->orotten
= TRUE
;
1615 (void) touchfood(otmp
);
1619 if (!mons
[otmp
->corpsenm
].cnutrit
) {
1620 /* no nutrition: rots away, no message if you passed out */
1622 pline_The("corpse rots away completely.");
1631 consume_oeaten(otmp
, 2); /* oeaten >>= 2 */
1632 } else if ((mnum
== PM_COCKATRICE
|| mnum
== PM_CHICKATRICE
)
1633 && (Stone_resistance
|| Hallucination
)) {
1634 pline("This tastes just like chicken!");
1635 } else if (mnum
== PM_FLOATING_EYE
&& u
.umonnum
== PM_RAVEN
) {
1636 You("peck the eyeball with delight.");
1638 /* [is this right? omnivores end up always disliking the taste] */
1639 boolean yummy
= vegan(&mons
[mnum
])
1640 ? (!carnivorous(youmonst
.data
)
1641 && herbivorous(youmonst
.data
))
1642 : (carnivorous(youmonst
.data
)
1643 && !herbivorous(youmonst
.data
));
1646 type_is_pname(&mons
[mnum
])
1647 ? "" : the_unique_pm(&mons
[mnum
]) ? "The " : "This ",
1648 food_xname(otmp
, FALSE
),
1650 ? (yummy
? ((u
.umonnum
== PM_TIGER
) ? "is gr-r-reat"
1653 : (yummy
? "is delicious" : "tastes terrible"));
1659 /* called as you start to eat */
1664 const char *old_nomovemsg
, *save_nomovemsg
;
1666 debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp
,
1667 (unsigned long) context
.victual
.piece
);
1668 debugpline1("reqtime = %d", context
.victual
.reqtime
);
1669 debugpline1("(original reqtime = %d)", objects
[otmp
->otyp
].oc_delay
);
1670 debugpline1("nmod = %d", context
.victual
.nmod
);
1671 debugpline1("oeaten = %d", otmp
->oeaten
);
1672 context
.victual
.fullwarn
= context
.victual
.doreset
= FALSE
;
1673 context
.victual
.eating
= TRUE
;
1675 if (otmp
->otyp
== CORPSE
|| otmp
->globby
) {
1676 cprefx(context
.victual
.piece
->corpsenm
);
1677 if (!context
.victual
.piece
|| !context
.victual
.eating
) {
1678 /* rider revived, or died and lifesaved */
1683 old_nomovemsg
= nomovemsg
;
1685 /* survived choking, finish off food that's nearly done;
1686 need this to handle cockatrice eggs, fortune cookies, etc */
1687 if (++context
.victual
.usedtime
>= context
.victual
.reqtime
) {
1688 /* don't want done_eating() to issue nomovemsg if it
1689 is due to vomit() called by bite() */
1690 save_nomovemsg
= nomovemsg
;
1695 nomovemsg
= save_nomovemsg
;
1700 if (++context
.victual
.usedtime
>= context
.victual
.reqtime
) {
1701 /* print "finish eating" message if they just resumed -dlc */
1702 done_eating(context
.victual
.reqtime
> 1 ? TRUE
: FALSE
);
1706 Sprintf(msgbuf
, "eating %s", food_xname(otmp
, TRUE
));
1707 set_occupation(eatfood
, msgbuf
, 0);
1711 * called on "first bite" of (non-corpse) food.
1712 * used for non-rotten non-tin non-corpse food
1718 switch (otmp
->otyp
) {
1720 if (u
.uhunger
<= 200)
1721 pline(Hallucination
? "Oh wow, like, superior, man!"
1722 : "That food really hit the spot!");
1723 else if (u
.uhunger
<= 700)
1724 pline("That satiated your %s!", body_part(STOMACH
));
1727 if (carnivorous(youmonst
.data
) && !humanoid(youmonst
.data
))
1728 pline("That tripe ration was surprisingly good!");
1729 else if (maybe_polyd(is_orc(youmonst
.data
), Race_if(PM_ORC
)))
1730 pline(Hallucination
? "Tastes great! Less filling!"
1731 : "Mmm, tripe... not bad!");
1733 pline("Yak - dog food!");
1734 more_experienced(1, 0);
1736 /* not cannibalism, but we use similar criteria
1737 for deciding whether to be sickened by this meal */
1738 if (rn2(2) && !CANNIBAL_ALLOWED())
1739 make_vomiting((long) rn1(context
.victual
.reqtime
, 14), FALSE
);
1744 case HUGE_CHUNK_OF_MEAT
:
1747 case CLOVE_OF_GARLIC
:
1748 if (is_undead(youmonst
.data
)) {
1749 make_vomiting((long) rn1(context
.victual
.reqtime
, 5), FALSE
);
1754 if (otmp
->otyp
== SLIME_MOLD
&& !otmp
->cursed
1755 && otmp
->spe
== context
.current_fruit
) {
1756 pline("My, that was a %s %s!",
1757 Hallucination
? "primo" : "yummy",
1758 singular(otmp
, xname
));
1759 } else if (otmp
->otyp
== APPLE
&& otmp
->cursed
&& !Sleep_resistance
) {
1760 ; /* skip core joke; feedback deferred til fpostfx() */
1762 #if defined(MAC) || defined(MACOSX)
1763 /* KMH -- Why should Unix have all the fun?
1764 We check MACOSX before UNIX to get the Apple-specific apple
1765 message; the '#if UNIX' code will still kick in for pear. */
1766 } else if (otmp
->otyp
== APPLE
) {
1767 pline("Delicious! Must be a Macintosh!");
1771 } else if (otmp
->otyp
== APPLE
|| otmp
->otyp
== PEAR
) {
1772 if (!Hallucination
) {
1773 pline("Core dumped.");
1775 /* This is based on an old Usenet joke, a fake a.out manual
1780 pline("%s -- core dumped.",
1782 ? "Segmentation fault"
1788 } else if (otmp
->otyp
== EGG
&& stale_egg(otmp
)) {
1789 pline("Ugh. Rotten egg."); /* perhaps others like it */
1790 /* increasing existing nausea means that it will take longer
1791 before eventual vomit, but also means that constitution
1792 will be abused more times before illness completes */
1793 make_vomiting((Vomiting
& TIMEOUT
) + (long) d(10, 4), TRUE
);
1796 pline("This %s is %s", singular(otmp
, xname
),
1798 ? (Hallucination
? "grody!" : "terrible!")
1799 : (otmp
->otyp
== CRAM_RATION
1800 || otmp
->otyp
== K_RATION
1801 || otmp
->otyp
== C_RATION
)
1803 : Hallucination
? "gnarly!" : "delicious!");
1805 break; /* default */
1809 /* increment a combat intrinsic with limits on its growth */
1811 bounded_increase(old
, inc
, typ
)
1814 int absold
, absinc
, sgnold
, sgninc
;
1816 /* don't include any amount coming from worn rings */
1817 if (uright
&& uright
->otyp
== typ
)
1819 if (uleft
&& uleft
->otyp
== typ
)
1821 absold
= abs(old
), absinc
= abs(inc
);
1822 sgnold
= sgn(old
), sgninc
= sgn(inc
);
1824 if (absinc
== 0 || sgnold
!= sgninc
|| absold
+ absinc
< 10) {
1825 ; /* use inc as-is */
1826 } else if (absold
+ absinc
< 20) {
1827 absinc
= rnd(absinc
); /* 1..n */
1828 if (absold
+ absinc
< 10)
1829 absinc
= 10 - absold
;
1830 inc
= sgninc
* absinc
;
1831 } else if (absold
+ absinc
< 40) {
1832 absinc
= rn2(absinc
) ? 1 : 0;
1833 if (absold
+ absinc
< 20)
1834 absinc
= rnd(20 - absold
);
1835 inc
= sgninc
* absinc
;
1837 inc
= 0; /* no further increase allowed via this method */
1843 accessory_has_effect(otmp
)
1846 pline("Magic spreads through your body as you digest the %s.",
1847 otmp
->oclass
== RING_CLASS
? "ring" : "amulet");
1854 int typ
= otmp
->otyp
;
1857 /* Note: rings are not so common that this is unbalancing. */
1858 /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1859 oldprop
= u
.uprops
[objects
[typ
].oc_oprop
].intrinsic
;
1860 if (otmp
== uleft
|| otmp
== uright
) {
1863 return; /* died from sink fall */
1865 otmp
->known
= otmp
->dknown
= 1; /* by taste */
1866 if (!rn2(otmp
->oclass
== RING_CLASS
? 3 : 5)) {
1867 switch (otmp
->otyp
) {
1869 if (!objects
[typ
].oc_oprop
)
1870 break; /* should never happen */
1872 if (!(u
.uprops
[objects
[typ
].oc_oprop
].intrinsic
& FROMOUTSIDE
))
1873 accessory_has_effect(otmp
);
1875 u
.uprops
[objects
[typ
].oc_oprop
].intrinsic
|= FROMOUTSIDE
;
1878 case RIN_SEE_INVISIBLE
:
1879 set_mimic_blocking();
1881 if (Invis
&& !oldprop
&& !ESee_invisible
1882 && !perceives(youmonst
.data
) && !Blind
) {
1884 pline("Suddenly you can see yourself.");
1888 case RIN_INVISIBILITY
:
1889 if (!oldprop
&& !EInvis
&& !BInvis
&& !See_invisible
1892 Your("body takes on a %s transparency...",
1893 Hallucination
? "normal" : "strange");
1897 case RIN_PROTECTION_FROM_SHAPE_CHAN
:
1900 case RIN_LEVITATION
:
1901 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1902 u
.uprops
[LEVITATION
].intrinsic
= oldprop
;
1905 incr_itimeout(&HLevitation
, d(10, 20));
1909 } /* inner switch */
1910 break; /* default case of outer switch */
1913 accessory_has_effect(otmp
);
1914 if (adjattrib(A_CHA
, otmp
->spe
, -1))
1917 case RIN_GAIN_STRENGTH
:
1918 accessory_has_effect(otmp
);
1919 if (adjattrib(A_STR
, otmp
->spe
, -1))
1922 case RIN_GAIN_CONSTITUTION
:
1923 accessory_has_effect(otmp
);
1924 if (adjattrib(A_CON
, otmp
->spe
, -1))
1927 case RIN_INCREASE_ACCURACY
:
1928 accessory_has_effect(otmp
);
1929 u
.uhitinc
= (schar
) bounded_increase((int) u
.uhitinc
, otmp
->spe
,
1930 RIN_INCREASE_ACCURACY
);
1932 case RIN_INCREASE_DAMAGE
:
1933 accessory_has_effect(otmp
);
1934 u
.udaminc
= (schar
) bounded_increase((int) u
.udaminc
, otmp
->spe
,
1935 RIN_INCREASE_DAMAGE
);
1937 case RIN_PROTECTION
:
1938 accessory_has_effect(otmp
);
1939 HProtection
|= FROMOUTSIDE
;
1940 u
.ublessed
= bounded_increase(u
.ublessed
, otmp
->spe
,
1944 case RIN_FREE_ACTION
:
1945 /* Give sleep resistance instead */
1946 if (!(HSleep_resistance
& FROMOUTSIDE
))
1947 accessory_has_effect(otmp
);
1948 if (!Sleep_resistance
)
1949 You_feel("wide awake.");
1950 HSleep_resistance
|= FROMOUTSIDE
;
1952 case AMULET_OF_CHANGE
:
1953 accessory_has_effect(otmp
);
1956 You("are suddenly very %s!",
1957 flags
.female
? "feminine" : "masculine");
1960 case AMULET_OF_UNCHANGING
:
1961 /* un-change: it's a pun */
1962 if (!Unchanging
&& Upolyd
) {
1963 accessory_has_effect(otmp
);
1968 case AMULET_OF_STRANGULATION
: /* bad idea! */
1969 /* no message--this gives no permanent effect */
1972 case AMULET_OF_RESTFUL_SLEEP
: { /* another bad idea! */
1973 long newnap
= (long) rnd(100), oldnap
= (HSleepy
& TIMEOUT
);
1975 if (!(HSleepy
& FROMOUTSIDE
))
1976 accessory_has_effect(otmp
);
1977 HSleepy
|= FROMOUTSIDE
;
1978 /* might also be wearing one; use shorter of two timeouts */
1979 if (newnap
< oldnap
|| oldnap
== 0L)
1980 HSleepy
= (HSleepy
& ~TIMEOUT
) | newnap
;
1983 case RIN_SUSTAIN_ABILITY
:
1984 case AMULET_OF_LIFE_SAVING
:
1985 case AMULET_OF_REFLECTION
: /* nice try */
1986 /* can't eat Amulet of Yendor or fakes,
1987 * and no oc_prop even if you could -3.
1994 /* called after eating non-food */
1998 struct obj
*otmp
= context
.victual
.piece
;
2000 /* lesshungry wants an occupation to handle choke messages correctly */
2001 set_occupation(eatfood
, "eating non-food", 0);
2002 lesshungry(context
.victual
.nmod
);
2004 context
.victual
.piece
= (struct obj
*) 0;
2005 context
.victual
.o_id
= 0;
2006 context
.victual
.eating
= 0;
2007 if (otmp
->oclass
== COIN_CLASS
) {
2011 useupf(otmp
, otmp
->quan
);
2012 vault_gd_watching(GD_EATGOLD
);
2016 if (otmp
->otyp
== SCR_MAIL
) {
2018 pline("This junk mail is less than satisfying.");
2021 if (otmp
->oclass
== POTION_CLASS
) {
2022 otmp
->quan
++; /* dopotion() does a useup() */
2023 (void) dopotion(otmp
);
2024 } else if (otmp
->oclass
== RING_CLASS
|| otmp
->oclass
== AMULET_CLASS
) {
2026 } else if (otmp
->otyp
== LEASH
&& otmp
->leashmon
) {
2030 /* KMH -- idea by "Tommy the Terrorist" */
2031 if (otmp
->otyp
== TRIDENT
&& !otmp
->cursed
) {
2032 /* sugarless chewing gum which used to be heavily advertised on TV */
2033 pline(Hallucination
? "Four out of five dentists agree."
2034 : "That was pure chewing satisfaction!");
2035 exercise(A_WIS
, TRUE
);
2037 if (otmp
->otyp
== FLINT
&& !otmp
->cursed
) {
2038 /* chewable vitamin for kids based on "The Flintstones" TV cartoon */
2039 pline("Yabba-dabba delicious!");
2040 exercise(A_CON
, TRUE
);
2043 if (otmp
== uwep
&& otmp
->quan
== 1L)
2045 if (otmp
== uquiver
&& otmp
->quan
== 1L)
2047 if (otmp
== uswapwep
&& otmp
->quan
== 1L)
2053 unpunish(); /* but no useup() */
2054 else if (carried(otmp
))
2060 /* NOTE: the order of these words exactly corresponds to the
2061 order of oc_material values #define'd in objclass.h. */
2062 static const char *foodwords
[] = {
2063 "meal", "liquid", "wax", "food", "meat", "paper",
2064 "cloth", "leather", "wood", "bone", "scale", "metal",
2065 "metal", "metal", "silver", "gold", "platinum", "mithril",
2066 "plastic", "glass", "rich food", "stone"
2069 STATIC_OVL
const char *
2073 if (otmp
->oclass
== FOOD_CLASS
)
2075 if (otmp
->oclass
== GEM_CLASS
&& objects
[otmp
->otyp
].oc_material
== GLASS
2077 makeknown(otmp
->otyp
);
2078 return foodwords
[objects
[otmp
->otyp
].oc_material
];
2081 /* called after consuming (non-corpse) food */
2086 switch (otmp
->otyp
) {
2087 case SPRIG_OF_WOLFSBANE
:
2088 if (u
.ulycn
>= LOW_PM
|| is_were(youmonst
.data
))
2093 || !attacktype_fordmg(u
.ustuck
->data
, AT_ENGL
, AD_BLND
))
2094 make_blinded((long) u
.ucreamed
, TRUE
);
2096 case FORTUNE_COOKIE
:
2097 outrumor(bcsign(otmp
), BY_COOKIE
);
2099 u
.uconduct
.literate
++;
2101 case LUMP_OF_ROYAL_JELLY
:
2102 /* This stuff seems to be VERY healthy! */
2103 gainstr(otmp
, 1, TRUE
);
2105 u
.mh
+= otmp
->cursed
? -rnd(20) : rnd(20);
2106 if (u
.mh
> u
.mhmax
) {
2110 } else if (u
.mh
<= 0) {
2114 u
.uhp
+= otmp
->cursed
? -rnd(20) : rnd(20);
2115 if (u
.uhp
> u
.uhpmax
) {
2119 } else if (u
.uhp
<= 0) {
2120 killer
.format
= KILLED_BY_AN
;
2121 Strcpy(killer
.name
, "rotten lump of royal jelly");
2129 if (flesh_petrifies(&mons
[otmp
->corpsenm
])) {
2130 if (!Stone_resistance
2131 && !(poly_when_stoned(youmonst
.data
)
2132 && polymon(PM_STONE_GOLEM
))) {
2134 Sprintf(killer
.name
, "%s egg",
2135 mons
[otmp
->corpsenm
].mname
);
2136 make_stoned(5L, (char *) 0, KILLED_BY_AN
, killer
.name
);
2139 /* note: no "tastes like chicken" message for eggs */
2142 case EUCALYPTUS_LEAF
:
2143 if (Sick
&& !otmp
->cursed
)
2144 make_sick(0L, (char *) 0, TRUE
, SICK_ALL
);
2145 if (Vomiting
&& !otmp
->cursed
)
2146 make_vomiting(0L, TRUE
);
2149 if (otmp
->cursed
&& !Sleep_resistance
) {
2150 /* Snow White; 'poisoned' applies to [a subset of] weapons,
2151 not food, so we substitute cursed; fortunately our hero
2152 won't have to wait for a prince to be rescued/revived */
2153 if (Race_if(PM_DWARF
) && Hallucination
)
2154 verbalize("Heigh-ho, ho-hum, I think I'll skip work today.");
2155 else if (Deaf
|| !flags
.acoustics
)
2156 You("fall asleep.");
2158 You_hear("sinister laughter as you fall asleep...");
2159 fall_asleep(-rn1(11, 20), TRUE
);
2167 /* intended for eating a spellbook while polymorphed, but not used;
2168 "leather" applied to appearance, not composition, and has been
2169 changed to "leathery" to reflect that */
2170 STATIC_DCL boolean
FDECL(leather_cover
, (struct obj
*));
2176 const char *odesc
= OBJ_DESCR(objects
[otmp
->otyp
]);
2178 if (odesc
&& (otmp
->oclass
== SPBOOK_CLASS
)) {
2179 if (!strcmp(odesc
, "leather"))
2187 * return 0 if the food was not dangerous.
2188 * return 1 if the food was dangerous and you chose to stop.
2189 * return 2 if the food was dangerous and you chose to eat it anyway.
2192 edibility_prompts(otmp
)
2195 /* Blessed food detection grants hero a one-use
2196 * ability to detect food that is unfit for consumption
2197 * or dangerous and avoid it.
2199 char buf
[BUFSZ
], foodsmell
[BUFSZ
],
2200 it_or_they
[QBUFSZ
], eat_it_anyway
[QBUFSZ
];
2201 boolean cadaver
= (otmp
->otyp
== CORPSE
|| otmp
->globby
),
2202 stoneorslime
= FALSE
;
2203 int material
= objects
[otmp
->otyp
].oc_material
, mnum
= otmp
->corpsenm
;
2206 Strcpy(foodsmell
, Tobjnam(otmp
, "smell"));
2207 Strcpy(it_or_they
, (otmp
->quan
== 1L) ? "it" : "they");
2208 Sprintf(eat_it_anyway
, "Eat %s anyway?",
2209 (otmp
->quan
== 1L) ? "it" : "one");
2211 if (cadaver
|| otmp
->otyp
== EGG
|| otmp
->otyp
== TIN
) {
2212 /* These checks must match those in eatcorpse() */
2213 stoneorslime
= (flesh_petrifies(&mons
[mnum
]) && !Stone_resistance
2214 && !poly_when_stoned(youmonst
.data
));
2216 if (mnum
== PM_GREEN_SLIME
|| otmp
->otyp
== GLOB_OF_GREEN_SLIME
)
2217 stoneorslime
= (!Unchanging
&& !slimeproof(youmonst
.data
));
2219 if (cadaver
&& !nonrotting_corpse(mnum
)) {
2220 long age
= peek_at_iced_corpse_age(otmp
);
2222 /* worst case rather than random
2223 in this calculation to force prompt */
2224 rotted
= (monstermoves
- age
) / (10L + 0 /* was rn2(20) */);
2227 else if (otmp
->blessed
)
2233 * These problems with food should be checked in
2234 * order from most detrimental to least detrimental.
2236 if (cadaver
&& mnum
!= PM_ACID_BLOB
&& rotted
> 5L && !Sick_resistance
) {
2238 Sprintf(buf
, "%s like %s could be tainted! %s", foodsmell
, it_or_they
,
2240 if (yn_function(buf
, ynchars
, 'n') == 'n')
2246 Sprintf(buf
, "%s like %s could be something very dangerous! %s",
2247 foodsmell
, it_or_they
, eat_it_anyway
);
2248 if (yn_function(buf
, ynchars
, 'n') == 'n')
2253 if (otmp
->orotten
|| (cadaver
&& rotted
> 3L)) {
2255 Sprintf(buf
, "%s like %s could be rotten! %s", foodsmell
, it_or_they
,
2257 if (yn_function(buf
, ynchars
, 'n') == 'n')
2262 if (cadaver
&& poisonous(&mons
[mnum
]) && !Poison_resistance
) {
2264 Sprintf(buf
, "%s like %s might be poisonous! %s", foodsmell
,
2265 it_or_they
, eat_it_anyway
);
2266 if (yn_function(buf
, ynchars
, 'n') == 'n')
2271 if (otmp
->otyp
== APPLE
&& otmp
->cursed
&& !Sleep_resistance
) {
2272 /* causes sleep, for long enough to be dangerous */
2273 Sprintf(buf
, "%s like %s might have been poisoned. %s", foodsmell
,
2274 it_or_they
, eat_it_anyway
);
2275 return (yn_function(buf
, ynchars
, 'n') == 'n') ? 1 : 2;
2277 if (cadaver
&& !vegetarian(&mons
[mnum
]) && !u
.uconduct
.unvegetarian
2278 && Role_if(PM_MONK
)) {
2279 Sprintf(buf
, "%s unhealthy. %s", foodsmell
, eat_it_anyway
);
2280 if (yn_function(buf
, ynchars
, 'n') == 'n')
2285 if (cadaver
&& acidic(&mons
[mnum
]) && !Acid_resistance
) {
2286 Sprintf(buf
, "%s rather acidic. %s", foodsmell
, eat_it_anyway
);
2287 if (yn_function(buf
, ynchars
, 'n') == 'n')
2292 if (Upolyd
&& u
.umonnum
== PM_RUST_MONSTER
&& is_metallic(otmp
)
2293 && otmp
->oerodeproof
) {
2294 Sprintf(buf
, "%s disgusting to you right now. %s", foodsmell
,
2296 if (yn_function(buf
, ynchars
, 'n') == 'n')
2303 * Breaks conduct, but otherwise safe.
2305 if (!u
.uconduct
.unvegan
2306 && ((material
== LEATHER
|| material
== BONE
2307 || material
== DRAGON_HIDE
|| material
== WAX
)
2308 || (cadaver
&& !vegan(&mons
[mnum
])))) {
2309 Sprintf(buf
, "%s foul and unfamiliar to you. %s", foodsmell
,
2311 if (yn_function(buf
, ynchars
, 'n') == 'n')
2316 if (!u
.uconduct
.unvegetarian
2317 && ((material
== LEATHER
|| material
== BONE
2318 || material
== DRAGON_HIDE
)
2319 || (cadaver
&& !vegetarian(&mons
[mnum
])))) {
2320 Sprintf(buf
, "%s unfamiliar to you. %s", foodsmell
, eat_it_anyway
);
2321 if (yn_function(buf
, ynchars
, 'n') == 'n')
2327 if (cadaver
&& mnum
!= PM_ACID_BLOB
&& rotted
> 5L && Sick_resistance
) {
2328 /* Tainted meat with Sick_resistance */
2329 Sprintf(buf
, "%s like %s could be tainted! %s", foodsmell
, it_or_they
,
2331 if (yn_function(buf
, ynchars
, 'n') == 'n')
2344 int basenutrit
; /* nutrition of full item */
2345 boolean dont_start
= FALSE
, nodelicious
= FALSE
;
2348 pline("If you can't breathe air, how can you consume solids?");
2351 if (!(otmp
= floorfood("eat", 0)))
2353 if (check_capacity((char *) 0))
2357 int res
= edibility_prompts(otmp
);
2360 "%s stops tingling and your sense of smell returns to normal.",
2368 /* We have to make non-foods take 1 move to eat, unless we want to
2369 * do ridiculous amounts of coding to deal with partly eaten plate
2370 * mails, players who polymorph back to human in the middle of their
2371 * metallic meal, etc....
2373 if (!(carried(otmp
) ? retouch_object(&otmp
, FALSE
)
2374 : touch_artifact(otmp
, &youmonst
))) {
2376 } else if (!is_edible(otmp
)) {
2377 You("cannot eat that!");
2379 } else if ((otmp
->owornmask
& (W_ARMOR
| W_TOOL
| W_AMUL
| W_SADDLE
))
2381 /* let them eat rings */
2382 You_cant("eat %s you're wearing.", something
);
2385 if (is_metallic(otmp
) && u
.umonnum
== PM_RUST_MONSTER
2386 && otmp
->oerodeproof
) {
2387 otmp
->rknown
= TRUE
;
2388 if (otmp
->quan
> 1L) {
2390 (void) splitobj(otmp
, otmp
->quan
- 1L);
2392 otmp
= splitobj(otmp
, 1L);
2394 pline("Ulch - that %s was rustproofed!", xname(otmp
));
2395 /* The regurgitated object's rustproofing is gone now */
2396 otmp
->oerodeproof
= 0;
2397 make_stunned((HStun
& TIMEOUT
) + (long) rn2(10), TRUE
);
2398 You("spit %s out onto the %s.", the(xname(otmp
)),
2399 surface(u
.ux
, u
.uy
));
2400 if (carried(otmp
)) {
2407 /* KMH -- Slow digestion is... indigestible */
2408 if (otmp
->otyp
== RIN_SLOW_DIGESTION
) {
2409 pline("This ring is indigestible!");
2410 (void) rottenfood(otmp
);
2411 if (otmp
->dknown
&& !objects
[otmp
->otyp
].oc_name_known
2412 && !objects
[otmp
->otyp
].oc_uname
)
2416 if (otmp
->oclass
!= FOOD_CLASS
) {
2419 context
.victual
.reqtime
= 1;
2420 context
.victual
.piece
= otmp
;
2421 context
.victual
.o_id
= otmp
->o_id
;
2422 /* Don't split it, we don't need to if it's 1 move */
2423 context
.victual
.usedtime
= 0;
2424 context
.victual
.canchoke
= (u
.uhs
== SATIATED
);
2425 /* Note: gold weighs 1 pt. for each 1000 pieces (see
2426 pickup.c) so gold and non-gold is consistent. */
2427 if (otmp
->oclass
== COIN_CLASS
)
2428 basenutrit
= ((otmp
->quan
> 200000L)
2430 : (int) (otmp
->quan
/ 100L));
2431 else if (otmp
->oclass
== BALL_CLASS
|| otmp
->oclass
== CHAIN_CLASS
)
2432 basenutrit
= weight(otmp
);
2433 /* oc_nutrition is usually weight anyway */
2435 basenutrit
= objects
[otmp
->otyp
].oc_nutrition
;
2437 if (otmp
->otyp
== SCR_MAIL
) {
2442 context
.victual
.nmod
= basenutrit
;
2443 context
.victual
.eating
= TRUE
; /* needed for lesshungry() */
2445 material
= objects
[otmp
->otyp
].oc_material
;
2446 if (material
== LEATHER
|| material
== BONE
2447 || material
== DRAGON_HIDE
) {
2448 u
.uconduct
.unvegan
++;
2449 violated_vegetarian();
2450 } else if (material
== WAX
)
2451 u
.uconduct
.unvegan
++;
2455 (void) rottenfood(otmp
);
2457 if (otmp
->oclass
== WEAPON_CLASS
&& otmp
->opoisoned
) {
2458 pline("Ecch - that must have been poisonous!");
2459 if (!Poison_resistance
) {
2461 losehp(rnd(15), xname(otmp
), KILLED_BY_AN
);
2463 You("seem unaffected by the poison.");
2464 } else if (!otmp
->cursed
&& !nodelicious
) {
2465 pline("%s%s is delicious!",
2467 && otmp
->oartifact
< ART_ORB_OF_DETECTION
)
2470 (otmp
->oclass
== COIN_CLASS
)
2472 : singular(otmp
, xname
));
2478 if (otmp
== context
.victual
.piece
) {
2479 /* If they weren't able to choke, they don't suddenly become able to
2480 * choke just because they were interrupted. On the other hand, if
2481 * they were able to choke before, if they lost food it's possible
2482 * they shouldn't be able to choke now.
2484 if (u
.uhs
!= SATIATED
)
2485 context
.victual
.canchoke
= FALSE
;
2486 context
.victual
.o_id
= 0;
2487 context
.victual
.piece
= touchfood(otmp
);
2488 if (context
.victual
.piece
)
2489 context
.victual
.o_id
= context
.victual
.piece
->o_id
;
2490 You("resume your meal.");
2491 start_eating(context
.victual
.piece
);
2495 /* nothing in progress - so try to find something. */
2496 /* tins are a special case */
2497 /* tins must also check conduct separately in case they're discarded */
2498 if (otmp
->otyp
== TIN
) {
2506 context
.victual
.o_id
= 0;
2507 context
.victual
.piece
= otmp
= touchfood(otmp
);
2508 if (context
.victual
.piece
)
2509 context
.victual
.o_id
= context
.victual
.piece
->o_id
;
2510 context
.victual
.usedtime
= 0;
2512 /* Now we need to calculate delay and nutritional info.
2513 * The base nutrition calculated here and in eatcorpse() accounts
2514 * for normal vs. rotten food. The reqtime and nutrit values are
2515 * then adjusted in accordance with the amount of food left.
2517 if (otmp
->otyp
== CORPSE
|| otmp
->globby
) {
2518 int tmp
= eatcorpse(otmp
);
2522 context
.victual
.piece
= (struct obj
*) 0;
2523 context
.victual
.o_id
= 0;
2527 /* if not used up, eatcorpse sets up reqtime and may modify oeaten */
2529 /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are
2530 * all handled in the != FOOD_CLASS case, above.
2532 switch (objects
[otmp
->otyp
].oc_material
) {
2534 u
.uconduct
.unvegan
++;
2535 if (otmp
->otyp
!= EGG
) {
2536 violated_vegetarian();
2541 if (otmp
->otyp
== PANCAKE
|| otmp
->otyp
== FORTUNE_COOKIE
/*eggs*/
2542 || otmp
->otyp
== CREAM_PIE
|| otmp
->otyp
== CANDY_BAR
/*milk*/
2543 || otmp
->otyp
== LUMP_OF_ROYAL_JELLY
)
2544 u
.uconduct
.unvegan
++;
2548 context
.victual
.reqtime
= objects
[otmp
->otyp
].oc_delay
;
2549 if (otmp
->otyp
!= FORTUNE_COOKIE
2550 && (otmp
->cursed
|| (!nonrotting_food(otmp
->otyp
)
2551 && (monstermoves
- otmp
->age
)
2552 > (otmp
->blessed
? 50L : 30L)
2553 && (otmp
->orotten
|| !rn2(7))))) {
2554 if (rottenfood(otmp
)) {
2555 otmp
->orotten
= TRUE
;
2558 consume_oeaten(otmp
, 1); /* oeaten >>= 1 */
2563 /* re-calc the nutrition */
2564 basenutrit
= (otmp
->otyp
== CORPSE
) ? mons
[otmp
->corpsenm
].cnutrit
2565 : otmp
->globby
? otmp
->owt
2566 : (unsigned) objects
[otmp
->otyp
].oc_nutrition
;
2569 "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d",
2570 context
.victual
.reqtime
, otmp
->oeaten
, basenutrit
);
2572 context
.victual
.reqtime
= (basenutrit
== 0) ? 0
2573 : rounddiv(context
.victual
.reqtime
* (long) otmp
->oeaten
, basenutrit
);
2575 debugpline1("after rounddiv: victual.reqtime == %d",
2576 context
.victual
.reqtime
);
2578 * calculate the modulo value (nutrit. units per round eating)
2579 * note: this isn't exact - you actually lose a little nutrition due
2581 * TODO: add in a "remainder" value to be given at the end of the meal.
2583 if (context
.victual
.reqtime
== 0 || otmp
->oeaten
== 0)
2584 /* possible if most has been eaten before */
2585 context
.victual
.nmod
= 0;
2586 else if ((int) otmp
->oeaten
>= context
.victual
.reqtime
)
2587 context
.victual
.nmod
= -((int) otmp
->oeaten
2588 / context
.victual
.reqtime
);
2590 context
.victual
.nmod
= context
.victual
.reqtime
% otmp
->oeaten
;
2591 context
.victual
.canchoke
= (u
.uhs
== SATIATED
);
2605 if (!carrying(TIN
)) {
2606 You("have no tin to open.");
2611 if (obj
->cursed
&& obj
->bknown
) {
2614 if (ynq(safe_qbuf(qbuf
, "Really wield ", "?",
2615 obj
, doname
, thesimpleoname
, "that")) != 'y')
2618 if (!wield_tool(obj
, "use"))
2623 otmp
= getobj(comestibles
, "open");
2631 /* Take a single bite from a piece of food, checking for choking and
2632 * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
2637 if (context
.victual
.canchoke
&& u
.uhunger
>= 2000) {
2638 choke(context
.victual
.piece
);
2641 if (context
.victual
.doreset
) {
2645 force_save_hs
= TRUE
;
2646 if (context
.victual
.nmod
< 0) {
2647 lesshungry(-context
.victual
.nmod
);
2648 consume_oeaten(context
.victual
.piece
,
2649 context
.victual
.nmod
); /* -= -nmod */
2650 } else if (context
.victual
.nmod
> 0
2651 && (context
.victual
.usedtime
% context
.victual
.nmod
)) {
2653 consume_oeaten(context
.victual
.piece
, -1); /* -= 1 */
2655 force_save_hs
= FALSE
;
2660 /* as time goes by - called by moveloop() and domove() */
2664 if (u
.uinvulnerable
)
2665 return; /* you don't feel hungrier */
2667 if ((!u
.usleep
|| !rn2(10)) /* slow metabolic rate while asleep */
2668 && (carnivorous(youmonst
.data
) || herbivorous(youmonst
.data
))
2670 u
.uhunger
--; /* ordinary food consumption */
2672 if (moves
% 2) { /* odd turns */
2673 /* Regeneration uses up food, unless due to an artifact */
2674 if ((HRegeneration
& ~FROMFORM
)
2675 || (ERegeneration
& ~(W_ARTI
| W_WEP
)))
2677 if (near_capacity() > SLT_ENCUMBER
)
2679 } else { /* even turns */
2682 /* Conflict uses up food too */
2683 if (HConflict
|| (EConflict
& (~W_ARTI
)))
2685 /* +0 charged rings don't do anything, so don't affect hunger */
2686 /* Slow digestion still uses ring hunger */
2687 switch ((int) (moves
% 20)) { /* note: use even cases only */
2689 if (uleft
&& (uleft
->spe
|| !objects
[uleft
->otyp
].oc_charged
))
2697 if (uright
&& (uright
->spe
|| !objects
[uright
->otyp
].oc_charged
))
2711 /* called after vomiting and after performing feats of magic */
2720 /* called after eating (and after drinking fruit juice) */
2725 /* See comments in newuhs() for discussion on force_save_hs */
2726 boolean iseating
= (occupation
== eatfood
) || force_save_hs
;
2728 debugpline1("lesshungry(%d)", num
);
2730 if (u
.uhunger
>= 2000) {
2731 if (!iseating
|| context
.victual
.canchoke
) {
2733 choke(context
.victual
.piece
);
2736 choke(occupation
== opentin
? context
.tin
.tin
2737 : (struct obj
*) 0);
2738 /* no reset_eat() */
2741 /* Have lesshungry() report when you're nearly full so all eating
2742 * warns when you're about to choke.
2744 if (u
.uhunger
>= 1500) {
2745 if (!context
.victual
.eating
2746 || (context
.victual
.eating
&& !context
.victual
.fullwarn
)) {
2747 pline("You're having a hard time getting all of it down.");
2748 nomovemsg
= "You're finally finished.";
2749 if (!context
.victual
.eating
) {
2752 context
.victual
.fullwarn
= TRUE
;
2753 if (context
.victual
.canchoke
2754 && context
.victual
.reqtime
> 1) {
2755 /* a one-gulp food will not survive a stop */
2756 if (yn_function("Continue eating?", ynchars
, 'n')
2759 nomovemsg
= (char *) 0;
2773 (void) Hear_again();
2774 if (u
.uhs
> FAINTING
)
2784 return (boolean
) (u
.uhs
== FAINTED
);
2787 /* call when a faint must be prematurely terminated */
2791 if (afternmv
== unfaint
)
2792 unmul("You revive.");
2795 /* compute and comment on your (new?) hunger status */
2801 static unsigned save_hs
;
2802 static boolean saved_hs
= FALSE
;
2807 : (h
> 150) ? NOT_HUNGRY
2808 : (h
> 50) ? HUNGRY
: (h
> 0) ? WEAK
: FAINTING
;
2810 /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2811 * This should not produce the message "you only feel hungry now";
2812 * that message should only appear if HUNGRY is an endpoint. Therefore
2813 * we check to see if we're in the middle of eating. If so, we save
2814 * the first hunger status, and at the end of eating we decide what
2815 * message to print based on the _entire_ meal, not on each little bit.
2817 /* It is normally possible to check if you are in the middle of a meal
2818 * by checking occupation == eatfood, but there is one special case:
2819 * start_eating() can call bite() for your first bite before it
2820 * sets the occupation.
2821 * Anyone who wants to get that case to work _without_ an ugly static
2822 * force_save_hs variable, feel free.
2824 /* Note: If you become a certain hunger status in the middle of the
2825 * meal, and still have that same status at the end of the meal,
2826 * this will incorrectly print the associated message at the end of
2827 * the meal instead of the middle. Such a case is currently
2828 * impossible, but could become possible if a message for SATIATED
2829 * were added or if HUNGRY and WEAK were separated by a big enough
2830 * gap to fit two bites.
2832 if (occupation
== eatfood
|| force_save_hs
) {
2846 if (newhs
== FAINTING
) {
2849 if (u
.uhs
<= WEAK
|| rn2(20 - u
.uhunger
/ 10) >= 19) {
2850 if (!is_fainted() && multi
>= 0 /* %% */) {
2851 int duration
= 10 - (u
.uhunger
/ 10);
2853 /* stop what you're doing, then faint */
2855 You("faint from lack of food.");
2856 incr_itimeout(&HDeaf
, duration
);
2857 context
.botl
= TRUE
;
2859 multi_reason
= "fainted from lack of food";
2860 nomovemsg
= "You regain consciousness.";
2864 selftouch("Falling, you");
2866 } else if (u
.uhunger
< -(int) (200 + 20 * ACURR(A_CON
))) {
2870 You("die from starvation.");
2871 killer
.format
= KILLED_BY
;
2872 Strcpy(killer
.name
, "starvation");
2874 /* if we return, we lifesaved, and that calls newuhs */
2879 if (newhs
!= u
.uhs
) {
2880 if (newhs
>= WEAK
&& u
.uhs
< WEAK
)
2881 losestr(1); /* this may kill you -- see below */
2882 else if (newhs
< WEAK
&& u
.uhs
>= WEAK
)
2886 if (Hallucination
) {
2887 You((!incr
) ? "now have a lesser case of the munchies."
2888 : "are getting the munchies.");
2890 You((!incr
) ? "only feel hungry now."
2893 : "are beginning to feel hungry.");
2894 if (incr
&& occupation
2895 && (occupation
!= eatfood
&& occupation
!= opentin
))
2897 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
2901 pline((!incr
) ? "You still have the munchies."
2902 : "The munchies are interfering with your motor capabilities.");
2903 else if (incr
&& (Role_if(PM_WIZARD
) || Race_if(PM_ELF
)
2904 || Role_if(PM_VALKYRIE
)))
2905 pline("%s needs food, badly!",
2906 (Role_if(PM_WIZARD
) || Role_if(PM_VALKYRIE
))
2912 : (u
.uhunger
< 45) ? "feel weak."
2913 : "are beginning to feel weak.");
2914 if (incr
&& occupation
2915 && (occupation
!= eatfood
&& occupation
!= opentin
))
2917 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
2923 if ((Upolyd
? u
.mh
: u
.uhp
) < 1) {
2924 You("die from hunger and exhaustion.");
2925 killer
.format
= KILLED_BY
;
2926 Strcpy(killer
.name
, "exhaustion");
2933 /* Returns an object representing food.
2934 * Object may be either on floor or in inventory.
2937 floorfood(verb
, corpsecheck
)
2939 int corpsecheck
; /* 0, no check, 1, corpses, 2, tinnable corpses */
2941 register struct obj
*otmp
;
2944 boolean feeding
= !strcmp(verb
, "eat"), /* corpsecheck==0 */
2945 offering
= !strcmp(verb
, "sacrifice"); /* corpsecheck==1 */
2947 /* if we can't touch floor objects then use invent food only */
2948 if (!can_reach_floor(TRUE
) || (feeding
&& u
.usteed
)
2949 || (is_pool_or_lava(u
.ux
, u
.uy
)
2950 && (Wwalking
|| is_clinger(youmonst
.data
)
2951 || (Flying
&& !Breathless
))))
2954 if (feeding
&& metallivorous(youmonst
.data
)) {
2956 struct trap
*ttmp
= t_at(u
.ux
, u
.uy
);
2958 if (ttmp
&& ttmp
->tseen
&& ttmp
->ttyp
== BEAR_TRAP
) {
2959 /* If not already stuck in the trap, perhaps there should
2960 be a chance to becoming trapped? Probably not, because
2961 then the trap would just get eaten on the _next_ turn... */
2962 Sprintf(qbuf
, "There is a bear trap here (%s); eat it?",
2963 (u
.utrap
&& u
.utraptype
== TT_BEARTRAP
) ? "holding you"
2965 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
2966 u
.utrap
= u
.utraptype
= 0;
2968 return mksobj(BEARTRAP
, TRUE
, FALSE
);
2969 } else if (c
== 'q') {
2970 return (struct obj
*) 0;
2974 if (youmonst
.data
!= &mons
[PM_RUST_MONSTER
]
2975 && (gold
= g_at(u
.ux
, u
.uy
)) != 0) {
2976 if (gold
->quan
== 1L)
2977 Sprintf(qbuf
, "There is 1 gold piece here; eat it?");
2979 Sprintf(qbuf
, "There are %ld gold pieces here; eat them?",
2981 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y') {
2983 } else if (c
== 'q') {
2984 return (struct obj
*) 0;
2989 /* Is there some food (probably a heavy corpse) here on the ground? */
2990 for (otmp
= level
.objects
[u
.ux
][u
.uy
]; otmp
; otmp
= otmp
->nexthere
) {
2992 ? (otmp
->otyp
== CORPSE
2993 && (corpsecheck
== 1 || tinnable(otmp
)))
2994 : feeding
? (otmp
->oclass
!= COIN_CLASS
&& is_edible(otmp
))
2995 : otmp
->oclass
== FOOD_CLASS
) {
2997 boolean one
= (otmp
->quan
== 1L);
2999 /* "There is <an object> here; <verb> it?" or
3000 "There are <N objects> here; <verb> one?" */
3001 Sprintf(qbuf
, "There %s ", otense(otmp
, "are"));
3002 Sprintf(qsfx
, " here; %s %s?", verb
, one
? "it" : "one");
3003 (void) safe_qbuf(qbuf
, qbuf
, qsfx
, otmp
, doname
, ansimpleoname
,
3004 one
? something
: (const char *) "things");
3005 if ((c
= yn_function(qbuf
, ynqchars
, 'n')) == 'y')
3008 return (struct obj
*) 0;
3013 /* We cannot use ALL_CLASSES since that causes getobj() to skip its
3014 * "ugly checks" and we need to check for inedible items.
3017 getobj(feeding
? allobj
: offering
? offerfodder
: comestibles
, verb
);
3018 if (corpsecheck
&& otmp
&& !(offering
&& otmp
->oclass
== AMULET_CLASS
))
3019 if (otmp
->otyp
!= CORPSE
|| (corpsecheck
== 2 && !tinnable(otmp
))) {
3020 You_cant("%s that!", verb
);
3021 return (struct obj
*) 0;
3026 /* Side effects of vomiting */
3027 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
3029 vomit() /* A good idea from David Neves */
3031 if (cantvomit(youmonst
.data
))
3032 /* doesn't cure food poisoning; message assumes that we aren't
3033 dealing with some esoteric body_part() */
3034 Your("jaw gapes convulsively.");
3036 make_sick(0L, (char *) 0, TRUE
, SICK_VOMITABLE
);
3038 multi_reason
= "vomiting";
3039 nomovemsg
= You_can_move_again
;
3043 eaten_stat(base
, obj
)
3047 long uneaten_amt
, full_amount
;
3049 uneaten_amt
= (long) obj
->oeaten
;
3050 full_amount
= (long) ((obj
->otyp
== CORPSE
) ? mons
[obj
->corpsenm
].cnutrit
3051 : obj
->globby
? obj
->owt
3052 : (unsigned) objects
[obj
->otyp
].oc_nutrition
);
3053 if (uneaten_amt
> full_amount
) {
3055 "partly eaten food (%ld) more nutritious than untouched food (%ld)",
3056 uneaten_amt
, full_amount
);
3057 uneaten_amt
= full_amount
;
3060 base
= (int) (full_amount
? (long) base
* uneaten_amt
/ full_amount
: 0L);
3061 return (base
< 1) ? 1 : base
;
3064 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
3066 consume_oeaten(obj
, amt
)
3071 * This is a hack to try to squelch several long standing mystery
3072 * food bugs. A better solution would be to rewrite the entire
3073 * victual handling mechanism from scratch using a less complex
3074 * model. Alternatively, this routine could call done_eating()
3075 * or food_disappears() but its callers would need revisions to
3076 * cope with context.victual.piece unexpectedly going away.
3078 * Multi-turn eating operates by setting the food's oeaten field
3079 * to its full nutritional value and then running a counter which
3080 * independently keeps track of whether there is any food left.
3081 * The oeaten field can reach exactly zero on the last turn, and
3082 * the object isn't removed from inventory until the next turn
3083 * when the "you finish eating" message gets delivered, so the
3084 * food would be restored to the status of untouched during that
3085 * interval. This resulted in unexpected encumbrance messages
3086 * at the end of a meal (if near enough to a threshold) and would
3087 * yield full food if there was an interruption on the critical
3088 * turn. Also, there have been reports over the years of food
3089 * becoming massively heavy or producing unlimited satiation;
3090 * this would occur if reducing oeaten via subtraction attempted
3091 * to drop it below 0 since its unsigned type would produce a
3092 * huge positive value instead. So far, no one has figured out
3093 * _why_ that inappropriate subtraction might sometimes happen.
3097 /* bit shift to divide the remaining amount of food */
3098 obj
->oeaten
>>= amt
;
3100 /* simple decrement; value is negative so we actually add it */
3101 if ((int) obj
->oeaten
> -amt
)
3107 if (obj
->oeaten
== 0) {
3108 if (obj
== context
.victual
.piece
) /* always true unless wishing... */
3109 context
.victual
.reqtime
=
3110 context
.victual
.usedtime
; /* no bites left */
3111 obj
->oeaten
= 1; /* smallest possible positive value */
3115 /* called when eatfood occupation has been interrupted,
3116 or in the case of theft, is about to be interrupted */
3118 maybe_finished_meal(stopping
)
3121 /* in case consume_oeaten() has decided that the food is all gone */
3122 if (occupation
== eatfood
3123 && context
.victual
.usedtime
>= context
.victual
.reqtime
) {
3125 occupation
= 0; /* for do_reset_eat */
3126 (void) eatfood(); /* calls done_eating() to use up
3127 context.victual.piece */
3133 /* Tin of <something> to the rescue? Decide whether current occupation
3134 is an attempt to eat a tin of something capable of saving hero's life.
3135 We don't care about consumption of non-tinned food here because special
3136 effects there take place on first bite rather than at end of occupation.
3137 [Popeye the Sailor gets out of trouble by eating tins of spinach. :-] */
3145 if (occupation
!= opentin
)
3147 otin
= context
.tin
.tin
;
3148 /* make sure hero still has access to tin */
3150 && (!obj_here(otin
, u
.ux
, u
.uy
) || !can_reach_floor(TRUE
)))
3152 /* unknown tin is assumed to be helpful */
3155 /* known tin is helpful if it will stop life-threatening problem */
3156 mndx
= otin
->corpsenm
;
3158 /* note: not used; hunger code bypasses stop_occupation() when eating */
3160 return (boolean
) (mndx
!= NON_PM
|| otin
->spe
== 1);
3161 /* flesh from lizards and acidic critters stops petrification */
3163 return (boolean
) (mndx
>= LOW_PM
3164 && (mndx
== PM_LIZARD
|| acidic(&mons
[mndx
])));
3165 /* no tins can cure these (yet?) */