1/*	SCCS Id: @(#)dig.c	3.4	2003/03/23	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6#include "edog.h"
7/* #define DEBUG */	/* turn on for diagnostics */
8
9#ifdef OVLB
10
11static NEARDATA boolean did_dig_msg;
12
13STATIC_DCL boolean NDECL(rm_waslit);
14STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P));
15STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P));
16STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P));
17STATIC_DCL int NDECL(dig);
18STATIC_DCL schar FDECL(fillholetyp, (int, int));
19STATIC_DCL void NDECL(dig_up_grave);
20
21/* Indices returned by dig_typ() */
22#define DIGTYP_UNDIGGABLE 0
23#define DIGTYP_ROCK       1
24#define DIGTYP_STATUE     2
25#define DIGTYP_BOULDER    3
26#define DIGTYP_DOOR       4
27#define DIGTYP_TREE       5
28
29
30STATIC_OVL boolean
31rm_waslit()
32{
33    register xchar x, y;
34
35    if(levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit)
36	return(TRUE);
37    for(x = u.ux-2; x < u.ux+3; x++)
38	for(y = u.uy-1; y < u.uy+2; y++)
39	    if(isok(x,y) && levl[x][y].waslit) return(TRUE);
40    return(FALSE);
41}
42
43/* Change level topology.  Messes with vision tables and ignores things like
44 * boulders in the name of a nice effect.  Vision will get fixed up again
45 * immediately after the effect is complete.
46 */
47STATIC_OVL void
48mkcavepos(x, y, dist, waslit, rockit)
49    xchar x,y;
50    int dist;
51    boolean waslit, rockit;
52{
53    register struct rm *lev;
54
55    if(!isok(x,y)) return;
56    lev = &levl[x][y];
57
58    if(rockit) {
59	register struct monst *mtmp;
60
61	if(IS_ROCK(lev->typ)) return;
62	if(t_at(x, y)) return; /* don't cover the portal */
63	if ((mtmp = m_at(x, y)) != 0)	/* make sure crucial monsters survive */
64	    if(!passes_walls(mtmp->data)) (void) rloc(mtmp, FALSE);
65    } else if(lev->typ == ROOM) return;
66
67    unblock_point(x,y);	/* make sure vision knows this location is open */
68
69    /* fake out saved state */
70    lev->seenv = 0;
71    lev->doormask = 0;
72    if(dist < 3) lev->lit = (rockit ? FALSE : TRUE);
73    if(waslit) lev->waslit = (rockit ? FALSE : TRUE);
74    lev->horizontal = FALSE;
75    viz_array[y][x] = (dist < 3 ) ?
76	(IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
77	COULD_SEE;
78    lev->typ = (rockit ? STONE : ROOM);
79    if(dist >= 3)
80	impossible("mkcavepos called with dist %d", dist);
81    if(Blind)
82	feel_location(x, y);
83    else newsym(x,y);
84}
85
86STATIC_OVL void
87mkcavearea(rockit)
88register boolean rockit;
89{
90    int dist;
91    xchar xmin = u.ux, xmax = u.ux;
92    xchar ymin = u.uy, ymax = u.uy;
93    register xchar i;
94    register boolean waslit = rm_waslit();
95
96    if(rockit) pline("Crash!  The ceiling collapses around you!");
97    else pline("A mysterious force %s cave around you!",
98	     (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the");
99    display_nhwindow(WIN_MESSAGE, TRUE);
100
101    for(dist = 1; dist <= 2; dist++) {
102	xmin--; xmax++;
103
104	/* top and bottom */
105	if(dist < 2) { /* the area is wider that it is high */
106	    ymin--; ymax++;
107	    for(i = xmin+1; i < xmax; i++) {
108		mkcavepos(i, ymin, dist, waslit, rockit);
109		mkcavepos(i, ymax, dist, waslit, rockit);
110	    }
111	}
112
113	/* left and right */
114	for(i = ymin; i <= ymax; i++) {
115	    mkcavepos(xmin, i, dist, waslit, rockit);
116	    mkcavepos(xmax, i, dist, waslit, rockit);
117	}
118
119	flush_screen(1);	/* make sure the new glyphs shows up */
120	delay_output();
121    }
122
123    if(!rockit && levl[u.ux][u.uy].typ == CORR) {
124	levl[u.ux][u.uy].typ = ROOM;
125	if(waslit) levl[u.ux][u.uy].waslit = TRUE;
126	newsym(u.ux, u.uy); /* in case player is invisible */
127    }
128
129    vision_full_recalc = 1;	/* everything changed */
130}
131
132/* When digging into location <x,y>, what are you actually digging into? */
133STATIC_OVL int
134dig_typ(otmp, x, y)
135struct obj *otmp;
136xchar x, y;
137{
138	boolean ispick = is_pick(otmp);
139
140	return (ispick && sobj_at(STATUE, x, y) ? DIGTYP_STATUE :
141		ispick && sobj_at(BOULDER, x, y) ? DIGTYP_BOULDER :
142		closed_door(x, y) ? DIGTYP_DOOR :
143		IS_TREE(levl[x][y].typ) ?
144			(ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) :
145		ispick && IS_ROCK(levl[x][y].typ) &&
146			(!level.flags.arboreal || IS_WALL(levl[x][y].typ)) ?
147			DIGTYP_ROCK : DIGTYP_UNDIGGABLE);
148}
149
150boolean
151is_digging()
152{
153	if (occupation == dig) {
154	    return TRUE;
155	}
156	return FALSE;
157}
158
159#define BY_YOU		(&youmonst)
160#define BY_OBJECT	((struct monst *)0)
161
162boolean
163dig_check(madeby, verbose, x, y)
164	struct monst	*madeby;
165	boolean		verbose;
166	int		x, y;
167{
168	struct trap *ttmp = t_at(x, y);
169	const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
170
171	if (On_stairs(x, y)) {
172	    if (x == xdnladder || x == xupladder) {
173		if(verbose) pline_The("ladder resists your effort.");
174	    } else if(verbose) pline_The("stairs are too hard to %s.", verb);
175	    return(FALSE);
176	} else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
177	    if(verbose) pline_The("throne is too hard to break apart.");
178	    return(FALSE);
179	} else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT ||
180				Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) {
181	    if(verbose) pline_The("altar is too hard to break apart.");
182	    return(FALSE);
183	} else if (Is_airlevel(&u.uz)) {
184	    if(verbose) You("cannot %s thin air.", verb);
185	    return(FALSE);
186	} else if (Is_waterlevel(&u.uz)) {
187	    if(verbose) pline_The("water splashes and subsides.");
188	    return(FALSE);
189	} else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR &&
190		      (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
191		|| (ttmp &&
192		      (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) {
193	    if(verbose) pline_The("%s here is too hard to %s.",
194				  surface(x,y), verb);
195	    return(FALSE);
196	} else if (sobj_at(BOULDER, x, y)) {
197	    if(verbose) There("isn't enough room to %s here.", verb);
198	    return(FALSE);
199	} else if (madeby == BY_OBJECT &&
200		    /* the block against existing traps is mainly to
201		       prevent broken wands from turning holes into pits */
202		    (ttmp || is_pool(x,y) || is_lava(x,y))) {
203	    /* digging by player handles pools separately */
204	    return FALSE;
205	}
206	return(TRUE);
207}
208
209STATIC_OVL int
210dig()
211{
212	register struct rm *lev;
213	register xchar dpx = digging.pos.x, dpy = digging.pos.y;
214	register boolean ispick = uwep && is_pick(uwep);
215	const char *verb =
216	    (!uwep || is_pick(uwep)) ? "dig into" : "chop through";
217
218	lev = &levl[dpx][dpy];
219	/* perhaps a nymph stole your pick-axe while you were busy digging */
220	/* or perhaps you teleported away */
221	if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) ||
222	    !on_level(&digging.level, &u.uz) ||
223	    ((digging.down ? (dpx != u.ux || dpy != u.uy)
224			   : (distu(dpx,dpy) > 2))))
225		return(0);
226
227	if (digging.down) {
228	    if(!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return(0);
229	} else { /* !digging.down */
230	    if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) &&
231			dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) {
232		pline("This tree seems to be petrified.");
233		return(0);
234	    }
235	    if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) &&
236			dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) {
237		pline("This wall is too hard to %s.", verb);
238		return(0);
239	    }
240	}
241	if(Fumbling && !rn2(3)) {
242	    switch(rn2(3)) {
243	    case 0:
244		if(!welded(uwep)) {
245		    You("fumble and drop your %s.", xname(uwep));
246		    dropx(uwep);
247		} else {
248#ifdef STEED
249		    if (u.usteed)
250			Your("%s %s and %s %s!",
251			     xname(uwep),
252			     otense(uwep, "bounce"), otense(uwep, "hit"),
253			     mon_nam(u.usteed));
254		    else
255#endif
256			pline("Ouch!  Your %s %s and %s you!",
257			      xname(uwep),
258			      otense(uwep, "bounce"), otense(uwep, "hit"));
259		    set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
260		}
261		break;
262	    case 1:
263		pline("Bang!  You hit with the broad side of %s!",
264		      the(xname(uwep)));
265		break;
266	    default: Your("swing misses its mark.");
267		break;
268	    }
269	    return(0);
270	}
271
272	digging.effort += 10 + rn2(5) + abon() +
273			   uwep->spe - greatest_erosion(uwep) + u.udaminc;
274	if (Race_if(PM_DWARF))
275	    digging.effort *= 2;
276	if (digging.down) {
277		register struct trap *ttmp;
278
279		if (digging.effort > 250) {
280		    (void) dighole(FALSE);
281		    (void) memset((genericptr_t)&digging, 0, sizeof digging);
282		    return(0);	/* done with digging */
283		}
284
285		if (digging.effort <= 50 ||
286		    ((ttmp = t_at(dpx,dpy)) != 0 &&
287			(ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT ||
288			 ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)))
289		    return(1);
290
291		if (IS_ALTAR(lev->typ)) {
292		    altar_wrath(dpx, dpy);
293		    angry_priest();
294		}
295
296		if (dighole(TRUE)) {	/* make pit at <u.ux,u.uy> */
297		    digging.level.dnum = 0;
298		    digging.level.dlevel = -1;
299		}
300		return(0);
301	}
302
303	if (digging.effort > 100) {
304		register const char *digtxt, *dmgtxt = (const char*) 0;
305		register struct obj *obj;
306		register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE);
307
308		if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) {
309			if (break_statue(obj))
310				digtxt = "The statue shatters.";
311			else
312				/* it was a statue trap; break_statue()
313				 * printed a message and updated the screen
314				 */
315				digtxt = (char *)0;
316		} else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) {
317			struct obj *bobj;
318
319			fracture_rock(obj);
320			if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) {
321			    /* another boulder here, restack it to the top */
322			    obj_extract_self(bobj);
323			    place_object(bobj, dpx, dpy);
324			}
325			digtxt = "The boulder falls apart.";
326		} else if (lev->typ == STONE || lev->typ == SCORR ||
327				IS_TREE(lev->typ)) {
328			if(Is_earthlevel(&u.uz)) {
329			    if(uwep->blessed && !rn2(3)) {
330				mkcavearea(FALSE);
331				goto cleanup;
332			    } else if((uwep->cursed && !rn2(4)) ||
333					  (!uwep->blessed && !rn2(6))) {
334				mkcavearea(TRUE);
335				goto cleanup;
336			    }
337			}
338			if (IS_TREE(lev->typ)) {
339			    digtxt = "You cut down the tree.";
340			    lev->typ = ROOM;
341			    if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy);
342			} else {
343			    digtxt = "You succeed in cutting away some rock.";
344			    lev->typ = CORR;
345			}
346		} else if(IS_WALL(lev->typ)) {
347			if(shopedge) {
348			    add_damage(dpx, dpy, 10L * ACURRSTR);
349			    dmgtxt = "damage";
350			}
351			if (level.flags.is_maze_lev) {
352			    lev->typ = ROOM;
353			} else if (level.flags.is_cavernous_lev &&
354				   !in_town(dpx, dpy)) {
355			    lev->typ = CORR;
356			} else {
357			    lev->typ = DOOR;
358			    lev->doormask = D_NODOOR;
359			}
360			digtxt = "You make an opening in the wall.";
361		} else if(lev->typ == SDOOR) {
362			cvt_sdoor_to_door(lev);	/* ->typ = DOOR */
363			digtxt = "You break through a secret door!";
364			if(!(lev->doormask & D_TRAPPED))
365				lev->doormask = D_BROKEN;
366		} else if(closed_door(dpx, dpy)) {
367			digtxt = "You break through the door.";
368			if(shopedge) {
369			    add_damage(dpx, dpy, 400L);
370			    dmgtxt = "break";
371			}
372			if(!(lev->doormask & D_TRAPPED))
373				lev->doormask = D_BROKEN;
374		} else return(0); /* statue or boulder got taken */
375
376		if(!does_block(dpx,dpy,&levl[dpx][dpy]))
377		    unblock_point(dpx,dpy);	/* vision:  can see through */
378		if(Blind)
379		    feel_location(dpx, dpy);
380		else
381		    newsym(dpx, dpy);
382		if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */
383		if(dmgtxt)
384		    pay_for_damage(dmgtxt, FALSE);
385
386		if(Is_earthlevel(&u.uz) && !rn2(3)) {
387		    register struct monst *mtmp;
388
389		    switch(rn2(2)) {
390		      case 0:
391			mtmp = makemon(&mons[PM_EARTH_ELEMENTAL],
392					dpx, dpy, NO_MM_FLAGS);
393			break;
394		      default:
395			mtmp = makemon(&mons[PM_XORN],
396					dpx, dpy, NO_MM_FLAGS);
397			break;
398		    }
399		    if(mtmp) pline_The("debris from your digging comes to life!");
400		}
401		if(IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) {
402			lev->doormask = D_NODOOR;
403			b_trapped("door", 0);
404			newsym(dpx, dpy);
405		}
406cleanup:
407		digging.lastdigtime = moves;
408		digging.quiet = FALSE;
409		digging.level.dnum = 0;
410		digging.level.dlevel = -1;
411		return(0);
412	} else {		/* not enough effort has been spent yet */
413		static const char *const d_target[6] = {
414			"", "rock", "statue", "boulder", "door", "tree"
415		};
416		int dig_target = dig_typ(uwep, dpx, dpy);
417
418		if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) {
419		    if(*in_rooms(dpx, dpy, SHOPBASE)) {
420			pline("This %s seems too hard to %s.",
421			      IS_DOOR(lev->typ) ? "door" : "wall", verb);
422			return(0);
423		    }
424		} else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK)
425		    return(0); /* statue or boulder got taken */
426		if(!did_dig_msg) {
427		    You("hit the %s with all your might.",
428			d_target[dig_target]);
429		    did_dig_msg = TRUE;
430		}
431	}
432	return(1);
433}
434
435/* When will hole be finished? Very rough indication used by shopkeeper. */
436int
437holetime()
438{
439	if(occupation != dig || !*u.ushops) return(-1);
440	return ((250 - digging.effort) / 20);
441}
442
443/* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
444STATIC_OVL
445schar
446fillholetyp(x,y)
447int x, y;
448{
449    register int x1, y1;
450    int lo_x = max(1,x-1), hi_x = min(x+1,COLNO-1),
451	lo_y = max(0,y-1), hi_y = min(y+1,ROWNO-1);
452    int pool_cnt = 0, moat_cnt = 0, lava_cnt = 0;
453
454    for (x1 = lo_x; x1 <= hi_x; x1++)
455	for (y1 = lo_y; y1 <= hi_y; y1++)
456	    if (levl[x1][y1].typ == POOL)
457		pool_cnt++;
458	    else if (levl[x1][y1].typ == MOAT ||
459		    (levl[x1][y1].typ == DRAWBRIDGE_UP &&
460			(levl[x1][y1].drawbridgemask & DB_UNDER) == DB_MOAT))
461		moat_cnt++;
462	    else if (levl[x1][y1].typ == LAVAPOOL ||
463		    (levl[x1][y1].typ == DRAWBRIDGE_UP &&
464			(levl[x1][y1].drawbridgemask & DB_UNDER) == DB_LAVA))
465		lava_cnt++;
466    pool_cnt /= 3;		/* not as much liquid as the others */
467
468    if (lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1))
469	return LAVAPOOL;
470    else if (moat_cnt > 0 && rn2(moat_cnt + 1))
471	return MOAT;
472    else if (pool_cnt > 0 && rn2(pool_cnt + 1))
473	return POOL;
474    else
475	return ROOM;
476}
477
478void
479digactualhole(x, y, madeby, ttyp)
480register int	x, y;
481struct monst	*madeby;
482int ttyp;
483{
484	struct obj *oldobjs, *newobjs;
485	register struct trap *ttmp;
486	char surface_type[BUFSZ];
487	struct rm *lev = &levl[x][y];
488	boolean shopdoor;
489	struct monst *mtmp = m_at(x, y);	/* may be madeby */
490	boolean madeby_u = (madeby == BY_YOU);
491	boolean madeby_obj = (madeby == BY_OBJECT);
492	boolean at_u = (x == u.ux) && (y == u.uy);
493	boolean wont_fall = Levitation || Flying;
494
495	if (u.utrap && u.utraptype == TT_INFLOOR) u.utrap = 0;
496
497	/* these furniture checks were in dighole(), but wand
498	   breaking bypasses that routine and calls us directly */
499	if (IS_FOUNTAIN(lev->typ)) {
500	    dogushforth(FALSE);
501	    SET_FOUNTAIN_WARNED(x,y);		/* force dryup */
502	    dryup(x, y, madeby_u);
503	    return;
504#ifdef SINKS
505	} else if (IS_SINK(lev->typ)) {
506	    breaksink(x, y);
507	    return;
508#endif
509	} else if (lev->typ == DRAWBRIDGE_DOWN ||
510		   (is_drawbridge_wall(x, y) >= 0)) {
511	    int bx = x, by = y;
512	    /* if under the portcullis, the bridge is adjacent */
513	    (void) find_drawbridge(&bx, &by);
514	    destroy_drawbridge(bx, by);
515	    return;
516	}
517
518	if (ttyp != PIT && !Can_dig_down(&u.uz)) {
519	    impossible("digactualhole: can't dig %s on this level.",
520		       defsyms[trap_to_defsym(ttyp)].explanation);
521	    ttyp = PIT;
522	}
523
524	/* maketrap() might change it, also, in this situation,
525	   surface() returns an inappropriate string for a grave */
526	if (IS_GRAVE(lev->typ))
527	    Strcpy(surface_type, "grave");
528	else
529	    Strcpy(surface_type, surface(x,y));
530	shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE);
531	oldobjs = level.objects[x][y];
532	ttmp = maketrap(x, y, ttyp);
533	if (!ttmp) return;
534	newobjs = level.objects[x][y];
535	ttmp->tseen = (madeby_u || cansee(x,y));
536	ttmp->madeby_u = madeby_u;
537	newsym(ttmp->tx,ttmp->ty);
538
539	if (ttyp == PIT) {
540
541	    if(madeby_u) {
542		You("dig a pit in the %s.", surface_type);
543		if (shopdoor) pay_for_damage("ruin", FALSE);
544	    } else if (!madeby_obj && canseemon(madeby))
545		pline("%s digs a pit in the %s.", Monnam(madeby), surface_type);
546	    else if (cansee(x, y) && flags.verbose)
547		pline("A pit appears in the %s.", surface_type);
548
549	    if(at_u) {
550		if (!wont_fall) {
551		    if (!Passes_walls)
552			u.utrap = rn1(4,2);
553		    u.utraptype = TT_PIT;
554		    vision_full_recalc = 1;	/* vision limits change */
555		} else
556		    u.utrap = 0;
557		if (oldobjs != newobjs)	/* something unearthed */
558			(void) pickup(1);	/* detects pit */
559	    } else if(mtmp) {
560		if(is_flyer(mtmp->data) || is_floater(mtmp->data)) {
561		    if(canseemon(mtmp))
562			pline("%s %s over the pit.", Monnam(mtmp),
563						     (is_flyer(mtmp->data)) ?
564						     "flies" : "floats");
565		} else if(mtmp != madeby)
566		    (void) mintrap(mtmp);
567	    }
568	} else {	/* was TRAPDOOR now a HOLE*/
569
570	    if(madeby_u)
571		You("dig a hole through the %s.", surface_type);
572	    else if(!madeby_obj && canseemon(madeby))
573		pline("%s digs a hole through the %s.",
574		      Monnam(madeby), surface_type);
575	    else if(cansee(x, y) && flags.verbose)
576		pline("A hole appears in the %s.", surface_type);
577
578	    if (at_u) {
579		if (!u.ustuck && !wont_fall && !next_to_u()) {
580		    You("are jerked back by your pet!");
581		    wont_fall = TRUE;
582		}
583
584		/* Floor objects get a chance of falling down.  The case where
585		 * the hero does NOT fall down is treated here.  The case
586		 * where the hero does fall down is treated in goto_level().
587		 */
588		if (u.ustuck || wont_fall) {
589		    if (newobjs)
590			impact_drop((struct obj *)0, x, y, 0);
591		    if (oldobjs != newobjs)
592			(void) pickup(1);
593		    if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
594
595		} else {
596		    d_level newlevel;
597
598		    if (*u.ushops && madeby_u)
599			shopdig(1); /* shk might snatch pack */
600		    /* handle earlier damage, eg breaking wand of digging */
601		    else if (!madeby_u) pay_for_damage("dig into", TRUE);
602
603		    You("fall through...");
604		    /* Earlier checks must ensure that the destination
605		     * level exists and is in the present dungeon.
606		     */
607		    newlevel.dnum = u.uz.dnum;
608		    newlevel.dlevel = u.uz.dlevel + 1;
609		    goto_level(&newlevel, FALSE, TRUE, FALSE);
610		    /* messages for arriving in special rooms */
611		    spoteffects(FALSE);
612		}
613	    } else {
614		if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
615		if (newobjs)
616		    impact_drop((struct obj *)0, x, y, 0);
617		if (mtmp) {
618		     /*[don't we need special sokoban handling here?]*/
619		    if (is_flyer(mtmp->data) || is_floater(mtmp->data) ||
620		        mtmp->data == &mons[PM_WUMPUS] ||
621			(mtmp->wormno && count_wsegs(mtmp) > 5) ||
622			mtmp->data->msize >= MZ_HUGE) return;
623		    if (mtmp == u.ustuck)	/* probably a vortex */
624			    return;		/* temporary? kludge */
625
626		    if (teleport_pet(mtmp, FALSE)) {
627			d_level tolevel;
628
629			if (Is_stronghold(&u.uz)) {
630			    assign_level(&tolevel, &valley_level);
631			} else if (Is_botlevel(&u.uz)) {
632			    if (canseemon(mtmp))
633				pline("%s avoids the trap.", Monnam(mtmp));
634			    return;
635			} else {
636			    get_level(&tolevel, depth(&u.uz) + 1);
637			}
638			if (mtmp->isshk) make_angry_shk(mtmp, 0, 0);
639			migrate_to_level(mtmp, ledger_no(&tolevel),
640					 MIGR_RANDOM, (coord *)0);
641		    }
642		}
643	    }
644	}
645}
646
647/* return TRUE if digging succeeded, FALSE otherwise */
648boolean
649dighole(pit_only)
650boolean pit_only;
651{
652	register struct trap *ttmp = t_at(u.ux, u.uy);
653	struct rm *lev = &levl[u.ux][u.uy];
654	struct obj *boulder_here;
655	schar typ;
656	boolean nohole = !Can_dig_down(&u.uz);
657
658	if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) ||
659	   (IS_ROCK(lev->typ) && lev->typ != SDOOR &&
660	    (lev->wall_info & W_NONDIGGABLE) != 0)) {
661		pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy));
662
663	} else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
664		pline_The("%s sloshes furiously for a moment, then subsides.",
665			is_lava(u.ux, u.uy) ? "lava" : "water");
666		wake_nearby();	/* splashing */
667
668	} else if (lev->typ == DRAWBRIDGE_DOWN ||
669		   (is_drawbridge_wall(u.ux, u.uy) >= 0)) {
670		/* drawbridge_down is the platform crossing the moat when the
671		   bridge is extended; drawbridge_wall is the open "doorway" or
672		   closed "door" where the portcullis/mechanism is located */
673		if (pit_only) {
674		    pline_The("drawbridge seems too hard to dig through.");
675		    return FALSE;
676		} else {
677		    int x = u.ux, y = u.uy;
678		    /* if under the portcullis, the bridge is adjacent */
679		    (void) find_drawbridge(&x, &y);
680		    destroy_drawbridge(x, y);
681		    return TRUE;
682		}
683
684	} else if ((boulder_here = sobj_at(BOULDER, u.ux, u.uy)) != 0) {
685		if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
686		    rn2(2)) {
687			pline_The("boulder settles into the pit.");
688			ttmp->ttyp = PIT;	 /* crush spikes */
689		} else {
690			/*
691			 * digging makes a hole, but the boulder immediately
692			 * fills it.  Final outcome:  no hole, no boulder.
693			 */
694			pline("KADOOM! The boulder falls in!");
695			(void) delfloortrap(ttmp);
696		}
697		delobj(boulder_here);
698		return TRUE;
699
700	} else if (IS_GRAVE(lev->typ)) {
701	    digactualhole(u.ux, u.uy, BY_YOU, PIT);
702	    dig_up_grave();
703	    return TRUE;
704	} else if (lev->typ == DRAWBRIDGE_UP) {
705		/* must be floor or ice, other cases handled above */
706		/* dig "pit" and let fluid flow in (if possible) */
707		typ = fillholetyp(u.ux,u.uy);
708
709		if (typ == ROOM) {
710			/*
711			 * We can't dig a hole here since that will destroy
712			 * the drawbridge.  The following is a cop-out. --dlc
713			 */
714			pline_The("%s here is too hard to dig in.",
715			      surface(u.ux, u.uy));
716			return FALSE;
717		}
718
719		lev->drawbridgemask &= ~DB_UNDER;
720		lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT;
721
722 liquid_flow:
723		if (ttmp) (void) delfloortrap(ttmp);
724		/* if any objects were frozen here, they're released now */
725		unearth_objs(u.ux, u.uy);
726
727		pline("As you dig, the hole fills with %s!",
728		      typ == LAVAPOOL ? "lava" : "water");
729		if (!Levitation && !Flying) {
730		    if (typ == LAVAPOOL)
731			(void) lava_effects();
732		    else if (!Wwalking)
733			(void) drown();
734		}
735		return TRUE;
736
737	/* the following two are here for the wand of digging */
738	} else if (IS_THRONE(lev->typ)) {
739		pline_The("throne is too hard to break apart.");
740
741	} else if (IS_ALTAR(lev->typ)) {
742		pline_The("altar is too hard to break apart.");
743
744	} else {
745		typ = fillholetyp(u.ux,u.uy);
746
747		if (typ != ROOM) {
748			lev->typ = typ;
749			goto liquid_flow;
750		}
751
752		/* finally we get to make a hole */
753		if (nohole || pit_only)
754			digactualhole(u.ux, u.uy, BY_YOU, PIT);
755		else
756			digactualhole(u.ux, u.uy, BY_YOU, HOLE);
757
758		return TRUE;
759	}
760
761	return FALSE;
762}
763
764STATIC_OVL void
765dig_up_grave()
766{
767	struct obj *otmp;
768
769	/* Grave-robbing is frowned upon... */
770	exercise(A_WIS, FALSE);
771	if (Role_if(PM_ARCHEOLOGIST)) {
772	    adjalign(-sgn(u.ualign.type)*3);
773	    You_feel("like a despicable grave-robber!");
774	} else if (Role_if(PM_SAMURAI)) {
775	    adjalign(-sgn(u.ualign.type));
776	    You("disturb the honorable dead!");
777	} else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
778	    adjalign(-sgn(u.ualign.type));
779	    You("have violated the sanctity of this grave!");
780	}
781
782	switch (rn2(5)) {
783	case 0:
784	case 1:
785	    You("unearth a corpse.");
786	    if (!!(otmp = mk_tt_object(CORPSE, u.ux, u.uy)))
787	    	otmp->age -= 100;		/* this is an *OLD* corpse */;
788	    break;
789	case 2:
790	    if (!Blind) pline(Hallucination ? "Dude!  The living dead!" :
791 			"The grave's owner is very upset!");
792 	    (void) makemon(mkclass(S_ZOMBIE,0), u.ux, u.uy, NO_MM_FLAGS);
793	    break;
794	case 3:
795	    if (!Blind) pline(Hallucination ? "I want my mummy!" :
796 			"You've disturbed a tomb!");
797 	    (void) makemon(mkclass(S_MUMMY,0), u.ux, u.uy, NO_MM_FLAGS);
798	    break;
799	default:
800	    /* No corpse */
801	    pline_The("grave seems unused.  Strange....");
802	    break;
803	}
804	levl[u.ux][u.uy].typ = ROOM;
805	del_engr_at(u.ux, u.uy);
806	newsym(u.ux,u.uy);
807	return;
808}
809
810int
811use_pick_axe(obj)
812struct obj *obj;
813{
814	boolean ispick;
815	char dirsyms[12];
816	char qbuf[QBUFSZ];
817	register char *dsp = dirsyms;
818	register int rx, ry;
819	int res = 0;
820	register const char *sdp, *verb;
821
822	if(iflags.num_pad) sdp = ndir; else sdp = sdir;	/* DICE workaround */
823
824	/* Check tool */
825	if (obj != uwep) {
826	    if (!wield_tool(obj, "swing")) return 0;
827	    else res = 1;
828	}
829	ispick = is_pick(obj);
830	verb = ispick ? "dig" : "chop";
831
832	if (u.utrap && u.utraptype == TT_WEB) {
833	    pline("%s you can't %s while entangled in a web.",
834		  /* res==0 => no prior message;
835		     res==1 => just got "You now wield a pick-axe." message */
836		  !res ? "Unfortunately," : "But", verb);
837	    return res;
838	}
839
840	while(*sdp) {
841		(void) movecmd(*sdp);	/* sets u.dx and u.dy and u.dz */
842		rx = u.ux + u.dx;
843		ry = u.uy + u.dy;
844		/* Include down even with axe, so we have at least one direction */
845		if (u.dz > 0 ||
846		    (u.dz == 0 && isok(rx, ry) &&
847		     dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE))
848			*dsp++ = *sdp;
849		sdp++;
850	}
851	*dsp = 0;
852	Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms);
853	if(!getdir(qbuf))
854		return(res);
855
856	return(use_pick_axe2(obj));
857}
858
859/* MRKR: use_pick_axe() is split in two to allow autodig to bypass */
860/*       the "In what direction do you want to dig?" query.        */
861/*       use_pick_axe2() uses the existing u.dx, u.dy and u.dz    */
862
863int
864use_pick_axe2(obj)
865struct obj *obj;
866{
867	register int rx, ry;
868	register struct rm *lev;
869	int dig_target;
870	boolean ispick = is_pick(obj);
871	const char *verbing = ispick ? "digging" : "chopping";
872
873	if (u.uswallow && attack(u.ustuck)) {
874		;  /* return(1) */
875	} else if (Underwater) {
876		pline("Turbulence torpedoes your %s attempts.", verbing);
877	} else if(u.dz < 0) {
878		if(Levitation)
879			You("don't have enough leverage.");
880		else
881			You_cant("reach the %s.",ceiling(u.ux,u.uy));
882	} else if(!u.dx && !u.dy && !u.dz) {
883		char buf[BUFSZ];
884		int dam;
885
886		dam = rnd(2) + dbon() + obj->spe;
887		if (dam <= 0) dam = 1;
888		You("hit yourself with %s.", yname(uwep));
889		Sprintf(buf, "%s own %s", uhis(),
890				OBJ_NAME(objects[obj->otyp]));
891		losehp(dam, buf, KILLED_BY);
892		flags.botl=1;
893		return(1);
894	} else if(u.dz == 0) {
895		if(Stunned || (Confusion && !rn2(5))) confdir();
896		rx = u.ux + u.dx;
897		ry = u.uy + u.dy;
898		if(!isok(rx, ry)) {
899			pline("Clash!");
900			return(1);
901		}
902		lev = &levl[rx][ry];
903		if(MON_AT(rx, ry) && attack(m_at(rx, ry)))
904			return(1);
905		dig_target = dig_typ(obj, rx, ry);
906		if (dig_target == DIGTYP_UNDIGGABLE) {
907			/* ACCESSIBLE or POOL */
908			struct trap *trap = t_at(rx, ry);
909
910			if (trap && trap->ttyp == WEB) {
911			    if (!trap->tseen) {
912				seetrap(trap);
913				There("is a spider web there!");
914			    }
915			    Your("%s entangled in the web.",
916				aobjnam(obj, "become"));
917			    /* you ought to be able to let go; tough luck */
918			    /* (maybe `move_into_trap()' would be better) */
919			    nomul(-d(2,2));
920			    nomovemsg = "You pull free.";
921			} else if (lev->typ == IRONBARS) {
922			    pline("Clang!");
923			    wake_nearby();
924			} else if (IS_TREE(lev->typ))
925			    You("need an axe to cut down a tree.");
926			else if (IS_ROCK(lev->typ))
927			    You("need a pick to dig rock.");
928			else if (!ispick && (sobj_at(STATUE, rx, ry) ||
929					     sobj_at(BOULDER, rx, ry))) {
930			    boolean vibrate = !rn2(3);
931			    pline("Sparks fly as you whack the %s.%s",
932				sobj_at(STATUE, rx, ry) ? "statue" : "boulder",
933				vibrate ? " The axe-handle vibrates violently!" : "");
934			    if (vibrate) losehp(2, "axing a hard object", KILLED_BY);
935			}
936			else
937			    You("swing your %s through thin air.",
938				aobjnam(obj, (char *)0));
939		} else {
940			static const char * const d_action[6] = {
941						"swinging",
942						"digging",
943						"chipping the statue",
944						"hitting the boulder",
945						"chopping at the door",
946						"cutting the tree"
947			};
948			did_dig_msg = FALSE;
949			digging.quiet = FALSE;
950			if (digging.pos.x != rx || digging.pos.y != ry ||
951			    !on_level(&digging.level, &u.uz) || digging.down) {
952			    if (flags.autodig &&
953				dig_target == DIGTYP_ROCK && !digging.down &&
954				digging.pos.x == u.ux &&
955				digging.pos.y == u.uy &&
956				(moves <= digging.lastdigtime+2 &&
957				 moves >= digging.lastdigtime)) {
958				/* avoid messages if repeated autodigging */
959				did_dig_msg = TRUE;
960				digging.quiet = TRUE;
961			    }
962			    digging.down = digging.chew = FALSE;
963			    digging.warned = FALSE;
964			    digging.pos.x = rx;
965			    digging.pos.y = ry;
966			    assign_level(&digging.level, &u.uz);
967			    digging.effort = 0;
968			    if (!digging.quiet)
969				You("start %s.", d_action[dig_target]);
970			} else {
971			    You("%s %s.", digging.chew ? "begin" : "continue",
972					d_action[dig_target]);
973			    digging.chew = FALSE;
974			}
975			set_occupation(dig, verbing, 0);
976		}
977	} else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
978		/* it must be air -- water checked above */
979		You("swing your %s through thin air.", aobjnam(obj, (char *)0));
980	} else if (!can_reach_floor()) {
981		You_cant("reach the %s.", surface(u.ux,u.uy));
982	} else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
983		/* Monsters which swim also happen not to be able to dig */
984		You("cannot stay under%s long enough.",
985				is_pool(u.ux, u.uy) ? "water" : " the lava");
986	} else if (!ispick) {
987		Your("%s merely scratches the %s.",
988				aobjnam(obj, (char *)0), surface(u.ux,u.uy));
989		u_wipe_engr(3);
990	} else {
991		if (digging.pos.x != u.ux || digging.pos.y != u.uy ||
992			!on_level(&digging.level, &u.uz) || !digging.down) {
993		    digging.chew = FALSE;
994		    digging.down = TRUE;
995		    digging.warned = FALSE;
996		    digging.pos.x = u.ux;
997		    digging.pos.y = u.uy;
998		    assign_level(&digging.level, &u.uz);
999		    digging.effort = 0;
1000		    You("start %s downward.", verbing);
1001		    if (*u.ushops) shopdig(0);
1002		} else
1003		    You("continue %s downward.", verbing);
1004		did_dig_msg = FALSE;
1005		set_occupation(dig, verbing, 0);
1006	}
1007	return(1);
1008}
1009
1010/*
1011 * Town Watchmen frown on damage to the town walls, trees or fountains.
1012 * It's OK to dig holes in the ground, however.
1013 * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0
1014 * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing)
1015 */
1016void
1017watch_dig(mtmp, x, y, zap)
1018    struct monst *mtmp;
1019    xchar x, y;
1020    boolean zap;
1021{
1022	struct rm *lev = &levl[x][y];
1023
1024	if (in_town(x, y) &&
1025	    (closed_door(x, y) || lev->typ == SDOOR ||
1026	     IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) {
1027	    if (!mtmp) {
1028		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1029		    if (DEADMONSTER(mtmp)) continue;
1030		    if ((mtmp->data == &mons[PM_WATCHMAN] ||
1031			 mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
1032			mtmp->mcansee && m_canseeu(mtmp) &&
1033			couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful)
1034			break;
1035		}
1036	    }
1037
1038	    if (mtmp) {
1039		if(zap || digging.warned) {
1040		    verbalize("Halt, vandal!  You're under arrest!");
1041		    (void) angry_guards(!(flags.soundok));
1042		} else {
1043		    const char *str;
1044
1045		    if (IS_DOOR(lev->typ))
1046			str = "door";
1047		    else if (IS_TREE(lev->typ))
1048			str = "tree";
1049		    else if (IS_ROCK(lev->typ))
1050			str = "wall";
1051		    else
1052			str = "fountain";
1053		    verbalize("Hey, stop damaging that %s!", str);
1054		    digging.warned = TRUE;
1055		}
1056		if (is_digging())
1057		    stop_occupation();
1058	    }
1059	}
1060}
1061
1062#endif /* OVLB */
1063#ifdef OVL0
1064
1065/* Return TRUE if monster died, FALSE otherwise.  Called from m_move(). */
1066boolean
1067mdig_tunnel(mtmp)
1068register struct monst *mtmp;
1069{
1070	register struct rm *here;
1071	int pile = rnd(12);
1072
1073	here = &levl[mtmp->mx][mtmp->my];
1074	if (here->typ == SDOOR)
1075	    cvt_sdoor_to_door(here);	/* ->typ = DOOR */
1076
1077	/* Eats away door if present & closed or locked */
1078	if (closed_door(mtmp->mx, mtmp->my)) {
1079	    if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
1080		add_damage(mtmp->mx, mtmp->my, 0L);
1081	    unblock_point(mtmp->mx, mtmp->my);	/* vision */
1082	    if (here->doormask & D_TRAPPED) {
1083		here->doormask = D_NODOOR;
1084		if (mb_trapped(mtmp)) {	/* mtmp is killed */
1085		    newsym(mtmp->mx, mtmp->my);
1086		    return TRUE;
1087		}
1088	    } else {
1089		if (!rn2(3) && flags.verbose)	/* not too often.. */
1090		    You_feel("an unexpected draft.");
1091		here->doormask = D_BROKEN;
1092	    }
1093	    newsym(mtmp->mx, mtmp->my);
1094	    return FALSE;
1095	} else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */
1096	    return FALSE;
1097
1098	/* Only rock, trees, and walls fall through to this point. */
1099	if ((here->wall_info & W_NONDIGGABLE) != 0) {
1100	    impossible("mdig_tunnel:  %s at (%d,%d) is undiggable",
1101		       (IS_WALL(here->typ) ? "wall" : "stone"),
1102		       (int) mtmp->mx, (int) mtmp->my);
1103	    return FALSE;	/* still alive */
1104	}
1105
1106	if (IS_WALL(here->typ)) {
1107	    /* KMH -- Okay on arboreal levels (room walls are still stone) */
1108	    if (flags.soundok && flags.verbose && !rn2(5))
1109		You_hear("crashing rock.");
1110	    if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
1111		add_damage(mtmp->mx, mtmp->my, 0L);
1112	    if (level.flags.is_maze_lev) {
1113		here->typ = ROOM;
1114	    } else if (level.flags.is_cavernous_lev &&
1115		       !in_town(mtmp->mx, mtmp->my)) {
1116		here->typ = CORR;
1117	    } else {
1118		here->typ = DOOR;
1119		here->doormask = D_NODOOR;
1120	    }
1121	} else if (IS_TREE(here->typ)) {
1122	    here->typ = ROOM;
1123	    if (pile && pile < 5)
1124		(void) rnd_treefruit_at(mtmp->mx, mtmp->my);
1125	} else {
1126	    here->typ = CORR;
1127	    if (pile && pile < 5)
1128		(void) mksobj_at((pile == 1) ? BOULDER : ROCK,
1129			     mtmp->mx, mtmp->my, TRUE, FALSE);
1130	}
1131	newsym(mtmp->mx, mtmp->my);
1132	if (!sobj_at(BOULDER, mtmp->mx, mtmp->my))
1133	    unblock_point(mtmp->mx, mtmp->my);	/* vision */
1134
1135	return FALSE;
1136}
1137
1138#endif /* OVL0 */
1139#ifdef OVL3
1140
1141/* digging via wand zap or spell cast */
1142void
1143zap_dig()
1144{
1145	struct rm *room;
1146	struct monst *mtmp;
1147	struct obj *otmp;
1148	int zx, zy, digdepth;
1149	boolean shopdoor, shopwall, maze_dig;
1150	/*
1151	 * Original effect (approximately):
1152	 * from CORR: dig until we pierce a wall
1153	 * from ROOM: pierce wall and dig until we reach
1154	 * an ACCESSIBLE place.
1155	 * Currently: dig for digdepth positions;
1156	 * also down on request of Lennart Augustsson.
1157	 */
1158
1159	if (u.uswallow) {
1160	    mtmp = u.ustuck;
1161
1162	    if (!is_whirly(mtmp->data)) {
1163		if (is_animal(mtmp->data))
1164		    You("pierce %s %s wall!",
1165			s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
1166		mtmp->mhp = 1;		/* almost dead */
1167		expels(mtmp, mtmp->data, !is_animal(mtmp->data));
1168	    }
1169	    return;
1170	} /* swallowed */
1171
1172	if (u.dz) {
1173	    if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) {
1174		if (u.dz < 0 || On_stairs(u.ux, u.uy)) {
1175		    if (On_stairs(u.ux, u.uy))
1176			pline_The("beam bounces off the %s and hits the %s.",
1177			      (u.ux == xdnladder || u.ux == xupladder) ?
1178			      "ladder" : "stairs", ceiling(u.ux, u.uy));
1179		    You("loosen a rock from the %s.", ceiling(u.ux, u.uy));
1180		    pline("It falls on your %s!", body_part(HEAD));
1181		    losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
1182			   "falling rock", KILLED_BY_AN);
1183		    otmp = mksobj_at(ROCK, u.ux, u.uy, FALSE, FALSE);
1184		    if (otmp) {
1185			(void)xname(otmp);	/* set dknown, maybe bknown */
1186			stackobj(otmp);
1187		    }
1188		    newsym(u.ux, u.uy);
1189		} else {
1190		    watch_dig((struct monst *)0, u.ux, u.uy, TRUE);
1191		    (void) dighole(FALSE);
1192		}
1193	    }
1194	    return;
1195	} /* up or down */
1196
1197	/* normal case: digging across the level */
1198	shopdoor = shopwall = FALSE;
1199	maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz);
1200	zx = u.ux + u.dx;
1201	zy = u.uy + u.dy;
1202	digdepth = rn1(18, 8);
1203	tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam));
1204	while (--digdepth >= 0) {
1205	    if (!isok(zx,zy)) break;
1206	    room = &levl[zx][zy];
1207	    tmp_at(zx,zy);
1208	    delay_output();	/* wait a little bit */
1209	    if (closed_door(zx, zy) || room->typ == SDOOR) {
1210		if (*in_rooms(zx,zy,SHOPBASE)) {
1211		    add_damage(zx, zy, 400L);
1212		    shopdoor = TRUE;
1213		}
1214		if (room->typ == SDOOR)
1215		    room->typ = DOOR;
1216		else if (cansee(zx, zy))
1217		    pline_The("door is razed!");
1218		watch_dig((struct monst *)0, zx, zy, TRUE);
1219		room->doormask = D_NODOOR;
1220		unblock_point(zx,zy); /* vision */
1221		digdepth -= 2;
1222		if (maze_dig) break;
1223	    } else if (maze_dig) {
1224		if (IS_WALL(room->typ)) {
1225		    if (!(room->wall_info & W_NONDIGGABLE)) {
1226			if (*in_rooms(zx,zy,SHOPBASE)) {
1227			    add_damage(zx, zy, 200L);
1228			    shopwall = TRUE;
1229			}
1230			room->typ = ROOM;
1231			unblock_point(zx,zy); /* vision */
1232		    } else if (!Blind)
1233			pline_The("wall glows then fades.");
1234		    break;
1235		} else if (IS_TREE(room->typ)) { /* check trees before stone */
1236		    if (!(room->wall_info & W_NONDIGGABLE)) {
1237			room->typ = ROOM;
1238			unblock_point(zx,zy); /* vision */
1239		    } else if (!Blind)
1240			pline_The("tree shudders but is unharmed.");
1241		    break;
1242		} else if (room->typ == STONE || room->typ == SCORR) {
1243		    if (!(room->wall_info & W_NONDIGGABLE)) {
1244			room->typ = CORR;
1245			unblock_point(zx,zy); /* vision */
1246		    } else if (!Blind)
1247			pline_The("rock glows then fades.");
1248		    break;
1249		}
1250	    } else if (IS_ROCK(room->typ)) {
1251		if (!may_dig(zx,zy)) break;
1252		if (IS_WALL(room->typ) || room->typ == SDOOR) {
1253		    if (*in_rooms(zx,zy,SHOPBASE)) {
1254			add_damage(zx, zy, 200L);
1255			shopwall = TRUE;
1256		    }
1257		    watch_dig((struct monst *)0, zx, zy, TRUE);
1258		    if (level.flags.is_cavernous_lev && !in_town(zx, zy)) {
1259			room->typ = CORR;
1260		    } else {
1261			room->typ = DOOR;
1262			room->doormask = D_NODOOR;
1263		    }
1264		    digdepth -= 2;
1265		} else if (IS_TREE(room->typ)) {
1266		    room->typ = ROOM;
1267		    digdepth -= 2;
1268		} else {	/* IS_ROCK but not IS_WALL or SDOOR */
1269		    room->typ = CORR;
1270		    digdepth--;
1271		}
1272		unblock_point(zx,zy); /* vision */
1273	    }
1274	    zx += u.dx;
1275	    zy += u.dy;
1276	} /* while */
1277	tmp_at(DISP_END,0);	/* closing call */
1278	if (shopdoor || shopwall)
1279	    pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
1280	return;
1281}
1282
1283/* move objects from fobj/nexthere lists to buriedobjlist, keeping position */
1284/* information */
1285struct obj *
1286bury_an_obj(otmp)
1287	struct obj *otmp;
1288{
1289	struct obj *otmp2;
1290	boolean under_ice;
1291
1292#ifdef NETHACK_DEBUG
1293	pline("bury_an_obj: %s", xname(otmp));
1294#endif
1295	if (otmp == uball)
1296		unpunish();
1297	/* after unpunish(), or might get deallocated chain */
1298	otmp2 = otmp->nexthere;
1299	/*
1300	 * obj_resists(,0,0) prevents Rider corpses from being buried.
1301	 * It also prevents The Amulet and invocation tools from being
1302	 * buried.  Since they can't be confined to bags and statues,
1303	 * it makes sense that they can't be buried either, even though
1304	 * the real reason there (direct accessibility when carried) is
1305	 * completely different.
1306	 */
1307	if (otmp == uchain || obj_resists(otmp, 0, 0))
1308		return(otmp2);
1309
1310	if (otmp->otyp == LEASH && otmp->leashmon != 0)
1311		o_unleash(otmp);
1312
1313	if (otmp->lamplit && otmp->otyp != POT_OIL)
1314		end_burn(otmp, TRUE);
1315
1316	obj_extract_self(otmp);
1317
1318	under_ice = is_ice(otmp->ox, otmp->oy);
1319	if (otmp->otyp == ROCK && !under_ice) {
1320		/* merges into burying material */
1321		obfree(otmp, (struct obj *)0);
1322		return(otmp2);
1323	}
1324	/*
1325	 * Start a rot on organic material.  Not corpses -- they
1326	 * are already handled.
1327	 */
1328	if (otmp->otyp == CORPSE) {
1329	    ;		/* should cancel timer if under_ice */
1330	} else if ((under_ice ? otmp->oclass == POTION_CLASS : is_organic(otmp))
1331		&& !obj_resists(otmp, 5, 95)) {
1332	    (void) start_timer((under_ice ? 0L : 250L) + (long)rnd(250),
1333			       TIMER_OBJECT, ROT_ORGANIC, (genericptr_t)otmp);
1334	}
1335	add_to_buried(otmp);
1336	return(otmp2);
1337}
1338
1339void
1340bury_objs(x, y)
1341int x, y;
1342{
1343	struct obj *otmp, *otmp2;
1344
1345#ifdef NETHACK_DEBUG
1346	if(level.objects[x][y] != (struct obj *)0)
1347		pline("bury_objs: at %d, %d", x, y);
1348#endif
1349	for (otmp = level.objects[x][y]; otmp; otmp = otmp2)
1350		otmp2 = bury_an_obj(otmp);
1351
1352	/* don't expect any engravings here, but just in case */
1353	del_engr_at(x, y);
1354	newsym(x, y);
1355}
1356
1357/* move objects from buriedobjlist to fobj/nexthere lists */
1358void
1359unearth_objs(x, y)
1360int x, y;
1361{
1362	struct obj *otmp, *otmp2;
1363
1364#ifdef NETHACK_DEBUG
1365	pline("unearth_objs: at %d, %d", x, y);
1366#endif
1367	for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
1368		otmp2 = otmp->nobj;
1369		if (otmp->ox == x && otmp->oy == y) {
1370		    obj_extract_self(otmp);
1371		    if (otmp->timed)
1372			(void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp);
1373		    place_object(otmp, x, y);
1374		    stackobj(otmp);
1375		}
1376	}
1377	del_engr_at(x, y);
1378	newsym(x, y);
1379}
1380
1381/*
1382 * The organic material has rotted away while buried.  As an expansion,
1383 * we could add add partial damage.  A damage count is kept in the object
1384 * and every time we are called we increment the count and reschedule another
1385 * timeout.  Eventually the object rots away.
1386 *
1387 * This is used by buried objects other than corpses.  When a container rots
1388 * away, any contents become newly buried objects.
1389 */
1390/* ARGSUSED */
1391void
1392rot_organic(arg, timeout)
1393genericptr_t arg;
1394long timeout;	/* unused */
1395{
1396	struct obj *obj = (struct obj *) arg;
1397
1398	while (Has_contents(obj)) {
1399	    /* We don't need to place contained object on the floor
1400	       first, but we do need to update its map coordinates. */
1401	    obj->cobj->ox = obj->ox,  obj->cobj->oy = obj->oy;
1402	    /* Everything which can be held in a container can also be
1403	       buried, so bury_an_obj's use of obj_extract_self insures
1404	       that Has_contents(obj) will eventually become false. */
1405	    (void)bury_an_obj(obj->cobj);
1406	}
1407	obj_extract_self(obj);
1408	obfree(obj, (struct obj *) 0);
1409}
1410
1411/*
1412 * Called when a corpse has rotted completely away.
1413 */
1414void
1415rot_corpse(arg, timeout)
1416genericptr_t arg;
1417long timeout;	/* unused */
1418{
1419	xchar x = 0, y = 0;
1420	struct obj *obj = (struct obj *) arg;
1421	boolean on_floor = obj->where == OBJ_FLOOR,
1422		in_invent = obj->where == OBJ_INVENT;
1423
1424	if (on_floor) {
1425	    x = obj->ox;
1426	    y = obj->oy;
1427	} else if (in_invent) {
1428	    if (flags.verbose) {
1429		char *cname = corpse_xname(obj, FALSE);
1430		Your("%s%s %s away%c",
1431		     obj == uwep ? "wielded " : nul, cname,
1432		     otense(obj, "rot"), obj == uwep ? '!' : '.');
1433	    }
1434	    if (obj == uwep) {
1435		uwepgone();	/* now bare handed */
1436		stop_occupation();
1437	    } else if (obj == uswapwep) {
1438		uswapwepgone();
1439		stop_occupation();
1440	    } else if (obj == uquiver) {
1441		uqwepgone();
1442		stop_occupation();
1443	    }
1444	} else if (obj->where == OBJ_MINVENT && obj->owornmask) {
1445	    if (obj == MON_WEP(obj->ocarry)) {
1446		setmnotwielded(obj->ocarry,obj);
1447		MON_NOWEP(obj->ocarry);
1448	    }
1449	}
1450	rot_organic(arg, timeout);
1451	if (on_floor) newsym(x, y);
1452	else if (in_invent) update_inventory();
1453}
1454
1455#if 0
1456void
1457bury_monst(mtmp)
1458struct monst *mtmp;
1459{
1460#ifdef NETHACK_DEBUG
1461	pline("bury_monst: %s", mon_nam(mtmp));
1462#endif
1463	if(canseemon(mtmp)) {
1464	    if(is_flyer(mtmp->data) || is_floater(mtmp->data)) {
1465		pline_The("%s opens up, but %s is not swallowed!",
1466			surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
1467		return;
1468	    } else
1469	        pline_The("%s opens up and swallows %s!",
1470			surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
1471	}
1472
1473	mtmp->mburied = TRUE;
1474	wakeup(mtmp);			/* at least give it a chance :-) */
1475	newsym(mtmp->mx, mtmp->my);
1476}
1477
1478void
1479bury_you()
1480{
1481#ifdef NETHACK_DEBUG
1482	pline("bury_you");
1483#endif
1484    if (!Levitation && !Flying) {
1485	if(u.uswallow)
1486	    You_feel("a sensation like falling into a trap!");
1487	else
1488	    pline_The("%s opens beneath you and you fall in!",
1489		  surface(u.ux, u.uy));
1490
1491	u.uburied = TRUE;
1492	if(!Strangled && !Breathless) Strangled = 6;
1493	under_ground(1);
1494    }
1495}
1496
1497void
1498unearth_you()
1499{
1500#ifdef NETHACK_DEBUG
1501	pline("unearth_you");
1502#endif
1503	u.uburied = FALSE;
1504	under_ground(0);
1505	if(!uamul || uamul->otyp != AMULET_OF_STRANGULATION)
1506		Strangled = 0;
1507	vision_recalc(0);
1508}
1509
1510void
1511escape_tomb()
1512{
1513#ifdef NETHACK_DEBUG
1514	pline("escape_tomb");
1515#endif
1516	if ((Teleportation || can_teleport(youmonst.data)) &&
1517	    (Teleport_control || rn2(3) < Luck+2)) {
1518		You("attempt a teleport spell.");
1519		(void) dotele();	/* calls unearth_you() */
1520	} else if(u.uburied) { /* still buried after 'port attempt */
1521		boolean good;
1522
1523		if(amorphous(youmonst.data) || Passes_walls ||
1524		   noncorporeal(youmonst.data) || unsolid(youmonst.data) ||
1525		   (tunnels(youmonst.data) && !needspick(youmonst.data))) {
1526
1527		    You("%s up through the %s.",
1528			(tunnels(youmonst.data) && !needspick(youmonst.data)) ?
1529			 "try to tunnel" : (amorphous(youmonst.data)) ?
1530			 "ooze" : "phase", surface(u.ux, u.uy));
1531
1532		    if(tunnels(youmonst.data) && !needspick(youmonst.data))
1533			good = dighole(TRUE);
1534		    else good = TRUE;
1535		    if(good) unearth_you();
1536		}
1537	}
1538}
1539
1540void
1541bury_obj(otmp)
1542struct obj *otmp;
1543{
1544
1545#ifdef NETHACK_DEBUG
1546	pline("bury_obj");
1547#endif
1548	if(cansee(otmp->ox, otmp->oy))
1549	   pline_The("objects on the %s tumble into a hole!",
1550		surface(otmp->ox, otmp->oy));
1551
1552	bury_objs(otmp->ox, otmp->oy);
1553}
1554#endif
1555
1556#ifdef NETHACK_DEBUG
1557int
1558wiz_debug_cmd() /* in this case, bury everything at your loc and around */
1559{
1560	int x, y;
1561
1562	for (x = u.ux - 1; x <= u.ux + 1; x++)
1563	    for (y = u.uy - 1; y <= u.uy + 1; y++)
1564		if (isok(x,y)) bury_objs(x,y);
1565	return 0;
1566}
1567
1568#endif /* DEBUG */
1569#endif /* OVL3 */
1570
1571/*dig.c*/
1572