/*	SCCS Id: @(#)apply.c	3.1	92/12/10		  */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include "edog.h"

#ifdef OVLB

static const char NEARDATA tools[] = { TOOL_CLASS, 0 };

static boolean NEARDATA did_dig_msg;

#ifdef TOURIST
static int FDECL(use_camera, (struct obj *));
#endif
static int FDECL(use_towel, (struct obj *));
static void FDECL(use_stethoscope, (struct obj *));
static void FDECL(use_whistle, (struct obj *));
static void FDECL(use_magic_whistle, (struct obj *));
#ifdef WALKIES
static void FDECL(use_leash, (struct obj *));
#endif
STATIC_DCL int NDECL(dig);
#ifdef OVLB
STATIC_DCL schar FDECL(fillholetyp, (int, int));
#endif
static boolean FDECL(wield_tool, (struct obj *));
static int FDECL(use_pick_axe, (struct obj *));
static int FDECL(use_mirror, (struct obj *));
static void FDECL(use_bell, (struct obj *));
static void FDECL(use_candelabrum, (struct obj *));
static void FDECL(use_candle, (struct obj *));
static void FDECL(use_lamp, (struct obj *));
static void FDECL(use_tinning_kit, (struct obj *));
static void FDECL(use_figurine, (struct obj *));
static void FDECL(use_grease, (struct obj *));
static boolean NDECL(rm_waslit);
static void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P));
static void FDECL(mkcavearea, (BOOLEAN_P));

#ifdef TOURIST
static int
use_camera(obj)
	struct obj *obj;
{
	register struct monst *mtmp;

	if(Underwater) {
		pline("Using your camera underwater voids the warranty.");
		return(0);
	}
	if(!getdir(NULL)) return(0);
	if(u.uswallow) {
		You("take a picture of %s's %s.", mon_nam(u.ustuck),
		    is_animal(u.ustuck->data) ? "stomach" : "interior");
	} else if(obj->cursed && !rn2(2)) goto blindu;
	else if(u.dz) {
		You("take a picture of the %s.",
			(u.dz > 0) ? "floor" : "ceiling");
	} else if(!u.dx && !u.dy) {
blindu:
		if(!Blind) {
			You("are blinded by the flash!");
			make_blinded((long)rnd(25),FALSE);
		}
	} else if(mtmp = bhit(u.dx,u.dy,COLNO,FLASHED_LIGHT,
						(int(*)())0,(int(*)())0,obj)) {
		if(mtmp->msleep) {
		    mtmp->msleep = 0;
		    if(cansee(mtmp->mx,mtmp->my))
			pline("The flash awakens %s.", mon_nam(mtmp)); /* a3 */
		} else if (mtmp->data->mlet != S_LIGHT)
		    if((mtmp->mcansee && haseyes(mtmp->data))
		       || mtmp->mblinded) {
			register int tmp = distu(mtmp->mx,mtmp->my);
			register int tmp2;

			if(cansee(mtmp->mx,mtmp->my))
			    pline("%s is blinded by the flash!", Monnam(mtmp));
			if(mtmp->data == &mons[PM_GREMLIN]) {
			    /* Rule #1: Keep them out of the light. */
			    pline("%s cries out in pain!", Monnam(mtmp));
			    if (mtmp->mhp > 1) mtmp->mhp--;
			}
			setmangry(mtmp);
			if(tmp < 9 && !mtmp->isshk && rn2(4)) {
				mtmp->mflee = 1;
				if(rn2(4)) mtmp->mfleetim = rnd(100);
			}
			mtmp->mcansee = 0;
			if(tmp < 3) {
				mtmp->mblinded = 0;
			} else {
				tmp2 = mtmp->mblinded;
				tmp2 += rnd(1 + 50/tmp);
				if(tmp2 > 127) tmp2 = 127;
				mtmp->mblinded = tmp2;
			}
		    }
	}
	return 1;
}
#endif

static int
use_towel(obj)
	struct obj *obj;
{
	if(!freehand()) {
		You("have no free %s!", body_part(HAND));
		return 0;
	} else if (obj->owornmask) {
		You("can't use it while you're wearing it!");
		return 0;
	} else if (obj->cursed) {
		long old;
		switch (rn2(3)) {
		case 2:
		    old = Glib;
		    Glib += rn1(10, 3);
		    Your("%s are %s!", makeplural(body_part(HAND)),
			(old ? "filthier than ever" : "now slimy"));
		    return 1;
		case 1:
		    if (!Blindfolded) {
			old = u.ucreamed;
			u.ucreamed += rn1(10, 3);
			pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
			      (old ? "has more" : "now has"));
			make_blinded(Blinded + (long)u.ucreamed - old, TRUE);
		    } else {
			if (ublindf->cursed) {
			    You("pushed your blindfold %s.",
				rn2(2) ? "cock-eyed" : "crooked");
			} else {
			    You("pushed your blindfold off.");
			    Blindf_off(ublindf);
			    dropx(ublindf);
			}
		    }
		    return 1;
		case 0:
		    break;
		}
	}

	if (Glib) {
		Glib = 0;
		You("wipe off your %s.", makeplural(body_part(HAND)));
		return 1;
	} else if(u.ucreamed) {
		Blinded -= u.ucreamed;
		u.ucreamed = 0;

		if (!Blinded) {
			pline("You've got the glop off.");
			Blinded = 1;
			make_blinded(0L,TRUE);
		} else {
			Your("%s feels clean now.", body_part(FACE));
		}
		return 1;
	}

	Your("%s and %s are already clean.", 
		body_part(FACE), makeplural(body_part(HAND)));

	return 0;
}

static char hollow_str[] = "hear a hollow sound!  This must be a secret %s!";

/* Strictly speaking it makes no sense for usage of a stethoscope to
   not take any time; however, unless it did, the stethoscope would be
   almost useless. */
static void
use_stethoscope(obj)
	register struct obj *obj;
{
	register struct monst *mtmp;
	register struct rm *lev;
	register int rx, ry;

	if(!freehand()) {
		You("have no free %s!", body_part(HAND));
		return;
	}
	if (!getdir(NULL)) return;
	if (u.uswallow && (u.dx || u.dy || u.dz)) {
		mstatusline(u.ustuck);
		return;
	} else if (u.dz) {
		if (Underwater)
		    You("hear faint splashing.");
		else if (u.dz < 0 || Levitation)
		    You("can't reach the %s!", u.dz<0 ? "ceiling" : "floor");
		else if (Is_stronghold(&u.uz))
		    You("hear the crackling of hellfire.");
		else
		    pline("The floor seems healthy enough.");
		return;
	} else if (obj->cursed && !rn2(2)) {
		You("hear your heart beat.");
		return;
	}
	if (Stunned || (Confusion && !rn2(5))) confdir();
	if (!u.dx && !u.dy) {
		ustatusline();
		return;
	}
	rx = u.ux + u.dx; ry = u.uy + u.dy;
	if (!isok(rx,ry)) {
		You("hear a faint typing noise.");
		return;
	}
	if(mtmp = m_at(rx,ry)) {
		mstatusline(mtmp);
		if (mtmp->mundetected) {
			mtmp->mundetected = 0;
			if (cansee(rx,ry)) newsym(mtmp->my,mtmp->my);
		}
		return;
	}
	lev = &levl[rx][ry];
	switch(lev->typ) {
	case SDOOR:
		You(hollow_str, "door");
		lev->typ = DOOR;
		newsym(rx,ry);
		return;
	case SCORR:
		You(hollow_str, "passage");
		lev->typ = CORR;
		newsym(rx,ry);
		return;
	}
	You("hear nothing special.");
}

static char whistle_str[] = "produce a %s whistling sound.";

/*ARGSUSED*/
static void
use_whistle(obj)
struct obj *obj;
{
	You(whistle_str, "high");
	wake_nearby();
}

static void
use_magic_whistle(obj)
struct obj *obj;
{
	register struct monst *mtmp;

	if(obj->cursed && !rn2(2)) {
		You("produce a high-pitched humming noise.");
		wake_nearby();
	} else {
		makeknown(MAGIC_WHISTLE);
		You(whistle_str, Hallucination ? "normal" : "strange");
		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(mtmp->mtame) mnexto(mtmp);
	}
}

boolean
um_dist(x,y,n)
register xchar x, y, n;
{
	return(abs(u.ux - x) > n  || abs(u.uy - y) > n);
}

