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