ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/potion.c

This is potion.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)potion.c	3.0	88/11/11
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

#ifdef OVLB
static int nothing, unkn;
#endif /* OVLB */

#ifdef WORM

extern boolean notonhead;

#ifdef OVLB

boolean notonhead = FALSE;

#endif /* OVLB */

#endif

#ifdef OVLB

static const char beverages[] = { POTION_SYM, 0 };

void
make_confused(xtime,talk)
long xtime;
boolean talk;
{
	long old = HConfusion;

	if (!xtime && old) {
		if (talk) {
			if (Hallucination) You("feel less trippy now.");
			else		   You("feel less confused now.");
		}
		flags.botl = 1;
	}
	if (xtime && !old)
		flags.botl = 1;
	HConfusion = xtime;
}

void
make_stunned(xtime,talk)
long xtime;
boolean talk;
{
	long old = HStun;

	if (!xtime && old) {
		if (talk) {
			if (Hallucination) You("feel less wobbly now.");
			else		   You("feel a bit steadier now.");
		}
		flags.botl = 1;
	}
	if (xtime && !old) {
		if (talk)
			You("stagger...");
		flags.botl = 1;
	}
	HStun = xtime;
}

void
make_sick(xtime, talk)
long xtime;
boolean talk;
{
	long old = Sick;

#ifdef POLYSELF
	if (xtime && u.usym == S_FUNGUS) return;
#endif
	if (!xtime && old) {
		if (talk) pline("What a relief!");
		flags.botl = 1;
	}
	if (!old && xtime) {
		You("feel deathly sick.");
		flags.botl = 1;
	}
	Sick = xtime;
}

void
make_vomiting(xtime, talk)
long xtime;
boolean talk;
{
	long old = Vomiting;

	if(!xtime && old)
	    if(talk) You("feel much less nauseous now.");

	Vomiting = xtime;
}


void
make_blinded(xtime, talk)
long xtime;
boolean talk;
{
	long old = Blinded;

	if (!xtime && old && !Blindfolded) {
		if (talk) {
			if (Hallucination) pline("Oh, like, wow!  What a rush.");
			else		   You("can see again.");
		}
		flags.botl = 1;
	}
	if (xtime && !old && !Blindfolded) {
		if (talk) {
			if (Hallucination)
				pline("Bummer!  Everything is dark!  Help!");
			else
				pline("A cloud of darkness falls upon you.");
		}
		seeoff(0);
		flags.botl = 1;
	}
	Blinded = xtime;
	if (!Blind)
		setsee();
}

void
make_hallucinated(xtime, talk)
long xtime;
boolean talk;
{
	long old = Hallucination;
	register struct monst *mtmp;

	if (!xtime && old ) {
		if (!Blind && talk) pline("Everything looks SO boring now.");
		for (mtmp=fmon; mtmp; mtmp=mtmp->nmon)
		  if (showmon(mtmp))
		    atl(mtmp->mx, mtmp->my, (!mtmp->m_ap_type ||
					     Protection_from_shape_changers)
			? mtmp->data->mlet : (char) mimic_appearance(mtmp));
		flags.botl = 1;
	}
	if (xtime && !old ) {
		if (!Blind && talk) pline("Oh wow!  Everything looks so cosmic!");
		flags.botl = 1;
	}
	Hallucination = xtime;
	setsee();
}

static void
ghost_from_bottle()
{
	if(!makemon(&mons[PM_GHOST], u.ux, u.uy)){
		pline("This bottle turns out to be empty.");
		return;
	}
	pline("As you open the bottle, an enormous ghost emerges!");
	if(flags.verbose)
	    You("are frightened to death, and unable to move.");
	nomul(-3);
	nomovemsg = "You regain your composure.";
}

int
dodrink() {
	register struct obj *otmp;

	if (Strangled) {
		pline("If you can't breathe air, how can you drink liquid?");
		return 0;
	}
#ifdef FOUNTAINS
	/* Is there a fountain to drink from here? */
        if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
		pline("Drink from the fountain? ");
		if(yn() == 'y') {
			(void) drinkfountain();
			return 1;
		}
	}
#endif
#ifdef SINKS
	/* Or a kitchen sink? */
	if (IS_SINK(levl[u.ux][u.uy].typ)) {
		pline("Drink from the sink? ");
		if (yn() == 'y') {
			(void) drinksink();
			return 1;
		}
	}
#endif

	otmp = getobj(beverages, "drink");
	if(!otmp) return(0);
#ifndef NO_SIGNAL
	otmp->in_use = TRUE;		/* you've opened the stopper */
#endif
	if(objects[otmp->otyp].oc_descr && !strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
		ghost_from_bottle();
		useup(otmp);
		return(1);
	}
	if(objects[otmp->otyp].oc_descr && !strcmp(objects[otmp->otyp].oc_descr, "glowing") && !rn2(13)) {
		djinni_from_bottle(otmp);
		useup(otmp);
		return(1);
	}
	return dopotion(otmp);
}