#endif /* OVLB */

#ifdef WALKIES
#define MAXLEASHED	2

#ifdef OVLB

int
number_leashed()
{
	register int i = 0;
	register struct obj *obj;

	for(obj = invent; obj; obj = obj->nobj)
		if(obj->otyp == LEASH && obj->leashmon != 0) i++;
	return(i);
}

void
o_unleash(otmp) 	/* otmp is about to be destroyed or stolen */
register struct obj *otmp;
{
	register struct monst *mtmp;

	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->m_id == (unsigned)otmp->leashmon)
			mtmp->mleashed = 0;
	otmp->leashmon = 0;
}

void
m_unleash(mtmp) 	/* mtmp is about to die, or become untame */
register struct monst *mtmp;
{
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->otyp == LEASH &&
				otmp->leashmon == (int)mtmp->m_id)
			otmp->leashmon = 0;
	mtmp->mleashed = 0;
}

void
unleash_all()		/* player is about to die (for bones) */
{
	register struct obj *otmp;
	register struct monst *mtmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->otyp == LEASH) otmp->leashmon = 0;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->mtame) mtmp->mleashed = 0;
}

/* ARGSUSED */
static void
use_leash(obj)
struct obj *obj;
{
	register int x, y;
	register struct monst *mtmp;
	int spotmon;

	if(!obj->leashmon && number_leashed() >= MAXLEASHED) {
		You("can't leash additional pets.");
		return;
	}

	if(!getdir(NULL)) return;

	x = u.ux + u.dx;
	y = u.uy + u.dy;

	if((x == u.ux) && (y == u.uy)) {
		pline("Leash yourself?  Very funny...");
		return;
	}

	if(!(mtmp = m_at(x, y))) {
		pline("There is no creature here.");
		return;
	}

	spotmon = canseemon(mtmp) || sensemon(mtmp);

	if(!mtmp->mtame) {
	    if(!spotmon)
		pline("There is no creature here.");
	    else
		pline("%s is not %s!", Monnam(mtmp), (!obj->leashmon) ?
				"leashable" : "leashed");
	    return;
	}
	if(!obj->leashmon) {
		if(mtmp->mleashed) {
			pline("This %s is already leashed!",
			      spotmon ? l_monnam(mtmp) : "monster");
			return;
		}
		You("slip the leash around %s%s.",
		    spotmon ? "your " : "", l_monnam(mtmp));
		mtmp->mleashed = 1;
		obj->leashmon = (int)mtmp->m_id;
		if(mtmp->msleep)  mtmp->msleep = 0;
		return;
	}
	if(obj->leashmon != (int)mtmp->m_id) {
		pline("This leash is not attached to that creature!");
		return;
	} else {
		if(obj->cursed) {
			pline("The leash wouldn't come off!");
			return;
		}
		mtmp->mleashed = 0;
		obj->leashmon = 0;
		You("remove the leash from %s%s.",
		    spotmon ? "your " : "", l_monnam(mtmp));
	}
	return;
}

#endif /* OVLB */
#ifdef OVL1

boolean
next_to_u()
{
	register struct monst *mtmp;
	register struct obj *otmp;

	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
		if(mtmp->mleashed) {
			if (distu(mtmp->mx,mtmp->my) > 2) mnexto(mtmp);
			if (distu(mtmp->mx,mtmp->my) > 2) {
			    for(otmp = invent; otmp; otmp = otmp->nobj)
				if(otmp->otyp == LEASH &&
					otmp->leashmon == (int)mtmp->m_id) {
				    if(otmp->cursed) return(FALSE);
				    You("feel %s leash go slack.",
					(number_leashed() > 1) ? "a" : "the");
				    mtmp->mleashed = 0;
				    otmp->leashmon = 0;
				}
			}
		}
	return(TRUE);
}

#endif /* OVL1 */
#ifdef OVLB
struct obj *
get_mleash(mtmp) 	/* assuming mtmp->mleashed has been checked */
register struct monst *mtmp;
{
	register struct obj *otmp;

	otmp = invent;
	while(otmp) {
		if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id)
			return(otmp);
		otmp = otmp->nobj;
	}
	return((struct obj *)0);
}
#endif /* OVLB */

#endif /* WALKIES */
#ifdef OVL0

#ifdef WALKIES
void
check_leash(x, y)
register xchar x, y;
{
	register struct obj *otmp;
	register struct monst *mtmp = fmon;

	for(otmp = invent; otmp; otmp = otmp->nobj)
	    if(otmp->otyp == LEASH && otmp->leashmon != 0) {
		while(mtmp) {
		    if((int)mtmp->m_id == otmp->leashmon &&
			    (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
				dist2(x,y,mtmp->mx,mtmp->my))
			) {
			if(otmp->cursed) {
			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
				pline("%s chokes to death!",Monnam(mtmp));
				mondied(mtmp);
			    } else
				if(um_dist(mtmp->mx, mtmp->my, 3))
					pline("%s chokes on the leash!",
						Monnam(mtmp));
			} else {
			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
				pline("%s's leash snaps loose!",Monnam(mtmp));
				m_unleash(mtmp);
			    } else {
				if(um_dist(mtmp->mx, mtmp->my, 3)) {
				    You("pull on the leash.");
# ifdef SOUNDS
				    if (mtmp->data->msound != MS_SILENT)
				    switch(rn2(3)) {
					case 0:  growl(mtmp);	break;
					case 1:  yelp(mtmp);	break;
					default: whimper(mtmp); break;
				    }
# endif
				}
			    }
			}
		    }
		    mtmp = mtmp->nmon;
		}
	    }
}

#endif /* WALKIES */

#endif /* OVL0 */
#ifdef OVLB

static boolean
rm_waslit() {
    register xchar x, y;

    if(levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit) 
        return(TRUE);
    for(x = u.ux-2; x < u.ux+3; x++)
        for(y = u.uy-1; y < u.uy+2; y++)
	    if(isok(x,y) && levl[x][y].waslit) return(TRUE);
    return(FALSE);
}

/* Change level topology.  Messes with vision tables and ignores things like
 * boulders in the name of a nice effect.  Vision will get fixed up again
 * immediately after the effect is complete.
 */
