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