NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / src / potion.c
blobe5af40073ec360bfa8060e630065afa7b4d00b99
1 /* aNetHack 0.0.1 potion.c $ANH-Date: 1455407631 2016/02/13 23:53:51 $ $ANH-Branch: master $:$ANH-Revision: 1.129 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 boolean notonhead = FALSE;
9 static NEARDATA int nothing, unkn;
10 static NEARDATA const char beverages[] = { POTION_CLASS, 0 };
12 STATIC_DCL long FDECL(itimeout, (long));
13 STATIC_DCL long FDECL(itimeout_incr, (long, int));
14 STATIC_DCL void NDECL(ghost_from_bottle);
15 STATIC_DCL boolean
16 FDECL(H2Opotion_dip, (struct obj *, struct obj *, BOOLEAN_P, const char *));
17 STATIC_DCL short FDECL(mixtype, (struct obj *, struct obj *));
19 /* force `val' to be within valid range for intrinsic timeout value */
20 STATIC_OVL long
21 itimeout(val)
22 long val;
24 if (val >= TIMEOUT)
25 val = TIMEOUT;
26 else if (val < 1)
27 val = 0;
29 return val;
32 /* increment `old' by `incr' and force result to be valid intrinsic timeout */
33 STATIC_OVL long
34 itimeout_incr(old, incr)
35 long old;
36 int incr;
38 return itimeout((old & TIMEOUT) + (long) incr);
41 /* set the timeout field of intrinsic `which' */
42 void
43 set_itimeout(which, val)
44 long *which, val;
46 *which &= ~TIMEOUT;
47 *which |= itimeout(val);
50 /* increment the timeout field of intrinsic `which' */
51 void
52 incr_itimeout(which, incr)
53 long *which;
54 int incr;
56 set_itimeout(which, itimeout_incr(*which, incr));
59 void
60 make_confused(xtime, talk)
61 long xtime;
62 boolean talk;
64 long old = HConfusion;
66 if (Unaware)
67 talk = FALSE;
69 if (!xtime && old) {
70 if (talk)
71 You_feel("less %s now.", Hallucination ? "trippy" : "confused");
73 if ((xtime && !old) || (!xtime && old))
74 context.botl = TRUE;
76 set_itimeout(&HConfusion, xtime);
79 void
80 make_stunned(xtime, talk)
81 long xtime;
82 boolean talk;
84 long old = HStun;
86 if (Unaware)
87 talk = FALSE;
89 if (!xtime && old) {
90 if (talk)
91 You_feel("%s now.",
92 Hallucination ? "less wobbly" : "a bit steadier");
94 if (xtime && !old) {
95 if (talk) {
96 if (u.usteed)
97 You("wobble in the saddle.");
98 else
99 You("%s...", stagger(youmonst.data, "stagger"));
102 if ((!xtime && old) || (xtime && !old))
103 context.botl = TRUE;
105 set_itimeout(&HStun, xtime);
108 void
109 make_sick(xtime, cause, talk, type)
110 long xtime;
111 const char *cause; /* sickness cause */
112 boolean talk;
113 int type;
115 long old = Sick;
117 #if 0
118 if (Unaware)
119 talk = FALSE;
120 #endif
121 if (xtime > 0L) {
122 if (Sick_resistance)
123 return;
124 if (!old) {
125 /* newly sick */
126 You_feel("deathly sick.");
127 } else {
128 /* already sick */
129 if (talk)
130 You_feel("%s worse.", xtime <= Sick / 2L ? "much" : "even");
132 set_itimeout(&Sick, xtime);
133 u.usick_type |= type;
134 context.botl = TRUE;
135 } else if (old && (type & u.usick_type)) {
136 /* was sick, now not */
137 u.usick_type &= ~type;
138 if (u.usick_type) { /* only partly cured */
139 if (talk)
140 You_feel("somewhat better.");
141 set_itimeout(&Sick, Sick * 2); /* approximation */
142 } else {
143 if (talk)
144 You_feel("cured. What a relief!");
145 Sick = 0L; /* set_itimeout(&Sick, 0L) */
147 context.botl = TRUE;
150 if (Sick) {
151 exercise(A_CON, FALSE);
152 delayed_killer(SICK, KILLED_BY_AN, cause);
153 } else
154 dealloc_killer(find_delayed_killer(SICK));
157 void
158 make_slimed(xtime, msg)
159 long xtime;
160 const char *msg;
162 long old = Slimed;
164 #if 0
165 if (Unaware)
166 msg = 0;
167 #endif
168 set_itimeout(&Slimed, xtime);
169 if ((xtime != 0L) ^ (old != 0L)) {
170 context.botl = TRUE;
171 if (msg)
172 pline1(msg);
174 if (!Slimed)
175 dealloc_killer(find_delayed_killer(SLIMED));
178 /* start or stop petrification */
179 void
180 make_stoned(xtime, msg, killedby, killername)
181 long xtime;
182 const char *msg;
183 int killedby;
184 const char *killername;
186 long old = Stoned;
188 #if 0
189 if (Unaware)
190 msg = 0;
191 #endif
192 set_itimeout(&Stoned, xtime);
193 if ((xtime != 0L) ^ (old != 0L)) {
194 context.botl = TRUE;
195 if (msg)
196 pline1(msg);
198 if (!Stoned)
199 dealloc_killer(find_delayed_killer(STONED));
200 else if (!old)
201 delayed_killer(STONED, killedby, killername);
204 void
205 make_vomiting(xtime, talk)
206 long xtime;
207 boolean talk;
209 long old = Vomiting;
211 if (Unaware)
212 talk = FALSE;
214 set_itimeout(&Vomiting, xtime);
215 context.botl = TRUE;
216 if (!xtime && old)
217 if (talk)
218 You_feel("much less nauseated now.");
221 static const char vismsg[] = "vision seems to %s for a moment but is %s now.";
222 static const char eyemsg[] = "%s momentarily %s.";
224 void
225 make_blinded(xtime, talk)
226 long xtime;
227 boolean talk;
229 long old = Blinded;
230 boolean u_could_see, can_see_now;
231 const char *eyes;
233 /* we need to probe ahead in case the Eyes of the Overworld
234 are or will be overriding blindness */
235 u_could_see = !Blind;
236 Blinded = xtime ? 1L : 0L;
237 can_see_now = !Blind;
238 Blinded = old; /* restore */
240 if (Unaware)
241 talk = FALSE;
243 if (can_see_now && !u_could_see) { /* regaining sight */
244 if (talk) {
245 if (Hallucination)
246 pline("Far out! Everything is all cosmic again!");
247 else
248 You("can see again.");
250 } else if (old && !xtime) {
251 /* clearing temporary blindness without toggling blindness */
252 if (talk) {
253 if (!haseyes(youmonst.data)) {
254 strange_feeling((struct obj *) 0, (char *) 0);
255 } else if (Blindfolded) {
256 eyes = body_part(EYE);
257 if (eyecount(youmonst.data) != 1)
258 eyes = makeplural(eyes);
259 Your(eyemsg, eyes, vtense(eyes, "itch"));
260 } else { /* Eyes of the Overworld */
261 Your(vismsg, "brighten", Hallucination ? "sadder" : "normal");
266 if (u_could_see && !can_see_now) { /* losing sight */
267 if (talk) {
268 if (Hallucination)
269 pline("Oh, bummer! Everything is dark! Help!");
270 else
271 pline("A cloud of darkness falls upon you.");
273 /* Before the hero goes blind, set the ball&chain variables. */
274 if (Punished)
275 set_bc(0);
276 } else if (!old && xtime) {
277 /* setting temporary blindness without toggling blindness */
278 if (talk) {
279 if (!haseyes(youmonst.data)) {
280 strange_feeling((struct obj *) 0, (char *) 0);
281 } else if (Blindfolded) {
282 eyes = body_part(EYE);
283 if (eyecount(youmonst.data) != 1)
284 eyes = makeplural(eyes);
285 Your(eyemsg, eyes, vtense(eyes, "twitch"));
286 } else { /* Eyes of the Overworld */
287 Your(vismsg, "dim", Hallucination ? "happier" : "normal");
292 set_itimeout(&Blinded, xtime);
294 if (u_could_see ^ can_see_now) { /* one or the other but not both */
295 context.botl = TRUE;
296 vision_full_recalc = 1; /* blindness just got toggled */
297 /* this vision recalculation used to be deferred until
298 moveloop(), but that made it possible for vision
299 irregularities to occur (cited case was force bolt
300 hitting adjacent potion of blindness and then a
301 secret door; hero was blinded by vapors but then
302 got the message "a door appears in the wall") */
303 vision_recalc(0);
304 if (Blind_telepat || Infravision)
305 see_monsters();
307 /* avoid either of the sequences
308 "Sting starts glowing", [become blind], "Sting stops quivering" or
309 "Sting starts quivering", [regain sight], "Sting stops glowing"
310 by giving "Sting is quivering" when becoming blind or
311 "Sting is glowing" when regaining sight so that the eventual
312 "stops" message matches */
313 if (warn_obj_cnt && uwep && (EWarn_of_mon & W_WEP) != 0L)
314 Sting_effects(-1);
315 /* update dknown flag for inventory picked up while blind */
316 if (can_see_now)
317 learn_unseen_invent();
321 boolean
322 make_hallucinated(xtime, talk, mask)
323 long xtime; /* nonzero if this is an attempt to turn on hallucination */
324 boolean talk;
325 long mask; /* nonzero if resistance status should change by mask */
327 long old = HHallucination;
328 boolean changed = 0;
329 const char *message, *verb;
331 if (Unaware)
332 talk = FALSE;
334 message = (!xtime) ? "Everything %s SO boring now."
335 : "Oh wow! Everything %s so cosmic!";
336 verb = (!Blind) ? "looks" : "feels";
338 if (mask) {
339 if (HHallucination)
340 changed = TRUE;
342 if (!xtime)
343 EHalluc_resistance |= mask;
344 else
345 EHalluc_resistance &= ~mask;
346 } else {
347 if (!EHalluc_resistance && (!!HHallucination != !!xtime))
348 changed = TRUE;
349 set_itimeout(&HHallucination, xtime);
351 /* clearing temporary hallucination without toggling vision */
352 if (!changed && !HHallucination && old && talk) {
353 if (!haseyes(youmonst.data)) {
354 strange_feeling((struct obj *) 0, (char *) 0);
355 } else if (Blind) {
356 const char *eyes = body_part(EYE);
358 if (eyecount(youmonst.data) != 1)
359 eyes = makeplural(eyes);
360 Your(eyemsg, eyes, vtense(eyes, "itch"));
361 } else { /* Grayswandir */
362 Your(vismsg, "flatten", "normal");
367 if (changed) {
368 /* in case we're mimicking an orange (hallucinatory form
369 of mimicking gold) update the mimicking's-over message */
370 if (!Hallucination)
371 eatmupdate();
373 if (u.uswallow) {
374 swallowed(0); /* redraw swallow display */
375 } else {
376 /* The see_* routines should be called *before* the pline. */
377 see_monsters();
378 see_objects();
379 see_traps();
382 /* for perm_inv and anything similar
383 (eg. Qt windowport's equipped items display) */
384 update_inventory();
386 context.botl = TRUE;
387 if (talk)
388 pline(message, verb);
390 return changed;
393 void
394 make_deaf(xtime, talk)
395 long xtime;
396 boolean talk;
398 long old = HDeaf;
400 if (Unaware)
401 talk = FALSE;
403 set_itimeout(&HDeaf, xtime);
404 if ((xtime != 0L) ^ (old != 0L)) {
405 context.botl = TRUE;
406 if (talk)
407 You(old ? "can hear again." : "are unable to hear anything.");
411 STATIC_OVL void
412 ghost_from_bottle()
414 struct monst *mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS);
416 if (!mtmp) {
417 pline("This bottle turns out to be empty.");
418 return;
420 if (Blind) {
421 pline("As you open the bottle, %s emerges.", something);
422 return;
424 pline("As you open the bottle, an enormous %s emerges!",
425 Hallucination ? rndmonnam(NULL) : (const char *) "ghost");
426 if (flags.verbose)
427 You("are frightened to death, and unable to move.");
428 nomul(-3);
429 multi_reason = "being frightened to death";
430 nomovemsg = "You regain your composure.";
433 /* "Quaffing is like drinking, except you spill more." - Terry Pratchett */
435 dodrink()
437 register struct obj *otmp;
438 const char *potion_descr;
440 if (Strangled) {
441 pline("If you can't breathe air, how can you drink liquid?");
442 return 0;
444 /* Is there a fountain to drink from here? */
445 if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)
446 /* not as low as floor level but similar restrictions apply */
447 && can_reach_floor(FALSE)) {
448 if (yn("Drink from the fountain?") == 'y') {
449 drinkfountain();
450 return 1;
453 /* Or a kitchen sink? */
454 if (IS_SINK(levl[u.ux][u.uy].typ)
455 /* not as low as floor level but similar restrictions apply */
456 && can_reach_floor(FALSE)) {
457 if (yn("Drink from the sink?") == 'y') {
458 drinksink();
459 return 1;
462 /* Or are you surrounded by water? */
463 if (Underwater && !u.uswallow) {
464 if (yn("Drink the water around you?") == 'y') {
465 pline("Do you know what lives in this water?");
466 return 1;
470 otmp = getobj(beverages, "drink");
471 if (!otmp)
472 return 0;
474 /* quan > 1 used to be left to useup(), but we need to force
475 the current potion to be unworn, and don't want to do
476 that for the entire stack when starting with more than 1.
477 [Drinking a wielded potion of polymorph can trigger a shape
478 change which causes hero's weapon to be dropped. In 3.4.x,
479 that led to an "object lost" panic since subsequent useup()
480 was no longer dealing with an inventory item. Unwearing
481 the current potion is intended to keep it in inventory.] */
482 if (otmp->quan > 1L) {
483 otmp = splitobj(otmp, 1L);
484 otmp->owornmask = 0L; /* rest of original stuck unaffected */
485 } else if (otmp->owornmask) {
486 remove_worn_item(otmp, FALSE);
488 otmp->in_use = TRUE; /* you've opened the stopper */
490 potion_descr = OBJ_DESCR(objects[otmp->otyp]);
491 if (potion_descr) {
492 if (!strcmp(potion_descr, "milky")
493 && !(mvitals[PM_GHOST].mvflags & G_GONE)
494 && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_GHOST].born))) {
495 ghost_from_bottle();
496 useup(otmp);
497 return 1;
498 } else if (!strcmp(potion_descr, "smoky")
499 && !(mvitals[PM_DJINNI].mvflags & G_GONE)
500 && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_DJINNI].born))) {
501 djinni_from_bottle(otmp);
502 useup(otmp);
503 return 1;
506 return dopotion(otmp);
510 dopotion(otmp)
511 register struct obj *otmp;
513 int retval;
515 otmp->in_use = TRUE;
516 nothing = unkn = 0;
517 if ((retval = peffects(otmp)) >= 0)
518 return retval;
520 if (nothing) {
521 unkn++;
522 You("have a %s feeling for a moment, then it passes.",
523 Hallucination ? "normal" : "peculiar");
525 if (otmp->dknown && !objects[otmp->otyp].oc_name_known) {
526 if (!unkn) {
527 makeknown(otmp->otyp);
528 more_experienced(0, 10);
529 } else if (!objects[otmp->otyp].oc_uname)
530 docall(otmp);
532 useup(otmp);
533 return 1;
537 peffects(otmp)
538 register struct obj *otmp;
540 register int i, ii, lim;
542 switch (otmp->otyp) {
543 case POT_RESTORE_ABILITY:
544 case SPE_RESTORE_ABILITY:
545 unkn++;
546 if (otmp->cursed) {
547 pline("Ulch! This makes you feel mediocre!");
548 break;
549 } else {
550 /* unlike unicorn horn, overrides Fixed_abil */
551 pline("Wow! This makes you feel %s!",
552 (otmp->blessed)
553 ? (unfixable_trouble_count(FALSE) ? "better" : "great")
554 : "good");
555 i = rn2(A_MAX); /* start at a random point */
556 for (ii = 0; ii < A_MAX; ii++) {
557 lim = AMAX(i);
558 if (i == A_STR && u.uhs >= 3)
559 --lim; /* WEAK */
560 if (ABASE(i) < lim) {
561 ABASE(i) = lim;
562 context.botl = 1;
563 /* only first found if not blessed */
564 if (!otmp->blessed)
565 break;
567 if (++i >= A_MAX)
568 i = 0;
571 break;
572 case POT_HALLUCINATION:
573 if (Hallucination || Halluc_resistance)
574 nothing++;
575 (void) make_hallucinated(
576 itimeout_incr(HHallucination, rn1(200, 600 - 300 * bcsign(otmp))),
577 TRUE, 0L);
578 break;
579 case POT_WATER:
580 if (!otmp->blessed && !otmp->cursed) {
581 pline("This tastes like %s.", hliquid("water"));
582 u.uhunger += rnd(10);
583 newuhs(FALSE);
584 break;
586 unkn++;
587 if (is_undead(youmonst.data) || is_demon(youmonst.data)
588 || u.ualign.type == A_CHAOTIC) {
589 if (otmp->blessed) {
590 pline("This burns like %s!", hliquid("acid"));
591 exercise(A_CON, FALSE);
592 if (u.ulycn >= LOW_PM) {
593 Your("affinity to %s disappears!",
594 makeplural(mons[u.ulycn].mname));
595 if (youmonst.data == &mons[u.ulycn])
596 you_unwere(FALSE);
597 set_ulycn(NON_PM); /* cure lycanthropy */
599 losehp(Maybe_Half_Phys(d(2, 6)), "potion of holy water",
600 KILLED_BY_AN);
601 } else if (otmp->cursed) {
602 You_feel("quite proud of yourself.");
603 healup(d(2, 6), 0, 0, 0);
604 if (u.ulycn >= LOW_PM && !Upolyd)
605 you_were();
606 exercise(A_CON, TRUE);
608 } else {
609 if (otmp->blessed) {
610 You_feel("full of awe.");
611 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
612 exercise(A_WIS, TRUE);
613 exercise(A_CON, TRUE);
614 if (u.ulycn >= LOW_PM)
615 you_unwere(TRUE); /* "Purified" */
616 /* make_confused(0L, TRUE); */
617 } else {
618 if (u.ualign.type == A_LAWFUL) {
619 pline("This burns like %s!", hliquid("acid"));
620 losehp(Maybe_Half_Phys(d(2, 6)), "potion of unholy water",
621 KILLED_BY_AN);
622 } else
623 You_feel("full of dread.");
624 if (u.ulycn >= LOW_PM && !Upolyd)
625 you_were();
626 exercise(A_CON, FALSE);
629 break;
630 case POT_BOOZE:
631 unkn++;
632 pline("Ooph! This tastes like %s%s!",
633 otmp->odiluted ? "watered down " : "",
634 Hallucination ? "dandelion wine" : "liquid fire");
635 if (!otmp->blessed)
636 make_confused(itimeout_incr(HConfusion, d(3, 8)), FALSE);
637 /* the whiskey makes us feel better */
638 if (!otmp->odiluted)
639 healup(1, 0, FALSE, FALSE);
640 u.uhunger += 10 * (2 + bcsign(otmp));
641 newuhs(FALSE);
642 exercise(A_WIS, FALSE);
643 if (otmp->cursed) {
644 You("pass out.");
645 multi = -rnd(15);
646 nomovemsg = "You awake with a headache.";
648 break;
649 case POT_ENLIGHTENMENT:
650 if (otmp->cursed) {
651 unkn++;
652 You("have an uneasy feeling...");
653 exercise(A_WIS, FALSE);
654 } else {
655 if (otmp->blessed) {
656 (void) adjattrib(A_INT, 1, FALSE);
657 (void) adjattrib(A_WIS, 1, FALSE);
659 You_feel("self-knowledgeable...");
660 display_nhwindow(WIN_MESSAGE, FALSE);
661 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
662 pline_The("feeling subsides.");
663 exercise(A_WIS, TRUE);
665 break;
666 case SPE_INVISIBILITY:
667 /* spell cannot penetrate mummy wrapping */
668 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
669 You_feel("rather itchy under %s.", yname(uarmc));
670 break;
672 /* FALLTHRU */
673 case POT_INVISIBILITY:
674 if (Invis || Blind || BInvis) {
675 nothing++;
676 } else {
677 self_invis_message();
679 if (otmp->blessed)
680 HInvis |= FROMOUTSIDE;
681 else
682 incr_itimeout(&HInvis, rn1(15, 31));
683 newsym(u.ux, u.uy); /* update position */
684 if (otmp->cursed) {
685 pline("For some reason, you feel your presence is known.");
686 aggravate();
688 break;
689 case POT_SEE_INVISIBLE: /* tastes like fruit juice in Rogue */
690 case POT_FRUIT_JUICE: {
691 int msg = Invisible && !Blind;
693 unkn++;
694 if (otmp->cursed)
695 pline("Yecch! This tastes %s.",
696 Hallucination ? "overripe" : "rotten");
697 else
698 pline(
699 Hallucination
700 ? "This tastes like 10%% real %s%s all-natural beverage."
701 : "This tastes like %s%s.",
702 otmp->odiluted ? "reconstituted " : "", fruitname(TRUE));
703 if (otmp->otyp == POT_FRUIT_JUICE) {
704 u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp));
705 newuhs(FALSE);
706 break;
708 if (!otmp->cursed) {
709 /* Tell them they can see again immediately, which
710 * will help them identify the potion...
712 make_blinded(0L, TRUE);
714 if (otmp->blessed)
715 HSee_invisible |= FROMOUTSIDE;
716 else
717 incr_itimeout(&HSee_invisible, rn1(100, 750));
718 set_mimic_blocking(); /* do special mimic handling */
719 see_monsters(); /* see invisible monsters */
720 newsym(u.ux, u.uy); /* see yourself! */
721 if (msg && !Blind) { /* Blind possible if polymorphed */
722 You("can see through yourself, but you are visible!");
723 unkn--;
725 break;
727 case POT_PARALYSIS:
728 if (Free_action) {
729 You("stiffen momentarily.");
730 } else {
731 if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
732 You("are motionlessly suspended.");
733 else if (u.usteed)
734 You("are frozen in place!");
735 else
736 Your("%s are frozen to the %s!", makeplural(body_part(FOOT)),
737 surface(u.ux, u.uy));
738 nomul(-(rn1(10, 25 - 12 * bcsign(otmp))));
739 multi_reason = "frozen by a potion";
740 nomovemsg = You_can_move_again;
741 exercise(A_DEX, FALSE);
743 break;
744 case POT_SLEEPING:
745 if (Sleep_resistance || Free_action) {
746 You("yawn.");
747 } else {
748 You("suddenly fall asleep!");
749 fall_asleep(-rn1(10, 25 - 12 * bcsign(otmp)), TRUE);
751 break;
752 case POT_MONSTER_DETECTION:
753 case SPE_DETECT_MONSTERS:
754 if (otmp->blessed) {
755 int x, y;
757 if (Detect_monsters)
758 nothing++;
759 unkn++;
760 /* after a while, repeated uses become less effective */
761 if ((HDetect_monsters & TIMEOUT) >= 300L)
762 i = 1;
763 else
764 i = rn1(40, 21);
765 incr_itimeout(&HDetect_monsters, i);
766 for (x = 1; x < COLNO; x++) {
767 for (y = 0; y < ROWNO; y++) {
768 if (levl[x][y].glyph == GLYPH_INVISIBLE) {
769 unmap_object(x, y);
770 newsym(x, y);
772 if (MON_AT(x, y))
773 unkn = 0;
776 see_monsters();
777 if (unkn)
778 You_feel("lonely.");
779 break;
781 if (monster_detect(otmp, 0))
782 return 1; /* nothing detected */
783 exercise(A_WIS, TRUE);
784 break;
785 case POT_OBJECT_DETECTION:
786 case SPE_DETECT_TREASURE:
787 if (object_detect(otmp, 0))
788 return 1; /* nothing detected */
789 exercise(A_WIS, TRUE);
790 break;
791 case POT_SICKNESS:
792 pline("Yecch! This stuff tastes like poison.");
793 if (otmp->blessed) {
794 pline("(But in fact it was mildly stale %s.)", fruitname(TRUE));
795 if (!Role_if(PM_HEALER)) {
796 /* NB: blessed otmp->fromsink is not possible */
797 losehp(1, "mildly contaminated potion", KILLED_BY_AN);
799 } else {
800 if (Poison_resistance)
801 pline("(But in fact it was biologically contaminated %s.)",
802 fruitname(TRUE));
803 if (Role_if(PM_HEALER)) {
804 pline("Fortunately, you have been immunized.");
805 } else {
806 char contaminant[BUFSZ];
807 int typ = rn2(A_MAX);
809 Sprintf(contaminant, "%s%s",
810 (Poison_resistance) ? "mildly " : "",
811 (otmp->fromsink) ? "contaminated tap water"
812 : "contaminated potion");
813 if (!Fixed_abil) {
814 poisontell(typ, FALSE);
815 (void) adjattrib(typ, Poison_resistance ? -1 : -rn1(4, 3),
818 if (!Poison_resistance) {
819 if (otmp->fromsink)
820 losehp(rnd(10) + 5 * !!(otmp->cursed), contaminant,
821 KILLED_BY);
822 else
823 losehp(rnd(10) + 5 * !!(otmp->cursed), contaminant,
824 KILLED_BY_AN);
825 } else {
826 /* rnd loss is so that unblessed poorer than blessed */
827 losehp(1 + rn2(2), contaminant,
828 (otmp->fromsink) ? KILLED_BY : KILLED_BY_AN);
830 exercise(A_CON, FALSE);
833 if (Hallucination) {
834 You("are shocked back to your senses!");
835 (void) make_hallucinated(0L, FALSE, 0L);
837 break;
838 case POT_CONFUSION:
839 if (!Confusion) {
840 if (Hallucination) {
841 pline("What a trippy feeling!");
842 unkn++;
843 } else
844 pline("Huh, What? Where am I?");
845 } else
846 nothing++;
847 make_confused(itimeout_incr(HConfusion,
848 rn1(7, 16 - 8 * bcsign(otmp))),
849 FALSE);
850 break;
851 case POT_GAIN_ABILITY:
852 if (otmp->cursed) {
853 pline("Ulch! That potion tasted foul!");
854 unkn++;
855 } else if (Fixed_abil) {
856 nothing++;
857 } else { /* If blessed, increase all; if not, try up to */
858 int itmp; /* 6 times to find one which can be increased. */
860 i = -1; /* increment to 0 */
861 for (ii = A_MAX; ii > 0; ii--) {
862 i = (otmp->blessed ? i + 1 : rn2(A_MAX));
863 /* only give "your X is already as high as it can get"
864 message on last attempt (except blessed potions) */
865 itmp = (otmp->blessed || ii == 1) ? 0 : -1;
866 if (adjattrib(i, 1, itmp) && !otmp->blessed)
867 break;
870 break;
871 case POT_SPEED:
872 if (Wounded_legs && !otmp->cursed && !u.usteed) {
873 /* heal_legs() would heal steeds legs */
874 heal_legs();
875 unkn++;
876 break;
878 /* FALLTHRU */
879 case SPE_HASTE_SELF:
880 if (!Very_fast) { /* wwf@doe.carleton.ca */
881 You("are suddenly moving %sfaster.", Fast ? "" : "much ");
882 } else {
883 Your("%s get new energy.", makeplural(body_part(LEG)));
884 unkn++;
886 exercise(A_DEX, TRUE);
887 incr_itimeout(&HFast, rn1(10, 100 + 60 * bcsign(otmp)));
888 break;
889 case POT_BLINDNESS:
890 if (Blind)
891 nothing++;
892 make_blinded(itimeout_incr(Blinded,
893 rn1(200, 250 - 125 * bcsign(otmp))),
894 (boolean) !Blind);
895 break;
896 case POT_GAIN_LEVEL:
897 if (otmp->cursed) {
898 unkn++;
899 /* they went up a level */
900 if ((ledger_no(&u.uz) == 1 && u.uhave.amulet)
901 || Can_rise_up(u.ux, u.uy, &u.uz)) {
902 const char *riseup = "rise up, through the %s!";
904 if (ledger_no(&u.uz) == 1) {
905 You(riseup, ceiling(u.ux, u.uy));
906 goto_level(&earth_level, FALSE, FALSE, FALSE);
907 } else {
908 register int newlev = depth(&u.uz) - 1;
909 d_level newlevel;
911 get_level(&newlevel, newlev);
912 if (on_level(&newlevel, &u.uz)) {
913 pline("It tasted bad.");
914 break;
915 } else
916 You(riseup, ceiling(u.ux, u.uy));
917 goto_level(&newlevel, FALSE, FALSE, FALSE);
919 } else
920 You("have an uneasy feeling.");
921 break;
923 pluslvl(FALSE);
924 /* blessed potions place you at a random spot in the
925 middle of the new level instead of the low point */
926 if (otmp->blessed)
927 u.uexp = rndexp(TRUE);
928 break;
929 case POT_HEALING:
930 You_feel("better.");
931 healup(d(6 + 2 * bcsign(otmp), 4), !otmp->cursed ? 1 : 0,
932 !!otmp->blessed, !otmp->cursed);
933 exercise(A_CON, TRUE);
934 break;
935 case POT_EXTRA_HEALING:
936 You_feel("much better.");
937 healup(d(6 + 2 * bcsign(otmp), 8),
938 otmp->blessed ? 5 : !otmp->cursed ? 2 : 0, !otmp->cursed,
939 TRUE);
940 (void) make_hallucinated(0L, TRUE, 0L);
941 exercise(A_CON, TRUE);
942 exercise(A_STR, TRUE);
943 break;
944 case POT_FULL_HEALING:
945 You_feel("completely healed.");
946 healup(400, 4 + 4 * bcsign(otmp), !otmp->cursed, TRUE);
947 /* Restore one lost level if blessed */
948 if (otmp->blessed && u.ulevel < u.ulevelmax) {
949 /* when multiple levels have been lost, drinking
950 multiple potions will only get half of them back */
951 u.ulevelmax -= 1;
952 pluslvl(FALSE);
954 (void) make_hallucinated(0L, TRUE, 0L);
955 exercise(A_STR, TRUE);
956 exercise(A_CON, TRUE);
957 break;
958 case POT_LEVITATION:
959 case SPE_LEVITATION:
961 * BLevitation will be set if levitation is blocked due to being
962 * inside rock (currently or formerly in phazing xorn form, perhaps)
963 * but it doesn't prevent setting or incrementing Levitation timeout
964 * (which will take effect after escaping from the rock if it hasn't
965 * expired by then).
967 if (!Levitation && !BLevitation) {
968 /* kludge to ensure proper operation of float_up() */
969 set_itimeout(&HLevitation, 1L);
970 float_up();
971 /* This used to set timeout back to 0, then increment it below
972 for blessed and uncursed effects. But now we leave it so
973 that cursed effect yields "you float down" on next turn.
974 Blessed and uncursed get one extra turn duration. */
975 } else /* already levitating, or can't levitate */
976 nothing++;
978 if (otmp->cursed) {
979 /* 'already levitating' used to block the cursed effect(s)
980 aside from ~I_SPECIAL; it was not clear whether that was
981 intentional; either way, it no longer does (as of 3.6.1) */
982 HLevitation &= ~I_SPECIAL; /* can't descend upon demand */
983 if (BLevitation) {
984 ; /* rising via levitation is blocked */
985 } else if ((u.ux == xupstair && u.uy == yupstair)
986 || (sstairs.up && u.ux == sstairs.sx && u.uy == sstairs.sy)
987 || (xupladder && u.ux == xupladder && u.uy == yupladder)) {
988 (void) doup();
989 /* in case we're already Levitating, which would have
990 resulted in incrementing 'nothing' */
991 nothing = 0; /* not nothing after all */
992 } else if (has_ceiling(&u.uz)) {
993 int dmg = rnd(!uarmh ? 10 : !is_metallic(uarmh) ? 6 : 3);
995 You("hit your %s on the %s.", body_part(HEAD),
996 ceiling(u.ux, u.uy));
997 losehp(Maybe_Half_Phys(dmg), "colliding with the ceiling",
998 KILLED_BY);
999 nothing = 0; /* not nothing after all */
1001 } else if (otmp->blessed) {
1002 /* at this point, timeout is already at least 1 */
1003 incr_itimeout(&HLevitation, rn1(50, 250));
1004 /* can descend at will (stop levitating via '>') provided timeout
1005 is the only factor (ie, not also wearing Lev ring or boots) */
1006 HLevitation |= I_SPECIAL;
1007 } else /* timeout is already at least 1 */
1008 incr_itimeout(&HLevitation, rn1(140, 10));
1010 if (Levitation && IS_SINK(levl[u.ux][u.uy].typ))
1011 spoteffects(FALSE);
1012 /* levitating blocks flying */
1013 float_vs_flight();
1014 break;
1015 case POT_GAIN_ENERGY: { /* M. Stephenson */
1016 int num;
1018 if (otmp->cursed)
1019 You_feel("lackluster.");
1020 else
1021 pline("Magical energies course through your body.");
1023 /* old: num = rnd(5) + 5 * otmp->blessed + 1;
1024 * blessed: +7..11 max & current (+9 avg)
1025 * uncursed: +2.. 6 max & current (+4 avg)
1026 * cursed: -2.. 6 max & current (-4 avg)
1027 * new: (3.6.0)
1028 * blessed: +3..18 max (+10.5 avg), +9..54 current (+31.5 avg)
1029 * uncursed: +2..12 max (+ 7 avg), +6..36 current (+21 avg)
1030 * cursed: -1.. 6 max (- 3.5 avg), -3..18 current (-10.5 avg)
1032 num = d(otmp->blessed ? 3 : !otmp->cursed ? 2 : 1, 6);
1033 if (otmp->cursed)
1034 num = -num; /* subtract instead of add when cursed */
1035 u.uenmax += num;
1036 if (u.uenmax <= 0)
1037 u.uenmax = 0;
1038 u.uen += 3 * num;
1039 if (u.uen > u.uenmax)
1040 u.uen = u.uenmax;
1041 else if (u.uen <= 0)
1042 u.uen = 0;
1043 context.botl = 1;
1044 exercise(A_WIS, TRUE);
1045 break;
1047 case POT_OIL: { /* P. Winner */
1048 boolean good_for_you = FALSE;
1050 if (otmp->lamplit) {
1051 if (likes_fire(youmonst.data)) {
1052 pline("Ahh, a refreshing drink.");
1053 good_for_you = TRUE;
1054 } else {
1055 You("burn your %s.", body_part(FACE));
1056 /* fire damage */
1057 losehp(d(Fire_resistance ? 1 : 3, 4), "burning potion of oil",
1058 KILLED_BY_AN);
1060 } else if (otmp->cursed)
1061 pline("This tastes like castor oil.");
1062 else
1063 pline("That was smooth!");
1064 exercise(A_WIS, good_for_you);
1065 break;
1067 case POT_ACID:
1068 if (Acid_resistance) {
1069 /* Not necessarily a creature who _likes_ acid */
1070 pline("This tastes %s.", Hallucination ? "tangy" : "sour");
1071 } else {
1072 int dmg;
1074 pline("This burns%s!",
1075 otmp->blessed ? " a little" : otmp->cursed ? " a lot"
1076 : " like acid");
1077 dmg = d(otmp->cursed ? 2 : 1, otmp->blessed ? 4 : 8);
1078 losehp(Maybe_Half_Phys(dmg), "potion of acid", KILLED_BY_AN);
1079 exercise(A_CON, FALSE);
1081 if (Stoned)
1082 fix_petrification();
1083 unkn++; /* holy/unholy water can burn like acid too */
1084 break;
1085 case POT_POLYMORPH:
1086 You_feel("a little %s.", Hallucination ? "normal" : "strange");
1087 if (!Unchanging)
1088 polyself(0);
1089 break;
1090 default:
1091 impossible("What a funny potion! (%u)", otmp->otyp);
1092 return 0;
1094 return -1;
1097 void
1098 healup(nhp, nxtra, curesick, cureblind)
1099 int nhp, nxtra;
1100 register boolean curesick, cureblind;
1102 if (nhp) {
1103 if (Upolyd) {
1104 u.mh += nhp;
1105 if (u.mh > u.mhmax)
1106 u.mh = (u.mhmax += nxtra);
1107 } else {
1108 u.uhp += nhp;
1109 if (u.uhp > u.uhpmax)
1110 u.uhp = (u.uhpmax += nxtra);
1113 if (cureblind) {
1114 /* 3.6.1: it's debatible whether healing magic should clean off
1115 mundane 'dirt', but if it doesn't, blindness isn't cured */
1116 u.ucreamed = 0;
1117 make_blinded(0L, TRUE);
1119 if (curesick) {
1120 make_vomiting(0L, TRUE);
1121 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
1123 context.botl = 1;
1124 return;
1127 void
1128 strange_feeling(obj, txt)
1129 struct obj *obj;
1130 const char *txt;
1132 if (flags.beginner || !txt)
1133 You("have a %s feeling for a moment, then it passes.",
1134 Hallucination ? "normal" : "strange");
1135 else
1136 pline1(txt);
1138 if (!obj) /* e.g., crystal ball finds no traps */
1139 return;
1141 if (obj->dknown && !objects[obj->otyp].oc_name_known
1142 && !objects[obj->otyp].oc_uname)
1143 docall(obj);
1145 useup(obj);
1148 const char *bottlenames[] = { "bottle", "phial", "flagon", "carafe",
1149 "flask", "jar", "vial" };
1151 const char *
1152 bottlename()
1154 return bottlenames[rn2(SIZE(bottlenames))];
1157 /* handle item dipped into water potion or steed saddle splashed by same */
1158 STATIC_OVL boolean
1159 H2Opotion_dip(potion, targobj, useeit, objphrase)
1160 struct obj *potion, *targobj;
1161 boolean useeit;
1162 const char *objphrase; /* "Your widget glows" or "Steed's saddle glows" */
1164 void FDECL((*func), (OBJ_P)) = 0;
1165 const char *glowcolor = 0;
1166 #define COST_alter (-2)
1167 #define COST_none (-1)
1168 int costchange = COST_none;
1169 boolean altfmt = FALSE, res = FALSE;
1171 if (!potion || potion->otyp != POT_WATER)
1172 return FALSE;
1174 if (potion->blessed) {
1175 if (targobj->cursed) {
1176 func = uncurse;
1177 glowcolor = NH_AMBER;
1178 costchange = COST_UNCURS;
1179 } else if (!targobj->blessed) {
1180 func = bless;
1181 glowcolor = NH_LIGHT_BLUE;
1182 costchange = COST_alter;
1183 altfmt = TRUE; /* "with a <color> aura" */
1185 } else if (potion->cursed) {
1186 if (targobj->blessed) {
1187 func = unbless;
1188 glowcolor = "brown";
1189 costchange = COST_UNBLSS;
1190 } else if (!targobj->cursed) {
1191 func = curse;
1192 glowcolor = NH_BLACK;
1193 costchange = COST_alter;
1194 altfmt = TRUE;
1196 } else {
1197 /* dipping into uncursed water; carried() check skips steed saddle */
1198 if (carried(targobj)) {
1199 if (water_damage(targobj, 0, TRUE) != ER_NOTHING)
1200 res = TRUE;
1203 if (func) {
1204 /* give feedback before altering the target object;
1205 this used to set obj->bknown even when not seeing
1206 the effect; now hero has to see the glow, and bknown
1207 is cleared instead of set if perception is distorted */
1208 if (useeit) {
1209 glowcolor = hcolor(glowcolor);
1210 if (altfmt)
1211 pline("%s with %s aura.", objphrase, an(glowcolor));
1212 else
1213 pline("%s %s.", objphrase, glowcolor);
1214 iflags.last_msg = PLNMSG_OBJ_GLOWS;
1215 targobj->bknown = !Hallucination;
1217 /* potions of water are the only shop goods whose price depends
1218 on their curse/bless state */
1219 if (targobj->unpaid && targobj->otyp == POT_WATER) {
1220 if (costchange == COST_alter)
1221 /* added blessing or cursing; update shop
1222 bill to reflect item's new higher price */
1223 alter_cost(targobj, 0L);
1224 else if (costchange != COST_none)
1225 /* removed blessing or cursing; you
1226 degraded it, now you'll have to buy it... */
1227 costly_alteration(targobj, costchange);
1229 /* finally, change curse/bless state */
1230 (*func)(targobj);
1231 res = TRUE;
1233 return res;
1236 void
1237 potionhit(mon, obj, your_fault)
1238 register struct monst *mon;
1239 register struct obj *obj;
1240 boolean your_fault;
1242 const char *botlnam = bottlename();
1243 boolean isyou = (mon == &youmonst);
1244 int distance, tx, ty;
1245 struct obj *saddle = (struct obj *) 0;
1246 boolean hit_saddle = FALSE;
1248 if (isyou) {
1249 tx = u.ux, ty = u.uy;
1250 distance = 0;
1251 pline_The("%s crashes on your %s and breaks into shards.", botlnam,
1252 body_part(HEAD));
1253 losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
1254 } else {
1255 tx = mon->mx, ty = mon->my;
1256 /* sometimes it hits the saddle */
1257 if (((mon->misc_worn_check & W_SADDLE)
1258 && (saddle = which_armor(mon, W_SADDLE)))
1259 && (!rn2(10)
1260 || (obj->otyp == POT_WATER
1261 && ((rnl(10) > 7 && obj->cursed)
1262 || (rnl(10) < 4 && obj->blessed) || !rn2(3)))))
1263 hit_saddle = TRUE;
1264 distance = distu(tx, ty);
1265 if (!cansee(tx, ty)) {
1266 pline("Crash!");
1267 } else {
1268 char *mnam = mon_nam(mon);
1269 char buf[BUFSZ];
1271 if (hit_saddle && saddle) {
1272 Sprintf(buf, "%s saddle",
1273 s_suffix(x_monnam(mon, ARTICLE_THE, (char *) 0,
1274 (SUPPRESS_IT | SUPPRESS_SADDLE),
1275 FALSE)));
1276 } else if (has_head(mon->data)) {
1277 Sprintf(buf, "%s %s", s_suffix(mnam),
1278 (notonhead ? "body" : "head"));
1279 } else {
1280 Strcpy(buf, mnam);
1282 pline_The("%s crashes on %s and breaks into shards.", botlnam,
1283 buf);
1285 if (rn2(5) && mon->mhp > 1 && !hit_saddle)
1286 mon->mhp--;
1289 /* oil doesn't instantly evaporate; Neither does a saddle hit */
1290 if (obj->otyp != POT_OIL && !hit_saddle && cansee(tx, ty))
1291 pline("%s.", Tobjnam(obj, "evaporate"));
1293 if (isyou) {
1294 switch (obj->otyp) {
1295 case POT_OIL:
1296 if (obj->lamplit)
1297 explode_oil(obj, u.ux, u.uy);
1298 break;
1299 case POT_POLYMORPH:
1300 You_feel("a little %s.", Hallucination ? "normal" : "strange");
1301 if (!Unchanging && !Antimagic)
1302 polyself(0);
1303 break;
1304 case POT_ACID:
1305 if (!Acid_resistance) {
1306 int dmg;
1307 pline("This burns%s!",
1308 obj->blessed ? " a little"
1309 : obj->cursed ? " a lot" : "");
1310 dmg = d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
1311 losehp(Maybe_Half_Phys(dmg), "potion of acid", KILLED_BY_AN);
1313 break;
1315 } else if (hit_saddle && saddle) {
1316 char *mnam, buf[BUFSZ], saddle_glows[BUFSZ];
1317 boolean affected = FALSE;
1318 boolean useeit = !Blind && canseemon(mon) && cansee(tx, ty);
1320 mnam = x_monnam(mon, ARTICLE_THE, (char *) 0,
1321 (SUPPRESS_IT | SUPPRESS_SADDLE), FALSE);
1322 Sprintf(buf, "%s", upstart(s_suffix(mnam)));
1324 switch (obj->otyp) {
1325 case POT_WATER:
1326 Sprintf(saddle_glows, "%s %s", buf, aobjnam(saddle, "glow"));
1327 affected = H2Opotion_dip(obj, saddle, useeit, saddle_glows);
1328 break;
1329 case POT_POLYMORPH:
1330 /* Do we allow the saddle to polymorph? */
1331 break;
1333 if (useeit && !affected)
1334 pline("%s %s wet.", buf, aobjnam(saddle, "get"));
1335 } else {
1336 boolean angermon = your_fault;
1338 switch (obj->otyp) {
1339 case POT_HEALING:
1340 case POT_EXTRA_HEALING:
1341 case POT_FULL_HEALING:
1342 if (mon->data == &mons[PM_PESTILENCE])
1343 goto do_illness;
1344 /*FALLTHRU*/
1345 case POT_RESTORE_ABILITY:
1346 case POT_GAIN_ABILITY:
1347 do_healing:
1348 angermon = FALSE;
1349 if (mon->mhp < mon->mhpmax) {
1350 mon->mhp = mon->mhpmax;
1351 if (canseemon(mon))
1352 pline("%s looks sound and hale again.", Monnam(mon));
1354 break;
1355 case POT_SICKNESS:
1356 if (mon->data == &mons[PM_PESTILENCE])
1357 goto do_healing;
1358 if (dmgtype(mon->data, AD_DISE)
1359 /* won't happen, see prior goto */
1360 || dmgtype(mon->data, AD_PEST)
1361 /* most common case */
1362 || resists_poison(mon)) {
1363 if (canseemon(mon))
1364 pline("%s looks unharmed.", Monnam(mon));
1365 break;
1367 do_illness:
1368 if ((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL))
1369 mon->mhpmax /= 2;
1370 if ((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL))
1371 mon->mhp /= 2;
1372 if (mon->mhp > mon->mhpmax)
1373 mon->mhp = mon->mhpmax;
1374 if (canseemon(mon))
1375 pline("%s looks rather ill.", Monnam(mon));
1376 break;
1377 case POT_CONFUSION:
1378 case POT_BOOZE:
1379 if (!resist(mon, POTION_CLASS, 0, NOTELL))
1380 mon->mconf = TRUE;
1381 break;
1382 case POT_INVISIBILITY: {
1383 boolean sawit = canspotmon(mon);
1385 angermon = FALSE;
1386 mon_set_minvis(mon);
1387 if (sawit && !canspotmon(mon) && cansee(mon->mx, mon->my))
1388 map_invisible(mon->mx, mon->my);
1389 break;
1391 case POT_SLEEPING:
1392 /* wakeup() doesn't rouse victims of temporary sleep */
1393 if (sleep_monst(mon, rnd(12), POTION_CLASS)) {
1394 pline("%s falls asleep.", Monnam(mon));
1395 slept_monst(mon);
1397 break;
1398 case POT_PARALYSIS:
1399 if (mon->mcanmove) {
1400 /* really should be rnd(5) for consistency with players
1401 * breathing potions, but...
1403 paralyze_monst(mon, rnd(25));
1405 break;
1406 case POT_SPEED:
1407 angermon = FALSE;
1408 mon_adjust_speed(mon, 1, obj);
1409 break;
1410 case POT_BLINDNESS:
1411 if (haseyes(mon->data)) {
1412 register int btmp = 64 + rn2(32)
1413 + rn2(32) * !resist(mon, POTION_CLASS, 0, NOTELL);
1415 btmp += mon->mblinded;
1416 mon->mblinded = min(btmp, 127);
1417 mon->mcansee = 0;
1419 break;
1420 case POT_WATER:
1421 if (is_undead(mon->data) || is_demon(mon->data)
1422 || is_were(mon->data) || is_vampshifter(mon)) {
1423 if (obj->blessed) {
1424 pline("%s %s in pain!", Monnam(mon),
1425 is_silent(mon->data) ? "writhes" : "shrieks");
1426 if (!is_silent(mon->data))
1427 wake_nearto(tx, ty, mon->data->mlevel * 10);
1428 mon->mhp -= d(2, 6);
1429 /* should only be by you */
1430 if (mon->mhp < 1)
1431 killed(mon);
1432 else if (is_were(mon->data) && !is_human(mon->data))
1433 new_were(mon); /* revert to human */
1434 } else if (obj->cursed) {
1435 angermon = FALSE;
1436 if (canseemon(mon))
1437 pline("%s looks healthier.", Monnam(mon));
1438 mon->mhp += d(2, 6);
1439 if (mon->mhp > mon->mhpmax)
1440 mon->mhp = mon->mhpmax;
1441 if (is_were(mon->data) && is_human(mon->data)
1442 && !Protection_from_shape_changers)
1443 new_were(mon); /* transform into beast */
1445 } else if (mon->data == &mons[PM_GREMLIN]) {
1446 angermon = FALSE;
1447 (void) split_mon(mon, (struct monst *) 0);
1448 } else if (mon->data == &mons[PM_IRON_GOLEM]) {
1449 if (canseemon(mon))
1450 pline("%s rusts.", Monnam(mon));
1451 mon->mhp -= d(1, 6);
1452 /* should only be by you */
1453 if (mon->mhp < 1)
1454 killed(mon);
1456 break;
1457 case POT_OIL:
1458 if (obj->lamplit)
1459 explode_oil(obj, tx, ty);
1460 break;
1461 case POT_ACID:
1462 if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
1463 pline("%s %s in pain!", Monnam(mon),
1464 is_silent(mon->data) ? "writhes" : "shrieks");
1465 if (!is_silent(mon->data))
1466 wake_nearto(tx, ty, mon->data->mlevel * 10);
1467 mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
1468 if (mon->mhp < 1) {
1469 if (your_fault)
1470 killed(mon);
1471 else
1472 monkilled(mon, "", AD_ACID);
1475 break;
1476 case POT_POLYMORPH:
1477 (void) bhitm(mon, obj);
1478 break;
1480 case POT_GAIN_LEVEL:
1481 case POT_LEVITATION:
1482 case POT_FRUIT_JUICE:
1483 case POT_MONSTER_DETECTION:
1484 case POT_OBJECT_DETECTION:
1485 break;
1488 /* target might have been killed */
1489 if (mon->mhp > 0) {
1490 if (angermon)
1491 wakeup(mon, TRUE);
1492 else
1493 mon->msleeping = 0;
1497 /* Note: potionbreathe() does its own docall() */
1498 if ((distance == 0 || (distance < 3 && rn2(5)))
1499 && (!breathless(youmonst.data) || haseyes(youmonst.data)))
1500 potionbreathe(obj);
1501 else if (obj->dknown && !objects[obj->otyp].oc_name_known
1502 && !objects[obj->otyp].oc_uname && cansee(tx, ty))
1503 docall(obj);
1505 if (*u.ushops && obj->unpaid) {
1506 struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
1508 /* neither of the first two cases should be able to happen;
1509 only the hero should ever have an unpaid item, and only
1510 when inside a tended shop */
1511 if (!shkp) /* if shkp was killed, unpaid ought to cleared already */
1512 obj->unpaid = 0;
1513 else if (context.mon_moving) /* obj thrown by monster */
1514 subfrombill(obj, shkp);
1515 else /* obj thrown by hero */
1516 (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
1517 FALSE);
1519 obfree(obj, (struct obj *) 0);
1522 /* vapors are inhaled or get in your eyes */
1523 void
1524 potionbreathe(obj)
1525 register struct obj *obj;
1527 register int i, ii, isdone, kn = 0;
1529 switch (obj->otyp) {
1530 case POT_RESTORE_ABILITY:
1531 case POT_GAIN_ABILITY:
1532 if (obj->cursed) {
1533 if (!breathless(youmonst.data))
1534 pline("Ulch! That potion smells terrible!");
1535 else if (haseyes(youmonst.data)) {
1536 const char *eyes = body_part(EYE);
1538 if (eyecount(youmonst.data) != 1)
1539 eyes = makeplural(eyes);
1540 Your("%s %s!", eyes, vtense(eyes, "sting"));
1542 break;
1543 } else {
1544 i = rn2(A_MAX); /* start at a random point */
1545 for (isdone = ii = 0; !isdone && ii < A_MAX; ii++) {
1546 if (ABASE(i) < AMAX(i)) {
1547 ABASE(i)++;
1548 /* only first found if not blessed */
1549 isdone = !(obj->blessed);
1550 context.botl = 1;
1552 if (++i >= A_MAX)
1553 i = 0;
1556 break;
1557 case POT_FULL_HEALING:
1558 if (Upolyd && u.mh < u.mhmax)
1559 u.mh++, context.botl = 1;
1560 if (u.uhp < u.uhpmax)
1561 u.uhp++, context.botl = 1;
1562 /*FALLTHRU*/
1563 case POT_EXTRA_HEALING:
1564 if (Upolyd && u.mh < u.mhmax)
1565 u.mh++, context.botl = 1;
1566 if (u.uhp < u.uhpmax)
1567 u.uhp++, context.botl = 1;
1568 /*FALLTHRU*/
1569 case POT_HEALING:
1570 if (Upolyd && u.mh < u.mhmax)
1571 u.mh++, context.botl = 1;
1572 if (u.uhp < u.uhpmax)
1573 u.uhp++, context.botl = 1;
1574 exercise(A_CON, TRUE);
1575 break;
1576 case POT_SICKNESS:
1577 if (!Role_if(PM_HEALER)) {
1578 if (Upolyd) {
1579 if (u.mh <= 5)
1580 u.mh = 1;
1581 else
1582 u.mh -= 5;
1583 } else {
1584 if (u.uhp <= 5)
1585 u.uhp = 1;
1586 else
1587 u.uhp -= 5;
1589 context.botl = 1;
1590 exercise(A_CON, FALSE);
1592 break;
1593 case POT_HALLUCINATION:
1594 You("have a momentary vision.");
1595 break;
1596 case POT_CONFUSION:
1597 case POT_BOOZE:
1598 if (!Confusion)
1599 You_feel("somewhat dizzy.");
1600 make_confused(itimeout_incr(HConfusion, rnd(5)), FALSE);
1601 break;
1602 case POT_INVISIBILITY:
1603 if (!Blind && !Invis) {
1604 kn++;
1605 pline("For an instant you %s!",
1606 See_invisible ? "could see right through yourself"
1607 : "couldn't see yourself");
1609 break;
1610 case POT_PARALYSIS:
1611 kn++;
1612 if (!Free_action) {
1613 pline("%s seems to be holding you.", Something);
1614 nomul(-rnd(5));
1615 multi_reason = "frozen by a potion";
1616 nomovemsg = You_can_move_again;
1617 exercise(A_DEX, FALSE);
1618 } else
1619 You("stiffen momentarily.");
1620 break;
1621 case POT_SLEEPING:
1622 kn++;
1623 if (!Free_action && !Sleep_resistance) {
1624 You_feel("rather tired.");
1625 nomul(-rnd(5));
1626 multi_reason = "sleeping off a magical draught";
1627 nomovemsg = You_can_move_again;
1628 exercise(A_DEX, FALSE);
1629 } else
1630 You("yawn.");
1631 break;
1632 case POT_SPEED:
1633 if (!Fast)
1634 Your("knees seem more flexible now.");
1635 incr_itimeout(&HFast, rnd(5));
1636 exercise(A_DEX, TRUE);
1637 break;
1638 case POT_BLINDNESS:
1639 if (!Blind && !Unaware) {
1640 kn++;
1641 pline("It suddenly gets dark.");
1643 make_blinded(itimeout_incr(Blinded, rnd(5)), FALSE);
1644 if (!Blind && !Unaware)
1645 Your1(vision_clears);
1646 break;
1647 case POT_WATER:
1648 if (u.umonnum == PM_GREMLIN) {
1649 (void) split_mon(&youmonst, (struct monst *) 0);
1650 } else if (u.ulycn >= LOW_PM) {
1651 /* vapor from [un]holy water will trigger
1652 transformation but won't cure lycanthropy */
1653 if (obj->blessed && youmonst.data == &mons[u.ulycn])
1654 you_unwere(FALSE);
1655 else if (obj->cursed && !Upolyd)
1656 you_were();
1658 break;
1659 case POT_ACID:
1660 case POT_POLYMORPH:
1661 exercise(A_CON, FALSE);
1662 break;
1664 case POT_GAIN_LEVEL:
1665 case POT_LEVITATION:
1666 case POT_FRUIT_JUICE:
1667 case POT_MONSTER_DETECTION:
1668 case POT_OBJECT_DETECTION:
1669 case POT_OIL:
1670 break;
1673 /* note: no obfree() */
1674 if (obj->dknown) {
1675 if (kn)
1676 makeknown(obj->otyp);
1677 else if (!objects[obj->otyp].oc_name_known
1678 && !objects[obj->otyp].oc_uname)
1679 docall(obj);
1683 /* returns the potion type when o1 is dipped in o2 */
1684 STATIC_OVL short
1685 mixtype(o1, o2)
1686 register struct obj *o1, *o2;
1688 /* cut down on the number of cases below */
1689 if (o1->oclass == POTION_CLASS
1690 && (o2->otyp == POT_GAIN_LEVEL || o2->otyp == POT_GAIN_ENERGY
1691 || o2->otyp == POT_HEALING || o2->otyp == POT_EXTRA_HEALING
1692 || o2->otyp == POT_FULL_HEALING || o2->otyp == POT_ENLIGHTENMENT
1693 || o2->otyp == POT_FRUIT_JUICE)) {
1694 struct obj *swp;
1696 swp = o1;
1697 o1 = o2;
1698 o2 = swp;
1701 switch (o1->otyp) {
1702 case POT_HEALING:
1703 switch (o2->otyp) {
1704 case POT_SPEED:
1705 case POT_GAIN_LEVEL:
1706 case POT_GAIN_ENERGY:
1707 return POT_EXTRA_HEALING;
1709 case POT_EXTRA_HEALING:
1710 switch (o2->otyp) {
1711 case POT_GAIN_LEVEL:
1712 case POT_GAIN_ENERGY:
1713 return POT_FULL_HEALING;
1715 case POT_FULL_HEALING:
1716 switch (o2->otyp) {
1717 case POT_GAIN_LEVEL:
1718 case POT_GAIN_ENERGY:
1719 return POT_GAIN_ABILITY;
1721 case UNICORN_HORN:
1722 switch (o2->otyp) {
1723 case POT_SICKNESS:
1724 return POT_FRUIT_JUICE;
1725 case POT_HALLUCINATION:
1726 case POT_BLINDNESS:
1727 case POT_CONFUSION:
1728 return POT_WATER;
1730 break;
1731 case AMETHYST: /* "a-methyst" == "not intoxicated" */
1732 if (o2->otyp == POT_BOOZE)
1733 return POT_FRUIT_JUICE;
1734 break;
1735 case POT_GAIN_LEVEL:
1736 case POT_GAIN_ENERGY:
1737 switch (o2->otyp) {
1738 case POT_CONFUSION:
1739 return (rn2(3) ? POT_BOOZE : POT_ENLIGHTENMENT);
1740 case POT_HEALING:
1741 return POT_EXTRA_HEALING;
1742 case POT_EXTRA_HEALING:
1743 return POT_FULL_HEALING;
1744 case POT_FULL_HEALING:
1745 return POT_GAIN_ABILITY;
1746 case POT_FRUIT_JUICE:
1747 return POT_SEE_INVISIBLE;
1748 case POT_BOOZE:
1749 return POT_HALLUCINATION;
1751 break;
1752 case POT_FRUIT_JUICE:
1753 switch (o2->otyp) {
1754 case POT_SICKNESS:
1755 return POT_SICKNESS;
1756 case POT_ENLIGHTENMENT:
1757 case POT_SPEED:
1758 return POT_BOOZE;
1759 case POT_GAIN_LEVEL:
1760 case POT_GAIN_ENERGY:
1761 return POT_SEE_INVISIBLE;
1763 break;
1764 case POT_ENLIGHTENMENT:
1765 switch (o2->otyp) {
1766 case POT_LEVITATION:
1767 if (rn2(3))
1768 return POT_GAIN_LEVEL;
1769 break;
1770 case POT_FRUIT_JUICE:
1771 return POT_BOOZE;
1772 case POT_BOOZE:
1773 return POT_CONFUSION;
1775 break;
1778 return STRANGE_OBJECT;
1781 /* #dip command */
1783 dodip()
1785 static const char Dip_[] = "Dip ";
1786 register struct obj *potion, *obj;
1787 struct obj *singlepotion;
1788 uchar here;
1789 char allowall[2];
1790 short mixture;
1791 char qbuf[QBUFSZ], obuf[QBUFSZ];
1792 const char *shortestname; /* last resort obj name for prompt */
1794 allowall[0] = ALL_CLASSES;
1795 allowall[1] = '\0';
1796 if (!(obj = getobj(allowall, "dip")))
1797 return 0;
1798 if (inaccessible_equipment(obj, "dip", FALSE))
1799 return 0;
1801 shortestname = (is_plural(obj) || pair_of(obj)) ? "them" : "it";
1803 * Bypass safe_qbuf() since it doesn't handle varying suffix without
1804 * an awful lot of support work. Format the object once, even though
1805 * the fountain and pool prompts offer a lot more room for it.
1806 * 3.6.0 used thesimpleoname() unconditionally, which posed no risk
1807 * of buffer overflow but drew bug reports because it omits user-
1808 * supplied type name.
1809 * getobj: "What do you want to dip <the object> into? [xyz or ?*] "
1811 Strcpy(obuf, short_oname(obj, doname, thesimpleoname,
1812 /* 128 - (24 + 54 + 1) leaves 49 for <object> */
1813 QBUFSZ - sizeof "What do you want to dip \
1814 into? [abdeghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ#-# or ?*] "));
1816 here = levl[u.ux][u.uy].typ;
1817 /* Is there a fountain to dip into here? */
1818 if (IS_FOUNTAIN(here)) {
1819 Sprintf(qbuf, "%s%s into the fountain?", Dip_,
1820 flags.verbose ? obuf : shortestname);
1821 /* "Dip <the object> into the fountain?" */
1822 if (yn(qbuf) == 'y') {
1823 dipfountain(obj);
1824 return 1;
1826 } else if (is_pool(u.ux, u.uy)) {
1827 const char *pooltype = waterbody_name(u.ux, u.uy);
1829 Sprintf(qbuf, "%s%s into the %s?", Dip_,
1830 flags.verbose ? obuf : shortestname, pooltype);
1831 /* "Dip <the object> into the {pool, moat, &c}?" */
1832 if (yn(qbuf) == 'y') {
1833 if (Levitation) {
1834 floating_above(pooltype);
1835 } else if (u.usteed && !is_swimmer(u.usteed->data)
1836 && P_SKILL(P_RIDING) < P_BASIC) {
1837 rider_cant_reach(); /* not skilled enough to reach */
1838 } else {
1839 if (obj->otyp == POT_ACID)
1840 obj->in_use = 1;
1841 if (water_damage(obj, 0, TRUE) != ER_DESTROYED && obj->in_use)
1842 useup(obj);
1844 return 1;
1848 /* "What do you want to dip <the object> into? [xyz or ?*] " */
1849 Sprintf(qbuf, "dip %s into", flags.verbose ? obuf : shortestname);
1850 potion = getobj(beverages, qbuf);
1851 if (!potion)
1852 return 0;
1853 if (potion == obj && potion->quan == 1L) {
1854 pline("That is a potion bottle, not a Klein bottle!");
1855 return 0;
1857 potion->in_use = TRUE; /* assume it will be used up */
1858 if (potion->otyp == POT_WATER) {
1859 boolean useeit = !Blind || (obj == ublindf && Blindfolded_only);
1860 const char *obj_glows = Yobjnam2(obj, "glow");
1862 if (H2Opotion_dip(potion, obj, useeit, obj_glows))
1863 goto poof;
1864 } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) {
1865 /* some objects can't be polymorphed */
1866 if (obj->otyp == potion->otyp /* both POT_POLY */
1867 || obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH
1868 || obj == uball || obj == uskin
1869 || obj_resists(obj->otyp == POT_POLYMORPH ? potion : obj,
1870 5, 95)) {
1871 pline1(nothing_happens);
1872 } else {
1873 boolean was_wep, was_swapwep, was_quiver;
1874 short save_otyp = obj->otyp;
1876 /* KMH, conduct */
1877 u.uconduct.polypiles++;
1879 was_wep = (obj == uwep);
1880 was_swapwep = (obj == uswapwep);
1881 was_quiver = (obj == uquiver);
1883 obj = poly_obj(obj, STRANGE_OBJECT);
1885 if (was_wep)
1886 setuwep(obj);
1887 else if (was_swapwep)
1888 setuswapwep(obj);
1889 else if (was_quiver)
1890 setuqwep(obj);
1892 if (obj->otyp != save_otyp) {
1893 makeknown(POT_POLYMORPH);
1894 useup(potion);
1895 prinv((char *) 0, obj, 0L);
1896 return 1;
1897 } else {
1898 pline("Nothing seems to happen.");
1899 goto poof;
1902 potion->in_use = FALSE; /* didn't go poof */
1903 return 1;
1904 } else if (obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) {
1905 int amt = (int) obj->quan;
1906 boolean magic;
1908 mixture = mixtype(obj, potion);
1910 magic = (mixture != STRANGE_OBJECT) ? objects[mixture].oc_magic
1911 : (objects[obj->otyp].oc_magic || objects[potion->otyp].oc_magic);
1912 Strcpy(qbuf, "The"); /* assume full stack */
1913 if (amt > (magic ? 3 : 7)) {
1914 /* trying to dip multiple potions will usually affect only a
1915 subset; pick an amount between 3 and 8, inclusive, for magic
1916 potion result, between 7 and N for non-magic */
1917 if (magic)
1918 amt = rnd(min(amt, 8) - (3 - 1)) + (3 - 1); /* 1..6 + 2 */
1919 else
1920 amt = rnd(amt - (7 - 1)) + (7 - 1); /* 1..(N-6) + 6 */
1922 if ((long) amt < obj->quan) {
1923 obj = splitobj(obj, (long) amt);
1924 Sprintf(qbuf, "%ld of the", obj->quan);
1927 /* [N of] the {obj(s)} mix(es) with [one of] {the potion}... */
1928 pline("%s %s %s with %s%s...", qbuf, simpleonames(obj),
1929 otense(obj, "mix"), (potion->quan > 1L) ? "one of " : "",
1930 thesimpleoname(potion));
1931 /* Mixing potions is dangerous...
1932 KMH, balance patch -- acid is particularly unstable */
1933 if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) {
1934 /* it would be better to use up the whole stack in advance
1935 of the message, but we can't because we need to keep it
1936 around for potionbreathe() [and we can't set obj->in_use
1937 to 'amt' because that's not implemented] */
1938 obj->in_use = 1;
1939 pline("BOOM! They explode!");
1940 wake_nearto(u.ux, u.uy, (BOLT_LIM + 1) * (BOLT_LIM + 1));
1941 exercise(A_STR, FALSE);
1942 if (!breathless(youmonst.data) || haseyes(youmonst.data))
1943 potionbreathe(obj);
1944 useupall(obj);
1945 useup(potion);
1946 losehp(amt + rnd(9), /* not physical damage */
1947 "alchemic blast", KILLED_BY_AN);
1948 return 1;
1951 obj->blessed = obj->cursed = obj->bknown = 0;
1952 if (Blind || Hallucination)
1953 obj->dknown = 0;
1955 if (mixture != STRANGE_OBJECT) {
1956 obj->otyp = mixture;
1957 } else {
1958 switch (obj->odiluted ? 1 : rnd(8)) {
1959 case 1:
1960 obj->otyp = POT_WATER;
1961 break;
1962 case 2:
1963 case 3:
1964 obj->otyp = POT_SICKNESS;
1965 break;
1966 case 4: {
1967 struct obj *otmp = mkobj(POTION_CLASS, FALSE);
1969 obj->otyp = otmp->otyp;
1970 obfree(otmp, (struct obj *) 0);
1971 break;
1973 default:
1974 useupall(obj);
1975 useup(potion);
1976 if (!Blind)
1977 pline_The("mixture glows brightly and evaporates.");
1978 return 1;
1981 obj->odiluted = (obj->otyp != POT_WATER);
1983 if (obj->otyp == POT_WATER && !Hallucination) {
1984 pline_The("mixture bubbles%s.", Blind ? "" : ", then clears");
1985 } else if (!Blind) {
1986 pline_The("mixture looks %s.",
1987 hcolor(OBJ_DESCR(objects[obj->otyp])));
1990 useup(potion);
1991 /* this is required when 'obj' was split off from a bigger stack,
1992 so that 'obj' will now be assigned its own inventory slot;
1993 it has a side-effect of merging 'obj' into another compatible
1994 stack if there is one, so we do it even when no split has
1995 been made in order to get the merge result for both cases;
1996 as a consequence, mixing while Fumbling drops the mixture */
1997 freeinv(obj);
1998 (void) hold_another_object(obj, "You drop %s!", doname(obj),
1999 (const char *) 0);
2000 return 1;
2003 if (potion->otyp == POT_ACID && obj->otyp == CORPSE
2004 && obj->corpsenm == PM_LICHEN && !Blind) {
2005 pline("%s %s %s around the edges.", The(cxname(obj)),
2006 otense(obj, "turn"),
2007 potion->odiluted ? hcolor(NH_ORANGE) : hcolor(NH_RED));
2008 potion->in_use = FALSE; /* didn't go poof */
2009 return 1;
2012 if (potion->otyp == POT_WATER && obj->otyp == TOWEL) {
2013 pline_The("towel soaks it up!");
2014 /* wetting towel already done via water_damage() in H2Opotion_dip */
2015 goto poof;
2018 if (is_poisonable(obj)) {
2019 if (potion->otyp == POT_SICKNESS && !obj->opoisoned) {
2020 char buf[BUFSZ];
2022 if (potion->quan > 1L)
2023 Sprintf(buf, "One of %s", the(xname(potion)));
2024 else
2025 Strcpy(buf, The(xname(potion)));
2026 pline("%s forms a coating on %s.", buf, the(xname(obj)));
2027 obj->opoisoned = TRUE;
2028 goto poof;
2029 } else if (obj->opoisoned && (potion->otyp == POT_HEALING
2030 || potion->otyp == POT_EXTRA_HEALING
2031 || potion->otyp == POT_FULL_HEALING)) {
2032 pline("A coating wears off %s.", the(xname(obj)));
2033 obj->opoisoned = 0;
2034 goto poof;
2038 if (potion->otyp == POT_ACID) {
2039 if (erode_obj(obj, 0, ERODE_CORRODE, EF_GREASE) != ER_NOTHING)
2040 goto poof;
2043 if (potion->otyp == POT_OIL) {
2044 boolean wisx = FALSE;
2046 if (potion->lamplit) { /* burning */
2047 fire_damage(obj, TRUE, u.ux, u.uy);
2048 } else if (potion->cursed) {
2049 pline_The("potion spills and covers your %s with oil.",
2050 makeplural(body_part(FINGER)));
2051 incr_itimeout(&Glib, d(2, 10));
2052 } else if (obj->oclass != WEAPON_CLASS && !is_weptool(obj)) {
2053 /* the following cases apply only to weapons */
2054 goto more_dips;
2055 /* Oil removes rust and corrosion, but doesn't unburn.
2056 * Arrows, etc are classed as metallic due to arrowhead
2057 * material, but dipping in oil shouldn't repair them.
2059 } else if ((!is_rustprone(obj) && !is_corrodeable(obj))
2060 || is_ammo(obj) || (!obj->oeroded && !obj->oeroded2)) {
2061 /* uses up potion, doesn't set obj->greased */
2062 pline("%s %s with an oily sheen.", Yname2(obj),
2063 otense(obj, "gleam"));
2064 } else {
2065 pline("%s %s less %s.", Yname2(obj), otense(obj, "are"),
2066 (obj->oeroded && obj->oeroded2)
2067 ? "corroded and rusty"
2068 : obj->oeroded ? "rusty" : "corroded");
2069 if (obj->oeroded > 0)
2070 obj->oeroded--;
2071 if (obj->oeroded2 > 0)
2072 obj->oeroded2--;
2073 wisx = TRUE;
2075 exercise(A_WIS, wisx);
2076 makeknown(potion->otyp);
2077 useup(potion);
2078 return 1;
2080 more_dips:
2082 /* Allow filling of MAGIC_LAMPs to prevent identification by player */
2083 if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP)
2084 && (potion->otyp == POT_OIL)) {
2085 /* Turn off engine before fueling, turn off fuel too :-) */
2086 if (obj->lamplit || potion->lamplit) {
2087 useup(potion);
2088 explode(u.ux, u.uy, 11, d(6, 6), 0, EXPL_FIERY);
2089 exercise(A_WIS, FALSE);
2090 return 1;
2092 /* Adding oil to an empty magic lamp renders it into an oil lamp */
2093 if ((obj->otyp == MAGIC_LAMP) && obj->spe == 0) {
2094 obj->otyp = OIL_LAMP;
2095 obj->age = 0;
2097 if (obj->age > 1000L) {
2098 pline("%s %s full.", Yname2(obj), otense(obj, "are"));
2099 potion->in_use = FALSE; /* didn't go poof */
2100 } else {
2101 You("fill %s with oil.", yname(obj));
2102 check_unpaid(potion); /* Yendorian Fuel Tax */
2103 obj->age += 2 * potion->age; /* burns more efficiently */
2104 if (obj->age > 1500L)
2105 obj->age = 1500L;
2106 useup(potion);
2107 exercise(A_WIS, TRUE);
2109 makeknown(POT_OIL);
2110 obj->spe = 1;
2111 update_inventory();
2112 return 1;
2115 potion->in_use = FALSE; /* didn't go poof */
2116 if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST)
2117 && (mixture = mixtype(obj, potion)) != STRANGE_OBJECT) {
2118 char oldbuf[BUFSZ], newbuf[BUFSZ];
2119 short old_otyp = potion->otyp;
2120 boolean old_dknown = FALSE;
2121 boolean more_than_one = potion->quan > 1L;
2123 oldbuf[0] = '\0';
2124 if (potion->dknown) {
2125 old_dknown = TRUE;
2126 Sprintf(oldbuf, "%s ", hcolor(OBJ_DESCR(objects[potion->otyp])));
2128 /* with multiple merged potions, split off one and
2129 just clear it */
2130 if (potion->quan > 1L) {
2131 singlepotion = splitobj(potion, 1L);
2132 } else
2133 singlepotion = potion;
2135 costly_alteration(singlepotion, COST_NUTRLZ);
2136 singlepotion->otyp = mixture;
2137 singlepotion->blessed = 0;
2138 if (mixture == POT_WATER)
2139 singlepotion->cursed = singlepotion->odiluted = 0;
2140 else
2141 singlepotion->cursed = obj->cursed; /* odiluted left as-is */
2142 singlepotion->bknown = FALSE;
2143 if (Blind) {
2144 singlepotion->dknown = FALSE;
2145 } else {
2146 singlepotion->dknown = !Hallucination;
2147 if (mixture == POT_WATER && singlepotion->dknown)
2148 Sprintf(newbuf, "clears");
2149 else
2150 Sprintf(newbuf, "turns %s",
2151 hcolor(OBJ_DESCR(objects[mixture])));
2152 pline_The("%spotion%s %s.", oldbuf,
2153 more_than_one ? " that you dipped into" : "", newbuf);
2154 if (!objects[old_otyp].oc_uname
2155 && !objects[old_otyp].oc_name_known && old_dknown) {
2156 struct obj fakeobj;
2157 fakeobj = zeroobj;
2158 fakeobj.dknown = 1;
2159 fakeobj.otyp = old_otyp;
2160 fakeobj.oclass = POTION_CLASS;
2161 docall(&fakeobj);
2164 obj_extract_self(singlepotion);
2165 singlepotion =
2166 hold_another_object(singlepotion, "You juggle and drop %s!",
2167 doname(singlepotion), (const char *) 0);
2168 update_inventory();
2169 return 1;
2172 pline("Interesting...");
2173 return 1;
2175 poof:
2176 if (!objects[potion->otyp].oc_name_known
2177 && !objects[potion->otyp].oc_uname)
2178 docall(potion);
2179 useup(potion);
2180 return 1;
2183 /* *monp grants a wish and then leaves the game */
2184 void
2185 mongrantswish(monp)
2186 struct monst **monp;
2188 struct monst *mon = *monp;
2189 int mx = mon->mx, my = mon->my, glyph = glyph_at(mx, my);
2191 /* remove the monster first in case wish proves to be fatal
2192 (blasted by artifact), to keep it out of resulting bones file */
2193 mongone(mon);
2194 *monp = 0; /* inform caller that monster is gone */
2195 /* hide that removal from player--map is visible during wish prompt */
2196 tmp_at(DISP_ALWAYS, glyph);
2197 tmp_at(mx, my);
2198 /* grant the wish */
2199 makewish();
2200 /* clean up */
2201 tmp_at(DISP_END, 0);
2204 void
2205 djinni_from_bottle(obj)
2206 struct obj *obj;
2208 struct monst *mtmp;
2209 int chance;
2211 if (!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))) {
2212 pline("It turns out to be empty.");
2213 return;
2216 if (!Blind) {
2217 pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp));
2218 pline("%s speaks.", Monnam(mtmp));
2219 } else {
2220 You("smell acrid fumes.");
2221 pline("%s speaks.", Something);
2224 chance = rn2(5);
2225 if (obj->blessed)
2226 chance = (chance == 4) ? rnd(4) : 0;
2227 else if (obj->cursed)
2228 chance = (chance == 0) ? rn2(4) : 4;
2229 /* 0,1,2,3,4: b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */
2231 switch (chance) {
2232 case 0:
2233 verbalize("I am in your debt. I will grant one wish!");
2234 /* give a wish and discard the monster (mtmp set to null) */
2235 mongrantswish(&mtmp);
2236 break;
2237 case 1:
2238 verbalize("Thank you for freeing me!");
2239 (void) tamedog(mtmp, (struct obj *) 0);
2240 break;
2241 case 2:
2242 verbalize("You freed me!");
2243 mtmp->mpeaceful = TRUE;
2244 set_malign(mtmp);
2245 break;
2246 case 3:
2247 verbalize("It is about time!");
2248 if (canspotmon(mtmp))
2249 pline("%s vanishes.", Monnam(mtmp));
2250 mongone(mtmp);
2251 break;
2252 default:
2253 verbalize("You disturbed me, fool!");
2254 mtmp->mpeaceful = FALSE;
2255 set_malign(mtmp);
2256 break;
2260 /* clone a gremlin or mold (2nd arg non-null implies heat as the trigger);
2261 hit points are cut in half (odd HP stays with original) */
2262 struct monst *
2263 split_mon(mon, mtmp)
2264 struct monst *mon, /* monster being split */
2265 *mtmp; /* optional attacker whose heat triggered it */
2267 struct monst *mtmp2;
2268 char reason[BUFSZ];
2270 reason[0] = '\0';
2271 if (mtmp)
2272 Sprintf(reason, " from %s heat",
2273 (mtmp == &youmonst) ? the_your[1]
2274 : (const char *) s_suffix(mon_nam(mtmp)));
2276 if (mon == &youmonst) {
2277 mtmp2 = cloneu();
2278 if (mtmp2) {
2279 mtmp2->mhpmax = u.mhmax / 2;
2280 u.mhmax -= mtmp2->mhpmax;
2281 context.botl = 1;
2282 You("multiply%s!", reason);
2284 } else {
2285 mtmp2 = clone_mon(mon, 0, 0);
2286 if (mtmp2) {
2287 mtmp2->mhpmax = mon->mhpmax / 2;
2288 mon->mhpmax -= mtmp2->mhpmax;
2289 if (canspotmon(mon))
2290 pline("%s multiplies%s!", Monnam(mon), reason);
2293 return mtmp2;
2296 /*potion.c*/