1/* SCCS Id: @(#)potion.c 3.4 2002/10/02 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7#ifdef OVLB 8boolean notonhead = FALSE; 9 10static NEARDATA int nothing, unkn; 11static NEARDATA const char beverages[] = { POTION_CLASS, 0 }; 12 13STATIC_DCL long FDECL(itimeout, (long)); 14STATIC_DCL long FDECL(itimeout_incr, (long,int)); 15STATIC_DCL void NDECL(ghost_from_bottle); 16STATIC_DCL short FDECL(mixtype, (struct obj *,struct obj *)); 17 18/* force `val' to be within valid range for intrinsic timeout value */ 19STATIC_OVL long 20itimeout(val) 21long val; 22{ 23 if (val >= TIMEOUT) val = TIMEOUT; 24 else if (val < 1) val = 0; 25 26 return val; 27} 28 29/* increment `old' by `incr' and force result to be valid intrinsic timeout */ 30STATIC_OVL long 31itimeout_incr(old, incr) 32long old; 33int incr; 34{ 35 return itimeout((old & TIMEOUT) + (long)incr); 36} 37 38/* set the timeout field of intrinsic `which' */ 39void 40set_itimeout(which, val) 41long *which, val; 42{ 43 *which &= ~TIMEOUT; 44 *which |= itimeout(val); 45} 46 47/* increment the timeout field of intrinsic `which' */ 48void 49incr_itimeout(which, incr) 50long *which; 51int incr; 52{ 53 set_itimeout(which, itimeout_incr(*which, incr)); 54} 55 56void 57make_confused(xtime,talk) 58long xtime; 59boolean talk; 60{ 61 long old = HConfusion; 62 63 if (!xtime && old) { 64 if (talk) 65 You_feel("less %s now.", 66 Hallucination ? "trippy" : "confused"); 67 } 68 if ((xtime && !old) || (!xtime && old)) flags.botl = TRUE; 69 70 set_itimeout(&HConfusion, xtime); 71} 72 73void 74make_stunned(xtime,talk) 75long xtime; 76boolean talk; 77{ 78 long old = HStun; 79 80 if (!xtime && old) { 81 if (talk) 82 You_feel("%s now.", 83 Hallucination ? "less wobbly" : "a bit steadier"); 84 } 85 if (xtime && !old) { 86 if (talk) { 87#ifdef STEED 88 if (u.usteed) 89 You("wobble in the saddle."); 90 else 91#endif 92 You("%s...", stagger(youmonst.data, "stagger")); 93 } 94 } 95 if ((!xtime && old) || (xtime && !old)) flags.botl = TRUE; 96 97 set_itimeout(&HStun, xtime); 98} 99 100void 101make_sick(xtime, cause, talk, type) 102long xtime; 103const char *cause; /* sickness cause */ 104boolean talk; 105int type; 106{ 107 long old = Sick; 108 109 if (xtime > 0L) { 110 if (Sick_resistance) return; 111 if (!old) { 112 /* newly sick */ 113 You_feel("deathly sick."); 114 } else { 115 /* already sick */ 116 if (talk) You_feel("%s worse.", 117 xtime <= Sick/2L ? "much" : "even"); 118 } 119 set_itimeout(&Sick, xtime); 120 u.usick_type |= type; 121 flags.botl = TRUE; 122 } else if (old && (type & u.usick_type)) { 123 /* was sick, now not */ 124 u.usick_type &= ~type; 125 if (u.usick_type) { /* only partly cured */ 126 if (talk) You_feel("somewhat better."); 127 set_itimeout(&Sick, Sick * 2); /* approximation */ 128 } else { 129 if (talk) pline("What a relief!"); 130 Sick = 0L; /* set_itimeout(&Sick, 0L) */ 131 } 132 flags.botl = TRUE; 133 } 134 135 if (Sick) { 136 exercise(A_CON, FALSE); 137 if (cause) { 138 (void) strncpy(u.usick_cause, cause, sizeof(u.usick_cause)); 139 u.usick_cause[sizeof(u.usick_cause)-1] = 0; 140 } 141 else 142 u.usick_cause[0] = 0; 143 } else 144 u.usick_cause[0] = 0; 145} 146 147void 148make_vomiting(xtime, talk) 149long xtime; 150boolean talk; 151{ 152 long old = Vomiting; 153 154 if(!xtime && old) 155 if(talk) You_feel("much less nauseated now."); 156 157 set_itimeout(&Vomiting, xtime); 158} 159 160static const char vismsg[] = "vision seems to %s for a moment but is %s now."; 161static const char eyemsg[] = "%s momentarily %s."; 162 163void 164make_blinded(xtime, talk) 165long xtime; 166boolean talk; 167{ 168 long old = Blinded; 169 boolean u_could_see, can_see_now; 170 int eyecnt; 171 char buf[BUFSZ]; 172 173 /* we need to probe ahead in case the Eyes of the Overworld 174 are or will be overriding blindness */ 175 u_could_see = !Blind; 176 Blinded = xtime ? 1L : 0L; 177 can_see_now = !Blind; 178 Blinded = old; /* restore */ 179 180 if (u.usleep) talk = FALSE; 181 182 if (can_see_now && !u_could_see) { /* regaining sight */ 183 if (talk) { 184 if (Hallucination) 185 pline("Far out! Everything is all cosmic again!"); 186 else 187 You("can see again."); 188 } 189 } else if (old && !xtime) { 190 /* clearing temporary blindness without toggling blindness */ 191 if (talk) { 192 if (!haseyes(youmonst.data)) { 193 strange_feeling((struct obj *)0, (char *)0); 194 } else if (Blindfolded) { 195 Strcpy(buf, body_part(EYE)); 196 eyecnt = eyecount(youmonst.data); 197 Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), 198 (eyecnt == 1) ? "itches" : "itch"); 199 } else { /* Eyes of the Overworld */ 200 Your(vismsg, "brighten", 201 Hallucination ? "sadder" : "normal"); 202 } 203 } 204 } 205 206 if (u_could_see && !can_see_now) { /* losing sight */ 207 if (talk) { 208 if (Hallucination) 209 pline("Oh, bummer! Everything is dark! Help!"); 210 else 211 pline("A cloud of darkness falls upon you."); 212 } 213 /* Before the hero goes blind, set the ball&chain variables. */ 214 if (Punished) set_bc(0); 215 } else if (!old && xtime) { 216 /* setting temporary blindness without toggling blindness */ 217 if (talk) { 218 if (!haseyes(youmonst.data)) { 219 strange_feeling((struct obj *)0, (char *)0); 220 } else if (Blindfolded) { 221 Strcpy(buf, body_part(EYE)); 222 eyecnt = eyecount(youmonst.data); 223 Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), 224 (eyecnt == 1) ? "twitches" : "twitch"); 225 } else { /* Eyes of the Overworld */ 226 Your(vismsg, "dim", 227 Hallucination ? "happier" : "normal"); 228 } 229 } 230 } 231 232 set_itimeout(&Blinded, xtime); 233 234 if (u_could_see ^ can_see_now) { /* one or the other but not both */ 235 flags.botl = 1; 236 vision_full_recalc = 1; /* blindness just got toggled */ 237 if (Blind_telepat || Infravision) see_monsters(); 238 } 239} 240 241boolean 242make_hallucinated(xtime, talk, mask) 243long xtime; /* nonzero if this is an attempt to turn on hallucination */ 244boolean talk; 245long mask; /* nonzero if resistance status should change by mask */ 246{ 247 long old = HHallucination; 248 boolean changed = 0; 249 const char *message, *verb; 250 251 message = (!xtime) ? "Everything %s SO boring now." : 252 "Oh wow! Everything %s so cosmic!"; 253 verb = (!Blind) ? "looks" : "feels"; 254 255 if (mask) { 256 if (HHallucination) changed = TRUE; 257 258 if (!xtime) EHalluc_resistance |= mask; 259 else EHalluc_resistance &= ~mask; 260 } else { 261 if (!EHalluc_resistance && (!!HHallucination != !!xtime)) 262 changed = TRUE; 263 set_itimeout(&HHallucination, xtime); 264 265 /* clearing temporary hallucination without toggling vision */ 266 if (!changed && !HHallucination && old && talk) { 267 if (!haseyes(youmonst.data)) { 268 strange_feeling((struct obj *)0, (char *)0); 269 } else if (Blind) { 270 char buf[BUFSZ]; 271 int eyecnt = eyecount(youmonst.data); 272 273 Strcpy(buf, body_part(EYE)); 274 Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), 275 (eyecnt == 1) ? "itches" : "itch"); 276 } else { /* Grayswandir */ 277 Your(vismsg, "flatten", "normal"); 278 } 279 } 280 } 281 282 if (changed) { 283 if (u.uswallow) { 284 swallowed(0); /* redraw swallow display */ 285 } else { 286 /* The see_* routines should be called *before* the pline. */ 287 see_monsters(); 288 see_objects(); 289 see_traps(); 290 } 291 292 /* for perm_inv and anything similar 293 (eg. Qt windowport's equipped items display) */ 294 update_inventory(); 295 296 flags.botl = 1; 297 if (talk) pline(message, verb); 298 } 299 return changed; 300} 301 302STATIC_OVL void 303ghost_from_bottle() 304{ 305 struct monst *mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS); 306 307 if (!mtmp) { 308 pline("This bottle turns out to be empty."); 309 return; 310 } 311 if (Blind) { 312 pline("As you open the bottle, %s emerges.", something); 313 return; 314 } 315 pline("As you open the bottle, an enormous %s emerges!", 316 Hallucination ? rndmonnam() : (const char *)"ghost"); 317 if(flags.verbose) 318 You("are frightened to death, and unable to move."); 319 nomul(-3); 320 nomovemsg = "You regain your composure."; 321} 322 323/* "Quaffing is like drinking, except you spill more." -- Terry Pratchett 324 */ 325int 326dodrink() 327{ 328 register struct obj *otmp; 329 const char *potion_descr; 330 331 if (Strangled) { 332 pline("If you can't breathe air, how can you drink liquid?"); 333 return 0; 334 } 335 /* Is there a fountain to drink from here? */ 336 if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) && !Levitation) { 337 if(yn("Drink from the fountain?") == 'y') { 338 drinkfountain(); 339 return 1; 340 } 341 } 342#ifdef SINKS 343 /* Or a kitchen sink? */ 344 if (IS_SINK(levl[u.ux][u.uy].typ)) { 345 if (yn("Drink from the sink?") == 'y') { 346 drinksink(); 347 return 1; 348 } 349 } 350#endif 351 352 /* Or are you surrounded by water? */ 353 if (Underwater) { 354 if (yn("Drink the water around you?") == 'y') { 355 pline("Do you know what lives in this water!"); 356 return 1; 357 } 358 } 359 360 otmp = getobj(beverages, "drink"); 361 if(!otmp) return(0); 362 otmp->in_use = TRUE; /* you've opened the stopper */ 363 364#define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in muse.c */ 365 366 potion_descr = OBJ_DESCR(objects[otmp->otyp]); 367 if (potion_descr) { 368 if (!strcmp(potion_descr, "milky") && 369 flags.ghost_count < MAXMONNO && 370 !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) { 371 ghost_from_bottle(); 372 useup(otmp); 373 return(1); 374 } else if (!strcmp(potion_descr, "smoky") && 375 flags.djinni_count < MAXMONNO && 376 !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) { 377 djinni_from_bottle(otmp); 378 useup(otmp); 379 return(1); 380 } 381 } 382 return dopotion(otmp); 383} 384 385int 386dopotion(otmp) 387register struct obj *otmp; 388{ 389 int retval; 390 391 otmp->in_use = TRUE; 392 nothing = unkn = 0; 393 if((retval = peffects(otmp)) >= 0) return(retval); 394 395 if(nothing) { 396 unkn++; 397 You("have a %s feeling for a moment, then it passes.", 398 Hallucination ? "normal" : "peculiar"); 399 } 400 if(otmp->dknown && !objects[otmp->otyp].oc_name_known) { 401 if(!unkn) { 402 makeknown(otmp->otyp); 403 more_experienced(0,10); 404 } else if(!objects[otmp->otyp].oc_uname) 405 docall(otmp); 406 } 407 useup(otmp); 408 return(1); 409} 410 411int 412peffects(otmp) 413 register struct obj *otmp; 414{ 415 register int i, ii, lim; 416 417 switch(otmp->otyp){ 418 case POT_RESTORE_ABILITY: 419 case SPE_RESTORE_ABILITY: 420 unkn++; 421 if(otmp->cursed) { 422 pline("Ulch! This makes you feel mediocre!"); 423 break; 424 } else { 425 pline("Wow! This makes you feel %s!", 426 (otmp->blessed) ? 427 (unfixable_trouble_count(FALSE) ? "better" : "great") 428 : "good"); 429 i = rn2(A_MAX); /* start at a random point */ 430 for (ii = 0; ii < A_MAX; ii++) { 431 lim = AMAX(i); 432 if (i == A_STR && u.uhs >= 3) --lim; /* WEAK */ 433 if (ABASE(i) < lim) { 434 ABASE(i) = lim; 435 flags.botl = 1; 436 /* only first found if not blessed */ 437 if (!otmp->blessed) break; 438 } 439 if(++i >= A_MAX) i = 0; 440 } 441 } 442 break; 443 case POT_HALLUCINATION: 444 if (Hallucination || Halluc_resistance) nothing++; 445 (void) make_hallucinated(itimeout_incr(HHallucination, 446 rn1(200, 600 - 300 * bcsign(otmp))), 447 TRUE, 0L); 448 break; 449 case POT_WATER: 450 if(!otmp->blessed && !otmp->cursed) { 451 pline("This tastes like water."); 452 u.uhunger += rnd(10); 453 newuhs(FALSE); 454 break; 455 } 456 unkn++; 457 if(is_undead(youmonst.data) || is_demon(youmonst.data) || 458 u.ualign.type == A_CHAOTIC) { 459 if(otmp->blessed) { 460 pline("This burns like acid!"); 461 exercise(A_CON, FALSE); 462 if (u.ulycn >= LOW_PM) { 463 Your("affinity to %s disappears!", 464 makeplural(mons[u.ulycn].mname)); 465 if (youmonst.data == &mons[u.ulycn]) 466 you_unwere(FALSE); 467 u.ulycn = NON_PM; /* cure lycanthropy */ 468 } 469 losehp(d(2,6), "potion of holy water", KILLED_BY_AN); 470 } else if(otmp->cursed) { 471 You_feel("quite proud of yourself."); 472 healup(d(2,6),0,0,0); 473 if (u.ulycn >= LOW_PM && !Upolyd) you_were(); 474 exercise(A_CON, TRUE); 475 } 476 } else { 477 if(otmp->blessed) { 478 You_feel("full of awe."); 479 make_sick(0L, (char *) 0, TRUE, SICK_ALL); 480 exercise(A_WIS, TRUE); 481 exercise(A_CON, TRUE); 482 if (u.ulycn >= LOW_PM) 483 you_unwere(TRUE); /* "Purified" */ 484 /* make_confused(0L,TRUE); */ 485 } else { 486 if(u.ualign.type == A_LAWFUL) { 487 pline("This burns like acid!"); 488 losehp(d(2,6), "potion of unholy water", 489 KILLED_BY_AN); 490 } else 491 You_feel("full of dread."); 492 if (u.ulycn >= LOW_PM && !Upolyd) you_were(); 493 exercise(A_CON, FALSE); 494 } 495 } 496 break; 497 case POT_BOOZE: 498 unkn++; 499 pline("Ooph! This tastes like %s%s!", 500 otmp->odiluted ? "watered down " : "", 501 Hallucination ? "dandelion wine" : "liquid fire"); 502 if (!otmp->blessed) 503 make_confused(itimeout_incr(HConfusion, d(3,8)), FALSE); 504 /* the whiskey makes us feel better */ 505 if (!otmp->odiluted) healup(1, 0, FALSE, FALSE); 506 u.uhunger += 10 * (2 + bcsign(otmp)); 507 newuhs(FALSE); 508 exercise(A_WIS, FALSE); 509 if(otmp->cursed) { 510 You("pass out."); 511 multi = -rnd(15); 512 nomovemsg = "You awake with a headache."; 513 } 514 break; 515 case POT_ENLIGHTENMENT: 516 if(otmp->cursed) { 517 unkn++; 518 You("have an uneasy feeling..."); 519 exercise(A_WIS, FALSE); 520 } else { 521 if (otmp->blessed) { 522 (void) adjattrib(A_INT, 1, FALSE); 523 (void) adjattrib(A_WIS, 1, FALSE); 524 } 525 You_feel("self-knowledgeable..."); 526 display_nhwindow(WIN_MESSAGE, FALSE); 527 enlightenment(0); 528 pline_The("feeling subsides."); 529 exercise(A_WIS, TRUE); 530 } 531 break; 532 case SPE_INVISIBILITY: 533 /* spell cannot penetrate mummy wrapping */ 534 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { 535 You_feel("rather itchy under your %s.", xname(uarmc)); 536 break; 537 } 538 /* FALLTHRU */ 539 case POT_INVISIBILITY: 540 if (Invis || Blind || BInvis) { 541 nothing++; 542 } else { 543 self_invis_message(); 544 } 545 if (otmp->blessed) HInvis |= FROMOUTSIDE; 546 else incr_itimeout(&HInvis, rn1(15,31)); 547 newsym(u.ux,u.uy); /* update position */ 548 if(otmp->cursed) { 549 pline("For some reason, you feel your presence is known."); 550 aggravate(); 551 } 552 break; 553 case POT_SEE_INVISIBLE: 554 /* tastes like fruit juice in Rogue */ 555 case POT_FRUIT_JUICE: 556 { 557 int msg = Invisible && !Blind; 558 559 unkn++; 560 if (otmp->cursed) 561 pline("Yecch! This tastes %s.", 562 Hallucination ? "overripe" : "rotten"); 563 else 564 pline(Hallucination ? 565 "This tastes like 10%% real %s%s all-natural beverage." : 566 "This tastes like %s%s.", 567 otmp->odiluted ? "reconstituted " : "", 568 fruitname(TRUE)); 569 if (otmp->otyp == POT_FRUIT_JUICE) { 570 u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp)); 571 newuhs(FALSE); 572 break; 573 } 574 if (!otmp->cursed) { 575 /* Tell them they can see again immediately, which 576 * will help them identify the potion... 577 */ 578 make_blinded(0L,TRUE); 579 } 580 if (otmp->blessed) 581 HSee_invisible |= FROMOUTSIDE; 582 else 583 incr_itimeout(&HSee_invisible, rn1(100,750)); 584 set_mimic_blocking(); /* do special mimic handling */ 585 see_monsters(); /* see invisible monsters */ 586 newsym(u.ux,u.uy); /* see yourself! */ 587 if (msg && !Blind) { /* Blind possible if polymorphed */ 588 You("can see through yourself, but you are visible!"); 589 unkn--; 590 } 591 break; 592 } 593 case POT_PARALYSIS: 594 if (Free_action) 595 You("stiffen momentarily."); 596 else { 597 if (Levitation || Is_airlevel(&u.uz)||Is_waterlevel(&u.uz)) 598 You("are motionlessly suspended."); 599#ifdef STEED 600 else if (u.usteed) 601 You("are frozen in place!"); 602#endif 603 else 604 Your("%s are frozen to the %s!", 605 makeplural(body_part(FOOT)), surface(u.ux, u.uy)); 606 nomul(-(rn1(10, 25 - 12*bcsign(otmp)))); 607 nomovemsg = You_can_move_again; 608 exercise(A_DEX, FALSE); 609 } 610 break; 611 case POT_SLEEPING: 612 if(Sleep_resistance || Free_action) 613 You("yawn."); 614 else { 615 You("suddenly fall asleep!"); 616 fall_asleep(-rn1(10, 25 - 12*bcsign(otmp)), TRUE); 617 } 618 break; 619 case POT_MONSTER_DETECTION: 620 case SPE_DETECT_MONSTERS: 621 if (otmp->blessed) { 622 int x, y; 623 624 if (Detect_monsters) nothing++; 625 unkn++; 626 /* after a while, repeated uses become less effective */ 627 if (HDetect_monsters >= 300L) 628 i = 1; 629 else 630 i = rn1(40,21); 631 incr_itimeout(&HDetect_monsters, i); 632 for (x = 1; x < COLNO; x++) { 633 for (y = 0; y < ROWNO; y++) { 634 if (levl[x][y].glyph == GLYPH_INVISIBLE) { 635 unmap_object(x, y); 636 newsym(x,y); 637 } 638 if (MON_AT(x,y)) unkn = 0; 639 } 640 } 641 see_monsters(); 642 if (unkn) You_feel("lonely."); 643 break; 644 } 645 if (monster_detect(otmp, 0)) 646 return(1); /* nothing detected */ 647 exercise(A_WIS, TRUE); 648 break; 649 case POT_OBJECT_DETECTION: 650 case SPE_DETECT_TREASURE: 651 if (object_detect(otmp, 0)) 652 return(1); /* nothing detected */ 653 exercise(A_WIS, TRUE); 654 break; 655 case POT_SICKNESS: 656 pline("Yecch! This stuff tastes like poison."); 657 if (otmp->blessed) { 658 pline("(But in fact it was mildly stale %s.)", 659 fruitname(TRUE)); 660 if (!Role_if(PM_HEALER)) { 661 /* NB: blessed otmp->fromsink is not possible */ 662 losehp(1, "mildly contaminated potion", KILLED_BY_AN); 663 } 664 } else { 665 if(Poison_resistance) 666 pline( 667 "(But in fact it was biologically contaminated %s.)", 668 fruitname(TRUE)); 669 if (Role_if(PM_HEALER)) 670 pline("Fortunately, you have been immunized."); 671 else { 672 int typ = rn2(A_MAX); 673 674 if (!Fixed_abil) { 675 poisontell(typ); 676 (void) adjattrib(typ, 677 Poison_resistance ? -1 : -rn1(4,3), 678 TRUE); 679 } 680 if(!Poison_resistance) { 681 if (otmp->fromsink) 682 losehp(rnd(10)+5*!!(otmp->cursed), 683 "contaminated tap water", KILLED_BY); 684 else 685 losehp(rnd(10)+5*!!(otmp->cursed), 686 "contaminated potion", KILLED_BY_AN); 687 } 688 exercise(A_CON, FALSE); 689 } 690 } 691 if(Hallucination) { 692 You("are shocked back to your senses!"); 693 (void) make_hallucinated(0L,FALSE,0L); 694 } 695 break; 696 case POT_CONFUSION: 697 if(!Confusion) 698 if (Hallucination) { 699 pline("What a trippy feeling!"); 700 unkn++; 701 } else 702 pline("Huh, What? Where am I?"); 703 else nothing++; 704 make_confused(itimeout_incr(HConfusion, 705 rn1(7, 16 - 8 * bcsign(otmp))), 706 FALSE); 707 break; 708 case POT_GAIN_ABILITY: 709 if(otmp->cursed) { 710 pline("Ulch! That potion tasted foul!"); 711 unkn++; 712 } else if (Fixed_abil) { 713 nothing++; 714 } else { /* If blessed, increase all; if not, try up to */ 715 int itmp; /* 6 times to find one which can be increased. */ 716 i = -1; /* increment to 0 */ 717 for (ii = A_MAX; ii > 0; ii--) { 718 i = (otmp->blessed ? i + 1 : rn2(A_MAX)); 719 /* only give "your X is already as high as it can get" 720 message on last attempt (except blessed potions) */ 721 itmp = (otmp->blessed || ii == 1) ? 0 : -1; 722 if (adjattrib(i, 1, itmp) && !otmp->blessed) 723 break; 724 } 725 } 726 break; 727 case POT_SPEED: 728 if(Wounded_legs && !otmp->cursed 729#ifdef STEED 730 && !u.usteed /* heal_legs() would heal steeds legs */ 731#endif 732 ) { 733 heal_legs(); 734 unkn++; 735 break; 736 } /* and fall through */ 737 case SPE_HASTE_SELF: 738 if(!Very_fast) /* wwf@doe.carleton.ca */ 739 You("are suddenly moving %sfaster.", 740 Fast ? "" : "much "); 741 else { 742 Your("%s get new energy.", 743 makeplural(body_part(LEG))); 744 unkn++; 745 } 746 exercise(A_DEX, TRUE); 747 incr_itimeout(&HFast, rn1(10, 100 + 60 * bcsign(otmp))); 748 break; 749 case POT_BLINDNESS: 750 if(Blind) nothing++; 751 make_blinded(itimeout_incr(Blinded, 752 rn1(200, 250 - 125 * bcsign(otmp))), 753 (boolean)!Blind); 754 break; 755 case POT_GAIN_LEVEL: 756 if (otmp->cursed) { 757 unkn++; 758 /* they went up a level */ 759 if((ledger_no(&u.uz) == 1 && u.uhave.amulet) || 760 Can_rise_up(u.ux, u.uy, &u.uz)) { 761 const char *riseup ="rise up, through the %s!"; 762 if(ledger_no(&u.uz) == 1) { 763 You(riseup, ceiling(u.ux,u.uy)); 764 goto_level(&earth_level, FALSE, FALSE, FALSE); 765 } else { 766 register int newlev = depth(&u.uz)-1; 767 d_level newlevel; 768 769 get_level(&newlevel, newlev); 770 if(on_level(&newlevel, &u.uz)) { 771 pline("It tasted bad."); 772 break; 773 } else You(riseup, ceiling(u.ux,u.uy)); 774 goto_level(&newlevel, FALSE, FALSE, FALSE); 775 } 776 } 777 else You("have an uneasy feeling."); 778 break; 779 } 780 pluslvl(FALSE); 781 if (otmp->blessed) 782 /* blessed potions place you at a random spot in the 783 * middle of the new level instead of the low point 784 */ 785 u.uexp = rndexp(TRUE); 786 break; 787 case POT_HEALING: 788 You_feel("better."); 789 healup(d(6 + 2 * bcsign(otmp), 4), 790 !otmp->cursed ? 1 : 0, !!otmp->blessed, !otmp->cursed); 791 exercise(A_CON, TRUE); 792 break; 793 case POT_EXTRA_HEALING: 794 You_feel("much better."); 795 healup(d(6 + 2 * bcsign(otmp), 8), 796 otmp->blessed ? 5 : !otmp->cursed ? 2 : 0, 797 !otmp->cursed, TRUE); 798 (void) make_hallucinated(0L,TRUE,0L); 799 exercise(A_CON, TRUE); 800 exercise(A_STR, TRUE); 801 break; 802 case POT_FULL_HEALING: 803 You_feel("completely healed."); 804 healup(400, 4+4*bcsign(otmp), !otmp->cursed, TRUE); 805 /* Restore one lost level if blessed */ 806 if (otmp->blessed && u.ulevel < u.ulevelmax) { 807 /* when multiple levels have been lost, drinking 808 multiple potions will only get half of them back */ 809 u.ulevelmax -= 1; 810 pluslvl(FALSE); 811 } 812 (void) make_hallucinated(0L,TRUE,0L); 813 exercise(A_STR, TRUE); 814 exercise(A_CON, TRUE); 815 break; 816 case POT_LEVITATION: 817 case SPE_LEVITATION: 818 if (otmp->cursed) HLevitation &= ~I_SPECIAL; 819 if(!Levitation) { 820 /* kludge to ensure proper operation of float_up() */ 821 HLevitation = 1; 822 float_up(); 823 /* reverse kludge */ 824 HLevitation = 0; 825 if (otmp->cursed && !Is_waterlevel(&u.uz)) { 826 if((u.ux != xupstair || u.uy != yupstair) 827 && (u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up) 828 && (!xupladder || u.ux != xupladder || u.uy != yupladder) 829 ) { 830 You("hit your %s on the %s.", 831 body_part(HEAD), 832 ceiling(u.ux,u.uy)); 833 losehp(uarmh ? 1 : rnd(10), 834 "colliding with the ceiling", 835 KILLED_BY); 836 } else (void) doup(); 837 } 838 } else 839 nothing++; 840 if (otmp->blessed) { 841 incr_itimeout(&HLevitation, rn1(50,250)); 842 HLevitation |= I_SPECIAL; 843 } else incr_itimeout(&HLevitation, rn1(140,10)); 844 spoteffects(FALSE); /* for sinks */ 845 break; 846 case POT_GAIN_ENERGY: /* M. Stephenson */ 847 { register int num; 848 if(otmp->cursed) 849 You_feel("lackluster."); 850 else 851 pline("Magical energies course through your body."); 852 num = rnd(5) + 5 * otmp->blessed + 1; 853 u.uenmax += (otmp->cursed) ? -num : num; 854 u.uen += (otmp->cursed) ? -num : num; 855 if(u.uenmax <= 0) u.uenmax = 0; 856 if(u.uen <= 0) u.uen = 0; 857 flags.botl = 1; 858 exercise(A_WIS, TRUE); 859 } 860 break; 861 case POT_OIL: /* P. Winner */ 862 { 863 boolean good_for_you = FALSE; 864 865 if (otmp->lamplit) { 866 if (likes_fire(youmonst.data)) { 867 pline("Ahh, a refreshing drink."); 868 good_for_you = TRUE; 869 } else { 870 You("burn your %s.", body_part(FACE)); 871 losehp(d(Fire_resistance ? 1 : 3, 4), 872 "burning potion of oil", KILLED_BY_AN); 873 } 874 } else if(otmp->cursed) 875 pline("This tastes like castor oil."); 876 else 877 pline("That was smooth!"); 878 exercise(A_WIS, good_for_you); 879 } 880 break; 881 case POT_ACID: 882 if (Acid_resistance) 883 /* Not necessarily a creature who _likes_ acid */ 884 pline("This tastes %s.", Hallucination ? "tangy" : "sour"); 885 else { 886 pline("This burns%s!", otmp->blessed ? " a little" : 887 otmp->cursed ? " a lot" : " like acid"); 888 losehp(d(otmp->cursed ? 2 : 1, otmp->blessed ? 4 : 8), 889 "potion of acid", KILLED_BY_AN); 890 exercise(A_CON, FALSE); 891 } 892 if (Stoned) fix_petrification(); 893 unkn++; /* holy/unholy water can burn like acid too */ 894 break; 895 case POT_POLYMORPH: 896 You_feel("a little %s.", Hallucination ? "normal" : "strange"); 897 if (!Unchanging) polyself(FALSE); 898 break; 899 default: 900 impossible("What a funny potion! (%u)", otmp->otyp); 901 return(0); 902 } 903 return(-1); 904} 905 906void 907healup(nhp, nxtra, curesick, cureblind) 908 int nhp, nxtra; 909 register boolean curesick, cureblind; 910{ 911 if (nhp) { 912 if (Upolyd) { 913 u.mh += nhp; 914 if (u.mh > u.mhmax) u.mh = (u.mhmax += nxtra); 915 } else { 916 u.uhp += nhp; 917 if(u.uhp > u.uhpmax) u.uhp = (u.uhpmax += nxtra); 918 } 919 } 920 if(cureblind) make_blinded(0L,TRUE); 921 if(curesick) make_sick(0L, (char *) 0, TRUE, SICK_ALL); 922 flags.botl = 1; 923 return; 924} 925 926void 927strange_feeling(obj,txt) 928register struct obj *obj; 929register const char *txt; 930{ 931 if (flags.beginner || !txt) 932 You("have a %s feeling for a moment, then it passes.", 933 Hallucination ? "normal" : "strange"); 934 else 935 pline(txt); 936 937 if(!obj) /* e.g., crystal ball finds no traps */ 938 return; 939 940 if(obj->dknown && !objects[obj->otyp].oc_name_known && 941 !objects[obj->otyp].oc_uname) 942 docall(obj); 943 useup(obj); 944} 945 946const char *bottlenames[] = { 947 "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial" 948}; 949 950 951const char * 952bottlename() 953{ 954 return bottlenames[rn2(SIZE(bottlenames))]; 955} 956 957void 958potionhit(mon, obj, your_fault) 959register struct monst *mon; 960register struct obj *obj; 961boolean your_fault; 962{ 963 register const char *botlnam = bottlename(); 964 boolean isyou = (mon == &youmonst); 965 int distance; 966 967 if(isyou) { 968 distance = 0; 969 pline_The("%s crashes on your %s and breaks into shards.", 970 botlnam, body_part(HEAD)); 971 losehp(rnd(2), "thrown potion", KILLED_BY_AN); 972 } else { 973 distance = distu(mon->mx,mon->my); 974 if (!cansee(mon->mx,mon->my)) pline("Crash!"); 975 else { 976 char *mnam = mon_nam(mon); 977 char buf[BUFSZ]; 978 979 if(has_head(mon->data)) { 980 Sprintf(buf, "%s %s", 981 s_suffix(mnam), 982 (notonhead ? "body" : "head")); 983 } else { 984 Strcpy(buf, mnam); 985 } 986 pline_The("%s crashes on %s and breaks into shards.", 987 botlnam, buf); 988 } 989 if(rn2(5) && mon->mhp > 1) 990 mon->mhp--; 991 } 992 993 /* oil doesn't instantly evaporate */ 994 if (obj->otyp != POT_OIL && cansee(mon->mx,mon->my)) 995 pline("%s.", Tobjnam(obj, "evaporate")); 996 997 if (isyou) { 998 switch (obj->otyp) { 999 case POT_OIL: 1000 if (obj->lamplit) 1001 splatter_burning_oil(u.ux, u.uy); 1002 break; 1003 case POT_POLYMORPH: 1004 You_feel("a little %s.", Hallucination ? "normal" : "strange"); 1005 if (!Unchanging && !Antimagic) polyself(FALSE); 1006 break; 1007 case POT_ACID: 1008 if (!Acid_resistance) { 1009 pline("This burns%s!", obj->blessed ? " a little" : 1010 obj->cursed ? " a lot" : ""); 1011 losehp(d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8), 1012 "potion of acid", KILLED_BY_AN); 1013 } 1014 break; 1015 } 1016 } else { 1017 boolean angermon = TRUE; 1018 1019 if (!your_fault) angermon = FALSE; 1020 switch (obj->otyp) { 1021 case POT_HEALING: 1022 case POT_EXTRA_HEALING: 1023 case POT_FULL_HEALING: 1024 if (mon->data == &mons[PM_PESTILENCE]) goto do_illness; 1025 /*FALLTHRU*/ 1026 case POT_RESTORE_ABILITY: 1027 case POT_GAIN_ABILITY: 1028 do_healing: 1029 angermon = FALSE; 1030 if(mon->mhp < mon->mhpmax) { 1031 mon->mhp = mon->mhpmax; 1032 if (canseemon(mon)) 1033 pline("%s looks sound and hale again.", Monnam(mon)); 1034 } 1035 break; 1036 case POT_SICKNESS: 1037 if (mon->data == &mons[PM_PESTILENCE]) goto do_healing; 1038 if (dmgtype(mon->data, AD_DISE) || 1039 dmgtype(mon->data, AD_PEST) || /* won't happen, see prior goto */ 1040 resists_poison(mon)) { 1041 if (canseemon(mon)) 1042 pline("%s looks unharmed.", Monnam(mon)); 1043 break; 1044 } 1045 do_illness: 1046 if((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL)) 1047 mon->mhpmax /= 2; 1048 if((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL)) 1049 mon->mhp /= 2; 1050 if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; 1051 if (canseemon(mon)) 1052 pline("%s looks rather ill.", Monnam(mon)); 1053 break; 1054 case POT_CONFUSION: 1055 case POT_BOOZE: 1056 if(!resist(mon, POTION_CLASS, 0, NOTELL)) mon->mconf = TRUE; 1057 break; 1058 case POT_INVISIBILITY: 1059 angermon = FALSE; 1060 mon_set_minvis(mon); 1061 break; 1062 case POT_SLEEPING: 1063 /* wakeup() doesn't rouse victims of temporary sleep */ 1064 if (sleep_monst(mon, rnd(12), POTION_CLASS)) { 1065 pline("%s falls asleep.", Monnam(mon)); 1066 slept_monst(mon); 1067 } 1068 break; 1069 case POT_PARALYSIS: 1070 if (mon->mcanmove) { 1071 mon->mcanmove = 0; 1072 /* really should be rnd(5) for consistency with players 1073 * breathing potions, but... 1074 */ 1075 mon->mfrozen = rnd(25); 1076 } 1077 break; 1078 case POT_SPEED: 1079 angermon = FALSE; 1080 mon_adjust_speed(mon, 1, obj); 1081 break; 1082 case POT_BLINDNESS: 1083 if(haseyes(mon->data)) { 1084 register int btmp = 64 + rn2(32) + 1085 rn2(32) * !resist(mon, POTION_CLASS, 0, NOTELL); 1086 btmp += mon->mblinded; 1087 mon->mblinded = min(btmp,127); 1088 mon->mcansee = 0; 1089 } 1090 break; 1091 case POT_WATER: 1092 if (is_undead(mon->data) || is_demon(mon->data) || 1093 is_were(mon->data)) { 1094 if (obj->blessed) { 1095 pline("%s %s in pain!", Monnam(mon), 1096 is_silent(mon->data) ? "writhes" : "shrieks"); 1097 mon->mhp -= d(2,6); 1098 /* should only be by you */ 1099 if (mon->mhp < 1) killed(mon); 1100 else if (is_were(mon->data) && !is_human(mon->data)) 1101 new_were(mon); /* revert to human */ 1102 } else if (obj->cursed) { 1103 angermon = FALSE; 1104 if (canseemon(mon)) 1105 pline("%s looks healthier.", Monnam(mon)); 1106 mon->mhp += d(2,6); 1107 if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; 1108 if (is_were(mon->data) && is_human(mon->data) && 1109 !Protection_from_shape_changers) 1110 new_were(mon); /* transform into beast */ 1111 } 1112 } else if(mon->data == &mons[PM_GREMLIN]) { 1113 angermon = FALSE; 1114 (void)split_mon(mon, (struct monst *)0); 1115 } else if(mon->data == &mons[PM_IRON_GOLEM]) { 1116 if (canseemon(mon)) 1117 pline("%s rusts.", Monnam(mon)); 1118 mon->mhp -= d(1,6); 1119 /* should only be by you */ 1120 if (mon->mhp < 1) killed(mon); 1121 } 1122 break; 1123 case POT_OIL: 1124 if (obj->lamplit) 1125 splatter_burning_oil(mon->mx, mon->my); 1126 break; 1127 case POT_ACID: 1128 if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) { 1129 pline("%s %s in pain!", Monnam(mon), 1130 is_silent(mon->data) ? "writhes" : "shrieks"); 1131 mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); 1132 if (mon->mhp < 1) { 1133 if (your_fault) 1134 killed(mon); 1135 else 1136 monkilled(mon, "", AD_ACID); 1137 } 1138 } 1139 break; 1140 case POT_POLYMORPH: 1141 (void) bhitm(mon, obj); 1142 break; 1143/* 1144 case POT_GAIN_LEVEL: 1145 case POT_LEVITATION: 1146 case POT_FRUIT_JUICE: 1147 case POT_MONSTER_DETECTION: 1148 case POT_OBJECT_DETECTION: 1149 break; 1150*/ 1151 } 1152 if (angermon) 1153 wakeup(mon); 1154 else 1155 mon->msleeping = 0; 1156 } 1157 1158 /* Note: potionbreathe() does its own docall() */ 1159 if ((distance==0 || ((distance < 3) && rn2(5))) && 1160 (!breathless(youmonst.data) || haseyes(youmonst.data))) 1161 potionbreathe(obj); 1162 else if (obj->dknown && !objects[obj->otyp].oc_name_known && 1163 !objects[obj->otyp].oc_uname && cansee(mon->mx,mon->my)) 1164 docall(obj); 1165 if(*u.ushops && obj->unpaid) { 1166 register struct monst *shkp = 1167 shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); 1168 1169 if(!shkp) 1170 obj->unpaid = 0; 1171 else { 1172 (void)stolen_value(obj, u.ux, u.uy, 1173 (boolean)shkp->mpeaceful, FALSE); 1174 subfrombill(obj, shkp); 1175 } 1176 } 1177 obfree(obj, (struct obj *)0); 1178} 1179 1180/* vapors are inhaled or get in your eyes */ 1181void 1182potionbreathe(obj) 1183register struct obj *obj; 1184{ 1185 register int i, ii, isdone, kn = 0; 1186 1187 switch(obj->otyp) { 1188 case POT_RESTORE_ABILITY: 1189 case POT_GAIN_ABILITY: 1190 if(obj->cursed) { 1191 if (!breathless(youmonst.data)) 1192 pline("Ulch! That potion smells terrible!"); 1193 else if (haseyes(youmonst.data)) { 1194 int numeyes = eyecount(youmonst.data); 1195 Your("%s sting%s!", 1196 (numeyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)), 1197 (numeyes == 1) ? "s" : ""); 1198 } 1199 break; 1200 } else { 1201 i = rn2(A_MAX); /* start at a random point */ 1202 for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) { 1203 if(ABASE(i) < AMAX(i)) { 1204 ABASE(i)++; 1205 /* only first found if not blessed */ 1206 isdone = !(obj->blessed); 1207 flags.botl = 1; 1208 } 1209 if(++i >= A_MAX) i = 0; 1210 } 1211 } 1212 break; 1213 case POT_FULL_HEALING: 1214 if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; 1215 if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; 1216 /*FALL THROUGH*/ 1217 case POT_EXTRA_HEALING: 1218 if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; 1219 if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; 1220 /*FALL THROUGH*/ 1221 case POT_HEALING: 1222 if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; 1223 if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; 1224 exercise(A_CON, TRUE); 1225 break; 1226 case POT_SICKNESS: 1227 if (!Role_if(PM_HEALER)) { 1228 if (Upolyd) { 1229 if (u.mh <= 5) u.mh = 1; else u.mh -= 5; 1230 } else { 1231 if (u.uhp <= 5) u.uhp = 1; else u.uhp -= 5; 1232 } 1233 flags.botl = 1; 1234 exercise(A_CON, FALSE); 1235 } 1236 break; 1237 case POT_HALLUCINATION: 1238 You("have a momentary vision."); 1239 break; 1240 case POT_CONFUSION: 1241 case POT_BOOZE: 1242 if(!Confusion) 1243 You_feel("somewhat dizzy."); 1244 make_confused(itimeout_incr(HConfusion, rnd(5)), FALSE); 1245 break; 1246 case POT_INVISIBILITY: 1247 if (!Blind && !Invis) { 1248 kn++; 1249 pline("For an instant you %s!", 1250 See_invisible ? "could see right through yourself" 1251 : "couldn't see yourself"); 1252 } 1253 break; 1254 case POT_PARALYSIS: 1255 kn++; 1256 if (!Free_action) { 1257 pline("%s seems to be holding you.", Something); 1258 nomul(-rnd(5)); 1259 nomovemsg = You_can_move_again; 1260 exercise(A_DEX, FALSE); 1261 } else You("stiffen momentarily."); 1262 break; 1263 case POT_SLEEPING: 1264 kn++; 1265 if (!Free_action && !Sleep_resistance) { 1266 You_feel("rather tired."); 1267 nomul(-rnd(5)); 1268 nomovemsg = You_can_move_again; 1269 exercise(A_DEX, FALSE); 1270 } else You("yawn."); 1271 break; 1272 case POT_SPEED: 1273 if (!Fast) Your("knees seem more flexible now."); 1274 incr_itimeout(&HFast, rnd(5)); 1275 exercise(A_DEX, TRUE); 1276 break; 1277 case POT_BLINDNESS: 1278 if (!Blind && !u.usleep) { 1279 kn++; 1280 pline("It suddenly gets dark."); 1281 } 1282 make_blinded(itimeout_incr(Blinded, rnd(5)), FALSE); 1283 if (!Blind && !u.usleep) Your(vision_clears); 1284 break; 1285 case POT_WATER: 1286 if(u.umonnum == PM_GREMLIN) { 1287 (void)split_mon(&youmonst, (struct monst *)0); 1288 } else if (u.ulycn >= LOW_PM) { 1289 /* vapor from [un]holy water will trigger 1290 transformation but won't cure lycanthropy */ 1291 if (obj->blessed && youmonst.data == &mons[u.ulycn]) 1292 you_unwere(FALSE); 1293 else if (obj->cursed && !Upolyd) 1294 you_were(); 1295 } 1296 break; 1297 case POT_ACID: 1298 case POT_POLYMORPH: 1299 exercise(A_CON, FALSE); 1300 break; 1301/* 1302 case POT_GAIN_LEVEL: 1303 case POT_LEVITATION: 1304 case POT_FRUIT_JUICE: 1305 case POT_MONSTER_DETECTION: 1306 case POT_OBJECT_DETECTION: 1307 case POT_OIL: 1308 break; 1309*/ 1310 } 1311 /* note: no obfree() */ 1312 if (obj->dknown) { 1313 if (kn) 1314 makeknown(obj->otyp); 1315 else if (!objects[obj->otyp].oc_name_known && 1316 !objects[obj->otyp].oc_uname) 1317 docall(obj); 1318 } 1319} 1320 1321STATIC_OVL short 1322mixtype(o1, o2) 1323register struct obj *o1, *o2; 1324/* returns the potion type when o1 is dipped in o2 */ 1325{ 1326 /* cut down on the number of cases below */ 1327 if (o1->oclass == POTION_CLASS && 1328 (o2->otyp == POT_GAIN_LEVEL || 1329 o2->otyp == POT_GAIN_ENERGY || 1330 o2->otyp == POT_HEALING || 1331 o2->otyp == POT_EXTRA_HEALING || 1332 o2->otyp == POT_FULL_HEALING || 1333 o2->otyp == POT_ENLIGHTENMENT || 1334 o2->otyp == POT_FRUIT_JUICE)) { 1335 struct obj *swp; 1336 1337 swp = o1; o1 = o2; o2 = swp; 1338 } 1339 1340 switch (o1->otyp) { 1341 case POT_HEALING: 1342 switch (o2->otyp) { 1343 case POT_SPEED: 1344 case POT_GAIN_LEVEL: 1345 case POT_GAIN_ENERGY: 1346 return POT_EXTRA_HEALING; 1347 } 1348 case POT_EXTRA_HEALING: 1349 switch (o2->otyp) { 1350 case POT_GAIN_LEVEL: 1351 case POT_GAIN_ENERGY: 1352 return POT_FULL_HEALING; 1353 } 1354 case POT_FULL_HEALING: 1355 switch (o2->otyp) { 1356 case POT_GAIN_LEVEL: 1357 case POT_GAIN_ENERGY: 1358 return POT_GAIN_ABILITY; 1359 } 1360 case UNICORN_HORN: 1361 switch (o2->otyp) { 1362 case POT_SICKNESS: 1363 return POT_FRUIT_JUICE; 1364 case POT_HALLUCINATION: 1365 case POT_BLINDNESS: 1366 case POT_CONFUSION: 1367 return POT_WATER; 1368 } 1369 break; 1370 case AMETHYST: /* "a-methyst" == "not intoxicated" */ 1371 if (o2->otyp == POT_BOOZE) 1372 return POT_FRUIT_JUICE; 1373 break; 1374 case POT_GAIN_LEVEL: 1375 case POT_GAIN_ENERGY: 1376 switch (o2->otyp) { 1377 case POT_CONFUSION: 1378 return (rn2(3) ? POT_BOOZE : POT_ENLIGHTENMENT); 1379 case POT_HEALING: 1380 return POT_EXTRA_HEALING; 1381 case POT_EXTRA_HEALING: 1382 return POT_FULL_HEALING; 1383 case POT_FULL_HEALING: 1384 return POT_GAIN_ABILITY; 1385 case POT_FRUIT_JUICE: 1386 return POT_SEE_INVISIBLE; 1387 case POT_BOOZE: 1388 return POT_HALLUCINATION; 1389 } 1390 break; 1391 case POT_FRUIT_JUICE: 1392 switch (o2->otyp) { 1393 case POT_SICKNESS: 1394 return POT_SICKNESS; 1395 case POT_SPEED: 1396 return POT_BOOZE; 1397 case POT_GAIN_LEVEL: 1398 case POT_GAIN_ENERGY: 1399 return POT_SEE_INVISIBLE; 1400 } 1401 break; 1402 case POT_ENLIGHTENMENT: 1403 switch (o2->otyp) { 1404 case POT_LEVITATION: 1405 if (rn2(3)) return POT_GAIN_LEVEL; 1406 break; 1407 case POT_FRUIT_JUICE: 1408 return POT_BOOZE; 1409 case POT_BOOZE: 1410 return POT_CONFUSION; 1411 } 1412 break; 1413 } 1414 1415 return 0; 1416} 1417 1418 1419boolean 1420get_wet(obj) 1421register struct obj *obj; 1422/* returns TRUE if something happened (potion should be used up) */ 1423{ 1424 char Your_buf[BUFSZ]; 1425 1426 if (snuff_lit(obj)) return(TRUE); 1427 1428 if (obj->greased) { 1429 grease_protect(obj,(char *)0,&youmonst); 1430 return(FALSE); 1431 } 1432 (void) Shk_Your(Your_buf, obj); 1433 /* (Rusting shop goods ought to be charged for.) */ 1434 switch (obj->oclass) { 1435 case POTION_CLASS: 1436 if (obj->otyp == POT_WATER) return FALSE; 1437 /* KMH -- Water into acid causes an explosion */ 1438 if (obj->otyp == POT_ACID) { 1439 pline("It boils vigorously!"); 1440 You("are caught in the explosion!"); 1441 losehp(rnd(10), "elementary chemistry", KILLED_BY); 1442 makeknown(obj->otyp); 1443 update_inventory(); 1444 return (TRUE); 1445 } 1446 pline("%s %s%s.", Your_buf, aobjnam(obj,"dilute"), 1447 obj->odiluted ? " further" : ""); 1448 if(obj->unpaid && costly_spot(u.ux, u.uy)) { 1449 You("dilute it, you pay for it."); 1450 bill_dummy_object(obj); 1451 } 1452 if (obj->odiluted) { 1453 obj->odiluted = 0; 1454#ifdef UNIXPC 1455 obj->blessed = FALSE; 1456 obj->cursed = FALSE; 1457#else 1458 obj->blessed = obj->cursed = FALSE; 1459#endif 1460 obj->otyp = POT_WATER; 1461 } else obj->odiluted++; 1462 update_inventory(); 1463 return TRUE; 1464 case SCROLL_CLASS: 1465 if (obj->otyp != SCR_BLANK_PAPER 1466#ifdef MAIL 1467 && obj->otyp != SCR_MAIL 1468#endif 1469 ) { 1470 if (!Blind) { 1471 boolean oq1 = obj->quan == 1L; 1472 pline_The("scroll%s %s.", 1473 oq1 ? "" : "s", otense(obj, "fade")); 1474 } 1475 if(obj->unpaid && costly_spot(u.ux, u.uy)) { 1476 You("erase it, you pay for it."); 1477 bill_dummy_object(obj); 1478 } 1479 obj->otyp = SCR_BLANK_PAPER; 1480 obj->spe = 0; 1481 update_inventory(); 1482 return TRUE; 1483 } else break; 1484 case SPBOOK_CLASS: 1485 if (obj->otyp != SPE_BLANK_PAPER) { 1486 1487 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 1488 pline("%s suddenly heats up; steam rises and it remains dry.", 1489 The(xname(obj))); 1490 } else { 1491 if (!Blind) { 1492 boolean oq1 = obj->quan == 1L; 1493 pline_The("spellbook%s %s.", 1494 oq1 ? "" : "s", otense(obj, "fade")); 1495 } 1496 if(obj->unpaid && costly_spot(u.ux, u.uy)) { 1497 You("erase it, you pay for it."); 1498 bill_dummy_object(obj); 1499 } 1500 obj->otyp = SPE_BLANK_PAPER; 1501 update_inventory(); 1502 } 1503 return TRUE; 1504 } 1505 break; 1506 case WEAPON_CLASS: 1507 /* Just "fall through" to generic rustprone check for now. */ 1508 /* fall through */ 1509 default: 1510 if (!obj->oerodeproof && is_rustprone(obj) && 1511 (obj->oeroded < MAX_ERODE) && !rn2(2)) { 1512 pline("%s %s some%s.", 1513 Your_buf, aobjnam(obj, "rust"), 1514 obj->oeroded ? " more" : "what"); 1515 obj->oeroded++; 1516 update_inventory(); 1517 return TRUE; 1518 } else break; 1519 } 1520 pline("%s %s wet.", Your_buf, aobjnam(obj,"get")); 1521 return FALSE; 1522} 1523 1524int 1525dodip() 1526{ 1527 register struct obj *potion, *obj; 1528 struct obj *singlepotion; 1529 const char *tmp; 1530 uchar here; 1531 char allowall[2]; 1532 short mixture; 1533 char qbuf[QBUFSZ], Your_buf[BUFSZ]; 1534 1535 allowall[0] = ALL_CLASSES; allowall[1] = '\0'; 1536 if(!(obj = getobj(allowall, "dip"))) 1537 return(0); 1538 1539 here = levl[u.ux][u.uy].typ; 1540 /* Is there a fountain to dip into here? */ 1541 if (IS_FOUNTAIN(here)) { 1542 if(yn("Dip it into the fountain?") == 'y') { 1543 dipfountain(obj); 1544 return(1); 1545 } 1546 } else if (is_pool(u.ux,u.uy)) { 1547 tmp = waterbody_name(u.ux,u.uy); 1548 Sprintf(qbuf, "Dip it into the %s?", tmp); 1549 if (yn(qbuf) == 'y') { 1550 if (Levitation) { 1551 floating_above(tmp); 1552#ifdef STEED 1553 } else if (u.usteed && !is_swimmer(u.usteed->data) && 1554 P_SKILL(P_RIDING) < P_BASIC) { 1555 rider_cant_reach(); /* not skilled enough to reach */ 1556#endif 1557 } else { 1558 (void) get_wet(obj); 1559 if (obj->otyp == POT_ACID) useup(obj); 1560 } 1561 return 1; 1562 } 1563 } 1564 1565 if(!(potion = getobj(beverages, "dip into"))) 1566 return(0); 1567 if (potion == obj && potion->quan == 1L) { 1568 pline("That is a potion bottle, not a Klein bottle!"); 1569 return 0; 1570 } 1571 potion->in_use = TRUE; /* assume it will be used up */ 1572 if(potion->otyp == POT_WATER) { 1573 boolean useeit = !Blind; 1574 if (useeit) (void) Shk_Your(Your_buf, obj); 1575 if (potion->blessed) { 1576 if (obj->cursed) { 1577 if (useeit) 1578 pline("%s %s %s.", 1579 Your_buf, 1580 aobjnam(obj, "softly glow"), 1581 hcolor(NH_AMBER)); 1582 uncurse(obj); 1583 obj->bknown=1; 1584 poof: 1585 if(!(objects[potion->otyp].oc_name_known) && 1586 !(objects[potion->otyp].oc_uname)) 1587 docall(potion); 1588 useup(potion); 1589 return(1); 1590 } else if(!obj->blessed) { 1591 if (useeit) { 1592 tmp = hcolor(NH_LIGHT_BLUE); 1593 pline("%s %s with a%s %s aura.", 1594 Your_buf, 1595 aobjnam(obj, "softly glow"), 1596 index(vowels, *tmp) ? "n" : "", tmp); 1597 } 1598 bless(obj); 1599 obj->bknown=1; 1600 goto poof; 1601 } 1602 } else if (potion->cursed) { 1603 if (obj->blessed) { 1604 if (useeit) 1605 pline("%s %s %s.", 1606 Your_buf, 1607 aobjnam(obj, "glow"), 1608 hcolor((const char *)"brown")); 1609 unbless(obj); 1610 obj->bknown=1; 1611 goto poof; 1612 } else if(!obj->cursed) { 1613 if (useeit) { 1614 tmp = hcolor(NH_BLACK); 1615 pline("%s %s with a%s %s aura.", 1616 Your_buf, 1617 aobjnam(obj, "glow"), 1618 index(vowels, *tmp) ? "n" : "", tmp); 1619 } 1620 curse(obj); 1621 obj->bknown=1; 1622 goto poof; 1623 } 1624 } else 1625 if (get_wet(obj)) 1626 goto poof; 1627 } else if (obj->otyp == POT_POLYMORPH || 1628 potion->otyp == POT_POLYMORPH) { 1629 /* some objects can't be polymorphed */ 1630 if (obj->otyp == potion->otyp || /* both POT_POLY */ 1631 obj->otyp == WAN_POLYMORPH || 1632 obj->otyp == SPE_POLYMORPH || 1633 obj == uball || obj == uskin || 1634 obj_resists(obj->otyp == POT_POLYMORPH ? 1635 potion : obj, 5, 95)) { 1636 pline(nothing_happens); 1637 } else { 1638 boolean was_wep = FALSE, was_swapwep = FALSE, was_quiver = FALSE; 1639 short save_otyp = obj->otyp; 1640 /* KMH, conduct */ 1641 u.uconduct.polypiles++; 1642 1643 if (obj == uwep) was_wep = TRUE; 1644 else if (obj == uswapwep) was_swapwep = TRUE; 1645 else if (obj == uquiver) was_quiver = TRUE; 1646 1647 obj = poly_obj(obj, STRANGE_OBJECT); 1648 1649 if (was_wep) setuwep(obj); 1650 else if (was_swapwep) setuswapwep(obj); 1651 else if (was_quiver) setuqwep(obj); 1652 1653 if (obj->otyp != save_otyp) { 1654 makeknown(POT_POLYMORPH); 1655 useup(potion); 1656 prinv((char *)0, obj, 0L); 1657 return 1; 1658 } else { 1659 pline("Nothing seems to happen."); 1660 goto poof; 1661 } 1662 } 1663 potion->in_use = FALSE; /* didn't go poof */ 1664 return(1); 1665 } else if(obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) { 1666 /* Mixing potions is dangerous... */ 1667 pline_The("potions mix..."); 1668 /* KMH, balance patch -- acid is particularly unstable */ 1669 if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) { 1670 pline("BOOM! They explode!"); 1671 exercise(A_STR, FALSE); 1672 if (!breathless(youmonst.data) || haseyes(youmonst.data)) 1673 potionbreathe(obj); 1674 useup(obj); 1675 useup(potion); 1676 losehp(rnd(10), "alchemic blast", KILLED_BY_AN); 1677 return(1); 1678 } 1679 1680 obj->blessed = obj->cursed = obj->bknown = 0; 1681 if (Blind || Hallucination) obj->dknown = 0; 1682 1683 if ((mixture = mixtype(obj, potion)) != 0) { 1684 obj->otyp = mixture; 1685 } else { 1686 switch (obj->odiluted ? 1 : rnd(8)) { 1687 case 1: 1688 obj->otyp = POT_WATER; 1689 break; 1690 case 2: 1691 case 3: 1692 obj->otyp = POT_SICKNESS; 1693 break; 1694 case 4: 1695 { 1696 struct obj *otmp; 1697 otmp = mkobj(POTION_CLASS,FALSE); 1698 obj->otyp = otmp->otyp; 1699 obfree(otmp, (struct obj *)0); 1700 } 1701 break; 1702 default: 1703 if (!Blind) 1704 pline_The("mixture glows brightly and evaporates."); 1705 useup(obj); 1706 useup(potion); 1707 return(1); 1708 } 1709 } 1710 1711 obj->odiluted = (obj->otyp != POT_WATER); 1712 1713 if (obj->otyp == POT_WATER && !Hallucination) { 1714 pline_The("mixture bubbles%s.", 1715 Blind ? "" : ", then clears"); 1716 } else if (!Blind) { 1717 pline_The("mixture looks %s.", 1718 hcolor(OBJ_DESCR(objects[obj->otyp]))); 1719 } 1720 1721 useup(potion); 1722 return(1); 1723 } 1724 1725#ifdef INVISIBLE_OBJECTS 1726 if (potion->otyp == POT_INVISIBILITY && !obj->oinvis) { 1727 obj->oinvis = TRUE; 1728 if (!Blind) { 1729 if (!See_invisible) pline("Where did %s go?", 1730 the(xname(obj))); 1731 else You("notice a little haziness around %s.", 1732 the(xname(obj))); 1733 } 1734 goto poof; 1735 } else if (potion->otyp == POT_SEE_INVISIBLE && obj->oinvis) { 1736 obj->oinvis = FALSE; 1737 if (!Blind) { 1738 if (!See_invisible) pline("So that's where %s went!", 1739 the(xname(obj))); 1740 else pline_The("haziness around %s disappears.", 1741 the(xname(obj))); 1742 } 1743 goto poof; 1744 } 1745#endif 1746 1747 if(is_poisonable(obj)) { 1748 if(potion->otyp == POT_SICKNESS && !obj->opoisoned) { 1749 char buf[BUFSZ]; 1750 if (potion->quan > 1L) 1751 Sprintf(buf, "One of %s", the(xname(potion))); 1752 else 1753 Strcpy(buf, The(xname(potion))); 1754 pline("%s forms a coating on %s.", 1755 buf, the(xname(obj))); 1756 obj->opoisoned = TRUE; 1757 goto poof; 1758 } else if(obj->opoisoned && 1759 (potion->otyp == POT_HEALING || 1760 potion->otyp == POT_EXTRA_HEALING || 1761 potion->otyp == POT_FULL_HEALING)) { 1762 pline("A coating wears off %s.", the(xname(obj))); 1763 obj->opoisoned = 0; 1764 goto poof; 1765 } 1766 } 1767 1768 if (potion->otyp == POT_OIL) { 1769 boolean wisx = FALSE; 1770 if (potion->lamplit) { /* burning */ 1771 int omat = objects[obj->otyp].oc_material; 1772 /* the code here should be merged with fire_damage */ 1773 if (catch_lit(obj)) { 1774 /* catch_lit does all the work if true */ 1775 } else if (obj->oerodeproof || obj_resists(obj, 5, 95) || 1776 !is_flammable(obj) || obj->oclass == FOOD_CLASS) { 1777 pline("%s %s to burn for a moment.", 1778 Yname2(obj), otense(obj, "seem")); 1779 } else { 1780 if ((omat == PLASTIC || omat == PAPER) && !obj->oartifact) 1781 obj->oeroded = MAX_ERODE; 1782 pline_The("burning oil %s %s.", 1783 obj->oeroded == MAX_ERODE ? "destroys" : "damages", 1784 yname(obj)); 1785 if (obj->oeroded == MAX_ERODE) { 1786 obj_extract_self(obj); 1787 obfree(obj, (struct obj *)0); 1788 obj = (struct obj *) 0; 1789 } else { 1790 /* we know it's carried */ 1791 if (obj->unpaid) { 1792 /* create a dummy duplicate to put on bill */ 1793 verbalize("You burnt it, you bought it!"); 1794 bill_dummy_object(obj); 1795 } 1796 obj->oeroded++; 1797 } 1798 } 1799 } else if (potion->cursed) { 1800 pline_The("potion spills and covers your %s with oil.", 1801 makeplural(body_part(FINGER))); 1802 incr_itimeout(&Glib, d(2,10)); 1803 } else if (obj->oclass != WEAPON_CLASS && !is_weptool(obj)) { 1804 /* the following cases apply only to weapons */ 1805 goto more_dips; 1806 /* Oil removes rust and corrosion, but doesn't unburn. 1807 * Arrows, etc are classed as metallic due to arrowhead 1808 * material, but dipping in oil shouldn't repair them. 1809 */ 1810 } else if ((!is_rustprone(obj) && !is_corrodeable(obj)) || 1811 is_ammo(obj) || (!obj->oeroded && !obj->oeroded2)) { 1812 /* uses up potion, doesn't set obj->greased */ 1813 pline("%s %s with an oily sheen.", 1814 Yname2(obj), otense(obj, "gleam")); 1815 } else { 1816 pline("%s %s less %s.", 1817 Yname2(obj), otense(obj, "are"), 1818 (obj->oeroded && obj->oeroded2) ? "corroded and rusty" : 1819 obj->oeroded ? "rusty" : "corroded"); 1820 if (obj->oeroded > 0) obj->oeroded--; 1821 if (obj->oeroded2 > 0) obj->oeroded2--; 1822 wisx = TRUE; 1823 } 1824 exercise(A_WIS, wisx); 1825 makeknown(potion->otyp); 1826 useup(potion); 1827 return 1; 1828 } 1829 more_dips: 1830 1831 /* Allow filling of MAGIC_LAMPs to prevent identification by player */ 1832 if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP) && 1833 (potion->otyp == POT_OIL)) { 1834 /* Turn off engine before fueling, turn off fuel too :-) */ 1835 if (obj->lamplit || potion->lamplit) { 1836 useup(potion); 1837 explode(u.ux, u.uy, 11, d(6,6), 0, EXPL_FIERY); 1838 exercise(A_WIS, FALSE); 1839 return 1; 1840 } 1841 /* Adding oil to an empty magic lamp renders it into an oil lamp */ 1842 if ((obj->otyp == MAGIC_LAMP) && obj->spe == 0) { 1843 obj->otyp = OIL_LAMP; 1844 obj->age = 0; 1845 } 1846 if (obj->age > 1000L) { 1847 pline("%s %s full.", Yname2(obj), otense(obj, "are")); 1848 potion->in_use = FALSE; /* didn't go poof */ 1849 } else { 1850 You("fill %s with oil.", yname(obj)); 1851 check_unpaid(potion); /* Yendorian Fuel Tax */ 1852 obj->age += 2*potion->age; /* burns more efficiently */ 1853 if (obj->age > 1500L) obj->age = 1500L; 1854 useup(potion); 1855 exercise(A_WIS, TRUE); 1856 } 1857 makeknown(POT_OIL); 1858 obj->spe = 1; 1859 update_inventory(); 1860 return 1; 1861 } 1862 1863 potion->in_use = FALSE; /* didn't go poof */ 1864 if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) && 1865 (mixture = mixtype(obj, potion)) != 0) { 1866 char oldbuf[BUFSZ], newbuf[BUFSZ]; 1867 short old_otyp = potion->otyp; 1868 boolean old_dknown = FALSE; 1869 boolean more_than_one = potion->quan > 1; 1870 1871 oldbuf[0] = '\0'; 1872 if (potion->dknown) { 1873 old_dknown = TRUE; 1874 Sprintf(oldbuf, "%s ", 1875 hcolor(OBJ_DESCR(objects[potion->otyp]))); 1876 } 1877 /* with multiple merged potions, split off one and 1878 just clear it */ 1879 if (potion->quan > 1L) { 1880 singlepotion = splitobj(potion, 1L); 1881 } else singlepotion = potion; 1882 1883 if(singlepotion->unpaid && costly_spot(u.ux, u.uy)) { 1884 You("use it, you pay for it."); 1885 bill_dummy_object(singlepotion); 1886 } 1887 singlepotion->otyp = mixture; 1888 singlepotion->blessed = 0; 1889 if (mixture == POT_WATER) 1890 singlepotion->cursed = singlepotion->odiluted = 0; 1891 else 1892 singlepotion->cursed = obj->cursed; /* odiluted left as-is */ 1893 singlepotion->bknown = FALSE; 1894 if (Blind) { 1895 singlepotion->dknown = FALSE; 1896 } else { 1897 singlepotion->dknown = !Hallucination; 1898 if (mixture == POT_WATER && singlepotion->dknown) 1899 Sprintf(newbuf, "clears"); 1900 else 1901 Sprintf(newbuf, "turns %s", 1902 hcolor(OBJ_DESCR(objects[mixture]))); 1903 pline_The("%spotion%s %s.", oldbuf, 1904 more_than_one ? " that you dipped into" : "", 1905 newbuf); 1906 if(!objects[old_otyp].oc_uname && 1907 !objects[old_otyp].oc_name_known && old_dknown) { 1908 struct obj fakeobj; 1909 fakeobj = zeroobj; 1910 fakeobj.dknown = 1; 1911 fakeobj.otyp = old_otyp; 1912 fakeobj.oclass = POTION_CLASS; 1913 docall(&fakeobj); 1914 } 1915 } 1916 obj_extract_self(singlepotion); 1917 singlepotion = hold_another_object(singlepotion, 1918 "You juggle and drop %s!", 1919 doname(singlepotion), (const char *)0); 1920 update_inventory(); 1921 return(1); 1922 } 1923 1924 pline("Interesting..."); 1925 return(1); 1926} 1927 1928 1929void 1930djinni_from_bottle(obj) 1931register struct obj *obj; 1932{ 1933 struct monst *mtmp; 1934 int chance; 1935 1936 if(!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))){ 1937 pline("It turns out to be empty."); 1938 return; 1939 } 1940 1941 if (!Blind) { 1942 pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); 1943 pline("%s speaks.", Monnam(mtmp)); 1944 } else { 1945 You("smell acrid fumes."); 1946 pline("%s speaks.", Something); 1947 } 1948 1949 chance = rn2(5); 1950 if (obj->blessed) chance = (chance == 4) ? rnd(4) : 0; 1951 else if (obj->cursed) chance = (chance == 0) ? rn2(4) : 4; 1952 /* 0,1,2,3,4: b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */ 1953 1954 switch (chance) { 1955 case 0 : verbalize("I am in your debt. I will grant one wish!"); 1956 makewish(); 1957 mongone(mtmp); 1958 break; 1959 case 1 : verbalize("Thank you for freeing me!"); 1960 (void) tamedog(mtmp, (struct obj *)0); 1961 break; 1962 case 2 : verbalize("You freed me!"); 1963 mtmp->mpeaceful = TRUE; 1964 set_malign(mtmp); 1965 break; 1966 case 3 : verbalize("It is about time!"); 1967 pline("%s vanishes.", Monnam(mtmp)); 1968 mongone(mtmp); 1969 break; 1970 default: verbalize("You disturbed me, fool!"); 1971 break; 1972 } 1973} 1974 1975/* clone a gremlin or mold (2nd arg non-null implies heat as the trigger); 1976 hit points are cut in half (odd HP stays with original) */ 1977struct monst * 1978split_mon(mon, mtmp) 1979struct monst *mon, /* monster being split */ 1980 *mtmp; /* optional attacker whose heat triggered it */ 1981{ 1982 struct monst *mtmp2; 1983 char reason[BUFSZ]; 1984 1985 reason[0] = '\0'; 1986 if (mtmp) Sprintf(reason, " from %s heat", 1987 (mtmp == &youmonst) ? (const char *)"your" : 1988 (const char *)s_suffix(mon_nam(mtmp))); 1989 1990 if (mon == &youmonst) { 1991 mtmp2 = cloneu(); 1992 if (mtmp2) { 1993 mtmp2->mhpmax = u.mhmax / 2; 1994 u.mhmax -= mtmp2->mhpmax; 1995 flags.botl = 1; 1996 You("multiply%s!", reason); 1997 } 1998 } else { 1999 mtmp2 = clone_mon(mon, 0, 0); 2000 if (mtmp2) { 2001 mtmp2->mhpmax = mon->mhpmax / 2; 2002 mon->mhpmax -= mtmp2->mhpmax; 2003 if (canspotmon(mon)) 2004 pline("%s multiplies%s!", Monnam(mon), reason); 2005 } 2006 } 2007 return mtmp2; 2008} 2009 2010#endif /* OVLB */ 2011 2012/*potion.c*/ 2013