static void
mkcavepos(x, y, dist, waslit, rockit)
    xchar x,y;
    int dist;
    boolean waslit, rockit;
{
    register struct rm *lev;

    if(!isok(x,y)) return;
    lev = &levl[x][y];

    if(rockit) {
        register struct monst *mtmp;

        if(IS_ROCK(lev->typ)) return;
	if(t_at(x, y)) return; /* don't cover the portal */
	if(mtmp = m_at(x, y)) /* make sure crucial monsters survive */
	    if(!passes_walls(mtmp->data)) rloc(mtmp);
    } else if(lev->typ == ROOM) return;

    unblock_point(x,y);	/* make sure vision knows this location is open */

    /* fake out saved state */
    lev->seen = FALSE;
    lev->doormask = 0;
    if(dist < 3) lev->lit = (rockit ? FALSE : TRUE);
    if(waslit) lev->waslit = (rockit ? FALSE : TRUE);
    lev->horizontal = FALSE;
    viz_array[y][x] = (dist < 3 ) ?
	(IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
	COULD_SEE;
    lev->typ = (rockit ? STONE : ROOM);
    if(dist >= 3)
	impossible("mkcavepos called with dist %d", dist);
    if(Blind)
	feel_location(x, y);
    else newsym(x,y);
}

static void
mkcavearea(rockit)
register boolean rockit;
{
    int dist;
    xchar xmin = u.ux, xmax = u.ux;
    xchar ymin = u.uy, ymax = u.uy;
    register xchar i;
    register boolean waslit = rm_waslit();

    if(rockit) pline("Crash!  The ceiling collapses around you!");
    else pline("A mysterious force %s cave around you!",
	     (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the");
    display_nhwindow(WIN_MESSAGE, TRUE);

    for(dist = 1; dist <= 2; dist++) {
	xmin--; xmax++;

	/* top and bottom */
	if(dist < 2) { /* the area is wider that it is high */
	    ymin--; ymax++;
	    for(i = xmin+1; i < xmax; i++) {
		mkcavepos(i, ymin, dist, waslit, rockit);
		mkcavepos(i, ymax, dist, waslit, rockit);
	    }
	}

	/* left and right */
	for(i = ymin; i <= ymax; i++) {
	    mkcavepos(xmin, i, dist, waslit, rockit);
	    mkcavepos(xmax, i, dist, waslit, rockit);
	}

	flush_screen(1);	/* make sure the new glyphs shows up */
	delay_output();
    }

    if(!rockit && levl[u.ux][u.uy].typ == CORR) {
        levl[u.ux][u.uy].typ = ROOM;
	if(waslit) levl[u.ux][u.uy].waslit = TRUE;
	newsym(u.ux, u.uy); /* in case player is invisible */
    }

    vision_full_recalc = 1;	/* everything changed */
}

STATIC_OVL int
dig()
{
	register struct rm *lev;
	register xchar dpx = dig_pos.x, dpy = dig_pos.y;

	lev = &levl[dpx][dpy];
	/* perhaps a nymph stole your pick-axe while you were busy digging */
	/* or perhaps you teleported away */
	if(u.uswallow || !uwep || uwep->otyp != PICK_AXE ||
	    !on_level(&dig_level, &u.uz) ||
	    ((dig_down && (dpx != u.ux || dpy != u.uy)) ||
	     (!dig_down && distu(dpx,dpy) > 2)))
		return(0);
	if (dig_down) {
	    if(On_stairs(u.ux, u.uy)) {
		if(u.ux == xdnladder || u.ux == xupladder)
		     pline("The ladder resists your effort.");
		else pline("The stairs here are too hard to dig in.");
		return(0);
	    }
	    if(IS_THRONE(levl[u.ux][u.uy].typ)) {
		pline("The throne here is too hard to break apart.");
		return (0);
	    }
	    if(IS_ALTAR(levl[u.ux][u.uy].typ)) {
		pline("The altar here is too hard to break apart.");
		return (0);
	    }
	    if(t_at(dpx, dpy) && !Can_dig_down(&u.uz)) {
		pline("The floor here is too hard to dig in.");
		return(0);
	    }
	    if(sobj_at(BOULDER, dpx, dpy)) {
		pline("There is not enough room here to dig.");
		return(0);
	    }
	    if(Is_airlevel(&u.uz)) {
		You("cannot dig in thin air.");
		return(0);
	    }
	    if(Is_waterlevel(&u.uz)) {
		pline("The water splashes and subsides.");
		return(0);
	    }
	} else /* !dig_down */
	    if(IS_ROCK(lev->typ) && !may_dig(dpx,dpy)) {
		pline("This wall is too hard to dig into.");
		return(0);
	    }
	if(Fumbling && !rn2(3)) {
		switch(rn2(3)) {
		case 0:  if(!welded(uwep)) {
			     You("fumble and drop your %s.", xname(uwep));
			     dropx(uwep);
			     setuwep((struct obj *)0);
			 } else {
			     pline("Ouch!  Your %s bounces and hits you!",
				xname(uwep));
			     set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
			 }
			 break;
		case 1:  pline("Bang!  You hit with the broad side of %s!",
			       the(xname(uwep)));
			 break;
		default: Your("swing misses its mark."); 
			 break;
		}
		return(0);
	}
	dig_effort += 10 + abon() + uwep->spe - uwep->oeroded + rn2(5);
	if(dig_down) {
		register struct trap *ttmp;

		if(dig_effort > 250) {
			dighole();
			dig_level.dnum = 0;
			dig_level.dlevel = -1;
			return(0);	/* done with digging */
		}

		if (dig_effort <= 50)
			return(1);

		if ((ttmp = t_at(dpx,dpy)) &&
		    ((ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) ||
		     (ttmp->ttyp == TRAPDOOR)))
			return(1);

		if (IS_ALTAR(lev->typ)) {
			altar_wrath(dpx, dpy);
			angry_priest();
		}

		ttmp = maketrap(dpx,dpy,PIT);
		ttmp->tseen = 1;
		if(Invisible) newsym(ttmp->tx,ttmp->ty);
		You("have dug a pit.");
		u.utrap = rn1(4,2);
		u.utraptype = TT_PIT;
		vision_full_recalc = 1;	/* vision limits change */
		dig_level.dnum = 0;
		dig_level.dlevel = -1;
		return(0);
	} 
	if(dig_effort > 100) {
		register const char *digtxt, *dmgtxt = (const char*) 0;
		register struct obj *obj;
		register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE);

		if(obj = sobj_at(STATUE, dpx, dpy)) {
			if (break_statue(obj))
				digtxt = "The statue shatters.";
			else
				/* it was a statue trap; break_statue()
				 * printed a message and updated the screen
				 */
				digtxt = NULL;
		} else if(obj = sobj_at(BOULDER, dpx, dpy)) {
			fracture_rock(obj);
			digtxt = "The boulder falls apart.";
		} else if(!lev->typ || lev->typ == SCORR) {
		        if(Is_earthlevel(&u.uz)) {
			    if(uwep->blessed && !rn2(3)) {
			        mkcavearea(FALSE);
				goto cleanup;
			    } else if((uwep->cursed && !rn2(4)) || 
				          (!uwep->blessed && !rn2(6))) {
			        mkcavearea(TRUE);
			        goto cleanup;
			    }
			}
			lev->typ = CORR;
			digtxt = "You succeeded in cutting away some rock.";
		} else if(IS_WALL(lev->typ)) {
			if(shopedge) {
		    	    add_damage(dpx, dpy, 10L * ACURRSTR);
			    dmgtxt = "dig into";
			}
		        if (level.flags.is_maze_lev) {
			    lev->typ = ROOM;
		        } else if (level.flags.is_cavernous_lev) {
			    lev->typ = CORR;
			} else {
			    lev->typ = DOOR;
			    lev->doormask = D_NODOOR;
			}
			digtxt = "You just made an opening in the wall.";
		} else if(lev->typ == SDOOR) {
			lev->typ = DOOR;
			digtxt = "You just broke through a secret door.";
			if(!(lev->doormask & D_TRAPPED))
				lev->doormask = D_BROKEN;
		} else if(closed_door(dpx, dpy)) {
			digtxt = "You just broke a hole through the door.";
			if(shopedge) {
		    	    add_damage(dpx, dpy, 400L);
			    dmgtxt = "break";
			}
			if(!(lev->doormask & D_TRAPPED))
				lev->doormask = D_BROKEN;
		} else return(0); /* statue or boulder got taken */

		unblock_point(dpx,dpy);	/* vision:  can see through */
		if(Blind)
		    feel_location(dpx, dpy);
		else
		    newsym(dpx, dpy);
		if(digtxt) pline(digtxt);	/* after newsym */
		if(dmgtxt)
		    pay_for_damage(dmgtxt);

		if(Is_earthlevel(&u.uz) && !rn2(3)) {
		    register struct monst *mtmp;

		    switch(rn2(2)) {
		      case 0: 
		        mtmp = makemon(&mons[PM_EARTH_ELEMENTAL], dpx, dpy);
			break;
		      default: 
			mtmp = makemon(&mons[PM_XORN], dpx, dpy); 
			break;
		    }
		    if(mtmp) pline("The debris of your dig comes alive!");
		}
		if(IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) {
			b_trapped("door");
			lev->doormask = D_NODOOR;
			newsym(dpx, dpy);
		}
cleanup:
		dig_level.dnum = 0;
		dig_level.dlevel = -1;
		return(0);
	} else {
		if(IS_WALL(lev->typ) || closed_door(dpx, dpy)) {
		    if(*in_rooms(dpx, dpy, SHOPBASE)) {
			pline("This %s seems too hard to dig into.",
			      IS_DOOR(lev->typ) ? "door" : "wall");
			return(0);
		    }
		} else if (!IS_ROCK(lev->typ) && !sobj_at(STATUE, dpx, dpy)
				&& !sobj_at(BOULDER, dpx, dpy))
			return(0); /* statue or boulder got taken */
		if(!did_dig_msg) {
		    You("hit the %s with all your might.",
			sobj_at(STATUE, dpx, dpy) ? "statue" :
			sobj_at(BOULDER, dpx, dpy) ? "boulder" :
			IS_DOOR(lev->typ) ? "door" : "rock");
		    did_dig_msg = TRUE;
		}
	}
	return(1);
}

/* When will hole be finished? Very rough indication used by shopkeeper. */
int
holetime() {
	if(occupation != dig || !*u.ushops) return(-1);
	return((250 - dig_effort)/20);
}

/* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
STATIC_OVL
schar
fillholetyp(x,y)
int x, y;
{
    register int x1, y1;

    for(x1 = max(1,x-1); x1<=min(x+1,COLNO-1); x1++)
	for(y1 = max(0,y-1); y1<=min(y+1,ROWNO-1); y1++)
	    if(levl[x1][y1].typ == MOAT || levl[x1][y1].typ == LAVAPOOL)
		return levl[x1][y1].typ;

    return ROOM;
}

void
dighole()
{
	register struct trap *ttmp = t_at(u.ux, u.uy);
	struct rm *lev = &levl[u.ux][u.uy];
	struct obj *boulder_here;
	boolean nohole = !Can_dig_down(&u.uz);

	if(ttmp && nohole) {
		pline("The floor here seems too hard to dig in.");
	} else {
		d_level	newlevel;

		if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
		    pline(
		       "The %s sloshes furiously for a moment, then subsides.",
			  is_lava(u.ux, u.uy) ? "lava" : "water");
		    return;
		}
		if (lev->typ == DRAWBRIDGE_DOWN) {
			destroy_drawbridge(u.ux,u.uy);
			return;
		} else if (boulder_here = sobj_at(BOULDER, u.ux, u.uy)) {
			if (ttmp && ((ttmp->ttyp == PIT) || 
			 	     (ttmp->ttyp == SPIKED_PIT))) {
				pline("The boulder settles into the pit.");
				ttmp->ttyp = PIT; 	 /* crush spikes */
			} else {
				/*
				 * digging makes a hole, but the boulder
				 * immediately fills it.  Final outcome:
				 * no hole, no boulder.
				 */
				pline("KADOOM! The boulder falls in!");

				/* destroy traps that emanate from the floor */
				/* some of these are arbitrary -dlc */
				if (ttmp && ((ttmp->ttyp == SQKY_BOARD) ||
					     (ttmp->ttyp == BEAR_TRAP) ||
					     (ttmp->ttyp == LANDMINE) ||
					     (ttmp->ttyp == FIRE_TRAP) ||
					     (ttmp->ttyp == TRAPDOOR) ||
					     (ttmp->ttyp == TELEP_TRAP) ||
					     (ttmp->ttyp == LEVEL_TELEP) ||
					     (ttmp->ttyp == WEB) ||
					     (ttmp->ttyp == MAGIC_TRAP) ||
					     (ttmp->ttyp == ANTI_MAGIC))) {
					deltrap(ttmp);
					u.utrap = 0;
					u.utraptype = 0;
				}
			}
			delobj(boulder_here);
			return;
		}
		if (lev->typ == DRAWBRIDGE_UP) {
			/* must be floor or ice, other cases handled above */
			/* dig "pit" and let fluid flow in (if possible) */
			schar typ = fillholetyp(u.ux,u.uy);

			if(typ == ROOM) {
			    if(lev->drawbridgemask & DB_ICE)
				typ = MOAT;
			    else {
				/*
				 * We can't dig a pit here since that will
				 * destroy the drawbridge.  The following is
				 * a cop-out. --dlc
				 */
				pline("The floor here seems too hard to dig in.");
				return;
			    }
			}

		    	lev->drawbridgemask &= DB_DIR;
			if(typ == LAVAPOOL) lev->drawbridgemask |= DB_LAVA;
			newsym(u.ux,u.uy);

			pline("As you dig a pit, it fills with %s!",
			      typ == LAVAPOOL ? "lava" : "water");
			if(!Levitation
#ifdef POLYSELF
			   && !is_flyer(uasmon)
#endif
	    					) {
			    if (typ == LAVAPOOL)
				(void) lava_effects();
			    else if(!Wwalking)
				(void) drown();
			}
			return;
		} else if (lev->typ == ICE) {
			/* assume we can remove most of the ice by drilling
			 * without melting it or allowing neighboring water
			 * to flow in.
			 */
			lev->typ = ROOM;
		} else if (IS_FOUNTAIN(lev->typ)) {
			dogushforth(FALSE);
			dryup(u.ux,u.uy);
			return;
#ifdef SINKS
		} else if (IS_SINK(lev->typ)) {
			breaksink(u.ux, u.uy);
			return;
#endif
		/* the following two are here for the wand of digging */
		} else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
			pline("The throne here is too hard to break apart.");
			return;
		} else if(IS_ALTAR(levl[u.ux][u.uy].typ)) {
			pline("The altar here is too hard to break apart.");
			return;
		} else if(ttmp) {
			ttmp->ttyp = TRAPDOOR;
		} else if(nohole) {
			/* can't make a trapdoor, so make a pit */
			ttmp = maketrap(u.ux, u.uy, PIT);
		} else
			ttmp = maketrap(u.ux, u.uy, TRAPDOOR);
		ttmp->tseen = 1;
		if(Invisible) newsym(ttmp->tx,ttmp->ty);
		if(ttmp->ttyp == PIT) {
		    You("have dug a pit.");
		    if(!Levitation) {
			u.utrap = rn1(4,2);
			u.utraptype = TT_PIT;
			vision_full_recalc = 1;	/* vision limits change */
		    } else
			u.utrap = 0;
		    return;
		} 
		pline("You've made a hole in the floor.");

		/* floor objects get a chance of falling down.
		 * the case where the hero does NOT fall down
		 * is treated here.  the case where the hero
		 * does fall down is treated in goto_level().
		 */
		if(OBJ_AT(u.ux, u.uy) && (u.ustuck || Levitation 
#ifdef WALKIES
			                     || !next_to_u()
#endif
					  ))
		    impact_drop((struct obj *)0, u.ux, u.uy, 0);

		if (*u.ushops)
		    add_damage(u.ux, u.uy, 0L);
		if(!u.ustuck && !Levitation) {			/* KAA */
			if(*u.ushops)
				shopdig(1);
#ifdef WALKIES
			if(!next_to_u())
			    You("are jerked back by your pet!");
			else
#endif
			{
			    You("fall through...");

			    /* the checks above must ensure that   */
			    /* the destination level exists and is */
			    /* in the present dungeon.		   */

			    newlevel.dnum = u.uz.dnum;
			    newlevel.dlevel = u.uz.dlevel + 1;
			    goto_level(&newlevel, FALSE, TRUE, FALSE);
			}
		}
	}
}