int
dopotion(otmp)
register struct obj *otmp;
{
	int retval;

	nothing = unkn = 0;
	if((retval = peffects(otmp)) >= 0) return(retval);

	if(nothing) {
	    unkn++;
	    You("have a %s feeling for a moment, then it passes.",
		  Hallucination ? "normal" : "peculiar");
	}
	if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
		if(!unkn) {
			makeknown(otmp->otyp);
			more_experienced(0,10);
		} else if(!objects[otmp->otyp].oc_uname)
			docall(otmp);
	}
	useup(otmp);
	return(1);
}

int
peffects(otmp)
	register struct obj	*otmp;
{
	register int i, ii, isdone;

	switch(otmp->otyp){
	case POT_RESTORE_ABILITY:
#ifdef SPELLS
	case SPE_RESTORE_ABILITY:
#endif
		unkn++;
		if(otmp->cursed) {
		    pline("Ulch!  This makes you feel mediocre!");
		    break;
		} else {
		    pline("Wow!  This makes you feel %s!",
			  (otmp->blessed) ? "great" : "good");
		    i = rn2(A_MAX);		/* start at a random point */
		    for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) {
			if(ABASE(i) < AMAX(i)) {
			    ABASE(i) = AMAX(i);
			    /* only first found if not blessed */
			    isdone = !(otmp->blessed);
			    flags.botl = 1;
			}
			if(++i >= A_MAX) i = 0;
		    }
		}
		break;
	case POT_HALLUCINATION:
		if (Hallucination) nothing++;
		make_hallucinated(Hallucination +
				  rn1(200, 600 - 300*bcsign(otmp)), TRUE);
		break;
	case POT_WATER:
		if(!otmp->blessed && !otmp->cursed) {
			pline("This tastes like %swater.",
			      otmp->spe == -1 ? "impure " : "");
			lesshungry(rnd(otmp->spe == -1 ? 3 : 10));
			break;
		}
		unkn++;
#ifdef POLYSELF
		if(is_undead(uasmon) || is_demon(uasmon) || 
				u.ualigntyp == U_CHAOTIC) {
		    if(otmp->blessed) {
			pline("This burns like acid!");
			if (u.ulycn != -1) {
				Your("affinity to %s disappears!",
				     makeplural(mons[u.ulycn].mname));
				if(uasmon == &mons[u.ulycn] && !Polymorph_control)
					rehumanize();
				u.ulycn = -1;
			}
			losehp(d(2,6), "potion of holy water", KILLED_BY_AN);
		    } else if(otmp->cursed) {
			You("feel quite proud of yourself.");
			healup(d(2,6),0,0,0);
		    }
		} else
#endif
		    if(otmp->blessed) {
			You("feel full of awe.");
			make_sick(0L,TRUE);
#ifdef POLYSELF
			if (u.ulycn != -1) {
				You("feel purified.");
				if(uasmon == &mons[u.ulycn] && !Polymorph_control)
					rehumanize();
				u.ulycn = -1;
			}
#endif
			/* make_confused(0L,TRUE); */
		    } else {
			if(u.ualigntyp == U_LAWFUL) {
			    pline("This burns like acid!");
			    losehp(d(2,6), "potion of unholy water",
				KILLED_BY_AN);
			} else
			    You("feel full of dread.");
		    }
		break;
	case POT_BOOZE:
		unkn++;
		pline("Ooph!  This tastes like %s!",
		      Hallucination ? "furniture polish" : "liquid fire");
		if (!otmp->blessed) make_confused(HConfusion + d(3,8),FALSE);
		/* the whiskey makes us feel better */
		if(u.uhp < u.uhpmax) losehp(-1, "", 0); /* can't kill you */
		lesshungry(10 * (2 + bcsign(otmp)));
		if(otmp->cursed) {
			You("pass out.");
			multi = -rnd(15);
			nomovemsg = "You awake with a headache.";
		}
		break;
	case POT_ENLIGHTENMENT:
		if(otmp->cursed) {
			unkn++;
			You("have an uneasy feeling...");
		} else {
			You("feel self-knowledgeable...");
			if (otmp->blessed) {
				adjattrib(A_INT, 1, FALSE);
				adjattrib(A_WIS, 1, FALSE);
			}
			more();
			enlightenment();
			pline("The feeling subsides.");
		}
		break;
	case POT_INVISIBILITY:
#ifdef SPELLS
	case SPE_INVISIBILITY:
#endif
		if(Invisible || See_invisible) nothing++;
		else {
		     newsym(u.ux,u.uy);
		     if(!Blind)
		       pline("Gee!  All of a sudden, you can't see yourself.");
		     else
		       You("feel rather airy."), unkn++;
		}
		if (otmp->blessed && !(HInvis & INTRINSIC)) {
#ifndef MACOS
			pline("Do you want the invisibility to be permanent? ");
			nothing = 0;
			if (yn()=='n') HInvis += rn1(15,31);
			else HInvis |= INTRINSIC;
#else
			nothing = 0;
			if (UseMacAlertText(128,
				"Do you want the invisibility to be permanent ?")
				== 2) HInvis += rn1(15,31);
			else HInvis |= INTRINSIC;
#endif
		} else HInvis += rn1(15,31);
		if(otmp->cursed) {
		    pline("For some reason, you feel your presence is known.");
		    aggravate();
		}
		break;
	case POT_SEE_INVISIBLE:
	case POT_FRUIT_JUICE:
		unkn++;
		if(otmp->cursed)
			pline("Yecch!  This tastes %s.",
			  Hallucination ? "overripe" : "rotten"
			 );
		else pline (Hallucination ?
#ifdef TUTTI_FRUTTI
		   "This tastes like 10%% real %s juice all-natural beverage." :
		   "This tastes like %s juice.", pl_fruit);
#else
		   "This tastes like 10%% real fruit juice all-natural beverage." :
		   "This tastes like fruit juice.");
