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