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. */
7 /* #define DEBUG */ /* turn on for diagnostics */
11 static NEARDATA boolean did_dig_msg;
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);
21 /* Indices returned by dig_typ() */
22 #define DIGTYP_UNDIGGABLE 0
24 #define DIGTYP_STATUE 2
25 #define DIGTYP_BOULDER 3
35 if(levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit)
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);
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.
48 mkcavepos(x, y, dist, waslit, rockit)
51 boolean waslit, rockit;
53 register struct rm *lev;
55 if(!isok(x,y)) return;
59 register struct monst *mtmp;
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;
67 unblock_point(x,y); /* make sure vision knows this location is open */
69 /* fake out saved state */
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 */
78 lev->typ = (rockit ? STONE : ROOM);
80 impossible("mkcavepos called with dist %d", dist);
88 register boolean rockit;
91 xchar xmin = u.ux, xmax = u.ux;
92 xchar ymin = u.uy, ymax = u.uy;
94 register boolean waslit = rm_waslit();
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);
101 for(dist = 1; dist <= 2; dist++) {
105 if(dist < 2) { /* the area is wider that it is high */
107 for(i = xmin+1; i < xmax; i++) {
108 mkcavepos(i, ymin, dist, waslit, rockit);
109 mkcavepos(i, ymax, dist, waslit, rockit);
114 for(i = ymin; i <= ymax; i++) {
115 mkcavepos(xmin, i, dist, waslit, rockit);
116 mkcavepos(xmax, i, dist, waslit, rockit);
119 flush_screen(1); /* make sure the new glyphs shows up */
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 */
129 vision_full_recalc = 1; /* everything changed */
132 /* When digging into location <x,y>, what are you actually digging into? */
138 boolean ispick = is_pick(otmp);
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);
153 if (occupation == dig) {
159 #define BY_YOU (&youmonst)
160 #define BY_OBJECT ((struct monst *)0)
163 dig_check(madeby, verbose, x, y)
164 struct monst *madeby;
168 struct trap *ttmp = t_at(x, y);
169 const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in";
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);
176 } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
177 if(verbose) pline_The("throne is too hard to break apart.");
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.");
183 } else if (Is_airlevel(&u.uz)) {
184 if(verbose) You("cannot %s thin air.", verb);
186 } else if (Is_waterlevel(&u.uz)) {
187 if(verbose) pline_The("water splashes and subsides.");
189 } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR &&
190 (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
192 (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) {
193 if(verbose) pline_The("%s here is too hard to %s.",
196 } else if (sobj_at(BOULDER, x, y)) {
197 if(verbose) There("isn't enough room to %s here.", verb);
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 */
212 register struct rm *lev;
213 register xchar dpx = digging.pos.x, dpy = digging.pos.y;
214 register boolean ispick = uwep && is_pick(uwep);
216 (!uwep || is_pick(uwep)) ? "dig into" : "chop through";
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))))
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.");
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);
241 if(Fumbling && !rn2(3)) {
245 You("fumble and drop your %s.", xname(uwep));
250 Your("%s %s and %s %s!",
252 otense(uwep, "bounce"), otense(uwep, "hit"),
256 pline("Ouch! Your %s %s and %s you!",
258 otense(uwep, "bounce"), otense(uwep, "hit"));
259 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
263 pline("Bang! You hit with the broad side of %s!",
266 default: Your("swing misses its mark.");
272 digging.effort += 10 + rn2(5) + abon() +
273 uwep->spe - greatest_erosion(uwep) + u.udaminc;
274 if (Race_if(PM_DWARF))
277 register struct trap *ttmp;
279 if (digging.effort > 250) {
280 (void) dighole(FALSE);
281 (void) memset((genericptr_t)&digging, 0, sizeof digging);
282 return(0); /* done with digging */
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)))
291 if (IS_ALTAR(lev->typ)) {
292 altar_wrath(dpx, dpy);
296 if (dighole(TRUE)) { /* make pit at <u.ux,u.uy> */
297 digging.level.dnum = 0;
298 digging.level.dlevel = -1;
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);
308 if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) {
309 if (break_statue(obj))
310 digtxt = "The statue shatters.";
312 /* it was a statue trap; break_statue()
313 * printed a message and updated the screen
316 } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) {
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);
325 digtxt = "The boulder falls apart.";
326 } else if (lev->typ == STONE || lev->typ == SCORR ||
328 if(Is_earthlevel(&u.uz)) {
329 if(uwep->blessed && !rn2(3)) {
332 } else if((uwep->cursed && !rn2(4)) ||
333 (!uwep->blessed && !rn2(6))) {
338 if (IS_TREE(lev->typ)) {
339 digtxt = "You cut down the tree.";
341 if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy);
343 digtxt = "You succeed in cutting away some rock.";
346 } else if(IS_WALL(lev->typ)) {
348 add_damage(dpx, dpy, 10L * ACURRSTR);
351 if (level.flags.is_maze_lev) {
353 } else if (level.flags.is_cavernous_lev &&
354 !in_town(dpx, dpy)) {
358 lev->doormask = D_NODOOR;
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.";
369 add_damage(dpx, dpy, 400L);
372 if(!(lev->doormask & D_TRAPPED))
373 lev->doormask = D_BROKEN;
374 } else return(0); /* statue or boulder got taken */
376 if(!does_block(dpx,dpy,&levl[dpx][dpy]))
377 unblock_point(dpx,dpy); /* vision: can see through */
379 feel_location(dpx, dpy);
382 if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */
384 pay_for_damage(dmgtxt, FALSE);
386 if(Is_earthlevel(&u.uz) && !rn2(3)) {
387 register struct monst *mtmp;
391 mtmp = makemon(&mons[PM_EARTH_ELEMENTAL],
392 dpx, dpy, NO_MM_FLAGS);
395 mtmp = makemon(&mons[PM_XORN],
396 dpx, dpy, NO_MM_FLAGS);
399 if(mtmp) pline_The("debris from your digging comes to life!");
401 if(IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) {
402 lev->doormask = D_NODOOR;
403 b_trapped("door", 0);
407 digging.lastdigtime = moves;
408 digging.quiet = FALSE;
409 digging.level.dnum = 0;
410 digging.level.dlevel = -1;
412 } else { /* not enough effort has been spent yet */
413 static const char *const d_target[6] = {
414 "", "rock", "statue", "boulder", "door", "tree"
416 int dig_target = dig_typ(uwep, dpx, dpy);
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);
424 } else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK)
425 return(0); /* statue or boulder got taken */
427 You("hit the %s with all your might.",
428 d_target[dig_target]);
435 /* When will hole be finished? Very rough indication used by shopkeeper. */
439 if(occupation != dig || !*u.ushops) return(-1);
440 return ((250 - digging.effort) / 20);
443 /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
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;
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)
458 else if (levl[x1][y1].typ == MOAT ||
459 (levl[x1][y1].typ == DRAWBRIDGE_UP &&
460 (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_MOAT))
462 else if (levl[x1][y1].typ == LAVAPOOL ||
463 (levl[x1][y1].typ == DRAWBRIDGE_UP &&
464 (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_LAVA))
466 pool_cnt /= 3; /* not as much liquid as the others */
468 if (lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1))
470 else if (moat_cnt > 0 && rn2(moat_cnt + 1))
472 else if (pool_cnt > 0 && rn2(pool_cnt + 1))
479 digactualhole(x, y, madeby, ttyp)
481 struct monst *madeby;
484 struct obj *oldobjs, *newobjs;
485 register struct trap *ttmp;
486 char surface_type[BUFSZ];
487 struct rm *lev = &levl[x][y];
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;
495 if (u.utrap && u.utraptype == TT_INFLOOR) u.utrap = 0;
497 /* these furniture checks were in dighole(), but wand
498 breaking bypasses that routine and calls us directly */
499 if (IS_FOUNTAIN(lev->typ)) {
501 SET_FOUNTAIN_WARNED(x,y); /* force dryup */
502 dryup(x, y, madeby_u);
505 } else if (IS_SINK(lev->typ)) {
509 } else if (lev->typ == DRAWBRIDGE_DOWN ||
510 (is_drawbridge_wall(x, y) >= 0)) {
512 /* if under the portcullis, the bridge is adjacent */
513 (void) find_drawbridge(&bx, &by);
514 destroy_drawbridge(bx, by);
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);
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");
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);
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);
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);
553 u.utraptype = TT_PIT;
554 vision_full_recalc = 1; /* vision limits change */
557 if (oldobjs != newobjs) /* something unearthed */
558 (void) pickup(1); /* detects pit */
560 if(is_flyer(mtmp->data) || is_floater(mtmp->data)) {
562 pline("%s %s over the pit.", Monnam(mtmp),
563 (is_flyer(mtmp->data)) ?
565 } else if(mtmp != madeby)
566 (void) mintrap(mtmp);
568 } else { /* was TRAPDOOR now a HOLE*/
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);
579 if (!u.ustuck && !wont_fall && !next_to_u()) {
580 You("are jerked back by your pet!");
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().
588 if (u.ustuck || wont_fall) {
590 impact_drop((struct obj *)0, x, y, 0);
591 if (oldobjs != newobjs)
593 if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
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);
603 You("fall through...");
604 /* Earlier checks must ensure that the destination
605 * level exists and is in the present dungeon.
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 */
614 if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE);
616 impact_drop((struct obj *)0, x, y, 0);
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 */
626 if (teleport_pet(mtmp, FALSE)) {
629 if (Is_stronghold(&u.uz)) {
630 assign_level(&tolevel, &valley_level);
631 } else if (Is_botlevel(&u.uz)) {
633 pline("%s avoids the trap.", Monnam(mtmp));
636 get_level(&tolevel, depth(&u.uz) + 1);
638 if (mtmp->isshk) make_angry_shk(mtmp, 0, 0);
639 migrate_to_level(mtmp, ledger_no(&tolevel),
640 MIGR_RANDOM, (coord *)0);
647 /* return TRUE if digging succeeded, FALSE otherwise */
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;
656 boolean nohole = !Can_dig_down(&u.uz);
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));
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 */
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 */
674 pline_The("drawbridge seems too hard to dig through.");
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);
684 } else if ((boulder_here = sobj_at(BOULDER, u.ux, u.uy)) != 0) {
685 if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) &&
687 pline_The("boulder settles into the pit.");
688 ttmp->ttyp = PIT; /* crush spikes */
691 * digging makes a hole, but the boulder immediately
692 * fills it. Final outcome: no hole, no boulder.
694 pline("KADOOM! The boulder falls in!");
695 (void) delfloortrap(ttmp);
697 delobj(boulder_here);
700 } else if (IS_GRAVE(lev->typ)) {
701 digactualhole(u.ux, u.uy, BY_YOU, PIT);
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);
711 * We can't dig a hole here since that will destroy
712 * the drawbridge. The following is a cop-out. --dlc
714 pline_The("%s here is too hard to dig in.",
715 surface(u.ux, u.uy));
719 lev->drawbridgemask &= ~DB_UNDER;
720 lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT;
723 if (ttmp) (void) delfloortrap(ttmp);
724 /* if any objects were frozen here, they're released now */
725 unearth_objs(u.ux, u.uy);
727 pline("As you dig, the hole fills with %s!",
728 typ == LAVAPOOL ? "lava" : "water");
729 if (!Levitation && !Flying) {
731 (void) lava_effects();
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.");
741 } else if (IS_ALTAR(lev->typ)) {
742 pline_The("altar is too hard to break apart.");
745 typ = fillholetyp(u.ux,u.uy);
752 /* finally we get to make a hole */
753 if (nohole || pit_only)
754 digactualhole(u.ux, u.uy, BY_YOU, PIT);
756 digactualhole(u.ux, u.uy, BY_YOU, HOLE);
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!");
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 */;
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);
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);
801 pline_The("grave seems unused. Strange....");
804 levl[u.ux][u.uy].typ = ROOM;
805 del_engr_at(u.ux, u.uy);
817 register char *dsp = dirsyms;
820 register const char *sdp, *verb;
822 if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
826 if (!wield_tool(obj, "swing")) return 0;
829 ispick = is_pick(obj);
830 verb = ispick ? "dig" : "chop";
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);
841 (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */
844 /* Include down even with axe, so we have at least one direction */
846 (u.dz == 0 && isok(rx, ry) &&
847 dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE))
852 Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms);
856 return(use_pick_axe2(obj));
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 */
868 register struct rm *lev;
870 boolean ispick = is_pick(obj);
871 const char *verbing = ispick ? "digging" : "chopping";
873 if (u.uswallow && attack(u.ustuck)) {
875 } else if (Underwater) {
876 pline("Turbulence torpedoes your %s attempts.", verbing);
877 } else if(u.dz < 0) {
879 You("don't have enough leverage.");
881 You_cant("reach the %s.",ceiling(u.ux,u.uy));
882 } else if(!u.dx && !u.dy && !u.dz) {
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);
894 } else if(u.dz == 0) {
895 if(Stunned || (Confusion && !rn2(5))) confdir();
903 if(MON_AT(rx, ry) && attack(m_at(rx, ry)))
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);
910 if (trap && trap->ttyp == WEB) {
913 There("is a spider web there!");
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) */
920 nomovemsg = "You pull free.";
921 } else if (lev->typ == IRONBARS) {
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);
937 You("swing your %s through thin air.",
938 aobjnam(obj, (char *)0));
940 static const char * const d_action[6] = {
943 "chipping the statue",
944 "hitting the boulder",
945 "chopping at the door",
949 digging.quiet = FALSE;
950 if (digging.pos.x != rx || digging.pos.y != ry ||
951 !on_level(&digging.level, &u.uz) || digging.down) {
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 */
960 digging.quiet = TRUE;
962 digging.down = digging.chew = FALSE;
963 digging.warned = FALSE;
966 assign_level(&digging.level, &u.uz);
969 You("start %s.", d_action[dig_target]);
971 You("%s %s.", digging.chew ? "begin" : "continue",
972 d_action[dig_target]);
973 digging.chew = FALSE;
975 set_occupation(dig, verbing, 0);
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));
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;
995 digging.warned = FALSE;
996 digging.pos.x = u.ux;
997 digging.pos.y = u.uy;
998 assign_level(&digging.level, &u.uz);
1000 You("start %s downward.", verbing);
1001 if (*u.ushops) shopdig(0);
1003 You("continue %s downward.", verbing);
1004 did_dig_msg = FALSE;
1005 set_occupation(dig, verbing, 0);
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)
1017 watch_dig(mtmp, x, y, zap)
1022 struct rm *lev = &levl[x][y];
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))) {
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)
1039 if(zap || digging.warned) {
1040 verbalize("Halt, vandal! You're under arrest!");
1041 (void) angry_guards(!(flags.soundok));
1045 if (IS_DOOR(lev->typ))
1047 else if (IS_TREE(lev->typ))
1049 else if (IS_ROCK(lev->typ))
1053 verbalize("Hey, stop damaging that %s!", str);
1054 digging.warned = TRUE;
1065 /* Return TRUE if monster died, FALSE otherwise. Called from m_move(). */
1068 register struct monst *mtmp;
1070 register struct rm *here;
1073 here = &levl[mtmp->mx][mtmp->my];
1074 if (here->typ == SDOOR)
1075 cvt_sdoor_to_door(here); /* ->typ = DOOR */
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);
1089 if (!rn2(3) && flags.verbose) /* not too often.. */
1090 You_feel("an unexpected draft.");
1091 here->doormask = D_BROKEN;
1093 newsym(mtmp->mx, mtmp->my);
1095 } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */
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 */
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) {
1114 } else if (level.flags.is_cavernous_lev &&
1115 !in_town(mtmp->mx, mtmp->my)) {
1119 here->doormask = D_NODOOR;
1121 } else if (IS_TREE(here->typ)) {
1123 if (pile && pile < 5)
1124 (void) rnd_treefruit_at(mtmp->mx, mtmp->my);
1127 if (pile && pile < 5)
1128 (void) mksobj_at((pile == 1) ? BOULDER : ROCK,
1129 mtmp->mx, mtmp->my, TRUE, FALSE);
1131 newsym(mtmp->mx, mtmp->my);
1132 if (!sobj_at(BOULDER, mtmp->mx, mtmp->my))
1133 unblock_point(mtmp->mx, mtmp->my); /* vision */
1141 /* digging via wand zap or spell cast */
1148 int zx, zy, digdepth;
1149 boolean shopdoor, shopwall, maze_dig;
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.
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));
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);
1185 (void)xname(otmp); /* set dknown, maybe bknown */
1190 watch_dig((struct monst *)0, u.ux, u.uy, TRUE);
1191 (void) dighole(FALSE);
1197 /* normal case: digging across the level */
1198 shopdoor = shopwall = FALSE;
1199 maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz);
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];
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);
1214 if (room->typ == SDOOR)
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 */
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);
1231 unblock_point(zx,zy); /* vision */
1233 pline_The("wall glows then fades.");
1235 } else if (IS_TREE(room->typ)) { /* check trees before stone */
1236 if (!(room->wall_info & W_NONDIGGABLE)) {
1238 unblock_point(zx,zy); /* vision */
1240 pline_The("tree shudders but is unharmed.");
1242 } else if (room->typ == STONE || room->typ == SCORR) {
1243 if (!(room->wall_info & W_NONDIGGABLE)) {
1245 unblock_point(zx,zy); /* vision */
1247 pline_The("rock glows then fades.");
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);
1257 watch_dig((struct monst *)0, zx, zy, TRUE);
1258 if (level.flags.is_cavernous_lev && !in_town(zx, zy)) {
1262 room->doormask = D_NODOOR;
1265 } else if (IS_TREE(room->typ)) {
1268 } else { /* IS_ROCK but not IS_WALL or SDOOR */
1272 unblock_point(zx,zy); /* vision */
1277 tmp_at(DISP_END,0); /* closing call */
1278 if (shopdoor || shopwall)
1279 pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE);
1283 /* move objects from fobj/nexthere lists to buriedobjlist, keeping position */
1293 pline("bury_an_obj: %s", xname(otmp));
1297 /* after unpunish(), or might get deallocated chain */
1298 otmp2 = otmp->nexthere;
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.
1307 if (otmp == uchain || obj_resists(otmp, 0, 0))
1310 if (otmp->otyp == LEASH && otmp->leashmon != 0)
1313 if (otmp->lamplit && otmp->otyp != POT_OIL)
1314 end_burn(otmp, TRUE);
1316 obj_extract_self(otmp);
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);
1325 * Start a rot on organic material. Not corpses -- they
1326 * are already handled.
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);
1335 add_to_buried(otmp);
1343 struct obj *otmp, *otmp2;
1346 if(level.objects[x][y] != (struct obj *)0)
1347 pline("bury_objs: at %d, %d", x, y);
1349 for (otmp = level.objects[x][y]; otmp; otmp = otmp2)
1350 otmp2 = bury_an_obj(otmp);
1352 /* don't expect any engravings here, but just in case */
1357 /* move objects from buriedobjlist to fobj/nexthere lists */
1362 struct obj *otmp, *otmp2;
1365 pline("unearth_objs: at %d, %d", x, y);
1367 for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
1369 if (otmp->ox == x && otmp->oy == y) {
1370 obj_extract_self(otmp);
1372 (void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp);
1373 place_object(otmp, x, y);
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.
1387 * This is used by buried objects other than corpses. When a container rots
1388 * away, any contents become newly buried objects.
1392 rot_organic(arg, timeout)
1394 long timeout; /* unused */
1396 struct obj *obj = (struct obj *) arg;
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);
1407 obj_extract_self(obj);
1408 obfree(obj, (struct obj *) 0);
1412 * Called when a corpse has rotted completely away.
1415 rot_corpse(arg, timeout)
1417 long timeout; /* unused */
1420 struct obj *obj = (struct obj *) arg;
1421 boolean on_floor = obj->where == OBJ_FLOOR,
1422 in_invent = obj->where == OBJ_INVENT;
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 ? '!' : '.');
1435 uwepgone(); /* now bare handed */
1437 } else if (obj == uswapwep) {
1440 } else if (obj == uquiver) {
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);
1450 rot_organic(arg, timeout);
1451 if (on_floor) newsym(x, y);
1452 else if (in_invent) update_inventory();
1461 pline("bury_monst: %s", mon_nam(mtmp));
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));
1469 pline_The("%s opens up and swallows %s!",
1470 surface(mtmp->mx, mtmp->my), mon_nam(mtmp));
1473 mtmp->mburied = TRUE;
1474 wakeup(mtmp); /* at least give it a chance :-) */
1475 newsym(mtmp->mx, mtmp->my);
1484 if (!Levitation && !Flying) {
1486 You_feel("a sensation like falling into a trap!");
1488 pline_The("%s opens beneath you and you fall in!",
1489 surface(u.ux, u.uy));
1492 if(!Strangled && !Breathless) Strangled = 6;
1501 pline("unearth_you");
1505 if(!uamul || uamul->otyp != AMULET_OF_STRANGULATION)
1514 pline("escape_tomb");
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 */
1523 if(amorphous(youmonst.data) || Passes_walls ||
1524 noncorporeal(youmonst.data) || unsolid(youmonst.data) ||
1525 (tunnels(youmonst.data) && !needspick(youmonst.data))) {
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));
1532 if(tunnels(youmonst.data) && !needspick(youmonst.data))
1533 good = dighole(TRUE);
1535 if(good) unearth_you();
1548 if(cansee(otmp->ox, otmp->oy))
1549 pline_The("objects on the %s tumble into a hole!",
1550 surface(otmp->ox, otmp->oy));
1552 bury_objs(otmp->ox, otmp->oy);
1558 wiz_debug_cmd() /* in this case, bury everything at your loc and around */
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);