static boolean
wield_tool(obj)
struct obj *obj;
{
	if(welded(uwep)) {
		/* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */
		if(flags.verbose) {
			pline("Since your weapon is welded to your %s,",
				bimanual(uwep) ?
				(const char *)makeplural(body_part(HAND))
				: body_part(HAND));
			pline("you cannot wield that %s.", xname(obj));
		}
		return(FALSE);
	}
# ifdef POLYSELF
	if(cantwield(uasmon)) {
		You("can't hold it strongly enough.");
		return(FALSE);
	}
# endif
	unweapon = TRUE;
	You("now wield %s.", doname(obj));
	setuwep(obj);
	if (uwep != obj) return(FALSE); /* rewielded old object after dying */
	return(TRUE);
}

static int
use_pick_axe(obj)
struct obj *obj;
{
	char dirsyms[12];
	char qbuf[QBUFSZ];
	register char *dsp = dirsyms;
	register const char *sdp = flags.num_pad ? ndir : sdir;
	register struct rm *lev;
	register int rx, ry, res = 0;
	register boolean isclosedoor;

	if(obj != uwep)
	    if (!wield_tool(obj)) return(0);
	    else res = 1;

	while(*sdp) {
		(void) movecmd(*sdp);	/* sets u.dx and u.dy and u.dz */
		rx = u.ux + u.dx;
		ry = u.uy + u.dy;
		if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) &&
		    (IS_ROCK(levl[rx][ry].typ)
		    || sobj_at(STATUE, rx, ry)
		    || sobj_at(BOULDER, rx, ry))))
			*dsp++ = *sdp;
		sdp++;
	}
	*dsp = 0;
	Sprintf(qbuf, "In what direction do you want to dig? [%s]", dirsyms);
	if(!getdir(qbuf))
		return(res);
	if(u.uswallow && attack(u.ustuck)) /* return(1) */;
	else if(Underwater) {
		pline("Turbulence torpedoes your digging attempts.");
	} else if(u.dz < 0) {
		if(Levitation)
			You("don't have enough leverage.");
		else
			You("cannot reach the ceiling.");
	} else if(!u.dx && !u.dy && !u.dz) {
		char buf[BUFSZ];
		int dam;

		dam = rnd(2) + dbon() + obj->spe;
		if (dam <= 0) dam = 1;
		You("hit yourself with your own pick-axe.");
		/* self_pronoun() won't work twice in a sentence */
		Strcpy(buf, self_pronoun("killed %sself with %%s own pick-axe",
			"him"));
		losehp(dam, self_pronoun(buf, "his"), NO_KILLER_PREFIX);
		flags.botl=1;
		return(1);
	} else if(u.dz == 0) {
		if(Stunned || (Confusion && !rn2(5))) confdir();
		rx = u.ux + u.dx;
		ry = u.uy + u.dy;
		if(!isok(rx, ry)) {
			pline("Clash!");
			return(1);
		}
		lev = &levl[rx][ry];
		if(MON_AT(rx, ry) && attack(m_at(rx, ry)))
			return(1);
		isclosedoor = closed_door(rx, ry);
		if(!IS_ROCK(lev->typ)
		     && !isclosedoor
		     && !sobj_at(STATUE, rx, ry)
		     && !sobj_at(BOULDER, rx, ry)) {
			/* ACCESSIBLE or POOL */
			You("swing your %s through thin air.",
				aobjnam(obj, NULL));
		} else {
			if(dig_pos.x != rx || dig_pos.y != ry
			    || !on_level(&dig_level, &u.uz) || dig_down) {
				dig_down = FALSE;
				dig_pos.x = rx;
				dig_pos.y = ry;
				assign_level(&dig_level, &u.uz);
				dig_effort = 0;
			    	You("start %s.",
				   sobj_at(STATUE, rx, ry) ?
						"chipping the statue" :
				   sobj_at(BOULDER, rx, ry) ?
						"hitting the boulder" :
				   isclosedoor ? "chopping at the door" :
						"digging");
			} else
				You("continue %s.",
				   sobj_at(STATUE, rx, ry) ?
						"chipping the statue" :
				   sobj_at(BOULDER, rx, ry) ?
						"hitting the boulder" :
				   isclosedoor ? "chopping at the door" :
						"digging");
			did_dig_msg = FALSE;
			set_occupation(dig, "digging", 0);
		}
	} else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
		/* it must be air -- water checked above */
		You("swing your %s through thin air.", aobjnam(obj, NULL));
	} else if(Levitation) {
		You("cannot reach the floor.");
	} else if (is_pool(u.ux, u.uy)) {
		/* Monsters which swim also happen not to be able to dig */
		You("cannot stay underwater long enough.");
	} else {
		if(dig_pos.x != u.ux || dig_pos.y != u.uy
		    || !on_level(&dig_level, &u.uz) || !dig_down) {
			dig_down = TRUE;
			dig_pos.x = u.ux;
			dig_pos.y = u.uy;
			assign_level(&dig_level, &u.uz);
			dig_effort = 0;
			You("start digging in the floor.");
			if(*u.ushops)
				shopdig(0);
		} else
			You("continue digging in the floor.");
		did_dig_msg = FALSE;
		set_occupation(dig, "digging", 0);
	}
	return(1);
}