#endif
		if (otmp->otyp == POT_FRUIT_JUICE) {
			lesshungry(10 * (2 + bcsign(otmp)));
			break;
		}
		if (!otmp->cursed) {
			/* Tell them they can see again immediately, which
			 * will help them identify the potion...
			 */
			make_blinded(0L,TRUE);
		}
		if (otmp->blessed)
			HSee_invisible |= INTRINSIC;
		else
			HSee_invisible += rn1(100,750);
		break;
	case POT_PARALYSIS:
		if(Levitation)
			You("are motionlessly suspended.");
		else
			Your("%s are frozen to the floor!",
				makeplural(body_part(FOOT)));
		nomul(-(rn1(10, 25 - 12*bcsign(otmp))));
		break;
	case POT_MONSTER_DETECTION:
#ifdef SPELLS
	case SPE_DETECT_MONSTERS:
#endif
		if (monster_detect(otmp))
			return(1);		/* nothing detected */
		break;
	case POT_OBJECT_DETECTION:
#ifdef SPELLS
	case SPE_DETECT_TREASURE:
#endif
		if (object_detect(otmp))
			return(1);		/* nothing detected */
		break;
	case POT_SICKNESS:
		pline("Yecch!  This stuff tastes like poison.");
		if (otmp->blessed) {
#ifdef TUTTI_FRUTTI
		pline("(But in fact it was mildly stale %s juice.)", pl_fruit);
#else
		pline("(But in fact it was mildly stale orange juice.)");
#endif
			if (pl_character[0] != 'H')
				losehp(1, "mildly contaminated potion",
					KILLED_BY_AN);
		} else {
		    if(Poison_resistance)
#ifdef TUTTI_FRUTTI
    pline("(But in fact it was biologically contaminated %s juice.)",pl_fruit);
#else
    pline("(But in fact it was biologically contaminated orange juice.)");
#endif
		    if (pl_character[0] == 'H')
			pline("Fortunately, you have been immunized.");
		    else {
			int typ = rn2(A_MAX);
			poisontell(typ);
			adjattrib(typ,Poison_resistance ? -1 : -rn1(4,3), TRUE);
			if(!Poison_resistance)
				losehp(rnd(10)+5*!!(otmp->cursed),
				       "contaminated potion", KILLED_BY_AN);
		    }
		}
		if(Hallucination) {
			You("are shocked back to your senses!");
			make_hallucinated(0L,FALSE);
		}
		break;
	case POT_CONFUSION:
		if(!Confusion)
		    if (Hallucination) {
			pline("What a trippy feeling!");
			unkn++;
		    } else
			pline("Huh, What?  Where am I?");
		else	nothing++;
		make_confused(HConfusion + rn1(7,16-8*bcsign(otmp)),FALSE);
		break;
	case POT_GAIN_ABILITY:
		if(otmp->cursed) {
		    pline("Ulch!  That potion tasted foul!");
		    unkn++;
		} else {
		    i = rn2(A_MAX);		/* start at a random point */
		    for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) {
			adjattrib(i, 1, FALSE);
			/* only first found if not blessed */
			isdone = !(otmp->blessed);
			flags.botl = 1;
			if(++i >= A_MAX) i = 0;
		    }
		}
		break;
	case POT_SPEED:
		if(Wounded_legs && !otmp->cursed) {
			heal_legs();
			unkn++;
			break;
		}		/* and fall through */
#ifdef SPELLS
	case SPE_HASTE_SELF:
