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