#define WEAK	3	/* from eat.c */

static char look_str[] = "look %s.";

static int
use_mirror(obj)
struct obj *obj;
{
	register struct monst *mtmp;
	register char mlet;
	boolean vis;

	if(!getdir(NULL)) return 0;
	if(obj->cursed && !rn2(2)) {
		if (!Blind)
			pline("The mirror fogs up and doesn't reflect!");
		return 1;
	}
	if(!u.dx && !u.dy && !u.dz) {
		if(!Blind && !Invisible) {
#ifdef POLYSELF
		    if(u.umonnum == PM_FLOATING_EYE) {
			pline(Hallucination ?
			      "Yow!  The mirror stared back at you!" :
			      "Yikes!  You've frozen yourself!");
			nomul(-rnd((MAXULEV+6) - (int)u.ulevel));
		    } else if (u.usym == S_VAMPIRE)
			You("don't seem to reflect anything.");
		    else if(u.umonnum == PM_UMBER_HULK) {
			pline("Huh?  That doesn't look like you!");
			make_confused(HConfusion + d(3,4),FALSE);
		    } else
#endif
			   if (Hallucination) You(look_str, hcolor());
		    else if (Sick)
			You(look_str, "peaked");
		    else if (u.uhs >= WEAK)
			You(look_str, "undernourished");
		    else You("look as %s as ever.",
				ACURR(A_CHA) > 14 ?
				(poly_gender()==1 ? "beautiful" : "handsome") :
				"ugly");
		} else {
			You("can't see your %s %s.",
				ACURR(A_CHA) > 14 ?
				(poly_gender()==1 ? "beautiful" : "handsome") :
				"ugly",
				body_part(FACE));
		}
		return 1;
	}
	if(u.uswallow) {
		if (!Blind) You("reflect %s's %s.", mon_nam(u.ustuck),
		    is_animal(u.ustuck->data)? "stomach" : "interior");
		return 1;
	}
	if(Underwater) {
		You("offer the fish a chance to do some makeup.");
		return 1;
	}
	if(u.dz) {
		if (!Blind)
		    You("reflect the %s.", (u.dz > 0) ? "floor" : "ceiling");
		return 1;
	}
	if(!(mtmp = bhit(u.dx,u.dy,COLNO,INVIS_BEAM,
					(int(*)())0,(int(*)())0,obj)) ||
	   !haseyes(mtmp->data))
		return 1;

