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