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*/