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