1 /* $NetBSD: hack.eat.c,v 1.13 2019/02/04 03:33:15 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include "hack.h" 65 #include "extern.h" 66 static char POISONOUS[] = "ADKSVabhks"; 67 68 /* hunger texts used on bottom line (each 8 chars long) */ 69 #define SATIATED 0 70 #define NOT_HUNGRY 1 71 #define HUNGRY 2 72 #define WEAK 3 73 #define FAINTING 4 74 #define FAINTED 5 75 #define STARVED 6 76 77 const char *const hu_stat[] = { 78 "Satiated", 79 " ", 80 "Hungry ", 81 "Weak ", 82 "Fainting", 83 "Fainted ", 84 "Starved " 85 }; 86 87 static int opentin(void); 88 static int Meatdone(void); 89 static int unfaint(void); 90 static void newuhs(boolean); 91 static int eatcorpse(struct obj *); 92 93 void 94 init_uhunger(void) 95 { 96 u.uhunger = 900; 97 u.uhs = NOT_HUNGRY; 98 } 99 100 #define TTSZ SIZE(tintxts) 101 static const struct { 102 const char *txt; 103 int nut; 104 } tintxts[] = { 105 { "It contains first quality peaches - what a surprise!", 40 }, 106 { "It contains salmon - not bad!", 60 }, 107 { "It contains apple juice - perhaps not what you hoped for.", 20 }, 108 { "It contains some nondescript substance, tasting awfully.", 500 }, 109 { "It contains rotten meat. You vomit.", -50 }, 110 { "It turns out to be empty.", 0 } 111 }; 112 113 static struct { 114 struct obj *tin; 115 int usedtime, reqtime; 116 } tin; 117 118 static int 119 opentin(void) 120 { 121 int r; 122 123 if (!carried(tin.tin)) /* perhaps it was stolen? */ 124 return (0); /* %% probably we should use tinoid */ 125 if (tin.usedtime++ >= 50) { 126 pline("You give up your attempt to open the tin."); 127 return (0); 128 } 129 if (tin.usedtime < tin.reqtime) 130 return (1); /* still busy */ 131 132 pline("You succeed in opening the tin."); 133 useup(tin.tin); 134 r = rn2(2 * TTSZ); 135 if (r < TTSZ) { 136 pline("%s", tintxts[r].txt); 137 lesshungry(tintxts[r].nut); 138 if (r == 1) { /* SALMON */ 139 Glib = rnd(15); 140 pline("Eating salmon made your fingers very slippery."); 141 } 142 } else { 143 pline("It contains spinach - this makes you feel like Popeye!"); 144 lesshungry(600); 145 if (u.ustr < 118) 146 u.ustr += rnd(((u.ustr < 17) ? 19 : 118) - u.ustr); 147 if (u.ustr > u.ustrmax) 148 u.ustrmax = u.ustr; 149 flags.botl = 1; 150 } 151 return (0); 152 } 153 154 static int 155 Meatdone(void) 156 { 157 u.usym = '@'; 158 prme(); 159 return 0; 160 } 161 162 int 163 doeat(void) 164 { 165 struct obj *otmp; 166 struct objclass *ftmp; 167 int tmp; 168 169 /* Is there some food (probably a heavy corpse) here on the ground? */ 170 if (!Levitation) 171 for (otmp = fobj; otmp; otmp = otmp->nobj) { 172 if (otmp->ox == u.ux && otmp->oy == u.uy && 173 otmp->olet == FOOD_SYM) { 174 pline("There %s %s here; eat %s? [ny] ", 175 (otmp->quan == 1) ? "is" : "are", 176 doname(otmp), 177 (otmp->quan == 1) ? "it" : "one"); 178 if (readchar() == 'y') { 179 if (otmp->quan != 1) 180 (void) splitobj(otmp, 1); 181 freeobj(otmp); 182 otmp = addinv(otmp); 183 addtobill(otmp); 184 goto gotit; 185 } 186 } 187 } 188 otmp = getobj("%", "eat"); 189 if (!otmp) 190 return (0); 191 gotit: 192 if (otmp->otyp == TIN) { 193 if (uwep) { 194 switch (uwep->otyp) { 195 case CAN_OPENER: 196 tmp = 1; 197 break; 198 case DAGGER: 199 case CRYSKNIFE: 200 tmp = 3; 201 break; 202 case PICK_AXE: 203 case AXE: 204 tmp = 6; 205 break; 206 default: 207 goto no_opener; 208 } 209 pline("Using your %s you try to open the tin.", 210 aobjnam(uwep, NULL)); 211 } else { 212 no_opener: 213 pline("It is not so easy to open this tin."); 214 if (Glib) { 215 pline("The tin slips out of your hands."); 216 if (otmp->quan > 1) { 217 struct obj *obj; 218 219 obj = splitobj(otmp, 1); 220 if (otmp == uwep) 221 setuwep(obj); 222 } 223 dropx(otmp); 224 return (1); 225 } 226 tmp = 10 + rn2(1 + 500 / ((int) (u.ulevel + u.ustr))); 227 } 228 tin.reqtime = tmp; 229 tin.usedtime = 0; 230 tin.tin = otmp; 231 occupation = opentin; 232 occtxt = "opening the tin"; 233 return (1); 234 } 235 ftmp = &objects[otmp->otyp]; 236 multi = -ftmp->oc_delay; 237 if (otmp->otyp >= CORPSE && eatcorpse(otmp)) 238 goto eatx; 239 if (!rn2(7) && otmp->otyp != FORTUNE_COOKIE) { 240 pline("Blecch! Rotten food!"); 241 if (!rn2(4)) { 242 pline("You feel rather light headed."); 243 Confusion += d(2, 4); 244 } else if (!rn2(4) && !Blind) { 245 pline("Everything suddenly goes dark."); 246 Blind = d(2, 10); 247 seeoff(0); 248 } else if (!rn2(3)) { 249 if (Blind) 250 pline("The world spins and you slap against the floor."); 251 else 252 pline("The world spins and goes dark."); 253 nomul(-rnd(10)); 254 nomovemsg = "You are conscious again."; 255 } 256 lesshungry(ftmp->nutrition / 4); 257 } else { 258 if (u.uhunger >= 1500) { 259 pline("You choke over your food."); 260 pline("You die..."); 261 killer = ftmp->oc_name; 262 done("choked"); 263 } 264 switch (otmp->otyp) { 265 case FOOD_RATION: 266 if (u.uhunger <= 200) 267 pline("That food really hit the spot!"); 268 else if (u.uhunger <= 700) 269 pline("That satiated your stomach!"); 270 else { 271 pline("You're having a hard time getting all that food down."); 272 multi -= 2; 273 } 274 lesshungry(ftmp->nutrition); 275 if (multi < 0) 276 nomovemsg = "You finished your meal."; 277 break; 278 case TRIPE_RATION: 279 pline("Yak - dog food!"); 280 more_experienced(1, 0); 281 flags.botl = 1; 282 if (rn2(2)) { 283 pline("You vomit."); 284 morehungry(20); 285 if (Sick) { 286 Sick = 0; /* David Neves */ 287 pline("What a relief!"); 288 } 289 } else 290 lesshungry(ftmp->nutrition); 291 break; 292 default: 293 if (otmp->otyp >= CORPSE) 294 pline("That %s tasted terrible!", ftmp->oc_name); 295 else 296 pline("That %s was delicious!", ftmp->oc_name); 297 lesshungry(ftmp->nutrition); 298 if (otmp->otyp == DEAD_LIZARD && (Confusion > 2)) 299 Confusion = 2; 300 else 301 #ifdef QUEST 302 if (otmp->otyp == CARROT && !Blind) { 303 u.uhorizon++; 304 setsee(); 305 pline("Your vision improves."); 306 } else 307 #endif /* QUEST */ 308 if (otmp->otyp == FORTUNE_COOKIE) { 309 if (Blind) { 310 pline("This cookie has a scrap of paper inside!"); 311 pline("What a pity, that you cannot read it!"); 312 } else 313 outrumor(); 314 } else if (otmp->otyp == LUMP_OF_ROYAL_JELLY) { 315 /* This stuff seems to be VERY healthy! */ 316 if (u.ustrmax < 118) 317 u.ustrmax++; 318 if (u.ustr < u.ustrmax) 319 u.ustr++; 320 u.uhp += rnd(20); 321 if (u.uhp > u.uhpmax) { 322 if (!rn2(17)) 323 u.uhpmax++; 324 u.uhp = u.uhpmax; 325 } 326 heal_legs(); 327 } 328 break; 329 } 330 } 331 eatx: 332 if (multi < 0 && !nomovemsg) { 333 static char msgbuf[BUFSZ]; 334 (void) snprintf(msgbuf, sizeof(msgbuf), 335 "You finished eating the %s.", 336 ftmp->oc_name); 337 nomovemsg = msgbuf; 338 } 339 useup(otmp); 340 return (1); 341 } 342 343 /* called in hack.main.c */ 344 void 345 gethungry(void) 346 { 347 --u.uhunger; 348 if (moves % 2) { 349 if (Regeneration) 350 u.uhunger--; 351 if (Hunger) 352 u.uhunger--; 353 /* 354 * a3: if(Hunger & LEFT_RING) u.uhunger--; if(Hunger & 355 * RIGHT_RING) u.uhunger--; etc. 356 */ 357 } 358 if (moves % 20 == 0) { /* jimt@asgb */ 359 if (uleft) 360 u.uhunger--; 361 if (uright) 362 u.uhunger--; 363 } 364 newuhs(TRUE); 365 } 366 367 /* called after vomiting and after performing feats of magic */ 368 void 369 morehungry(int num) 370 { 371 u.uhunger -= num; 372 newuhs(TRUE); 373 } 374 375 /* called after eating something (and after drinking fruit juice) */ 376 void 377 lesshungry(int num) 378 { 379 u.uhunger += num; 380 newuhs(FALSE); 381 } 382 383 static int 384 unfaint(void) 385 { 386 u.uhs = FAINTING; 387 flags.botl = 1; 388 return 0; 389 } 390 391 static void 392 newuhs(boolean incr) 393 { 394 int newhs, h = u.uhunger; 395 396 newhs = (h > 1000) ? SATIATED : 397 (h > 150) ? NOT_HUNGRY : 398 (h > 50) ? HUNGRY : 399 (h > 0) ? WEAK : FAINTING; 400 401 if (newhs == FAINTING) { 402 if (u.uhs == FAINTED) 403 newhs = FAINTED; 404 if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) { 405 if (u.uhs != FAINTED && multi >= 0 /* %% */ ) { 406 pline("You faint from lack of food."); 407 nomul(-10 + (u.uhunger / 10)); 408 nomovemsg = "You regain consciousness."; 409 afternmv = unfaint; 410 newhs = FAINTED; 411 } 412 } else if (u.uhunger < -(int) (200 + 25 * u.ulevel)) { 413 u.uhs = STARVED; 414 flags.botl = 1; 415 bot(); 416 pline("You die from starvation."); 417 done("starved"); 418 } 419 } 420 if (newhs != u.uhs) { 421 if (newhs >= WEAK && u.uhs < WEAK) 422 losestr(1); /* this may kill you -- see below */ 423 else if (newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax) 424 losestr(-1); 425 switch (newhs) { 426 case HUNGRY: 427 pline((!incr) ? "You only feel hungry now." : 428 (u.uhunger < 145) ? "You feel hungry." : 429 "You are beginning to feel hungry."); 430 break; 431 case WEAK: 432 pline((!incr) ? "You feel weak now." : 433 (u.uhunger < 45) ? "You feel weak." : 434 "You are beginning to feel weak."); 435 break; 436 } 437 u.uhs = newhs; 438 flags.botl = 1; 439 if (u.uhp < 1) { 440 pline("You die from hunger and exhaustion."); 441 killer = "exhaustion"; 442 done("starved"); 443 } 444 } 445 } 446 447 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\ 448 ? 'a' + (otyp - DEAD_ACID_BLOB)\ 449 : '@' + (otyp - DEAD_HUMAN)) 450 int 451 poisonous(struct obj *otmp) 452 { 453 return (strchr(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0); 454 } 455 456 /* returns 1 if some text was printed */ 457 static int 458 eatcorpse(struct obj *otmp) 459 { 460 char let = CORPSE_I_TO_C(otmp->otyp); 461 int tp = 0; 462 if (let != 'a' && moves > otmp->age + 50 + rn2(100)) { 463 tp++; 464 pline("Ulch -- that meat was tainted!"); 465 pline("You get very sick."); 466 Sick = 10 + rn2(10); 467 u.usick_cause = objects[otmp->otyp].oc_name; 468 } else if (strchr(POISONOUS, let) && rn2(5)) { 469 tp++; 470 pline("Ecch -- that must have been poisonous!"); 471 if (!Poison_resistance) { 472 losestr(rnd(4)); 473 losehp(rnd(15), "poisonous corpse"); 474 } else 475 pline("You don't seem affected by the poison."); 476 } else if (strchr("ELNOPQRUuxz", let) && rn2(5)) { 477 tp++; 478 pline("You feel sick."); 479 losehp(rnd(8), "cadaver"); 480 } 481 switch (let) { 482 case 'L': 483 case 'N': 484 case 't': 485 Teleportation |= INTRINSIC; 486 break; 487 case 'W': 488 pluslvl(); 489 break; 490 case 'n': 491 u.uhp = u.uhpmax; 492 flags.botl = 1; 493 /* FALLTHROUGH */ 494 case '@': 495 pline("You cannibal! You will be sorry for this!"); 496 /* not tp++; */ 497 /* FALLTHROUGH */ 498 case 'd': 499 Aggravate_monster |= INTRINSIC; 500 break; 501 case 'I': 502 if (!Invis) { 503 Invis = 50 + rn2(100); 504 if (!See_invisible) 505 newsym(u.ux, u.uy); 506 } else { 507 Invis |= INTRINSIC; 508 See_invisible |= INTRINSIC; 509 } 510 /* FALLTHROUGH */ 511 case 'y': 512 #ifdef QUEST 513 u.uhorizon++; 514 #endif /* QUEST */ 515 /* FALLTHROUGH */ 516 case 'B': 517 Confusion = 50; 518 break; 519 case 'D': 520 Fire_resistance |= INTRINSIC; 521 break; 522 case 'E': 523 Telepat |= INTRINSIC; 524 break; 525 case 'F': 526 case 'Y': 527 Cold_resistance |= INTRINSIC; 528 break; 529 case 'k': 530 case 's': 531 Poison_resistance |= INTRINSIC; 532 break; 533 case 'c': 534 pline("You turn to stone."); 535 killer = "dead cockatrice"; 536 done("died"); 537 break; 538 case 'a': 539 if (Stoned) { 540 pline("What a pity - you just destroyed a future piece of art!"); 541 tp++; 542 Stoned = 0; 543 } 544 break; 545 case 'M': 546 pline("You cannot resist the temptation to mimic a treasure chest."); 547 tp++; 548 nomul(-30); 549 afternmv = Meatdone; 550 nomovemsg = "You now again prefer mimicking a human."; 551 u.usym = '$'; 552 prme(); 553 break; 554 } 555 return (tp); 556 } 557