1 | /* SCCS Id: @(#)eat.c 3.3 1999/12/13 */ 2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | #include "hack.h" 6 | /* #define DEBUG */ /* uncomment to enable new eat code debugging */ 7 | 8 | #ifdef DEBUG 9 | # ifdef WIZARD 10 | #define debugpline if (wizard) pline 11 | # else 12 | #define debugpline pline 13 | # endif 14 | #endif 15 | 16 | STATIC_PTR int NDECL(eatmdone); 17 | STATIC_PTR int NDECL(eatfood); 18 | STATIC_PTR int NDECL(opentin); 19 | STATIC_PTR int NDECL(unfaint); 20 | 21 | #ifdef OVLB 22 | STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P)); 23 | STATIC_DCL void FDECL(choke, (struct obj *)); 24 | STATIC_DCL void NDECL(recalc_wt); 25 | STATIC_DCL struct obj *FDECL(touchfood, (struct obj *)); 26 | STATIC_DCL void NDECL(do_reset_eat); 27 | STATIC_DCL void FDECL(done_eating, (BOOLEAN_P)); 28 | STATIC_DCL void FDECL(cprefx, (int)); 29 | STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *)); 30 | STATIC_DCL void FDECL(givit, (int,struct permonst *)); 31 | STATIC_DCL void FDECL(cpostfx, (int)); 32 | STATIC_DCL void FDECL(start_tin, (struct obj *)); 33 | STATIC_DCL int FDECL(eatcorpse, (struct obj *)); 34 | STATIC_DCL void FDECL(start_eating, (struct obj *)); 35 | STATIC_DCL void FDECL(fprefx, (struct obj *)); 36 | STATIC_DCL void FDECL(fpostfx, (struct obj *)); 37 | STATIC_DCL int NDECL(bite); 38 | 39 | STATIC_DCL int FDECL(rottenfood, (struct obj *)); 40 | STATIC_DCL void NDECL(eatspecial); 41 | STATIC_DCL void FDECL(eataccessory, (struct obj *)); 42 | STATIC_DCL const char * FDECL(foodword, (struct obj *)); 43 | 44 | char msgbuf[BUFSZ]; 45 | 46 | #endif /* OVLB */ 47 | 48 | /* hunger texts used on bottom line (each 8 chars long) */ 49 | #define SATIATED 0 50 | #define NOT_HUNGRY 1 51 | #define HUNGRY 2 52 | #define WEAK 3 53 | #define FAINTING 4 54 | #define FAINTED 5 55 | #define STARVED 6 56 | 57 | /* also used to see if you're allowed to eat cats and dogs */ 58 | #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC)) 59 | 60 | #ifndef OVLB 61 | 62 | STATIC_DCL NEARDATA const char comestibles[]; 63 | STATIC_DCL NEARDATA const char allobj[]; 64 | STATIC_DCL boolean force_save_hs; 65 | 66 | #else 67 | 68 | STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 }; 69 | 70 | /* Gold must come first for getobj(). */ 71 | STATIC_OVL NEARDATA const char allobj[] = { 72 | GOLD_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS, 73 | WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS, 74 | GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 }; 75 | 76 | STATIC_OVL boolean force_save_hs = FALSE; 77 | 78 | const char *hu_stat[] = { 79 | "Satiated", 80 | " ", 81 | "Hungry ", 82 | "Weak ", 83 | "Fainting", 84 | "Fainted ", 85 | "Starved " 86 | }; 87 | 88 | #endif /* OVLB */ 89 | #ifdef OVL1 90 | 91 | /* 92 | * Decide whether a particular object can be eaten by the possibly 93 | * polymorphed character. Not used for monster checks. 94 | */ 95 | boolean 96 | is_edible(obj) 97 | register struct obj *obj; 98 | { 99 | /* protect invocation tools but not Rider corpses (handled elsewhere)*/ 100 | /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */ 101 | if (objects[obj->otyp].oc_unique) 102 | return FALSE; 103 | /* above also prevents the Amulet from being eaten, so we must never 104 | allow fake amulets to be eaten either [which is already the case] */ 105 | 106 | if (metallivorous(youmonst.data) && is_metallic(obj)) 107 | return TRUE; 108 | if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) && 109 | /* [g.cubes can eat containers and retain all contents 110 | as engulfed items, but poly'd player can't do that] */ 111 | !Has_contents(obj)) 112 | return TRUE; 113 | 114 | /* return((boolean)(!!index(comestibles, obj->oclass))); */ 115 | return (boolean)(obj->oclass == FOOD_CLASS); 116 | } 117 | 118 | #endif /* OVL1 */ 119 | #ifdef OVLB 120 | 121 | void 122 | init_uhunger() 123 | { 124 | u.uhunger = 900; 125 | u.uhs = NOT_HUNGRY; 126 | } 127 | 128 | static const struct { const char *txt; int nut; } tintxts[] = { 129 | {"deep fried", 60}, 130 | {"pickled", 40}, 131 | {"soup made from", 20}, 132 | {"pureed", 500}, 133 | #define ROTTEN_TIN 4 134 | {"rotten", -50}, 135 | #define HOMEMADE_TIN 5 136 | {"homemade", 50}, 137 | {"stir fried", 80}, 138 | {"candied", 100}, 139 | {"boiled", 50}, 140 | {"dried", 55}, 141 | {"szechuan", 70}, 142 | {"french fried", 40}, 143 | {"sauteed", 95}, 144 | {"broiled", 80}, 145 | {"smoked", 50}, 146 | {"", 0} 147 | }; 148 | #define TTSZ SIZE(tintxts) 149 | 150 | static NEARDATA struct { 151 | struct obj *tin; 152 | int usedtime, reqtime; 153 | } tin; 154 | 155 | static NEARDATA struct { 156 | struct obj *piece; /* the thing being eaten, or last thing that 157 | * was partially eaten, unless that thing was 158 | * a tin, which uses the tin structure above, 159 | * in which case this should be 0 */ 160 | /* doeat() initializes these when piece is valid */ 161 | int usedtime, /* turns spent eating */ 162 | reqtime; /* turns required to eat */ 163 | int nmod; /* coded nutrition per turn */ 164 | Bitfield(canchoke,1); /* was satiated at beginning */ 165 | 166 | /* start_eating() initializes these */ 167 | Bitfield(fullwarn,1); /* have warned about being full */ 168 | Bitfield(eating,1); /* victual currently being eaten */ 169 | Bitfield(doreset,1); /* stop eating at end of turn */ 170 | } victual; 171 | 172 | static char *eatmbuf = 0; /* set by cpostfx() */ 173 | 174 | STATIC_PTR 175 | int 176 | eatmdone() /* called after mimicing is over */ 177 | { 178 | /* release `eatmbuf' */ 179 | if (eatmbuf) { 180 | if (nomovemsg == eatmbuf) nomovemsg = 0; 181 | free((genericptr_t)eatmbuf), eatmbuf = 0; 182 | } 183 | /* update display */ 184 | if (youmonst.m_ap_type) { 185 | youmonst.m_ap_type = M_AP_NOTHING; 186 | newsym(u.ux,u.uy); 187 | } 188 | return 0; 189 | } 190 | 191 | /* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */ 192 | STATIC_OVL const char * 193 | food_xname(food, the_pfx) 194 | struct obj *food; 195 | boolean the_pfx; 196 | { 197 | const char *result; 198 | int mnum = food->corpsenm; 199 | 200 | if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) { 201 | /* grab xname()'s modifiable return buffer for our own use */ 202 | char *bufp = xname(food); 203 | Sprintf(bufp, "%s%s corpse", 204 | (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "", 205 | s_suffix(mons[mnum].mname)); 206 | result = bufp; 207 | } else { 208 | /* the ordinary case */ 209 | result = singular(food, xname); 210 | if (the_pfx) result = the(result); 211 | } 212 | return result; 213 | } 214 | 215 | /* Created by GAN 01/28/87 216 | * Amended by AKP 09/22/87: if not hard, don't choke, just vomit. 217 | * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk. 218 | * 11/10/89: if hard, rarely vomit anyway, for slim chance. 219 | */ 220 | STATIC_OVL void 221 | choke(food) /* To a full belly all food is bad. (It.) */ 222 | register struct obj *food; 223 | { 224 | /* only happens if you were satiated */ 225 | if (u.uhs != SATIATED) { 226 | if (food->otyp != AMULET_OF_STRANGULATION) 227 | return; 228 | } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) { 229 | adjalign(-1); /* gluttony is unchivalrous */ 230 | You_feel("like a glutton!"); 231 | } 232 | 233 | exercise(A_CON, FALSE); 234 | 235 | if (Breathless || (!Strangled && !rn2(20))) { 236 | /* choking by eating AoS doesn't involve stuffing yourself */ 237 | if (food->otyp == AMULET_OF_STRANGULATION) { 238 | You("choke, but recover your composure."); 239 | return; 240 | } 241 | You("stuff yourself and then vomit voluminously."); 242 | morehungry(1000); /* you just got *very* sick! */ 243 | vomit(); 244 | } else { 245 | killer_format = KILLED_BY_AN; 246 | /* 247 | * Note all "killer"s below read "Choked on %s" on the 248 | * high score list & tombstone. So plan accordingly. 249 | */ 250 | if(food) { 251 | You("choke over your %s.", foodword(food)); 252 | if (food->oclass == GOLD_CLASS) { 253 | killer = "a very rich meal"; 254 | } else { 255 | killer = food_xname(food, FALSE); 256 | } 257 | } else { 258 | You("choke over it."); 259 | killer = "quick snack"; 260 | } 261 | You("die..."); 262 | done(CHOKING); 263 | } 264 | } 265 | 266 | STATIC_OVL void 267 | recalc_wt() /* modify object wt. depending on time spent consuming it */ 268 | { 269 | register struct obj *piece = victual.piece; 270 | 271 | #ifdef DEBUG 272 | debugpline("Old weight = %d", piece->owt); 273 | debugpline("Used time = %d, Req'd time = %d", 274 | victual.usedtime, victual.reqtime); 275 | #endif 276 | /* weight(piece) = weight of full item */ 277 | if(victual.usedtime) 278 | piece->owt = eaten_stat(weight(piece), piece); 279 | #ifdef DEBUG 280 | debugpline("New weight = %d", piece->owt); 281 | #endif 282 | } 283 | 284 | void 285 | reset_eat() /* called when eating interrupted by an event */ 286 | { 287 | /* we only set a flag here - the actual reset process is done after 288 | * the round is spent eating. 289 | */ 290 | if(victual.eating && !victual.doreset) { 291 | #ifdef DEBUG 292 | debugpline("reset_eat..."); 293 | #endif 294 | victual.doreset = TRUE; 295 | } 296 | return; 297 | } 298 | 299 | STATIC_OVL struct obj * 300 | touchfood(otmp) 301 | register struct obj *otmp; 302 | { 303 | if (otmp->quan > 1L) { 304 | if(!carried(otmp)) 305 | (void) splitobj(otmp, 1L); 306 | else 307 | otmp = splitobj(otmp, otmp->quan - 1L); 308 | #ifdef DEBUG 309 | debugpline("split object,"); 310 | #endif 311 | } 312 | 313 | if (!otmp->oeaten) { 314 | if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) && 315 | !otmp->no_charge) 316 | || otmp->unpaid) && 317 | (otmp->otyp == CORPSE || objects[otmp->otyp].oc_delay > 1)) { 318 | /* create a dummy duplicate to put on bill */ 319 | verbalize("You bit it, you bought it!"); 320 | bill_dummy_object(otmp); 321 | } 322 | otmp->oeaten = (otmp->otyp == CORPSE ? 323 | mons[otmp->corpsenm].cnutrit : 324 | objects[otmp->otyp].oc_nutrition); 325 | } 326 | 327 | if (carried(otmp)) { 328 | freeinv(otmp); 329 | if (inv_cnt() >= 52 && !merge_choice(invent, otmp)) 330 | dropy(otmp); 331 | else 332 | otmp = addinv(otmp); /* unlikely but a merge is possible */ 333 | } 334 | return(otmp); 335 | } 336 | 337 | /* When food decays, in the middle of your meal, we don't want to dereference 338 | * any dangling pointers, so set it to null (which should still trigger 339 | * do_reset_eat() at the beginning of eatfood()) and check for null pointers 340 | * in do_reset_eat(). 341 | */ 342 | void 343 | food_disappears(obj) 344 | register struct obj *obj; 345 | { 346 | if (obj == victual.piece) victual.piece = (struct obj *)0; 347 | if (obj->timed) obj_stop_timers(obj); 348 | } 349 | 350 | /* renaming an object usually results in it having a different address; 351 | so the sequence start eating/opening, get interrupted, name the food, 352 | resume eating/opening would restart from scratch */ 353 | void 354 | food_substitution(old_obj, new_obj) 355 | struct obj *old_obj, *new_obj; 356 | { 357 | if (old_obj == victual.piece) victual.piece = new_obj; 358 | if (old_obj == tin.tin) tin.tin = new_obj; 359 | } 360 | 361 | STATIC_OVL void 362 | do_reset_eat() 363 | { 364 | #ifdef DEBUG 365 | debugpline("do_reset_eat..."); 366 | #endif 367 | if (victual.piece) { 368 | victual.piece = touchfood(victual.piece); 369 | recalc_wt(); 370 | } 371 | victual.fullwarn = victual.eating = victual.doreset = FALSE; 372 | /* Do not set canchoke to FALSE; if we continue eating the same object 373 | * we need to know if canchoke was set when they started eating it the 374 | * previous time. And if we don't continue eating the same object 375 | * canchoke always gets recalculated anyway. 376 | */ 377 | stop_occupation(); 378 | newuhs(FALSE); 379 | } 380 | 381 | STATIC_PTR 382 | int 383 | eatfood() /* called each move during eating process */ 384 | { 385 | if(!victual.piece || 386 | (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) { 387 | /* maybe it was stolen? */ 388 | do_reset_eat(); 389 | return(0); 390 | } 391 | if(!victual.eating) return(0); 392 | 393 | if(++victual.usedtime <= victual.reqtime) { 394 | if(bite()) return(0); 395 | return(1); /* still busy */ 396 | } else { /* done */ 397 | done_eating(TRUE); 398 | return(0); 399 | } 400 | } 401 | 402 | STATIC_OVL void 403 | done_eating(message) 404 | boolean message; 405 | { 406 | victual.piece->in_use = TRUE; 407 | occupation = 0; /* do this early, so newuhs() knows we're done */ 408 | newuhs(FALSE); 409 | if (nomovemsg) { 410 | if (message) pline(nomovemsg); 411 | nomovemsg = 0; 412 | } else if (message) 413 | You("finish eating %s.", food_xname(victual.piece, TRUE)); 414 | 415 | if(victual.piece->otyp == CORPSE) 416 | cpostfx(victual.piece->corpsenm); 417 | else 418 | fpostfx(victual.piece); 419 | 420 | if (carried(victual.piece)) useup(victual.piece); 421 | else useupf(victual.piece, 1L); 422 | victual.piece = (struct obj *) 0; 423 | victual.fullwarn = victual.eating = victual.doreset = FALSE; 424 | } 425 | 426 | STATIC_OVL void 427 | cprefx(pm) 428 | register int pm; 429 | { 430 | if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) { 431 | if (Upolyd) 432 | You("have a bad feeling deep inside."); 433 | You("cannibal! You will regret this!"); 434 | HAggravate_monster |= FROMOUTSIDE; 435 | change_luck(-rn1(4,2)); /* -5..-2 */ 436 | } 437 | 438 | if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) { 439 | if (!Stone_resistance && 440 | !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { 441 | Sprintf(killer_buf, "tasting %s meat", mons[pm].mname); 442 | killer_format = KILLED_BY; 443 | killer = killer_buf; 444 | You("turn to stone."); 445 | done(STONING); 446 | if (victual.piece) 447 | victual.eating = FALSE; 448 | return; /* lifesaved */ 449 | } 450 | } 451 | 452 | switch(pm) { 453 | case PM_LITTLE_DOG: 454 | case PM_DOG: 455 | case PM_LARGE_DOG: 456 | case PM_KITTEN: 457 | case PM_HOUSECAT: 458 | case PM_LARGE_CAT: 459 | if (!CANNIBAL_ALLOWED()) { 460 | You_feel("that eating the %s was a bad idea.", mons[pm].mname); 461 | HAggravate_monster |= FROMOUTSIDE; 462 | } 463 | break; 464 | case PM_LIZARD: 465 | if (Stoned) fix_petrification(); 466 | break; 467 | case PM_DEATH: 468 | case PM_PESTILENCE: 469 | case PM_FAMINE: 470 | { char buf[BUFSZ]; 471 | pline("Eating that is instantly fatal."); 472 | Sprintf(buf, "unwisely ate the body of %s", 473 | mons[pm].mname); 474 | killer = buf; 475 | killer_format = NO_KILLER_PREFIX; 476 | done(DIED); 477 | /* It so happens that since we know these monsters */ 478 | /* cannot appear in tins, victual.piece will always */ 479 | /* be what we want, which is not generally true. */ 480 | if (revive_corpse(victual.piece)) 481 | victual.piece = (struct obj *)0; 482 | return; 483 | } 484 | case PM_GREEN_SLIME: 485 | if (!Unchanging && youmonst.data != &mons[PM_FIRE_VORTEX] && 486 | youmonst.data != &mons[PM_FIRE_ELEMENTAL] && 487 | youmonst.data != &mons[PM_GREEN_SLIME]) { 488 | You("don't feel very well."); 489 | Slimed = 10L; 490 | } 491 | /* Fall through */ 492 | default: 493 | if (acidic(&mons[pm]) && Stoned) 494 | fix_petrification(); 495 | break; 496 | } 497 | } 498 | 499 | void 500 | fix_petrification() 501 | { 502 | Stoned = 0; 503 | delayed_killer = 0; 504 | if (Hallucination) 505 | pline("What a pity - you just ruined a future piece of %sart!", 506 | ACURR(A_CHA) > 15 ? "fine " : ""); 507 | else 508 | You_feel("limber!"); 509 | } 510 | 511 | /* 512 | * If you add an intrinsic that can be gotten by eating a monster, add it 513 | * to intrinsic_possible() and givit(). (It must already be in prop.h to 514 | * be an intrinsic property.) 515 | * It would be very easy to make the intrinsics not try to give you one 516 | * that you already had by checking to see if you have it in 517 | * intrinsic_possible() instead of givit(). 518 | */ 519 | 520 | /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */ 521 | STATIC_OVL int 522 | intrinsic_possible(type, ptr) 523 | int type; 524 | register struct permonst *ptr; 525 | { 526 | switch (type) { 527 | case FIRE_RES: 528 | #ifdef DEBUG 529 | if (ptr->mconveys & MR_FIRE) { 530 | debugpline("can get fire resistance"); 531 | return(TRUE); 532 | } else return(FALSE); 533 | #else 534 | return(ptr->mconveys & MR_FIRE); 535 | #endif 536 | case SLEEP_RES: 537 | #ifdef DEBUG 538 | if (ptr->mconveys & MR_SLEEP) { 539 | debugpline("can get sleep resistance"); 540 | return(TRUE); 541 | } else return(FALSE); 542 | #else 543 | return(ptr->mconveys & MR_SLEEP); 544 | #endif 545 | case COLD_RES: 546 | #ifdef DEBUG 547 | if (ptr->mconveys & MR_COLD) { 548 | debugpline("can get cold resistance"); 549 | return(TRUE); 550 | } else return(FALSE); 551 | #else 552 | return(ptr->mconveys & MR_COLD); 553 | #endif 554 | case DISINT_RES: 555 | #ifdef DEBUG 556 | if (ptr->mconveys & MR_DISINT) { 557 | debugpline("can get disintegration resistance"); 558 | return(TRUE); 559 | } else return(FALSE); 560 | #else 561 | return(ptr->mconveys & MR_DISINT); 562 | #endif 563 | case SHOCK_RES: /* shock (electricity) resistance */ 564 | #ifdef DEBUG 565 | if (ptr->mconveys & MR_ELEC) { 566 | debugpline("can get shock resistance"); 567 | return(TRUE); 568 | } else return(FALSE); 569 | #else 570 | return(ptr->mconveys & MR_ELEC); 571 | #endif 572 | case POISON_RES: 573 | #ifdef DEBUG 574 | if (ptr->mconveys & MR_POISON) { 575 | debugpline("can get poison resistance"); 576 | return(TRUE); 577 | } else return(FALSE); 578 | #else 579 | return(ptr->mconveys & MR_POISON); 580 | #endif 581 | case TELEPORT: 582 | #ifdef DEBUG 583 | if (can_teleport(ptr)) { 584 | debugpline("can get teleport"); 585 | return(TRUE); 586 | } else return(FALSE); 587 | #else 588 | return(can_teleport(ptr)); 589 | #endif 590 | case TELEPORT_CONTROL: 591 | #ifdef DEBUG 592 | if (control_teleport(ptr)) { 593 | debugpline("can get teleport control"); 594 | return(TRUE); 595 | } else return(FALSE); 596 | #else 597 | return(control_teleport(ptr)); 598 | #endif 599 | case TELEPAT: 600 | #ifdef DEBUG 601 | if (telepathic(ptr)) { 602 | debugpline("can get telepathy"); 603 | return(TRUE); 604 | } else return(FALSE); 605 | #else 606 | return(telepathic(ptr)); 607 | #endif 608 | default: 609 | return(FALSE); 610 | } 611 | /*NOTREACHED*/ 612 | } 613 | 614 | /* givit() tries to give you an intrinsic based on the monster's level 615 | * and what type of intrinsic it is trying to give you. 616 | */ 617 | STATIC_OVL void 618 | givit(type, ptr) 619 | int type; 620 | register struct permonst *ptr; 621 | { 622 | register int chance; 623 | 624 | #ifdef DEBUG 625 | debugpline("Attempting to give intrinsic %d", type); 626 | #endif 627 | /* some intrinsics are easier to get than others */ 628 | switch (type) { 629 | case POISON_RES: 630 | if ((ptr == &mons[PM_KILLER_BEE] || 631 | ptr == &mons[PM_SCORPION]) && !rn2(4)) 632 | chance = 1; 633 | else 634 | chance = 15; 635 | break; 636 | case TELEPORT: 637 | chance = 10; 638 | break; 639 | case TELEPORT_CONTROL: 640 | chance = 12; 641 | break; 642 | case TELEPAT: 643 | chance = 1; 644 | break; 645 | default: 646 | chance = 15; 647 | break; 648 | } 649 | 650 | if (ptr->mlevel <= rn2(chance)) 651 | return; /* failed die roll */ 652 | 653 | switch (type) { 654 | case FIRE_RES: 655 | #ifdef DEBUG 656 | debugpline("Trying to give fire resistance"); 657 | #endif 658 | if(!(HFire_resistance & FROMOUTSIDE)) { 659 | You(Hallucination ? "be chillin'." : 660 | "feel a momentary chill."); 661 | HFire_resistance |= FROMOUTSIDE; 662 | } 663 | break; 664 | case SLEEP_RES: 665 | #ifdef DEBUG 666 | debugpline("Trying to give sleep resistance"); 667 | #endif 668 | if(!(HSleep_resistance & FROMOUTSIDE)) { 669 | You_feel("wide awake."); 670 | HSleep_resistance |= FROMOUTSIDE; 671 | } 672 | break; 673 | case COLD_RES: 674 | #ifdef DEBUG 675 | debugpline("Trying to give cold resistance"); 676 | #endif 677 | if(!(HCold_resistance & FROMOUTSIDE)) { 678 | You_feel("full of hot air."); 679 | HCold_resistance |= FROMOUTSIDE; 680 | } 681 | break; 682 | case DISINT_RES: 683 | #ifdef DEBUG 684 | debugpline("Trying to give disintegration resistance"); 685 | #endif 686 | if(!(HDisint_resistance & FROMOUTSIDE)) { 687 | You_feel(Hallucination ? 688 | "totally together, man." : 689 | "very firm."); 690 | HDisint_resistance |= FROMOUTSIDE; 691 | } 692 | break; 693 | case SHOCK_RES: /* shock (electricity) resistance */ 694 | #ifdef DEBUG 695 | debugpline("Trying to give shock resistance"); 696 | #endif 697 | if(!(HShock_resistance & FROMOUTSIDE)) { 698 | if (Hallucination) 699 | You_feel("grounded in reality."); 700 | else 701 | Your("health currently feels amplified!"); 702 | HShock_resistance |= FROMOUTSIDE; 703 | } 704 | break; 705 | case POISON_RES: 706 | #ifdef DEBUG 707 | debugpline("Trying to give poison resistance"); 708 | #endif 709 | if(!(HPoison_resistance & FROMOUTSIDE)) { 710 | You_feel(Poison_resistance ? 711 | "especially healthy." : "healthy."); 712 | HPoison_resistance |= FROMOUTSIDE; 713 | } 714 | break; 715 | case TELEPORT: 716 | #ifdef DEBUG 717 | debugpline("Trying to give teleport"); 718 | #endif 719 | if(!(HTeleportation & FROMOUTSIDE)) { 720 | You_feel(Hallucination ? "diffuse." : 721 | "very jumpy."); 722 | HTeleportation |= FROMOUTSIDE; 723 | } 724 | break; 725 | case TELEPORT_CONTROL: 726 | #ifdef DEBUG 727 | debugpline("Trying to give teleport control"); 728 | #endif 729 | if(!(HTeleport_control & FROMOUTSIDE)) { 730 | You_feel(Hallucination ? 731 | "centered in your personal space." : 732 | "in control of yourself."); 733 | HTeleport_control |= FROMOUTSIDE; 734 | } 735 | break; 736 | case TELEPAT: 737 | #ifdef DEBUG 738 | debugpline("Trying to give telepathy"); 739 | #endif 740 | if(!(HTelepat & FROMOUTSIDE)) { 741 | You_feel(Hallucination ? 742 | "in touch with the cosmos." : 743 | "a strange mental acuity."); 744 | HTelepat |= FROMOUTSIDE; 745 | /* If blind, make sure monsters show up. */ 746 | if (Blind) see_monsters(); 747 | } 748 | break; 749 | default: 750 | #ifdef DEBUG 751 | debugpline("Tried to give an impossible intrinsic"); 752 | #endif 753 | break; 754 | } 755 | } 756 | 757 | STATIC_OVL void 758 | cpostfx(pm) /* called after completely consuming a corpse */ 759 | register int pm; 760 | { 761 | register int tmp = 0; 762 | 763 | /* in case `afternmv' didn't get called for previously mimicking 764 | gold, clean up now to avoid `eatmbuf' memory leak */ 765 | if (eatmbuf) (void)eatmdone(); 766 | 767 | switch(pm) { 768 | case PM_WRAITH: 769 | pluslvl(FALSE); 770 | break; 771 | case PM_HUMAN_WERERAT: 772 | u.ulycn = PM_WERERAT; 773 | break; 774 | case PM_HUMAN_WEREJACKAL: 775 | u.ulycn = PM_WEREJACKAL; 776 | break; 777 | case PM_HUMAN_WEREWOLF: 778 | u.ulycn = PM_WEREWOLF; 779 | break; 780 | case PM_NURSE: 781 | if (Upolyd) u.mh = u.mhmax; 782 | else u.uhp = u.uhpmax; 783 | flags.botl = 1; 784 | break; 785 | case PM_STALKER: 786 | if(!Invis) { 787 | set_itimeout(&HInvis, (long)rn1(100, 50)); 788 | } else { 789 | if (!(HInvis & INTRINSIC)) You_feel("hidden!"); 790 | HInvis |= FROMOUTSIDE; 791 | HSee_invisible |= FROMOUTSIDE; 792 | } 793 | newsym(u.ux, u.uy); 794 | /* fall into next case */ 795 | case PM_YELLOW_LIGHT: 796 | /* fall into next case */ 797 | case PM_GIANT_BAT: 798 | make_stunned(HStun + 30,FALSE); 799 | /* fall into next case */ 800 | case PM_BAT: 801 | make_stunned(HStun + 30,FALSE); 802 | break; 803 | case PM_GIANT_MIMIC: 804 | tmp += 10; 805 | /* fall into next case */ 806 | case PM_LARGE_MIMIC: 807 | tmp += 20; 808 | /* fall into next case */ 809 | case PM_SMALL_MIMIC: 810 | tmp += 20; 811 | if (youmonst.data->mlet != S_MIMIC) { 812 | char buf[BUFSZ]; 813 | 814 | You_cant("resist the temptation to mimic a pile of gold."); 815 | nomul(-tmp); 816 | Sprintf(buf, "You now prefer mimicking %s again.", 817 | an(Upolyd ? youmonst.data->mname : urace.noun)); 818 | eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf); 819 | nomovemsg = eatmbuf; 820 | afternmv = eatmdone; 821 | /* ??? what if this was set before? */ 822 | youmonst.m_ap_type = M_AP_OBJECT; 823 | youmonst.mappearance = GOLD_PIECE; 824 | newsym(u.ux,u.uy); 825 | curs_on_u(); 826 | /* make gold symbol show up now */ 827 | display_nhwindow(WIN_MAP, TRUE); 828 | } 829 | break; 830 | case PM_QUANTUM_MECHANIC: 831 | Your("velocity suddenly seems very uncertain!"); 832 | if (HFast & INTRINSIC) { 833 | HFast &= ~INTRINSIC; 834 | You("seem slower."); 835 | } else { 836 | HFast |= FROMOUTSIDE; 837 | You("seem faster."); 838 | } 839 | break; 840 | case PM_LIZARD: 841 | if (HStun > 2) make_stunned(2L,FALSE); 842 | if (HConfusion > 2) make_confused(2L,FALSE); 843 | break; 844 | case PM_CHAMELEON: 845 | case PM_DOPPELGANGER: 846 | /* case PM_SANDESTIN: */ 847 | if (!Unchanging) { 848 | You_feel("a change coming over you."); 849 | polyself(); 850 | } 851 | break; 852 | case PM_MIND_FLAYER: 853 | case PM_MASTER_MIND_FLAYER: 854 | if (ABASE(A_INT) < ATTRMAX(A_INT)) { 855 | if (!rn2(2)) { 856 | pline("Yum! That was real brain food!"); 857 | (void) adjattrib(A_INT, 1, FALSE); 858 | break; /* don't give them telepathy, too */ 859 | } 860 | } 861 | else { 862 | pline("For some reason, that tasted bland."); 863 | } 864 | /* fall through to default case */ 865 | default: { 866 | register struct permonst *ptr = &mons[pm]; 867 | int i, count; 868 | 869 | if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) || 870 | pm == PM_VIOLET_FUNGUS) { 871 | pline ("Oh wow! Great stuff!"); 872 | make_hallucinated(HHallucination + 200,FALSE,0L); 873 | } 874 | if(is_giant(ptr)) gainstr((struct obj *)0, 0); 875 | 876 | /* Check the monster for all of the intrinsics. If this 877 | * monster can give more than one, pick one to try to give 878 | * from among all it can give. 879 | * 880 | * If a monster can give 4 intrinsics then you have 881 | * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first, 882 | * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second, 883 | * a 1/3 * 3/4 = 1/4 chance of getting the third, 884 | * and a 1/4 chance of getting the fourth. 885 | * 886 | * And now a proof by induction: 887 | * it works for 1 intrinsic (1 in 1 of getting it) 888 | * for 2 you have a 1 in 2 chance of getting the second, 889 | * otherwise you keep the first 890 | * for 3 you have a 1 in 3 chance of getting the third, 891 | * otherwise you keep the first or the second 892 | * for n+1 you have a 1 in n+1 chance of getting the (n+1)st, 893 | * otherwise you keep the previous one. 894 | * Elliott Kleinrock, October 5, 1990 895 | */ 896 | 897 | count = 0; /* number of possible intrinsics */ 898 | tmp = 0; /* which one we will try to give */ 899 | for (i = 1; i <= LAST_PROP; i++) { 900 | if (intrinsic_possible(i, ptr)) { 901 | count++; 902 | /* a 1 in count chance of replacing the old 903 | * one with this one, and a count-1 in count 904 | * chance of keeping the old one. (note 905 | * that 1 in 1 and 0 in 1 are what we want 906 | * for the first one 907 | */ 908 | if (!rn2(count)) { 909 | #ifdef DEBUG 910 | debugpline("Intrinsic %d replacing %d", 911 | i, tmp); 912 | #endif 913 | tmp = i; 914 | } 915 | } 916 | } 917 | 918 | /* if any found try to give them one */ 919 | if (count) givit(tmp, ptr); 920 | } 921 | break; 922 | } 923 | return; 924 | } 925 | 926 | void 927 | violated_vegetarian() 928 | { 929 | u.uconduct.unvegetarian++; 930 | if (Role_if(PM_MONK)) { 931 | You_feel("guilty."); 932 | adjalign(-1); 933 | } 934 | return; 935 | } 936 | 937 | STATIC_PTR 938 | int 939 | opentin() /* called during each move whilst opening a tin */ 940 | { 941 | register int r; 942 | const char *what; 943 | int which; 944 | 945 | if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy)) 946 | /* perhaps it was stolen? */ 947 | return(0); /* %% probably we should use tinoid */ 948 | if(tin.usedtime++ >= 50) { 949 | You("give up your attempt to open the tin."); 950 | return(0); 951 | } 952 | if(tin.usedtime < tin.reqtime) 953 | return(1); /* still busy */ 954 | if(tin.tin->otrapped || 955 | (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) { 956 | b_trapped("tin", 0); 957 | goto use_me; 958 | } 959 | You("succeed in opening the tin."); 960 | if(tin.tin->spe != 1) { 961 | if (tin.tin->corpsenm == NON_PM) { 962 | pline("It turns out to be empty."); 963 | tin.tin->dknown = tin.tin->known = TRUE; 964 | goto use_me; 965 | } 966 | r = tin.tin->cursed ? ROTTEN_TIN : /* always rotten if cursed */ 967 | (tin.tin->spe == -1) ? HOMEMADE_TIN : /* player made it */ 968 | rn2(TTSZ-1); /* else take your pick */ 969 | if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD || 970 | tin.tin->corpsenm == PM_LICHEN)) 971 | r = HOMEMADE_TIN; /* lizards don't rot */ 972 | else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7)) 973 | r = ROTTEN_TIN; /* some homemade tins go bad */ 974 | which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ 975 | if (Hallucination) { 976 | what = rndmonnam(); 977 | } else { 978 | what = mons[tin.tin->corpsenm].mname; 979 | if (mons[tin.tin->corpsenm].geno & G_UNIQ) 980 | which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2; 981 | } 982 | if (which == 0) what = makeplural(what); 983 | pline("It smells like %s%s.", (which == 2) ? "the " : "", what); 984 | if (yn("Eat it?") == 'n') { 985 | if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE; 986 | if (flags.verbose) You("discard the open tin."); 987 | goto use_me; 988 | } 989 | /* in case stop_occupation() was called on previous meal */ 990 | victual.piece = (struct obj *)0; 991 | victual.fullwarn = victual.eating = victual.doreset = FALSE; 992 | 993 | You("consume %s %s.", tintxts[r].txt, 994 | mons[tin.tin->corpsenm].mname); 995 | 996 | /* KMH, conduct */ 997 | u.uconduct.food++; 998 | if (!vegan(&mons[tin.tin->corpsenm])) 999 | u.uconduct.unvegan++; 1000 | if (!vegetarian(&mons[tin.tin->corpsenm])) 1001 | violated_vegetarian(); 1002 | 1003 | tin.tin->dknown = tin.tin->known = TRUE; 1004 | cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm); 1005 | 1006 | /* check for vomiting added by GAN 01/16/87 */ 1007 | if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE); 1008 | else lesshungry(tintxts[r].nut); 1009 | 1010 | if(r == 0) { /* Deep Fried */ 1011 | /* Assume !Glib, because you can't open tins when Glib. */ 1012 | incr_itimeout(&Glib, rnd(15)); 1013 | pline("Eating deep fried food made your %s very slippery.", 1014 | makeplural(body_part(FINGER))); 1015 | } 1016 | } else { 1017 | if (tin.tin->cursed) 1018 | pline("It contains some decaying %s substance.", 1019 | hcolor(green)); 1020 | else 1021 | pline("It contains spinach."); 1022 | 1023 | if (yn("Eat it?") == 'n') { 1024 | if (!Hallucination && !tin.tin->cursed) 1025 | tin.tin->dknown = tin.tin->known = TRUE; 1026 | if (flags.verbose) 1027 | You("discard the open tin."); 1028 | goto use_me; 1029 | } 1030 | if (!tin.tin->cursed) 1031 | pline("This makes you feel like %s!", 1032 | Hallucination ? "Swee'pea" : "Popeye"); 1033 | lesshungry(600); 1034 | gainstr(tin.tin, 0); 1035 | u.uconduct.food++; 1036 | } 1037 | tin.tin->dknown = tin.tin->known = TRUE; 1038 | use_me: 1039 | if (carried(tin.tin)) useup(tin.tin); 1040 | else useupf(tin.tin, 1L); 1041 | tin.tin = (struct obj *) 0; 1042 | return(0); 1043 | } 1044 | 1045 | STATIC_OVL void 1046 | start_tin(otmp) /* called when starting to open a tin */ 1047 | register struct obj *otmp; 1048 | { 1049 | register int tmp; 1050 | 1051 | if (metallivorous(youmonst.data)) { 1052 | You("bite right into the metal tin..."); 1053 | tmp = 1; 1054 | } else if (nolimbs(youmonst.data)) { 1055 | You("cannot handle the tin properly to open it."); 1056 | return; 1057 | } else if (otmp->blessed) { 1058 | pline_The("tin opens like magic!"); 1059 | tmp = 1; 1060 | } else if(uwep) { 1061 | switch(uwep->otyp) { 1062 | case TIN_OPENER: 1063 | tmp = 1; 1064 | break; 1065 | case DAGGER: 1066 | case SILVER_DAGGER: 1067 | case ELVEN_DAGGER: 1068 | case ORCISH_DAGGER: 1069 | case ATHAME: 1070 | case CRYSKNIFE: 1071 | tmp = 3; 1072 | break; 1073 | case PICK_AXE: 1074 | case AXE: 1075 | tmp = 6; 1076 | break; 1077 | default: 1078 | goto no_opener; 1079 | } 1080 | pline("Using your %s you try to open the tin.", 1081 | aobjnam(uwep, (char *)0)); 1082 | } else { 1083 | no_opener: 1084 | pline("It is not so easy to open this tin."); 1085 | if(Glib) { 1086 | pline_The("tin slips from your %s.", 1087 | makeplural(body_part(FINGER))); 1088 | if(otmp->quan > 1L) { 1089 | register struct obj *obj; 1090 | obj = splitobj(otmp, 1L); 1091 | if (otmp == uwep) setuwep(obj); 1092 | if (otmp == uswapwep) setuswapwep(obj); 1093 | if (otmp == uquiver) setuqwep(obj); 1094 | } 1095 | if (carried(otmp)) dropx(otmp); 1096 | else stackobj(otmp); 1097 | return; 1098 | } 1099 | tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10); 1100 | } 1101 | tin.reqtime = tmp; 1102 | tin.usedtime = 0; 1103 | tin.tin = otmp; 1104 | set_occupation(opentin, "opening the tin", 0); 1105 | return; 1106 | } 1107 | 1108 | int 1109 | Hear_again() /* called when waking up after fainting */ 1110 | { 1111 | flags.soundok = 1; 1112 | return 0; 1113 | } 1114 | 1115 | /* called on the "first bite" of rotten food */ 1116 | STATIC_OVL int 1117 | rottenfood(obj) 1118 | struct obj *obj; 1119 | { 1120 | pline("Blecch! Rotten %s!", foodword(obj)); 1121 | if(!rn2(4)) { 1122 | if (Hallucination) You_feel("rather trippy."); 1123 | else You_feel("rather %s.", body_part(LIGHT_HEADED)); 1124 | make_confused(HConfusion + d(2,4),FALSE); 1125 | } else if(!rn2(4) && !Blind) { 1126 | pline("Everything suddenly goes dark."); 1127 | make_blinded((long)d(2,10),FALSE); 1128 | } else if(!rn2(3)) { 1129 | const char *what, *where; 1130 | if (!Blind) 1131 | what = "goes", where = "dark"; 1132 | else if (Levitation || Is_airlevel(&u.uz) || 1133 | Is_waterlevel(&u.uz)) 1134 | what = "you lose control of", where = "yourself"; 1135 | else 1136 | what = "you slap against the", where = surface(u.ux,u.uy); 1137 | pline_The("world spins and %s %s.", what, where); 1138 | flags.soundok = 0; 1139 | nomul(-rnd(10)); 1140 | nomovemsg = "You are conscious again."; 1141 | afternmv = Hear_again; 1142 | return(1); 1143 | } 1144 | return(0); 1145 | } 1146 | 1147 | STATIC_OVL int 1148 | eatcorpse(otmp) /* called when a corpse is selected as food */ 1149 | register struct obj *otmp; 1150 | { 1151 | int tp = 0, mnum = otmp->corpsenm; 1152 | long rotted = 0L; 1153 | boolean uniq = !!(mons[mnum].geno & G_UNIQ); 1154 | int retcode = 0; 1155 | boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance && 1156 | !poly_when_stoned(youmonst.data)); 1157 | 1158 | if (mnum != PM_LIZARD && mnum != PM_LICHEN) { 1159 | long age = peek_at_iced_corpse_age(otmp); 1160 | 1161 | rotted = (monstermoves - age)/(10L + rn2(20)); 1162 | if (otmp->cursed) rotted += 2L; 1163 | else if (otmp->blessed) rotted -= 2L; 1164 | } 1165 | 1166 | if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) { 1167 | pline("Ulch - that %s was tainted!", 1168 | mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" : 1169 | !vegetarian(&mons[mnum]) ? "meat" : "protoplasm"); 1170 | if (Sick_resistance) { 1171 | pline("It doesn't seem at all sickening, though..."); 1172 | } else { 1173 | char buf[BUFSZ]; 1174 | long sick_time; 1175 | 1176 | sick_time = (long) rn1(10, 10); 1177 | /* make sure new ill doesn't result in improvement */ 1178 | if (Sick && (sick_time > Sick)) 1179 | sick_time = (Sick > 1L) ? Sick - 1L : 1L; 1180 | if (!uniq) 1181 | Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE)); 1182 | else 1183 | Sprintf(buf, "%s%s rotted corpse", 1184 | !type_is_pname(&mons[mnum]) ? "the " : "", 1185 | s_suffix(mons[mnum].mname)); 1186 | make_sick(sick_time, buf, TRUE, SICK_VOMITABLE); 1187 | } 1188 | 1189 | /* KMH, conduct */ 1190 | if (!vegan(&mons[mnum])) 1191 | u.uconduct.unvegan++; 1192 | if (!vegetarian(&mons[mnum])) 1193 | violated_vegetarian(); 1194 | 1195 | if (carried(otmp)) useup(otmp); 1196 | else useupf(otmp, 1L); 1197 | return(2); 1198 | } else if (acidic(&mons[mnum]) && !Acid_resistance) { 1199 | tp++; 1200 | You("have a very bad case of stomach acid."); 1201 | losehp(rnd(15), "acidic corpse", KILLED_BY_AN); 1202 | } else if (poisonous(&mons[mnum]) && rn2(5)) { 1203 | tp++; 1204 | pline("Ecch - that must have been poisonous!"); 1205 | if(!Poison_resistance) { 1206 | losestr(rnd(4)); 1207 | losehp(rnd(15), "poisonous corpse", KILLED_BY_AN); 1208 | } else You("seem unaffected by the poison."); 1209 | /* now any corpse left too long will make you mildly ill */ 1210 | } else if ((rotted > 5L || (rotted > 3L && rn2(5))) 1211 | && !Sick_resistance) { 1212 | tp++; 1213 | You_feel("%ssick.", (Sick) ? "very " : ""); 1214 | losehp(rnd(8), "cadaver", KILLED_BY_AN); 1215 | } 1216 | 1217 | /* delay is weight dependent */ 1218 | victual.reqtime = 3 + (mons[mnum].cwt >> 6); 1219 | 1220 | if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN && 1221 | (otmp->orotten || !rn2(7))) { 1222 | if (rottenfood(otmp)) { 1223 | otmp->orotten = TRUE; 1224 | (void)touchfood(otmp); 1225 | retcode = 1; 1226 | } else 1227 | otmp->oeaten >>= 2; 1228 | } else { 1229 | pline("%s%s %s!", 1230 | !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "", 1231 | food_xname(otmp, FALSE), 1232 | (carnivorous(youmonst.data) && !herbivorous(youmonst.data)) ? 1233 | "is delicious" : "tastes terrible"); 1234 | } 1235 | 1236 | /* KMH, conduct */ 1237 | if (!vegan(&mons[mnum])) 1238 | u.uconduct.unvegan++; 1239 | if (!vegetarian(&mons[mnum])) 1240 | violated_vegetarian(); 1241 | 1242 | return(retcode); 1243 | } 1244 | 1245 | STATIC_OVL void 1246 | start_eating(otmp) /* called as you start to eat */ 1247 | register struct obj *otmp; 1248 | { 1249 | #ifdef DEBUG 1250 | debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece); 1251 | debugpline("reqtime = %d", victual.reqtime); 1252 | debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay); 1253 | debugpline("nmod = %d", victual.nmod); 1254 | debugpline("oeaten = %d", otmp->oeaten); 1255 | #endif 1256 | victual.fullwarn = victual.doreset = FALSE; 1257 | victual.eating = TRUE; 1258 | 1259 | if (otmp->otyp == CORPSE) { 1260 | cprefx(victual.piece->corpsenm); 1261 | if (!victual.piece || !victual.eating) { 1262 | /* rider revived, or died and lifesaved */ 1263 | return; 1264 | } 1265 | } 1266 | 1267 | if (bite()) return; 1268 | 1269 | if (++victual.usedtime >= victual.reqtime) { 1270 | /* print "finish eating" message if they just resumed -dlc */ 1271 | done_eating(victual.reqtime > 1 ? TRUE : FALSE); 1272 | return; 1273 | } 1274 | 1275 | Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE)); 1276 | set_occupation(eatfood, msgbuf, 0); 1277 | } 1278 | 1279 | 1280 | STATIC_OVL void 1281 | fprefx(otmp) /* called on "first bite" of (non-corpse) food */ 1282 | struct obj *otmp; 1283 | { 1284 | switch(otmp->otyp) { 1285 | case FOOD_RATION: 1286 | if(u.uhunger <= 200) 1287 | if (Hallucination) pline("Oh wow, like, superior, man!"); 1288 | else pline("That food really hit the spot!"); 1289 | else if(u.uhunger <= 700) pline("That satiated your stomach!"); 1290 | break; 1291 | case TRIPE_RATION: 1292 | if (carnivorous(youmonst.data) && !humanoid(youmonst.data)) 1293 | pline("That tripe ration was surprisingly good!"); 1294 | else { 1295 | pline("Yak - dog food!"); 1296 | more_experienced(1,0); 1297 | flags.botl = 1; 1298 | } 1299 | if (rn2(2) && 1300 | (Upolyd ? (!carnivorous(youmonst.data) || 1301 | (humanoid(youmonst.data) && 1302 | !is_orc(youmonst.data))) 1303 | : !CANNIBAL_ALLOWED())) { 1304 | make_vomiting((long)rn1(victual.reqtime, 14), FALSE); 1305 | } 1306 | break; 1307 | case MEATBALL: 1308 | case MEAT_STICK: 1309 | case HUGE_CHUNK_OF_MEAT: 1310 | case MEAT_RING: 1311 | goto give_feedback; 1312 | /* break; */ 1313 | case CLOVE_OF_GARLIC: 1314 | if (is_undead(youmonst.data)) { 1315 | make_vomiting((long)rn1(victual.reqtime, 5), FALSE); 1316 | break; 1317 | } 1318 | /* Fall through otherwise */ 1319 | default: 1320 | if (otmp->otyp==SLIME_MOLD && !otmp->cursed 1321 | && otmp->spe == current_fruit) 1322 | pline("My, that was a %s %s!", 1323 | Hallucination ? "primo" : "yummy", 1324 | singular(otmp, xname)); 1325 | else 1326 | #ifdef UNIX 1327 | if (otmp->otyp == APPLE || otmp->otyp == PEAR) { 1328 | if (!Hallucination) pline("Core dumped."); 1329 | else { 1330 | /* This is based on an old Usenet joke, a fake a.out manual page */ 1331 | int x = rnd(100); 1332 | if (x <= 75) 1333 | pline("Segmentation fault -- core dumped."); 1334 | else if (x <= 99) 1335 | pline("Bus error -- core dumped."); 1336 | else pline("Yo' mama -- core dumped."); 1337 | } 1338 | } else 1339 | #endif 1340 | #ifdef MAC /* KMH -- Why should Unix have all the fun? */ 1341 | if (otmp->otyp == APPLE) { 1342 | pline("Delicious! Must be a Macintosh!"); 1343 | } else 1344 | #endif 1345 | if (otmp->otyp == EGG && stale_egg(otmp)) { 1346 | pline("Ugh. Rotten egg."); /* perhaps others like it */ 1347 | make_vomiting(Vomiting+d(10,4), TRUE); 1348 | } else 1349 | give_feedback: 1350 | pline("This %s is %s", singular(otmp, xname), 1351 | otmp->cursed ? (Hallucination ? "grody!" : "terrible!") : 1352 | (otmp->otyp == CRAM_RATION 1353 | || otmp->otyp == K_RATION 1354 | || otmp->otyp == C_RATION) 1355 | ? "bland." : 1356 | Hallucination ? "gnarly!" : "delicious!"); 1357 | break; 1358 | } 1359 | 1360 | /* KMH, conduct */ 1361 | switch (objects[otmp->otyp].oc_material) { 1362 | case WAX: /* let's assume bees' wax */ 1363 | u.uconduct.unvegan++; 1364 | break; 1365 | 1366 | case FLESH: 1367 | if (otmp->otyp == EGG) { 1368 | u.uconduct.unvegan++; 1369 | break; 1370 | } 1371 | case LEATHER: 1372 | case BONE: 1373 | case DRAGON_HIDE: 1374 | u.uconduct.unvegan++; 1375 | violated_vegetarian(); 1376 | break; 1377 | 1378 | default: 1379 | if (otmp->otyp == PANCAKE || 1380 | otmp->otyp == FORTUNE_COOKIE || /* eggs */ 1381 | otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR || /* milk */ 1382 | otmp->otyp == LUMP_OF_ROYAL_JELLY) 1383 | u.uconduct.unvegan++; 1384 | break; 1385 | } 1386 | } 1387 | 1388 | STATIC_OVL void 1389 | eataccessory(otmp) 1390 | struct obj *otmp; 1391 | { 1392 | int typ = otmp->otyp; 1393 | int oldprop; 1394 | 1395 | /* Note: rings are not so common that this is unbalancing. */ 1396 | /* (How often do you even _find_ 3 rings of polymorph in a game?) */ 1397 | oldprop = !!(u.uprops[objects[typ].oc_oprop].intrinsic); 1398 | if (otmp == uleft || otmp == uright) { 1399 | Ring_gone(otmp); 1400 | if (u.uhp <= 0) return; /* died from sink fall */ 1401 | } 1402 | otmp->known = otmp->dknown = 1; /* by taste */ 1403 | if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) 1404 | switch (otmp->otyp) { 1405 | default: 1406 | if (!objects[typ].oc_oprop) break; /* should never happen */ 1407 | 1408 | if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE)) 1409 | pline("Magic spreads through your body as you digest the %s.", 1410 | otmp->oclass == RING_CLASS ? "ring" : "amulet"); 1411 | 1412 | u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE; 1413 | 1414 | switch (typ) { 1415 | case RIN_SEE_INVISIBLE: 1416 | set_mimic_blocking(); 1417 | see_monsters(); 1418 | if (Invis && !oldprop && !ESee_invisible && 1419 | !perceives(youmonst.data) && !Blind) { 1420 | newsym(u.ux,u.uy); 1421 | pline("Suddenly you can see yourself."); 1422 | makeknown(typ); 1423 | } 1424 | break; 1425 | case RIN_INVISIBILITY: 1426 | if (!oldprop && !EInvis && !BInvis && 1427 | !See_invisible && !Blind) { 1428 | newsym(u.ux,u.uy); 1429 | Your("body takes on a %s transparency...", 1430 | Hallucination ? "normal" : "strange"); 1431 | makeknown(typ); 1432 | } 1433 | break; 1434 | case RIN_PROTECTION_FROM_SHAPE_CHAN: 1435 | rescham(); 1436 | break; 1437 | case RIN_LEVITATION: 1438 | if (!Levitation) { 1439 | float_up(); 1440 | incr_itimeout(&HLevitation, d(10,20)); 1441 | makeknown(typ); 1442 | } 1443 | break; 1444 | } 1445 | break; 1446 | case RIN_ADORNMENT: 1447 | if (adjattrib(A_CHA, otmp->spe, -1)) 1448 | makeknown(typ); 1449 | break; 1450 | case RIN_GAIN_STRENGTH: 1451 | if (adjattrib(A_STR, otmp->spe, -1)) 1452 | makeknown(typ); 1453 | break; 1454 | case RIN_GAIN_CONSTITUTION: 1455 | if (adjattrib(A_CON, otmp->spe, -1)) 1456 | makeknown(typ); 1457 | break; 1458 | case RIN_INCREASE_ACCURACY: 1459 | u.uhitinc += otmp->spe; 1460 | break; 1461 | case RIN_INCREASE_DAMAGE: 1462 | u.udaminc += otmp->spe; 1463 | break; 1464 | case RIN_PROTECTION: 1465 | HProtection |= FROMOUTSIDE; 1466 | u.ublessed += otmp->spe; 1467 | flags.botl = 1; 1468 | break; 1469 | case RIN_FREE_ACTION: 1470 | /* Give sleep resistance instead */ 1471 | if (!Sleep_resistance) 1472 | You_feel("wide awake."); 1473 | HSleep_resistance |= FROMOUTSIDE; 1474 | break; 1475 | case AMULET_OF_CHANGE: 1476 | makeknown(typ); 1477 | change_sex(); 1478 | You("are suddenly very %s!", 1479 | flags.female ? "feminine" : "masculine"); 1480 | flags.botl = 1; 1481 | break; 1482 | case AMULET_OF_STRANGULATION: /* bad idea! */ 1483 | choke(otmp); 1484 | break; 1485 | case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */ 1486 | HSleeping = FROMOUTSIDE | rnd(100); 1487 | break; 1488 | case RIN_SUSTAIN_ABILITY: 1489 | case AMULET_OF_LIFE_SAVING: 1490 | case AMULET_OF_REFLECTION: /* nice try */ 1491 | /* can't eat Amulet of Yendor or fakes, 1492 | * and no oc_prop even if you could -3. 1493 | */ 1494 | break; 1495 | } 1496 | } 1497 | 1498 | STATIC_OVL void 1499 | eatspecial() /* called after eating non-food */ 1500 | { 1501 | register struct obj *otmp = victual.piece; 1502 | 1503 | lesshungry(victual.nmod); 1504 | victual.piece = (struct obj *)0; 1505 | victual.eating = 0; 1506 | if (otmp->oclass == GOLD_CLASS) { 1507 | dealloc_obj(otmp); 1508 | return; 1509 | } 1510 | if (otmp->oclass == POTION_CLASS) { 1511 | otmp->quan++; /* dopotion() does a useup() */ 1512 | (void)dopotion(otmp); 1513 | } 1514 | if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) 1515 | eataccessory(otmp); 1516 | else if (otmp->otyp == LEASH && otmp->leashmon) 1517 | o_unleash(otmp); 1518 | 1519 | /* KMH -- idea by "Tommy the Terrorist" */ 1520 | if ((otmp->otyp == TRIDENT) && !otmp->cursed) 1521 | { 1522 | pline(Hallucination ? "Four out of five dentists agree." : 1523 | "That was pure chewing satisfaction!"); 1524 | exercise(A_WIS, TRUE); 1525 | } 1526 | if ((otmp->otyp == FLINT) && !otmp->cursed) 1527 | { 1528 | pline("Yabba-dabba delicious!"); 1529 | exercise(A_CON, TRUE); 1530 | } 1531 | 1532 | if (otmp == uwep && otmp->quan == 1L) uwepgone(); 1533 | if (otmp == uquiver && otmp->quan == 1L) uqwepgone(); 1534 | if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone(); 1535 | 1536 | if (otmp == uball) unpunish(); 1537 | if (otmp == uchain) unpunish(); /* but no useup() */ 1538 | else if (carried(otmp)) useup(otmp); 1539 | else useupf(otmp, 1L); 1540 | } 1541 | 1542 | /* NOTE: the order of these words exactly corresponds to the 1543 | order of oc_material values #define'd in objclass.h. */ 1544 | static const char *foodwords[] = { 1545 | "meal", "liquid", "wax", "food", "meat", 1546 | "paper", "cloth", "leather", "wood", "bone", "scale", 1547 | "metal", "metal", "metal", "silver", "gold", "platinum", "mithril", 1548 | "plastic", "glass", "rich food", "stone" 1549 | }; 1550 | 1551 | STATIC_OVL const char * 1552 | foodword(otmp) 1553 | register struct obj *otmp; 1554 | { 1555 | if (otmp->oclass == FOOD_CLASS) return "food"; 1556 | if (otmp->oclass == GEM_CLASS && 1557 | objects[otmp->otyp].oc_material == GLASS && 1558 | otmp->dknown) 1559 | makeknown(otmp->otyp); 1560 | return foodwords[objects[otmp->otyp].oc_material]; 1561 | } 1562 | 1563 | STATIC_OVL void 1564 | fpostfx(otmp) /* called after consuming (non-corpse) food */ 1565 | register struct obj *otmp; 1566 | { 1567 | switch(otmp->otyp) { 1568 | case SPRIG_OF_WOLFSBANE: 1569 | if (u.ulycn >= LOW_PM || is_were(youmonst.data)) 1570 | you_unwere(TRUE); 1571 | break; 1572 | case CARROT: 1573 | make_blinded(0L,TRUE); 1574 | break; 1575 | case FORTUNE_COOKIE: 1576 | outrumor(bcsign(otmp), BY_COOKIE); 1577 | if (!Blind) u.uconduct.literate++; 1578 | break; 1579 | case LUMP_OF_ROYAL_JELLY: 1580 | /* This stuff seems to be VERY healthy! */ 1581 | gainstr(otmp, 1); 1582 | if (Upolyd) { 1583 | u.mh += otmp->cursed ? -rnd(20) : rnd(20); 1584 | if (u.mh > u.mhmax) { 1585 | if (!rn2(17)) u.mhmax++; 1586 | u.mh = u.mhmax; 1587 | } else if (u.mh <= 0) { 1588 | rehumanize(); 1589 | } 1590 | } else { 1591 | u.uhp += otmp->cursed ? -rnd(20) : rnd(20); 1592 | if (u.uhp > u.uhpmax) { 1593 | if(!rn2(17)) u.uhpmax++; 1594 | u.uhp = u.uhpmax; 1595 | } else if (u.uhp <= 0) { 1596 | killer_format = KILLED_BY_AN; 1597 | killer = "rotten lump of royal jelly"; 1598 | done(POISONING); 1599 | } 1600 | } 1601 | if(!otmp->cursed) heal_legs(); 1602 | break; 1603 | case EGG: 1604 | if (touch_petrifies(&mons[otmp->corpsenm])) { 1605 | if (!Stone_resistance && 1606 | !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { 1607 | if (!Stoned) Stoned = 5; 1608 | killer_format = KILLED_BY_AN; 1609 | Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname); 1610 | delayed_killer = killer_buf; 1611 | } 1612 | } 1613 | break; 1614 | case EUCALYPTUS_LEAF: 1615 | if (Sick && !otmp->cursed) 1616 | make_sick(0L, (char *)0, TRUE, SICK_ALL); 1617 | if (Vomiting && !otmp->cursed) 1618 | make_vomiting(0L, TRUE); 1619 | break; 1620 | } 1621 | return; 1622 | } 1623 | 1624 | int 1625 | doeat() /* generic "eat" command funtion (see cmd.c) */ 1626 | { 1627 | register struct obj *otmp; 1628 | int basenutrit; /* nutrition of full item */ 1629 | boolean dont_start = FALSE; 1630 | 1631 | if (Strangled) { 1632 | pline("If you can't breathe air, how can you consume solids?"); 1633 | return 0; 1634 | } 1635 | if (!(otmp = floorfood("eat", 0))) return 0; 1636 | if (check_capacity((char *)0)) return 0; 1637 | 1638 | /* We have to make non-foods take 1 move to eat, unless we want to 1639 | * do ridiculous amounts of coding to deal with partly eaten plate 1640 | * mails, players who polymorph back to human in the middle of their 1641 | * metallic meal, etc.... 1642 | */ 1643 | if (!is_edible(otmp)) { 1644 | You("cannot eat that!"); 1645 | return 0; 1646 | } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL 1647 | #ifdef STEED 1648 | |W_SADDLE 1649 | #endif 1650 | )) != 0) { 1651 | /* let them eat rings */ 1652 | You_cant("eat %s you're wearing.", something); 1653 | return 0; 1654 | } 1655 | if (is_metallic(otmp) && 1656 | u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) { 1657 | otmp->rknown = TRUE; 1658 | if (otmp->quan > 1L) { 1659 | if(!carried(otmp)) 1660 | (void) splitobj(otmp, 1L); 1661 | else 1662 | otmp = splitobj(otmp, otmp->quan - 1L); 1663 | } 1664 | pline("Ulch - That %s was rustproofed!", xname(otmp)); 1665 | /* The regurgitated object's rustproofing is gone now */ 1666 | otmp->oerodeproof = 0; 1667 | make_stunned(HStun + rn2(10), TRUE); 1668 | You("spit %s out onto the %s.", the(xname(otmp)), 1669 | surface(u.ux, u.uy)); 1670 | if (carried(otmp)) { 1671 | freeinv(otmp); 1672 | dropy(otmp); 1673 | } 1674 | stackobj(otmp); 1675 | return 1; 1676 | } 1677 | /* KMH -- Slow digestion is... undigestable */ 1678 | if (otmp->otyp == RIN_SLOW_DIGESTION) { 1679 | pline("This ring is undigestable!"); 1680 | (void) rottenfood(otmp); 1681 | if (otmp->dknown && !objects[otmp->otyp].oc_name_known 1682 | && !objects[otmp->otyp].oc_uname) 1683 | docall(otmp); 1684 | return (1); 1685 | } 1686 | if (otmp->oclass != FOOD_CLASS) { 1687 | victual.reqtime = 1; 1688 | victual.piece = otmp; 1689 | /* Don't split it, we don't need to if it's 1 move */ 1690 | victual.usedtime = 0; 1691 | victual.canchoke = (u.uhs == SATIATED); 1692 | /* Note: gold weighs 1 pt. for each 1000 pieces (see */ 1693 | /* pickup.c) so gold and non-gold is consistent. */ 1694 | if (otmp->oclass == GOLD_CLASS) 1695 | basenutrit = ((otmp->quan > 200000L) ? 2000 1696 | : (int)(otmp->quan/100L)); 1697 | else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) 1698 | basenutrit = weight(otmp); 1699 | /* oc_nutrition is usually weight anyway */ 1700 | else basenutrit = objects[otmp->otyp].oc_nutrition; 1701 | victual.nmod = basenutrit; 1702 | victual.eating = TRUE; /* needed for lesshungry() */ 1703 | 1704 | if (otmp->cursed) 1705 | (void) rottenfood(otmp); 1706 | 1707 | if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) { 1708 | pline("Ecch - that must have been poisonous!"); 1709 | if(!Poison_resistance) { 1710 | losestr(rnd(4)); 1711 | losehp(rnd(15), xname(otmp), KILLED_BY_AN); 1712 | } else 1713 | You("seem unaffected by the poison."); 1714 | } else if (!otmp->cursed) 1715 | pline("This %s is delicious!", 1716 | otmp->oclass == GOLD_CLASS ? foodword(otmp) : 1717 | singular(otmp, xname)); 1718 | 1719 | u.uconduct.food++; 1720 | eatspecial(); 1721 | return 1; 1722 | } 1723 | 1724 | if(otmp == victual.piece) { 1725 | /* If they weren't able to choke, they don't suddenly become able to 1726 | * choke just because they were interrupted. On the other hand, if 1727 | * they were able to choke before, if they lost food it's possible 1728 | * they shouldn't be able to choke now. 1729 | */ 1730 | if (u.uhs != SATIATED) victual.canchoke = FALSE; 1731 | if(!carried(victual.piece)) { 1732 | if(victual.piece->quan > 1L) 1733 | (void) splitobj(victual.piece, 1L); 1734 | } 1735 | You("resume your meal."); 1736 | start_eating(victual.piece); 1737 | return(1); 1738 | } 1739 | 1740 | /* nothing in progress - so try to find something. */ 1741 | /* tins are a special case */ 1742 | /* tins must also check conduct separately in case they're discarded */ 1743 | if(otmp->otyp == TIN) { 1744 | start_tin(otmp); 1745 | return(1); 1746 | } 1747 | 1748 | /* KMH, conduct */ 1749 | u.uconduct.food++; 1750 | 1751 | victual.piece = otmp = touchfood(otmp); 1752 | victual.usedtime = 0; 1753 | 1754 | /* Now we need to calculate delay and nutritional info. 1755 | * The base nutrition calculated here and in eatcorpse() accounts 1756 | * for normal vs. rotten food. The reqtime and nutrit values are 1757 | * then adjusted in accordance with the amount of food left. 1758 | */ 1759 | if(otmp->otyp == CORPSE) { 1760 | int tmp = eatcorpse(otmp); 1761 | if (tmp == 2) { 1762 | /* used up */ 1763 | victual.piece = (struct obj *)0; 1764 | return(1); 1765 | } else if (tmp) 1766 | dont_start = TRUE; 1767 | /* if not used up, eatcorpse sets up reqtime and may modify 1768 | * oeaten */ 1769 | } else { 1770 | victual.reqtime = objects[otmp->otyp].oc_delay; 1771 | if (otmp->otyp != FORTUNE_COOKIE && 1772 | (otmp->cursed || 1773 | (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) && 1774 | (otmp->orotten || !rn2(7))))) { 1775 | 1776 | if (rottenfood(otmp)) { 1777 | otmp->orotten = TRUE; 1778 | dont_start = TRUE; 1779 | } 1780 | otmp->oeaten >>= 1; 1781 | } else fprefx(otmp); 1782 | } 1783 | 1784 | /* re-calc the nutrition */ 1785 | if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit; 1786 | else basenutrit = objects[otmp->otyp].oc_nutrition; 1787 | 1788 | #ifdef DEBUG 1789 | debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime); 1790 | debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit); 1791 | #endif 1792 | victual.reqtime = (basenutrit == 0 ? 0 : 1793 | rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit)); 1794 | #ifdef DEBUG 1795 | debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime); 1796 | #endif 1797 | /* calculate the modulo value (nutrit. units per round eating) 1798 | * note: this isn't exact - you actually lose a little nutrition 1799 | * due to this method. 1800 | * TODO: add in a "remainder" value to be given at the end of the 1801 | * meal. 1802 | */ 1803 | if (victual.reqtime == 0 || otmp->oeaten == 0) 1804 | /* possible if most has been eaten before */ 1805 | victual.nmod = 0; 1806 | else if ((int)otmp->oeaten >= victual.reqtime) 1807 | victual.nmod = -((int)otmp->oeaten / victual.reqtime); 1808 | else 1809 | victual.nmod = victual.reqtime % otmp->oeaten; 1810 | victual.canchoke = (u.uhs == SATIATED); 1811 | 1812 | if (!dont_start) start_eating(otmp); 1813 | return(1); 1814 | } 1815 | 1816 | /* Take a single bite from a piece of food, checking for choking and 1817 | * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise. 1818 | */ 1819 | STATIC_OVL int 1820 | bite() 1821 | { 1822 | if(victual.canchoke && u.uhunger >= 2000) { 1823 | choke(victual.piece); 1824 | return 1; 1825 | } 1826 | if (victual.doreset) { 1827 | do_reset_eat(); 1828 | return 0; 1829 | } 1830 | force_save_hs = TRUE; 1831 | if(victual.nmod < 0) { 1832 | lesshungry(-victual.nmod); 1833 | victual.piece->oeaten -= -victual.nmod; 1834 | } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) { 1835 | lesshungry(1); 1836 | victual.piece->oeaten--; 1837 | } 1838 | force_save_hs = FALSE; 1839 | recalc_wt(); 1840 | return 0; 1841 | } 1842 | 1843 | #endif /* OVLB */ 1844 | #ifdef OVL0 1845 | 1846 | void 1847 | gethungry() /* as time goes by - called by moveloop() and domove() */ 1848 | { 1849 | if (u.uinvulnerable) return; /* you don't feel hungrier */ 1850 | 1851 | if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */ 1852 | && (carnivorous(youmonst.data) || herbivorous(youmonst.data)) 1853 | && !Slow_digestion) 1854 | u.uhunger--; /* ordinary food consumption */ 1855 | 1856 | if (moves % 2) { /* odd turns */ 1857 | /* Regeneration uses up food, unless due to an artifact */ 1858 | if (HRegeneration || ((ERegeneration & (~W_ART)) && 1859 | (ERegeneration != W_WEP || !uwep->oartifact))) 1860 | u.uhunger--; 1861 | if (near_capacity() > SLT_ENCUMBER) u.uhunger--; 1862 | } else { /* even turns */ 1863 | if (Hunger) u.uhunger--; 1864 | /* Conflict uses up food too */ 1865 | if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--; 1866 | /* +0 charged rings don't do anything, so don't affect hunger */ 1867 | /* Slow digestion still uses ring hunger */ 1868 | switch ((int)(moves % 20)) { /* note: use even cases only */ 1869 | case 4: if (uleft && 1870 | (uleft->spe || !objects[uleft->otyp].oc_charged)) 1871 | u.uhunger--; 1872 | break; 1873 | case 8: if (uamul) u.uhunger--; 1874 | break; 1875 | case 12: if (uright && 1876 | (uright->spe || !objects[uright->otyp].oc_charged)) 1877 | u.uhunger--; 1878 | break; 1879 | case 16: if (u.uhave.amulet) u.uhunger--; 1880 | break; 1881 | default: break; 1882 | } 1883 | } 1884 | newuhs(TRUE); 1885 | } 1886 | 1887 | #endif /* OVL0 */ 1888 | #ifdef OVLB 1889 | 1890 | void 1891 | morehungry(num) /* called after vomiting and after performing feats of magic */ 1892 | register int num; 1893 | { 1894 | u.uhunger -= num; 1895 | newuhs(TRUE); 1896 | } 1897 | 1898 | 1899 | void 1900 | lesshungry(num) /* called after eating (and after drinking fruit juice) */ 1901 | register int num; 1902 | { 1903 | #ifdef DEBUG 1904 | debugpline("lesshungry(%d)", num); 1905 | #endif 1906 | u.uhunger += num; 1907 | if(u.uhunger >= 2000) { 1908 | if (!victual.eating || victual.canchoke) { 1909 | if (victual.eating) { 1910 | choke(victual.piece); 1911 | reset_eat(); 1912 | } else 1913 | choke(tin.tin); /* may be null */ 1914 | /* no reset_eat() */ 1915 | } 1916 | } else { 1917 | /* Have lesshungry() report when you're nearly full so all eating 1918 | * warns when you're about to choke. 1919 | */ 1920 | if (u.uhunger >= 1500) { 1921 | if (!victual.eating || (victual.eating && !victual.fullwarn)) { 1922 | pline("You're having a hard time getting all of it down."); 1923 | nomovemsg = "You're finally finished."; 1924 | if (!victual.eating) 1925 | multi = -2; 1926 | else { 1927 | victual.fullwarn = TRUE; 1928 | if (victual.canchoke && victual.reqtime > 1) { 1929 | /* a one-gulp food will not survive a stop */ 1930 | if (yn_function("Stop eating?",ynchars,'y')=='y') { 1931 | reset_eat(); 1932 | nomovemsg = (char *)0; 1933 | } 1934 | } 1935 | } 1936 | } 1937 | } 1938 | } 1939 | newuhs(FALSE); 1940 | } 1941 | 1942 | STATIC_PTR 1943 | int 1944 | unfaint() 1945 | { 1946 | (void) Hear_again(); 1947 | if(u.uhs > FAINTING) 1948 | u.uhs = FAINTING; 1949 | stop_occupation(); 1950 | flags.botl = 1; 1951 | return 0; 1952 | } 1953 | 1954 | #endif /* OVLB */ 1955 | #ifdef OVL0 1956 | 1957 | boolean 1958 | is_fainted() 1959 | { 1960 | return((boolean)(u.uhs == FAINTED)); 1961 | } 1962 | 1963 | void 1964 | reset_faint() /* call when a faint must be prematurely terminated */ 1965 | { 1966 | if(is_fainted()) nomul(0); 1967 | } 1968 | 1969 | #if 0 1970 | void 1971 | sync_hunger() 1972 | { 1973 | 1974 | if(is_fainted()) { 1975 | 1976 | flags.soundok = 0; 1977 | nomul(-10+(u.uhunger/10)); 1978 | nomovemsg = "You regain consciousness."; 1979 | afternmv = unfaint; 1980 | } 1981 | } 1982 | #endif 1983 | 1984 | void 1985 | newuhs(incr) /* compute and comment on your (new?) hunger status */ 1986 | boolean incr; 1987 | { 1988 | unsigned newhs; 1989 | static unsigned save_hs; 1990 | static boolean saved_hs = FALSE; 1991 | int h = u.uhunger; 1992 | 1993 | newhs = (h > 1000) ? SATIATED : 1994 | (h > 150) ? NOT_HUNGRY : 1995 | (h > 50) ? HUNGRY : 1996 | (h > 0) ? WEAK : FAINTING; 1997 | 1998 | /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY. 1999 | * This should not produce the message "you only feel hungry now"; 2000 | * that message should only appear if HUNGRY is an endpoint. Therefore 2001 | * we check to see if we're in the middle of eating. If so, we save 2002 | * the first hunger status, and at the end of eating we decide what 2003 | * message to print based on the _entire_ meal, not on each little bit. 2004 | */ 2005 | /* It is normally possible to check if you are in the middle of a meal 2006 | * by checking occupation == eatfood, but there is one special case: 2007 | * start_eating() can call bite() for your first bite before it 2008 | * sets the occupation. 2009 | * Anyone who wants to get that case to work _without_ an ugly static 2010 | * force_save_hs variable, feel free. 2011 | */ 2012 | /* Note: If you become a certain hunger status in the middle of the 2013 | * meal, and still have that same status at the end of the meal, 2014 | * this will incorrectly print the associated message at the end of 2015 | * the meal instead of the middle. Such a case is currently 2016 | * impossible, but could become possible if a message for SATIATED 2017 | * were added or if HUNGRY and WEAK were separated by a big enough 2018 | * gap to fit two bites. 2019 | */ 2020 | if (occupation == eatfood || force_save_hs) { 2021 | if (!saved_hs) { 2022 | save_hs = u.uhs; 2023 | saved_hs = TRUE; 2024 | } 2025 | u.uhs = newhs; 2026 | return; 2027 | } else { 2028 | if (saved_hs) { 2029 | u.uhs = save_hs; 2030 | saved_hs = FALSE; 2031 | } 2032 | } 2033 | 2034 | if(newhs == FAINTING) { 2035 | if(is_fainted()) newhs = FAINTED; 2036 | if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) { 2037 | if(!is_fainted() && multi >= 0 /* %% */) { 2038 | /* stop what you're doing, then faint */ 2039 | stop_occupation(); 2040 | You("faint from lack of food."); 2041 | flags.soundok = 0; 2042 | nomul(-10+(u.uhunger/10)); 2043 | nomovemsg = "You regain consciousness."; 2044 | afternmv = unfaint; 2045 | newhs = FAINTED; 2046 | } 2047 | } else 2048 | if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) { 2049 | u.uhs = STARVED; 2050 | flags.botl = 1; 2051 | bot(); 2052 | You("die from starvation."); 2053 | killer_format = KILLED_BY; 2054 | killer = "starvation"; 2055 | done(STARVING); 2056 | /* if we return, we lifesaved, and that calls newuhs */ 2057 | return; 2058 | } 2059 | } 2060 | 2061 | if(newhs != u.uhs) { 2062 | if(newhs >= WEAK && u.uhs < WEAK) 2063 | losestr(1); /* this may kill you -- see below */ 2064 | else if(newhs < WEAK && u.uhs >= WEAK) 2065 | losestr(-1); 2066 | switch(newhs){ 2067 | case HUNGRY: 2068 | if (Hallucination) { 2069 | You((!incr) ? 2070 | "now have a lesser case of the munchies." : 2071 | "are getting the munchies."); 2072 | } else 2073 | You((!incr) ? "only feel hungry now." : 2074 | (u.uhunger < 145) ? "feel hungry." : 2075 | "are beginning to feel hungry."); 2076 | if (incr && occupation && 2077 | (occupation != eatfood && occupation != opentin)) 2078 | stop_occupation(); 2079 | break; 2080 | case WEAK: 2081 | if (Hallucination) 2082 | pline((!incr) ? 2083 | "You still have the munchies." : 2084 | "The munchies are interfering with your motor capabilities."); 2085 | else if (incr && 2086 | (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE))) 2087 | pline("%s needs food, badly!", 2088 | (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? 2089 | urole.name.m : "Elf"); 2090 | else 2091 | You((!incr) ? "feel weak now." : 2092 | (u.uhunger < 45) ? "feel weak." : 2093 | "are beginning to feel weak."); 2094 | if (incr && occupation && 2095 | (occupation != eatfood && occupation != opentin)) 2096 | stop_occupation(); 2097 | break; 2098 | } 2099 | u.uhs = newhs; 2100 | flags.botl = 1; 2101 | bot(); 2102 | if ((Upolyd ? u.mh : u.uhp) < 1) { 2103 | You("die from hunger and exhaustion."); 2104 | killer_format = KILLED_BY; 2105 | killer = "exhaustion"; 2106 | done(STARVING); 2107 | return; 2108 | } 2109 | } 2110 | } 2111 | 2112 | #endif /* OVL0 */ 2113 | #ifdef OVLB 2114 | 2115 | /* Returns an object representing food. Object may be either on floor or 2116 | * in inventory. 2117 | */ 2118 | struct obj * 2119 | floorfood(verb,corpsecheck) /* get food from floor or pack */ 2120 | const char *verb; 2121 | int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ 2122 | { 2123 | register struct obj *otmp; 2124 | char qbuf[QBUFSZ]; 2125 | char c; 2126 | boolean feeding = (!strcmp(verb, "eat")); 2127 | 2128 | if (feeding && metallivorous(youmonst.data)) { 2129 | struct obj *gold; 2130 | struct trap *ttmp = t_at(u.ux, u.uy); 2131 | 2132 | if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) { 2133 | /* If not already stuck in the trap, perhaps there should 2134 | be a chance to becoming trapped? Probably not, because 2135 | then the trap would just get eaten on the _next_ turn... */ 2136 | Sprintf(qbuf, "There is a bear trap here (%s); eat it?", 2137 | (u.utrap && u.utraptype == TT_BEARTRAP) ? 2138 | "holding you" : "armed"); 2139 | if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { 2140 | u.utrap = u.utraptype = 0; 2141 | deltrap(ttmp); 2142 | return mksobj(BEARTRAP, TRUE, FALSE); 2143 | } else if (c == 'q') { 2144 | return (struct obj *)0; 2145 | } 2146 | } 2147 | 2148 | if ( 2149 | #ifdef STEED 2150 | !u.usteed && 2151 | #endif 2152 | (gold = g_at(u.ux, u.uy)) != 0) { 2153 | if (gold->quan == 1L) 2154 | Sprintf(qbuf, "There is 1 gold piece here; eat it?"); 2155 | else 2156 | Sprintf(qbuf, "There are %ld gold pieces here; eat them?", 2157 | gold->quan); 2158 | if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { 2159 | obj_extract_self(gold); 2160 | return gold; 2161 | } else if (c == 'q') { 2162 | return (struct obj *)0; 2163 | } 2164 | } 2165 | } 2166 | 2167 | /* Is there some food (probably a heavy corpse) here on the ground? */ 2168 | if ( 2169 | #ifdef STEED 2170 | !u.usteed && 2171 | #endif 2172 | !(Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) 2173 | && !u.uswallow) { 2174 | for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { 2175 | if(corpsecheck ? 2176 | (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) : 2177 | feeding ? (otmp->oclass != GOLD_CLASS && is_edible(otmp)) : 2178 | otmp->oclass==FOOD_CLASS) { 2179 | Sprintf(qbuf, "There %s %s here; %s %s?", 2180 | (otmp->quan == 1L) ? "is" : "are", 2181 | doname(otmp), verb, 2182 | (otmp->quan == 1L) ? "it" : "one"); 2183 | if((c = yn_function(qbuf,ynqchars,'n')) == 'y') 2184 | return(otmp); 2185 | else if(c == 'q') 2186 | return((struct obj *) 0); 2187 | } 2188 | } 2189 | } 2190 | /* We cannot use ALL_CLASSES since that causes getobj() to skip its 2191 | * "ugly checks" and we need to check for inedible items. 2192 | */ 2193 | otmp = getobj(feeding ? (const char *)allobj : 2194 | (const char *)comestibles, verb); 2195 | if (corpsecheck && otmp) 2196 | if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) { 2197 | You_cant("%s that!", verb); 2198 | return (struct obj *)0; 2199 | } 2200 | return otmp; 2201 | } 2202 | 2203 | /* Side effects of vomiting */ 2204 | /* added nomul (MRS) - it makes sense, you're too busy being sick! */ 2205 | void 2206 | vomit() /* A good idea from David Neves */ 2207 | { 2208 | make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE); 2209 | nomul(-2); 2210 | } 2211 | 2212 | int 2213 | eaten_stat(base, obj) 2214 | register int base; 2215 | register struct obj *obj; 2216 | { 2217 | long uneaten_amt, full_amount; 2218 | 2219 | uneaten_amt = (long)obj->oeaten; 2220 | full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit 2221 | : (long)objects[obj->otyp].oc_nutrition; 2222 | 2223 | base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L); 2224 | return (base < 1) ? 1 : base; 2225 | } 2226 | 2227 | #endif /* OVLB */ 2228 | 2229 | /*eat.c*/