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