1 /* $NetBSD: hack.eat.c,v 1.8 2009/06/07 20:13:18 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.8 2009/06/07 20:13:18 dholland 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(void) 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(void) 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(void) 155 { 156 u.usym = '@'; 157 prme(); 158 return 0; 159 } 160 161 int 162 doeat(void) 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) snprintf(msgbuf, sizeof(msgbuf), 334 "You finished eating the %s.", 335 ftmp->oc_name); 336 nomovemsg = msgbuf; 337 } 338 useup(otmp); 339 return (1); 340 } 341 342 /* called in hack.main.c */ 343 void 344 gethungry(void) 345 { 346 --u.uhunger; 347 if (moves % 2) { 348 if (Regeneration) 349 u.uhunger--; 350 if (Hunger) 351 u.uhunger--; 352 /* 353 * a3: if(Hunger & LEFT_RING) u.uhunger--; if(Hunger & 354 * RIGHT_RING) u.uhunger--; etc. 355 */ 356 } 357 if (moves % 20 == 0) { /* jimt@asgb */ 358 if (uleft) 359 u.uhunger--; 360 if (uright) 361 u.uhunger--; 362 } 363 newuhs(TRUE); 364 } 365 366 /* called after vomiting and after performing feats of magic */ 367 void 368 morehungry(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(int num) 377 { 378 u.uhunger += num; 379 newuhs(FALSE); 380 } 381 382 int 383 unfaint(void) 384 { 385 u.uhs = FAINTING; 386 flags.botl = 1; 387 return 0; 388 } 389 390 void 391 newuhs(boolean incr) 392 { 393 int newhs, h = u.uhunger; 394 395 newhs = (h > 1000) ? SATIATED : 396 (h > 150) ? NOT_HUNGRY : 397 (h > 50) ? HUNGRY : 398 (h > 0) ? WEAK : FAINTING; 399 400 if (newhs == FAINTING) { 401 if (u.uhs == FAINTED) 402 newhs = FAINTED; 403 if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) { 404 if (u.uhs != FAINTED && multi >= 0 /* %% */ ) { 405 pline("You faint from lack of food."); 406 nomul(-10 + (u.uhunger / 10)); 407 nomovemsg = "You regain consciousness."; 408 afternmv = unfaint; 409 newhs = FAINTED; 410 } 411 } else if (u.uhunger < -(int) (200 + 25 * u.ulevel)) { 412 u.uhs = STARVED; 413 flags.botl = 1; 414 bot(); 415 pline("You die from starvation."); 416 done("starved"); 417 } 418 } 419 if (newhs != u.uhs) { 420 if (newhs >= WEAK && u.uhs < WEAK) 421 losestr(1); /* this may kill you -- see below */ 422 else if (newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax) 423 losestr(-1); 424 switch (newhs) { 425 case HUNGRY: 426 pline((!incr) ? "You only feel hungry now." : 427 (u.uhunger < 145) ? "You feel hungry." : 428 "You are beginning to feel hungry."); 429 break; 430 case WEAK: 431 pline((!incr) ? "You feel weak now." : 432 (u.uhunger < 45) ? "You feel weak." : 433 "You are beginning to feel weak."); 434 break; 435 } 436 u.uhs = newhs; 437 flags.botl = 1; 438 if (u.uhp < 1) { 439 pline("You die from hunger and exhaustion."); 440 killer = "exhaustion"; 441 done("starved"); 442 } 443 } 444 } 445 446 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\ 447 ? 'a' + (otyp - DEAD_ACID_BLOB)\ 448 : '@' + (otyp - DEAD_HUMAN)) 449 int 450 poisonous(struct obj *otmp) 451 { 452 return (strchr(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0); 453 } 454 455 /* returns 1 if some text was printed */ 456 int 457 eatcorpse(struct obj *otmp) 458 { 459 char let = CORPSE_I_TO_C(otmp->otyp); 460 int tp = 0; 461 if (let != 'a' && moves > otmp->age + 50 + rn2(100)) { 462 tp++; 463 pline("Ulch -- that meat was tainted!"); 464 pline("You get very sick."); 465 Sick = 10 + rn2(10); 466 u.usick_cause = objects[otmp->otyp].oc_name; 467 } else if (strchr(POISONOUS, let) && rn2(5)) { 468 tp++; 469 pline("Ecch -- that must have been poisonous!"); 470 if (!Poison_resistance) { 471 losestr(rnd(4)); 472 losehp(rnd(15), "poisonous corpse"); 473 } else 474 pline("You don't seem affected by the poison."); 475 } else if (strchr("ELNOPQRUuxz", let) && rn2(5)) { 476 tp++; 477 pline("You feel sick."); 478 losehp(rnd(8), "cadaver"); 479 } 480 switch (let) { 481 case 'L': 482 case 'N': 483 case 't': 484 Teleportation |= INTRINSIC; 485 break; 486 case 'W': 487 pluslvl(); 488 break; 489 case 'n': 490 u.uhp = u.uhpmax; 491 flags.botl = 1; 492 /* fall into next case */ 493 case '@': 494 pline("You cannibal! You will be sorry for this!"); 495 /* not tp++; */ 496 /* fall into next case */ 497 case 'd': 498 Aggravate_monster |= INTRINSIC; 499 break; 500 case 'I': 501 if (!Invis) { 502 Invis = 50 + rn2(100); 503 if (!See_invisible) 504 newsym(u.ux, u.uy); 505 } else { 506 Invis |= INTRINSIC; 507 See_invisible |= INTRINSIC; 508 } 509 /* fall into next case */ 510 case 'y': 511 #ifdef QUEST 512 u.uhorizon++; 513 #endif /* QUEST */ 514 /* fall into next case */ 515 case 'B': 516 Confusion = 50; 517 break; 518 case 'D': 519 Fire_resistance |= INTRINSIC; 520 break; 521 case 'E': 522 Telepat |= INTRINSIC; 523 break; 524 case 'F': 525 case 'Y': 526 Cold_resistance |= INTRINSIC; 527 break; 528 case 'k': 529 case 's': 530 Poison_resistance |= INTRINSIC; 531 break; 532 case 'c': 533 pline("You turn to stone."); 534 killer = "dead cockatrice"; 535 done("died"); 536 /* NOTREACHED */ 537 case 'a': 538 if (Stoned) { 539 pline("What a pity - you just destroyed a future piece of art!"); 540 tp++; 541 Stoned = 0; 542 } 543 break; 544 case 'M': 545 pline("You cannot resist the temptation to mimic a treasure chest."); 546 tp++; 547 nomul(-30); 548 afternmv = Meatdone; 549 nomovemsg = "You now again prefer mimicking a human."; 550 u.usym = '$'; 551 prme(); 552 break; 553 } 554 return (tp); 555 } 556