/* $NetBSD: hack.eat.c,v 1.13 2019/02/04 03:33:15 mrg Exp $ */ /* * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, * Amsterdam * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Stichting Centrum voor Wiskunde en * Informatica, nor the names of its contributors may be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1982 Jay Fenlason * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: hack.eat.c,v 1.13 2019/02/04 03:33:15 mrg Exp $"); #endif /* not lint */ #include "hack.h" #include "extern.h" static char POISONOUS[] = "ADKSVabhks"; /* hunger texts used on bottom line (each 8 chars long) */ #define SATIATED 0 #define NOT_HUNGRY 1 #define HUNGRY 2 #define WEAK 3 #define FAINTING 4 #define FAINTED 5 #define STARVED 6 const char *const hu_stat[] = { "Satiated", " ", "Hungry ", "Weak ", "Fainting", "Fainted ", "Starved " }; static int opentin(void); static int Meatdone(void); static int unfaint(void); static void newuhs(boolean); static int eatcorpse(struct obj *); void init_uhunger(void) { u.uhunger = 900; u.uhs = NOT_HUNGRY; } #define TTSZ SIZE(tintxts) static const struct { const char *txt; int nut; } tintxts[] = { { "It contains first quality peaches - what a surprise!", 40 }, { "It contains salmon - not bad!", 60 }, { "It contains apple juice - perhaps not what you hoped for.", 20 }, { "It contains some nondescript substance, tasting awfully.", 500 }, { "It contains rotten meat. You vomit.", -50 }, { "It turns out to be empty.", 0 } }; static struct { struct obj *tin; int usedtime, reqtime; } tin; static int opentin(void) { int r; if (!carried(tin.tin)) /* perhaps it was stolen? */ return (0); /* %% probably we should use tinoid */ if (tin.usedtime++ >= 50) { pline("You give up your attempt to open the tin."); return (0); } if (tin.usedtime < tin.reqtime) return (1); /* still busy */ pline("You succeed in opening the tin."); useup(tin.tin); r = rn2(2 * TTSZ); if (r < TTSZ) { pline("%s", tintxts[r].txt); lesshungry(tintxts[r].nut); if (r == 1) { /* SALMON */ Glib = rnd(15); pline("Eating salmon made your fingers very slippery."); } } else { pline("It contains spinach - this makes you feel like Popeye!"); lesshungry(600); if (u.ustr < 118) u.ustr += rnd(((u.ustr < 17) ? 19 : 118) - u.ustr); if (u.ustr > u.ustrmax) u.ustrmax = u.ustr; flags.botl = 1; } return (0); } static int Meatdone(void) { u.usym = '@'; prme(); return 0; } int doeat(void) { struct obj *otmp; struct objclass *ftmp; int tmp; /* Is there some food (probably a heavy corpse) here on the ground? */ if (!Levitation) for (otmp = fobj; otmp; otmp = otmp->nobj) { if (otmp->ox == u.ux && otmp->oy == u.uy && otmp->olet == FOOD_SYM) { pline("There %s %s here; eat %s? [ny] ", (otmp->quan == 1) ? "is" : "are", doname(otmp), (otmp->quan == 1) ? "it" : "one"); if (readchar() == 'y') { if (otmp->quan != 1) (void) splitobj(otmp, 1); freeobj(otmp); otmp = addinv(otmp); addtobill(otmp); goto gotit; } } } otmp = getobj("%", "eat"); if (!otmp) return (0); gotit: if (otmp->otyp == TIN) { if (uwep) { switch (uwep->otyp) { case CAN_OPENER: tmp = 1; break; case DAGGER: case CRYSKNIFE: tmp = 3; break; case PICK_AXE: case AXE: tmp = 6; break; default: goto no_opener; } pline("Using your %s you try to open the tin.", aobjnam(uwep, NULL)); } else { no_opener: pline("It is not so easy to open this tin."); if (Glib) { pline("The tin slips out of your hands."); if (otmp->quan > 1) { struct obj *obj; obj = splitobj(otmp, 1); if (otmp == uwep) setuwep(obj); } dropx(otmp); return (1); } tmp = 10 + rn2(1 + 500 / ((int) (u.ulevel + u.ustr))); } tin.reqtime = tmp; tin.usedtime = 0; tin.tin = otmp; occupation = opentin; occtxt = "opening the tin"; return (1); } ftmp = &objects[otmp->otyp]; multi = -ftmp->oc_delay; if (otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx; if (!rn2(7) && otmp->otyp != FORTUNE_COOKIE) { pline("Blecch! Rotten food!"); if (!rn2(4)) { pline("You feel rather light headed."); Confusion += d(2, 4); } else if (!rn2(4) && !Blind) { pline("Everything suddenly goes dark."); Blind = d(2, 10); seeoff(0); } else if (!rn2(3)) { if (Blind) pline("The world spins and you slap against the floor."); else pline("The world spins and goes dark."); nomul(-rnd(10)); nomovemsg = "You are conscious again."; } lesshungry(ftmp->nutrition / 4); } else { if (u.uhunger >= 1500) { pline("You choke over your food."); pline("You die..."); killer = ftmp->oc_name; done("choked"); } switch (otmp->otyp) { case FOOD_RATION: if (u.uhunger <= 200) pline("That food really hit the spot!"); else if (u.uhunger <= 700) pline("That satiated your stomach!"); else { pline("You're having a hard time getting all that food down."); multi -= 2; } lesshungry(ftmp->nutrition); if (multi < 0) nomovemsg = "You finished your meal."; break; case TRIPE_RATION: pline("Yak - dog food!"); more_experienced(1, 0); flags.botl = 1; if (rn2(2)) { pline("You vomit."); morehungry(20); if (Sick) { Sick = 0; /* David Neves */ pline("What a relief!"); } } else lesshungry(ftmp->nutrition); break; default: if (otmp->otyp >= CORPSE) pline("That %s tasted terrible!", ftmp->oc_name); else pline("That %s was delicious!", ftmp->oc_name); lesshungry(ftmp->nutrition); if (otmp->otyp == DEAD_LIZARD && (Confusion > 2)) Confusion = 2; else #ifdef QUEST if (otmp->otyp == CARROT && !Blind) { u.uhorizon++; setsee(); pline("Your vision improves."); } else #endif /* QUEST */ if (otmp->otyp == FORTUNE_COOKIE) { if (Blind) { pline("This cookie has a scrap of paper inside!"); pline("What a pity, that you cannot read it!"); } else outrumor(); } else if (otmp->otyp == LUMP_OF_ROYAL_JELLY) { /* This stuff seems to be VERY healthy! */ if (u.ustrmax < 118) u.ustrmax++; if (u.ustr < u.ustrmax) u.ustr++; u.uhp += rnd(20); if (u.uhp > u.uhpmax) { if (!rn2(17)) u.uhpmax++; u.uhp = u.uhpmax; } heal_legs(); } break; } } eatx: if (multi < 0 && !nomovemsg) { static char msgbuf[BUFSZ]; (void) snprintf(msgbuf, sizeof(msgbuf), "You finished eating the %s.", ftmp->oc_name); nomovemsg = msgbuf; } useup(otmp); return (1); } /* called in hack.main.c */ void gethungry(void) { --u.uhunger; if (moves % 2) { if (Regeneration) u.uhunger--; if (Hunger) u.uhunger--; /* * a3: if(Hunger & LEFT_RING) u.uhunger--; if(Hunger & * RIGHT_RING) u.uhunger--; etc. */ } if (moves % 20 == 0) { /* jimt@asgb */ if (uleft) u.uhunger--; if (uright) u.uhunger--; } newuhs(TRUE); } /* called after vomiting and after performing feats of magic */ void morehungry(int num) { u.uhunger -= num; newuhs(TRUE); } /* called after eating something (and after drinking fruit juice) */ void lesshungry(int num) { u.uhunger += num; newuhs(FALSE); } static int unfaint(void) { u.uhs = FAINTING; flags.botl = 1; return 0; } static void newuhs(boolean incr) { int newhs, h = u.uhunger; newhs = (h > 1000) ? SATIATED : (h > 150) ? NOT_HUNGRY : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING; if (newhs == FAINTING) { if (u.uhs == FAINTED) newhs = FAINTED; if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) { if (u.uhs != FAINTED && multi >= 0 /* %% */ ) { pline("You faint from lack of food."); nomul(-10 + (u.uhunger / 10)); nomovemsg = "You regain consciousness."; afternmv = unfaint; newhs = FAINTED; } } else if (u.uhunger < -(int) (200 + 25 * u.ulevel)) { u.uhs = STARVED; flags.botl = 1; bot(); pline("You die from starvation."); done("starved"); } } 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 && u.ustr < u.ustrmax) losestr(-1); switch (newhs) { case HUNGRY: pline((!incr) ? "You only feel hungry now." : (u.uhunger < 145) ? "You feel hungry." : "You are beginning to feel hungry."); break; case WEAK: pline((!incr) ? "You feel weak now." : (u.uhunger < 45) ? "You feel weak." : "You are beginning to feel weak."); break; } u.uhs = newhs; flags.botl = 1; if (u.uhp < 1) { pline("You die from hunger and exhaustion."); killer = "exhaustion"; done("starved"); } } } #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\ ? 'a' + (otyp - DEAD_ACID_BLOB)\ : '@' + (otyp - DEAD_HUMAN)) int poisonous(struct obj *otmp) { return (strchr(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0); } /* returns 1 if some text was printed */ static int eatcorpse(struct obj *otmp) { char let = CORPSE_I_TO_C(otmp->otyp); int tp = 0; if (let != 'a' && moves > otmp->age + 50 + rn2(100)) { tp++; pline("Ulch -- that meat was tainted!"); pline("You get very sick."); Sick = 10 + rn2(10); u.usick_cause = objects[otmp->otyp].oc_name; } else if (strchr(POISONOUS, let) && rn2(5)) { tp++; pline("Ecch -- that must have been poisonous!"); if (!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), "poisonous corpse"); } else pline("You don't seem affected by the poison."); } else if (strchr("ELNOPQRUuxz", let) && rn2(5)) { tp++; pline("You feel sick."); losehp(rnd(8), "cadaver"); } switch (let) { case 'L': case 'N': case 't': Teleportation |= INTRINSIC; break; case 'W': pluslvl(); break; case 'n': u.uhp = u.uhpmax; flags.botl = 1; /* FALLTHROUGH */ case '@': pline("You cannibal! You will be sorry for this!"); /* not tp++; */ /* FALLTHROUGH */ case 'd': Aggravate_monster |= INTRINSIC; break; case 'I': if (!Invis) { Invis = 50 + rn2(100); if (!See_invisible) newsym(u.ux, u.uy); } else { Invis |= INTRINSIC; See_invisible |= INTRINSIC; } /* FALLTHROUGH */ case 'y': #ifdef QUEST u.uhorizon++; #endif /* QUEST */ /* FALLTHROUGH */ case 'B': Confusion = 50; break; case 'D': Fire_resistance |= INTRINSIC; break; case 'E': Telepat |= INTRINSIC; break; case 'F': case 'Y': Cold_resistance |= INTRINSIC; break; case 'k': case 's': Poison_resistance |= INTRINSIC; break; case 'c': pline("You turn to stone."); killer = "dead cockatrice"; done("died"); break; case 'a': if (Stoned) { pline("What a pity - you just destroyed a future piece of art!"); tp++; Stoned = 0; } break; case 'M': pline("You cannot resist the temptation to mimic a treasure chest."); tp++; nomul(-30); afternmv = Meatdone; nomovemsg = "You now again prefer mimicking a human."; u.usym = '$'; prme(); break; } return (tp); }