1 /* NetHack 3.6 dig.c $NHDT-Date: 1449269915 2015/12/04 22:58:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.103 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 static NEARDATA boolean did_dig_msg
;
9 STATIC_DCL boolean
NDECL(rm_waslit
);
10 STATIC_DCL
void FDECL(mkcavepos
,
11 (XCHAR_P
, XCHAR_P
, int, BOOLEAN_P
, BOOLEAN_P
));
12 STATIC_DCL
void FDECL(mkcavearea
, (BOOLEAN_P
));
13 STATIC_DCL
int NDECL(dig
);
14 STATIC_DCL
void FDECL(dig_up_grave
, (coord
*));
15 STATIC_DCL
int FDECL(adj_pit_checks
, (coord
*, char *));
16 STATIC_DCL
void FDECL(pit_flow
, (struct trap
*, SCHAR_P
));
18 /* Indices returned by dig_typ() */
19 #define DIGTYP_UNDIGGABLE 0
21 #define DIGTYP_STATUE 2
22 #define DIGTYP_BOULDER 3
31 if (levl
[u
.ux
][u
.uy
].typ
== ROOM
&& levl
[u
.ux
][u
.uy
].waslit
)
33 for (x
= u
.ux
- 2; x
< u
.ux
+ 3; x
++)
34 for (y
= u
.uy
- 1; y
< u
.uy
+ 2; y
++)
35 if (isok(x
, y
) && levl
[x
][y
].waslit
)
40 /* Change level topology. Messes with vision tables and ignores things like
41 * boulders in the name of a nice effect. Vision will get fixed up again
42 * immediately after the effect is complete.
45 mkcavepos(x
, y
, dist
, waslit
, rockit
)
48 boolean waslit
, rockit
;
50 register struct rm
*lev
;
57 register struct monst
*mtmp
;
59 if (IS_ROCK(lev
->typ
))
62 return; /* don't cover the portal */
63 if ((mtmp
= m_at(x
, y
)) != 0) /* make sure crucial monsters survive */
64 if (!passes_walls(mtmp
->data
))
65 (void) rloc(mtmp
, TRUE
);
66 } else if (lev
->typ
== ROOM
)
69 unblock_point(x
, y
); /* make sure vision knows this location is open */
71 /* fake out saved state */
75 lev
->lit
= (rockit
? FALSE
: TRUE
);
77 lev
->waslit
= (rockit
? FALSE
: TRUE
);
78 lev
->horizontal
= FALSE
;
79 /* short-circuit vision recalc */
80 viz_array
[y
][x
] = (dist
< 3) ? (IN_SIGHT
| COULD_SEE
) : COULD_SEE
;
81 lev
->typ
= (rockit
? STONE
: ROOM
);
83 impossible("mkcavepos called with dist %d", dist
);
89 register boolean rockit
;
92 xchar xmin
= u
.ux
, xmax
= u
.ux
;
93 xchar ymin
= u
.uy
, ymax
= u
.uy
;
95 register boolean waslit
= rm_waslit();
98 pline("Crash! The ceiling collapses around you!");
100 pline("A mysterious force %s cave around you!",
101 (levl
[u
.ux
][u
.uy
].typ
== CORR
) ? "creates a" : "extends the");
102 display_nhwindow(WIN_MESSAGE
, TRUE
);
104 for (dist
= 1; dist
<= 2; dist
++) {
109 if (dist
< 2) { /* the area is wider that it is high */
112 for (i
= xmin
+ 1; i
< xmax
; i
++) {
113 mkcavepos(i
, ymin
, dist
, waslit
, rockit
);
114 mkcavepos(i
, ymax
, dist
, waslit
, rockit
);
119 for (i
= ymin
; i
<= ymax
; i
++) {
120 mkcavepos(xmin
, i
, dist
, waslit
, rockit
);
121 mkcavepos(xmax
, i
, dist
, waslit
, rockit
);
124 flush_screen(1); /* make sure the new glyphs shows up */
128 if (!rockit
&& levl
[u
.ux
][u
.uy
].typ
== CORR
) {
129 levl
[u
.ux
][u
.uy
].typ
= ROOM
;
131 levl
[u
.ux
][u
.uy
].waslit
= TRUE
;
132 newsym(u
.ux
, u
.uy
); /* in case player is invisible */
135 vision_full_recalc
= 1; /* everything changed */
138 /* When digging into location <x,y>, what are you actually digging into? */
147 return DIGTYP_UNDIGGABLE
;
148 ispick
= is_pick(otmp
);
149 if (!ispick
&& !is_axe(otmp
))
150 return DIGTYP_UNDIGGABLE
;
152 return ((ispick
&& sobj_at(STATUE
, x
, y
))
154 : (ispick
&& sobj_at(BOULDER
, x
, y
))
158 : IS_TREE(levl
[x
][y
].typ
)
159 ? (ispick
? DIGTYP_UNDIGGABLE
: DIGTYP_TREE
)
160 : (ispick
&& IS_ROCK(levl
[x
][y
].typ
)
161 && (!level
.flags
.arboreal
162 || IS_WALL(levl
[x
][y
].typ
)))
164 : DIGTYP_UNDIGGABLE
);
170 if (occupation
== dig
) {
176 #define BY_YOU (&youmonst)
177 #define BY_OBJECT ((struct monst *) 0)
180 dig_check(madeby
, verbose
, x
, y
)
181 struct monst
*madeby
;
185 struct trap
*ttmp
= t_at(x
, y
);
187 (madeby
== BY_YOU
&& uwep
&& is_axe(uwep
)) ? "chop" : "dig in";
189 if (On_stairs(x
, y
)) {
190 if (x
== xdnladder
|| x
== xupladder
) {
192 pline_The("ladder resists your effort.");
194 pline_The("stairs are too hard to %s.", verb
);
196 } else if (IS_THRONE(levl
[x
][y
].typ
) && madeby
!= BY_OBJECT
) {
198 pline_The("throne is too hard to break apart.");
200 } else if (IS_ALTAR(levl
[x
][y
].typ
)
201 && (madeby
!= BY_OBJECT
|| Is_astralevel(&u
.uz
)
202 || Is_sanctum(&u
.uz
))) {
204 pline_The("altar is too hard to break apart.");
206 } else if (Is_airlevel(&u
.uz
)) {
208 You("cannot %s thin air.", verb
);
210 } else if (Is_waterlevel(&u
.uz
)) {
212 pline_The("%s splashes and subsides.", hliquid("water"));
214 } else if ((IS_ROCK(levl
[x
][y
].typ
) && levl
[x
][y
].typ
!= SDOOR
215 && (levl
[x
][y
].wall_info
& W_NONDIGGABLE
) != 0)
217 && (ttmp
->ttyp
== MAGIC_PORTAL
218 || ttmp
->ttyp
== VIBRATING_SQUARE
219 || (!Can_dig_down(&u
.uz
) && !levl
[x
][y
].candig
)))) {
221 pline_The("%s here is too hard to %s.", surface(x
, y
), verb
);
223 } else if (sobj_at(BOULDER
, x
, y
)) {
225 There("isn't enough room to %s here.", verb
);
227 } else if (madeby
== BY_OBJECT
228 /* the block against existing traps is mainly to
229 prevent broken wands from turning holes into pits */
230 && (ttmp
|| is_pool_or_lava(x
, y
))) {
231 /* digging by player handles pools separately */
240 register struct rm
*lev
;
241 register xchar dpx
= context
.digging
.pos
.x
, dpy
= context
.digging
.pos
.y
;
242 register boolean ispick
= uwep
&& is_pick(uwep
);
243 const char *verb
= (!uwep
|| is_pick(uwep
)) ? "dig into" : "chop through";
245 lev
= &levl
[dpx
][dpy
];
246 /* perhaps a nymph stole your pick-axe while you were busy digging */
247 /* or perhaps you teleported away */
248 if (u
.uswallow
|| !uwep
|| (!ispick
&& !is_axe(uwep
))
249 || !on_level(&context
.digging
.level
, &u
.uz
)
250 || ((context
.digging
.down
? (dpx
!= u
.ux
|| dpy
!= u
.uy
)
251 : (distu(dpx
, dpy
) > 2))))
254 if (context
.digging
.down
) {
255 if (!dig_check(BY_YOU
, TRUE
, u
.ux
, u
.uy
))
257 } else { /* !context.digging.down */
258 if (IS_TREE(lev
->typ
) && !may_dig(dpx
, dpy
)
259 && dig_typ(uwep
, dpx
, dpy
) == DIGTYP_TREE
) {
260 pline("This tree seems to be petrified.");
263 if (IS_ROCK(lev
->typ
) && !may_dig(dpx
, dpy
)
264 && dig_typ(uwep
, dpx
, dpy
) == DIGTYP_ROCK
) {
265 pline("This %s is too hard to %s.",
266 is_db_wall(dpx
, dpy
) ? "drawbridge" : "wall", verb
);
270 if (Fumbling
&& !rn2(3)) {
274 You("fumble and drop %s.", yname(uwep
));
278 pline("%s and %s %s!", Yobjnam2(uwep
, "bounce"),
279 otense(uwep
, "hit"), mon_nam(u
.usteed
));
281 pline("Ouch! %s and %s you!", Yobjnam2(uwep
, "bounce"),
282 otense(uwep
, "hit"));
283 set_wounded_legs(RIGHT_SIDE
, 5 + rnd(5));
287 pline("Bang! You hit with the broad side of %s!",
291 Your("swing misses its mark.");
297 context
.digging
.effort
+=
298 10 + rn2(5) + abon() + uwep
->spe
- greatest_erosion(uwep
) + u
.udaminc
;
299 if (Race_if(PM_DWARF
))
300 context
.digging
.effort
*= 2;
301 if (context
.digging
.down
) {
302 struct trap
*ttmp
= t_at(dpx
, dpy
);
304 if (context
.digging
.effort
> 250 || (ttmp
&& ttmp
->ttyp
== HOLE
)) {
305 (void) dighole(FALSE
, FALSE
, (coord
*) 0);
306 (void) memset((genericptr_t
) &context
.digging
, 0,
307 sizeof context
.digging
);
308 return 0; /* done with digging */
311 if (context
.digging
.effort
<= 50
312 || (ttmp
&& (ttmp
->ttyp
== TRAPDOOR
|| ttmp
->ttyp
== PIT
313 || ttmp
->ttyp
== SPIKED_PIT
))) {
315 } else if (ttmp
&& (ttmp
->ttyp
== LANDMINE
316 || (ttmp
->ttyp
== BEAR_TRAP
&& !u
.utrap
))) {
317 /* digging onto a set object trap triggers it;
318 hero should have used #untrap first */
319 dotrap(ttmp
, FORCETRAP
);
320 /* restart completely from scratch if we resume digging */
321 (void) memset((genericptr_t
) &context
.digging
, 0,
322 sizeof context
.digging
);
324 } else if (ttmp
&& ttmp
->ttyp
== BEAR_TRAP
&& u
.utrap
) {
325 if (rnl(7) > (Fumbling
? 1 : 4)) {
327 int dmg
= dmgval(uwep
, &youmonst
) + dbon();
333 You("hit yourself in the %s.", body_part(FOOT
));
334 Sprintf(kbuf
, "chopping off %s own %s", uhis(),
336 losehp(Maybe_Half_Phys(dmg
), kbuf
, KILLED_BY
);
338 You("destroy the bear trap with %s.",
339 yobjnam(uwep
, (const char *) 0));
340 u
.utrap
= 0; /* release from trap */
343 /* we haven't made any progress toward a pit yet */
344 context
.digging
.effort
= 0;
348 if (IS_ALTAR(lev
->typ
)) {
349 altar_wrath(dpx
, dpy
);
353 /* make pit at <u.ux,u.uy> */
354 if (dighole(TRUE
, FALSE
, (coord
*) 0)) {
355 context
.digging
.level
.dnum
= 0;
356 context
.digging
.level
.dlevel
= -1;
361 if (context
.digging
.effort
> 100) {
362 register const char *digtxt
, *dmgtxt
= (const char *) 0;
363 register struct obj
*obj
;
364 register boolean shopedge
= *in_rooms(dpx
, dpy
, SHOPBASE
);
366 if ((obj
= sobj_at(STATUE
, dpx
, dpy
)) != 0) {
367 if (break_statue(obj
))
368 digtxt
= "The statue shatters.";
370 /* it was a statue trap; break_statue()
371 * printed a message and updated the screen
374 } else if ((obj
= sobj_at(BOULDER
, dpx
, dpy
)) != 0) {
378 if ((bobj
= sobj_at(BOULDER
, dpx
, dpy
)) != 0) {
379 /* another boulder here, restack it to the top */
380 obj_extract_self(bobj
);
381 place_object(bobj
, dpx
, dpy
);
383 digtxt
= "The boulder falls apart.";
384 } else if (lev
->typ
== STONE
|| lev
->typ
== SCORR
385 || IS_TREE(lev
->typ
)) {
386 if (Is_earthlevel(&u
.uz
)) {
387 if (uwep
->blessed
&& !rn2(3)) {
390 } else if ((uwep
->cursed
&& !rn2(4))
391 || (!uwep
->blessed
&& !rn2(6))) {
396 if (IS_TREE(lev
->typ
)) {
397 digtxt
= "You cut down the tree.";
400 (void) rnd_treefruit_at(dpx
, dpy
);
402 digtxt
= "You succeed in cutting away some rock.";
405 } else if (IS_WALL(lev
->typ
)) {
407 add_damage(dpx
, dpy
, 10L * ACURRSTR
);
410 if (level
.flags
.is_maze_lev
) {
412 } else if (level
.flags
.is_cavernous_lev
&& !in_town(dpx
, dpy
)) {
416 lev
->doormask
= D_NODOOR
;
418 digtxt
= "You make an opening in the wall.";
419 } else if (lev
->typ
== SDOOR
) {
420 cvt_sdoor_to_door(lev
); /* ->typ = DOOR */
421 digtxt
= "You break through a secret door!";
422 if (!(lev
->doormask
& D_TRAPPED
))
423 lev
->doormask
= D_BROKEN
;
424 } else if (closed_door(dpx
, dpy
)) {
425 digtxt
= "You break through the door.";
427 add_damage(dpx
, dpy
, 400L);
430 if (!(lev
->doormask
& D_TRAPPED
))
431 lev
->doormask
= D_BROKEN
;
433 return 0; /* statue or boulder got taken */
435 if (!does_block(dpx
, dpy
, &levl
[dpx
][dpy
]))
436 unblock_point(dpx
, dpy
); /* vision: can see through */
437 feel_newsym(dpx
, dpy
);
438 if (digtxt
&& !context
.digging
.quiet
)
439 pline1(digtxt
); /* after newsym */
441 pay_for_damage(dmgtxt
, FALSE
);
443 if (Is_earthlevel(&u
.uz
) && !rn2(3)) {
444 register struct monst
*mtmp
;
448 mtmp
= makemon(&mons
[PM_EARTH_ELEMENTAL
], dpx
, dpy
,
452 mtmp
= makemon(&mons
[PM_XORN
], dpx
, dpy
, NO_MM_FLAGS
);
456 pline_The("debris from your digging comes to life!");
458 if (IS_DOOR(lev
->typ
) && (lev
->doormask
& D_TRAPPED
)) {
459 lev
->doormask
= D_NODOOR
;
460 b_trapped("door", 0);
464 context
.digging
.lastdigtime
= moves
;
465 context
.digging
.quiet
= FALSE
;
466 context
.digging
.level
.dnum
= 0;
467 context
.digging
.level
.dlevel
= -1;
469 } else { /* not enough effort has been spent yet */
470 static const char *const d_target
[6] = { "", "rock", "statue",
471 "boulder", "door", "tree" };
472 int dig_target
= dig_typ(uwep
, dpx
, dpy
);
474 if (IS_WALL(lev
->typ
) || dig_target
== DIGTYP_DOOR
) {
475 if (*in_rooms(dpx
, dpy
, SHOPBASE
)) {
476 pline("This %s seems too hard to %s.",
477 IS_DOOR(lev
->typ
) ? "door" : "wall", verb
);
480 } else if (dig_target
== DIGTYP_UNDIGGABLE
481 || (dig_target
== DIGTYP_ROCK
&& !IS_ROCK(lev
->typ
)))
482 return 0; /* statue or boulder got taken */
485 You("hit the %s with all your might.", d_target
[dig_target
]);
492 /* When will hole be finished? Very rough indication used by shopkeeper. */
496 if (occupation
!= dig
|| !*u
.ushops
)
498 return ((250 - context
.digging
.effort
) / 20);
501 /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */
503 fillholetyp(x
, y
, fill_if_any
)
505 boolean fill_if_any
; /* force filling if it exists at all */
508 int lo_x
= max(1, x
- 1), hi_x
= min(x
+ 1, COLNO
- 1),
509 lo_y
= max(0, y
- 1), hi_y
= min(y
+ 1, ROWNO
- 1);
510 int pool_cnt
= 0, moat_cnt
= 0, lava_cnt
= 0;
512 for (x1
= lo_x
; x1
<= hi_x
; x1
++)
513 for (y1
= lo_y
; y1
<= hi_y
; y1
++)
516 else if (is_pool(x1
, y1
))
517 /* This must come after is_moat since moats are pools
518 * but not vice-versa. */
520 else if (is_lava(x1
, y1
))
524 pool_cnt
/= 3; /* not as much liquid as the others */
526 if ((lava_cnt
> moat_cnt
+ pool_cnt
&& rn2(lava_cnt
+ 1))
527 || (lava_cnt
&& fill_if_any
))
529 else if ((moat_cnt
> 0 && rn2(moat_cnt
+ 1)) || (moat_cnt
&& fill_if_any
))
531 else if ((pool_cnt
> 0 && rn2(pool_cnt
+ 1)) || (pool_cnt
&& fill_if_any
))
538 digactualhole(x
, y
, madeby
, ttyp
)
540 struct monst
*madeby
;
543 struct obj
*oldobjs
, *newobjs
;
544 register struct trap
*ttmp
;
545 char surface_type
[BUFSZ
];
546 struct rm
*lev
= &levl
[x
][y
];
548 struct monst
*mtmp
= m_at(x
, y
); /* may be madeby */
549 boolean madeby_u
= (madeby
== BY_YOU
);
550 boolean madeby_obj
= (madeby
== BY_OBJECT
);
551 boolean at_u
= (x
== u
.ux
) && (y
== u
.uy
);
552 boolean wont_fall
= Levitation
|| Flying
;
554 if (at_u
&& u
.utrap
) {
555 if (u
.utraptype
== TT_BURIEDBALL
)
556 buried_ball_to_punishment();
557 else if (u
.utraptype
== TT_INFLOOR
)
561 /* these furniture checks were in dighole(), but wand
562 breaking bypasses that routine and calls us directly */
563 if (IS_FOUNTAIN(lev
->typ
)) {
565 SET_FOUNTAIN_WARNED(x
, y
); /* force dryup */
566 dryup(x
, y
, madeby_u
);
568 } else if (IS_SINK(lev
->typ
)) {
571 } else if (lev
->typ
== DRAWBRIDGE_DOWN
572 || (is_drawbridge_wall(x
, y
) >= 0)) {
574 /* if under the portcullis, the bridge is adjacent */
575 (void) find_drawbridge(&bx
, &by
);
576 destroy_drawbridge(bx
, by
);
580 if (ttyp
!= PIT
&& (!Can_dig_down(&u
.uz
) && !lev
->candig
)) {
581 impossible("digactualhole: can't dig %s on this level.",
582 defsyms
[trap_to_defsym(ttyp
)].explanation
);
586 /* maketrap() might change it, also, in this situation,
587 surface() returns an inappropriate string for a grave */
588 if (IS_GRAVE(lev
->typ
))
589 Strcpy(surface_type
, "grave");
591 Strcpy(surface_type
, surface(x
, y
));
592 shopdoor
= IS_DOOR(lev
->typ
) && *in_rooms(x
, y
, SHOPBASE
);
593 oldobjs
= level
.objects
[x
][y
];
594 ttmp
= maketrap(x
, y
, ttyp
);
597 newobjs
= level
.objects
[x
][y
];
598 ttmp
->madeby_u
= madeby_u
;
607 if (x
!= u
.ux
|| y
!= u
.uy
)
608 You("dig an adjacent pit.");
610 You("dig a pit in the %s.", surface_type
);
612 pay_for_damage("ruin", FALSE
);
613 } else if (!madeby_obj
&& canseemon(madeby
))
614 pline("%s digs a pit in the %s.", Monnam(madeby
), surface_type
);
615 else if (cansee(x
, y
) && flags
.verbose
)
616 pline("A pit appears in the %s.", surface_type
);
621 u
.utraptype
= TT_PIT
;
622 vision_full_recalc
= 1; /* vision limits change */
625 if (oldobjs
!= newobjs
) /* something unearthed */
626 (void) pickup(1); /* detects pit */
628 if (is_flyer(mtmp
->data
) || is_floater(mtmp
->data
)) {
630 pline("%s %s over the pit.", Monnam(mtmp
),
631 (is_flyer(mtmp
->data
)) ? "flies" : "floats");
632 } else if (mtmp
!= madeby
)
633 (void) mintrap(mtmp
);
635 } else { /* was TRAPDOOR now a HOLE*/
638 You("dig a hole through the %s.", surface_type
);
639 else if (!madeby_obj
&& canseemon(madeby
))
640 pline("%s digs a hole through the %s.", Monnam(madeby
),
642 else if (cansee(x
, y
) && flags
.verbose
)
643 pline("A hole appears in the %s.", surface_type
);
646 if (!u
.ustuck
&& !wont_fall
&& !next_to_u()) {
647 You("are jerked back by your pet!");
651 /* Floor objects get a chance of falling down. The case where
652 * the hero does NOT fall down is treated here. The case
653 * where the hero does fall down is treated in goto_level().
655 if (u
.ustuck
|| wont_fall
) {
657 impact_drop((struct obj
*) 0, x
, y
, 0);
658 if (oldobjs
!= newobjs
)
660 if (shopdoor
&& madeby_u
)
661 pay_for_damage("ruin", FALSE
);
666 if (*u
.ushops
&& madeby_u
)
667 shopdig(1); /* shk might snatch pack */
668 /* handle earlier damage, eg breaking wand of digging */
670 pay_for_damage("dig into", TRUE
);
672 You("fall through...");
673 /* Earlier checks must ensure that the destination
674 * level exists and is in the present dungeon.
676 newlevel
.dnum
= u
.uz
.dnum
;
677 newlevel
.dlevel
= u
.uz
.dlevel
+ 1;
678 goto_level(&newlevel
, FALSE
, TRUE
, FALSE
);
679 /* messages for arriving in special rooms */
683 if (shopdoor
&& madeby_u
)
684 pay_for_damage("ruin", FALSE
);
686 impact_drop((struct obj
*) 0, x
, y
, 0);
688 /*[don't we need special sokoban handling here?]*/
689 if (is_flyer(mtmp
->data
) || is_floater(mtmp
->data
)
690 || mtmp
->data
== &mons
[PM_WUMPUS
]
691 || (mtmp
->wormno
&& count_wsegs(mtmp
) > 5)
692 || mtmp
->data
->msize
>= MZ_HUGE
)
694 if (mtmp
== u
.ustuck
) /* probably a vortex */
695 return; /* temporary? kludge */
697 if (teleport_pet(mtmp
, FALSE
)) {
700 if (Is_stronghold(&u
.uz
)) {
701 assign_level(&tolevel
, &valley_level
);
702 } else if (Is_botlevel(&u
.uz
)) {
704 pline("%s avoids the trap.", Monnam(mtmp
));
707 get_level(&tolevel
, depth(&u
.uz
) + 1);
710 make_angry_shk(mtmp
, 0, 0);
711 migrate_to_level(mtmp
, ledger_no(&tolevel
), MIGR_RANDOM
,
720 * Called from dighole(), but also from do_break_wand()
724 liquid_flow(x
, y
, typ
, ttmp
, fillmsg
)
730 boolean u_spot
= (x
== u
.ux
&& y
== u
.uy
);
733 (void) delfloortrap(ttmp
);
734 /* if any objects were frozen here, they're released now */
738 pline(fillmsg
, hliquid(typ
== LAVAPOOL
? "lava" : "water"));
739 if (u_spot
&& !(Levitation
|| Flying
)) {
741 (void) lava_effects();
747 /* return TRUE if digging succeeded, FALSE otherwise */
749 dighole(pit_only
, by_magic
, cc
)
750 boolean pit_only
, by_magic
;
753 register struct trap
*ttmp
;
755 struct obj
*boulder_here
;
766 if (!isok(dig_x
, dig_y
))
770 ttmp
= t_at(dig_x
, dig_y
);
771 lev
= &levl
[dig_x
][dig_y
];
772 nohole
= (!Can_dig_down(&u
.uz
) && !lev
->candig
);
774 if ((ttmp
&& (ttmp
->ttyp
== MAGIC_PORTAL
775 || ttmp
->ttyp
== VIBRATING_SQUARE
|| nohole
))
776 || (IS_ROCK(lev
->typ
) && lev
->typ
!= SDOOR
777 && (lev
->wall_info
& W_NONDIGGABLE
) != 0)) {
778 pline_The("%s %shere is too hard to dig in.", surface(dig_x
, dig_y
),
779 (dig_x
!= u
.ux
|| dig_y
!= u
.uy
) ? "t" : "");
781 } else if (is_pool_or_lava(dig_x
, dig_y
)) {
782 pline_The("%s sloshes furiously for a moment, then subsides.",
783 hliquid(is_lava(dig_x
, dig_y
) ? "lava" : "water"));
784 wake_nearby(); /* splashing */
786 } else if (lev
->typ
== DRAWBRIDGE_DOWN
787 || (is_drawbridge_wall(dig_x
, dig_y
) >= 0)) {
788 /* drawbridge_down is the platform crossing the moat when the
789 bridge is extended; drawbridge_wall is the open "doorway" or
790 closed "door" where the portcullis/mechanism is located */
792 pline_The("drawbridge seems too hard to dig through.");
795 int x
= dig_x
, y
= dig_y
;
796 /* if under the portcullis, the bridge is adjacent */
797 (void) find_drawbridge(&x
, &y
);
798 destroy_drawbridge(x
, y
);
802 } else if ((boulder_here
= sobj_at(BOULDER
, dig_x
, dig_y
)) != 0) {
803 if (ttmp
&& (ttmp
->ttyp
== PIT
|| ttmp
->ttyp
== SPIKED_PIT
)
805 pline_The("boulder settles into the %spit.",
806 (dig_x
!= u
.ux
|| dig_y
!= u
.uy
) ? "adjacent " : "");
807 ttmp
->ttyp
= PIT
; /* crush spikes */
810 * digging makes a hole, but the boulder immediately
811 * fills it. Final outcome: no hole, no boulder.
813 pline("KADOOM! The boulder falls in!");
814 (void) delfloortrap(ttmp
);
816 delobj(boulder_here
);
819 } else if (IS_GRAVE(lev
->typ
)) {
820 digactualhole(dig_x
, dig_y
, BY_YOU
, PIT
);
823 } else if (lev
->typ
== DRAWBRIDGE_UP
) {
824 /* must be floor or ice, other cases handled above */
825 /* dig "pit" and let fluid flow in (if possible) */
826 typ
= fillholetyp(dig_x
, dig_y
, FALSE
);
830 * We can't dig a hole here since that will destroy
831 * the drawbridge. The following is a cop-out. --dlc
833 pline_The("%s %shere is too hard to dig in.",
834 surface(dig_x
, dig_y
),
835 (dig_x
!= u
.ux
|| dig_y
!= u
.uy
) ? "t" : "");
839 lev
->drawbridgemask
&= ~DB_UNDER
;
840 lev
->drawbridgemask
|= (typ
== LAVAPOOL
) ? DB_LAVA
: DB_MOAT
;
841 liquid_flow(dig_x
, dig_y
, typ
, ttmp
,
842 "As you dig, the hole fills with %s!");
845 /* the following two are here for the wand of digging */
846 } else if (IS_THRONE(lev
->typ
)) {
847 pline_The("throne is too hard to break apart.");
849 } else if (IS_ALTAR(lev
->typ
)) {
850 pline_The("altar is too hard to break apart.");
853 typ
= fillholetyp(dig_x
, dig_y
, FALSE
);
857 liquid_flow(dig_x
, dig_y
, typ
, ttmp
,
858 "As you dig, the hole fills with %s!");
862 /* magical digging disarms settable traps */
864 && (ttmp
->ttyp
== LANDMINE
|| ttmp
->ttyp
== BEAR_TRAP
)) {
865 int otyp
= (ttmp
->ttyp
== LANDMINE
) ? LAND_MINE
: BEARTRAP
;
867 /* convert trap into buried object (deletes trap) */
868 cnv_trap_obj(otyp
, 1, ttmp
, TRUE
);
871 /* finally we get to make a hole */
872 if (nohole
|| pit_only
)
873 digactualhole(dig_x
, dig_y
, BY_YOU
, PIT
);
875 digactualhole(dig_x
, dig_y
, BY_YOU
, HOLE
);
896 if (!isok(dig_x
, dig_y
))
900 /* Grave-robbing is frowned upon... */
901 exercise(A_WIS
, FALSE
);
902 if (Role_if(PM_ARCHEOLOGIST
)) {
903 adjalign(-sgn(u
.ualign
.type
) * 3);
904 You_feel("like a despicable grave-robber!");
905 } else if (Role_if(PM_SAMURAI
)) {
906 adjalign(-sgn(u
.ualign
.type
));
907 You("disturb the honorable dead!");
908 } else if ((u
.ualign
.type
== A_LAWFUL
) && (u
.ualign
.record
> -10)) {
909 adjalign(-sgn(u
.ualign
.type
));
910 You("have violated the sanctity of this grave!");
916 You("unearth a corpse.");
917 if (!!(otmp
= mk_tt_object(CORPSE
, dig_x
, dig_y
)))
918 otmp
->age
-= 100; /* this is an *OLD* corpse */
923 pline(Hallucination
? "Dude! The living dead!"
924 : "The grave's owner is very upset!");
925 (void) makemon(mkclass(S_ZOMBIE
, 0), dig_x
, dig_y
, NO_MM_FLAGS
);
929 pline(Hallucination
? "I want my mummy!"
930 : "You've disturbed a tomb!");
931 (void) makemon(mkclass(S_MUMMY
, 0), dig_x
, dig_y
, NO_MM_FLAGS
);
935 pline_The("grave seems unused. Strange....");
938 levl
[dig_x
][dig_y
].typ
= ROOM
;
939 del_engr_at(dig_x
, dig_y
);
940 newsym(dig_x
, dig_y
);
948 const char *sdp
, *verb
;
949 char *dsp
, dirsyms
[12], qbuf
[BUFSZ
];
951 int rx
, ry
, downok
, res
= 0;
955 if (!wield_tool(obj
, "swing"))
960 ispick
= is_pick(obj
);
961 verb
= ispick
? "dig" : "chop";
963 if (u
.utrap
&& u
.utraptype
== TT_WEB
) {
964 pline("%s you can't %s while entangled in a web.",
965 /* res==0 => no prior message;
966 res==1 => just got "You now wield a pick-axe." message */
967 !res
? "Unfortunately," : "But", verb
);
971 /* construct list of directions to show player for likely choices */
972 downok
= !!can_reach_floor(FALSE
);
974 for (sdp
= Cmd
.dirchars
; *sdp
; ++sdp
) {
975 /* filter out useless directions */
977 ; /* all directions are viable when swallowed */
978 } else if (movecmd(*sdp
)) {
979 /* normal direction, within plane of the level map;
980 movecmd() sets u.dx, u.dy, u.dz and returns !u.dz */
982 continue; /* handle NODIAG */
985 if (!isok(rx
, ry
) || dig_typ(obj
, rx
, ry
) == DIGTYP_UNDIGGABLE
)
988 /* up or down; we used to always include down, so that
989 there would always be at least one choice shown, but
990 it shouldn't be a likely candidate when floating high
991 above the floor; include up instead in that situation
992 (as a silly candidate rather than a likely one...) */
993 if ((u
.dz
> 0) ^ downok
)
996 /* include this direction */
1000 Sprintf(qbuf
, "In what direction do you want to %s? [%s]", verb
, dirsyms
);
1004 return use_pick_axe2(obj
);
1007 /* MRKR: use_pick_axe() is split in two to allow autodig to bypass */
1008 /* the "In what direction do you want to dig?" query. */
1009 /* use_pick_axe2() uses the existing u.dx, u.dy and u.dz */
1014 register int rx
, ry
;
1015 register struct rm
*lev
;
1016 struct trap
*trap
, *trap_with_u
;
1018 boolean ispick
= is_pick(obj
);
1019 const char *verbing
= ispick
? "digging" : "chopping";
1021 if (u
.uswallow
&& attack(u
.ustuck
)) {
1023 } else if (Underwater
) {
1024 pline("Turbulence torpedoes your %s attempts.", verbing
);
1025 } else if (u
.dz
< 0) {
1027 You("don't have enough leverage.");
1029 You_cant("reach the %s.", ceiling(u
.ux
, u
.uy
));
1030 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1034 dam
= rnd(2) + dbon() + obj
->spe
;
1037 You("hit yourself with %s.", yname(uwep
));
1038 Sprintf(buf
, "%s own %s", uhis(), OBJ_NAME(objects
[obj
->otyp
]));
1039 losehp(Maybe_Half_Phys(dam
), buf
, KILLED_BY
);
1042 } else if (u
.dz
== 0) {
1043 if (Stunned
|| (Confusion
&& !rn2(5)))
1047 if (!isok(rx
, ry
)) {
1051 lev
= &levl
[rx
][ry
];
1052 if (MON_AT(rx
, ry
) && attack(m_at(rx
, ry
)))
1054 dig_target
= dig_typ(obj
, rx
, ry
);
1055 if (dig_target
== DIGTYP_UNDIGGABLE
) {
1056 /* ACCESSIBLE or POOL */
1057 trap
= t_at(rx
, ry
);
1058 if (trap
&& trap
->ttyp
== WEB
) {
1061 There("is a spider web there!");
1063 pline("%s entangled in the web.", Yobjnam2(obj
, "become"));
1064 /* you ought to be able to let go; tough luck */
1065 /* (maybe `move_into_trap()' would be better) */
1067 multi_reason
= "stuck in a spider web";
1068 nomovemsg
= "You pull free.";
1069 } else if (lev
->typ
== IRONBARS
) {
1072 } else if (IS_TREE(lev
->typ
))
1073 You("need an axe to cut down a tree.");
1074 else if (IS_ROCK(lev
->typ
))
1075 You("need a pick to dig rock.");
1076 else if (!ispick
&& (sobj_at(STATUE
, rx
, ry
)
1077 || sobj_at(BOULDER
, rx
, ry
))) {
1078 boolean vibrate
= !rn2(3);
1079 pline("Sparks fly as you whack the %s.%s",
1080 sobj_at(STATUE
, rx
, ry
) ? "statue" : "boulder",
1081 vibrate
? " The axe-handle vibrates violently!" : "");
1083 losehp(Maybe_Half_Phys(2), "axing a hard object",
1085 } else if (u
.utrap
&& u
.utraptype
== TT_PIT
&& trap
1086 && (trap_with_u
= t_at(u
.ux
, u
.uy
))
1087 && (trap
->ttyp
== PIT
|| trap
->ttyp
== SPIKED_PIT
)
1088 && !conjoined_pits(trap
, trap_with_u
, FALSE
)) {
1090 for (idx
= 0; idx
< 8; idx
++) {
1091 if (xdir
[idx
] == u
.dx
&& ydir
[idx
] == u
.dy
)
1094 /* idx is valid if < 8 */
1096 int adjidx
= (idx
+ 4) % 8;
1097 trap_with_u
->conjoined
|= (1 << idx
);
1098 trap
->conjoined
|= (1 << adjidx
);
1099 pline("You clear some debris from between the pits.");
1101 } else if (u
.utrap
&& u
.utraptype
== TT_PIT
1102 && (trap_with_u
= t_at(u
.ux
, u
.uy
))) {
1103 You("swing %s, but the rubble has no place to go.",
1104 yobjnam(obj
, (char *) 0));
1106 You("swing %s through thin air.", yobjnam(obj
, (char *) 0));
1108 static const char *const d_action
[6] = { "swinging", "digging",
1109 "chipping the statue",
1110 "hitting the boulder",
1111 "chopping at the door",
1112 "cutting the tree" };
1113 did_dig_msg
= FALSE
;
1114 context
.digging
.quiet
= FALSE
;
1115 if (context
.digging
.pos
.x
!= rx
|| context
.digging
.pos
.y
!= ry
1116 || !on_level(&context
.digging
.level
, &u
.uz
)
1117 || context
.digging
.down
) {
1118 if (flags
.autodig
&& dig_target
== DIGTYP_ROCK
1119 && !context
.digging
.down
&& context
.digging
.pos
.x
== u
.ux
1120 && context
.digging
.pos
.y
== u
.uy
1121 && (moves
<= context
.digging
.lastdigtime
+ 2
1122 && moves
>= context
.digging
.lastdigtime
)) {
1123 /* avoid messages if repeated autodigging */
1125 context
.digging
.quiet
= TRUE
;
1127 context
.digging
.down
= context
.digging
.chew
= FALSE
;
1128 context
.digging
.warned
= FALSE
;
1129 context
.digging
.pos
.x
= rx
;
1130 context
.digging
.pos
.y
= ry
;
1131 assign_level(&context
.digging
.level
, &u
.uz
);
1132 context
.digging
.effort
= 0;
1133 if (!context
.digging
.quiet
)
1134 You("start %s.", d_action
[dig_target
]);
1136 You("%s %s.", context
.digging
.chew
? "begin" : "continue",
1137 d_action
[dig_target
]);
1138 context
.digging
.chew
= FALSE
;
1140 set_occupation(dig
, verbing
, 0);
1142 } else if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)) {
1143 /* it must be air -- water checked above */
1144 You("swing %s through thin air.", yobjnam(obj
, (char *) 0));
1145 } else if (!can_reach_floor(FALSE
)) {
1146 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, FALSE
);
1147 } else if (is_pool_or_lava(u
.ux
, u
.uy
)) {
1148 /* Monsters which swim also happen not to be able to dig */
1149 You("cannot stay under%s long enough.",
1150 is_pool(u
.ux
, u
.uy
) ? "water" : " the lava");
1151 } else if ((trap
= t_at(u
.ux
, u
.uy
)) != 0
1152 && uteetering_at_seen_pit(trap
)) {
1153 dotrap(trap
, FORCEBUNGLE
);
1154 /* might escape trap and still be teetering at brink */
1156 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
1158 /* can only dig down with an axe when doing so will
1159 trigger or disarm a trap here */
1160 && (!trap
|| (trap
->ttyp
!= LANDMINE
1161 && trap
->ttyp
!= BEAR_TRAP
))) {
1162 pline("%s merely scratches the %s.", Yobjnam2(obj
, (char *) 0),
1163 surface(u
.ux
, u
.uy
));
1166 if (context
.digging
.pos
.x
!= u
.ux
|| context
.digging
.pos
.y
!= u
.uy
1167 || !on_level(&context
.digging
.level
, &u
.uz
)
1168 || !context
.digging
.down
) {
1169 context
.digging
.chew
= FALSE
;
1170 context
.digging
.down
= TRUE
;
1171 context
.digging
.warned
= FALSE
;
1172 context
.digging
.pos
.x
= u
.ux
;
1173 context
.digging
.pos
.y
= u
.uy
;
1174 assign_level(&context
.digging
.level
, &u
.uz
);
1175 context
.digging
.effort
= 0;
1176 You("start %s downward.", verbing
);
1180 You("continue %s downward.", verbing
);
1181 did_dig_msg
= FALSE
;
1182 set_occupation(dig
, verbing
, 0);
1188 * Town Watchmen frown on damage to the town walls, trees or fountains.
1189 * It's OK to dig holes in the ground, however.
1190 * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0
1191 * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing)
1194 watch_dig(mtmp
, x
, y
, zap
)
1199 struct rm
*lev
= &levl
[x
][y
];
1202 && (closed_door(x
, y
) || lev
->typ
== SDOOR
|| IS_WALL(lev
->typ
)
1203 || IS_FOUNTAIN(lev
->typ
) || IS_TREE(lev
->typ
))) {
1205 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
1206 if (DEADMONSTER(mtmp
))
1208 if (is_watch(mtmp
->data
) && mtmp
->mcansee
&& m_canseeu(mtmp
)
1209 && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mpeaceful
)
1215 if (zap
|| context
.digging
.warned
) {
1216 verbalize("Halt, vandal! You're under arrest!");
1217 (void) angry_guards(!!Deaf
);
1221 if (IS_DOOR(lev
->typ
))
1223 else if (IS_TREE(lev
->typ
))
1225 else if (IS_ROCK(lev
->typ
))
1229 verbalize("Hey, stop damaging that %s!", str
);
1230 context
.digging
.warned
= TRUE
;
1238 /* Return TRUE if monster died, FALSE otherwise. Called from m_move(). */
1241 register struct monst
*mtmp
;
1243 register struct rm
*here
;
1246 here
= &levl
[mtmp
->mx
][mtmp
->my
];
1247 if (here
->typ
== SDOOR
)
1248 cvt_sdoor_to_door(here
); /* ->typ = DOOR */
1250 /* Eats away door if present & closed or locked */
1251 if (closed_door(mtmp
->mx
, mtmp
->my
)) {
1252 if (*in_rooms(mtmp
->mx
, mtmp
->my
, SHOPBASE
))
1253 add_damage(mtmp
->mx
, mtmp
->my
, 0L);
1254 unblock_point(mtmp
->mx
, mtmp
->my
); /* vision */
1255 if (here
->doormask
& D_TRAPPED
) {
1256 here
->doormask
= D_NODOOR
;
1257 if (mb_trapped(mtmp
)) { /* mtmp is killed */
1258 newsym(mtmp
->mx
, mtmp
->my
);
1262 if (!rn2(3) && flags
.verbose
) /* not too often.. */
1263 draft_message(TRUE
); /* "You feel an unexpected draft." */
1264 here
->doormask
= D_BROKEN
;
1266 newsym(mtmp
->mx
, mtmp
->my
);
1268 } else if (here
->typ
== SCORR
) {
1270 unblock_point(mtmp
->mx
, mtmp
->my
);
1271 newsym(mtmp
->mx
, mtmp
->my
);
1272 draft_message(FALSE
); /* "You feel a draft." */
1274 } else if (!IS_ROCK(here
->typ
) && !IS_TREE(here
->typ
)) /* no dig */
1277 /* Only rock, trees, and walls fall through to this point. */
1278 if ((here
->wall_info
& W_NONDIGGABLE
) != 0) {
1279 impossible("mdig_tunnel: %s at (%d,%d) is undiggable",
1280 (IS_WALL(here
->typ
) ? "wall"
1281 : IS_TREE(here
->typ
) ? "tree" : "stone"),
1282 (int) mtmp
->mx
, (int) mtmp
->my
);
1283 return FALSE
; /* still alive */
1286 if (IS_WALL(here
->typ
)) {
1287 /* KMH -- Okay on arboreal levels (room walls are still stone) */
1288 if (flags
.verbose
&& !rn2(5))
1289 You_hear("crashing rock.");
1290 if (*in_rooms(mtmp
->mx
, mtmp
->my
, SHOPBASE
))
1291 add_damage(mtmp
->mx
, mtmp
->my
, 0L);
1292 if (level
.flags
.is_maze_lev
) {
1294 } else if (level
.flags
.is_cavernous_lev
1295 && !in_town(mtmp
->mx
, mtmp
->my
)) {
1299 here
->doormask
= D_NODOOR
;
1301 } else if (IS_TREE(here
->typ
)) {
1303 if (pile
&& pile
< 5)
1304 (void) rnd_treefruit_at(mtmp
->mx
, mtmp
->my
);
1307 if (pile
&& pile
< 5)
1308 (void) mksobj_at((pile
== 1) ? BOULDER
: ROCK
, mtmp
->mx
, mtmp
->my
,
1311 newsym(mtmp
->mx
, mtmp
->my
);
1312 if (!sobj_at(BOULDER
, mtmp
->mx
, mtmp
->my
))
1313 unblock_point(mtmp
->mx
, mtmp
->my
); /* vision */
1318 #define STRIDENT 4 /* from pray.c */
1320 /* draft refers to air currents, but can be a pun on "draft" as conscription
1321 for military service (probably not a good pun if it has to be explained) */
1323 draft_message(unexpected
)
1327 * [Bug or TODO? Have caller pass coordinates and use the travel
1328 * mechanism to determine whether there is a path between
1329 * destroyed door (or exposed secret corridor) and hero's location.
1330 * When there is no such path, no draft should be felt.]
1335 You_feel("an unexpected draft.");
1337 /* U.S. classification system uses 1-A for eligible to serve
1338 and 4-F for ineligible due to physical or mental defect;
1339 some intermediate values exist but are rarely seen */
1340 You_feel("like you are %s.",
1341 (ACURR(A_STR
) < 6 || ACURR(A_DEX
) < 6
1342 || ACURR(A_CON
) < 6 || ACURR(A_CHA
) < 6
1343 || ACURR(A_INT
) < 6 || ACURR(A_WIS
) < 6) ? "4-F"
1346 if (!Hallucination
) {
1347 You_feel("a draft.");
1349 /* "marching" is deliberately ambiguous; it might mean drills
1350 after entering military service or mean engaging in protests */
1351 static const char *draft_reaction
[] = {
1352 "enlisting", "marching", "protesting", "fleeing",
1356 /* Lawful: 0..1, Neutral: 1..2, Chaotic: 2..3 */
1357 dridx
= rn1(2, 1 - sgn(u
.ualign
.type
));
1358 if (u
.ualign
.record
< STRIDENT
)
1359 /* L: +(0..2), N: +(-1..1), C: +(-2..0); all: 0..3 */
1360 dridx
+= rn1(3, sgn(u
.ualign
.type
) - 1);
1361 You_feel("like %s.", draft_reaction
[dridx
]);
1366 /* digging via wand zap or spell cast */
1373 struct trap
*trap_with_u
= (struct trap
*) 0;
1374 int zx
, zy
, diridx
= 8, digdepth
, flow_x
= -1, flow_y
= -1;
1375 boolean shopdoor
, shopwall
, maze_dig
, pitdig
= FALSE
, pitflow
= FALSE
;
1378 * Original effect (approximately):
1379 * from CORR: dig until we pierce a wall
1380 * from ROOM: pierce wall and dig until we reach
1381 * an ACCESSIBLE place.
1382 * Currently: dig for digdepth positions;
1383 * also down on request of Lennart Augustsson.
1384 * 3.6.0: from a PIT: dig one adjacent pit.
1390 if (!is_whirly(mtmp
->data
)) {
1391 if (is_animal(mtmp
->data
))
1392 You("pierce %s %s wall!", s_suffix(mon_nam(mtmp
)),
1393 mbodypart(mtmp
, STOMACH
));
1394 mtmp
->mhp
= 1; /* almost dead */
1395 expels(mtmp
, mtmp
->data
, !is_animal(mtmp
->data
));
1401 if (!Is_airlevel(&u
.uz
) && !Is_waterlevel(&u
.uz
) && !Underwater
) {
1402 if (u
.dz
< 0 || On_stairs(u
.ux
, u
.uy
)) {
1404 if (On_stairs(u
.ux
, u
.uy
))
1405 pline_The("beam bounces off the %s and hits the %s.",
1406 (u
.ux
== xdnladder
|| u
.ux
== xupladder
)
1409 ceiling(u
.ux
, u
.uy
));
1410 You("loosen a rock from the %s.", ceiling(u
.ux
, u
.uy
));
1411 pline("It falls on your %s!", body_part(HEAD
));
1412 dmg
= rnd((uarmh
&& is_metallic(uarmh
)) ? 2 : 6);
1413 losehp(Maybe_Half_Phys(dmg
), "falling rock", KILLED_BY_AN
);
1414 otmp
= mksobj_at(ROCK
, u
.ux
, u
.uy
, FALSE
, FALSE
);
1416 (void) xname(otmp
); /* set dknown, maybe bknown */
1421 watch_dig((struct monst
*) 0, u
.ux
, u
.uy
, TRUE
);
1422 (void) dighole(FALSE
, TRUE
, (coord
*) 0);
1428 /* normal case: digging across the level */
1429 shopdoor
= shopwall
= FALSE
;
1430 maze_dig
= level
.flags
.is_maze_lev
&& !Is_earthlevel(&u
.uz
);
1433 if (u
.utrap
&& u
.utraptype
== TT_PIT
1434 && (trap_with_u
= t_at(u
.ux
, u
.uy
))) {
1436 for (diridx
= 0; diridx
< 8; diridx
++) {
1437 if (xdir
[diridx
] == u
.dx
&& ydir
[diridx
] == u
.dy
)
1439 /* diridx is valid if < 8 */
1442 digdepth
= rn1(18, 8);
1443 tmp_at(DISP_BEAM
, cmap_to_glyph(S_digbeam
));
1444 while (--digdepth
>= 0) {
1447 room
= &levl
[zx
][zy
];
1449 delay_output(); /* wait a little bit */
1451 if (pitdig
) { /* we are already in a pit if this is true */
1453 struct trap
*adjpit
= t_at(zx
, zy
);
1454 if ((diridx
< 8) && !conjoined_pits(adjpit
, trap_with_u
, FALSE
)) {
1455 digdepth
= 0; /* limited to the adjacent location only */
1456 if (!(adjpit
&& (adjpit
->ttyp
== PIT
1457 || adjpit
->ttyp
== SPIKED_PIT
))) {
1461 if (!adj_pit_checks(&cc
, buf
)) {
1465 /* this can also result in a pool at zx,zy */
1466 dighole(TRUE
, TRUE
, &cc
);
1467 adjpit
= t_at(zx
, zy
);
1471 && (adjpit
->ttyp
== PIT
|| adjpit
->ttyp
== SPIKED_PIT
)) {
1472 int adjidx
= (diridx
+ 4) % 8;
1473 trap_with_u
->conjoined
|= (1 << diridx
);
1474 adjpit
->conjoined
|= (1 << adjidx
);
1479 if (is_pool(zx
, zy
) || is_lava(zx
, zy
)) {
1486 } else if (closed_door(zx
, zy
) || room
->typ
== SDOOR
) {
1487 if (*in_rooms(zx
, zy
, SHOPBASE
)) {
1488 add_damage(zx
, zy
, 400L);
1491 if (room
->typ
== SDOOR
)
1493 else if (cansee(zx
, zy
))
1494 pline_The("door is razed!");
1495 watch_dig((struct monst
*) 0, zx
, zy
, TRUE
);
1496 room
->doormask
= D_NODOOR
;
1497 unblock_point(zx
, zy
); /* vision */
1501 } else if (maze_dig
) {
1502 if (IS_WALL(room
->typ
)) {
1503 if (!(room
->wall_info
& W_NONDIGGABLE
)) {
1504 if (*in_rooms(zx
, zy
, SHOPBASE
)) {
1505 add_damage(zx
, zy
, 200L);
1509 unblock_point(zx
, zy
); /* vision */
1511 pline_The("wall glows then fades.");
1513 } else if (IS_TREE(room
->typ
)) { /* check trees before stone */
1514 if (!(room
->wall_info
& W_NONDIGGABLE
)) {
1516 unblock_point(zx
, zy
); /* vision */
1518 pline_The("tree shudders but is unharmed.");
1520 } else if (room
->typ
== STONE
|| room
->typ
== SCORR
) {
1521 if (!(room
->wall_info
& W_NONDIGGABLE
)) {
1523 unblock_point(zx
, zy
); /* vision */
1525 pline_The("rock glows then fades.");
1528 } else if (IS_ROCK(room
->typ
)) {
1529 if (!may_dig(zx
, zy
))
1531 if (IS_WALL(room
->typ
) || room
->typ
== SDOOR
) {
1532 if (*in_rooms(zx
, zy
, SHOPBASE
)) {
1533 add_damage(zx
, zy
, 200L);
1536 watch_dig((struct monst
*) 0, zx
, zy
, TRUE
);
1537 if (level
.flags
.is_cavernous_lev
&& !in_town(zx
, zy
)) {
1541 room
->doormask
= D_NODOOR
;
1544 } else if (IS_TREE(room
->typ
)) {
1547 } else { /* IS_ROCK but not IS_WALL or SDOOR */
1551 unblock_point(zx
, zy
); /* vision */
1556 tmp_at(DISP_END
, 0); /* closing call */
1558 if (pitflow
&& isok(flow_x
, flow_y
)) {
1559 struct trap
*ttmp
= t_at(flow_x
, flow_y
);
1560 if (ttmp
&& (ttmp
->ttyp
== PIT
|| ttmp
->ttyp
== SPIKED_PIT
)) {
1561 schar filltyp
= fillholetyp(ttmp
->tx
, ttmp
->ty
, TRUE
);
1562 if (filltyp
!= ROOM
)
1563 pit_flow(ttmp
, filltyp
);
1567 if (shopdoor
|| shopwall
)
1568 pay_for_damage(shopdoor
? "destroy" : "dig into", FALSE
);
1573 * This checks what is on the surface above the
1574 * location where an adjacent pit might be created if
1575 * you're zapping a wand of digging laterally while
1579 adj_pit_checks(cc
, msg
)
1585 const char *foundation_msg
=
1586 "The foundation is too hard to dig through from this angle.";
1590 if (!isok(cc
->x
, cc
->y
))
1593 room
= &levl
[cc
->x
][cc
->y
];
1596 if (is_pool(cc
->x
, cc
->y
) || is_lava(cc
->x
, cc
->y
)) {
1597 /* this is handled by the caller after we return FALSE */
1599 } else if (closed_door(cc
->x
, cc
->y
) || room
->typ
== SDOOR
) {
1600 /* We reject this here because dighole() isn't
1601 prepared to deal with this case */
1602 Strcpy(msg
, foundation_msg
);
1604 } else if (IS_WALL(ltyp
)) {
1605 /* if (room->wall_info & W_NONDIGGABLE) */
1606 Strcpy(msg
, foundation_msg
);
1608 } else if (IS_TREE(ltyp
)) { /* check trees before stone */
1609 /* if (room->wall_info & W_NONDIGGABLE) */
1610 Strcpy(msg
, "The tree's roots glow then fade.");
1612 } else if (ltyp
== STONE
|| ltyp
== SCORR
) {
1613 if (room
->wall_info
& W_NONDIGGABLE
) {
1614 Strcpy(msg
, "The rock glows then fades.");
1617 } else if (ltyp
== IRONBARS
) {
1618 /* "set of iron bars" */
1619 Strcpy(msg
, "The bars go much deeper than your pit.");
1621 } else if (is_lava(cc
->x
, cc
->y
)) {
1622 } else if (is_ice(cc
->x
, cc
->y
)) {
1623 } else if (is_pool(cc
->x
, cc
->y
)) {
1624 } else if (IS_GRAVE(ltyp
)) {
1626 } else if (IS_SINK(ltyp
)) {
1627 Strcpy(msg
, "A tangled mass of plumbing remains below the sink.");
1629 } else if ((cc
->x
== xupladder
&& cc
->y
== yupladder
) /* ladder up */
1630 || (cc
->x
== xdnladder
&& cc
->y
== ydnladder
)) { /* " down */
1631 Strcpy(msg
, "The ladder is unaffected.");
1634 const char *supporting
= (const char *) 0;
1636 if (IS_FOUNTAIN(ltyp
))
1637 supporting
= "fountain";
1638 else if (IS_THRONE(ltyp
))
1639 supporting
= "throne";
1640 else if (IS_ALTAR(ltyp
))
1641 supporting
= "altar";
1642 else if ((cc
->x
== xupstair
&& cc
->y
== yupstair
)
1643 || (cc
->x
== sstairs
.sx
&& cc
->y
== sstairs
.sy
1645 /* "staircase up" */
1646 supporting
= "stairs";
1647 else if ((cc
->x
== xdnstair
&& cc
->y
== ydnstair
)
1648 || (cc
->x
== sstairs
.sx
&& cc
->y
== sstairs
.sy
1650 /* "staircase down" */
1651 supporting
= "stairs";
1652 else if (ltyp
== DRAWBRIDGE_DOWN
/* "lowered drawbridge" */
1653 || ltyp
== DBWALL
) /* "raised drawbridge" */
1654 supporting
= "drawbridge";
1657 Sprintf(msg
, "The %s%ssupporting structures remain intact.",
1658 supporting
? s_suffix(supporting
) : "",
1659 supporting
? " " : "");
1667 * Ensure that all conjoined pits fill up.
1670 pit_flow(trap
, filltyp
)
1674 if (trap
&& (filltyp
!= ROOM
)
1675 && (trap
->ttyp
== PIT
|| trap
->ttyp
== SPIKED_PIT
)) {
1680 levl
[trap
->tx
][trap
->ty
].typ
= filltyp
;
1681 liquid_flow(trap
->tx
, trap
->ty
, filltyp
, trap
,
1682 (trap
->tx
== u
.ux
&& trap
->ty
== u
.uy
)
1683 ? "Suddenly %s flows in from the adjacent pit!"
1685 for (idx
= 0; idx
< 8; ++idx
) {
1686 if (t
.conjoined
& (1 << idx
)) {
1690 x
= t
.tx
+ xdir
[idx
];
1691 y
= t
.ty
+ ydir
[idx
];
1694 /* cannot do this back-check; liquid_flow()
1695 * called deltrap() which cleaned up the
1696 * conjoined fields on both pits.
1698 if (t2
&& (t2
->conjoined
& (1 << ((idx
+ 4) % 8))))
1701 pit_flow(t2
, filltyp
);
1711 xchar check_x
, check_y
;
1712 struct obj
*otmp
, *otmp2
;
1714 if (u
.utraptype
== TT_BURIEDBALL
)
1715 for (otmp
= level
.buriedobjlist
; otmp
; otmp
= otmp2
) {
1717 if (otmp
->otyp
!= HEAVY_IRON_BALL
)
1719 /* try the exact location first */
1720 if (otmp
->ox
== cc
->x
&& otmp
->oy
== cc
->y
)
1722 /* Now try the vicinity */
1724 * (x-2,y-2) (x+2,y-2)
1726 * (x-2,y+2) (x+2,y+2)
1728 for (check_x
= cc
->x
- 2; check_x
<= cc
->x
+ 2; ++check_x
)
1729 for (check_y
= cc
->y
- 2; check_y
<= cc
->y
+ 2; ++check_y
) {
1730 if (check_x
== cc
->x
&& check_y
== cc
->y
)
1732 if (isok(check_x
, check_y
)
1733 && (otmp
->ox
== check_x
&& otmp
->oy
== check_y
)) {
1740 return (struct obj
*) 0;
1744 buried_ball_to_punishment()
1750 ball
= buried_ball(&cc
);
1752 obj_extract_self(ball
);
1754 /* rusting buried metallic objects is not implemented yet */
1756 (void) stop_timer(RUST_METAL
, obj_to_any(ball
));
1758 punish(ball
); /* use ball as flag for unearthed buried ball */
1761 del_engr_at(cc
.x
, cc
.y
);
1767 buried_ball_to_freedom()
1773 ball
= buried_ball(&cc
);
1775 obj_extract_self(ball
);
1777 /* rusting buried metallic objects is not implemented yet */
1779 (void) stop_timer(RUST_METAL
, obj_to_any(ball
));
1781 place_object(ball
, cc
.x
, cc
.y
);
1785 del_engr_at(cc
.x
, cc
.y
);
1790 /* move objects from fobj/nexthere lists to buriedobjlist, keeping position
1793 bury_an_obj(otmp
, dealloced
)
1800 debugpline1("bury_an_obj: %s", xname(otmp
));
1803 if (otmp
== uball
) {
1805 u
.utrap
= rn1(50, 20);
1806 u
.utraptype
= TT_BURIEDBALL
;
1807 pline_The("iron ball gets buried!");
1809 /* after unpunish(), or might get deallocated chain */
1810 otmp2
= otmp
->nexthere
;
1812 * obj_resists(,0,0) prevents Rider corpses from being buried.
1813 * It also prevents The Amulet and invocation tools from being
1814 * buried. Since they can't be confined to bags and statues,
1815 * it makes sense that they can't be buried either, even though
1816 * the real reason there (direct accessibility when carried) is
1817 * completely different.
1819 if (otmp
== uchain
|| obj_resists(otmp
, 0, 0))
1822 if (otmp
->otyp
== LEASH
&& otmp
->leashmon
!= 0)
1825 if (otmp
->lamplit
&& otmp
->otyp
!= POT_OIL
)
1826 end_burn(otmp
, TRUE
);
1828 obj_extract_self(otmp
);
1830 under_ice
= is_ice(otmp
->ox
, otmp
->oy
);
1831 if (otmp
->otyp
== ROCK
&& !under_ice
) {
1832 /* merges into burying material */
1835 obfree(otmp
, (struct obj
*) 0);
1839 * Start a rot on organic material. Not corpses -- they
1840 * are already handled.
1842 if (otmp
->otyp
== CORPSE
) {
1843 ; /* should cancel timer if under_ice */
1844 } else if ((under_ice
? otmp
->oclass
== POTION_CLASS
: is_organic(otmp
))
1845 && !obj_resists(otmp
, 5, 95)) {
1846 (void) start_timer((under_ice
? 0L : 250L) + (long) rnd(250),
1847 TIMER_OBJECT
, ROT_ORGANIC
, obj_to_any(otmp
));
1849 /* rusting of buried metal not yet implemented */
1850 } else if (is_rustprone(otmp
)) {
1851 (void) start_timer((long) rnd((otmp
->otyp
== HEAVY_IRON_BALL
)
1854 TIMER_OBJECT
, RUST_METAL
, obj_to_any(otmp
));
1857 add_to_buried(otmp
);
1865 struct obj
*otmp
, *otmp2
;
1867 if (level
.objects
[x
][y
] != (struct obj
*) 0) {
1868 debugpline2("bury_objs: at <%d,%d>", x
, y
);
1870 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp2
)
1871 otmp2
= bury_an_obj(otmp
, (boolean
*) 0);
1873 /* don't expect any engravings here, but just in case */
1878 /* move objects from buriedobjlist to fobj/nexthere lists */
1883 struct obj
*otmp
, *otmp2
, *bball
;
1886 debugpline2("unearth_objs: at <%d,%d>", x
, y
);
1889 bball
= buried_ball(&cc
);
1890 for (otmp
= level
.buriedobjlist
; otmp
; otmp
= otmp2
) {
1892 if (otmp
->ox
== x
&& otmp
->oy
== y
) {
1893 if (bball
&& otmp
== bball
&& u
.utraptype
== TT_BURIEDBALL
) {
1894 buried_ball_to_punishment();
1896 obj_extract_self(otmp
);
1898 (void) stop_timer(ROT_ORGANIC
, obj_to_any(otmp
));
1899 place_object(otmp
, x
, y
);
1909 * The organic material has rotted away while buried. As an expansion,
1910 * we could add add partial damage. A damage count is kept in the object
1911 * and every time we are called we increment the count and reschedule another
1912 * timeout. Eventually the object rots away.
1914 * This is used by buried objects other than corpses. When a container rots
1915 * away, any contents become newly buried objects.
1919 rot_organic(arg
, timeout
)
1921 long timeout UNUSED
;
1923 struct obj
*obj
= arg
->a_obj
;
1925 while (Has_contents(obj
)) {
1926 /* We don't need to place contained object on the floor
1927 first, but we do need to update its map coordinates. */
1928 obj
->cobj
->ox
= obj
->ox
, obj
->cobj
->oy
= obj
->oy
;
1929 /* Everything which can be held in a container can also be
1930 buried, so bury_an_obj's use of obj_extract_self insures
1931 that Has_contents(obj) will eventually become false. */
1932 (void) bury_an_obj(obj
->cobj
, (boolean
*) 0);
1934 obj_extract_self(obj
);
1935 obfree(obj
, (struct obj
*) 0);
1939 * Called when a corpse has rotted completely away.
1942 rot_corpse(arg
, timeout
)
1947 struct obj
*obj
= arg
->a_obj
;
1948 boolean on_floor
= obj
->where
== OBJ_FLOOR
,
1949 in_invent
= obj
->where
== OBJ_INVENT
;
1954 } else if (in_invent
) {
1955 if (flags
.verbose
) {
1956 char *cname
= corpse_xname(obj
, (const char *) 0, CXN_NO_PFX
);
1958 Your("%s%s %s away%c", obj
== uwep
? "wielded " : "", cname
,
1959 otense(obj
, "rot"), obj
== uwep
? '!' : '.');
1962 uwepgone(); /* now bare handed */
1964 } else if (obj
== uswapwep
) {
1967 } else if (obj
== uquiver
) {
1971 } else if (obj
->where
== OBJ_MINVENT
&& obj
->owornmask
) {
1972 if (obj
== MON_WEP(obj
->ocarry
))
1973 setmnotwielded(obj
->ocarry
, obj
);
1974 } else if (obj
->where
== OBJ_MIGRATING
) {
1975 /* clear destination flag so that obfree()'s check for
1976 freeing a worn object doesn't get a false hit */
1977 obj
->owornmask
= 0L;
1979 rot_organic(arg
, timeout
);
1981 struct monst
*mtmp
= m_at(x
, y
);
1983 /* a hiding monster may be exposed */
1984 if (mtmp
&& !OBJ_AT(x
, y
) && mtmp
->mundetected
1985 && hides_under(mtmp
->data
)) {
1986 mtmp
->mundetected
= 0;
1987 } else if (x
== u
.ux
&& y
== u
.uy
&& u
.uundetected
&& hides_under(youmonst
.data
))
1988 (void) hideunder(&youmonst
);
1990 } else if (in_invent
)
1999 debugpline1("bury_monst: %s", mon_nam(mtmp
));
2000 if (canseemon(mtmp
)) {
2001 if (is_flyer(mtmp
->data
) || is_floater(mtmp
->data
)) {
2002 pline_The("%s opens up, but %s is not swallowed!",
2003 surface(mtmp
->mx
, mtmp
->my
), mon_nam(mtmp
));
2006 pline_The("%s opens up and swallows %s!",
2007 surface(mtmp
->mx
, mtmp
->my
), mon_nam(mtmp
));
2010 mtmp
->mburied
= TRUE
;
2011 wakeup(mtmp
, FALSE
); /* at least give it a chance :-) */
2012 newsym(mtmp
->mx
, mtmp
->my
);
2018 debugpline0("bury_you");
2019 if (!Levitation
&& !Flying
) {
2021 You_feel("a sensation like falling into a trap!");
2023 pline_The("%s opens beneath you and you fall in!",
2024 surface(u
.ux
, u
.uy
));
2027 if (!Strangled
&& !Breathless
)
2036 debugpline0("unearth_you");
2039 if (!uamul
|| uamul
->otyp
!= AMULET_OF_STRANGULATION
)
2047 debugpline0("escape_tomb");
2048 if ((Teleportation
|| can_teleport(youmonst
.data
))
2049 && (Teleport_control
|| rn2(3) < Luck
+2)) {
2050 You("attempt a teleport spell.");
2051 (void) dotele(); /* calls unearth_you() */
2052 } else if (u
.uburied
) { /* still buried after 'port attempt */
2055 if (amorphous(youmonst
.data
) || Passes_walls
2056 || noncorporeal(youmonst
.data
)
2057 || (unsolid(youmonst
.data
)
2058 && youmonst
.data
!= &mons
[PM_WATER_ELEMENTAL
])
2059 || (tunnels(youmonst
.data
) && !needspick(youmonst
.data
))) {
2060 You("%s up through the %s.",
2061 (tunnels(youmonst
.data
) && !needspick(youmonst
.data
))
2063 : (amorphous(youmonst
.data
))
2066 surface(u
.ux
, u
.uy
));
2068 good
= (tunnels(youmonst
.data
) && !needspick(youmonst
.data
))
2069 ? dighole(TRUE
, FALSE
, (coord
*)0) : TRUE
;
2080 debugpline0("bury_obj");
2081 if (cansee(otmp
->ox
, otmp
->oy
))
2082 pline_The("objects on the %s tumble into a hole!",
2083 surface(otmp
->ox
, otmp
->oy
));
2085 bury_objs(otmp
->ox
, otmp
->oy
);
2090 /* bury everything at your loc and around */
2092 wiz_debug_cmd_bury()
2096 for (x
= u
.ux
- 1; x
<= u
.ux
+ 1; x
++)
2097 for (y
= u
.uy
- 1; y
<= u
.uy
+ 1; y
++)