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