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
rm_waslit()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
mkcavepos(x,y,dist,waslit,rockit)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
mkcavearea(rockit)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
dig_typ(x,y)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
dig_check(madeby,verbose,x,y)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
dig()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
holetime()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
fillholetyp(x,y)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
digactualhole(x,y,madeby,ttyp)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
dighole(pit_only)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
dig_up_grave()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
use_pick_axe(obj)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
mdig_tunnel(mtmp)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
zap_dig()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 *
bury_an_obj(otmp)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
bury_objs(x,y)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
unearth_objs(x,y)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
rot_organic(arg,timeout)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
rot_corpse(arg,timeout)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
wiz_debug_cmd()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*/
1376