#endif
		if(!(Fast & TIMEOUT))
			You("are suddenly moving much faster.");
		else {
			Your("%s get new energy.",
				makeplural(body_part(LEG)));
			unkn++;
		}
		Fast += rn1(10,100+60*bcsign(otmp));
		break;
	case POT_BLINDNESS:
		if(Blind) nothing++;
		make_blinded(Blinded + rn1(200, 250-125*bcsign(otmp)), TRUE);
		break;
	case POT_GAIN_LEVEL:
		if (otmp->cursed) {
			unkn++;
			/* they went up a level */
			if(dlevel > 1 && dlevel <= MAXLEVEL) { 
				You("rise up, through the ceiling!");
				goto_level(dlevel-1, FALSE, FALSE);
			} else You("have an uneasy feeling.");
			break;
		}
		pluslvl();
		if (otmp->blessed)
			/* blessed potions place you at a random spot in the
			 * middle of the new level instead of the low point
			 */
			u.uexp = rndexp();
		break;
	case POT_HEALING:
		You("begin to feel better.");
		healup(d(5,2) + 5 * bcsign(otmp),
		       1, !!(otmp->blessed), !(otmp->cursed));
		break;
	case POT_EXTRA_HEALING:
		You("feel much better.");
		healup(d(5,4) + 5 * bcsign(otmp),
		       2+3*!!(otmp->blessed), !(otmp->cursed), 1);
		make_hallucinated(0L,TRUE);
		break;
	case POT_LEVITATION:
#ifdef SPELLS
	case SPE_LEVITATION:
#endif
		if(!Levitation) {
			float_up();
			if (otmp->cursed) {
#ifdef STRONGHOLD
	if((u.ux != xupstair || u.uy != yupstair) &&
	   (!xupladder || u.ux != xupladder || u.uy != yupladder)) {
#else
	if(u.ux != xupstair || u.uy != yupstair) {
#endif /* STRONGHOLD /**/
					You("hit your %s on the ceiling.",
						body_part(HEAD));
					losehp(uarmh ? 1 : rnd(10),
						"colliding with the ceiling",
						KILLED_BY);
				} else (void) doup();
			}
		} else
			nothing++;
		if (otmp->blessed) {
			char buf[BUFSZ];
			int lmoves = 0;

			makeknown(POT_LEVITATION);
			pline("How many moves do you wish to levitate for? [1-300] ");
			do {
				getlin(buf);
			} while (buf[0]=='\033' || !buf[0] ||
				(lmoves = atoi(buf)) < 1 || lmoves > 300);
			HLevitation += lmoves;
		} else HLevitation += rnd(150);
		u.uprops[LEVITATION].p_tofn = float_down;
		break;
#ifdef SPELLS
	case POT_GAIN_ENERGY:			/* M. Stephenson */
		{	register int	 num;
			if(otmp->cursed)
			    You("feel lackluster.");
			else
			    pline("Magical energies course through your body.");
			num = rnd(5) + 5 * otmp->blessed + 1;
			u.uenmax += (otmp->cursed) ? -num : num;
			u.uen += (otmp->cursed) ? -num : num;
			if(u.uenmax <= 0) u.uen = u.uenmax = 0;
			flags.botl = 1;
		}
		break;
#endif
	default:
		impossible("What a funny potion! (%u)", otmp->otyp);
		return(0);
	}
	return(-1);
}

void
healup(nhp, nxtra, curesick, cureblind)
	int	nhp, nxtra;
	register boolean curesick, cureblind;
{
#ifdef POLYSELF
	if (u.mtimedone && nhp) {
		u.mh += nhp;
		if (u.mh > u.mhmax) u.mh = (u.mhmax += nxtra);
	}
#endif
	if(nhp)	{
		u.uhp += nhp;
		if(u.uhp > u.uhpmax)	u.uhp = (u.uhpmax += nxtra);
	}
	if(cureblind)	make_blinded(0L,TRUE);
	if(curesick)	make_sick(0L,TRUE);
	flags.botl = 1;
	return;
}

void
strange_feeling(obj,txt)
register struct obj *obj;
register const char *txt;
{
	if(flags.beginner)
		You("have a %s feeling for a moment, then it passes.",
		Hallucination ? "normal" : "strange");
	else
		pline(txt);

	if(!obj)	/* e.g., crystal ball finds no traps */
		return;

	if(obj->dknown && !objects[obj->otyp].oc_name_known &&
						!objects[obj->otyp].oc_uname)
		docall(obj);
	useup(obj);
}

const char *bottlenames[] = {
	"bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
};

