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