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