1 /* SCCS Id: @(#)eat.c 3.4 2003/02/13 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 /* #define DEBUG */ /* uncomment to enable new eat code debugging */
10 #define debugpline if (wizard) pline
12 #define debugpline pline
16 STATIC_PTR int NDECL(eatmdone);
17 STATIC_PTR int NDECL(eatfood);
18 STATIC_PTR void FDECL(costly_tin, (const char*));
19 STATIC_PTR int NDECL(opentin);
20 STATIC_PTR int NDECL(unfaint);
23 STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P));
24 STATIC_DCL void FDECL(choke, (struct obj *));
25 STATIC_DCL void NDECL(recalc_wt);
26 STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
27 STATIC_DCL void NDECL(do_reset_eat);
28 STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
29 STATIC_DCL void FDECL(cprefx, (int));
30 STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *));
31 STATIC_DCL void FDECL(givit, (int,struct permonst *));
32 STATIC_DCL void FDECL(cpostfx, (int));
33 STATIC_DCL void FDECL(start_tin, (struct obj *));
34 STATIC_DCL int FDECL(eatcorpse, (struct obj *));
35 STATIC_DCL void FDECL(start_eating, (struct obj *));
36 STATIC_DCL void FDECL(fprefx, (struct obj *));
37 STATIC_DCL void FDECL(accessory_has_effect, (struct obj *));
38 STATIC_DCL void FDECL(fpostfx, (struct obj *));
39 STATIC_DCL int NDECL(bite);
40 STATIC_DCL int FDECL(edibility_prompts, (struct obj *));
41 STATIC_DCL int FDECL(rottenfood, (struct obj *));
42 STATIC_DCL void NDECL(eatspecial);
43 STATIC_DCL void FDECL(eataccessory, (struct obj *));
44 STATIC_DCL const char *FDECL(foodword, (struct obj *));
45 STATIC_DCL boolean FDECL(maybe_cannibal, (int,BOOLEAN_P));
51 /* hunger texts used on bottom line (each 8 chars long) */
60 /* also used to see if you're allowed to eat cats and dogs */
61 #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
65 STATIC_DCL NEARDATA const char comestibles[];
66 STATIC_DCL NEARDATA const char allobj[];
67 STATIC_DCL boolean force_save_hs;
71 STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
73 /* Gold must come first for getobj(). */
74 STATIC_OVL NEARDATA const char allobj[] = {
75 COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
76 WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS,
77 GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 };
79 STATIC_OVL boolean force_save_hs = FALSE;
81 const char *hu_stat[] = {
95 * Decide whether a particular object can be eaten by the possibly
96 * polymorphed character. Not used for monster checks.
100 register struct obj *obj;
102 /* protect invocation tools but not Rider corpses (handled elsewhere)*/
103 /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
104 if (objects[obj->otyp].oc_unique)
106 /* above also prevents the Amulet from being eaten, so we must never
107 allow fake amulets to be eaten either [which is already the case] */
109 if (metallivorous(youmonst.data) && is_metallic(obj) &&
110 (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj)))
112 if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) &&
113 /* [g.cubes can eat containers and retain all contents
114 as engulfed items, but poly'd player can't do that] */
118 /* return((boolean)(!!index(comestibles, obj->oclass))); */
119 return (boolean)(obj->oclass == FOOD_CLASS);
132 static const struct { const char *txt; int nut; } tintxts[] = {
135 {"soup made from", 20},
139 #define HOMEMADE_TIN 5
146 #define FRENCH_FRIED_TIN 11
147 {"french fried", 40},
153 #define TTSZ SIZE(tintxts)
155 static NEARDATA struct {
157 int usedtime, reqtime;
160 static NEARDATA struct {
161 struct obj *piece; /* the thing being eaten, or last thing that
162 * was partially eaten, unless that thing was
163 * a tin, which uses the tin structure above,
164 * in which case this should be 0 */
165 /* doeat() initializes these when piece is valid */
166 int usedtime, /* turns spent eating */
167 reqtime; /* turns required to eat */
168 int nmod; /* coded nutrition per turn */
169 Bitfield(canchoke,1); /* was satiated at beginning */
171 /* start_eating() initializes these */
172 Bitfield(fullwarn,1); /* have warned about being full */
173 Bitfield(eating,1); /* victual currently being eaten */
174 Bitfield(doreset,1); /* stop eating at end of turn */
177 static char *eatmbuf = 0; /* set by cpostfx() */
181 eatmdone() /* called after mimicing is over */
183 /* release `eatmbuf' */
185 if (nomovemsg == eatmbuf) nomovemsg = 0;
186 free((genericptr_t)eatmbuf), eatmbuf = 0;
189 if (youmonst.m_ap_type) {
190 youmonst.m_ap_type = M_AP_NOTHING;
196 /* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */
197 STATIC_OVL const char *
198 food_xname(food, the_pfx)
203 int mnum = food->corpsenm;
205 if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) {
206 /* grab xname()'s modifiable return buffer for our own use */
207 char *bufp = xname(food);
208 Sprintf(bufp, "%s%s corpse",
209 (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "",
210 s_suffix(mons[mnum].mname));
213 /* the ordinary case */
214 result = singular(food, xname);
215 if (the_pfx) result = the(result);
220 /* Created by GAN 01/28/87
221 * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
222 * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk.
223 * 11/10/89: if hard, rarely vomit anyway, for slim chance.
226 choke(food) /* To a full belly all food is bad. (It.) */
227 register struct obj *food;
229 /* only happens if you were satiated */
230 if (u.uhs != SATIATED) {
231 if (!food || food->otyp != AMULET_OF_STRANGULATION)
233 } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
234 adjalign(-1); /* gluttony is unchivalrous */
235 You_feel("like a glutton!");
238 exercise(A_CON, FALSE);
240 if (Breathless || (!Strangled && !rn2(20))) {
241 /* choking by eating AoS doesn't involve stuffing yourself */
242 if (food && food->otyp == AMULET_OF_STRANGULATION) {
243 You("choke, but recover your composure.");
246 You("stuff yourself and then vomit voluminously.");
247 morehungry(1000); /* you just got *very* sick! */
251 killer_format = KILLED_BY_AN;
253 * Note all "killer"s below read "Choked on %s" on the
254 * high score list & tombstone. So plan accordingly.
257 You("choke over your %s.", foodword(food));
258 if (food->oclass == COIN_CLASS) {
259 killer = "a very rich meal";
261 killer = food_xname(food, FALSE);
262 if (food->otyp == CORPSE &&
263 (mons[food->corpsenm].geno & G_UNIQ)) {
264 if (!type_is_pname(&mons[food->corpsenm]))
265 killer = the(killer);
266 killer_format = KILLED_BY;
270 You("choke over it.");
271 killer = "quick snack";
278 /* modify object wt. depending on time spent consuming it */
282 struct obj *piece = victual.piece;
285 debugpline("Old weight = %d", piece->owt);
286 debugpline("Used time = %d, Req'd time = %d",
287 victual.usedtime, victual.reqtime);
289 piece->owt = weight(piece);
291 debugpline("New weight = %d", piece->owt);
296 reset_eat() /* called when eating interrupted by an event */
298 /* we only set a flag here - the actual reset process is done after
299 * the round is spent eating.
301 if(victual.eating && !victual.doreset) {
303 debugpline("reset_eat...");
305 victual.doreset = TRUE;
310 STATIC_OVL struct obj *
312 register struct obj *otmp;
314 if (otmp->quan > 1L) {
316 (void) splitobj(otmp, otmp->quan - 1L);
318 otmp = splitobj(otmp, 1L);
320 debugpline("split object,");
325 if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
328 /* create a dummy duplicate to put on bill */
329 verbalize("You bit it, you bought it!");
330 bill_dummy_object(otmp);
332 otmp->oeaten = (otmp->otyp == CORPSE ?
333 mons[otmp->corpsenm].cnutrit :
334 objects[otmp->otyp].oc_nutrition);
339 if (inv_cnt() >= 52) {
340 sellobj_state(SELL_DONTSELL);
342 sellobj_state(SELL_NORMAL);
344 otmp->oxlth++; /* hack to prevent merge */
352 /* When food decays, in the middle of your meal, we don't want to dereference
353 * any dangling pointers, so set it to null (which should still trigger
354 * do_reset_eat() at the beginning of eatfood()) and check for null pointers
359 register struct obj *obj;
361 if (obj == victual.piece) victual.piece = (struct obj *)0;
362 if (obj->timed) obj_stop_timers(obj);
365 /* renaming an object usually results in it having a different address;
366 so the sequence start eating/opening, get interrupted, name the food,
367 resume eating/opening would restart from scratch */
369 food_substitution(old_obj, new_obj)
370 struct obj *old_obj, *new_obj;
372 if (old_obj == victual.piece) victual.piece = new_obj;
373 if (old_obj == tin.tin) tin.tin = new_obj;
380 debugpline("do_reset_eat...");
383 victual.piece = touchfood(victual.piece);
386 victual.fullwarn = victual.eating = victual.doreset = FALSE;
387 /* Do not set canchoke to FALSE; if we continue eating the same object
388 * we need to know if canchoke was set when they started eating it the
389 * previous time. And if we don't continue eating the same object
390 * canchoke always gets recalculated anyway.
398 eatfood() /* called each move during eating process */
401 (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) {
402 /* maybe it was stolen? */
406 if(!victual.eating) return(0);
408 if(++victual.usedtime <= victual.reqtime) {
409 if(bite()) return(0);
410 return(1); /* still busy */
421 victual.piece->in_use = TRUE;
422 occupation = 0; /* do this early, so newuhs() knows we're done */
425 if (message) pline(nomovemsg);
428 You("finish eating %s.", food_xname(victual.piece, TRUE));
430 if(victual.piece->otyp == CORPSE)
431 cpostfx(victual.piece->corpsenm);
433 fpostfx(victual.piece);
435 if (carried(victual.piece)) useup(victual.piece);
436 else useupf(victual.piece, 1L);
437 victual.piece = (struct obj *) 0;
438 victual.fullwarn = victual.eating = victual.doreset = FALSE;
442 maybe_cannibal(pm, allowmsg)
446 if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) {
449 You("have a bad feeling deep inside.");
450 You("cannibal! You will regret this!");
452 HAggravate_monster |= FROMOUTSIDE;
453 change_luck(-rn1(4,2)); /* -5..-2 */
463 (void) maybe_cannibal(pm,TRUE);
464 if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) {
465 if (!Stone_resistance &&
466 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
467 Sprintf(killer_buf, "tasting %s meat", mons[pm].mname);
468 killer_format = KILLED_BY;
470 You("turn to stone.");
473 victual.eating = FALSE;
474 return; /* lifesaved */
485 if (!CANNIBAL_ALLOWED()) {
486 You_feel("that eating the %s was a bad idea.", mons[pm].mname);
487 HAggravate_monster |= FROMOUTSIDE;
491 if (Stoned) fix_petrification();
497 pline("Eating that is instantly fatal.");
498 Sprintf(buf, "unwisely ate the body of %s",
501 killer_format = NO_KILLER_PREFIX;
503 /* It so happens that since we know these monsters */
504 /* cannot appear in tins, victual.piece will always */
505 /* be what we want, which is not generally true. */
506 if (revive_corpse(victual.piece))
507 victual.piece = (struct obj *)0;
511 if (!Slimed && !Unchanging && !flaming(youmonst.data) &&
512 youmonst.data != &mons[PM_GREEN_SLIME]) {
513 You("don't feel very well.");
519 if (acidic(&mons[pm]) && Stoned)
531 pline("What a pity - you just ruined a future piece of %sart!",
532 ACURR(A_CHA) > 15 ? "fine " : "");
538 * If you add an intrinsic that can be gotten by eating a monster, add it
539 * to intrinsic_possible() and givit(). (It must already be in prop.h to
540 * be an intrinsic property.)
541 * It would be very easy to make the intrinsics not try to give you one
542 * that you already had by checking to see if you have it in
543 * intrinsic_possible() instead of givit().
546 /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
548 intrinsic_possible(type, ptr)
550 register struct permonst *ptr;
555 if (ptr->mconveys & MR_FIRE) {
556 debugpline("can get fire resistance");
558 } else return(FALSE);
560 return(ptr->mconveys & MR_FIRE);
564 if (ptr->mconveys & MR_SLEEP) {
565 debugpline("can get sleep resistance");
567 } else return(FALSE);
569 return(ptr->mconveys & MR_SLEEP);
573 if (ptr->mconveys & MR_COLD) {
574 debugpline("can get cold resistance");
576 } else return(FALSE);
578 return(ptr->mconveys & MR_COLD);
582 if (ptr->mconveys & MR_DISINT) {
583 debugpline("can get disintegration resistance");
585 } else return(FALSE);
587 return(ptr->mconveys & MR_DISINT);
589 case SHOCK_RES: /* shock (electricity) resistance */
591 if (ptr->mconveys & MR_ELEC) {
592 debugpline("can get shock resistance");
594 } else return(FALSE);
596 return(ptr->mconveys & MR_ELEC);
600 if (ptr->mconveys & MR_POISON) {
601 debugpline("can get poison resistance");
603 } else return(FALSE);
605 return(ptr->mconveys & MR_POISON);
609 if (can_teleport(ptr)) {
610 debugpline("can get teleport");
612 } else return(FALSE);
614 return(can_teleport(ptr));
616 case TELEPORT_CONTROL:
618 if (control_teleport(ptr)) {
619 debugpline("can get teleport control");
621 } else return(FALSE);
623 return(control_teleport(ptr));
627 if (telepathic(ptr)) {
628 debugpline("can get telepathy");
630 } else return(FALSE);
632 return(telepathic(ptr));
640 /* givit() tries to give you an intrinsic based on the monster's level
641 * and what type of intrinsic it is trying to give you.
646 register struct permonst *ptr;
651 debugpline("Attempting to give intrinsic %d", type);
653 /* some intrinsics are easier to get than others */
656 if ((ptr == &mons[PM_KILLER_BEE] ||
657 ptr == &mons[PM_SCORPION]) && !rn2(4))
665 case TELEPORT_CONTROL:
676 if (ptr->mlevel <= rn2(chance))
677 return; /* failed die roll */
682 debugpline("Trying to give fire resistance");
684 if(!(HFire_resistance & FROMOUTSIDE)) {
685 You(Hallucination ? "be chillin'." :
686 "feel a momentary chill.");
687 HFire_resistance |= FROMOUTSIDE;
692 debugpline("Trying to give sleep resistance");
694 if(!(HSleep_resistance & FROMOUTSIDE)) {
695 You_feel("wide awake.");
696 HSleep_resistance |= FROMOUTSIDE;
701 debugpline("Trying to give cold resistance");
703 if(!(HCold_resistance & FROMOUTSIDE)) {
704 You_feel("full of hot air.");
705 HCold_resistance |= FROMOUTSIDE;
710 debugpline("Trying to give disintegration resistance");
712 if(!(HDisint_resistance & FROMOUTSIDE)) {
713 You_feel(Hallucination ?
714 "totally together, man." :
716 HDisint_resistance |= FROMOUTSIDE;
719 case SHOCK_RES: /* shock (electricity) resistance */
721 debugpline("Trying to give shock resistance");
723 if(!(HShock_resistance & FROMOUTSIDE)) {
725 You_feel("grounded in reality.");
727 Your("health currently feels amplified!");
728 HShock_resistance |= FROMOUTSIDE;
733 debugpline("Trying to give poison resistance");
735 if(!(HPoison_resistance & FROMOUTSIDE)) {
736 You_feel(Poison_resistance ?
737 "especially healthy." : "healthy.");
738 HPoison_resistance |= FROMOUTSIDE;
743 debugpline("Trying to give teleport");
745 if(!(HTeleportation & FROMOUTSIDE)) {
746 You_feel(Hallucination ? "diffuse." :
748 HTeleportation |= FROMOUTSIDE;
751 case TELEPORT_CONTROL:
753 debugpline("Trying to give teleport control");
755 if(!(HTeleport_control & FROMOUTSIDE)) {
756 You_feel(Hallucination ?
757 "centered in your personal space." :
758 "in control of yourself.");
759 HTeleport_control |= FROMOUTSIDE;
764 debugpline("Trying to give telepathy");
766 if(!(HTelepat & FROMOUTSIDE)) {
767 You_feel(Hallucination ?
768 "in touch with the cosmos." :
769 "a strange mental acuity.");
770 HTelepat |= FROMOUTSIDE;
771 /* If blind, make sure monsters show up. */
772 if (Blind) see_monsters();
777 debugpline("Tried to give an impossible intrinsic");
784 cpostfx(pm) /* called after completely consuming a corpse */
787 register int tmp = 0;
788 boolean catch_lycanthropy = FALSE;
790 /* in case `afternmv' didn't get called for previously mimicking
791 gold, clean up now to avoid `eatmbuf' memory leak */
792 if (eatmbuf) (void)eatmdone();
796 /* MRKR: "eye of newt" may give small magical energy boost */
797 if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) {
800 if (u.uen > u.uenmax) {
801 if (!rn2(3)) u.uenmax++;
804 if (old_uen != u.uen) {
805 You_feel("a mild buzz.");
813 case PM_HUMAN_WERERAT:
814 catch_lycanthropy = TRUE;
815 u.ulycn = PM_WERERAT;
817 case PM_HUMAN_WEREJACKAL:
818 catch_lycanthropy = TRUE;
819 u.ulycn = PM_WEREJACKAL;
821 case PM_HUMAN_WEREWOLF:
822 catch_lycanthropy = TRUE;
823 u.ulycn = PM_WEREWOLF;
826 if (Upolyd) u.mh = u.mhmax;
827 else u.uhp = u.uhpmax;
832 set_itimeout(&HInvis, (long)rn1(100, 50));
833 if (!Blind && !BInvis) self_invis_message();
835 if (!(HInvis & INTRINSIC)) You_feel("hidden!");
836 HInvis |= FROMOUTSIDE;
837 HSee_invisible |= FROMOUTSIDE;
840 /* fall into next case */
841 case PM_YELLOW_LIGHT:
842 /* fall into next case */
844 make_stunned(HStun + 30,FALSE);
845 /* fall into next case */
847 make_stunned(HStun + 30,FALSE);
851 /* fall into next case */
854 /* fall into next case */
857 if (youmonst.data->mlet != S_MIMIC && !Unchanging) {
859 You_cant("resist the temptation to mimic %s.",
860 Hallucination ? "an orange" : "a pile of gold");
862 /* A pile of gold can't ride. */
863 if (u.usteed) dismount_steed(DISMOUNT_FELL);
866 Sprintf(buf, Hallucination ?
867 "You suddenly dread being peeled and mimic %s again!" :
868 "You now prefer mimicking %s again.",
869 an(Upolyd ? youmonst.data->mname : urace.noun));
870 eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf);
873 /* ??? what if this was set before? */
874 youmonst.m_ap_type = M_AP_OBJECT;
875 youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE;
878 /* make gold symbol show up now */
879 display_nhwindow(WIN_MAP, TRUE);
882 case PM_QUANTUM_MECHANIC:
883 Your("velocity suddenly seems very uncertain!");
884 if (HFast & INTRINSIC) {
888 HFast |= FROMOUTSIDE;
893 if (HStun > 2) make_stunned(2L,FALSE);
894 if (HConfusion > 2) make_confused(2L,FALSE);
897 case PM_DOPPELGANGER:
898 /* case PM_SANDESTIN: */
900 You_feel("a change coming over you.");
905 case PM_MASTER_MIND_FLAYER:
906 if (ABASE(A_INT) < ATTRMAX(A_INT)) {
908 pline("Yum! That was real brain food!");
909 (void) adjattrib(A_INT, 1, FALSE);
910 break; /* don't give them telepathy, too */
914 pline("For some reason, that tasted bland.");
916 /* fall through to default case */
918 register struct permonst *ptr = &mons[pm];
921 if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) ||
922 pm == PM_VIOLET_FUNGUS) {
923 pline ("Oh wow! Great stuff!");
924 make_hallucinated(HHallucination + 200,FALSE,0L);
926 if(is_giant(ptr)) gainstr((struct obj *)0, 0);
928 /* Check the monster for all of the intrinsics. If this
929 * monster can give more than one, pick one to try to give
930 * from among all it can give.
932 * If a monster can give 4 intrinsics then you have
933 * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first,
934 * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second,
935 * a 1/3 * 3/4 = 1/4 chance of getting the third,
936 * and a 1/4 chance of getting the fourth.
938 * And now a proof by induction:
939 * it works for 1 intrinsic (1 in 1 of getting it)
940 * for 2 you have a 1 in 2 chance of getting the second,
941 * otherwise you keep the first
942 * for 3 you have a 1 in 3 chance of getting the third,
943 * otherwise you keep the first or the second
944 * for n+1 you have a 1 in n+1 chance of getting the (n+1)st,
945 * otherwise you keep the previous one.
946 * Elliott Kleinrock, October 5, 1990
949 count = 0; /* number of possible intrinsics */
950 tmp = 0; /* which one we will try to give */
951 for (i = 1; i <= LAST_PROP; i++) {
952 if (intrinsic_possible(i, ptr)) {
954 /* a 1 in count chance of replacing the old
955 * one with this one, and a count-1 in count
956 * chance of keeping the old one. (note
957 * that 1 in 1 and 0 in 1 are what we want
962 debugpline("Intrinsic %d replacing %d",
970 /* if any found try to give them one */
971 if (count) givit(tmp, ptr);
976 if (catch_lycanthropy && defends(AD_WERE, uwep)) {
977 if (!touch_artifact(uwep, &youmonst)) {
987 violated_vegetarian()
989 u.uconduct.unvegetarian++;
990 if (Role_if(PM_MONK)) {
997 /* common code to check and possibly charge for 1 context.tin.tin,
998 * will split() context.tin.tin if necessary */
1002 const char* verb; /* if 0, the verb is "open" */
1004 if(((!carried(tin.tin) &&
1005 costly_spot(tin.tin->ox, tin.tin->oy) &&
1006 !tin.tin->no_charge)
1007 || tin.tin->unpaid)) {
1008 verbalize("You %s it, you bought it!", verb ? verb : "open");
1009 if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L);
1010 bill_dummy_object(tin.tin);
1016 opentin() /* called during each move whilst opening a tin */
1022 if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy))
1023 /* perhaps it was stolen? */
1024 return(0); /* %% probably we should use tinoid */
1025 if(tin.usedtime++ >= 50) {
1026 You("give up your attempt to open the tin.");
1029 if(tin.usedtime < tin.reqtime)
1030 return(1); /* still busy */
1031 if(tin.tin->otrapped ||
1032 (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) {
1033 b_trapped("tin", 0);
1034 costly_tin("destroyed");
1037 You("succeed in opening the tin.");
1038 if(tin.tin->spe != 1) {
1039 if (tin.tin->corpsenm == NON_PM) {
1040 pline("It turns out to be empty.");
1041 tin.tin->dknown = tin.tin->known = TRUE;
1042 costly_tin((const char*)0);
1045 r = tin.tin->cursed ? ROTTEN_TIN : /* always rotten if cursed */
1046 (tin.tin->spe == -1) ? HOMEMADE_TIN : /* player made it */
1047 rn2(TTSZ-1); /* else take your pick */
1048 if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD ||
1049 tin.tin->corpsenm == PM_LICHEN))
1050 r = HOMEMADE_TIN; /* lizards don't rot */
1051 else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7))
1052 r = ROTTEN_TIN; /* some homemade tins go bad */
1053 which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
1054 if (Hallucination) {
1057 what = mons[tin.tin->corpsenm].mname;
1058 if (mons[tin.tin->corpsenm].geno & G_UNIQ)
1059 which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2;
1061 if (which == 0) what = makeplural(what);
1062 pline("It smells like %s%s.", (which == 2) ? "the " : "", what);
1063 if (yn("Eat it?") == 'n') {
1064 if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE;
1065 if (flags.verbose) You("discard the open tin.");
1066 costly_tin((const char*)0);
1069 /* in case stop_occupation() was called on previous meal */
1070 victual.piece = (struct obj *)0;
1071 victual.fullwarn = victual.eating = victual.doreset = FALSE;
1073 You("consume %s %s.", tintxts[r].txt,
1074 mons[tin.tin->corpsenm].mname);
1078 if (!vegan(&mons[tin.tin->corpsenm]))
1079 u.uconduct.unvegan++;
1080 if (!vegetarian(&mons[tin.tin->corpsenm]))
1081 violated_vegetarian();
1083 tin.tin->dknown = tin.tin->known = TRUE;
1084 cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm);
1086 /* charge for one at pre-eating cost */
1087 costly_tin((const char*)0);
1089 /* check for vomiting added by GAN 01/16/87 */
1090 if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE);
1091 else lesshungry(tintxts[r].nut);
1093 if(r == 0 || r == FRENCH_FRIED_TIN) {
1094 /* Assume !Glib, because you can't open tins when Glib. */
1095 incr_itimeout(&Glib, rnd(15));
1096 pline("Eating deep fried food made your %s very slippery.",
1097 makeplural(body_part(FINGER)));
1100 if (tin.tin->cursed)
1101 pline("It contains some decaying%s%s substance.",
1102 Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN));
1104 pline("It contains spinach.");
1106 if (yn("Eat it?") == 'n') {
1107 if (!Hallucination && !tin.tin->cursed)
1108 tin.tin->dknown = tin.tin->known = TRUE;
1110 You("discard the open tin.");
1111 costly_tin((const char*)0);
1115 tin.tin->dknown = tin.tin->known = TRUE;
1116 costly_tin((const char*)0);
1118 if (!tin.tin->cursed)
1119 pline("This makes you feel like %s!",
1120 Hallucination ? "Swee'pea" : "Popeye");
1122 gainstr(tin.tin, 0);
1126 if (carried(tin.tin)) useup(tin.tin);
1127 else useupf(tin.tin, 1L);
1128 tin.tin = (struct obj *) 0;
1133 start_tin(otmp) /* called when starting to open a tin */
1134 register struct obj *otmp;
1138 if (metallivorous(youmonst.data)) {
1139 You("bite right into the metal tin...");
1141 } else if (nolimbs(youmonst.data)) {
1142 You("cannot handle the tin properly to open it.");
1144 } else if (otmp->blessed) {
1145 pline_The("tin opens like magic!");
1148 switch(uwep->otyp) {
1167 pline("Using your %s you try to open the tin.",
1168 aobjnam(uwep, (char *)0));
1171 pline("It is not so easy to open this tin.");
1173 pline_The("tin slips from your %s.",
1174 makeplural(body_part(FINGER)));
1175 if(otmp->quan > 1L) {
1176 otmp = splitobj(otmp, 1L);
1178 if (carried(otmp)) dropx(otmp);
1179 else stackobj(otmp);
1182 tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10);
1187 set_occupation(opentin, "opening the tin", 0);
1192 Hear_again() /* called when waking up after fainting */
1198 /* called on the "first bite" of rotten food */
1203 pline("Blecch! Rotten %s!", foodword(obj));
1205 if (Hallucination) You_feel("rather trippy.");
1206 else You_feel("rather %s.", body_part(LIGHT_HEADED));
1207 make_confused(HConfusion + d(2,4),FALSE);
1208 } else if(!rn2(4) && !Blind) {
1209 pline("Everything suddenly goes dark.");
1210 make_blinded((long)d(2,10),FALSE);
1211 if (!Blind) Your(vision_clears);
1212 } else if(!rn2(3)) {
1213 const char *what, *where;
1215 what = "goes", where = "dark";
1216 else if (Levitation || Is_airlevel(&u.uz) ||
1217 Is_waterlevel(&u.uz))
1218 what = "you lose control of", where = "yourself";
1220 what = "you slap against the", where =
1222 (u.usteed) ? "saddle" :
1225 pline_The("world spins and %s %s.", what, where);
1228 nomovemsg = "You are conscious again.";
1229 afternmv = Hear_again;
1236 eatcorpse(otmp) /* called when a corpse is selected as food */
1237 register struct obj *otmp;
1239 int tp = 0, mnum = otmp->corpsenm;
1241 boolean uniq = !!(mons[mnum].geno & G_UNIQ);
1243 boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance &&
1244 !poly_when_stoned(youmonst.data));
1247 if (!vegan(&mons[mnum])) u.uconduct.unvegan++;
1248 if (!vegetarian(&mons[mnum])) violated_vegetarian();
1250 if (mnum != PM_LIZARD && mnum != PM_LICHEN) {
1251 long age = peek_at_iced_corpse_age(otmp);
1253 rotted = (monstermoves - age)/(10L + rn2(20));
1254 if (otmp->cursed) rotted += 2L;
1255 else if (otmp->blessed) rotted -= 2L;
1258 if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) {
1259 boolean cannibal = maybe_cannibal(mnum, FALSE);
1260 pline("Ulch - that %s was tainted%s!",
1261 mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" :
1262 !vegetarian(&mons[mnum]) ? "meat" : "protoplasm",
1263 cannibal ? " cannibal" : "");
1264 if (Sick_resistance) {
1265 pline("It doesn't seem at all sickening, though...");
1270 sick_time = (long) rn1(10, 10);
1271 /* make sure new ill doesn't result in improvement */
1272 if (Sick && (sick_time > Sick))
1273 sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1275 Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE));
1277 Sprintf(buf, "%s%s rotted corpse",
1278 !type_is_pname(&mons[mnum]) ? "the " : "",
1279 s_suffix(mons[mnum].mname));
1280 make_sick(sick_time, buf, TRUE, SICK_VOMITABLE);
1282 if (carried(otmp)) useup(otmp);
1283 else useupf(otmp, 1L);
1285 } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1287 You("have a very bad case of stomach acid."); /* not body_part() */
1288 losehp(rnd(15), "acidic corpse", KILLED_BY_AN);
1289 } else if (poisonous(&mons[mnum]) && rn2(5)) {
1291 pline("Ecch - that must have been poisonous!");
1292 if(!Poison_resistance) {
1294 losehp(rnd(15), "poisonous corpse", KILLED_BY_AN);
1295 } else You("seem unaffected by the poison.");
1296 /* now any corpse left too long will make you mildly ill */
1297 } else if ((rotted > 5L || (rotted > 3L && rn2(5)))
1298 && !Sick_resistance) {
1300 You_feel("%ssick.", (Sick) ? "very " : "");
1301 losehp(rnd(8), "cadaver", KILLED_BY_AN);
1304 /* delay is weight dependent */
1305 victual.reqtime = 3 + (mons[mnum].cwt >> 6);
1307 if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN &&
1308 (otmp->orotten || !rn2(7))) {
1309 if (rottenfood(otmp)) {
1310 otmp->orotten = TRUE;
1311 (void)touchfood(otmp);
1315 if (!mons[otmp->corpsenm].cnutrit) {
1316 /* no nutrution: rots away, no message if you passed out */
1317 if (!retcode) pline_The("corpse rots away completely.");
1318 if (carried(otmp)) useup(otmp);
1319 else useupf(otmp, 1L);
1323 if (!retcode) consume_oeaten(otmp, 2); /* oeaten >>= 2 */
1326 !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "",
1327 food_xname(otmp, FALSE),
1328 (vegan(&mons[mnum]) ?
1329 (!carnivorous(youmonst.data) && herbivorous(youmonst.data)) :
1330 (carnivorous(youmonst.data) && !herbivorous(youmonst.data)))
1331 ? "is delicious" : "tastes terrible");
1338 start_eating(otmp) /* called as you start to eat */
1339 register struct obj *otmp;
1342 debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece);
1343 debugpline("reqtime = %d", victual.reqtime);
1344 debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1345 debugpline("nmod = %d", victual.nmod);
1346 debugpline("oeaten = %d", otmp->oeaten);
1348 victual.fullwarn = victual.doreset = FALSE;
1349 victual.eating = TRUE;
1351 if (otmp->otyp == CORPSE) {
1352 cprefx(victual.piece->corpsenm);
1353 if (!victual.piece || !victual.eating) {
1354 /* rider revived, or died and lifesaved */
1361 if (++victual.usedtime >= victual.reqtime) {
1362 /* print "finish eating" message if they just resumed -dlc */
1363 done_eating(victual.reqtime > 1 ? TRUE : FALSE);
1367 Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1368 set_occupation(eatfood, msgbuf, 0);
1373 * called on "first bite" of (non-corpse) food.
1374 * used for non-rotten non-tin non-corpse food
1380 switch(otmp->otyp) {
1382 if(u.uhunger <= 200)
1383 pline(Hallucination ? "Oh wow, like, superior, man!" :
1384 "That food really hit the spot!");
1385 else if(u.uhunger <= 700) pline("That satiated your %s!",
1386 body_part(STOMACH));
1389 if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1390 pline("That tripe ration was surprisingly good!");
1391 else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC)))
1392 pline(Hallucination ? "Tastes great! Less filling!" :
1393 "Mmm, tripe... not bad!");
1395 pline("Yak - dog food!");
1396 more_experienced(1,0);
1398 /* not cannibalism, but we use similar criteria
1399 for deciding whether to be sickened by this meal */
1400 if (rn2(2) && !CANNIBAL_ALLOWED())
1401 make_vomiting((long)rn1(victual.reqtime, 14), FALSE);
1406 case HUGE_CHUNK_OF_MEAT:
1410 case CLOVE_OF_GARLIC:
1411 if (is_undead(youmonst.data)) {
1412 make_vomiting((long)rn1(victual.reqtime, 5), FALSE);
1415 /* Fall through otherwise */
1417 if (otmp->otyp==SLIME_MOLD && !otmp->cursed
1418 && otmp->spe == current_fruit)
1419 pline("My, that was a %s %s!",
1420 Hallucination ? "primo" : "yummy",
1421 singular(otmp, xname));
1424 if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1425 if (!Hallucination) pline("Core dumped.");
1427 /* This is based on an old Usenet joke, a fake a.out manual page */
1430 pline("Segmentation fault -- core dumped.");
1432 pline("Bus error -- core dumped.");
1433 else pline("Yo' mama -- core dumped.");
1437 #ifdef MAC /* KMH -- Why should Unix have all the fun? */
1438 if (otmp->otyp == APPLE) {
1439 pline("Delicious! Must be a Macintosh!");
1442 if (otmp->otyp == EGG && stale_egg(otmp)) {
1443 pline("Ugh. Rotten egg."); /* perhaps others like it */
1444 make_vomiting(Vomiting+d(10,4), TRUE);
1447 pline("This %s is %s", singular(otmp, xname),
1448 otmp->cursed ? (Hallucination ? "grody!" : "terrible!") :
1449 (otmp->otyp == CRAM_RATION
1450 || otmp->otyp == K_RATION
1451 || otmp->otyp == C_RATION)
1453 Hallucination ? "gnarly!" : "delicious!");
1459 accessory_has_effect(otmp)
1462 pline("Magic spreads through your body as you digest the %s.",
1463 otmp->oclass == RING_CLASS ? "ring" : "amulet");
1470 int typ = otmp->otyp;
1473 /* Note: rings are not so common that this is unbalancing. */
1474 /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1475 oldprop = u.uprops[objects[typ].oc_oprop].intrinsic;
1476 if (otmp == uleft || otmp == uright) {
1478 if (u.uhp <= 0) return; /* died from sink fall */
1480 otmp->known = otmp->dknown = 1; /* by taste */
1481 if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) {
1482 switch (otmp->otyp) {
1484 if (!objects[typ].oc_oprop) break; /* should never happen */
1486 if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1487 accessory_has_effect(otmp);
1489 u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1492 case RIN_SEE_INVISIBLE:
1493 set_mimic_blocking();
1495 if (Invis && !oldprop && !ESee_invisible &&
1496 !perceives(youmonst.data) && !Blind) {
1498 pline("Suddenly you can see yourself.");
1502 case RIN_INVISIBILITY:
1503 if (!oldprop && !EInvis && !BInvis &&
1504 !See_invisible && !Blind) {
1506 Your("body takes on a %s transparency...",
1507 Hallucination ? "normal" : "strange");
1511 case RIN_PROTECTION_FROM_SHAPE_CHAN:
1514 case RIN_LEVITATION:
1515 /* undo the `.intrinsic |= FROMOUTSIDE' done above */
1516 u.uprops[LEVITATION].intrinsic = oldprop;
1519 incr_itimeout(&HLevitation, d(10,20));
1526 accessory_has_effect(otmp);
1527 if (adjattrib(A_CHA, otmp->spe, -1))
1530 case RIN_GAIN_STRENGTH:
1531 accessory_has_effect(otmp);
1532 if (adjattrib(A_STR, otmp->spe, -1))
1535 case RIN_GAIN_CONSTITUTION:
1536 accessory_has_effect(otmp);
1537 if (adjattrib(A_CON, otmp->spe, -1))
1540 case RIN_INCREASE_ACCURACY:
1541 accessory_has_effect(otmp);
1542 u.uhitinc += otmp->spe;
1544 case RIN_INCREASE_DAMAGE:
1545 accessory_has_effect(otmp);
1546 u.udaminc += otmp->spe;
1548 case RIN_PROTECTION:
1549 accessory_has_effect(otmp);
1550 HProtection |= FROMOUTSIDE;
1551 u.ublessed += otmp->spe;
1554 case RIN_FREE_ACTION:
1555 /* Give sleep resistance instead */
1556 if (!(HSleep_resistance & FROMOUTSIDE))
1557 accessory_has_effect(otmp);
1558 if (!Sleep_resistance)
1559 You_feel("wide awake.");
1560 HSleep_resistance |= FROMOUTSIDE;
1562 case AMULET_OF_CHANGE:
1563 accessory_has_effect(otmp);
1566 You("are suddenly very %s!",
1567 flags.female ? "feminine" : "masculine");
1570 case AMULET_OF_UNCHANGING:
1571 /* un-change: it's a pun */
1572 if (!Unchanging && Upolyd) {
1573 accessory_has_effect(otmp);
1578 case AMULET_OF_STRANGULATION: /* bad idea! */
1579 /* no message--this gives no permanent effect */
1582 case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */
1583 if (!(HSleeping & FROMOUTSIDE))
1584 accessory_has_effect(otmp);
1585 HSleeping = FROMOUTSIDE | rnd(100);
1587 case RIN_SUSTAIN_ABILITY:
1588 case AMULET_OF_LIFE_SAVING:
1589 case AMULET_OF_REFLECTION: /* nice try */
1590 /* can't eat Amulet of Yendor or fakes,
1591 * and no oc_prop even if you could -3.
1599 eatspecial() /* called after eating non-food */
1601 register struct obj *otmp = victual.piece;
1603 /* lesshungry wants an occupation to handle choke messages correctly */
1604 set_occupation(eatfood, "eating non-food", 0);
1605 lesshungry(victual.nmod);
1607 victual.piece = (struct obj *)0;
1609 if (otmp->oclass == COIN_CLASS) {
1614 if (otmp->where == OBJ_FREE)
1618 useupf(otmp, otmp->quan);
1621 if (otmp->oclass == POTION_CLASS) {
1622 otmp->quan++; /* dopotion() does a useup() */
1623 (void)dopotion(otmp);
1625 if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS)
1627 else if (otmp->otyp == LEASH && otmp->leashmon)
1630 /* KMH -- idea by "Tommy the Terrorist" */
1631 if ((otmp->otyp == TRIDENT) && !otmp->cursed)
1633 pline(Hallucination ? "Four out of five dentists agree." :
1634 "That was pure chewing satisfaction!");
1635 exercise(A_WIS, TRUE);
1637 if ((otmp->otyp == FLINT) && !otmp->cursed)
1639 pline("Yabba-dabba delicious!");
1640 exercise(A_CON, TRUE);
1643 if (otmp == uwep && otmp->quan == 1L) uwepgone();
1644 if (otmp == uquiver && otmp->quan == 1L) uqwepgone();
1645 if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone();
1647 if (otmp == uball) unpunish();
1648 if (otmp == uchain) unpunish(); /* but no useup() */
1649 else if (carried(otmp)) useup(otmp);
1650 else useupf(otmp, 1L);
1653 /* NOTE: the order of these words exactly corresponds to the
1654 order of oc_material values #define'd in objclass.h. */
1655 static const char *foodwords[] = {
1656 "meal", "liquid", "wax", "food", "meat",
1657 "paper", "cloth", "leather", "wood", "bone", "scale",
1658 "metal", "metal", "metal", "silver", "gold", "platinum", "mithril",
1659 "plastic", "glass", "rich food", "stone"
1662 STATIC_OVL const char *
1664 register struct obj *otmp;
1666 if (otmp->oclass == FOOD_CLASS) return "food";
1667 if (otmp->oclass == GEM_CLASS &&
1668 objects[otmp->otyp].oc_material == GLASS &&
1670 makeknown(otmp->otyp);
1671 return foodwords[objects[otmp->otyp].oc_material];
1675 fpostfx(otmp) /* called after consuming (non-corpse) food */
1676 register struct obj *otmp;
1678 switch(otmp->otyp) {
1679 case SPRIG_OF_WOLFSBANE:
1680 if (u.ulycn >= LOW_PM || is_were(youmonst.data))
1684 make_blinded((long)u.ucreamed,TRUE);
1686 case FORTUNE_COOKIE:
1687 outrumor(bcsign(otmp), BY_COOKIE);
1688 if (!Blind) u.uconduct.literate++;
1690 case LUMP_OF_ROYAL_JELLY:
1691 /* This stuff seems to be VERY healthy! */
1694 u.mh += otmp->cursed ? -rnd(20) : rnd(20);
1695 if (u.mh > u.mhmax) {
1696 if (!rn2(17)) u.mhmax++;
1698 } else if (u.mh <= 0) {
1702 u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
1703 if (u.uhp > u.uhpmax) {
1704 if(!rn2(17)) u.uhpmax++;
1706 } else if (u.uhp <= 0) {
1707 killer_format = KILLED_BY_AN;
1708 killer = "rotten lump of royal jelly";
1712 if(!otmp->cursed) heal_legs();
1715 if (touch_petrifies(&mons[otmp->corpsenm])) {
1716 if (!Stone_resistance &&
1717 !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
1718 if (!Stoned) Stoned = 5;
1719 killer_format = KILLED_BY_AN;
1720 Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname);
1721 delayed_killer = killer_buf;
1725 case EUCALYPTUS_LEAF:
1726 if (Sick && !otmp->cursed)
1727 make_sick(0L, (char *)0, TRUE, SICK_ALL);
1728 if (Vomiting && !otmp->cursed)
1729 make_vomiting(0L, TRUE);
1736 * return 0 if the food was not dangerous.
1737 * return 1 if the food was dangerous and you chose to stop.
1738 * return 2 if the food was dangerous and you chose to eat it anyway.
1741 edibility_prompts(otmp)
1744 /* blessed food detection granted you a one-use
1745 ability to detect food that is unfit for consumption
1746 or dangerous and avoid it. */
1748 char buf[BUFSZ], foodsmell[BUFSZ],
1749 it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ];
1750 boolean cadaver = (otmp->otyp == CORPSE),
1751 stoneorslime = FALSE;
1752 int material = objects[otmp->otyp].oc_material,
1753 mnum = otmp->corpsenm;
1756 Strcpy(foodsmell, Tobjnam(otmp, "smell"));
1757 Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they");
1758 Sprintf(eat_it_anyway, "Eat %s anyway?",
1759 (otmp->quan == 1L) ? "it" : "one");
1761 if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) {
1762 /* These checks must match those in eatcorpse() */
1763 stoneorslime = (touch_petrifies(&mons[mnum]) &&
1764 !Stone_resistance &&
1765 !poly_when_stoned(youmonst.data));
1767 if (mnum == PM_GREEN_SLIME)
1768 stoneorslime = (!Unchanging && !flaming(youmonst.data) &&
1769 youmonst.data != &mons[PM_GREEN_SLIME]);
1771 if (cadaver && mnum != PM_LIZARD && mnum != PM_LICHEN) {
1772 long age = peek_at_iced_corpse_age(otmp);
1773 /* worst case rather than random
1774 in this calculation to force prompt */
1775 rotted = (monstermoves - age)/(10L + 0 /* was rn2(20) */);
1776 if (otmp->cursed) rotted += 2L;
1777 else if (otmp->blessed) rotted -= 2L;
1782 * These problems with food should be checked in
1783 * order from most detrimental to least detrimental.
1786 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) {
1788 Sprintf(buf, "%s like %s could be tainted! %s",
1789 foodsmell, it_or_they, eat_it_anyway);
1790 if (yn_function(buf,ynchars,'n')=='n') return 1;
1794 Sprintf(buf, "%s like %s could be something very dangerous! %s",
1795 foodsmell, it_or_they, eat_it_anyway);
1796 if (yn_function(buf,ynchars,'n')=='n') return 1;
1799 if (otmp->orotten || (cadaver && rotted > 3L)) {
1801 Sprintf(buf, "%s like %s could be rotten! %s",
1802 foodsmell, it_or_they, eat_it_anyway);
1803 if (yn_function(buf,ynchars,'n')=='n') return 1;
1806 if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) {
1808 Sprintf(buf, "%s like %s might be poisonous! %s",
1809 foodsmell, it_or_they, eat_it_anyway);
1810 if (yn_function(buf,ynchars,'n')=='n') return 1;
1813 if (cadaver && !vegetarian(&mons[mnum]) &&
1814 !u.uconduct.unvegetarian && Role_if(PM_MONK)) {
1815 Sprintf(buf, "%s unhealthy. %s",
1816 foodsmell, eat_it_anyway);
1817 if (yn_function(buf,ynchars,'n')=='n') return 1;
1820 if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) {
1821 Sprintf(buf, "%s rather acidic. %s",
1822 foodsmell, eat_it_anyway);
1823 if (yn_function(buf,ynchars,'n')=='n') return 1;
1826 if (Upolyd && u.umonnum == PM_RUST_MONSTER &&
1827 is_metallic(otmp) && otmp->oerodeproof) {
1828 Sprintf(buf, "%s disgusting to you right now. %s",
1829 foodsmell, eat_it_anyway);
1830 if (yn_function(buf,ynchars,'n')=='n') return 1;
1835 * Breaks conduct, but otherwise safe.
1838 if (!u.uconduct.unvegan &&
1839 ((material == LEATHER || material == BONE ||
1840 material == DRAGON_HIDE || material == WAX) ||
1841 (cadaver && !vegan(&mons[mnum])))) {
1842 Sprintf(buf, "%s foul and unfamiliar to you. %s",
1843 foodsmell, eat_it_anyway);
1844 if (yn_function(buf,ynchars,'n')=='n') return 1;
1847 if (!u.uconduct.unvegetarian &&
1848 ((material == LEATHER || material == BONE ||
1849 material == DRAGON_HIDE) ||
1850 (cadaver && !vegetarian(&mons[mnum])))) {
1851 Sprintf(buf, "%s unfamiliar to you. %s",
1852 foodsmell, eat_it_anyway);
1853 if (yn_function(buf,ynchars,'n')=='n') return 1;
1857 if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) {
1858 /* Tainted meat with Sick_resistance */
1859 Sprintf(buf, "%s like %s could be tainted! %s",
1860 foodsmell, it_or_they, eat_it_anyway);
1861 if (yn_function(buf,ynchars,'n')=='n') return 1;
1868 doeat() /* generic "eat" command funtion (see cmd.c) */
1870 register struct obj *otmp;
1871 int basenutrit; /* nutrition of full item */
1872 boolean dont_start = FALSE;
1875 pline("If you can't breathe air, how can you consume solids?");
1878 if (!(otmp = floorfood("eat", 0))) return 0;
1879 if (check_capacity((char *)0)) return 0;
1882 int res = edibility_prompts(otmp);
1884 Your("%s stops tingling and your sense of smell returns to normal.",
1887 if (res == 1) return 0;
1891 /* We have to make non-foods take 1 move to eat, unless we want to
1892 * do ridiculous amounts of coding to deal with partly eaten plate
1893 * mails, players who polymorph back to human in the middle of their
1894 * metallic meal, etc....
1896 if (!is_edible(otmp)) {
1897 You("cannot eat that!");
1899 } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL
1904 /* let them eat rings */
1905 You_cant("eat %s you're wearing.", something);
1908 if (is_metallic(otmp) &&
1909 u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) {
1910 otmp->rknown = TRUE;
1911 if (otmp->quan > 1L) {
1913 (void) splitobj(otmp, otmp->quan - 1L);
1915 otmp = splitobj(otmp, 1L);
1917 pline("Ulch - That %s was rustproofed!", xname(otmp));
1918 /* The regurgitated object's rustproofing is gone now */
1919 otmp->oerodeproof = 0;
1920 make_stunned(HStun + rn2(10), TRUE);
1921 You("spit %s out onto the %s.", the(xname(otmp)),
1922 surface(u.ux, u.uy));
1923 if (carried(otmp)) {
1930 /* KMH -- Slow digestion is... indigestible */
1931 if (otmp->otyp == RIN_SLOW_DIGESTION) {
1932 pline("This ring is indigestible!");
1933 (void) rottenfood(otmp);
1934 if (otmp->dknown && !objects[otmp->otyp].oc_name_known
1935 && !objects[otmp->otyp].oc_uname)
1939 if (otmp->oclass != FOOD_CLASS) {
1941 victual.reqtime = 1;
1942 victual.piece = otmp;
1943 /* Don't split it, we don't need to if it's 1 move */
1944 victual.usedtime = 0;
1945 victual.canchoke = (u.uhs == SATIATED);
1946 /* Note: gold weighs 1 pt. for each 1000 pieces (see */
1947 /* pickup.c) so gold and non-gold is consistent. */
1948 if (otmp->oclass == COIN_CLASS)
1949 basenutrit = ((otmp->quan > 200000L) ? 2000
1950 : (int)(otmp->quan/100L));
1951 else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
1952 basenutrit = weight(otmp);
1953 /* oc_nutrition is usually weight anyway */
1954 else basenutrit = objects[otmp->otyp].oc_nutrition;
1955 victual.nmod = basenutrit;
1956 victual.eating = TRUE; /* needed for lesshungry() */
1958 material = objects[otmp->otyp].oc_material;
1959 if (material == LEATHER ||
1960 material == BONE || material == DRAGON_HIDE) {
1961 u.uconduct.unvegan++;
1962 violated_vegetarian();
1963 } else if (material == WAX)
1964 u.uconduct.unvegan++;
1968 (void) rottenfood(otmp);
1970 if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
1971 pline("Ecch - that must have been poisonous!");
1972 if(!Poison_resistance) {
1974 losehp(rnd(15), xname(otmp), KILLED_BY_AN);
1976 You("seem unaffected by the poison.");
1977 } else if (!otmp->cursed)
1978 pline("This %s is delicious!",
1979 otmp->oclass == COIN_CLASS ? foodword(otmp) :
1980 singular(otmp, xname));
1986 if(otmp == victual.piece) {
1987 /* If they weren't able to choke, they don't suddenly become able to
1988 * choke just because they were interrupted. On the other hand, if
1989 * they were able to choke before, if they lost food it's possible
1990 * they shouldn't be able to choke now.
1992 if (u.uhs != SATIATED) victual.canchoke = FALSE;
1993 victual.piece = touchfood(otmp);
1994 You("resume your meal.");
1995 start_eating(victual.piece);
1999 /* nothing in progress - so try to find something. */
2000 /* tins are a special case */
2001 /* tins must also check conduct separately in case they're discarded */
2002 if(otmp->otyp == TIN) {
2010 victual.piece = otmp = touchfood(otmp);
2011 victual.usedtime = 0;
2013 /* Now we need to calculate delay and nutritional info.
2014 * The base nutrition calculated here and in eatcorpse() accounts
2015 * for normal vs. rotten food. The reqtime and nutrit values are
2016 * then adjusted in accordance with the amount of food left.
2018 if(otmp->otyp == CORPSE) {
2019 int tmp = eatcorpse(otmp);
2022 victual.piece = (struct obj *)0;
2026 /* if not used up, eatcorpse sets up reqtime and may modify
2029 /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are
2030 * all handled in the != FOOD_CLASS case, above */
2031 switch (objects[otmp->otyp].oc_material) {
2033 u.uconduct.unvegan++;
2034 if (otmp->otyp != EGG) {
2035 violated_vegetarian();
2040 if (otmp->otyp == PANCAKE ||
2041 otmp->otyp == FORTUNE_COOKIE || /* eggs */
2042 otmp->otyp == CREAM_PIE ||
2043 otmp->otyp == CANDY_BAR || /* milk */
2044 otmp->otyp == LUMP_OF_ROYAL_JELLY)
2045 u.uconduct.unvegan++;
2049 victual.reqtime = objects[otmp->otyp].oc_delay;
2050 if (otmp->otyp != FORTUNE_COOKIE &&
2052 (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) &&
2053 (otmp->orotten || !rn2(7))))) {
2055 if (rottenfood(otmp)) {
2056 otmp->orotten = TRUE;
2059 consume_oeaten(otmp, 1); /* oeaten >>= 1 */
2060 } else fprefx(otmp);
2063 /* re-calc the nutrition */
2064 if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit;
2065 else basenutrit = objects[otmp->otyp].oc_nutrition;
2068 debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime);
2069 debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit);
2071 victual.reqtime = (basenutrit == 0 ? 0 :
2072 rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit));
2074 debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime);
2076 /* calculate the modulo value (nutrit. units per round eating)
2077 * note: this isn't exact - you actually lose a little nutrition
2078 * due to this method.
2079 * TODO: add in a "remainder" value to be given at the end of the
2082 if (victual.reqtime == 0 || otmp->oeaten == 0)
2083 /* possible if most has been eaten before */
2085 else if ((int)otmp->oeaten >= victual.reqtime)
2086 victual.nmod = -((int)otmp->oeaten / victual.reqtime);
2088 victual.nmod = victual.reqtime % otmp->oeaten;
2089 victual.canchoke = (u.uhs == SATIATED);
2091 if (!dont_start) start_eating(otmp);
2095 /* Take a single bite from a piece of food, checking for choking and
2096 * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
2101 if(victual.canchoke && u.uhunger >= 2000) {
2102 choke(victual.piece);
2105 if (victual.doreset) {
2109 force_save_hs = TRUE;
2110 if(victual.nmod < 0) {
2111 lesshungry(-victual.nmod);
2112 consume_oeaten(victual.piece, victual.nmod); /* -= -nmod */
2113 } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) {
2115 consume_oeaten(victual.piece, -1); /* -= 1 */
2117 force_save_hs = FALSE;
2126 gethungry() /* as time goes by - called by moveloop() and domove() */
2128 if (u.uinvulnerable) return; /* you don't feel hungrier */
2130 if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */
2131 && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
2133 u.uhunger--; /* ordinary food consumption */
2135 if (moves % 2) { /* odd turns */
2136 /* Regeneration uses up food, unless due to an artifact */
2137 if (HRegeneration || ((ERegeneration & (~W_ART)) &&
2138 (ERegeneration != W_WEP || !uwep->oartifact)))
2140 if (near_capacity() > SLT_ENCUMBER) u.uhunger--;
2141 } else { /* even turns */
2142 if (Hunger) u.uhunger--;
2143 /* Conflict uses up food too */
2144 if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--;
2145 /* +0 charged rings don't do anything, so don't affect hunger */
2146 /* Slow digestion still uses ring hunger */
2147 switch ((int)(moves % 20)) { /* note: use even cases only */
2148 case 4: if (uleft &&
2149 (uleft->spe || !objects[uleft->otyp].oc_charged))
2152 case 8: if (uamul) u.uhunger--;
2154 case 12: if (uright &&
2155 (uright->spe || !objects[uright->otyp].oc_charged))
2158 case 16: if (u.uhave.amulet) u.uhunger--;
2170 morehungry(num) /* called after vomiting and after performing feats of magic */
2179 lesshungry(num) /* called after eating (and after drinking fruit juice) */
2182 /* See comments in newuhs() for discussion on force_save_hs */
2183 boolean iseating = (occupation == eatfood) || force_save_hs;
2185 debugpline("lesshungry(%d)", num);
2188 if(u.uhunger >= 2000) {
2189 if (!iseating || victual.canchoke) {
2191 choke(victual.piece);
2194 choke(occupation == opentin ? tin.tin : (struct obj *)0);
2195 /* no reset_eat() */
2198 /* Have lesshungry() report when you're nearly full so all eating
2199 * warns when you're about to choke.
2201 if (u.uhunger >= 1500) {
2202 if (!victual.eating || (victual.eating && !victual.fullwarn)) {
2203 pline("You're having a hard time getting all of it down.");
2204 nomovemsg = "You're finally finished.";
2205 if (!victual.eating)
2208 victual.fullwarn = TRUE;
2209 if (victual.canchoke && victual.reqtime > 1) {
2210 /* a one-gulp food will not survive a stop */
2211 if (yn_function("Stop eating?",ynchars,'y')=='y') {
2213 nomovemsg = (char *)0;
2227 (void) Hear_again();
2228 if(u.uhs > FAINTING)
2241 return((boolean)(u.uhs == FAINTED));
2245 reset_faint() /* call when a faint must be prematurely terminated */
2247 if(is_fainted()) nomul(0);
2258 nomul(-10+(u.uhunger/10));
2259 nomovemsg = "You regain consciousness.";
2266 newuhs(incr) /* compute and comment on your (new?) hunger status */
2270 static unsigned save_hs;
2271 static boolean saved_hs = FALSE;
2274 newhs = (h > 1000) ? SATIATED :
2275 (h > 150) ? NOT_HUNGRY :
2277 (h > 0) ? WEAK : FAINTING;
2279 /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
2280 * This should not produce the message "you only feel hungry now";
2281 * that message should only appear if HUNGRY is an endpoint. Therefore
2282 * we check to see if we're in the middle of eating. If so, we save
2283 * the first hunger status, and at the end of eating we decide what
2284 * message to print based on the _entire_ meal, not on each little bit.
2286 /* It is normally possible to check if you are in the middle of a meal
2287 * by checking occupation == eatfood, but there is one special case:
2288 * start_eating() can call bite() for your first bite before it
2289 * sets the occupation.
2290 * Anyone who wants to get that case to work _without_ an ugly static
2291 * force_save_hs variable, feel free.
2293 /* Note: If you become a certain hunger status in the middle of the
2294 * meal, and still have that same status at the end of the meal,
2295 * this will incorrectly print the associated message at the end of
2296 * the meal instead of the middle. Such a case is currently
2297 * impossible, but could become possible if a message for SATIATED
2298 * were added or if HUNGRY and WEAK were separated by a big enough
2299 * gap to fit two bites.
2301 if (occupation == eatfood || force_save_hs) {
2315 if(newhs == FAINTING) {
2316 if(is_fainted()) newhs = FAINTED;
2317 if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
2318 if(!is_fainted() && multi >= 0 /* %% */) {
2319 /* stop what you're doing, then faint */
2321 You("faint from lack of food.");
2323 nomul(-10+(u.uhunger/10));
2324 nomovemsg = "You regain consciousness.";
2329 if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) {
2333 You("die from starvation.");
2334 killer_format = KILLED_BY;
2335 killer = "starvation";
2337 /* if we return, we lifesaved, and that calls newuhs */
2342 if(newhs != u.uhs) {
2343 if(newhs >= WEAK && u.uhs < WEAK)
2344 losestr(1); /* this may kill you -- see below */
2345 else if(newhs < WEAK && u.uhs >= WEAK)
2349 if (Hallucination) {
2351 "now have a lesser case of the munchies." :
2352 "are getting the munchies.");
2354 You((!incr) ? "only feel hungry now." :
2355 (u.uhunger < 145) ? "feel hungry." :
2356 "are beginning to feel hungry.");
2357 if (incr && occupation &&
2358 (occupation != eatfood && occupation != opentin))
2364 "You still have the munchies." :
2365 "The munchies are interfering with your motor capabilities.");
2367 (Role_if(PM_WIZARD) || Race_if(PM_ELF) ||
2368 Role_if(PM_VALKYRIE)))
2369 pline("%s needs food, badly!",
2370 (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
2371 urole.name.m : "Elf");
2373 You((!incr) ? "feel weak now." :
2374 (u.uhunger < 45) ? "feel weak." :
2375 "are beginning to feel weak.");
2376 if (incr && occupation &&
2377 (occupation != eatfood && occupation != opentin))
2384 if ((Upolyd ? u.mh : u.uhp) < 1) {
2385 You("die from hunger and exhaustion.");
2386 killer_format = KILLED_BY;
2387 killer = "exhaustion";
2397 /* Returns an object representing food. Object may be either on floor or
2401 floorfood(verb,corpsecheck) /* get food from floor or pack */
2403 int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
2405 register struct obj *otmp;
2408 boolean feeding = (!strcmp(verb, "eat"));
2410 /* if we can't touch floor objects then use invent food only */
2411 if (!can_reach_floor() ||
2413 (feeding && u.usteed) || /* can't eat off floor while riding */
2415 ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) &&
2416 (Wwalking || is_clinger(youmonst.data) ||
2417 (Flying && !Breathless))))
2420 if (feeding && metallivorous(youmonst.data)) {
2422 struct trap *ttmp = t_at(u.ux, u.uy);
2424 if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
2425 /* If not already stuck in the trap, perhaps there should
2426 be a chance to becoming trapped? Probably not, because
2427 then the trap would just get eaten on the _next_ turn... */
2428 Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
2429 (u.utrap && u.utraptype == TT_BEARTRAP) ?
2430 "holding you" : "armed");
2431 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2432 u.utrap = u.utraptype = 0;
2434 return mksobj(BEARTRAP, TRUE, FALSE);
2435 } else if (c == 'q') {
2436 return (struct obj *)0;
2440 if (youmonst.data != &mons[PM_RUST_MONSTER] &&
2441 (gold = g_at(u.ux, u.uy)) != 0) {
2442 if (gold->quan == 1L)
2443 Sprintf(qbuf, "There is 1 gold piece here; eat it?");
2445 Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
2447 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2449 } else if (c == 'q') {
2450 return (struct obj *)0;
2455 /* Is there some food (probably a heavy corpse) here on the ground? */
2456 for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
2458 (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) :
2459 feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) :
2460 otmp->oclass==FOOD_CLASS) {
2461 Sprintf(qbuf, "There %s %s here; %s %s?",
2462 otense(otmp, "are"),
2464 (otmp->quan == 1L) ? "it" : "one");
2465 if((c = yn_function(qbuf,ynqchars,'n')) == 'y')
2468 return((struct obj *) 0);
2473 /* We cannot use ALL_CLASSES since that causes getobj() to skip its
2474 * "ugly checks" and we need to check for inedible items.
2476 otmp = getobj(feeding ? (const char *)allobj :
2477 (const char *)comestibles, verb);
2478 if (corpsecheck && otmp)
2479 if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
2480 You_cant("%s that!", verb);
2481 return (struct obj *)0;
2486 /* Side effects of vomiting */
2487 /* added nomul (MRS) - it makes sense, you're too busy being sick! */
2489 vomit() /* A good idea from David Neves */
2491 make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
2496 eaten_stat(base, obj)
2498 register struct obj *obj;
2500 long uneaten_amt, full_amount;
2502 uneaten_amt = (long)obj->oeaten;
2503 full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit
2504 : (long)objects[obj->otyp].oc_nutrition;
2505 if (uneaten_amt > full_amount) {
2507 "partly eaten food (%ld) more nutritious than untouched food (%ld)",
2508 uneaten_amt, full_amount);
2509 uneaten_amt = full_amount;
2512 base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L);
2513 return (base < 1) ? 1 : base;
2516 /* reduce obj's oeaten field, making sure it never hits or passes 0 */
2518 consume_oeaten(obj, amt)
2523 * This is a hack to try to squelch several long standing mystery
2524 * food bugs. A better solution would be to rewrite the entire
2525 * victual handling mechanism from scratch using a less complex
2526 * model. Alternatively, this routine could call done_eating()
2527 * or food_disappears() but its callers would need revisions to
2528 * cope with victual.piece unexpectedly going away.
2530 * Multi-turn eating operates by setting the food's oeaten field
2531 * to its full nutritional value and then running a counter which
2532 * independently keeps track of whether there is any food left.
2533 * The oeaten field can reach exactly zero on the last turn, and
2534 * the object isn't removed from inventory until the next turn
2535 * when the "you finish eating" message gets delivered, so the
2536 * food would be restored to the status of untouched during that
2537 * interval. This resulted in unexpected encumbrance messages
2538 * at the end of a meal (if near enough to a threshold) and would
2539 * yield full food if there was an interruption on the critical
2540 * turn. Also, there have been reports over the years of food
2541 * becoming massively heavy or producing unlimited satiation;
2542 * this would occur if reducing oeaten via subtraction attempted
2543 * to drop it below 0 since its unsigned type would produce a
2544 * huge positive value instead. So far, no one has figured out
2545 * _why_ that inappropriate subtraction might sometimes happen.
2549 /* bit shift to divide the remaining amount of food */
2550 obj->oeaten >>= amt;
2552 /* simple decrement; value is negative so we actually add it */
2553 if ((int) obj->oeaten > -amt)
2559 if (obj->oeaten == 0) {
2560 if (obj == victual.piece) /* always true unless wishing... */
2561 victual.reqtime = victual.usedtime; /* no bites left */
2562 obj->oeaten = 1; /* smallest possible positive value */
2569 /* called when eatfood occupation has been interrupted,
2570 or in the case of theft, is about to be interrupted */
2572 maybe_finished_meal(stopping)
2575 /* in case consume_oeaten() has decided that the food is all gone */
2576 if (occupation == eatfood && victual.usedtime >= victual.reqtime) {
2577 if (stopping) occupation = 0; /* for do_reset_eat */
2578 (void) eatfood(); /* calls done_eating() to use up victual.piece */