1 /* NetHack 3.6 potion.c $NHDT-Date: 1455407631 2016/02/13 23:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.129 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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
);
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 */
32 /* increment `old' by `incr' and force result to be valid intrinsic timeout */
34 itimeout_incr(old
, incr
)
38 return itimeout((old
& TIMEOUT
) + (long) incr
);
41 /* set the timeout field of intrinsic `which' */
43 set_itimeout(which
, val
)
47 *which
|= itimeout(val
);
50 /* increment the timeout field of intrinsic `which' */
52 incr_itimeout(which
, incr
)
56 set_itimeout(which
, itimeout_incr(*which
, incr
));
60 make_confused(xtime
, talk
)
64 long old
= HConfusion
;
71 You_feel("less %s now.", Hallucination
? "trippy" : "confused");
73 if ((xtime
&& !old
) || (!xtime
&& old
))
76 set_itimeout(&HConfusion
, xtime
);
80 make_stunned(xtime
, talk
)
92 Hallucination
? "less wobbly" : "a bit steadier");
97 You("wobble in the saddle.");
99 You("%s...", stagger(youmonst
.data
, "stagger"));
102 if ((!xtime
&& old
) || (xtime
&& !old
))
105 set_itimeout(&HStun
, xtime
);
109 make_sick(xtime
, cause
, talk
, type
)
111 const char *cause
; /* sickness cause */
126 You_feel("deathly sick.");
130 You_feel("%s worse.", xtime
<= Sick
/ 2L ? "much" : "even");
132 set_itimeout(&Sick
, xtime
);
133 u
.usick_type
|= type
;
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 */
140 You_feel("somewhat better.");
141 set_itimeout(&Sick
, Sick
* 2); /* approximation */
144 You_feel("cured. What a relief!");
145 Sick
= 0L; /* set_itimeout(&Sick, 0L) */
151 exercise(A_CON
, FALSE
);
152 delayed_killer(SICK
, KILLED_BY_AN
, cause
);
154 dealloc_killer(find_delayed_killer(SICK
));
158 make_slimed(xtime
, msg
)
168 set_itimeout(&Slimed
, xtime
);
169 if ((xtime
!= 0L) ^ (old
!= 0L)) {
175 dealloc_killer(find_delayed_killer(SLIMED
));
178 /* start or stop petrification */
180 make_stoned(xtime
, msg
, killedby
, killername
)
184 const char *killername
;
192 set_itimeout(&Stoned
, xtime
);
193 if ((xtime
!= 0L) ^ (old
!= 0L)) {
199 dealloc_killer(find_delayed_killer(STONED
));
201 delayed_killer(STONED
, killedby
, killername
);
205 make_vomiting(xtime
, talk
)
214 set_itimeout(&Vomiting
, xtime
);
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.";
225 make_blinded(xtime
, talk
)
230 boolean u_could_see
, can_see_now
;
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 */
243 if (can_see_now
&& !u_could_see
) { /* regaining sight */
246 pline("Far out! Everything is all cosmic again!");
248 You("can see again.");
250 } else if (old
&& !xtime
) {
251 /* clearing temporary blindness without toggling blindness */
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 */
269 pline("Oh, bummer! Everything is dark! Help!");
271 pline("A cloud of darkness falls upon you.");
273 /* Before the hero goes blind, set the ball&chain variables. */
276 } else if (!old
&& xtime
) {
277 /* setting temporary blindness without toggling blindness */
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 */
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") */
304 if (Blind_telepat
|| Infravision
)
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)
315 /* update dknown flag for inventory picked up while blind */
317 learn_unseen_invent();
322 make_hallucinated(xtime
, talk
, mask
)
323 long xtime
; /* nonzero if this is an attempt to turn on hallucination */
325 long mask
; /* nonzero if resistance status should change by mask */
327 long old
= HHallucination
;
329 const char *message
, *verb
;
334 message
= (!xtime
) ? "Everything %s SO boring now."
335 : "Oh wow! Everything %s so cosmic!";
336 verb
= (!Blind
) ? "looks" : "feels";
343 EHalluc_resistance
|= mask
;
345 EHalluc_resistance
&= ~mask
;
347 if (!EHalluc_resistance
&& (!!HHallucination
!= !!xtime
))
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);
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");
368 /* in case we're mimicking an orange (hallucinatory form
369 of mimicking gold) update the mimicking's-over message */
374 swallowed(0); /* redraw swallow display */
376 /* The see_* routines should be called *before* the pline. */
382 /* for perm_inv and anything similar
383 (eg. Qt windowport's equipped items display) */
388 pline(message
, verb
);
394 make_deaf(xtime
, talk
)
403 set_itimeout(&HDeaf
, xtime
);
404 if ((xtime
!= 0L) ^ (old
!= 0L)) {
407 You(old
? "can hear again." : "are unable to hear anything.");
414 struct monst
*mtmp
= makemon(&mons
[PM_GHOST
], u
.ux
, u
.uy
, NO_MM_FLAGS
);
417 pline("This bottle turns out to be empty.");
421 pline("As you open the bottle, %s emerges.", something
);
424 pline("As you open the bottle, an enormous %s emerges!",
425 Hallucination
? rndmonnam(NULL
) : (const char *) "ghost");
427 You("are frightened to death, and unable to move.");
429 multi_reason
= "being frightened to death";
430 nomovemsg
= "You regain your composure.";
433 /* "Quaffing is like drinking, except you spill more." - Terry Pratchett */
437 register struct obj
*otmp
;
438 const char *potion_descr
;
441 pline("If you can't breathe air, how can you drink liquid?");
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') {
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') {
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?");
470 otmp
= getobj(beverages
, "drink");
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
]);
492 if (!strcmp(potion_descr
, "milky")
493 && !(mvitals
[PM_GHOST
].mvflags
& G_GONE
)
494 && !rn2(POTION_OCCUPANT_CHANCE(mvitals
[PM_GHOST
].born
))) {
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
);
506 return dopotion(otmp
);
511 register struct obj
*otmp
;
517 if ((retval
= peffects(otmp
)) >= 0)
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
) {
527 makeknown(otmp
->otyp
);
528 more_experienced(0, 10);
529 } else if (!objects
[otmp
->otyp
].oc_uname
)
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
:
547 pline("Ulch! This makes you feel mediocre!");
550 /* unlike unicorn horn, overrides Fixed_abil */
551 pline("Wow! This makes you feel %s!",
553 ? (unfixable_trouble_count(FALSE
) ? "better" : "great")
555 i
= rn2(A_MAX
); /* start at a random point */
556 for (ii
= 0; ii
< A_MAX
; ii
++) {
558 if (i
== A_STR
&& u
.uhs
>= 3)
560 if (ABASE(i
) < lim
) {
563 /* only first found if not blessed */
572 case POT_HALLUCINATION
:
573 if (Hallucination
|| Halluc_resistance
)
575 (void) make_hallucinated(
576 itimeout_incr(HHallucination
, rn1(200, 600 - 300 * bcsign(otmp
))),
580 if (!otmp
->blessed
&& !otmp
->cursed
) {
581 pline("This tastes like %s.", hliquid("water"));
582 u
.uhunger
+= rnd(10);
587 if (is_undead(youmonst
.data
) || is_demon(youmonst
.data
)
588 || u
.ualign
.type
== A_CHAOTIC
) {
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
])
597 set_ulycn(NON_PM
); /* cure lycanthropy */
599 losehp(Maybe_Half_Phys(d(2, 6)), "potion of holy water",
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
)
606 exercise(A_CON
, TRUE
);
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); */
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",
623 You_feel("full of dread.");
624 if (u
.ulycn
>= LOW_PM
&& !Upolyd
)
626 exercise(A_CON
, FALSE
);
632 pline("Ooph! This tastes like %s%s!",
633 otmp
->odiluted
? "watered down " : "",
634 Hallucination
? "dandelion wine" : "liquid fire");
636 make_confused(itimeout_incr(HConfusion
, d(3, 8)), FALSE
);
637 /* the whiskey makes us feel better */
639 healup(1, 0, FALSE
, FALSE
);
640 u
.uhunger
+= 10 * (2 + bcsign(otmp
));
642 exercise(A_WIS
, FALSE
);
646 nomovemsg
= "You awake with a headache.";
649 case POT_ENLIGHTENMENT
:
652 You("have an uneasy feeling...");
653 exercise(A_WIS
, FALSE
);
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
);
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
));
673 case POT_INVISIBILITY
:
674 if (Invis
|| Blind
|| BInvis
) {
677 self_invis_message();
680 HInvis
|= FROMOUTSIDE
;
682 incr_itimeout(&HInvis
, rn1(15, 31));
683 newsym(u
.ux
, u
.uy
); /* update position */
685 pline("For some reason, you feel your presence is known.");
689 case POT_SEE_INVISIBLE
: /* tastes like fruit juice in Rogue */
690 case POT_FRUIT_JUICE
: {
691 int msg
= Invisible
&& !Blind
;
695 pline("Yecch! This tastes %s.",
696 Hallucination
? "overripe" : "rotten");
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
));
709 /* Tell them they can see again immediately, which
710 * will help them identify the potion...
712 make_blinded(0L, TRUE
);
715 HSee_invisible
|= FROMOUTSIDE
;
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!");
729 You("stiffen momentarily.");
731 if (Levitation
|| Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
))
732 You("are motionlessly suspended.");
734 You("are frozen in place!");
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
);
745 if (Sleep_resistance
|| Free_action
) {
748 You("suddenly fall asleep!");
749 fall_asleep(-rn1(10, 25 - 12 * bcsign(otmp
)), TRUE
);
752 case POT_MONSTER_DETECTION
:
753 case SPE_DETECT_MONSTERS
:
760 /* after a while, repeated uses become less effective */
761 if ((HDetect_monsters
& TIMEOUT
) >= 300L)
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
) {
781 if (monster_detect(otmp
, 0))
782 return 1; /* nothing detected */
783 exercise(A_WIS
, TRUE
);
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
);
792 pline("Yecch! This stuff tastes like poison.");
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
);
800 if (Poison_resistance
)
801 pline("(But in fact it was biologically contaminated %s.)",
803 if (Role_if(PM_HEALER
)) {
804 pline("Fortunately, you have been immunized.");
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");
814 poisontell(typ
, FALSE
);
815 (void) adjattrib(typ
, Poison_resistance
? -1 : -rn1(4, 3),
818 if (!Poison_resistance
) {
820 losehp(rnd(10) + 5 * !!(otmp
->cursed
), contaminant
,
823 losehp(rnd(10) + 5 * !!(otmp
->cursed
), contaminant
,
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
);
834 You("are shocked back to your senses!");
835 (void) make_hallucinated(0L, FALSE
, 0L);
841 pline("What a trippy feeling!");
844 pline("Huh, What? Where am I?");
847 make_confused(itimeout_incr(HConfusion
,
848 rn1(7, 16 - 8 * bcsign(otmp
))),
851 case POT_GAIN_ABILITY
:
853 pline("Ulch! That potion tasted foul!");
855 } else if (Fixed_abil
) {
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
)
872 if (Wounded_legs
&& !otmp
->cursed
&& !u
.usteed
) {
873 /* heal_legs() would heal steeds legs */
880 if (!Very_fast
) { /* wwf@doe.carleton.ca */
881 You("are suddenly moving %sfaster.", Fast
? "" : "much ");
883 Your("%s get new energy.", makeplural(body_part(LEG
)));
886 exercise(A_DEX
, TRUE
);
887 incr_itimeout(&HFast
, rn1(10, 100 + 60 * bcsign(otmp
)));
892 make_blinded(itimeout_incr(Blinded
,
893 rn1(200, 250 - 125 * bcsign(otmp
))),
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
);
908 register int newlev
= depth(&u
.uz
) - 1;
911 get_level(&newlevel
, newlev
);
912 if (on_level(&newlevel
, &u
.uz
)) {
913 pline("It tasted bad.");
916 You(riseup
, ceiling(u
.ux
, u
.uy
));
917 goto_level(&newlevel
, FALSE
, FALSE
, FALSE
);
920 You("have an uneasy feeling.");
924 /* blessed potions place you at a random spot in the
925 middle of the new level instead of the low point */
927 u
.uexp
= rndexp(TRUE
);
931 healup(d(6 + 2 * bcsign(otmp
), 4), !otmp
->cursed
? 1 : 0,
932 !!otmp
->blessed
, !otmp
->cursed
);
933 exercise(A_CON
, TRUE
);
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
,
940 (void) make_hallucinated(0L, TRUE
, 0L);
941 exercise(A_CON
, TRUE
);
942 exercise(A_STR
, TRUE
);
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 */
954 (void) make_hallucinated(0L, TRUE
, 0L);
955 exercise(A_STR
, TRUE
);
956 exercise(A_CON
, TRUE
);
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
967 if (!Levitation
&& !BLevitation
) {
968 /* kludge to ensure proper operation of float_up() */
969 set_itimeout(&HLevitation
, 1L);
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 */
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 */
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
)) {
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",
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
))
1012 /* levitating blocks flying */
1015 case POT_GAIN_ENERGY
: { /* M. Stephenson */
1019 You_feel("lackluster.");
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)
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);
1034 num
= -num
; /* subtract instead of add when cursed */
1039 if (u
.uen
> u
.uenmax
)
1041 else if (u
.uen
<= 0)
1044 exercise(A_WIS
, TRUE
);
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
;
1055 You("burn your %s.", body_part(FACE
));
1057 losehp(d(Fire_resistance
? 1 : 3, 4), "burning potion of oil",
1060 } else if (otmp
->cursed
)
1061 pline("This tastes like castor oil.");
1063 pline("That was smooth!");
1064 exercise(A_WIS
, good_for_you
);
1068 if (Acid_resistance
) {
1069 /* Not necessarily a creature who _likes_ acid */
1070 pline("This tastes %s.", Hallucination
? "tangy" : "sour");
1074 pline("This burns%s!",
1075 otmp
->blessed
? " a little" : otmp
->cursed
? " a lot"
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
);
1082 fix_petrification();
1083 unkn
++; /* holy/unholy water can burn like acid too */
1086 You_feel("a little %s.", Hallucination
? "normal" : "strange");
1091 impossible("What a funny potion! (%u)", otmp
->otyp
);
1098 healup(nhp
, nxtra
, curesick
, cureblind
)
1100 register boolean curesick
, cureblind
;
1106 u
.mh
= (u
.mhmax
+= nxtra
);
1109 if (u
.uhp
> u
.uhpmax
)
1110 u
.uhp
= (u
.uhpmax
+= nxtra
);
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 */
1117 make_blinded(0L, TRUE
);
1120 make_vomiting(0L, TRUE
);
1121 make_sick(0L, (char *) 0, TRUE
, SICK_ALL
);
1128 strange_feeling(obj
, txt
)
1132 if (flags
.beginner
|| !txt
)
1133 You("have a %s feeling for a moment, then it passes.",
1134 Hallucination
? "normal" : "strange");
1138 if (!obj
) /* e.g., crystal ball finds no traps */
1141 if (obj
->dknown
&& !objects
[obj
->otyp
].oc_name_known
1142 && !objects
[obj
->otyp
].oc_uname
)
1148 const char *bottlenames
[] = { "bottle", "phial", "flagon", "carafe",
1149 "flask", "jar", "vial" };
1154 return bottlenames
[rn2(SIZE(bottlenames
))];
1157 /* handle item dipped into water potion or steed saddle splashed by same */
1159 H2Opotion_dip(potion
, targobj
, useeit
, objphrase
)
1160 struct obj
*potion
, *targobj
;
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
)
1174 if (potion
->blessed
) {
1175 if (targobj
->cursed
) {
1177 glowcolor
= NH_AMBER
;
1178 costchange
= COST_UNCURS
;
1179 } else if (!targobj
->blessed
) {
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
) {
1188 glowcolor
= "brown";
1189 costchange
= COST_UNBLSS
;
1190 } else if (!targobj
->cursed
) {
1192 glowcolor
= NH_BLACK
;
1193 costchange
= COST_alter
;
1197 /* dipping into uncursed water; carried() check skips steed saddle */
1198 if (carried(targobj
)) {
1199 if (water_damage(targobj
, 0, TRUE
) != ER_NOTHING
)
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 */
1209 glowcolor
= hcolor(glowcolor
);
1211 pline("%s with %s aura.", objphrase
, an(glowcolor
));
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 */
1237 potionhit(mon
, obj
, your_fault
)
1238 register struct monst
*mon
;
1239 register struct obj
*obj
;
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
;
1249 tx
= u
.ux
, ty
= u
.uy
;
1251 pline_The("%s crashes on your %s and breaks into shards.", botlnam
,
1253 losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN
);
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
)))
1260 || (obj
->otyp
== POT_WATER
1261 && ((rnl(10) > 7 && obj
->cursed
)
1262 || (rnl(10) < 4 && obj
->blessed
) || !rn2(3)))))
1264 distance
= distu(tx
, ty
);
1265 if (!cansee(tx
, ty
)) {
1268 char *mnam
= mon_nam(mon
);
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
),
1276 } else if (has_head(mon
->data
)) {
1277 Sprintf(buf
, "%s %s", s_suffix(mnam
),
1278 (notonhead
? "body" : "head"));
1282 pline_The("%s crashes on %s and breaks into shards.", botlnam
,
1285 if (rn2(5) && mon
->mhp
> 1 && !hit_saddle
)
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"));
1294 switch (obj
->otyp
) {
1297 explode_oil(obj
, u
.ux
, u
.uy
);
1300 You_feel("a little %s.", Hallucination
? "normal" : "strange");
1301 if (!Unchanging
&& !Antimagic
)
1305 if (!Acid_resistance
) {
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
);
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
) {
1326 Sprintf(saddle_glows
, "%s %s", buf
, aobjnam(saddle
, "glow"));
1327 affected
= H2Opotion_dip(obj
, saddle
, useeit
, saddle_glows
);
1330 /* Do we allow the saddle to polymorph? */
1333 if (useeit
&& !affected
)
1334 pline("%s %s wet.", buf
, aobjnam(saddle
, "get"));
1336 boolean angermon
= your_fault
;
1338 switch (obj
->otyp
) {
1340 case POT_EXTRA_HEALING
:
1341 case POT_FULL_HEALING
:
1342 if (mon
->data
== &mons
[PM_PESTILENCE
])
1345 case POT_RESTORE_ABILITY
:
1346 case POT_GAIN_ABILITY
:
1349 if (mon
->mhp
< mon
->mhpmax
) {
1350 mon
->mhp
= mon
->mhpmax
;
1352 pline("%s looks sound and hale again.", Monnam(mon
));
1356 if (mon
->data
== &mons
[PM_PESTILENCE
])
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
)) {
1364 pline("%s looks unharmed.", Monnam(mon
));
1368 if ((mon
->mhpmax
> 3) && !resist(mon
, POTION_CLASS
, 0, NOTELL
))
1370 if ((mon
->mhp
> 2) && !resist(mon
, POTION_CLASS
, 0, NOTELL
))
1372 if (mon
->mhp
> mon
->mhpmax
)
1373 mon
->mhp
= mon
->mhpmax
;
1375 pline("%s looks rather ill.", Monnam(mon
));
1379 if (!resist(mon
, POTION_CLASS
, 0, NOTELL
))
1382 case POT_INVISIBILITY
: {
1383 boolean sawit
= canspotmon(mon
);
1386 mon_set_minvis(mon
);
1387 if (sawit
&& !canspotmon(mon
) && cansee(mon
->mx
, mon
->my
))
1388 map_invisible(mon
->mx
, mon
->my
);
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
));
1399 if (mon
->mcanmove
) {
1400 /* really should be rnd(5) for consistency with players
1401 * breathing potions, but...
1403 paralyze_monst(mon
, rnd(25));
1408 mon_adjust_speed(mon
, 1, obj
);
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);
1421 if (is_undead(mon
->data
) || is_demon(mon
->data
)
1422 || is_were(mon
->data
) || is_vampshifter(mon
)) {
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 */
1432 else if (is_were(mon
->data
) && !is_human(mon
->data
))
1433 new_were(mon
); /* revert to human */
1434 } else if (obj
->cursed
) {
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
]) {
1447 (void) split_mon(mon
, (struct monst
*) 0);
1448 } else if (mon
->data
== &mons
[PM_IRON_GOLEM
]) {
1450 pline("%s rusts.", Monnam(mon
));
1451 mon
->mhp
-= d(1, 6);
1452 /* should only be by you */
1459 explode_oil(obj
, tx
, ty
);
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);
1472 monkilled(mon
, "", AD_ACID
);
1477 (void) bhitm(mon
, obj
);
1480 case POT_GAIN_LEVEL:
1481 case POT_LEVITATION:
1482 case POT_FRUIT_JUICE:
1483 case POT_MONSTER_DETECTION:
1484 case POT_OBJECT_DETECTION:
1488 /* target might have been killed */
1497 /* Note: potionbreathe() does its own docall() */
1498 if ((distance
== 0 || (distance
< 3 && rn2(5)))
1499 && (!breathless(youmonst
.data
) || haseyes(youmonst
.data
)))
1501 else if (obj
->dknown
&& !objects
[obj
->otyp
].oc_name_known
1502 && !objects
[obj
->otyp
].oc_uname
&& cansee(tx
, ty
))
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 */
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
,
1519 obfree(obj
, (struct obj
*) 0);
1522 /* vapors are inhaled or get in your eyes */
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
:
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"));
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
)) {
1548 /* only first found if not blessed */
1549 isdone
= !(obj
->blessed
);
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;
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;
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
);
1577 if (!Role_if(PM_HEALER
)) {
1590 exercise(A_CON
, FALSE
);
1593 case POT_HALLUCINATION
:
1594 You("have a momentary vision.");
1599 You_feel("somewhat dizzy.");
1600 make_confused(itimeout_incr(HConfusion
, rnd(5)), FALSE
);
1602 case POT_INVISIBILITY
:
1603 if (!Blind
&& !Invis
) {
1605 pline("For an instant you %s!",
1606 See_invisible
? "could see right through yourself"
1607 : "couldn't see yourself");
1613 pline("%s seems to be holding you.", Something
);
1615 multi_reason
= "frozen by a potion";
1616 nomovemsg
= You_can_move_again
;
1617 exercise(A_DEX
, FALSE
);
1619 You("stiffen momentarily.");
1623 if (!Free_action
&& !Sleep_resistance
) {
1624 You_feel("rather tired.");
1626 multi_reason
= "sleeping off a magical draught";
1627 nomovemsg
= You_can_move_again
;
1628 exercise(A_DEX
, FALSE
);
1634 Your("knees seem more flexible now.");
1635 incr_itimeout(&HFast
, rnd(5));
1636 exercise(A_DEX
, TRUE
);
1639 if (!Blind
&& !Unaware
) {
1641 pline("It suddenly gets dark.");
1643 make_blinded(itimeout_incr(Blinded
, rnd(5)), FALSE
);
1644 if (!Blind
&& !Unaware
)
1645 Your1(vision_clears
);
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
])
1655 else if (obj
->cursed
&& !Upolyd
)
1661 exercise(A_CON
, FALSE
);
1664 case POT_GAIN_LEVEL:
1665 case POT_LEVITATION:
1666 case POT_FRUIT_JUICE:
1667 case POT_MONSTER_DETECTION:
1668 case POT_OBJECT_DETECTION:
1673 /* note: no obfree() */
1676 makeknown(obj
->otyp
);
1677 else if (!objects
[obj
->otyp
].oc_name_known
1678 && !objects
[obj
->otyp
].oc_uname
)
1683 /* returns the potion type when o1 is dipped in 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
)) {
1705 case POT_GAIN_LEVEL
:
1706 case POT_GAIN_ENERGY
:
1707 return POT_EXTRA_HEALING
;
1709 case POT_EXTRA_HEALING
:
1711 case POT_GAIN_LEVEL
:
1712 case POT_GAIN_ENERGY
:
1713 return POT_FULL_HEALING
;
1715 case POT_FULL_HEALING
:
1717 case POT_GAIN_LEVEL
:
1718 case POT_GAIN_ENERGY
:
1719 return POT_GAIN_ABILITY
;
1724 return POT_FRUIT_JUICE
;
1725 case POT_HALLUCINATION
:
1731 case AMETHYST
: /* "a-methyst" == "not intoxicated" */
1732 if (o2
->otyp
== POT_BOOZE
)
1733 return POT_FRUIT_JUICE
;
1735 case POT_GAIN_LEVEL
:
1736 case POT_GAIN_ENERGY
:
1739 return (rn2(3) ? POT_BOOZE
: POT_ENLIGHTENMENT
);
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
;
1749 return POT_HALLUCINATION
;
1752 case POT_FRUIT_JUICE
:
1755 return POT_SICKNESS
;
1756 case POT_ENLIGHTENMENT
:
1759 case POT_GAIN_LEVEL
:
1760 case POT_GAIN_ENERGY
:
1761 return POT_SEE_INVISIBLE
;
1764 case POT_ENLIGHTENMENT
:
1766 case POT_LEVITATION
:
1768 return POT_GAIN_LEVEL
;
1770 case POT_FRUIT_JUICE
:
1773 return POT_CONFUSION
;
1778 return STRANGE_OBJECT
;
1785 static const char Dip_
[] = "Dip ";
1786 register struct obj
*potion
, *obj
;
1787 struct obj
*singlepotion
;
1791 char qbuf
[QBUFSZ
], obuf
[QBUFSZ
];
1792 const char *shortestname
; /* last resort obj name for prompt */
1794 allowall
[0] = ALL_CLASSES
;
1796 if (!(obj
= getobj(allowall
, "dip")))
1798 if (inaccessible_equipment(obj
, "dip", FALSE
))
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') {
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') {
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 */
1839 if (obj
->otyp
== POT_ACID
)
1841 if (water_damage(obj
, 0, TRUE
) != ER_DESTROYED
&& obj
->in_use
)
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
);
1853 if (potion
== obj
&& potion
->quan
== 1L) {
1854 pline("That is a potion bottle, not a Klein bottle!");
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
))
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
,
1871 pline1(nothing_happens
);
1873 boolean was_wep
, was_swapwep
, was_quiver
;
1874 short save_otyp
= obj
->otyp
;
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
);
1887 else if (was_swapwep
)
1889 else if (was_quiver
)
1892 if (obj
->otyp
!= save_otyp
) {
1893 makeknown(POT_POLYMORPH
);
1895 prinv((char *) 0, obj
, 0L);
1898 pline("Nothing seems to happen.");
1902 potion
->in_use
= FALSE
; /* didn't go poof */
1904 } else if (obj
->oclass
== POTION_CLASS
&& obj
->otyp
!= potion
->otyp
) {
1905 int amt
= (int) obj
->quan
;
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 */
1918 amt
= rnd(min(amt
, 8) - (3 - 1)) + (3 - 1); /* 1..6 + 2 */
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] */
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
))
1946 losehp(amt
+ rnd(9), /* not physical damage */
1947 "alchemic blast", KILLED_BY_AN
);
1951 obj
->blessed
= obj
->cursed
= obj
->bknown
= 0;
1952 if (Blind
|| Hallucination
)
1955 if (mixture
!= STRANGE_OBJECT
) {
1956 obj
->otyp
= mixture
;
1958 switch (obj
->odiluted
? 1 : rnd(8)) {
1960 obj
->otyp
= POT_WATER
;
1964 obj
->otyp
= POT_SICKNESS
;
1967 struct obj
*otmp
= mkobj(POTION_CLASS
, FALSE
);
1969 obj
->otyp
= otmp
->otyp
;
1970 obfree(otmp
, (struct obj
*) 0);
1977 pline_The("mixture glows brightly and evaporates.");
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
])));
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 */
1998 (void) hold_another_object(obj
, "You drop %s!", doname(obj
),
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 */
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 */
2018 if (is_poisonable(obj
)) {
2019 if (potion
->otyp
== POT_SICKNESS
&& !obj
->opoisoned
) {
2022 if (potion
->quan
> 1L)
2023 Sprintf(buf
, "One of %s", the(xname(potion
)));
2025 Strcpy(buf
, The(xname(potion
)));
2026 pline("%s forms a coating on %s.", buf
, the(xname(obj
)));
2027 obj
->opoisoned
= TRUE
;
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
)));
2038 if (potion
->otyp
== POT_ACID
) {
2039 if (erode_obj(obj
, 0, ERODE_CORRODE
, EF_GREASE
) != ER_NOTHING
)
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 */
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"));
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)
2071 if (obj
->oeroded2
> 0)
2075 exercise(A_WIS
, wisx
);
2076 makeknown(potion
->otyp
);
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
) {
2088 explode(u
.ux
, u
.uy
, 11, d(6, 6), 0, EXPL_FIERY
);
2089 exercise(A_WIS
, FALSE
);
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
;
2097 if (obj
->age
> 1000L) {
2098 pline("%s %s full.", Yname2(obj
), otense(obj
, "are"));
2099 potion
->in_use
= FALSE
; /* didn't go poof */
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)
2107 exercise(A_WIS
, TRUE
);
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;
2124 if (potion
->dknown
) {
2126 Sprintf(oldbuf
, "%s ", hcolor(OBJ_DESCR(objects
[potion
->otyp
])));
2128 /* with multiple merged potions, split off one and
2130 if (potion
->quan
> 1L) {
2131 singlepotion
= splitobj(potion
, 1L);
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;
2141 singlepotion
->cursed
= obj
->cursed
; /* odiluted left as-is */
2142 singlepotion
->bknown
= FALSE
;
2144 singlepotion
->dknown
= FALSE
;
2146 singlepotion
->dknown
= !Hallucination
;
2147 if (mixture
== POT_WATER
&& singlepotion
->dknown
)
2148 Sprintf(newbuf
, "clears");
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
) {
2159 fakeobj
.otyp
= old_otyp
;
2160 fakeobj
.oclass
= POTION_CLASS
;
2164 obj_extract_self(singlepotion
);
2166 hold_another_object(singlepotion
, "You juggle and drop %s!",
2167 doname(singlepotion
), (const char *) 0);
2172 pline("Interesting...");
2176 if (!objects
[potion
->otyp
].oc_name_known
2177 && !objects
[potion
->otyp
].oc_uname
)
2183 /* *monp grants a wish and then leaves the game */
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 */
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
);
2198 /* grant the wish */
2201 tmp_at(DISP_END
, 0);
2205 djinni_from_bottle(obj
)
2211 if (!(mtmp
= makemon(&mons
[PM_DJINNI
], u
.ux
, u
.uy
, NO_MM_FLAGS
))) {
2212 pline("It turns out to be empty.");
2217 pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp
));
2218 pline("%s speaks.", Monnam(mtmp
));
2220 You("smell acrid fumes.");
2221 pline("%s speaks.", Something
);
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 */
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
);
2238 verbalize("Thank you for freeing me!");
2239 (void) tamedog(mtmp
, (struct obj
*) 0);
2242 verbalize("You freed me!");
2243 mtmp
->mpeaceful
= TRUE
;
2247 verbalize("It is about time!");
2248 if (canspotmon(mtmp
))
2249 pline("%s vanishes.", Monnam(mtmp
));
2253 verbalize("You disturbed me, fool!");
2254 mtmp
->mpeaceful
= FALSE
;
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) */
2263 split_mon(mon
, mtmp
)
2264 struct monst
*mon
, /* monster being split */
2265 *mtmp
; /* optional attacker whose heat triggered it */
2267 struct monst
*mtmp2
;
2272 Sprintf(reason
, " from %s heat",
2273 (mtmp
== &youmonst
) ? the_your
[1]
2274 : (const char *) s_suffix(mon_nam(mtmp
)));
2276 if (mon
== &youmonst
) {
2279 mtmp2
->mhpmax
= u
.mhmax
/ 2;
2280 u
.mhmax
-= mtmp2
->mhpmax
;
2282 You("multiply%s!", reason
);
2285 mtmp2
= clone_mon(mon
, 0, 0);
2287 mtmp2
->mhpmax
= mon
->mhpmax
/ 2;
2288 mon
->mhpmax
-= mtmp2
->mhpmax
;
2289 if (canspotmon(mon
))
2290 pline("%s multiplies%s!", Monnam(mon
), reason
);