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