OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / dig.c
1 /* NetHack 3.6  dig.c   $NHDT-Date: 1449269915 2015/12/04 22:58:35 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.103 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6
7 static NEARDATA boolean did_dig_msg;
8
9 STATIC_DCL boolean NDECL(rm_waslit);
10 STATIC_DCL void FDECL(mkcavepos,
11                       (XCHAR_P, XCHAR_P, int, BOOLEAN_P, BOOLEAN_P));
12 STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P));
13 STATIC_DCL int NDECL(dig);
14 STATIC_DCL void FDECL(dig_up_grave, (coord *));
15 STATIC_DCL int FDECL(adj_pit_checks, (coord *, char *));
16 STATIC_DCL void FDECL(pit_flow, (struct trap *, SCHAR_P));
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
26 STATIC_OVL boolean
27 rm_waslit()
28 {
29     register xchar x, y;
30
31     if (levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit)
32         return TRUE;
33     for (x = u.ux - 2; x < u.ux + 3; x++)
34         for (y = u.uy - 1; y < u.uy + 2; y++)
35             if (isok(x, y) && levl[x][y].waslit)
36                 return TRUE;
37     return FALSE;
38 }
39
40 /* Change level topology.  Messes with vision tables and ignores things like
41  * boulders in the name of a nice effect.  Vision will get fixed up again
42  * immediately after the effect is complete.
43  */
44 STATIC_OVL void
45 mkcavepos(x, y, dist, waslit, rockit)
46 xchar x, y;
47 int dist;
48 boolean waslit, rockit;
49 {
50     register struct rm *lev;
51
52     if (!isok(x, y))
53         return;
54     lev = &levl[x][y];
55
56     if (rockit) {
57         register struct monst *mtmp;
58
59         if (IS_ROCK(lev->typ))
60             return;
61         if (t_at(x, y))
62             return;                   /* don't cover the portal */
63         if ((mtmp = m_at(x, y)) != 0) /* make sure crucial monsters survive */
64             if (!passes_walls(mtmp->data))
65                 (void) rloc(mtmp, TRUE);
66     } else if (lev->typ == ROOM)
67         return;
68
69     unblock_point(x, y); /* make sure vision knows this location is open */
70
71     /* fake out saved state */
72     lev->seenv = 0;
73     lev->doormask = 0;
74     if (dist < 3)
75         lev->lit = (rockit ? FALSE : TRUE);
76     if (waslit)
77         lev->waslit = (rockit ? FALSE : TRUE);
78     lev->horizontal = FALSE;
79     /* short-circuit vision recalc */
80     viz_array[y][x] = (dist < 3) ? (IN_SIGHT | COULD_SEE) : COULD_SEE;
81     lev->typ = (rockit ? STONE : ROOM);
82     if (dist >= 3)
83         impossible("mkcavepos called with dist %d", dist);
84     feel_newsym(x, y);
85 }
86
87 STATIC_OVL void
88 mkcavearea(rockit)
89 register boolean rockit;
90 {
91     int dist;
92     xchar xmin = u.ux, xmax = u.ux;
93     xchar ymin = u.uy, ymax = u.uy;
94     register xchar i;
95     register boolean waslit = rm_waslit();
96
97     if (rockit)
98         pline("Crash!  The ceiling collapses around you!");
99     else
100         pline("A mysterious force %s cave around you!",
101               (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the");
102     display_nhwindow(WIN_MESSAGE, TRUE);
103
104     for (dist = 1; dist <= 2; dist++) {
105         xmin--;
106         xmax++;
107
108         /* top and bottom */
109         if (dist < 2) { /* the area is wider that it is high */
110             ymin--;
111             ymax++;
112             for (i = xmin + 1; i < xmax; i++) {
113                 mkcavepos(i, ymin, dist, waslit, rockit);
114                 mkcavepos(i, ymax, dist, waslit, rockit);
115             }
116         }
117
118         /* left and right */
119         for (i = ymin; i <= ymax; i++) {
120             mkcavepos(xmin, i, dist, waslit, rockit);
121             mkcavepos(xmax, i, dist, waslit, rockit);
122         }
123
124         flush_screen(1); /* make sure the new glyphs shows up */
125         delay_output();
126     }
127
128     if (!rockit && levl[u.ux][u.uy].typ == CORR) {
129         levl[u.ux][u.uy].typ = ROOM;
130         if (waslit)
131             levl[u.ux][u.uy].waslit = TRUE;
132         newsym(u.ux, u.uy); /* in case player is invisible */
133     }
134
135     vision_full_recalc = 1; /* everything changed */
136 }
137
138 /* When digging into location <x,y>, what are you actually digging into? */
139 int
140 dig_typ(otmp, x, y)
141 struct obj *otmp;
142 xchar x, y;
143 {
144     boolean ispick;
145
146     if (!otmp)
147         return DIGTYP_UNDIGGABLE;
148     ispick = is_pick(otmp);
149     if (!ispick && !is_axe(otmp))
150         return DIGTYP_UNDIGGABLE;
151
152     return ((ispick && sobj_at(STATUE, x, y))
153                ? DIGTYP_STATUE
154                : (ispick && sobj_at(BOULDER, x, y))
155                   ? DIGTYP_BOULDER
156                   : closed_door(x, y)
157                      ? DIGTYP_DOOR
158                      : IS_TREE(levl[x][y].typ)
159                         ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE)
160                         : (ispick && IS_ROCK(levl[x][y].typ)
161                            && (!level.flags.arboreal
162                                || IS_WALL(levl[x][y].typ)))
163                            ? DIGTYP_ROCK
164                            : DIGTYP_UNDIGGABLE);
165 }
166
167 boolean
168 is_digging()
169 {
170     if (occupation == dig) {
171         return TRUE;
172     }
173     return FALSE;
174 }
175
176 #define BY_YOU (&youmonst)
177 #define BY_OBJECT ((struct monst *) 0)
178
179 boolean
180 dig_check(madeby, verbose, x, y)
181 struct monst *madeby;
182 boolean verbose;
183 int x, y;
184 {
185     struct trap *ttmp = t_at(x, y);
186     const char *verb =
187         (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
188
189     if (On_stairs(x, y)) {
190         if (x == xdnladder || x == xupladder) {
191             if (verbose)
192                 pline_The("ladder resists your effort.");
193         } else if (verbose)
194             pline_The("stairs are too hard to %s.", verb);
195         return FALSE;
196     } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
197         if (verbose)
198             pline_The("throne is too hard to break apart.");
199         return FALSE;
200     } else if (IS_ALTAR(levl[x][y].typ)
201                && (madeby != BY_OBJECT || Is_astralevel(&u.uz)
202                    || Is_sanctum(&u.uz))) {
203         if (verbose)
204             pline_The("altar is too hard to break apart.");
205         return FALSE;
206     } else if (Is_airlevel(&u.uz)) {
207         if (verbose)
208             You("cannot %s thin air.", verb);
209         return FALSE;
210     } else if (Is_waterlevel(&u.uz)) {
211         if (verbose)
212             pline_The("water splashes and subsides.");
213         return FALSE;
214     } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR
215                 && (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
216                || (ttmp
217                    && (ttmp->ttyp == MAGIC_PORTAL
218                        || ttmp->ttyp == VIBRATING_SQUARE
219                        || (!Can_dig_down(&u.uz) && !levl[x][y].candig)))) {
220         if (verbose)
221             pline_The("%s here is too hard to %s.", surface(x, y), verb);
222         return FALSE;
223     } else if (sobj_at(BOULDER, x, y)) {
224         if (verbose)
225             There("isn't enough room to %s here.", verb);
226         return FALSE;
227     } else if (madeby == BY_OBJECT
228                /* the block against existing traps is mainly to
229                   prevent broken wands from turning holes into pits */
230                && (ttmp || is_pool_or_lava(x, y))) {
231         /* digging by player handles pools separately */
232         return FALSE;
233     }
234     return TRUE;
235 }
236
237 STATIC_OVL int
238 dig(VOID_ARGS)
239 {
240     register struct rm *lev;
241     register xchar dpx = context.digging.pos.x, dpy = context.digging.pos.y;
242     register boolean ispick = uwep && is_pick(uwep);
243     const char *verb = (!uwep || is_pick(uwep)) ? "dig into" : "chop through";
244
245     lev = &levl[dpx][dpy];
246     /* perhaps a nymph stole your pick-axe while you were busy digging */
247     /* or perhaps you teleported away */
248     if (u.uswallow || !uwep || (!ispick && !is_axe(uwep))
249         || !on_level(&context.digging.level, &u.uz)
250         || ((context.digging.down ? (dpx != u.ux || dpy != u.uy)
251                                   : (distu(dpx, dpy) > 2))))
252         return 0;
253
254     if (context.digging.down) {
255         if (!dig_check(BY_YOU, TRUE, u.ux, u.uy))
256             return 0;
257     } else { /* !context.digging.down */
258         if (IS_TREE(lev->typ) && !may_dig(dpx, dpy)
259             && dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) {
260             pline("This tree seems to be petrified.");
261             return 0;
262         }
263         if (IS_ROCK(lev->typ) && !may_dig(dpx, dpy)
264             && dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) {
265             pline("This %s is too hard to %s.",
266                   is_db_wall(dpx, dpy) ? "drawbridge" : "wall", verb);
267             return 0;
268         }
269     }
270     if (Fumbling && !rn2(3)) {
271         switch (rn2(3)) {
272         case 0:
273             if (!welded(uwep)) {
274                 You("fumble and drop %s.", yname(uwep));
275                 dropx(uwep);
276             } else {
277                 if (u.usteed)
278                     pline("%s and %s %s!", Yobjnam2(uwep, "bounce"),
279                           otense(uwep, "hit"), mon_nam(u.usteed));
280                 else
281                     pline("Ouch!  %s and %s you!", Yobjnam2(uwep, "bounce"),
282                           otense(uwep, "hit"));
283                 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
284             }
285             break;
286         case 1:
287             pline("Bang!  You hit with the broad side of %s!",
288                   the(xname(uwep)));
289             break;
290         default:
291             Your("swing misses its mark.");
292             break;
293         }
294         return 0;
295     }
296
297     context.digging.effort +=
298         10 + rn2(5) + abon() + uwep->spe - greatest_erosion(uwep) + u.udaminc;
299     if (Race_if(PM_DWARF))
300         context.digging.effort *= 2;
301     if (context.digging.down) {
302         struct trap *ttmp = t_at(dpx, dpy);
303
304         if (context.digging.effort > 250 || (ttmp && ttmp->ttyp == HOLE)) {
305             (void) dighole(FALSE, FALSE, (coord *) 0);
306             (void) memset((genericptr_t) &context.digging, 0,
307                           sizeof context.digging);
308             return 0; /* done with digging */
309         }
310
311         if (context.digging.effort <= 50
312             || (ttmp && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == PIT
313                          || ttmp->ttyp == SPIKED_PIT))) {
314             return 1;
315         } else if (ttmp && (ttmp->ttyp == LANDMINE
316                             || (ttmp->ttyp == BEAR_TRAP && !u.utrap))) {
317             /* digging onto a set object trap triggers it;
318                hero should have used #untrap first */
319             dotrap(ttmp, FORCETRAP);
320             /* restart completely from scratch if we resume digging */
321             (void) memset((genericptr_t) &context.digging, 0,
322                           sizeof context.digging);
323             return 0;
324         } else if (ttmp && ttmp->ttyp == BEAR_TRAP && u.utrap) {
325             if (rnl(7) > (Fumbling ? 1 : 4)) {
326                 char kbuf[BUFSZ];
327                 int dmg = dmgval(uwep, &youmonst) + dbon();
328
329                 if (dmg < 1)
330                     dmg = 1;
331                 else if (uarmf)
332                     dmg = (dmg + 1) / 2;
333                 You("hit yourself in the %s.", body_part(FOOT));
334                 Sprintf(kbuf, "chopping off %s own %s", uhis(),
335                         body_part(FOOT));
336                 losehp(Maybe_Half_Phys(dmg), kbuf, KILLED_BY);
337             } else {
338                 You("destroy the bear trap with %s.",
339                     yobjnam(uwep, (const char *) 0));
340                 u.utrap = 0; /* release from trap */
341                 deltrap(ttmp);
342             }
343             /* we haven't made any progress toward a pit yet */
344             context.digging.effort = 0;
345             return 0;
346         }
347
348         if (IS_ALTAR(lev->typ)) {
349             altar_wrath(dpx, dpy);
350             angry_priest();
351         }
352
353         /* make pit at <u.ux,u.uy> */
354         if (dighole(TRUE, FALSE, (coord *) 0)) {
355             context.digging.level.dnum = 0;
356             context.digging.level.dlevel = -1;
357         }
358         return 0;
359     }
360
361     if (context.digging.effort > 100) {
362         register const char *digtxt, *dmgtxt = (const char *) 0;
363         register struct obj *obj;
364         register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE);
365
366         if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) {
367             if (break_statue(obj))
368                 digtxt = "The statue shatters.";
369             else
370                 /* it was a statue trap; break_statue()
371                  * printed a message and updated the screen
372                  */
373                 digtxt = (char *) 0;
374         } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) {
375             struct obj *bobj;
376
377             fracture_rock(obj);
378             if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) {
379                 /* another boulder here, restack it to the top */
380                 obj_extract_self(bobj);
381                 place_object(bobj, dpx, dpy);
382             }
383             digtxt = "The boulder falls apart.";
384         } else if (lev->typ == STONE || lev->typ == SCORR
385                    || IS_TREE(lev->typ)) {
386             if (Is_earthlevel(&u.uz)) {
387                 if (uwep->blessed && !rn2(3)) {
388                     mkcavearea(FALSE);
389                     goto cleanup;
390                 } else if ((uwep->cursed && !rn2(4))
391                            || (!uwep->blessed && !rn2(6))) {
392                     mkcavearea(TRUE);
393                     goto cleanup;
394                 }
395             }
396             if (IS_TREE(lev->typ)) {
397                 digtxt = "You cut down the tree.";
398                 lev->typ = ROOM;
399                 if (!rn2(5))
400                     (void) rnd_treefruit_at(dpx, dpy);
401             } else {
402                 digtxt = "You succeed in cutting away some rock.";
403                 lev->typ = CORR;
404             }
405         } else if (IS_WALL(lev->typ)) {
406             if (shopedge) {
407                 add_damage(dpx, dpy, 10L * ACURRSTR);
408                 dmgtxt = "damage";
409             }
410             if (level.flags.is_maze_lev) {
411                 lev->typ = ROOM;
412             } else if (level.flags.is_cavernous_lev && !in_town(dpx, dpy)) {
413                 lev->typ = CORR;
414             } else {
415                 lev->typ = DOOR;
416                 lev->doormask = D_NODOOR;
417             }
418             digtxt = "You make an opening in the wall.";
419         } else if (lev->typ == SDOOR) {
420             cvt_sdoor_to_door(lev); /* ->typ = DOOR */
421             digtxt = "You break through a secret door!";
422             if (!(lev->doormask & D_TRAPPED))
423                 lev->doormask = D_BROKEN;
424         } else if (closed_door(dpx, dpy)) {
425             digtxt = "You break through the door.";
426             if (shopedge) {
427                 add_damage(dpx, dpy, 400L);
428                 dmgtxt = "break";
429             }
430             if (!(lev->doormask & D_TRAPPED))
431                 lev->doormask = D_BROKEN;
432         } else
433             return 0; /* statue or boulder got taken */
434
435         if (!does_block(dpx, dpy, &levl[dpx][dpy]))
436             unblock_point(dpx, dpy); /* vision:  can see through */
437         feel_newsym(dpx, dpy);
438         if (digtxt && !context.digging.quiet)
439             pline1(digtxt); /* after newsym */
440         if (dmgtxt)
441             pay_for_damage(dmgtxt, FALSE);
442
443         if (Is_earthlevel(&u.uz) && !rn2(3)) {
444             register struct monst *mtmp;
445
446             switch (rn2(2)) {
447             case 0:
448                 mtmp = makemon(&mons[PM_EARTH_ELEMENTAL], dpx, dpy,
449                                NO_MM_FLAGS);
450                 break;
451             default:
452                 mtmp = makemon(&mons[PM_XORN], dpx, dpy, NO_MM_FLAGS);
453                 break;
454             }
455             if (mtmp)
456                 pline_The("debris from your digging comes to life!");
457         }
458         if (IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) {
459             lev->doormask = D_NODOOR;
460             b_trapped("door", 0);
461             newsym(dpx, dpy);
462         }
463     cleanup:
464         context.digging.lastdigtime = moves;
465         context.digging.quiet = FALSE;
466         context.digging.level.dnum = 0;
467         context.digging.level.dlevel = -1;
468         return 0;
469     } else { /* not enough effort has been spent yet */
470         static const char *const d_target[6] = { "",        "rock", "statue",
471                                                  "boulder", "door", "tree" };
472         int dig_target = dig_typ(uwep, dpx, dpy);
473
474         if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) {
475             if (*in_rooms(dpx, dpy, SHOPBASE)) {
476                 pline("This %s seems too hard to %s.",
477                       IS_DOOR(lev->typ) ? "door" : "wall", verb);
478                 return 0;
479             }
480         } else if (dig_target == DIGTYP_UNDIGGABLE
481                    || (dig_target == DIGTYP_ROCK && !IS_ROCK(lev->typ)))
482             return 0; /* statue or boulder got taken */
483
484         if (!did_dig_msg) {
485             You("hit the %s with all your might.", d_target[dig_target]);
486             did_dig_msg = TRUE;
487         }
488     }
489     return 1;
490 }
491
492 /* When will hole be finished? Very rough indication used by shopkeeper. */
493 int
494 holetime()
495 {
496     if (occupation != dig || !*u.ushops)
497         return -1;
498     return ((250 - context.digging.effort) / 20);
499 }
500
501 /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
502 schar
503 fillholetyp(x, y, fill_if_any)
504 int x, y;
505 boolean fill_if_any; /* force filling if it exists at all */
506 {
507     register int x1, y1;
508     int lo_x = max(1, x - 1), hi_x = min(x + 1, COLNO - 1),
509         lo_y = max(0, y - 1), hi_y = min(y + 1, ROWNO - 1);
510     int pool_cnt = 0, moat_cnt = 0, lava_cnt = 0;
511
512     for (x1 = lo_x; x1 <= hi_x; x1++)
513         for (y1 = lo_y; y1 <= hi_y; y1++)
514             if (is_moat(x1, y1))
515                 moat_cnt++;
516             else if (is_pool(x1, y1))
517                 /* This must come after is_moat since moats are pools
518                  * but not vice-versa. */
519                 pool_cnt++;
520             else if (is_lava(x1, y1))
521                 lava_cnt++;
522
523     if (!fill_if_any)
524         pool_cnt /= 3; /* not as much liquid as the others */
525
526     if ((lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1))
527         || (lava_cnt && fill_if_any))
528         return LAVAPOOL;
529     else if ((moat_cnt > 0 && rn2(moat_cnt + 1)) || (moat_cnt && fill_if_any))
530         return MOAT;
531     else if ((pool_cnt > 0 && rn2(pool_cnt + 1)) || (pool_cnt && fill_if_any))
532         return POOL;
533     else
534         return ROOM;
535 }
536
537 void
538 digactualhole(x, y, madeby, ttyp)
539 register int x, y;
540 struct monst *madeby;
541 int ttyp;
542 {
543     struct obj *oldobjs, *newobjs;
544     register struct trap *ttmp;
545     char surface_type[BUFSZ];
546     struct rm *lev = &levl[x][y];
547     boolean shopdoor;
548     struct monst *mtmp = m_at(x, y); /* may be madeby */
549     boolean madeby_u = (madeby == BY_YOU);
550     boolean madeby_obj = (madeby == BY_OBJECT);
551     boolean at_u = (x == u.ux) && (y == u.uy);
552     boolean wont_fall = Levitation || Flying;
553
554     if (at_u && u.utrap) {
555         if (u.utraptype == TT_BURIEDBALL)
556             buried_ball_to_punishment();
557         else if (u.utraptype == TT_INFLOOR)
558             u.utrap = 0;
559     }
560
561     /* these furniture checks were in dighole(), but wand
562        breaking bypasses that routine and calls us directly */
563     if (IS_FOUNTAIN(lev->typ)) {
564         dogushforth(FALSE);
565         SET_FOUNTAIN_WARNED(x, y); /* force dryup */
566         dryup(x, y, madeby_u);
567         return;
568     } else if (IS_SINK(lev->typ)) {
569         breaksink(x, y);
570         return;
571     } else if (lev->typ == DRAWBRIDGE_DOWN
572                || (is_drawbridge_wall(x, y) >= 0)) {
573         int bx = x, by = y;
574         /* if under the portcullis, the bridge is adjacent */
575         (void) find_drawbridge(&bx, &by);
576         destroy_drawbridge(bx, by);
577         return;
578     }
579
580     if (ttyp != PIT && (!Can_dig_down(&u.uz) && !lev->candig)) {
581         impossible("digactualhole: can't dig %s on this level.",
582                    defsyms[trap_to_defsym(ttyp)].explanation);
583         ttyp = PIT;
584     }
585
586     /* maketrap() might change it, also, in this situation,
587        surface() returns an inappropriate string for a grave */
588     if (IS_GRAVE(lev->typ))
589         Strcpy(surface_type, "grave");
590     else
591         Strcpy(surface_type, surface(x, y));
592     shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE);
593     oldobjs = level.objects[x][y];
594     ttmp = maketrap(x, y, ttyp);
595     if (!ttmp)
596         return;
597     newobjs = level.objects[x][y];
598     ttmp->madeby_u = madeby_u;
599     ttmp->tseen = 0;
600     if (cansee(x, y))
601         seetrap(ttmp);
602     else if (madeby_u)
603         feeltrap(ttmp);
604
605     if (ttyp == PIT) {
606         if (madeby_u) {
607             if (x != u.ux || y != u.uy)
608                 You("dig an adjacent pit.");
609             else
610                 You("dig a pit in the %s.", surface_type);
611             if (shopdoor)
612                 pay_for_damage("ruin", FALSE);
613         } else if (!madeby_obj && canseemon(madeby))
614             pline("%s digs a pit in the %s.", Monnam(madeby), surface_type);
615         else if (cansee(x, y) && flags.verbose)
616             pline("A pit appears in the %s.", surface_type);
617
618         if (at_u) {
619             if (!wont_fall) {
620                 u.utrap = rn1(4, 2);
621                 u.utraptype = TT_PIT;
622                 vision_full_recalc = 1; /* vision limits change */
623             } else
624                 u.utrap = 0;
625             if (oldobjs != newobjs) /* something unearthed */
626                 (void) pickup(1);   /* detects pit */
627         } else if (mtmp) {
628             if (is_flyer(mtmp->data) || is_floater(mtmp->data)) {
629                 if (canseemon(mtmp))
630                     pline("%s %s over the pit.", Monnam(mtmp),
631                           (is_flyer(mtmp->data)) ? "flies" : "floats");
632             } else if (mtmp != madeby)
633                 (void) mintrap(mtmp);
634         }
635     } else { /* was TRAPDOOR now a HOLE*/
636
637         if (madeby_u)
638             You("dig a hole through the %s.", surface_type);
639         else if (!madeby_obj && canseemon(madeby))
640             pline("%s digs a hole through the %s.", Monnam(madeby),
641                   surface_type);
642         else if (cansee(x, y) && flags.verbose)
643             pline("A hole appears in the %s.", surface_type);
644
645         if (at_u) {
646             if (!u.ustuck && !wont_fall && !next_to_u()) {
647                 You("are jerked back by your pet!");
648                 wont_fall = TRUE;
649             }
650
651             /* Floor objects get a chance of falling down.  The case where
652              * the hero does NOT fall down is treated here.  The case
653              * where the hero does fall down is treated in goto_level().
654              */
655             if (u.ustuck || wont_fall) {
656                 if (newobjs)
657                     impact_drop((struct obj *) 0, x, y, 0);
658                 if (oldobjs != newobjs)
659                     (void) pickup(1);
660                 if (shopdoor && madeby_u)
661                     pay_for_damage("ruin", FALSE);
662
663             } else {
664                 d_level newlevel;
665
666                 if (*u.ushops && madeby_u)
667                     shopdig(1); /* shk might snatch pack */
668                 /* handle earlier damage, eg breaking wand of digging */
669                 else if (!madeby_u)
670                     pay_for_damage("dig into", TRUE);
671
672                 You("fall through...");
673                 /* Earlier checks must ensure that the destination
674                  * level exists and is in the present dungeon.
675                  */
676                 newlevel.dnum = u.uz.dnum;
677                 newlevel.dlevel = u.uz.dlevel + 1;
678                 goto_level(&newlevel, FALSE, TRUE, FALSE);
679                 /* messages for arriving in special rooms */
680                 spoteffects(FALSE);
681             }
682         } else {
683             if (shopdoor && madeby_u)
684                 pay_for_damage("ruin", FALSE);
685             if (newobjs)
686                 impact_drop((struct obj *) 0, x, y, 0);
687             if (mtmp) {
688                 /*[don't we need special sokoban handling here?]*/
689                 if (is_flyer(mtmp->data) || is_floater(mtmp->data)
690                     || mtmp->data == &mons[PM_WUMPUS]
691                     || (mtmp->wormno && count_wsegs(mtmp) > 5)
692                     || mtmp->data->msize >= MZ_HUGE)
693                     return;
694                 if (mtmp == u.ustuck) /* probably a vortex */
695                     return;           /* temporary? kludge */
696
697                 if (teleport_pet(mtmp, FALSE)) {
698                     d_level tolevel;
699
700                     if (Is_stronghold(&u.uz)) {
701                         assign_level(&tolevel, &valley_level);
702                     } else if (Is_botlevel(&u.uz)) {
703                         if (canseemon(mtmp))
704                             pline("%s avoids the trap.", Monnam(mtmp));
705                         return;
706                     } else {
707                         get_level(&tolevel, depth(&u.uz) + 1);
708                     }
709                     if (mtmp->isshk)
710                         make_angry_shk(mtmp, 0, 0);
711                     migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM,
712                                      (coord *) 0);
713                 }
714             }
715         }
716     }
717 }
718
719 /*
720  * Called from dighole(), but also from do_break_wand()
721  * in apply.c.
722  */
723 void
724 liquid_flow(x, y, typ, ttmp, fillmsg)
725 xchar x, y;
726 schar typ;
727 struct trap *ttmp;
728 const char *fillmsg;
729 {
730     boolean u_spot = (x == u.ux && y == u.uy);
731
732     if (ttmp)
733         (void) delfloortrap(ttmp);
734     /* if any objects were frozen here, they're released now */
735     unearth_objs(x, y);
736
737     if (fillmsg)
738         pline(fillmsg, typ == LAVAPOOL ? "lava" : "water");
739     if (u_spot && !(Levitation || Flying)) {
740         if (typ == LAVAPOOL)
741             (void) lava_effects();
742         else if (!Wwalking)
743             (void) drown();
744     }
745 }
746
747 /* return TRUE if digging succeeded, FALSE otherwise */
748 boolean
749 dighole(pit_only, by_magic, cc)
750 boolean pit_only, by_magic;
751 coord *cc;
752 {
753     register struct trap *ttmp;
754     struct rm *lev;
755     struct obj *boulder_here;
756     schar typ;
757     xchar dig_x, dig_y;
758     boolean nohole;
759
760     if (!cc) {
761         dig_x = u.ux;
762         dig_y = u.uy;
763     } else {
764         dig_x = cc->x;
765         dig_y = cc->y;
766         if (!isok(dig_x, dig_y))
767             return FALSE;
768     }
769
770     ttmp = t_at(dig_x, dig_y);
771     lev = &levl[dig_x][dig_y];
772     nohole = (!Can_dig_down(&u.uz) && !lev->candig);
773
774     if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL
775                   || ttmp->ttyp == VIBRATING_SQUARE || nohole))
776         || (IS_ROCK(lev->typ) && lev->typ != SDOOR
777             && (lev->wall_info & W_NONDIGGABLE) != 0)) {
778         pline_The("%s %shere is too hard to dig in.", surface(dig_x, dig_y),
779                   (dig_x != u.ux || dig_y != u.uy) ? "t" : "");
780
781     } else if (is_pool_or_lava(dig_x, dig_y)) {
782         pline_The("%s sloshes furiously for a moment, then subsides.",
783                   is_lava(dig_x, dig_y) ? "lava" : "water");
784         wake_nearby(); /* splashing */
785
786     } else if (lev->typ == DRAWBRIDGE_DOWN
787                || (is_drawbridge_wall(dig_x, dig_y) >= 0)) {
788         /* drawbridge_down is the platform crossing the moat when the
789            bridge is extended; drawbridge_wall is the open "doorway" or
790            closed "door" where the portcullis/mechanism is located */
791         if (pit_only) {
792             pline_The("drawbridge seems too hard to dig through.");
793             return FALSE;
794         } else {
795             int x = dig_x, y = dig_y;
796             /* if under the portcullis, the bridge is adjacent */
797             (void) find_drawbridge(&x, &y);
798             destroy_drawbridge(x, y);
799             return TRUE;
800         }
801
802     } else if ((boulder_here = sobj_at(BOULDER, dig_x, dig_y)) != 0) {
803         if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)
804             && rn2(2)) {
805             pline_The("boulder settles into the %spit.",
806                       (dig_x != u.ux || dig_y != u.uy) ? "adjacent " : "");
807             ttmp->ttyp = PIT; /* crush spikes */
808         } else {
809             /*
810              * digging makes a hole, but the boulder immediately
811              * fills it.  Final outcome:  no hole, no boulder.
812              */
813             pline("KADOOM! The boulder falls in!");
814             (void) delfloortrap(ttmp);
815         }
816         delobj(boulder_here);
817         return TRUE;
818
819     } else if (IS_GRAVE(lev->typ)) {
820         digactualhole(dig_x, dig_y, BY_YOU, PIT);
821         dig_up_grave(cc);
822         return TRUE;
823     } else if (lev->typ == DRAWBRIDGE_UP) {
824         /* must be floor or ice, other cases handled above */
825         /* dig "pit" and let fluid flow in (if possible) */
826         typ = fillholetyp(dig_x, dig_y, FALSE);
827
828         if (typ == ROOM) {
829             /*
830              * We can't dig a hole here since that will destroy
831              * the drawbridge.  The following is a cop-out. --dlc
832              */
833             pline_The("%s %shere is too hard to dig in.",
834                       surface(dig_x, dig_y),
835                       (dig_x != u.ux || dig_y != u.uy) ? "t" : "");
836             return FALSE;
837         }
838
839         lev->drawbridgemask &= ~DB_UNDER;
840         lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT;
841         liquid_flow(dig_x, dig_y, typ, ttmp,
842                     "As you dig, the hole fills with %s!");
843         return TRUE;
844
845         /* the following two are here for the wand of digging */
846     } else if (IS_THRONE(lev->typ)) {
847         pline_The("throne is too hard to break apart.");
848
849     } else if (IS_ALTAR(lev->typ)) {
850         pline_The("altar is too hard to break apart.");
851
852     } else {
853         typ = fillholetyp(dig_x, dig_y, FALSE);
854
855         if (typ != ROOM) {
856             lev->typ = typ;
857             liquid_flow(dig_x, dig_y, typ, ttmp,
858                         "As you dig, the hole fills with %s!");
859             return TRUE;
860         }
861
862         /* magical digging disarms settable traps */
863         if (by_magic && ttmp
864             && (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP)) {
865             int otyp = (ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP;
866
867             /* convert trap into buried object (deletes trap) */
868             cnv_trap_obj(otyp, 1, ttmp, TRUE);
869         }
870
871         /* finally we get to make a hole */
872         if (nohole || pit_only)
873             digactualhole(dig_x, dig_y, BY_YOU, PIT);
874         else
875             digactualhole(dig_x, dig_y, BY_YOU, HOLE);
876
877         return TRUE;
878     }
879
880     return FALSE;
881 }
882
883 STATIC_OVL void
884 dig_up_grave(cc)
885 coord *cc;
886 {
887     struct obj *otmp;
888     xchar dig_x, dig_y;
889
890     if (!cc) {
891         dig_x = u.ux;
892         dig_y = u.uy;
893     } else {
894         dig_x = cc->x;
895         dig_y = cc->y;
896         if (!isok(dig_x, dig_y))
897             return;
898     }
899
900     /* Grave-robbing is frowned upon... */
901     exercise(A_WIS, FALSE);
902     if (Role_if(PM_ARCHEOLOGIST)) {
903         adjalign(-sgn(u.ualign.type) * 3);
904         You_feel("like a despicable grave-robber!");
905     } else if (Role_if(PM_SAMURAI)) {
906         adjalign(-sgn(u.ualign.type));
907         You("disturb the honorable dead!");
908     } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
909         adjalign(-sgn(u.ualign.type));
910         You("have violated the sanctity of this grave!");
911     }
912
913     switch (rn2(5)) {
914     case 0:
915     case 1:
916         You("unearth a corpse.");
917         if (!!(otmp = mk_tt_object(CORPSE, dig_x, dig_y)))
918             otmp->age -= 100; /* this is an *OLD* corpse */
919         ;
920         break;
921     case 2:
922         if (!Blind)
923             pline(Hallucination ? "Dude!  The living dead!"
924                                 : "The grave's owner is very upset!");
925         (void) makemon(mkclass(S_ZOMBIE, 0), dig_x, dig_y, NO_MM_FLAGS);
926         break;
927     case 3:
928         if (!Blind)
929             pline(Hallucination ? "I want my mummy!"
930                                 : "You've disturbed a tomb!");
931         (void) makemon(mkclass(S_MUMMY, 0), dig_x, dig_y, NO_MM_FLAGS);
932         break;
933     default:
934         /* No corpse */
935         pline_The("grave seems unused.  Strange....");
936         break;
937     }
938     levl[dig_x][dig_y].typ = ROOM;
939     del_engr_at(dig_x, dig_y);
940     newsym(dig_x, dig_y);
941     return;
942 }
943
944 int
945 use_pick_axe(obj)
946 struct obj *obj;
947 {
948     const char *sdp, *verb;
949     char *dsp, dirsyms[12], qbuf[BUFSZ];
950     boolean ispick;
951     int rx, ry, downok, res = 0;
952
953     /* Check tool */
954     if (obj != uwep) {
955         if (!wield_tool(obj, "swing"))
956             return 0;
957         else
958             res = 1;
959     }
960     ispick = is_pick(obj);
961     verb = ispick ? "dig" : "chop";
962
963     if (u.utrap && u.utraptype == TT_WEB) {
964         pline("%s you can't %s while entangled in a web.",
965               /* res==0 => no prior message;
966                  res==1 => just got "You now wield a pick-axe." message */
967               !res ? "Unfortunately," : "But", verb);
968         return res;
969     }
970
971     /* construct list of directions to show player for likely choices */
972     downok = !!can_reach_floor(FALSE);
973     dsp = dirsyms;
974     for (sdp = Cmd.dirchars; *sdp; ++sdp) {
975         /* filter out useless directions */
976         if (u.uswallow) {
977             ; /* all directions are viable when swallowed */
978         } else if (movecmd(*sdp)) {
979             /* normal direction, within plane of the level map;
980                movecmd() sets u.dx, u.dy, u.dz and returns !u.dz */
981             if (!dxdy_moveok())
982                 continue; /* handle NODIAG */
983             rx = u.ux + u.dx;
984             ry = u.uy + u.dy;
985             if (!isok(rx, ry) || dig_typ(obj, rx, ry) == DIGTYP_UNDIGGABLE)
986                 continue;
987         } else {
988             /* up or down; we used to always include down, so that
989                there would always be at least one choice shown, but
990                it shouldn't be a likely candidate when floating high
991                above the floor; include up instead in that situation
992                (as a silly candidate rather than a likely one...) */
993             if ((u.dz > 0) ^ downok)
994                 continue;
995         }
996         /* include this direction */
997         *dsp++ = *sdp;
998     }
999     *dsp = 0;
1000     Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms);
1001     if (!getdir(qbuf))
1002         return res;
1003
1004     return use_pick_axe2(obj);
1005 }
1006
1007 /* MRKR: use_pick_axe() is split in two to allow autodig to bypass */
1008 /*       the "In what direction do you want to dig?" query.        */
1009 /*       use_pick_axe2() uses the existing u.dx, u.dy and u.dz    */
1010 int
1011 use_pick_axe2(obj)
1012 struct obj *obj;
1013 {
1014     register int rx, ry;
1015     register struct rm *lev;
1016     struct trap *trap, *trap_with_u;
1017     int dig_target;
1018     boolean ispick = is_pick(obj);
1019     const char *verbing = ispick ? "digging" : "chopping";
1020
1021     if (u.uswallow && attack(u.ustuck)) {
1022         ; /* return 1 */
1023     } else if (Underwater) {
1024         pline("Turbulence torpedoes your %s attempts.", verbing);
1025     } else if (u.dz < 0) {
1026         if (Levitation)
1027             You("don't have enough leverage.");
1028         else
1029             You_cant("reach the %s.", ceiling(u.ux, u.uy));
1030     } else if (!u.dx && !u.dy && !u.dz) {
1031         char buf[BUFSZ];
1032         int dam;
1033
1034         dam = rnd(2) + dbon() + obj->spe;
1035         if (dam <= 0)
1036             dam = 1;
1037         You("hit yourself with %s.", yname(uwep));
1038         Sprintf(buf, "%s own %s", uhis(), OBJ_NAME(objects[obj->otyp]));
1039         losehp(Maybe_Half_Phys(dam), buf, KILLED_BY);
1040         context.botl = 1;
1041         return 1;
1042     } else if (u.dz == 0) {
1043         if (Stunned || (Confusion && !rn2(5)))
1044             confdir();
1045         rx = u.ux + u.dx;
1046         ry = u.uy + u.dy;
1047         if (!isok(rx, ry)) {
1048             pline("Clash!");
1049             return 1;
1050         }
1051         lev = &levl[rx][ry];
1052         if (MON_AT(rx, ry) && attack(m_at(rx, ry)))
1053             return 1;
1054         dig_target = dig_typ(obj, rx, ry);
1055         if (dig_target == DIGTYP_UNDIGGABLE) {
1056             /* ACCESSIBLE or POOL */
1057             trap = t_at(rx, ry);
1058             if (trap && trap->ttyp == WEB) {
1059                 if (!trap->tseen) {
1060                     seetrap(trap);
1061                     There("is a spider web there!");
1062                 }
1063                 pline("%s entangled in the web.", Yobjnam2(obj, "become"));
1064                 /* you ought to be able to let go; tough luck */
1065                 /* (maybe `move_into_trap()' would be better) */
1066                 nomul(-d(2, 2));
1067                 multi_reason = "stuck in a spider web";
1068                 nomovemsg = "You pull free.";
1069             } else if (lev->typ == IRONBARS) {
1070                 pline("Clang!");
1071                 wake_nearby();
1072             } else if (IS_TREE(lev->typ))
1073                 You("need an axe to cut down a tree.");
1074             else if (IS_ROCK(lev->typ))
1075                 You("need a pick to dig rock.");
1076             else if (!ispick && (sobj_at(STATUE, rx, ry)
1077                                  || sobj_at(BOULDER, rx, ry))) {
1078                 boolean vibrate = !rn2(3);
1079                 pline("Sparks fly as you whack the %s.%s",
1080                       sobj_at(STATUE, rx, ry) ? "statue" : "boulder",
1081                       vibrate ? " The axe-handle vibrates violently!" : "");
1082                 if (vibrate)
1083                     losehp(Maybe_Half_Phys(2), "axing a hard object",
1084                            KILLED_BY);
1085             } else if (u.utrap && u.utraptype == TT_PIT && trap
1086                        && (trap_with_u = t_at(u.ux, u.uy))
1087                        && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)
1088                        && !conjoined_pits(trap, trap_with_u, FALSE)) {
1089                 int idx;
1090                 for (idx = 0; idx < 8; idx++) {
1091                     if (xdir[idx] == u.dx && ydir[idx] == u.dy)
1092                         break;
1093                 }
1094                 /* idx is valid if < 8 */
1095                 if (idx < 8) {
1096                     int adjidx = (idx + 4) % 8;
1097                     trap_with_u->conjoined |= (1 << idx);
1098                     trap->conjoined |= (1 << adjidx);
1099                     pline("You clear some debris from between the pits.");
1100                 }
1101             } else if (u.utrap && u.utraptype == TT_PIT
1102                        && (trap_with_u = t_at(u.ux, u.uy))) {
1103                 You("swing %s, but the rubble has no place to go.",
1104                     yobjnam(obj, (char *) 0));
1105             } else
1106                 You("swing %s through thin air.", yobjnam(obj, (char *) 0));
1107         } else {
1108             static const char *const d_action[6] = { "swinging", "digging",
1109                                                      "chipping the statue",
1110                                                      "hitting the boulder",
1111                                                      "chopping at the door",
1112                                                      "cutting the tree" };
1113             did_dig_msg = FALSE;
1114             context.digging.quiet = FALSE;
1115             if (context.digging.pos.x != rx || context.digging.pos.y != ry
1116                 || !on_level(&context.digging.level, &u.uz)
1117                 || context.digging.down) {
1118                 if (flags.autodig && dig_target == DIGTYP_ROCK
1119                     && !context.digging.down && context.digging.pos.x == u.ux
1120                     && context.digging.pos.y == u.uy
1121                     && (moves <= context.digging.lastdigtime + 2
1122                         && moves >= context.digging.lastdigtime)) {
1123                     /* avoid messages if repeated autodigging */
1124                     did_dig_msg = TRUE;
1125                     context.digging.quiet = TRUE;
1126                 }
1127                 context.digging.down = context.digging.chew = FALSE;
1128                 context.digging.warned = FALSE;
1129                 context.digging.pos.x = rx;
1130                 context.digging.pos.y = ry;
1131                 assign_level(&context.digging.level, &u.uz);
1132                 context.digging.effort = 0;
1133                 if (!context.digging.quiet)
1134                     You("start %s.", d_action[dig_target]);
1135             } else {
1136                 You("%s %s.", context.digging.chew ? "begin" : "continue",
1137                     d_action[dig_target]);
1138                 context.digging.chew = FALSE;
1139             }
1140             set_occupation(dig, verbing, 0);
1141         }
1142     } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
1143         /* it must be air -- water checked above */
1144         You("swing %s through thin air.", yobjnam(obj, (char *) 0));
1145     } else if (!can_reach_floor(FALSE)) {
1146         cant_reach_floor(u.ux, u.uy, FALSE, FALSE);
1147     } else if (is_pool_or_lava(u.ux, u.uy)) {
1148         /* Monsters which swim also happen not to be able to dig */
1149         You("cannot stay under%s long enough.",
1150             is_pool(u.ux, u.uy) ? "water" : " the lava");
1151     } else if ((trap = t_at(u.ux, u.uy)) != 0
1152                && uteetering_at_seen_pit(trap)) {
1153         dotrap(trap, FORCEBUNGLE);
1154         /* might escape trap and still be teetering at brink */
1155         if (!u.utrap)
1156             cant_reach_floor(u.ux, u.uy, FALSE, TRUE);
1157     } else if (!ispick
1158                /* can only dig down with an axe when doing so will
1159                   trigger or disarm a trap here */
1160                && (!trap || (trap->ttyp != LANDMINE
1161                              && trap->ttyp != BEAR_TRAP))) {
1162         pline("%s merely scratches the %s.", Yobjnam2(obj, (char *) 0),
1163               surface(u.ux, u.uy));
1164         u_wipe_engr(3);
1165     } else {
1166         if (context.digging.pos.x != u.ux || context.digging.pos.y != u.uy
1167             || !on_level(&context.digging.level, &u.uz)
1168             || !context.digging.down) {
1169             context.digging.chew = FALSE;
1170             context.digging.down = TRUE;
1171             context.digging.warned = FALSE;
1172             context.digging.pos.x = u.ux;
1173             context.digging.pos.y = u.uy;
1174             assign_level(&context.digging.level, &u.uz);
1175             context.digging.effort = 0;
1176             You("start %s downward.", verbing);
1177             if (*u.ushops)
1178                 shopdig(0);
1179         } else
1180             You("continue %s downward.", verbing);
1181         did_dig_msg = FALSE;
1182         set_occupation(dig, verbing, 0);
1183     }
1184     return 1;
1185 }
1186
1187 /*
1188  * Town Watchmen frown on damage to the town walls, trees or fountains.
1189  * It's OK to dig holes in the ground, however.
1190  * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0
1191  * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing)
1192  */
1193 void
1194 watch_dig(mtmp, x, y, zap)
1195 struct monst *mtmp;
1196 xchar x, y;
1197 boolean zap;
1198 {
1199     struct rm *lev = &levl[x][y];
1200
1201     if (in_town(x, y)
1202         && (closed_door(x, y) || lev->typ == SDOOR || IS_WALL(lev->typ)
1203             || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) {
1204         if (!mtmp) {
1205             for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1206                 if (DEADMONSTER(mtmp))
1207                     continue;
1208                 if (is_watch(mtmp->data) && mtmp->mcansee && m_canseeu(mtmp)
1209                     && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful)
1210                     break;
1211             }
1212         }
1213
1214         if (mtmp) {
1215             if (zap || context.digging.warned) {
1216                 verbalize("Halt, vandal!  You're under arrest!");
1217                 (void) angry_guards(!!Deaf);
1218             } else {
1219                 const char *str;
1220
1221                 if (IS_DOOR(lev->typ))
1222                     str = "door";
1223                 else if (IS_TREE(lev->typ))
1224                     str = "tree";
1225                 else if (IS_ROCK(lev->typ))
1226                     str = "wall";
1227                 else
1228                     str = "fountain";
1229                 verbalize("Hey, stop damaging that %s!", str);
1230                 context.digging.warned = TRUE;
1231             }
1232             if (is_digging())
1233                 stop_occupation();
1234         }
1235     }
1236 }
1237
1238 /* Return TRUE if monster died, FALSE otherwise.  Called from m_move(). */
1239 boolean
1240 mdig_tunnel(mtmp)
1241 register struct monst *mtmp;
1242 {
1243     register struct rm *here;
1244     int pile = rnd(12);
1245
1246     here = &levl[mtmp->mx][mtmp->my];
1247     if (here->typ == SDOOR)
1248         cvt_sdoor_to_door(here); /* ->typ = DOOR */
1249
1250     /* Eats away door if present & closed or locked */
1251     if (closed_door(mtmp->mx, mtmp->my)) {
1252         if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
1253             add_damage(mtmp->mx, mtmp->my, 0L);
1254         unblock_point(mtmp->mx, mtmp->my); /* vision */
1255         if (here->doormask & D_TRAPPED) {
1256             here->doormask = D_NODOOR;
1257             if (mb_trapped(mtmp)) { /* mtmp is killed */
1258                 newsym(mtmp->mx, mtmp->my);
1259                 return TRUE;
1260             }
1261         } else {
1262             if (!rn2(3) && flags.verbose) /* not too often.. */
1263                 draft_message(TRUE); /* "You feel an unexpected draft." */
1264             here->doormask = D_BROKEN;
1265         }
1266         newsym(mtmp->mx, mtmp->my);
1267         return FALSE;
1268     } else if (here->typ == SCORR) {
1269         here->typ = CORR;
1270         unblock_point(mtmp->mx, mtmp->my);
1271         newsym(mtmp->mx, mtmp->my);
1272         draft_message(FALSE); /* "You feel a draft." */
1273         return FALSE;
1274     } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */
1275         return FALSE;
1276
1277     /* Only rock, trees, and walls fall through to this point. */
1278     if ((here->wall_info & W_NONDIGGABLE) != 0) {
1279         impossible("mdig_tunnel:  %s at (%d,%d) is undiggable",
1280                    (IS_WALL(here->typ) ? "wall"
1281                     : IS_TREE(here->typ) ? "tree" : "stone"),
1282                    (int) mtmp->mx, (int) mtmp->my);
1283         return FALSE; /* still alive */
1284     }
1285
1286     if (IS_WALL(here->typ)) {
1287         /* KMH -- Okay on arboreal levels (room walls are still stone) */
1288         if (flags.verbose && !rn2(5))
1289             You_hear("crashing rock.");
1290         if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
1291             add_damage(mtmp->mx, mtmp->my, 0L);
1292         if (level.flags.is_maze_lev) {
1293             here->typ = ROOM;
1294         } else if (level.flags.is_cavernous_lev
1295                    && !in_town(mtmp->mx, mtmp->my)) {
1296             here->typ = CORR;
1297         } else {
1298             here->typ = DOOR;
1299             here->doormask = D_NODOOR;
1300         }
1301     } else if (IS_TREE(here->typ)) {
1302         here->typ = ROOM;
1303         if (pile && pile < 5)
1304             (void) rnd_treefruit_at(mtmp->mx, mtmp->my);
1305     } else {
1306         here->typ = CORR;
1307         if (pile && pile < 5)
1308             (void) mksobj_at((pile == 1) ? BOULDER : ROCK, mtmp->mx, mtmp->my,
1309                              TRUE, FALSE);
1310     }
1311     newsym(mtmp->mx, mtmp->my);
1312     if (!sobj_at(BOULDER, mtmp->mx, mtmp->my))
1313         unblock_point(mtmp->mx, mtmp->my); /* vision */
1314
1315     return FALSE;
1316 }
1317
1318 #define STRIDENT 4 /* from pray.c */
1319
1320 /* draft refers to air currents, but can be a pun on "draft" as conscription
1321    for military service (probably not a good pun if it has to be explained) */
1322 void
1323 draft_message(unexpected)
1324 boolean unexpected;
1325 {
1326     /*
1327      * [Bug or TODO?  Have caller pass coordinates and use the travel
1328      * mechanism to determine whether there is a path between
1329      * destroyed door (or exposed secret corridor) and hero's location.
1330      * When there is no such path, no draft should be felt.]
1331      */
1332
1333     if (unexpected) {
1334         if (!Hallucination)
1335             You_feel("an unexpected draft.");
1336         else
1337             /* U.S. classification system uses 1-A for eligible to serve
1338                and 4-F for ineligible due to physical or mental defect;
1339                some intermediate values exist but are rarely seen */
1340             You_feel("like you are %s.",
1341                      (ACURR(A_STR) < 6 || ACURR(A_DEX) < 6
1342                       || ACURR(A_CON) < 6 || ACURR(A_CHA) < 6
1343                       || ACURR(A_INT) < 6 || ACURR(A_WIS) < 6) ? "4-F"
1344                                                                : "1-A");
1345     } else {
1346         if (!Hallucination) {
1347             You_feel("a draft.");
1348         } else {
1349             /* "marching" is deliberately ambiguous; it might mean drills
1350                 after entering military service or mean engaging in protests */
1351             static const char *draft_reaction[] = {
1352                 "enlisting", "marching", "protesting", "fleeing",
1353             };
1354             int dridx;
1355
1356             /* Lawful: 0..1, Neutral: 1..2, Chaotic: 2..3 */
1357             dridx = rn1(2, 1 - sgn(u.ualign.type));
1358             if (u.ualign.record < STRIDENT)
1359                 /* L: +(0..2), N: +(-1..1), C: +(-2..0); all: 0..3 */
1360                 dridx += rn1(3, sgn(u.ualign.type) - 1);
1361             You_feel("like %s.", draft_reaction[dridx]);
1362         }
1363     }
1364 }
1365
1366 /* digging via wand zap or spell cast */
1367 void
1368 zap_dig()
1369 {
1370     struct rm *room;
1371     struct monst *mtmp;
1372     struct obj *otmp;
1373     struct trap *trap_with_u = (struct trap *) 0;
1374     int zx, zy, diridx = 8, digdepth, flow_x = -1, flow_y = -1;
1375     boolean shopdoor, shopwall, maze_dig, pitdig = FALSE, pitflow = FALSE;
1376
1377     /*
1378      * Original effect (approximately):
1379      * from CORR: dig until we pierce a wall
1380      * from ROOM: pierce wall and dig until we reach
1381      * an ACCESSIBLE place.
1382      * Currently: dig for digdepth positions;
1383      * also down on request of Lennart Augustsson.
1384      * 3.6.0: from a PIT: dig one adjacent pit.
1385      */
1386
1387     if (u.uswallow) {
1388         mtmp = u.ustuck;
1389
1390         if (!is_whirly(mtmp->data)) {
1391             if (is_animal(mtmp->data))
1392                 You("pierce %s %s wall!", s_suffix(mon_nam(mtmp)),
1393                     mbodypart(mtmp, STOMACH));
1394             mtmp->mhp = 1; /* almost dead */
1395             expels(mtmp, mtmp->data, !is_animal(mtmp->data));
1396         }
1397         return;
1398     } /* swallowed */
1399
1400     if (u.dz) {
1401         if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) {
1402             if (u.dz < 0 || On_stairs(u.ux, u.uy)) {
1403                 int dmg;
1404                 if (On_stairs(u.ux, u.uy))
1405                     pline_The("beam bounces off the %s and hits the %s.",
1406                               (u.ux == xdnladder || u.ux == xupladder)
1407                                   ? "ladder"
1408                                   : "stairs",
1409                               ceiling(u.ux, u.uy));
1410                 You("loosen a rock from the %s.", ceiling(u.ux, u.uy));
1411                 pline("It falls on your %s!", body_part(HEAD));
1412                 dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6);
1413                 losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN);
1414                 otmp = mksobj_at(ROCK, u.ux, u.uy, FALSE, FALSE);
1415                 if (otmp) {
1416                     (void) xname(otmp); /* set dknown, maybe bknown */
1417                     stackobj(otmp);
1418                 }
1419                 newsym(u.ux, u.uy);
1420             } else {
1421                 watch_dig((struct monst *) 0, u.ux, u.uy, TRUE);
1422                 (void) dighole(FALSE, TRUE, (coord *) 0);
1423             }
1424         }
1425         return;
1426     } /* up or down */
1427
1428     /* normal case: digging across the level */
1429     shopdoor = shopwall = FALSE;
1430     maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz);
1431     zx = u.ux + u.dx;
1432     zy = u.uy + u.dy;
1433     if (u.utrap && u.utraptype == TT_PIT
1434         && (trap_with_u = t_at(u.ux, u.uy))) {
1435         pitdig = TRUE;
1436         for (diridx = 0; diridx < 8; diridx++) {
1437             if (xdir[diridx] == u.dx && ydir[diridx] == u.dy)
1438                 break;
1439             /* diridx is valid if < 8 */
1440         }
1441     }
1442     digdepth = rn1(18, 8);
1443     tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam));
1444     while (--digdepth >= 0) {
1445         if (!isok(zx, zy))
1446             break;
1447         room = &levl[zx][zy];
1448         tmp_at(zx, zy);
1449         delay_output(); /* wait a little bit */
1450
1451         if (pitdig) { /* we are already in a pit if this is true */
1452             coord cc;
1453             struct trap *adjpit = t_at(zx, zy);
1454             if ((diridx < 8) && !conjoined_pits(adjpit, trap_with_u, FALSE)) {
1455                 digdepth = 0; /* limited to the adjacent location only */
1456                 if (!(adjpit && (adjpit->ttyp == PIT
1457                                  || adjpit->ttyp == SPIKED_PIT))) {
1458                     char buf[BUFSZ];
1459                     cc.x = zx;
1460                     cc.y = zy;
1461                     if (!adj_pit_checks(&cc, buf)) {
1462                         if (buf[0])
1463                             pline1(buf);
1464                     } else {
1465                         /* this can also result in a pool at zx,zy */
1466                         dighole(TRUE, TRUE, &cc);
1467                         adjpit = t_at(zx, zy);
1468                     }
1469                 }
1470                 if (adjpit
1471                     && (adjpit->ttyp == PIT || adjpit->ttyp == SPIKED_PIT)) {
1472                     int adjidx = (diridx + 4) % 8;
1473                     trap_with_u->conjoined |= (1 << diridx);
1474                     adjpit->conjoined |= (1 << adjidx);
1475                     flow_x = zx;
1476                     flow_y = zy;
1477                     pitflow = TRUE;
1478                 }
1479                 if (is_pool(zx, zy) || is_lava(zx, zy)) {
1480                     flow_x = zx - u.dx;
1481                     flow_y = zy - u.dy;
1482                     pitflow = TRUE;
1483                 }
1484                 break;
1485             }
1486         } else if (closed_door(zx, zy) || room->typ == SDOOR) {
1487             if (*in_rooms(zx, zy, SHOPBASE)) {
1488                 add_damage(zx, zy, 400L);
1489                 shopdoor = TRUE;
1490             }
1491             if (room->typ == SDOOR)
1492                 room->typ = DOOR;
1493             else if (cansee(zx, zy))
1494                 pline_The("door is razed!");
1495             watch_dig((struct monst *) 0, zx, zy, TRUE);
1496             room->doormask = D_NODOOR;
1497             unblock_point(zx, zy); /* vision */
1498             digdepth -= 2;
1499             if (maze_dig)
1500                 break;
1501         } else if (maze_dig) {
1502             if (IS_WALL(room->typ)) {
1503                 if (!(room->wall_info & W_NONDIGGABLE)) {
1504                     if (*in_rooms(zx, zy, SHOPBASE)) {
1505                         add_damage(zx, zy, 200L);
1506                         shopwall = TRUE;
1507                     }
1508                     room->typ = ROOM;
1509                     unblock_point(zx, zy); /* vision */
1510                 } else if (!Blind)
1511                     pline_The("wall glows then fades.");
1512                 break;
1513             } else if (IS_TREE(room->typ)) { /* check trees before stone */
1514                 if (!(room->wall_info & W_NONDIGGABLE)) {
1515                     room->typ = ROOM;
1516                     unblock_point(zx, zy); /* vision */
1517                 } else if (!Blind)
1518                     pline_The("tree shudders but is unharmed.");
1519                 break;
1520             } else if (room->typ == STONE || room->typ == SCORR) {
1521                 if (!(room->wall_info & W_NONDIGGABLE)) {
1522                     room->typ = CORR;
1523                     unblock_point(zx, zy); /* vision */
1524                 } else if (!Blind)
1525                     pline_The("rock glows then fades.");
1526                 break;
1527             }
1528         } else if (IS_ROCK(room->typ)) {
1529             if (!may_dig(zx, zy))
1530                 break;
1531             if (IS_WALL(room->typ) || room->typ == SDOOR) {
1532                 if (*in_rooms(zx, zy, SHOPBASE)) {
1533                     add_damage(zx, zy, 200L);
1534                     shopwall = TRUE;
1535                 }
1536                 watch_dig((struct monst *) 0, zx, zy, TRUE);
1537                 if (level.flags.is_cavernous_lev && !in_town(zx, zy)) {
1538                     room->typ = CORR;
1539                 } else {
1540                     room->typ = DOOR;
1541                     room->doormask = D_NODOOR;
1542                 }
1543                 digdepth -= 2;
1544             } else if (IS_TREE(room->typ)) {
1545                 room->typ = ROOM;
1546                 digdepth -= 2;
1547             } else { /* IS_ROCK but not IS_WALL or SDOOR */
1548                 room->typ = CORR;
1549                 digdepth--;
1550             }
1551             unblock_point(zx, zy); /* vision */
1552         }
1553         zx += u.dx;
1554         zy += u.dy;
1555     }                    /* while */
1556     tmp_at(DISP_END, 0); /* closing call */
1557
1558     if (pitflow && isok(flow_x, flow_y)) {
1559         struct trap *ttmp = t_at(flow_x, flow_y);
1560         if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)) {
1561             schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE);
1562             if (filltyp != ROOM)
1563                 pit_flow(ttmp, filltyp);
1564         }
1565     }
1566
1567     if (shopdoor || shopwall)
1568         pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
1569     return;
1570 }
1571
1572 /*
1573  * This checks what is on the surface above the
1574  * location where an adjacent pit might be created if
1575  * you're zapping a wand of digging laterally while
1576  * down in the pit.
1577  */
1578 STATIC_OVL int
1579 adj_pit_checks(cc, msg)
1580 coord *cc;
1581 char *msg;
1582 {
1583     int ltyp;
1584     struct rm *room;
1585     const char *foundation_msg =
1586         "The foundation is too hard to dig through from this angle.";
1587
1588     if (!cc)
1589         return FALSE;
1590     if (!isok(cc->x, cc->y))
1591         return FALSE;
1592     *msg = '\0';
1593     room = &levl[cc->x][cc->y];
1594     ltyp = room->typ;
1595
1596     if (is_pool(cc->x, cc->y) || is_lava(cc->x, cc->y)) {
1597         /* this is handled by the caller after we return FALSE */
1598         return FALSE;
1599     } else if (closed_door(cc->x, cc->y) || room->typ == SDOOR) {
1600         /* We reject this here because dighole() isn't
1601            prepared to deal with this case */
1602         Strcpy(msg, foundation_msg);
1603         return FALSE;
1604     } else if (IS_WALL(ltyp)) {
1605         /* if (room->wall_info & W_NONDIGGABLE) */
1606         Strcpy(msg, foundation_msg);
1607         return FALSE;
1608     } else if (IS_TREE(ltyp)) { /* check trees before stone */
1609         /* if (room->wall_info & W_NONDIGGABLE) */
1610         Strcpy(msg, "The tree's roots glow then fade.");
1611         return FALSE;
1612     } else if (ltyp == STONE || ltyp == SCORR) {
1613         if (room->wall_info & W_NONDIGGABLE) {
1614             Strcpy(msg, "The rock glows then fades.");
1615             return FALSE;
1616         }
1617     } else if (ltyp == IRONBARS) {
1618         /* "set of iron bars" */
1619         Strcpy(msg, "The bars go much deeper than your pit.");
1620 #if 0
1621     } else if (is_lava(cc->x, cc->y)) {
1622     } else if (is_ice(cc->x, cc->y)) {
1623     } else if (is_pool(cc->x, cc->y)) {
1624     } else if (IS_GRAVE(ltyp)) {
1625 #endif
1626     } else if (IS_SINK(ltyp)) {
1627         Strcpy(msg, "A tangled mass of plumbing remains below the sink.");
1628         return FALSE;
1629     } else if ((cc->x == xupladder && cc->y == yupladder) /* ladder up */
1630                || (cc->x == xdnladder && cc->y == ydnladder)) { /* " down */
1631         Strcpy(msg, "The ladder is unaffected.");
1632         return FALSE;
1633     } else {
1634         const char *supporting = (const char *) 0;
1635
1636         if (IS_FOUNTAIN(ltyp))
1637             supporting = "fountain";
1638         else if (IS_THRONE(ltyp))
1639             supporting = "throne";
1640         else if (IS_ALTAR(ltyp))
1641             supporting = "altar";
1642         else if ((cc->x == xupstair && cc->y == yupstair)
1643                  || (cc->x == sstairs.sx && cc->y == sstairs.sy
1644                      && sstairs.up))
1645             /* "staircase up" */
1646             supporting = "stairs";
1647         else if ((cc->x == xdnstair && cc->y == ydnstair)
1648                  || (cc->x == sstairs.sx && cc->y == sstairs.sy
1649                      && !sstairs.up))
1650             /* "staircase down" */
1651             supporting = "stairs";
1652         else if (ltyp == DRAWBRIDGE_DOWN   /* "lowered drawbridge" */
1653                  || ltyp == DBWALL)        /* "raised drawbridge" */
1654             supporting = "drawbridge";
1655
1656         if (supporting) {
1657             Sprintf(msg, "The %s%ssupporting structures remain intact.",
1658                     supporting ? s_suffix(supporting) : "",
1659                     supporting ? " " : "");
1660             return FALSE;
1661         }
1662     }
1663     return TRUE;
1664 }
1665
1666 /*
1667  * Ensure that all conjoined pits fill up.
1668  */
1669 STATIC_OVL void
1670 pit_flow(trap, filltyp)
1671 struct trap *trap;
1672 schar filltyp;
1673 {
1674     if (trap && (filltyp != ROOM)
1675         && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
1676         struct trap t;
1677         int idx;
1678
1679         t = *trap;
1680         levl[trap->tx][trap->ty].typ = filltyp;
1681         liquid_flow(trap->tx, trap->ty, filltyp, trap,
1682                     (trap->tx == u.ux && trap->ty == u.uy)
1683                         ? "Suddenly %s flows in from the adjacent pit!"
1684                         : (char *) 0);
1685         for (idx = 0; idx < 8; ++idx) {
1686             if (t.conjoined & (1 << idx)) {
1687                 int x, y;
1688                 struct trap *t2;
1689
1690                 x = t.tx + xdir[idx];
1691                 y = t.ty + ydir[idx];
1692                 t2 = t_at(x, y);
1693 #if 0
1694                 /* cannot do this back-check; liquid_flow()
1695                  * called deltrap() which cleaned up the
1696                  * conjoined fields on both pits.
1697                  */
1698                 if (t2 && (t2->conjoined & (1 << ((idx + 4) % 8))))
1699 #endif
1700                 /* recursion */
1701                 pit_flow(t2, filltyp);
1702             }
1703         }
1704     }
1705 }
1706
1707 struct obj *
1708 buried_ball(cc)
1709 coord *cc;
1710 {
1711     xchar check_x, check_y;
1712     struct obj *otmp, *otmp2;
1713
1714     if (u.utraptype == TT_BURIEDBALL)
1715         for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
1716             otmp2 = otmp->nobj;
1717             if (otmp->otyp != HEAVY_IRON_BALL)
1718                 continue;
1719             /* try the exact location first */
1720             if (otmp->ox == cc->x && otmp->oy == cc->y)
1721                 return otmp;
1722             /* Now try the vicinity */
1723             /*
1724              * (x-2,y-2)       (x+2,y-2)
1725              *           (x,y)
1726              * (x-2,y+2)       (x+2,y+2)
1727              */
1728             for (check_x = cc->x - 2; check_x <= cc->x + 2; ++check_x)
1729                 for (check_y = cc->y - 2; check_y <= cc->y + 2; ++check_y) {
1730                     if (check_x == cc->x && check_y == cc->y)
1731                         continue;
1732                     if (isok(check_x, check_y)
1733                         && (otmp->ox == check_x && otmp->oy == check_y)) {
1734                         cc->x = check_x;
1735                         cc->y = check_y;
1736                         return otmp;
1737                     }
1738                 }
1739         }
1740     return (struct obj *) 0;
1741 }
1742
1743 void
1744 buried_ball_to_punishment()
1745 {
1746     coord cc;
1747     struct obj *ball;
1748     cc.x = u.ux;
1749     cc.y = u.uy;
1750     ball = buried_ball(&cc);
1751     if (ball) {
1752         obj_extract_self(ball);
1753 #if 0
1754         /* rusting buried metallic objects is not implemented yet */
1755         if (ball->timed)
1756             (void) stop_timer(RUST_METAL, obj_to_any(ball));
1757 #endif
1758         punish(ball); /* use ball as flag for unearthed buried ball */
1759         u.utrap = 0;
1760         u.utraptype = 0;
1761         del_engr_at(cc.x, cc.y);
1762         newsym(cc.x, cc.y);
1763     }
1764 }
1765
1766 void
1767 buried_ball_to_freedom()
1768 {
1769     coord cc;
1770     struct obj *ball;
1771     cc.x = u.ux;
1772     cc.y = u.uy;
1773     ball = buried_ball(&cc);
1774     if (ball) {
1775         obj_extract_self(ball);
1776 #if 0
1777         /* rusting buried metallic objects is not implemented yet */
1778         if (ball->timed)
1779             (void) stop_timer(RUST_METAL, obj_to_any(ball));
1780 #endif
1781         place_object(ball, cc.x, cc.y);
1782         stackobj(ball);
1783         u.utrap = 0;
1784         u.utraptype = 0;
1785         del_engr_at(cc.x, cc.y);
1786         newsym(cc.x, cc.y);
1787     }
1788 }
1789
1790 /* move objects from fobj/nexthere lists to buriedobjlist, keeping position
1791    information */
1792 struct obj *
1793 bury_an_obj(otmp, dealloced)
1794 struct obj *otmp;
1795 boolean *dealloced;
1796 {
1797     struct obj *otmp2;
1798     boolean under_ice;
1799
1800     debugpline1("bury_an_obj: %s", xname(otmp));
1801     if (dealloced)
1802         *dealloced = FALSE;
1803     if (otmp == uball) {
1804         unpunish();
1805         u.utrap = rn1(50, 20);
1806         u.utraptype = TT_BURIEDBALL;
1807         pline_The("iron ball gets buried!");
1808     }
1809     /* after unpunish(), or might get deallocated chain */
1810     otmp2 = otmp->nexthere;
1811     /*
1812      * obj_resists(,0,0) prevents Rider corpses from being buried.
1813      * It also prevents The Amulet and invocation tools from being
1814      * buried.  Since they can't be confined to bags and statues,
1815      * it makes sense that they can't be buried either, even though
1816      * the real reason there (direct accessibility when carried) is
1817      * completely different.
1818      */
1819     if (otmp == uchain || obj_resists(otmp, 0, 0))
1820         return otmp2;
1821
1822     if (otmp->otyp == LEASH && otmp->leashmon != 0)
1823         o_unleash(otmp);
1824
1825     if (otmp->lamplit && otmp->otyp != POT_OIL)
1826         end_burn(otmp, TRUE);
1827
1828     obj_extract_self(otmp);
1829
1830     under_ice = is_ice(otmp->ox, otmp->oy);
1831     if (otmp->otyp == ROCK && !under_ice) {
1832         /* merges into burying material */
1833         if (dealloced)
1834             *dealloced = TRUE;
1835         obfree(otmp, (struct obj *) 0);
1836         return otmp2;
1837     }
1838     /*
1839      * Start a rot on organic material.  Not corpses -- they
1840      * are already handled.
1841      */
1842     if (otmp->otyp == CORPSE) {
1843         ; /* should cancel timer if under_ice */
1844     } else if ((under_ice ? otmp->oclass == POTION_CLASS : is_organic(otmp))
1845                && !obj_resists(otmp, 5, 95)) {
1846         (void) start_timer((under_ice ? 0L : 250L) + (long) rnd(250),
1847                            TIMER_OBJECT, ROT_ORGANIC, obj_to_any(otmp));
1848 #if 0
1849     /* rusting of buried metal not yet implemented */
1850     } else if (is_rustprone(otmp)) {
1851         (void) start_timer((long) rnd((otmp->otyp == HEAVY_IRON_BALL)
1852                                          ? 1500
1853                                          : 250),
1854                            TIMER_OBJECT, RUST_METAL, obj_to_any(otmp));
1855 #endif
1856     }
1857     add_to_buried(otmp);
1858     return  otmp2;
1859 }
1860
1861 void
1862 bury_objs(x, y)
1863 int x, y;
1864 {
1865     struct obj *otmp, *otmp2;
1866
1867     if (level.objects[x][y] != (struct obj *) 0) {
1868         debugpline2("bury_objs: at <%d,%d>", x, y);
1869     }
1870     for (otmp = level.objects[x][y]; otmp; otmp = otmp2)
1871         otmp2 = bury_an_obj(otmp, (boolean *) 0);
1872
1873     /* don't expect any engravings here, but just in case */
1874     del_engr_at(x, y);
1875     newsym(x, y);
1876 }
1877
1878 /* move objects from buriedobjlist to fobj/nexthere lists */
1879 void
1880 unearth_objs(x, y)
1881 int x, y;
1882 {
1883     struct obj *otmp, *otmp2, *bball;
1884     coord cc;
1885
1886     debugpline2("unearth_objs: at <%d,%d>", x, y);
1887     cc.x = x;
1888     cc.y = y;
1889     bball = buried_ball(&cc);
1890     for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
1891         otmp2 = otmp->nobj;
1892         if (otmp->ox == x && otmp->oy == y) {
1893             if (bball && otmp == bball && u.utraptype == TT_BURIEDBALL) {
1894                 buried_ball_to_punishment();
1895             } else {
1896                 obj_extract_self(otmp);
1897                 if (otmp->timed)
1898                     (void) stop_timer(ROT_ORGANIC, obj_to_any(otmp));
1899                 place_object(otmp, x, y);
1900                 stackobj(otmp);
1901             }
1902         }
1903     }
1904     del_engr_at(x, y);
1905     newsym(x, y);
1906 }
1907
1908 /*
1909  * The organic material has rotted away while buried.  As an expansion,
1910  * we could add add partial damage.  A damage count is kept in the object
1911  * and every time we are called we increment the count and reschedule another
1912  * timeout.  Eventually the object rots away.
1913  *
1914  * This is used by buried objects other than corpses.  When a container rots
1915  * away, any contents become newly buried objects.
1916  */
1917 /* ARGSUSED */
1918 void
1919 rot_organic(arg, timeout)
1920 anything *arg;
1921 long timeout UNUSED;
1922 {
1923     struct obj *obj = arg->a_obj;
1924
1925     while (Has_contents(obj)) {
1926         /* We don't need to place contained object on the floor
1927            first, but we do need to update its map coordinates. */
1928         obj->cobj->ox = obj->ox, obj->cobj->oy = obj->oy;
1929         /* Everything which can be held in a container can also be
1930            buried, so bury_an_obj's use of obj_extract_self insures
1931            that Has_contents(obj) will eventually become false. */
1932         (void) bury_an_obj(obj->cobj, (boolean *) 0);
1933     }
1934     obj_extract_self(obj);
1935     obfree(obj, (struct obj *) 0);
1936 }
1937
1938 /*
1939  * Called when a corpse has rotted completely away.
1940  */
1941 void
1942 rot_corpse(arg, timeout)
1943 anything *arg;
1944 long timeout;
1945 {
1946     xchar x = 0, y = 0;
1947     struct obj *obj = arg->a_obj;
1948     boolean on_floor = obj->where == OBJ_FLOOR,
1949             in_invent = obj->where == OBJ_INVENT;
1950
1951     if (on_floor) {
1952         x = obj->ox;
1953         y = obj->oy;
1954     } else if (in_invent) {
1955         if (flags.verbose) {
1956             char *cname = corpse_xname(obj, (const char *) 0, CXN_NO_PFX);
1957
1958             Your("%s%s %s away%c", obj == uwep ? "wielded " : "", cname,
1959                  otense(obj, "rot"), obj == uwep ? '!' : '.');
1960         }
1961         if (obj == uwep) {
1962             uwepgone(); /* now bare handed */
1963             stop_occupation();
1964         } else if (obj == uswapwep) {
1965             uswapwepgone();
1966             stop_occupation();
1967         } else if (obj == uquiver) {
1968             uqwepgone();
1969             stop_occupation();
1970         }
1971     } else if (obj->where == OBJ_MINVENT && obj->owornmask) {
1972         if (obj == MON_WEP(obj->ocarry))
1973             setmnotwielded(obj->ocarry, obj);
1974     } else if (obj->where == OBJ_MIGRATING) {
1975         /* clear destination flag so that obfree()'s check for
1976            freeing a worn object doesn't get a false hit */
1977         obj->owornmask = 0L;
1978     }
1979     rot_organic(arg, timeout);
1980     if (on_floor) {
1981         struct monst *mtmp = m_at(x, y);
1982
1983         /* a hiding monster may be exposed */
1984         if (mtmp && !OBJ_AT(x, y) && mtmp->mundetected
1985             && hides_under(mtmp->data)) {
1986             mtmp->mundetected = 0;
1987         } else if (x == u.ux && y == u.uy && u.uundetected && hides_under(youmonst.data))
1988             (void) hideunder(&youmonst);
1989         newsym(x, y);
1990     } else if (in_invent)
1991         update_inventory();
1992 }
1993
1994 #if 0
1995 void
1996 bury_monst(mtmp)
1997 struct monst *mtmp;
1998 {
1999     debugpline1("bury_monst: %s", mon_nam(mtmp));
2000     if (canseemon(mtmp)) {
2001         if (is_flyer(mtmp->data) || is_floater(mtmp->data)) {
2002             pline_The("%s opens up, but %s is not swallowed!",
2003                       surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
2004             return;
2005         } else
2006             pline_The("%s opens up and swallows %s!",
2007                       surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
2008     }
2009
2010     mtmp->mburied = TRUE;
2011     wakeup(mtmp);       /* at least give it a chance :-) */
2012     newsym(mtmp->mx, mtmp->my);
2013 }
2014
2015 void
2016 bury_you()
2017 {
2018     debugpline0("bury_you");
2019     if (!Levitation && !Flying) {
2020         if (u.uswallow)
2021             You_feel("a sensation like falling into a trap!");
2022         else
2023             pline_The("%s opens beneath you and you fall in!",
2024                       surface(u.ux, u.uy));
2025
2026         u.uburied = TRUE;
2027         if (!Strangled && !Breathless)
2028             Strangled = 6;
2029         under_ground(1);
2030     }
2031 }
2032
2033 void
2034 unearth_you()
2035 {
2036     debugpline0("unearth_you");
2037     u.uburied = FALSE;
2038     under_ground(0);
2039     if (!uamul || uamul->otyp != AMULET_OF_STRANGULATION)
2040         Strangled = 0;
2041     vision_recalc(0);
2042 }
2043
2044 void
2045 escape_tomb()
2046 {
2047     debugpline0("escape_tomb");
2048     if ((Teleportation || can_teleport(youmonst.data))
2049         && (Teleport_control || rn2(3) < Luck+2)) {
2050         You("attempt a teleport spell.");
2051         (void) dotele();        /* calls unearth_you() */
2052     } else if (u.uburied) { /* still buried after 'port attempt */
2053         boolean good;
2054
2055         if (amorphous(youmonst.data) || Passes_walls
2056             || noncorporeal(youmonst.data)
2057             || (unsolid(youmonst.data)
2058                 && youmonst.data != &mons[PM_WATER_ELEMENTAL])
2059             || (tunnels(youmonst.data) && !needspick(youmonst.data))) {
2060             You("%s up through the %s.",
2061                 (tunnels(youmonst.data) && !needspick(youmonst.data))
2062                    ? "try to tunnel"
2063                    : (amorphous(youmonst.data))
2064                       ? "ooze"
2065                       : "phase",
2066                 surface(u.ux, u.uy));
2067
2068             good = (tunnels(youmonst.data) && !needspick(youmonst.data))
2069                       ? dighole(TRUE, FALSE, (coord *)0) : TRUE;
2070             if (good)
2071                 unearth_you();
2072         }
2073     }
2074 }
2075
2076 void
2077 bury_obj(otmp)
2078 struct obj *otmp;
2079 {
2080     debugpline0("bury_obj");
2081     if (cansee(otmp->ox, otmp->oy))
2082         pline_The("objects on the %s tumble into a hole!",
2083                   surface(otmp->ox, otmp->oy));
2084
2085     bury_objs(otmp->ox, otmp->oy);
2086 }
2087 #endif /*0*/
2088
2089 #ifdef DEBUG
2090 /* bury everything at your loc and around */
2091 int
2092 wiz_debug_cmd_bury()
2093 {
2094     int x, y;
2095
2096     for (x = u.ux - 1; x <= u.ux + 1; x++)
2097         for (y = u.uy - 1; y <= u.uy + 1; y++)
2098             if (isok(x, y))
2099                 bury_objs(x, y);
2100     return 0;
2101 }
2102 #endif /* DEBUG */
2103
2104 /*dig.c*/