	vis = canseemon(mtmp);
	mlet = mtmp->data->mlet;
	if(mtmp->msleep) {
		if (vis)
		    pline ("%s is tired and doesn't look at your mirror.",
			    Monnam(mtmp));
	} else if (!mtmp->mcansee) {
	    if (vis)
		pline("%s can't see anything at the moment.", Monnam(mtmp));
	/* some monsters do special things */
	} else if (mlet == S_VAMPIRE || mlet == S_GHOST) {
	    if (vis)
		pline ("%s doesn't seem to reflect anything.", Monnam(mtmp));
	} else if(!mtmp->mcan && mtmp->data == &mons[PM_MEDUSA]) {
		if (vis)
			pline("%s is turned to stone!", Monnam(mtmp));
		stoned = TRUE;
		killed(mtmp);
	} else if(!mtmp->mcan && !mtmp->minvis &&
					mtmp->data == &mons[PM_FLOATING_EYE]) {
		int tmp = d((int)mtmp->m_lev, (int)mtmp->data->mattk[0].damd);
		if (!rn2(4)) tmp = 120;
	/* Note: floating eyes cannot use their abilities while invisible,
	 * but Medusa and umber hulks can.
	 */
		if (vis)
			pline("%s is frozen by its reflection.",Monnam(mtmp));
		else You("hear something stop moving.");
		mtmp->mcanmove = 0;
		if ( (int) mtmp->mfrozen + tmp > 127)
			mtmp->mfrozen = 127;
		else mtmp->mfrozen += tmp;
	} else if(!mtmp->mcan && mtmp->data == &mons[PM_UMBER_HULK]) {
		if (vis)
			pline ("%s has confused itself!", Monnam(mtmp));
	    	mtmp->mconf = 1;
	} else if(!mtmp->mcan && !mtmp->minvis && (mlet == S_NYMPH
			             || mtmp->data==&mons[PM_SUCCUBUS])) {
		if (vis) {
	    	    pline ("%s looks beautiful in your mirror.",Monnam(mtmp));
	    	    pline ("She decides to take it!");
		} else pline ("It steals your mirror!");
		setnotworn(obj); /* in case mirror was wielded */
	    	freeinv(obj);
	    	mpickobj(mtmp,obj);
	    	rloc(mtmp);
	} else if (mlet != S_UNICORN && !humanoid(mtmp->data) &&
			(!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
		if (vis)
			pline ("%s is frightened by its reflection.",
				Monnam(mtmp));
		mtmp->mflee = 1;
		mtmp->mfleetim += d(2,4);
	} else if (!Blind) {
		if (mtmp->minvis && !See_invisible)
		    ;
		else if ((mtmp->minvis && !perceives(mtmp->data))
			 || !haseyes(mtmp->data))
		    pline("%s doesn't seem to be aware of its reflection.",
			Monnam(mtmp));
		else
		    pline("%s doesn't seem to mind %s reflection.",
			Monnam(mtmp),
			humanoid(mtmp->data) ? (mtmp->female ? "her" : "his")
						: "its");
	}
	return 1;
}

static void
use_bell(obj)
register struct obj *obj;
{
	You("ring %s.", the(xname(obj)));

	if(Underwater) {
	    pline("But it sounds kind of muffled.");
	    return;
	}
        if(obj->otyp == BELL) {
	    if(u.uswallow) {
	        pline(nothing_happens);
		return;
	    }
	    if(obj->cursed && !rn2(3)) {
	        register struct monst *mtmp;

		if(mtmp = makemon(&mons[PM_WOOD_NYMPH], u.ux, u.uy))
		   You("summon %s!", a_monnam(mtmp));
	    }
	    wake_nearby();
	    return;
	}

	/* bell of opening */
	if(u.uswallow && !obj->blessed) {
	    pline(nothing_happens);
	    return;
	}
        if(obj->cursed) {
	    coord mm;
	    mm.x = u.ux;
	    mm.y = u.uy;
	    mkundead(&mm);
cursed_bell:
	    wake_nearby();
	    if(obj->spe > 0) obj->spe--;
	    return;
	}
	if(invocation_pos(u.ux, u.uy) && 
	             !On_stairs(u.ux, u.uy) && !u.uswallow) {
	    pline("%s emits an unnerving high-pitched sound...",
		                                          The(xname(obj)));
	    obj->age = moves;
	    if(obj->spe > 0) obj->spe--;
	    wake_nearby();
	    obj->known = 1;
	    return;
	}
	if(obj->blessed) {
	    if(obj->spe > 0) {
	        register int cnt = openit();
		if(cnt == -1) return; /* was swallowed */
		switch(cnt) {
		  case 0:  pline(nothing_happens); break;
		  case 1:  pline("Something opens..."); break;
	          default: pline("Things open around you..."); break;
	        }
		if(cnt > 0) obj->known = 1;
		obj->spe--;
	    } else pline(nothing_happens);
	} else {  /* uncursed */
	    if(obj->spe > 0) {
	        register int cnt = findit();
		if(cnt == 0) pline(nothing_happens);
		else obj->known = 1;
	        obj->spe--;
	    } else {
	        if(!rn2(3)) goto cursed_bell;
		else pline(nothing_happens);
	    }
        }
}

static void
use_candelabrum(obj)
register struct obj *obj;
{
	if(Underwater) {
		You("can't make fire under water.");
		return;
	}
	if(obj->lamplit) {
		You("snuff the candle%s out.", obj->spe > 1 ? "s" : "");
		obj->lamplit = 0;
		check_lamps();
		return;
	}
	if(obj->spe <= 0) {
		pline("This %s has no candles.", xname(obj));
		return;
	}
	if(u.uswallow || obj->cursed) {
		pline("The candle%s flicker%s on for a moment, then die%s.", 
			obj->spe > 1 ? "s" : "",
			obj->spe > 1 ? "" : "s",
			obj->spe > 1 ? "" : "s");
	        return;
	} 
        if(obj->spe < 7) {
	        pline("There %s only %d candle%s in %s.",
		       obj->spe == 1 ? "is" : "are", 
		       obj->spe,
		       obj->spe > 1 ? "s" : "",
		       the(xname(obj)));
		pline("%s lit.  %s emits a dim light.",
		       obj->spe == 1 ? "It is" : "They are", The(xname(obj)));
	} else {
		pline("%s's candles burn%s", The(xname(obj)),
			(Blind ? "." : " brightly!"));
	}
	if (!invocation_pos(u.ux, u.uy)) {
		pline("The candle%s being rapidly consumed!",
			(obj->spe > 1 ? "s are" : " is"));
		obj->age /= 2;
	} else {
	        if(obj->spe == 7)
	            pline("%s glows with a strange light!", The(xname(obj)));
		obj->known = 1;
	}
	obj->lamplit = 1;
	check_lamps();
}

static void
use_candle(obj)
register struct obj *obj;
{

	register struct obj *otmp;
	char qbuf[QBUFSZ];

	if(obj->lamplit) {
	        use_lamp(obj);
		return;
	}

	if(u.uswallow) {
	        You("don't have enough elbow-room to maneuver.");
		return;
	}
	if(Underwater) {
		pline("Sorry, fire and water don't mix.");
		return;
	}

	for(otmp = invent; otmp; otmp = otmp->nobj) {
		if(otmp->otyp == CANDELABRUM_OF_INVOCATION && otmp->spe < 7)
			break;
	}
	if(!otmp || otmp->spe == 7) {
		use_lamp(obj);
		return;
	}

	Sprintf(qbuf, "Attach %s", the(xname(obj)));
	Sprintf(eos(qbuf), " to %s?", the(xname(otmp)));
	if(yn(qbuf) == 'n') {
		You("try to light %s...", the(xname(obj)));
		use_lamp(obj);
		return;
	} else {
		register long needed = 7L - (long)otmp->spe;

		You("attach %ld%s candle%s to %s.", 
			obj->quan >= needed ? needed : obj->quan,
			!otmp->spe ? "" : " more",
			(needed > 1L && obj->quan > 1L) ? "s" : "",
			the(xname(otmp)));
		if(otmp->lamplit) 
			pline("The new candle%s magically ignite%s!",
			    (needed > 1L && obj->quan > 1L) ? "s" : "",
			    (needed > 1L && obj->quan > 1L) ? "" : "s");
		if(obj->unpaid) 
			You("use %s, you bought %s!",
			    (needed > 1L && obj->quan > 1L) ? "them" : "it",
			    (needed > 1L && obj->quan > 1L) ? "them" : "it");
		if(!otmp->spe || otmp->age > obj->age)
			otmp->age = obj->age;
		if(obj->quan > needed) {
		    if(obj->unpaid) {
			/* this is a hack, until we re-write the billing */
			/* code to accommodate such cases directly. IM*/
			register long delta = obj->quan - needed;

			subfrombill(obj, shop_keeper(*u.ushops));
			obj->quan = needed;
			addtobill(obj, TRUE, FALSE, TRUE);
			bill_dummy_object(obj);
			obj->quan = delta;
			addtobill(obj, TRUE, FALSE, TRUE);
		     } else {
			obj->quan -= needed;
		     }
		     otmp->spe += (int)needed;
		} else {
		    otmp->spe += (int)obj->quan;
		    freeinv(obj);
		    obfree(obj, (struct obj *)0);
		}
		if(needed < 7L && otmp->spe == 7)
		    pline("%s has now seven%s candles attached.",
			The(xname(otmp)), otmp->lamplit ? " lit" : "");
	}
}

boolean
snuff_candle(otmp)  /* call in drop, throw, and put in box, etc. */
register struct obj *otmp;
{
	register boolean candle = Is_candle(otmp);

	if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) &&
		otmp->lamplit) {
	    register boolean many = candle ? otmp->quan > 1L : otmp->spe > 1;
	    pline("The %scandle%s flame%s extinguished.",
		  (candle ? "" : "candelabrum's "),
		  (many ? "s'" : "'s"), (many ? "s are" : " is"));
	   otmp->lamplit = 0;
	   check_lamps();
	   return(TRUE);
	}
	return(FALSE);
}

boolean
snuff_lit(obj)
struct obj *obj;
{
	if(obj->lamplit) {
		if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
				obj->otyp == BRASS_LANTERN) {
			Your("lamp is now off.");
			obj->lamplit = 0;
			check_lamps();
			return(TRUE);
		} 

		if(snuff_candle(obj)) return(TRUE);
	}

	return(FALSE);
}