void
potionhit(mon, obj)
register struct monst *mon;
register struct obj *obj;
{
	register const char *botlnam = bottlenames[rn2(SIZE(bottlenames))];
	boolean uclose, isyou = (mon == &youmonst);

	if(isyou) {
		uclose = TRUE;
		pline("The %s crashes on your %s and breaks into shivers.",
			botlnam, body_part(HEAD));
		losehp(rnd(2), "thrown potion", KILLED_BY_AN);
	} else {
		uclose = (dist(mon->mx,mon->my) < 3);
		if(Blind) pline("Crash!");
		else pline("The %s crashes on %s%s and breaks into shivers.",
			botlnam, mon_nam(mon), (haseyes(mon->data) &&
			mon->data != &mons[PM_FLOATING_EYE]) ?
#ifdef WORM
			(notonhead ? "'s body" : "'s head")
#else
			"'s head"
#endif
			: "");
		if(rn2(5) && mon->mhp > 1)
			mon->mhp--;
	}
#ifdef WORM
	notonhead = FALSE;
#endif
	pline("The %s evaporates.", xname(obj));

	if(!isyou) switch (obj->otyp) {

	case POT_RESTORE_ABILITY:
	case POT_GAIN_ABILITY:
	case POT_HEALING:
	case POT_EXTRA_HEALING:
		if(mon->mhp < mon->mhpmax) {
			mon->mhp = mon->mhpmax;
			if(!Blind)
			pline("%s looks sound and hale again.", Monnam(mon));
		}
		break;
	case POT_SICKNESS:
		if((mon->mhpmax > 3) && !resist(mon, POTION_SYM, 0, NOTELL))
			mon->mhpmax /= 2;
		if((mon->mhp > 2) && !resist(mon, POTION_SYM, 0, NOTELL))
			mon->mhp /= 2;
		if(!Blind)
		pline("%s looks rather ill.", Monnam(mon));
		break;
	case POT_CONFUSION:
	case POT_BOOZE:
		if(!resist(mon, POTION_SYM, 0, NOTELL))  mon->mconf = 1;
		break;
	case POT_INVISIBILITY:
		unpmon(mon);
		mon->minvis = 1;
		pmon(mon);
		break;
	case POT_PARALYSIS:
		if (mon->mcanmove) {
			mon->mcanmove = 0;
			/* really should be rnd(5) for consistency with players
			 * breathing potions, but...
			 */
			mon->mfrozen = rnd(25);
		}
		break;
	case POT_SPEED:
		if (mon->mspeed == MSLOW) mon->mspeed = 0;
		else mon->mspeed = MFAST;
		break;
	case POT_BLINDNESS:
		{
		    register int btmp = 64 + rn2(32) +
					rn2(32) * !resist(mon, POTION_SYM, 0, NOTELL);
		    mon->mblinded |= btmp;
		    mon->mcansee = 0;
		}
		break;
	case POT_WATER:
		if (is_undead(mon->data) || is_demon(mon->data)) {
			if (obj->blessed) {
				kludge("%s shrieks in pain!", Monnam(mon));
				mon->mhp -= d(2,6);
				if (mon->mhp <1) killed(mon);
			} else if (obj->cursed) {
				if(!Blind)
				pline("%s looks healthier.", Monnam(mon));
				mon->mhp += d(2,6);
			}
		}
		/* TO DO: Gremlins multiply when doused with water */
		break;
/*
	case POT_GAIN_LEVEL:
	case POT_LEVITATION:
	case POT_FRUIT_JUICE:
	case POT_MONSTER_DETECTION:
	case POT_OBJECT_DETECTION:
		break;
*/
	}
	if(uclose && rn2(5))
		potionbreathe(obj);
	obfree(obj, (struct obj *)0);
}

void
potionbreathe(obj)
register struct obj *obj;
{
	register int i, ii, isdone;

	switch(obj->otyp) {
	case POT_RESTORE_ABILITY:
	case POT_GAIN_ABILITY:
		if(obj->cursed) {
		    pline("Ulch!  That potion smells terrible!");
		    break;
		} else {
		    i = rn2(A_MAX);		/* start at a random point */
		    for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) {
			if(ABASE(i) < AMAX(i)) {
			    ABASE(i)++;
			    /* only first found if not blessed */
			    isdone = !(obj->blessed);
			    flags.botl = 1;
			}
			if(++i >= A_MAX) i = 0;
		    }
		}
		break;
	case POT_HEALING:
	case POT_EXTRA_HEALING:
		if(u.uhp < u.uhpmax) u.uhp++, flags.botl = 1;
		break;
	case POT_SICKNESS:
		if(u.uhp <= 5) u.uhp = 1; else u.uhp -= 5;
		flags.botl = 1;
		break;
	case POT_HALLUCINATION:
		You("have a vision for a moment.");
		break;
	case POT_CONFUSION:
	case POT_BOOZE:
		if(!Confusion)
			You("feel somewhat dizzy.");
		make_confused(HConfusion + rnd(5),FALSE);
		break;
	case POT_INVISIBILITY:
		if (!See_invisible && !Invis)
			pline("For an instant you could see through yourself!");
		break;
	case POT_PARALYSIS:
		pline("Something seems to be holding you.");
		nomul(-rnd(5));
		break;
	case POT_SPEED:
		Fast += rnd(5);
		Your("knees seem more flexible now.");
		break;
	case POT_BLINDNESS:
		if(!Blind) pline("It suddenly gets dark.");
		make_blinded(Blinded + rnd(5),FALSE);
		seeoff(0);
		break;
/*
	case POT_GAIN_LEVEL:
	case POT_LEVITATION:
	case POT_FRUIT_JUICE:
	case POT_MONSTER_DETECTION:
	case POT_OBJECT_DETECTION:
		break;
*/
	}
	/* note: no obfree() */
}

