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