static void
use_lamp(obj)
struct obj *obj;
{
	if(Underwater) {
		pline("This is not a diving lamp.");
		return;
	}
	if(obj->lamplit) {
		if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
				obj->otyp == BRASS_LANTERN)
		    Your("lamp is now off.");
		else
		    You("snuff out %s.", the(xname(obj)));
		obj->lamplit = 0;
		check_lamps();
		return;
	}
	if (!Is_candle(obj) && obj->spe <= 0) {
		if (obj->otyp == BRASS_LANTERN)
			Your("lamp has run out of power.");
		else pline("This %s has no oil.", xname(obj));
		return;
	}
	if(obj->cursed && !rn2(2))
		pline("%s flicker%s on for a moment, then die%s.", 
		       The(xname(obj)),
		       obj->quan > 1L ? "" : "s",
		       obj->quan > 1L ? "" : "s");
	else {
		if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
				obj->otyp == BRASS_LANTERN)
		    Your("lamp is now on.");
		else
		    pline("%s%s flame%s burn%s%s", The(xname(obj)),
		        obj->quan > 1L ? "'" : "'s",
		        obj->quan > 1L ? "s" : "",
		        obj->quan > 1L ? "" : "s",
			Blind ? "." : " brightly!");
		obj->lamplit = 1;
		check_lamps();
		if (obj->unpaid && Is_candle(obj) &&
			obj->age == 20L * (long)objects[obj->otyp].oc_cost) {
		    const char *it_them = obj->quan > 1L ? "them" : "it";
		    You("use %s, you've bought %s!", it_them, it_them);
		    bill_dummy_object(obj);
		}
	}
}

void
check_lamps()
{
	register struct obj *obj;
	int lamps = 0;

	for(obj = invent; obj; obj = obj->nobj)
		if (obj->lamplit) {
			lamps++;
			break;
		}

	if (lamps && u.nv_range == 1) {
		u.nv_range = 3;
		vision_full_recalc = 1;
	} else if (!lamps && u.nv_range == 3) {
		u.nv_range = 1;
		vision_full_recalc = 1;
	}
}

static const char NEARDATA cuddly[] = { TOOL_CLASS, 0 };

int
dorub()
{
	struct obj *obj = getobj(cuddly, "rub");

	if(!obj || (obj != uwep && !wield_tool(obj))) return 0;

	/* now uwep is obj */
	if (uwep->otyp == MAGIC_LAMP) {
	    if (uwep->spe > 0 && !rn2(3)) {
		djinni_from_bottle(uwep);
		makeknown(MAGIC_LAMP);
		uwep->otyp = OIL_LAMP;
		uwep->spe = 1; /* for safety */
		uwep->age = rn1(500,1000);
	    } else if (rn2(2) && !Blind)
		You("see a puff of smoke.");
	    else pline(nothing_happens);
	} else if (obj->otyp == BRASS_LANTERN) {
	    /* message from Adventure */
	    pline("Rubbing the electric lamp is not particularly rewarding.");
	    pline("Anyway, nothing exciting happens.");
	} else pline(nothing_happens);
	return 1;
}

int
dojump()
{
	coord cc;
	register struct monst *mtmp;
	if (!Jumping || Levitation) {
		You("can't jump very far.");
		return 0;
	} else if (u.uswallow) {
		pline("You've got to be kidding!");
		return 0;
	} else if (u.uinwater) {
		pline("This calls for swimming, not jumping!");
		return 0;
	} else if (u.ustuck) {
		You("cannot escape from %s!", mon_nam(u.ustuck));
		return 0;
	} else if (near_capacity() > UNENCUMBERED) {
		You("are carrying too much to jump!");
		return 0;
	} else if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
		You("lack the strength to jump!");
		return 0;
	}
	pline("Where do you want to jump?");
	cc.x = u.ux;
	cc.y = u.uy;
	getpos(&cc, TRUE, "the desired position");
        if(cc.x == -10) return 0; /* user pressed esc */
	if (!(Jumping & ~INTRINSIC) && distu(cc.x, cc.y) != 5) {
		pline("Illegal move!");
		return 0;
	} else if (distu(cc.x, cc.y) > 9) {
		pline("Too far!");
		return 0;
	} else if (!cansee(cc.x, cc.y)) {
		You("cannot see where to land!");
		return 0;
	} else if (mtmp = m_at(cc.x, cc.y)) {
		You("cannot trample %s!", mon_nam(mtmp));
		return 0;
	} else if (!isok(cc.x, cc.y) ||
#ifdef POLYSELF
		(IS_ROCK(levl[cc.x][cc.y].typ) && !passes_walls(uasmon)) ||
#else
		IS_ROCK(levl[cc.x][cc.y].typ) ||
#endif
		sobj_at(BOULDER, cc.x, cc.x) ) {
			You("cannot jump there!");
			return 0;
	} else {
	    if(u.utrap)
		switch(u.utraptype) {
		case TT_BEARTRAP: {
		    register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
		    You("rip yourself out of the bear trap!  Ouch!");
		    losehp(rnd(10), "jumping out of a bear trap", KILLED_BY);
		    set_wounded_legs(side, rn1(1000,500));
		    break;
		  }
		case TT_PIT:
		    You("leap from the pit!");
		    break;
		case TT_WEB:
		    You("tear the web apart as you pull yourself free!");
		    deltrap(t_at(u.ux,u.uy));
		    break;
		case TT_LAVA:
		    You("pull yourself above the lava!");
		    u.utrap = 0;
		    return 1;
		case TT_INFLOOR:
		    You("strain your %s, but are still stuck in the floor.",
			makeplural(body_part(LEG)));
		    set_wounded_legs(LEFT_SIDE, rn1(10, 11));
		    set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
		    return 1;
		}

	    teleds(cc.x, cc.y);
	    nomul(-1);
	    nomovemsg = "";
	    morehungry(rnd(25));
	    return 1;
	}
}

static void
use_tinning_kit(obj)
register struct obj *obj;
{
	register struct obj *corpse, *can;

	/* This takes only 1 move.  If this is to be changed to take many
	 * moves, we've got to deal with decaying corpses...
	 */
	if (!(corpse = floorfood("can", 1))) return;
	if (corpse->oeaten) {
		You("cannot tin something which is partly eaten.");
		return;
	}
	if ((corpse->corpsenm == PM_COCKATRICE)
#ifdef POLYSELF
		&& !resists_ston(uasmon)
#endif
		&& !uarmg) {
pline("Tinning a cockatrice corpse without gloves was not a very wise move...");
#if defined(POLYSELF)
/* this will have to change if more monsters can poly */
		if(!(poly_when_stoned(uasmon) && polymon(PM_STONE_GOLEM)))
#endif
	    {
		You("turn to stone...");
		killer_format = KILLED_BY;
		killer = "trying to tin a cockatrice without gloves";
		done(STONING);
	    }
	}
	if (mons[corpse->corpsenm].cnutrit == 0) {
		You("can't tin something that insubstantial!");
		return;
	}
	if (is_rider(&mons[corpse->corpsenm])) {
		revive_corpse(corpse, 0, FALSE);
		verbalize("Yes....  But War does not preserve its enemies...");
		return;
	}
	if(can = mksobj(TIN, FALSE, FALSE)) {
	    can->corpsenm = corpse->corpsenm;
	    can->cursed = obj->cursed;
	    can->blessed = obj->blessed;
	    can->owt = weight(can);
	    can->known = 1;
	    can->spe = -1;  /* Mark tinned tins. No spinach allowed... */
	    can = hold_another_object(can, "You make, but cannot pick up, %s.",
				      doname(can), (const char *)0);
	    if (carried(corpse)) useup(corpse);
	    else useupf(corpse);
	} else impossible("Tinning failed.");
}

void
use_unicorn_horn(obj)
struct obj *obj;
{
	boolean blessed = (obj && obj->blessed);
	boolean did_something = FALSE;

	if (obj && obj->cursed) {
		switch (rn2(6)) {
		    static char buf[BUFSZ];
		    case 0: make_sick(Sick ? 1L : (long) rn1(20, 20), TRUE);
			    Strcpy(buf, xname(obj));
			    u.usick_cause = (const char *)buf;
			    break;
		    case 1: make_blinded(Blinded + (long) rnd(100), TRUE);
			    break;
		    case 2: if (!Confusion)
				You("suddenly feel %s.",
					Hallucination ? "trippy" : "confused");
			    make_confused(HConfusion + (long) rnd(100), TRUE);
			    break;
		    case 3: make_stunned(HStun + (long) rnd(100), TRUE);
			    break;
		    case 4: (void) adjattrib(rn2(6), -1, FALSE);
			    break;
		    case 5: make_hallucinated(HHallucination + (long) rnd(100),
				TRUE, 0L);
			    break;
		}
		return;
	}
		