static boolean
neutralizes(o1, o2)
register struct obj *o1, *o2;
{
	switch (o1->otyp) {
		case POT_SICKNESS:
		case POT_HALLUCINATION:
		case POT_BLINDNESS:
		case POT_CONFUSION:
			if (o2->otyp == POT_HEALING ||
			    o2->otyp == POT_EXTRA_HEALING)
				return TRUE;
		case POT_HEALING:
		case POT_EXTRA_HEALING:
		case UNICORN_HORN:
			if (o2->otyp == POT_SICKNESS ||
			    o2->otyp == POT_HALLUCINATION ||
			    o2->otyp == POT_BLINDNESS ||
			    o2->otyp == POT_CONFUSION)
				return TRUE;
	}

	return FALSE;
}

boolean
get_wet(obj)
register struct obj *obj;
/* returns TRUE if something happened (potion should be used up) */
{
	switch (obj->olet) {
	    case WEAPON_SYM:
		if (!obj->rustfree &&
		    objects[obj->otyp].oc_material == METAL &&
		    obj->spe > -6 && !rn2(10)) {
			Your("%s somewhat.", aobjnam(obj,"rust"));
			obj->spe--;
			return TRUE;
		} else break;
	    case POTION_SYM:
		if (obj->otyp == POT_WATER) return FALSE;
		Your("%s.", aobjnam(obj,"dilute"));
		if (obj->spe == -1) {
			obj->spe = 0;
			obj->blessed = obj->cursed = 0;
			obj->otyp = POT_WATER;
		} else obj->spe--;
		return TRUE;
	    case SCROLL_SYM:
		if (obj->otyp != SCR_BLANK_PAPER
#ifdef MAIL
		    && obj->otyp != SCR_MAIL
#endif
		    ) {
			if (!Blind) {
				if (obj->quan == 1)
					pline("The scroll fades.");
				else pline("The scrolls fade.");
			}
			obj->otyp = SCR_BLANK_PAPER;
			return TRUE;
		}
	}
	Your("%s wet.", aobjnam(obj,"get"));
	return FALSE;
}

