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) 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 otmp = getobj("%", "eat"); 125 if(!otmp) return(0); 126 gotit: 127 if(otmp->otyp == TIN){ 128 if(uwep) { 129 switch(uwep->otyp) { 130 case CAN_OPENER: 131 tmp = 1; 132 break; 133 case DAGGER: 134 case CRYSKNIFE: 135 tmp = 3; 136 break; 137 case PICK_AXE: 138 case AXE: 139 tmp = 6; 140 break; 141 default: 142 goto no_opener; 143 } 144 pline("Using your %s you try to open the tin.", 145 aobjnam(uwep, (char *) 0)); 146 } else { 147 no_opener: 148 pline("It is not so easy to open this tin."); 149 if(Glib) { 150 pline("The tin slips out of your hands."); 151 if(otmp->quan > 1) { 152 struct obj *obj; 153 154 obj = splitobj(otmp, 1); 155 if(otmp == uwep) setuwep(obj); 156 } 157 dropx(otmp); 158 return(1); 159 } 160 tmp = 10 + rn2(1 + 500/((int)(u.ulevel + u.ustr))); 161 } 162 tin.reqtime = tmp; 163 tin.usedtime = 0; 164 tin.tin = otmp; 165 occupation = opentin; 166 occtxt = "opening the tin"; 167 return(1); 168 } 169 ftmp = &objects[otmp->otyp]; 170 multi = -ftmp->oc_delay; 171 if(otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx; 172 if(!rn2(7) && otmp->otyp != FORTUNE_COOKIE) { 173 pline("Blecch! Rotten food!"); 174 if(!rn2(4)) { 175 pline("You feel rather light headed."); 176 Confusion += d(2,4); 177 } else if(!rn2(4)&& !Blind) { 178 pline("Everything suddenly goes dark."); 179 Blind = d(2,10); 180 seeoff(0); 181 } else if(!rn2(3)) { 182 if(Blind) 183 pline("The world spins and you slap against the floor."); 184 else 185 pline("The world spins and goes dark."); 186 nomul(-rnd(10)); 187 nomovemsg = "You are conscious again."; 188 } 189 lesshungry(ftmp->nutrition / 4); 190 } else { 191 if(u.uhunger >= 1500) { 192 pline("You choke over your food."); 193 pline("You die..."); 194 killer = ftmp->oc_name; 195 done("choked"); 196 } 197 switch(otmp->otyp){ 198 case FOOD_RATION: 199 if(u.uhunger <= 200) 200 pline("That food really hit the spot!"); 201 else if(u.uhunger <= 700) 202 pline("That satiated your stomach!"); 203 else { 204 pline("You're having a hard time getting all that food down."); 205 multi -= 2; 206 } 207 lesshungry(ftmp->nutrition); 208 if(multi < 0) nomovemsg = "You finished your meal."; 209 break; 210 case TRIPE_RATION: 211 pline("Yak - dog food!"); 212 more_experienced(1,0); 213 flags.botl = 1; 214 if(rn2(2)){ 215 pline("You vomit."); 216 morehungry(20); 217 if(Sick) { 218 Sick = 0; /* David Neves */ 219 pline("What a relief!"); 220 } 221 } else lesshungry(ftmp->nutrition); 222 break; 223 default: 224 if(otmp->otyp >= CORPSE) 225 pline("That %s tasted terrible!",ftmp->oc_name); 226 else 227 pline("That %s was delicious!",ftmp->oc_name); 228 lesshungry(ftmp->nutrition); 229 if(otmp->otyp == DEAD_LIZARD && (Confusion > 2)) 230 Confusion = 2; 231 else 232 #ifdef QUEST 233 if(otmp->otyp == CARROT && !Blind){ 234 u.uhorizon++; 235 setsee(); 236 pline("Your vision improves."); 237 } else 238 #endif /* QUEST */ 239 if(otmp->otyp == FORTUNE_COOKIE) { 240 if(Blind) { 241 pline("This cookie has a scrap of paper inside!"); 242 pline("What a pity, that you cannot read it!"); 243 } else 244 outrumor(); 245 } else 246 if(otmp->otyp == LUMP_OF_ROYAL_JELLY) { 247 /* This stuff seems to be VERY healthy! */ 248 if(u.ustrmax < 118) u.ustrmax++; 249 if(u.ustr < u.ustrmax) u.ustr++; 250 u.uhp += rnd(20); 251 if(u.uhp > u.uhpmax) { 252 if(!rn2(17)) u.uhpmax++; 253 u.uhp = u.uhpmax; 254 } 255 heal_legs(); 256 } 257 break; 258 } 259 } 260 eatx: 261 if(multi<0 && !nomovemsg){ 262 static char msgbuf[BUFSZ]; 263 sprintf(msgbuf, "You finished eating the %s.", 264 ftmp->oc_name); 265 nomovemsg = msgbuf; 266 } 267 useup(otmp); 268 return(1); 269 } 270 271 /* called in hack.main.c */ 272 void 273 gethungry(void) 274 { 275 --u.uhunger; 276 if(moves % 2) { 277 if(Regeneration) u.uhunger--; 278 if(Hunger) u.uhunger--; 279 /* a3: if(Hunger & LEFT_RING) u.uhunger--; 280 if(Hunger & RIGHT_RING) u.uhunger--; 281 etc. */ 282 } 283 if(moves % 20 == 0) { /* jimt@asgb */ 284 if(uleft) u.uhunger--; 285 if(uright) u.uhunger--; 286 } 287 newuhs(TRUE); 288 } 289 290 /* called after vomiting and after performing feats of magic */ 291 void 292 morehungry(int num) 293 { 294 u.uhunger -= num; 295 newuhs(TRUE); 296 } 297 298 /* called after eating something (and after drinking fruit juice) */ 299 void 300 lesshungry(int num) 301 { 302 u.uhunger += num; 303 newuhs(FALSE); 304 } 305 306 static void 307 unfaint(void) 308 { 309 u.uhs = FAINTING; 310 flags.botl = 1; 311 } 312 313 static void 314 newuhs(bool incr) 315 { 316 int newhs, h = u.uhunger; 317 318 newhs = (h > 1000) ? SATIATED : 319 (h > 150) ? NOT_HUNGRY : 320 (h > 50) ? HUNGRY : 321 (h > 0) ? WEAK : FAINTING; 322 323 if(newhs == FAINTING) { 324 if(u.uhs == FAINTED) 325 newhs = FAINTED; 326 if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) { 327 if(u.uhs != FAINTED && multi >= 0 /* %% */) { 328 pline("You faint from lack of food."); 329 nomul(-10+(u.uhunger/10)); 330 nomovemsg = "You regain consciousness."; 331 afternmv = unfaint; 332 newhs = FAINTED; 333 } 334 } else 335 if(u.uhunger < -(int)(200 + 25*u.ulevel)) { 336 u.uhs = STARVED; 337 flags.botl = 1; 338 bot(); 339 pline("You die from starvation."); 340 done("starved"); 341 } 342 } 343 344 if(newhs != u.uhs) { 345 if(newhs >= WEAK && u.uhs < WEAK) 346 losestr(1); /* this may kill you -- see below */ 347 else 348 if(newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax) 349 losestr(-1); 350 switch(newhs){ 351 case HUNGRY: 352 pline((!incr) ? "You only feel hungry now." : 353 (u.uhunger < 145) ? "You feel hungry." : 354 "You are beginning to feel hungry."); 355 break; 356 case WEAK: 357 pline((!incr) ? "You feel weak now." : 358 (u.uhunger < 45) ? "You feel weak." : 359 "You are beginning to feel weak."); 360 break; 361 } 362 u.uhs = newhs; 363 flags.botl = 1; 364 if(u.uhp < 1) { 365 pline("You die from hunger and exhaustion."); 366 killer = "exhaustion"; 367 done("starved"); 368 } 369 } 370 } 371 372 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\ 373 ? 'a' + (otyp - DEAD_ACID_BLOB)\ 374 : '@' + (otyp - DEAD_HUMAN)) 375 bool 376 poisonous(struct obj *otmp) 377 { 378 return(index(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0); 379 } 380 381 /* returns 1 if some text was printed */ 382 static int 383 eatcorpse(struct obj *otmp) 384 { 385 char let = CORPSE_I_TO_C(otmp->otyp); 386 int tp = 0; 387 if(let != 'a' && moves > otmp->age + 50 + rn2(100)) { 388 tp++; 389 pline("Ulch -- that meat was tainted!"); 390 pline("You get very sick."); 391 Sick = 10 + rn2(10); 392 u.usick_cause = objects[otmp->otyp].oc_name; 393 } else if(index(POISONOUS, let) && rn2(5)){ 394 tp++; 395 pline("Ecch -- that must have been poisonous!"); 396 if(!Poison_resistance){ 397 losestr(rnd(4)); 398 losehp(rnd(15), "poisonous corpse"); 399 } else 400 pline("You don't seem affected by the poison."); 401 } else if(index("ELNOPQRUuxz", let) && rn2(5)){ 402 tp++; 403 pline("You feel sick."); 404 losehp(rnd(8), "cadaver"); 405 } 406 switch(let) { 407 case 'L': 408 case 'N': 409 case 't': 410 Teleportation |= INTRINSIC; 411 break; 412 case 'W': 413 pluslvl(); 414 break; 415 case 'n': 416 u.uhp = u.uhpmax; 417 flags.botl = 1; 418 /* fall into next case */ 419 case '@': 420 pline("You cannibal! You will be sorry for this!"); 421 /* not tp++; */ 422 /* fall into next case */ 423 case 'd': 424 Aggravate_monster |= INTRINSIC; 425 break; 426 case 'I': 427 if(!Invis) { 428 Invis = 50+rn2(100); 429 if(!See_invisible) 430 newsym(u.ux, u.uy); 431 } else { 432 Invis |= INTRINSIC; 433 See_invisible |= INTRINSIC; 434 } 435 /* fall into next case */ 436 case 'y': 437 #ifdef QUEST 438 u.uhorizon++; 439 #endif /* QUEST */ 440 /* fall into next case */ 441 case 'B': 442 Confusion = 50; 443 break; 444 case 'D': 445 Fire_resistance |= INTRINSIC; 446 break; 447 case 'E': 448 Telepat |= INTRINSIC; 449 break; 450 case 'F': 451 case 'Y': 452 Cold_resistance |= INTRINSIC; 453 break; 454 case 'k': 455 case 's': 456 Poison_resistance |= INTRINSIC; 457 break; 458 case 'c': 459 pline("You turn to stone."); 460 killer = "dead cockatrice"; 461 done("died"); 462 /* NOTREACHED */ 463 case 'a': 464 if(Stoned) { 465 pline("What a pity - you just destroyed a future piece of art!"); 466 tp++; 467 Stoned = 0; 468 } 469 break; 470 case 'M': 471 pline("You cannot resist the temptation to mimic a treasure chest."); 472 tp++; 473 nomul(-30); 474 afternmv = Meatdone; 475 nomovemsg = "You now again prefer mimicking a human."; 476 u.usym = '$'; 477 prme(); 478 break; 479 } 480 return(tp); 481 } 482