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