X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Feat.c;h=087ea594c12aebddb6e5346f82a100f050bf7fcb;hb=5f4002a5cddba23f6116cf7bd75ef321317a65aa;hp=eb9ef7a7a88a76caa2139460310efc1c10c24a8d;hpb=1ac09e0d266750c55db570f602bf0ac4962b0811;p=jnethack%2Fsource.git diff --git a/src/eat.c b/src/eat.c index eb9ef7a..087ea59 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,23 +1,25 @@ -/* NetHack 3.6 eat.c $NHDT-Date: 1449269916 2015/12/04 22:58:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.154 $ */ +/* NetHack 3.6 eat.c $NHDT-Date: 1502754159 2017/08/14 23:42:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.179 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ /* JNetHack Copyright */ /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */ -/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */ +/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018 */ /* JNetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(eatmdone); STATIC_PTR int NDECL(eatfood); -STATIC_PTR void FDECL(costly_tin, (int)); +STATIC_PTR struct obj *FDECL(costly_tin, (int)); STATIC_PTR int NDECL(opentin); STATIC_PTR int NDECL(unfaint); STATIC_DCL const char *FDECL(food_xname, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(choke, (struct obj *)); STATIC_DCL void NDECL(recalc_wt); +STATIC_DCL unsigned FDECL(obj_nutrition, (struct obj *)); STATIC_DCL struct obj *FDECL(touchfood, (struct obj *)); STATIC_DCL void NDECL(do_reset_eat); STATIC_DCL void FDECL(done_eating, (BOOLEAN_P)); @@ -102,6 +104,12 @@ register struct obj *obj; && (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj))) return TRUE; + /* Ghouls only eat non-veggy corpses or eggs (see dogfood()) */ + if (u.umonnum == PM_GHOUL) + return (boolean)((obj->otyp == CORPSE + && !vegan(&mons[obj->corpsenm])) + || (obj->otyp == EGG)); + if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) /* [g.cubes can eat containers and retain all contents as engulfed items, but poly'd player can't do that] */ @@ -115,8 +123,11 @@ register struct obj *obj; void init_uhunger() { + context.botl = (u.uhs != NOT_HUNGRY || ATEMP(A_STR) < 0); u.uhunger = 900; u.uhs = NOT_HUNGRY; + if (ATEMP(A_STR) < 0) + ATEMP(A_STR) = 0; } /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */ @@ -355,6 +366,32 @@ reset_eat() return; } +/* base nutrition of a food-class object */ +STATIC_OVL unsigned +obj_nutrition(otmp) +struct obj *otmp; +{ + unsigned nut = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit + : otmp->globby ? otmp->owt + : (unsigned) objects[otmp->otyp].oc_nutrition; + + if (otmp->otyp == LEMBAS_WAFER) { + if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) + nut += nut / 4; /* 800 -> 1000 */ + else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) + nut -= nut / 4; /* 800 -> 600 */ + /* prevent polymorph making a partly eaten wafer + become more nutritious than an untouched one */ + if (otmp->oeaten >= nut) + otmp->oeaten = (otmp->oeaten < objects[LEMBAS_WAFER].oc_nutrition) + ? (nut - 1) : nut; + } else if (otmp->otyp == CRAM_RATION) { + if (maybe_polyd(is_dwarf(youmonst.data), Race_if(PM_DWARF))) + nut += nut / 6; /* 600 -> 700 */ + } + return nut; +} + STATIC_OVL struct obj * touchfood(otmp) struct obj *otmp; @@ -369,9 +406,7 @@ struct obj *otmp; if (!otmp->oeaten) { costly_alteration(otmp, COST_BITE); - otmp->oeaten = - (otmp->otyp == CORPSE ? mons[otmp->corpsenm].cnutrit - : objects[otmp->otyp].oc_nutrition); + otmp->oeaten = obj_nutrition(otmp); } if (carried(otmp)) { @@ -473,7 +508,9 @@ STATIC_OVL void done_eating(message) boolean message; { - context.victual.piece->in_use = TRUE; + struct obj *piece = context.victual.piece; + + piece->in_use = TRUE; occupation = 0; /* do this early, so newuhs() knows we're done */ newuhs(FALSE); if (nomovemsg) { @@ -482,19 +519,19 @@ boolean message; nomovemsg = 0; } else if (message) /*JP - You("finish eating %s.", food_xname(context.victual.piece, TRUE)); + You("finish eating %s.", food_xname(piece, TRUE)); */ - You("%s‚ðH‚׏I‚¦‚½D", food_xname(context.victual.piece, TRUE)); + You("%s‚ðH‚׏I‚¦‚½D", food_xname(piece, TRUE)); - if (context.victual.piece->otyp == CORPSE) - cpostfx(context.victual.piece->corpsenm); + if (piece->otyp == CORPSE || piece->globby) + cpostfx(piece->corpsenm); else - fpostfx(context.victual.piece); + fpostfx(piece); - if (carried(context.victual.piece)) - useup(context.victual.piece); + if (carried(piece)) + useup(piece); else - useupf(context.victual.piece, 1L); + useupf(piece, 1L); context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; context.victual.fullwarn = context.victual.eating = @@ -544,7 +581,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ */ Your("”]‚͐H‚ׂç‚ꂽI"); } else { /* monster against monster */ - if (visflag) + if (visflag && canspotmon(mdef)) /*JP pline("%s brain is eaten!", s_suffix(Monnam(mdef))); */ @@ -561,7 +598,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ } else { /* no need to check for poly_when_stoned or Stone_resistance; mind flayers don't have those capabilities */ - if (visflag) + if (visflag && canseemon(magr)) /*JP pline("%s turns to stone!", Monnam(magr)); */ @@ -574,7 +611,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ if (magr->mtame && !visflag) /* parallels mhitm.c's brief_feeling */ /*JP - You("have a sad thought for a moment, then is passes."); + You("have a sad thought for a moment, then it passes."); */ You("”ß‚µ‚¢l‚¦‚É‚¨‚»‚í‚ꂽ‚ªA‚·‚®‚ɉ߂¬‚³‚Á‚½D"); return MM_AGR_DIED; @@ -675,7 +712,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ * monster mind flayer is eating another monster's brain */ if (mindless(pd)) { - if (visflag) + if (visflag && canspotmon(mdef)) /*JP pline("%s doesn't notice.", Monnam(mdef)); */ @@ -690,12 +727,14 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ } else { *dmg_p += xtra_dmg; give_nutrit = TRUE; - if (*dmg_p >= mdef->mhp && visflag) -/*JP + if (*dmg_p >= mdef->mhp && visflag && canspotmon(mdef)) +#if 0 /*JP*/ pline("%s last thought fades away...", -*/ - pline("%s‚̍Ōã‚ÌŽv‚¢‚ª‚悬‚éDDD", s_suffix(Monnam(mdef))); +#else + pline("%s‚̍Ōã‚ÌŽv‚¢‚ª‚悬‚éDDD", + Monnam(mdef)); +#endif } } @@ -728,7 +767,9 @@ boolean allowmsg; and also shouldn't eat current species when polymorphed (even if having the form of something which doesn't care about cannibalism--hero's innate traits aren't altered) */ - && (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) { + && (your_race(fptr) + || (Upolyd && same_race(youmonst.data, fptr)) + || (u.ulycn >= LOW_PM && were_beastie(pm) == u.ulycn))) { if (allowmsg) { if (Upolyd && your_race(fptr)) /*JP @@ -1082,7 +1123,7 @@ cpostfx(pm) register int pm; { register int tmp = 0; - boolean catch_lycanthropy = FALSE; + int catch_lycanthropy = NON_PM; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ @@ -1113,22 +1154,20 @@ register int pm; pluslvl(FALSE); break; case PM_HUMAN_WERERAT: - catch_lycanthropy = TRUE; - u.ulycn = PM_WERERAT; + catch_lycanthropy = PM_WERERAT; break; case PM_HUMAN_WEREJACKAL: - catch_lycanthropy = TRUE; - u.ulycn = PM_WEREJACKAL; + catch_lycanthropy = PM_WEREJACKAL; break; case PM_HUMAN_WEREWOLF: - catch_lycanthropy = TRUE; - u.ulycn = PM_WEREWOLF; + catch_lycanthropy = PM_WEREWOLF; break; case PM_NURSE: if (Upolyd) u.mh = u.mhmax; else u.uhp = u.uhpmax; + make_blinded(0L, !u.ucreamed); context.botl = 1; break; case PM_STALKER: @@ -1177,7 +1216,10 @@ register int pm; if (u.usteed) dismount_steed(DISMOUNT_FELL); nomul(-tmp); +/*JP multi_reason = "pretending to be a pile of gold"; +*/ + multi_reason = "‹à‰Ý‚ÌŽR‚̐^Ž—‚ð‚µ‚Ä‚¢‚鎞‚É"; Sprintf(buf, Hallucination /*JP @@ -1231,8 +1273,9 @@ register int pm; case PM_SANDESTIN: /* moot--they don't leave corpses */ if (Unchanging) { #if 0 /*JP*/ - You_feel("ˆêuˆá‚Á‚½Š´‚¶‚ª‚µ‚½D"); /* same as poly trap */ + You_feel("momentarily different."); /* same as poly trap */ #else + You_feel("ˆêuˆá‚Á‚½Š´‚¶‚ª‚µ‚½D"); /* same as poly trap */ #endif } else { /*JP @@ -1316,12 +1359,14 @@ register int pm; gainstr((struct obj *) 0, 0, TRUE); else if (tmp > 0) givit(tmp, ptr); - } break; - } + break; + } /* default case */ + } /* switch */ - if (catch_lycanthropy) + if (catch_lycanthropy >= LOW_PM) { + set_ulycn(catch_lycanthropy); retouch_equipment(2); - + } return; } @@ -1341,7 +1386,7 @@ violated_vegetarian() /* common code to check and possibly charge for 1 context.tin.tin, * will split() context.tin.tin if necessary */ -STATIC_PTR void +STATIC_PTR struct obj * costly_tin(alter_type) int alter_type; /* COST_xxx */ { @@ -1355,6 +1400,7 @@ int alter_type; /* COST_xxx */ } costly_alteration(tin, alter_type); } + return tin; } int @@ -1389,7 +1435,9 @@ struct obj *obj; int mnum; char *buf; { +#if 0 /*JP*/ char buf2[BUFSZ]; +#endif int r = tin_variety(obj, TRUE); if (obj && buf) { @@ -1512,7 +1560,7 @@ const char *mesg; b_trapped("tin", 0); */ b_trapped("ŠÊ", 0); - costly_tin(COST_DSTROY); + tin = costly_tin(COST_DSTROY); goto use_up_tin; } @@ -1526,7 +1574,7 @@ const char *mesg; */ pline("ŠÊ‚Í‹ó‚Á‚Û‚¾‚Á‚½D"); tin->dknown = tin->known = 1; - costly_tin(COST_OPEN); + tin = costly_tin(COST_OPEN); goto use_up_tin; } @@ -1567,7 +1615,7 @@ const char *mesg; You("ŠJ‚¯‚½ŠÊ‚ðŽÌ‚Ä‚½D"); if (!Hallucination) tin->dknown = tin->known = 1; - costly_tin(COST_OPEN); + tin = costly_tin(COST_OPEN); goto use_up_tin; } @@ -1594,7 +1642,7 @@ const char *mesg; cpostfx(mnum); /* charge for one at pre-eating cost */ - costly_tin(COST_OPEN); + tin = costly_tin(COST_OPEN); if (tintxts[r].nut < 0) /* rotten */ make_vomiting((long) rn1(15, 10), FALSE); @@ -1639,7 +1687,7 @@ const char *mesg; You("discard the open tin."); */ You("ŠJ‚¯‚½ŠÊ‚ðŽÌ‚Ä‚½D"); - costly_tin(COST_OPEN); + tin = costly_tin(COST_OPEN); goto use_up_tin; } @@ -1647,8 +1695,7 @@ const char *mesg; * Same order as with non-spinach above: * conduct update, side-effects, shop handling, and nutrition. */ - u.uconduct - .food++; /* don't need vegan/vegetarian checks for spinach */ + u.uconduct.food++; /* don't need vegetarian checks for spinach */ if (!tin->cursed) #if 0 /*JP:T*/ pline("This makes you feel like %s!", @@ -1659,7 +1706,7 @@ const char *mesg; #endif gainstr(tin, 0, FALSE); - costly_tin(COST_OPEN); + tin = costly_tin(COST_OPEN); lesshungry(tin->blessed ? 600 /* blessed */ @@ -1754,6 +1801,8 @@ struct obj *otmp; case ELVEN_DAGGER: case ORCISH_DAGGER: case ATHAME: + case KNIFE: + case STILETTO: case CRYSKNIFE: tmp = 3; break; @@ -1812,8 +1861,10 @@ int Hear_again(VOID_ARGS) { /* Chance of deafness going away while fainted/sleeping/etc. */ - if (!rn2(2)) + if (!rn2(2)) { make_deaf(0L, FALSE); + context.botl = TRUE; + } return 0; } @@ -1843,7 +1894,9 @@ struct obj *obj; pline("Everything suddenly goes dark."); */ pline("“Ë‘R‘S‚Ä‚ªˆÃ‚­‚È‚Á‚½D"); - make_blinded((long) d(2, 10), FALSE); + /* hero is not Blind, but Blinded timer might be nonzero if + blindness is being overridden by the Eyes of the Overworld */ + make_blinded((Blinded & TIMEOUT) + (long) d(2, 10), FALSE); if (!Blind) Your1(vision_clears); } else if (!rn2(3)) { @@ -1874,8 +1927,12 @@ struct obj *obj; */ pline("¢ŠE‚ª‰ñ“]‚µC%s%sD", where, what); incr_itimeout(&HDeaf, duration); + context.botl = TRUE; nomul(-duration); +/*JP multi_reason = "unconscious from rotten food"; +*/ + multi_reason = "•…‚Á‚½H‚ו¨‚ňӎ¯‚ðŽ¸‚Á‚Ä‚¢‚éŠÔ‚É"; /*JP nomovemsg = "You are conscious again."; */ @@ -1891,11 +1948,13 @@ STATIC_OVL int eatcorpse(otmp) struct obj *otmp; { - int tp = 0, mnum = otmp->corpsenm; + int retcode = 0, tp = 0, mnum = otmp->corpsenm; long rotted = 0L; - int retcode = 0; boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance - && !poly_when_stoned(youmonst.data)); + && !poly_when_stoned(youmonst.data)), + slimeable = (mnum == PM_GREEN_SLIME && !Slimed && !Unchanging + && !slimeproof(youmonst.data)), + glob = otmp->globby ? TRUE : FALSE; /* KMH, conduct */ if (!vegan(&mons[mnum])) @@ -1913,21 +1972,19 @@ struct obj *otmp; rotted -= 2L; } - if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) { + if (mnum != PM_ACID_BLOB && !stoneable && !slimeable && rotted > 5L) { boolean cannibal = maybe_cannibal(mnum, FALSE); #if 0 /*JP*/ pline("Ulch - that %s was tainted%s!", - mons[mnum].mlet == S_FUNGUS - ? "fungoid vegetation" - : !vegetarian(&mons[mnum]) ? "meat" : "protoplasm", + (mons[mnum].mlet == S_FUNGUS) ? "fungoid vegetation" + : glob ? "glob" + : vegetarian(&mons[mnum]) ? "protoplasm" + : "meat", cannibal ? ", you cannibal" : ""); -#else - pline("ƒIƒFI‚±‚Ì%s‚Í•…‚Á‚Ä‚¢‚é%sI", - mons[mnum].mlet == S_FUNGUS - ? "×‹Û‚ɉ˜õ‚³‚ꂽA•¨" - : !vegetarian(&mons[mnum]) ? "“÷" : "¶•¨", - cannibal ? "D‚µ‚©‚à‹¤H‚¢‚¾" : ""); +#else /* “ú–{Œê‚Å‚Í’Pƒ‚É */ + pline("ƒIƒFI‚±‚ê‚Í•…‚Á‚Ä‚¢‚éI%s", + cannibal ? "‚µ‚©‚à‹¤H‚¢‚¾I" : ""); #endif if (Sick_resistance) { /*JP @@ -1941,13 +1998,18 @@ struct obj *otmp; /* make sure new ill doesn't result in improvement */ if (Sick && (sick_time > Sick)) sick_time = (Sick > 1L) ? Sick - 1L : 1L; -#if 0 /*JP*/ +#if 0 /*JP:T*/ make_sick(sick_time, corpse_xname(otmp, "rotted", CXN_NORMAL), TRUE, SICK_VOMITABLE); #else make_sick(sick_time, corpse_xname(otmp, "•…‚Á‚½", CXN_NORMAL), TRUE, SICK_VOMITABLE); #endif + +/*JP + pline("(It must have died too long ago to be safe to eat.)"); +*/ + pline("(‚±‚Ì“÷‚͈À‘S‚ɐH‚ׂç‚ê‚鎞ŠÔ‚ð‰ß‚¬‚Ä‚µ‚Ü‚Á‚Ä‚¢‚½‚悤‚¾D)"); } if (carried(otmp)) useup(otmp); @@ -1961,9 +2023,10 @@ struct obj *otmp; #else pline("ˆÝŽ_‚Ì’²Žq‚ª‚Æ‚Ä‚àˆ«‚¢D"); #endif -#if 0 /*JP*/ - losehp(rnd(15), "acidic corpse", KILLED_BY_AN); /* acid damage */ -#else +#if 0 /*JP:T*/ + losehp(rnd(15), !glob ? "acidic corpse" : "acidic glob", + KILLED_BY_AN); /* acid damage */ +#else /* “ú–{Œê‚Å‚Í‹æ•Ê‚µ‚È‚¢ */ losehp(rnd(15), "Ž_‚ÌŽ€‘Ì‚Å", KILLED_BY_AN); #endif } else if (poisonous(&mons[mnum]) && rn2(5)) { @@ -1974,16 +2037,18 @@ struct obj *otmp; pline("ƒEƒQƒF[C—L“Å‚¾‚Á‚½‚É‚¿‚ª‚¢‚È‚¢I"); if (!Poison_resistance) { losestr(rnd(4)); -/*JP - losehp(rnd(15), "poisonous corpse", KILLED_BY_AN); -*/ +#if 0 /*JP*/ + losehp(rnd(15), !glob ? "poisonous corpse" : "poisonous glob", + KILLED_BY_AN); +#else losehp(rnd(15), "“Å‚ÌŽ€‘Ì‚Å", KILLED_BY_AN); +#endif } else /*JP You("seem unaffected by the poison."); */ You("“ł̉e‹¿‚ðŽó‚¯‚È‚¢‚悤‚¾D"); - /* now any corpse left too long will make you mildly ill */ + /* now any corpse left too long will make you mildly ill */ } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) { tp++; /*JP @@ -1991,13 +2056,13 @@ struct obj *otmp; */ You("%s‹C•ª‚ªˆ«‚¢D", (Sick) ? "‚Æ‚Ä‚à" : ""); /*JP - losehp(rnd(8), "cadaver", KILLED_BY_AN); + losehp(rnd(8), !glob ? "cadaver" : "rotted glob", KILLED_BY_AN); */ losehp(rnd(8), "•…—Ž€‘Ì‚Å", KILLED_BY_AN); } /* delay is weight dependent */ - context.victual.reqtime = 3 + (mons[mnum].cwt >> 6); + context.victual.reqtime = 3 + ((!glob ? mons[mnum].cwt : otmp->owt) >> 6); if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) { if (rottenfood(otmp)) { @@ -2034,31 +2099,44 @@ struct obj *otmp; */ You("–Ú‹Ê‚ð‚‚ñ‚‚ñ‚‚‚¢‚½D"); } else { - /* [is this right? omnivores end up always disliking the taste] */ - boolean yummy = vegan(&mons[mnum]) - ? (!carnivorous(youmonst.data) - && herbivorous(youmonst.data)) - : (carnivorous(youmonst.data) - && !herbivorous(youmonst.data)); + /* yummy is always False for omnivores, palatable always True */ + boolean yummy = (vegan(&mons[mnum]) + ? (!carnivorous(youmonst.data) + && herbivorous(youmonst.data)) + : (carnivorous(youmonst.data) + && !herbivorous(youmonst.data))), + palatable = ((vegetarian(&mons[mnum]) + ? herbivorous(youmonst.data) + : carnivorous(youmonst.data)) + && rn2(10) + && ((rotted < 1) ? TRUE : !rn2(rotted+1))); + const char *pmxnam = food_xname(otmp, FALSE); #if 0 /*JP*/ - pline("%s%s %s!", + if (!strncmpi(pmxnam, "the ", 4)) + pmxnam += 4; + pline("%s%s %s %s%c", type_is_pname(&mons[mnum]) ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ", - food_xname(otmp, FALSE), + pmxnam, + Hallucination ? "is" : "tastes", + /* tiger reference is to TV ads for "Frosted Flakes", + breakfast cereal targeted at kids by "Tony the tiger" */ Hallucination - ? (yummy ? ((u.umonnum == PM_TIGER) ? "is gr-r-reat" - : "is gnarly") - : "is grody") - : (yummy ? "is delicious" : "tastes terrible")); + ? (yummy ? ((u.umonnum == PM_TIGER) ? "gr-r-reat" : "gnarly") + : palatable ? "copacetic" : "grody") + : (yummy ? "delicious" : palatable ? "okay" : "terrible"), + (yummy || !palatable) ? '!' : '.'); #else - pline("‚±‚Ì%s‚Í%sI", - food_xname(otmp, FALSE), + pline("‚±‚Ì%s‚Í%s%s", + pmxnam, Hallucination - ? (yummy ? ((u.umonnum == PM_TIGER) ? "ƒOƒDƒŒƒCƒgƒD" - : "ƒCƒP‚Ä‚é") - : "ƒCƒP‚Ä‚È‚¢") - : (yummy ? "‚Æ‚Ä‚àŽ|‚¢" : "‚Ђǂ¢–¡‚¾")); + ? (yummy ? ((u.umonnum == PM_TIGER) ? "ƒOƒDƒŒƒCƒgƒD" + : "ƒCƒP‚Ä‚é") + : palatable ? "‚Ü‚ ‚ ‚肾" : "ƒCƒP‚Ä‚È‚¢") + : (yummy ? "‚Æ‚Ä‚àŽ|‚¢" : palatable ? "‚Ü‚ ‚Ü‚ ‚¾" + : "‚Ђǂ¢–¡‚¾"), + (yummy || !palatable) ? "I" : "D"); #endif } @@ -2072,8 +2150,12 @@ struct obj *otmp; { const char *old_nomovemsg, *save_nomovemsg; - debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp, - (unsigned long) context.victual.piece); + debugpline2("start_eating: %s (victual = %s)", + /* note: fmt_ptr() returns a static buffer but supports + several such so we don't need to copy the first result + before calling it a second time */ + fmt_ptr((genericptr_t) otmp), + fmt_ptr((genericptr_t) context.victual.piece)); debugpline1("reqtime = %d", context.victual.reqtime); debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay); debugpline1("nmod = %d", context.victual.nmod); @@ -2172,6 +2254,21 @@ struct obj *otmp; make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE); } break; + case LEMBAS_WAFER: + if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) { +/*JP + pline("%s", "!#?&* elf kibble!"); +*/ + pline("%s", "I”H•– ƒGƒ‹ƒN‚̐H‚¢•¨I"); + break; + } else if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) { +/*JP + pline("A little goes a long way."); +*/ + pline("­‚µ‚ŏ\•ª‚¾D"); + break; + } + goto give_feedback; case MEATBALL: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: @@ -2182,7 +2279,7 @@ struct obj *otmp; make_vomiting((long) rn1(context.victual.reqtime, 5), FALSE); break; } - /* else FALLTHRU */ + /*FALLTHRU*/ default: if (otmp->otyp == SLIME_MOLD && !otmp->cursed && otmp->spe == context.current_fruit) { @@ -2233,6 +2330,9 @@ struct obj *otmp; #else pline("ƒEƒQƒF[•…‚Á‚½—‘‚¾D"); #endif + /* increasing existing nausea means that it will take longer + before eventual vomit, but also means that constitution + will be abused more times before illness completes */ make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE); } else { give_feedback: @@ -2490,12 +2590,35 @@ eatspecial() vault_gd_watching(GD_EATGOLD); return; } + if (objects[otmp->otyp].oc_material == PAPER) { #ifdef MAIL - if (otmp->otyp == SCR_MAIL) { - /* no nutrition */ - pline("This junk mail is less than satisfying."); - } + if (otmp->otyp == SCR_MAIL) + /* no nutrition */ +/*JP + pline("This junk mail is less than satisfying."); +*/ + pline("‚±‚̃Sƒ~ƒ[ƒ‹‚Í–ž‘«‚ɂ͂قlj“‚¢D"); + else #endif + if (otmp->otyp == SCR_SCARE_MONSTER) + /* to eat scroll, hero is currently polymorphed into a monster */ +/*JP + pline("Yuck%c", otmp->blessed ? '!' : '.'); +*/ + pline("‚¨‚¦‚Á%s", otmp->blessed ? "I" : "D"); + else if (otmp->oclass == SCROLL_CLASS + /* check description after checking for specific scrolls */ + && !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM")) +/*JP + pline("Yum%c", otmp->blessed ? '!' : '.'); +*/ + pline("‚¤‚Ü‚¢%s", otmp->blessed ? "I" : "D"); + else +/*JP + pline("Needs salt..."); +*/ + pline("–¡‚ª‚¤‚·‚¢DDD"); + } if (otmp->oclass == POTION_CLASS) { otmp->quan++; /* dopotion() does a useup() */ (void) dopotion(otmp); @@ -2709,9 +2832,15 @@ struct obj *otmp; * ability to detect food that is unfit for consumption * or dangerous and avoid it. */ +#if 0 /*JP*/ char buf[BUFSZ], foodsmell[BUFSZ], it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ]; - boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE; +#else + char buf[BUFSZ], foodsmell[BUFSZ], + eat_it_anyway[QBUFSZ]; +#endif + boolean cadaver = (otmp->otyp == CORPSE || otmp->globby), + stoneorslime = FALSE; int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm; long rotted = 0L; @@ -2720,7 +2849,9 @@ struct obj *otmp; #else Strcpy(foodsmell, xname(otmp)); #endif +#if 0 /*JP*/ Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they"); +#endif #if 0 /*JP*/ Sprintf(eat_it_anyway, "Eat %s anyway?", (otmp->quan == 1L) ? "it" : "one"); @@ -2738,6 +2869,7 @@ struct obj *otmp; if (cadaver && !nonrotting_corpse(mnum)) { long age = peek_at_iced_corpse_age(otmp); + /* worst case rather than random in this calculation to force prompt */ rotted = (monstermoves - age) / (10L + 0 /* was rn2(20) */); @@ -2919,16 +3051,14 @@ doeat() pline("‘§‚à‚Å‚«‚È‚¢‚̂ɁC‚Ç‚¤‚â‚Á‚ĐH‚ׂ½‚ç‚¢‚¢‚ñ‚¾‚¢H"); return 0; } -/*JP if (!(otmp = floorfood("eat", 0))) -*/ - if (!(otmp = floorfood("H‚ׂé", 0))) return 0; if (check_capacity((char *) 0)) return 0; if (u.uedibility) { int res = edibility_prompts(otmp); + if (res) { #if 0 /*JP*/ Your( @@ -2949,10 +3079,7 @@ doeat() * mails, players who polymorph back to human in the middle of their * metallic meal, etc.... */ - if (!(carried(otmp) ? retouch_object(&otmp, FALSE) - : touch_artifact(otmp, &youmonst))) { - return 1; - } else if (!is_edible(otmp)) { + if (!is_edible(otmp)) { /*JP You("cannot eat that!"); */ @@ -2966,6 +3093,9 @@ doeat() */ You("g‚ɂ‚¯‚Ä‚¢‚éŠÔ‚͐H‚ׂê‚È‚¢D"); return 0; + } else if (!(carried(otmp) ? retouch_object(&otmp, FALSE) + : touch_artifact(otmp, &youmonst))) { + return 1; /* got blasted so use a turn */ } if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) { @@ -2983,18 +3113,34 @@ doeat() /* The regurgitated object's rustproofing is gone now */ otmp->oerodeproof = 0; make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE); + /* + * We don't expect rust monsters to be wielding welded weapons + * or wearing cursed rings which were rustproofed, but guard + * against the possibility just in case. + */ + if (welded(otmp) || (otmp->cursed && (otmp->owornmask & W_RING))) { + otmp->bknown = 1; /* for ring; welded() does this for weapon */ +/*JP + You("spit out %s.", the(xname(otmp))); +*/ + You("%s‚ð“f‚«o‚µ‚½D", xname(otmp)); + } else { #if 0 /*JP*/ - You("spit %s out onto the %s.", the(xname(otmp)), - surface(u.ux, u.uy)); + You("spit %s out onto the %s.", the(xname(otmp)), + surface(u.ux, u.uy)); #else - You("%s‚ð%s‚É“f‚«o‚µ‚½D", the(xname(otmp)), - surface(u.ux, u.uy)); + You("%s‚ð%s‚É“f‚«o‚µ‚½D", the(xname(otmp)), + surface(u.ux, u.uy)); #endif - if (carried(otmp)) { - freeinv(otmp); - dropy(otmp); + if (carried(otmp)) { + /* no need to check for leash in use; it's not metallic */ + if (otmp->owornmask) + remove_worn_item(otmp, FALSE); + freeinv(otmp); + dropy(otmp); + } + stackobj(otmp); } - stackobj(otmp); return 1; } /* KMH -- Slow digestion is... indigestible */ @@ -3047,8 +3193,11 @@ doeat() u.uconduct.unvegan++; u.uconduct.food++; - if (otmp->cursed) + if (otmp->cursed) { (void) rottenfood(otmp); + nodelicious = TRUE; + } else if (objects[otmp->otyp].oc_material == PAPER) + nodelicious = TRUE; if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) { /*JP @@ -3071,7 +3220,7 @@ doeat() You("seem unaffected by the poison."); */ You("“ł̉e‹¿‚ðŽó‚¯‚È‚¢‚悤‚¾D"); - } else if (!otmp->cursed && !nodelicious) { + } else if (!nodelicious) { #if 0 /*JP*/ pline("%s%s is delicious!", (obj_is_pname(otmp) @@ -3181,20 +3330,16 @@ doeat() } /* re-calc the nutrition */ - if (otmp->otyp == CORPSE) - basenutrit = mons[otmp->corpsenm].cnutrit; - else - basenutrit = objects[otmp->otyp].oc_nutrition; + basenutrit = (int) obj_nutrition(otmp); - debugpline1("before rounddiv: context.victual.reqtime == %d", - context.victual.reqtime); - debugpline2("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit); - context.victual.reqtime = (basenutrit == 0) - ? 0 - : rounddiv(context.victual.reqtime - * (long) otmp->oeaten, - basenutrit); - debugpline1("after rounddiv: context.victual.reqtime == %d", + debugpline3( + "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d", + context.victual.reqtime, otmp->oeaten, basenutrit); + + context.victual.reqtime = (basenutrit == 0) ? 0 + : rounddiv(context.victual.reqtime * (long) otmp->oeaten, basenutrit); + + debugpline1("after rounddiv: victual.reqtime == %d", context.victual.reqtime); /* * calculate the modulo value (nutrit. units per round eating) @@ -3217,6 +3362,47 @@ doeat() return 1; } +int +use_tin_opener(obj) +struct obj *obj; +{ + struct obj *otmp; + int res = 0; + + if (!carrying(TIN)) { +/*JP + You("have no tin to open."); +*/ + You("ŠÊ‚ðŽ‚Á‚Ä‚¢‚È‚¢D"); + return 0; + } + + if (obj != uwep) { + if (obj->cursed && obj->bknown) { + char qbuf[QBUFSZ]; + +#if 0 /*JP*/ + if (ynq(safe_qbuf(qbuf, "Really wield ", "?", + obj, doname, thesimpleoname, "that")) != 'y') +#else + if (ynq(safe_qbuf(qbuf, "–{“–‚É", "‚ð‘•”õ‚·‚éH", + obj, doname, thesimpleoname, "‚»‚ê")) != 'y') +#endif + return 0; + } + if (!wield_tool(obj, "use")) + return 0; + res = 1; + } + + otmp = getobj(comestibles, "open"); + if (!otmp) + return res; + + start_tin(otmp); + return 1; +} + /* Take a single bite from a piece of food, checking for choking and * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise. */ @@ -3246,15 +3432,21 @@ bite() return 0; } -/* as time goes by - called by moveloop() and domove() */ +/* as time goes by - called by moveloop(every move) & domove(melee attack) */ void gethungry() { if (u.uinvulnerable) return; /* you don't feel hungrier */ - if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */ - && (carnivorous(youmonst.data) || herbivorous(youmonst.data)) + /* being polymorphed into a creature which doesn't eat prevents + this first uhunger decrement, but to stay in such form the hero + will need to wear an Amulet of Unchanging so still burn a small + amount of nutrition in the 'moves % 20' ring/amulet check below */ + if ((!Unaware || !rn2(10)) /* slow metabolic rate while asleep */ + && (carnivorous(youmonst.data) + || herbivorous(youmonst.data) + || metallivorous(youmonst.data)) && !Slow_digestion) u.uhunger--; /* ordinary food consumption */ @@ -3271,8 +3463,8 @@ gethungry() /* Conflict uses up food too */ if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--; - /* +0 charged rings don't do anything, so don't affect hunger */ - /* Slow digestion still uses ring hunger */ + /* +0 charged rings don't do anything, so don't affect hunger. + Slow digestion cancels move hunger but still causes ring hunger. */ switch ((int) (moves % 20)) { /* note: use even cases only */ case 4: if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged)) @@ -3445,11 +3637,14 @@ boolean incr; } if (newhs == FAINTING) { + /* u,uhunger is likely to be negative at this point */ + int uhunger_div_by_10 = sgn(u.uhunger) * ((abs(u.uhunger) + 5) / 10); + if (is_fainted()) newhs = FAINTED; - if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) { + if (u.uhs <= WEAK || rn2(20 - uhunger_div_by_10) >= 19) { if (!is_fainted() && multi >= 0 /* %% */) { - int duration = 10 - (u.uhunger / 10); + int duration = 10 - uhunger_div_by_10; /* stop what you're doing, then faint */ stop_occupation(); @@ -3457,22 +3652,30 @@ boolean incr; You("faint from lack of food."); */ You("• ‚ªŒ¸‚Á‚Ä“|‚ꂽD"); - if (!Levitation) -/*JP - selftouch("Falling, you"); -*/ - selftouch("—Ž‚¿‚È‚ª‚çC‚ ‚È‚½‚Í"); incr_itimeout(&HDeaf, duration); + context.botl = TRUE; nomul(-duration); +/*JP multi_reason = "fainted from lack of food"; +*/ + multi_reason = "‹ó• ‚Å‘²“|‚µ‚Ä‚¢‚éŠÔ‚É"; /*JP nomovemsg = "You regain consciousness."; */ nomovemsg = "‚ ‚È‚½‚͐³‹C‚¢‚½D"; afternmv = unfaint; newhs = FAINTED; + if (!Levitation) +/*JP + selftouch("Falling, you"); +*/ + selftouch("—Ž‚¿‚È‚ª‚çC‚ ‚È‚½‚Í"); } - } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) { + + /* this used to be -(200 + 20 * Con) but that was when being asleep + suppressed per-turn uhunger decrement but being fainted didn't; + now uhunger becomes more negative at a slower rate */ + } else if (u.uhunger < -(100 + 10 * (int) ACURR(A_CON))) { u.uhs = STARVED; context.botl = 1; bot(); @@ -3492,10 +3695,23 @@ boolean incr; } if (newhs != u.uhs) { - if (newhs >= WEAK && u.uhs < WEAK) - losestr(1); /* this may kill you -- see below */ - else if (newhs < WEAK && u.uhs >= WEAK) - losestr(-1); + if (newhs >= WEAK && u.uhs < WEAK) { + /* this used to be losestr(1) which had the potential to + be fatal (still handled below) by reducing HP if it + tried to take base strength below minimum of 3 */ + ATEMP(A_STR) = -1; /* temporary loss overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } else if (newhs < WEAK && u.uhs >= WEAK) { + /* this used to be losestr(-1) which could be abused by + becoming weak while wearing ring of sustain ability, + removing ring, eating to 'restore' strength which boosted + strength by a point each time the cycle was performed; + substituting "while polymorphed" for sustain ability and + "rehumanize" for ring removal might have done that too */ + ATEMP(A_STR) = 0; /* repair of loss also overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } + switch (newhs) { case HUNGRY: if (Hallucination) { @@ -3592,10 +3808,11 @@ boolean incr; /* Returns an object representing food. * Object may be either on floor or in inventory. */ -/*JP CHECK: 3.4.3 ‚ł̌Ăяo‚µŒ³ -apply.c:1959: if (!(corpse = floorfood("ŠÊ‹l‚ß‚É‚·‚é", 2))) return; -eat.c:2404: if (!(otmp = floorfood("H‚ׂé", 0))) return 0; -pray.c:1478: if (!(otmp = floorfood("•ù‚°‚é", 1))) return 0; +/*JP CHECK: 3.6.1 ‚ł̌Ăяo‚µŒ³ +apply.c:2478: if (!(corpse = floorfood("tin", 2))) +eat.c:3050: if (!(otmp = floorfood("eat", 0))) +pray.c:1659: otmp = floorfood("sacrifice", 1); + ‚±‚̊֐”‚͉pŒê–¼‚̂܂܌Ăяo‚·‚±‚ƁB */ struct obj * floorfood(verb, corpsecheck) @@ -3605,20 +3822,16 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ register struct obj *otmp; char qbuf[QBUFSZ]; char c; -#if 0 /*JP*/ boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */ offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */ -#else - boolean feeding = !strcmp(verb, "H‚ׂé"), /* corpsecheck==0 */ - offering = !strcmp(verb, "•ù‚°‚é"); /* corpsecheck==1 */ -#endif #if 1 /*JP*/ const char *jverb = trans_verb(verb)->jp; #endif /* if we can't touch floor objects then use invent food only */ - if (!can_reach_floor(TRUE) || (feeding && u.usteed) + if (iflags.menu_requested /* command was preceded by 'm' prefix */ + || !can_reach_floor(TRUE) || (feeding && u.usteed) || (is_pool_or_lava(u.ux, u.uy) && (Wwalking || is_clinger(youmonst.data) || (Flying && !Breathless)))) @@ -3682,6 +3895,16 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ char qsfx[QBUFSZ]; boolean one = (otmp->quan == 1L); + /* if blind and without gloves, attempting to eat (or tin or + offer) a cockatrice corpse is fatal before asking whether + or not to use it; otherwise, 'm' followed by 'e' could + be used to locate cockatrice corpses without touching them */ + if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { + feel_cockatrice(otmp, FALSE); + /* if life-saved (or poly'd into stone golem), terminate + attempt to eat off floor */ + return (struct obj *) 0; + } /* "There is here; it?" or "There are here; one?" */ #if 0 /*JP*/ @@ -3706,8 +3929,8 @@ skipfloor: /* We cannot use ALL_CLASSES since that causes getobj() to skip its * "ugly checks" and we need to check for inedible items. */ - otmp = - getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb); + otmp = getobj(feeding ? allobj : offering ? offerfodder : comestibles, + verb); if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS)) if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) { /*JP @@ -3724,18 +3947,33 @@ skipfloor: void vomit() /* A good idea from David Neves */ { - if (cantvomit(youmonst.data)) + if (cantvomit(youmonst.data)) { /* doesn't cure food poisoning; message assumes that we aren't dealing with some esoteric body_part() */ /*JP Your("jaw gapes convulsively."); */ Your("‚ ‚²‚Í”­ì“I‚É‘å‚«‚­ŠJ‚¢‚½D"); - else + } else { make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE); - nomul(-2); + /* if not enough in stomach to actually vomit then dry heave; + vomiting_dialog() gives a vomit message when its countdown + reaches 0, but only if u.uhs < FAINTING (and !cantvomit()) */ + if (u.uhs >= FAINTING) + Your("%s heaves convulsively!", body_part(STOMACH)); + } + + /* nomul()/You_can_move_again used to be unconditional, which was + viable while eating but not for Vomiting countdown where hero might + be immobilized for some other reason at the time vomit() is called */ + if (multi >= -2) { + nomul(-2); +/*JP multi_reason = "vomiting"; - nomovemsg = You_can_move_again; +*/ + multi_reason = "šq“f‚µ‚Ä‚¢‚éÅ’†‚É"; + nomovemsg = You_can_move_again; + } } int @@ -3745,10 +3983,9 @@ struct obj *obj; { long uneaten_amt, full_amount; + /* get full_amount first; obj_nutrition() might modify obj->oeaten */ + full_amount = (long) obj_nutrition(obj); uneaten_amt = (long) obj->oeaten; - full_amount = (obj->otyp == CORPSE) - ? (long) mons[obj->corpsenm].cnutrit - : (long) objects[obj->otyp].oc_nutrition; if (uneaten_amt > full_amount) { impossible( "partly eaten food (%ld) more nutritious than untouched food (%ld)",