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