OSDN Git Service

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