int
dodip()
{
	register struct obj *potion, *obj;
	const char *tmp;
	uchar here;

	if(!(obj = getobj("#", "dip")))
		return(0);

	here = levl[u.ux][u.uy].typ;
#ifdef FOUNTAINS
	/* Is there a fountain to dip into here? */
	if (IS_FOUNTAIN(here)) {
		pline("Dip it into the fountain? ");
		if(yn() == 'y') {
			dipfountain(obj);
			return(1);
		}
	}
#endif
        if (is_pool(u.ux,u.uy)) {
		pline("Dip it into the %s? ",
		      here == POOL ? "pool" : "moat");
		if(yn() == 'y') {
			(void) get_wet(obj);
			return(1);
		}
	}

	if(!(potion = getobj(beverages, "dip into")))
		return(0);
	if (potion==obj && potion->quan==1) {
		pline("That is a potion bottle, not a Klein bottle!");
		return 0;
	}
	if(potion->otyp == POT_WATER) {
		if (potion->blessed) {
			if (obj->cursed) {
				if (!Blind)
				    Your("%s %s.",
					  aobjnam(obj, "softly glow"),
					  Hallucination ? hcolor() : amber);
				obj->cursed=0;
				obj->bknown=1;
	poof:
				if(!(objects[potion->otyp].oc_name_known) &&
				   !(objects[potion->otyp].oc_uname))
					docall(potion);
				useup(potion);
				return(1);
			} else if(!obj->blessed) {
				if (!Blind) {
				    tmp = Hallucination ? hcolor() : light_blue;
				    Your("%s with a%s %s aura.",
					  aobjnam(obj, "softly glow"),
					  index(vowels, *tmp) ? "n" : "", tmp);
				}
				obj->blessed=1;
				obj->bknown=1;
				goto poof;
			}
		} else if (potion->cursed) {
			if (obj->blessed) {
				if (!Blind)
				    Your("%s %s.", aobjnam(obj, "glow"),
				     Hallucination ? hcolor() : (const char *)"brown");
				obj->blessed=0;
				obj->bknown=1;
				goto poof;
			} else if(!obj->cursed) {
				if (!Blind) {
				    tmp = Hallucination ? hcolor() : black;
				    Your("%s with a%s %s aura.",
					  aobjnam(obj, "glow"),
					  index(vowels, *tmp) ? "n" : "", tmp);
				}
				obj->cursed=1;
				obj->bknown=1;
				goto poof;
			}
		} else
			if (get_wet(obj))
			    goto poof;
	}
	else if(obj->olet == POTION_SYM && obj->otyp != potion->otyp) {
		/* Mixing potions is dangerous... */
		pline("The potions mix...");
		if (obj->cursed || !rn2(10)) {
			pline("BOOM!  They explode!");
			u.uhp -= rnd(10);
			flags.botl = 1;
			potionbreathe(obj);
			useup(obj);
			useup(potion);
			return(1);
		}

		obj->blessed = obj->cursed = obj->bknown = 0;
		if (Blind) obj->dknown = 0;

		switch (neutralizes(obj, potion) ||
			obj->spe == -1 /* diluted */ ? 1 : rnd(8)) {
			case 1:
				obj->otyp = POT_WATER;
				obj->blessed = obj->cursed = 0;
				break;
			case 2:
			case 3:
				obj->otyp = POT_SICKNESS;
				break;
			case 4:
				{
				  struct obj *otmp;
				  otmp = mkobj(POTION_SYM,FALSE);
				  obj->otyp = otmp->otyp;
				  obfree(otmp, (struct obj *)0);
				}
				break;
			default:
				if (!Blind)
			    pline("The mixture glows brightly and evaporates.");
				useup(obj);
				useup(potion);
				return(1);
		}

		obj->spe--; /* diluted */
		if (obj->otyp == POT_WATER)
			pline("The mixture bubbles violently, then clears.");
		else {
			if (!Blind) {
				pline("The mixture looks %s.", objects[obj->otyp].oc_descr);
				obj->dknown = 1;
			}
		}

		useup(potion);
		return(1);
	}

	if(obj->olet == WEAPON_SYM && obj->otyp <= SHURIKEN) {
	    if(potion->otyp == POT_SICKNESS && !obj->opoisoned) {
		char buf[BUFSZ];
		Strcpy(buf, xname(potion));
		pline("The %s form%s a coating on the %s.",
			buf, potion->quan==1 ? "s" : "", xname(obj));
		obj->opoisoned = 1;
		goto poof;
	    } else if(obj->opoisoned && 
		      (potion->otyp == POT_HEALING ||
		       potion->otyp == POT_EXTRA_HEALING)) {
		pline("A coating wears off the %s.", xname(obj));
		obj->opoisoned = 0;
		goto poof;
	    }
	}

	if(obj->otyp == UNICORN_HORN && neutralizes(obj, potion)) {
		pline("The potion clears.");
		potion->otyp = POT_WATER;
		potion->blessed = 0;
		potion->cursed = 0;
		return(1);
	}

	pline("Interesting...");
	return(1);
}


void
djinni_from_bottle(obj)
register struct obj *obj;
{
	register struct monst *mtmp;

	if(!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy))){
		pline("It turns out to be empty.");
		return;
	}

	if (!Blind) {
		pline("In a cloud of smoke, %s emerges!", defmonnam(mtmp));
		pline("%s speaks.", Monnam(mtmp));
	} else {
		You("smell acrid fumes.");
		pline("Something speaks.");
	}

	switch (obj->blessed ? 0 : obj->cursed ? 4 : rn2(5)) {
	case 0 : verbalize("I am in your debt.  I will grant one wish!");
		makewish();
		mongone(mtmp);
		break;
	case 1 : verbalize("Thank you for freeing me!");
		(void) tamedog(mtmp, (struct obj *)0);
		break;
	case 2 : verbalize("You freed me!");
		mtmp->mpeaceful = 1;
		break;
	case 3 : verbalize("It is about time!");
		pline("The %s vanishes.",
			Hallucination ? rndmonnam() : "djinni");
		mongone(mtmp);
		break;
	default: verbalize("You disturbed me, fool!");
		break;
	}
}