	if (Sick) {
		make_sick(0L, TRUE);
		did_something++;
	}
	if (Blinded > (long)(u.ucreamed+1) && (!did_something || blessed)) {
		make_blinded(u.ucreamed ? (long)(u.ucreamed+1) : 0L, TRUE);
		did_something++;
	}
	if (Hallucination && (!did_something || blessed)) {
		make_hallucinated(0L, TRUE, 0L);
		did_something++;
	}
	if (Vomiting && (!did_something || blessed)) {
		make_vomiting(0L, TRUE);
		did_something++;
	}
	if (HConfusion && (!did_something || blessed)) {
		make_confused(0L, TRUE);
		did_something++;
	}
	if (HStun && (!did_something || blessed)) {
		make_stunned(0L, TRUE);
		did_something++;
	}
	if (!did_something || blessed) {
		register int j;
		int did_stat = 0;
		int i = rn2(A_MAX);
		for(j=0; j<A_MAX; j++) {
			/* don't recover strength lost while hungry */
			if ((blessed || j==i) &&
				((j != A_STR || u.uhs < WEAK)
				? (ABASE(i) < AMAX(i))
				: (ABASE(A_STR) < (AMAX(A_STR) - 1)))) {
				did_something++;
				/* They may have to use it several times... */
				if (!did_stat) {
					did_stat++;
					pline("This makes you feel good!");
				}
				ABASE(i)++;
				flags.botl = 1;
			}
		}
	}
	if (!did_something) pline(nothing_happens);
}

static void
use_figurine(obj)
register struct obj *obj;
{
	xchar x, y;

	if(!getdir(NULL)) {
		flags.move = multi = 0;
		return;
	}
	x = u.ux + u.dx; y = u.uy + u.dy;
	if (!isok(x,y)) {
		You("can't seem to put the figurine there.");
		return;
	}
	if (IS_ROCK(levl[x][y].typ) && !passes_walls(&mons[obj->corpsenm])) {
		You("can't place a figurine in solid rock!");
		return;
	}
	if (sobj_at(BOULDER,x,y) && !passes_walls(&mons[obj->corpsenm])
			&& !throws_rocks(&mons[obj->corpsenm])) {
		You("can't fit the figurine on the boulder.");
		return;
	}
	You("%s and it transforms.",
	    (u.dx||u.dy) ? "set the figurine besides you" :
	    (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) ?
		"release the figurine" :
	    (u.dz < 0 ?
		"toss the figurine into the air" :
		"set the figurine on the ground"));
	make_familiar(obj, u.ux+u.dx, u.uy+u.dy);
	useup(obj);
}

static void
use_grease(obj)
struct obj *obj;
{
	struct obj *otmp;

	if (obj->spe > 0) {
		char allow_all[2];
		if (obj->cursed && !rn2(2)) {
			pline("The %s slips from your fingers!",xname(obj));
			dropx(obj);
			obj->spe -= 1;
			return;
		}
		allow_all[0] = ALL_CLASSES; allow_all[1] = '\0';
		otmp = getobj(allow_all,"grease");
		if (otmp) {
			You("cover your %s with a thick layer of grease.",xname(otmp));
			otmp->greased = 1;
			obj->spe -= 1;
		}
	}
}

int
doapply()
{
	register struct obj *obj;
	register int res = 1;

	if(check_capacity(NULL)) return (0);
	obj = getobj(tools, "use or apply");
	if(!obj) return 0;

	check_unpaid(obj);

	switch(obj->otyp){
	case BLINDFOLD:
		if (obj == ublindf) {
		    if(cursed(obj)) break;
		    else Blindf_off(obj);
		} 
		else if (!ublindf) Blindf_on(obj);
		else You("are already %s", ublindf->otyp == TOWEL ?
			 "covered by a towel." : "wearing a blindfold!");
		break;
	case LARGE_BOX:
	case CHEST:
	case ICE_BOX:
	case SACK:
	case BAG_OF_HOLDING:
	case OILSKIN_SACK:
		res = use_container(obj, 1); 
		break;
	case BAG_OF_TRICKS:
		if(obj->spe > 0) {
			register int cnt = 1;

			obj->spe -= 1;
			if(!rn2(23)) cnt += rn2(7) + 1;
			while(cnt--)
			    (void) makemon((struct permonst *) 0, u.ux, u.uy);
			makeknown(BAG_OF_TRICKS);
		} else
			pline(nothing_happens);
		break;
	case CAN_OF_GREASE:
		use_grease(obj);
		break;
	case LOCK_PICK:
#ifdef TOURIST
	case CREDIT_CARD:
#endif
	case SKELETON_KEY:
		(void) pick_lock(obj);
		break;
	case PICK_AXE:
		res = use_pick_axe(obj);
		break;
	case TINNING_KIT:
		use_tinning_kit(obj);
		break;
#ifdef WALKIES
	case LEASH:
		use_leash(obj);
		break;
#endif
	case MAGIC_WHISTLE:
		use_magic_whistle(obj);
		break;
	case TIN_WHISTLE:
		use_whistle(obj);
		break;
	case STETHOSCOPE:
		res = 0;
		use_stethoscope(obj);
		break;
	case MIRROR:
		res = use_mirror(obj);
		break;
	case BELL:
	case BELL_OF_OPENING:
	        use_bell(obj);
		break;
	case CANDELABRUM_OF_INVOCATION:
		use_candelabrum(obj);
		break;
	case WAX_CANDLE:
	case TALLOW_CANDLE:
		use_candle(obj);
		break;
	case OIL_LAMP:
	case MAGIC_LAMP:
	case BRASS_LANTERN:
		use_lamp(obj);
		break;
#ifdef TOURIST
	case EXPENSIVE_CAMERA:
		res = use_camera(obj); 
		break;
#endif
	case TOWEL:
		res = use_towel(obj); 
		break;
	case CRYSTAL_BALL:
		use_crystal_ball(obj);
		break;
	case MAGIC_MARKER:
		res = dowrite(obj);
		break;
	case TIN_OPENER:
		if(!carrying(TIN)) {
			You("have no tin to open.");
			goto xit;
		}
		You("cannot open a tin without eating or discarding its contents.");
		if(flags.verbose)
			pline("In order to eat, use the 'e' command.");
		if(obj != uwep)
    pline("Opening the tin will be much easier if you wield the tin opener.");
		goto xit;

	case FIGURINE:
		use_figurine(obj);
		break;
	case UNICORN_HORN:
		use_unicorn_horn(obj);
		break;
	case WOODEN_FLUTE:
	case MAGIC_FLUTE:
	case TOOLED_HORN:
	case FROST_HORN:
	case FIRE_HORN:
	case WOODEN_HARP:
	case MAGIC_HARP:
	case BUGLE:
	case LEATHER_DRUM:
	case DRUM_OF_EARTHQUAKE:
		res = do_play_instrument(obj);
		break;
	case HORN_OF_PLENTY:
		if (obj->spe > 0) {
		    struct obj *otmp;
		    const char *what;

#ifdef MAC
			char melody [ 3 ] = { 0 , 0 , 0 } ;
			melody [ 0 ] = rn2 ( 8 ) + 'A' ;
			melody [ 1 ] = rn2 ( 8 ) + 'A' ;
			mac_speaker ( obj , & melody ) ;
#endif

		    obj->spe -= 1;
		    if (!rn2(13)) {
			otmp = mkobj(POTION_CLASS, FALSE);
			if (objects[otmp->otyp].oc_magic) do {
			    otmp->otyp = rnd_class(POT_BOOZE, POT_WATER);
			} while (otmp->otyp == POT_SICKNESS);
			what = "A potion";
		    } else {
			otmp = mkobj(FOOD_CLASS, FALSE);
			if (otmp->otyp == FOOD_RATION && !rn2(7))
			    otmp->otyp = LUMP_OF_ROYAL_JELLY;
			what = "Some food";
		    }
		    pline("%s spills out.", what);
		    otmp->blessed = obj->blessed;
		    otmp->cursed = obj->cursed;
		    otmp->owt = weight(otmp);
		    otmp = hold_another_object(otmp, u.uswallow ?
					       "Oops!  %s away from you!" :
					       "Oops!  %s to the floor!",
					       The(aobjnam(otmp, "slip")),
					       (const char *)0);
		    makeknown(HORN_OF_PLENTY);
		} else
		    pline(nothing_happens);
		break;
	default:
		pline("Sorry, I don't know how to use that.");
	xit:
		nomul(0);
		return 0;
	}
	nomul(0);
	return res;
}

#endif /* OVLB */

/*apply.c*/