/* monster_detect is also used in the crystal ball routine */
/* returns 1 if nothing was detected		*/
/* returns 0 if something was detected		*/
int
monster_detect(otmp)
register struct obj	*otmp;
{
	register struct monst	*mtmp;

	if(!fmon) {
		if (otmp)
			strange_feeling(otmp, Hallucination ?
					      "You get the heebie jeebies." :
					      "You feel threatened.");
		return(1);
	} else {
		int woken = FALSE;

		cls();
		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
			if(mtmp->mx > 0)
		    at(mtmp->mx, mtmp->my,
		       (uchar)(Hallucination ? rndmonsym() : mtmp->data->mlet),
		       AT_MON);
			if (otmp && otmp->cursed && (mtmp->msleep || !mtmp->mcanmove)) {
				mtmp->msleep = mtmp->mfrozen = 0;
				mtmp->mcanmove = 1;
				woken = TRUE;
			}
		}
		prme();
		You("sense the presence of monsters.");
		if (woken)
			pline("Monsters sense the presence of you.");
		more();
		docrt();
	}
	return(0);
}

#endif /* OVLB */
#ifdef OVL0

/* object_detect is also used in the crystal ball routine */
/* returns 1 if nothing was detected		*/
/* returns 0 if something was detected		*/
int
object_detect(otmp)
register struct obj	*otmp;
{
	register struct obj	*objs;
	register struct monst	*mtmp;
	boolean mfound=FALSE;

	if(!fobj) {
		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
			if (mtmp->minvent) {
				/* OK, it's used for 2 different things */
				mfound = TRUE;
				break;
			}
		}
		if (!mfound) {
			if (otmp)
			    strange_feeling(otmp, "You feel a pull downward.");
			return(1);
		}
	}
	mfound = FALSE;
	for(objs = fobj; objs; objs = objs->nobj)
		if(objs->ox != u.ux || objs->oy != u.uy)
			goto outobjmap;
	You("sense the presence of objects nearby.");
	return(0);
outobjmap:
	cls();
	for(objs = fobj; objs; objs = objs->nobj)
at(objs->ox, objs->oy, (uchar)(Hallucination ? rndobjsym() : objs->olet), AT_OBJ);
	/* monster possessions added by GAN 12/16/86 */
	for(mtmp = fmon ; mtmp ; mtmp = mtmp->nmon)
		if(mtmp->minvent)
			for(objs = mtmp->minvent;objs;objs = objs->nobj)
			    at(mtmp->mx, mtmp->my, (uchar)objs->olet, AT_OBJ);
	if (otmp && otmp->cursed) {
		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
			if (mtmp->mimic) {
				mnexto(mtmp);
				mfound = TRUE;
			}
		}
	}
	prme();
	You("sense the presence of objects.");
	if (mfound) pline("Objects sense the presence of you.");
	more();
	docrt();
	return(0);
}

#endif /* OVL0 */
#ifdef OVLB

/* the detections are pulled out so they can	*/
/* also be used in the crystal ball routine	*/
/* returns 1 if nothing was detected		*/
/* returns 0 if something was detected		*/
int
trap_detect(sobj)
register struct obj	*sobj;
/* sobj is null if crystal ball, *scroll if gold detection scroll */
{
	register struct trap *ttmp;
	register struct obj *obj;
	register int door;
	boolean found = FALSE;
	coord cc;

	for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
		if(ttmp->tx != u.ux || ttmp->ty != u.uy)
			goto outtrapmap;
		else found = TRUE;
	}
	for(obj = fobj; obj; obj = obj->nobj) {
		if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped)
			if (obj->ox != u.ux || obj->oy != u.uy)
				goto outtrapmap;
			else found = TRUE;
	}
	for(door=0; door<=doorindex; door++) {
		cc = doors[door];
		if (levl[cc.x][cc.y].doormask & D_TRAPPED)
			if (cc.x != u.ux || cc.x != u.uy)
				goto outtrapmap;
			else found = TRUE;
	}
	if(!found) {
		char buf[42];
		Sprintf(buf, "Your %s stop itching.",
			makeplural(body_part(TOE)));
		strange_feeling(sobj,buf);
		return(1);
	}
	/* traps exist, but only under me - no separate display required */
	Your("%s itch.", makeplural(body_part(TOE)));
	return(0);
outtrapmap:
	cls();
#define SYMBOL (uchar)(Hallucination ? rndobjsym() : \
		(sobj && sobj->cursed) ? GOLD_SYM : TRAP_SYM)
#define AT Hallucination || (sobj && sobj->cursed) ? AT_OBJ : AT_MAP
	for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
		at(ttmp->tx, ttmp->ty, SYMBOL, AT);
	for(obj = fobj; obj; obj = obj->nobj) {
		if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped)
			at(obj->ox, obj->oy, SYMBOL, AT);
	}
	for(door=0; door<=doorindex; door++) {
		cc = doors[door];
		if (levl[cc.x][cc.y].doormask & D_TRAPPED)
			at(cc.x, cc.y, SYMBOL, AT);
	}
#undef SYMBOL
#undef AT
	prme();
	if (sobj && sobj->cursed)
		You("feel very greedy.");
	else
		You("feel entrapped.");
	more();
	docrt();
	return(0);
}

#endif /* OVLB */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.