1/* SCCS Id: @(#)lock.c 3.4 2000/02/06 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7STATIC_PTR int NDECL(picklock); 8STATIC_PTR int NDECL(forcelock); 9 10/* at most one of `door' and `box' should be non-null at any given time */ 11STATIC_VAR NEARDATA struct xlock_s { 12 struct rm *door; 13 struct obj *box; 14 int picktyp, chance, usedtime; 15} xlock; 16 17#ifdef OVLB 18 19STATIC_DCL const char *NDECL(lock_action); 20STATIC_DCL boolean FDECL(obstructed,(int,int)); 21STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *)); 22 23boolean 24picking_lock(x, y) 25 int *x, *y; 26{ 27 if (occupation == picklock) { 28 *x = u.ux + u.dx; 29 *y = u.uy + u.dy; 30 return TRUE; 31 } else { 32 *x = *y = 0; 33 return FALSE; 34 } 35} 36 37boolean 38picking_at(x, y) 39int x, y; 40{ 41 return (boolean)(occupation == picklock && xlock.door == &levl[x][y]); 42} 43 44/* produce an occupation string appropriate for the current activity */ 45STATIC_OVL const char * 46lock_action() 47{ 48 /* "unlocking"+2 == "locking" */ 49 static const char *actions[] = { 50 /* [0] */ "unlocking the door", 51 /* [1] */ "unlocking the chest", 52 /* [2] */ "unlocking the box", 53 /* [3] */ "picking the lock" 54 }; 55 56 /* if the target is currently unlocked, we're trying to lock it now */ 57 if (xlock.door && !(xlock.door->doormask & D_LOCKED)) 58 return actions[0]+2; /* "locking the door" */ 59 else if (xlock.box && !xlock.box->olocked) 60 return xlock.box->otyp == CHEST ? actions[1]+2 : actions[2]+2; 61 /* otherwise we're trying to unlock it */ 62 else if (xlock.picktyp == LOCK_PICK) 63 return actions[3]; /* "picking the lock" */ 64#ifdef TOURIST 65 else if (xlock.picktyp == CREDIT_CARD) 66 return actions[3]; /* same as lock_pick */ 67#endif 68 else if (xlock.door) 69 return actions[0]; /* "unlocking the door" */ 70 else 71 return xlock.box->otyp == CHEST ? actions[1] : actions[2]; 72} 73 74STATIC_PTR 75int 76picklock() /* try to open/close a lock */ 77{ 78 79 if (xlock.box) { 80 if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) { 81 return((xlock.usedtime = 0)); /* you or it moved */ 82 } 83 } else { /* door */ 84 if(xlock.door != &(levl[u.ux+u.dx][u.uy+u.dy])) { 85 return((xlock.usedtime = 0)); /* you moved */ 86 } 87 switch (xlock.door->doormask) { 88 case D_NODOOR: 89 pline("This doorway has no door."); 90 return((xlock.usedtime = 0)); 91 case D_ISOPEN: 92 You("cannot lock an open door."); 93 return((xlock.usedtime = 0)); 94 case D_BROKEN: 95 pline("This door is broken."); 96 return((xlock.usedtime = 0)); 97 } 98 } 99 100 if (xlock.usedtime++ >= 50 || nohands(youmonst.data)) { 101 You("give up your attempt at %s.", lock_action()); 102 exercise(A_DEX, TRUE); /* even if you don't succeed */ 103 return((xlock.usedtime = 0)); 104 } 105 106 if(rn2(100) >= xlock.chance) return(1); /* still busy */ 107 108 You("succeed in %s.", lock_action()); 109 if (xlock.door) { 110 if(xlock.door->doormask & D_TRAPPED) { 111 b_trapped("door", FINGER); 112 xlock.door->doormask = D_NODOOR; 113 unblock_point(u.ux+u.dx, u.uy+u.dy); 114 if (*in_rooms(u.ux+u.dx, u.uy+u.dy, SHOPBASE)) 115 add_damage(u.ux+u.dx, u.uy+u.dy, 0L); 116 newsym(u.ux+u.dx, u.uy+u.dy); 117 } else if (xlock.door->doormask & D_LOCKED) 118 xlock.door->doormask = D_CLOSED; 119 else xlock.door->doormask = D_LOCKED; 120 } else { 121 xlock.box->olocked = !xlock.box->olocked; 122 if(xlock.box->otrapped) 123 (void) chest_trap(xlock.box, FINGER, FALSE); 124 } 125 exercise(A_DEX, TRUE); 126 return((xlock.usedtime = 0)); 127} 128 129STATIC_PTR 130int 131forcelock() /* try to force a locked chest */ 132{ 133 134 register struct obj *otmp; 135 136 if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) 137 return((xlock.usedtime = 0)); /* you or it moved */ 138 139 if (xlock.usedtime++ >= 50 || !uwep || nohands(youmonst.data)) { 140 You("give up your attempt to force the lock."); 141 if(xlock.usedtime >= 50) /* you made the effort */ 142 exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); 143 return((xlock.usedtime = 0)); 144 } 145 146 if(xlock.picktyp) { /* blade */ 147 148 if(rn2(1000-(int)uwep->spe) > (992-greatest_erosion(uwep)*10) && 149 !uwep->cursed && !obj_resists(uwep, 0, 99)) { 150 /* for a +0 weapon, probability that it survives an unsuccessful 151 * attempt to force the lock is (.992)^50 = .67 152 */ 153 pline("%sour %s broke!", 154 (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep)); 155 useup(uwep); 156 You("give up your attempt to force the lock."); 157 exercise(A_DEX, TRUE); 158 return((xlock.usedtime = 0)); 159 } 160 } else /* blunt */ 161 wake_nearby(); /* due to hammering on the container */ 162 163 if(rn2(100) >= xlock.chance) return(1); /* still busy */ 164 165 You("succeed in forcing the lock."); 166 xlock.box->olocked = 0; 167 xlock.box->obroken = 1; 168 if(!xlock.picktyp && !rn2(3)) { 169 struct monst *shkp; 170 boolean costly; 171 long loss = 0L; 172 173 costly = (*u.ushops && costly_spot(u.ux, u.uy)); 174 shkp = costly ? shop_keeper(*u.ushops) : 0; 175 176 pline("In fact, you've totally destroyed %s.", 177 the(xname(xlock.box))); 178 179 /* Put the contents on ground at the hero's feet. */ 180 while ((otmp = xlock.box->cobj) != 0) { 181 obj_extract_self(otmp); 182 if(!rn2(3) || otmp->oclass == POTION_CLASS) { 183 chest_shatter_msg(otmp); 184 if (costly) 185 loss += stolen_value(otmp, u.ux, u.uy, 186 (boolean)shkp->mpeaceful, TRUE); 187 if (otmp->quan == 1L) { 188 obfree(otmp, (struct obj *) 0); 189 continue; 190 } 191 useup(otmp); 192 } 193 if (xlock.box->otyp == ICE_BOX && otmp->otyp == CORPSE) { 194 otmp->age = monstermoves - otmp->age; /* actual age */ 195 start_corpse_timeout(otmp); 196 } 197 place_object(otmp, u.ux, u.uy); 198 stackobj(otmp); 199 } 200 201 if (costly) 202 loss += stolen_value(xlock.box, u.ux, u.uy, 203 (boolean)shkp->mpeaceful, TRUE); 204 if(loss) You("owe %ld %s for objects destroyed.", loss, currency(loss)); 205 delobj(xlock.box); 206 } 207 exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); 208 return((xlock.usedtime = 0)); 209} 210 211#endif /* OVLB */ 212#ifdef OVL0 213 214void 215reset_pick() 216{ 217 xlock.usedtime = xlock.chance = xlock.picktyp = 0; 218 xlock.door = 0; 219 xlock.box = 0; 220} 221 222#endif /* OVL0 */ 223#ifdef OVLB 224 225int 226pick_lock(pick) /* pick a lock with a given object */ 227 register struct obj *pick; 228{ 229 int picktyp, c, ch; 230 coord cc; 231 struct rm *door; 232 struct obj *otmp; 233 char qbuf[QBUFSZ]; 234 235 picktyp = pick->otyp; 236 237 /* check whether we're resuming an interrupted previous attempt */ 238 if (xlock.usedtime && picktyp == xlock.picktyp) { 239 static char no_longer[] = "Unfortunately, you can no longer %s %s."; 240 241 if (nohands(youmonst.data)) { 242 const char *what = (picktyp == LOCK_PICK) ? "pick" : "key"; 243#ifdef TOURIST 244 if (picktyp == CREDIT_CARD) what = "card"; 245#endif 246 pline(no_longer, "hold the", what); 247 reset_pick(); 248 return 0; 249 } else if (xlock.box && !can_reach_floor()) { 250 pline(no_longer, "reach the", "lock"); 251 reset_pick(); 252 return 0; 253 } else { 254 const char *action = lock_action(); 255 You("resume your attempt at %s.", action); 256 set_occupation(picklock, action, 0); 257 return(1); 258 } 259 } 260 261 if(nohands(youmonst.data)) { 262 You_cant("hold %s -- you have no hands!", doname(pick)); 263 return(0); 264 } 265 266 if((picktyp != LOCK_PICK && 267#ifdef TOURIST 268 picktyp != CREDIT_CARD && 269#endif 270 picktyp != SKELETON_KEY)) { 271 impossible("picking lock with object %d?", picktyp); 272 return(0); 273 } 274 ch = 0; /* lint suppression */ 275 276 if(!get_adjacent_loc((char *)0, "Invalid location!", u.ux, u.uy, &cc)) return 0; 277 if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */ 278 const char *verb; 279 boolean it; 280 int count; 281 282 if (u.dz < 0) { 283 There("isn't any sort of lock up %s.", 284 Levitation ? "here" : "there"); 285 return 0; 286 } else if (is_lava(u.ux, u.uy)) { 287 pline("Doing that would probably melt your %s.", 288 xname(pick)); 289 return 0; 290 } else if (is_pool(u.ux, u.uy) && !Underwater) { 291 pline_The("water has no lock."); 292 return 0; 293 } 294 295 count = 0; 296 c = 'n'; /* in case there are no boxes here */ 297 for(otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) 298 if (Is_box(otmp)) { 299 ++count; 300 if (!can_reach_floor()) { 301 You_cant("reach %s from up here.", the(xname(otmp))); 302 return 0; 303 } 304 it = 0; 305 if (otmp->obroken) verb = "fix"; 306 else if (!otmp->olocked) verb = "lock", it = 1; 307 else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; 308 else verb = "pick"; 309 Sprintf(qbuf, "There is %s here, %s %s?", 310 safe_qbuf("", sizeof("There is here, unlock its lock?"), 311 doname(otmp), an(simple_typename(otmp->otyp)), "a box"), 312 verb, it ? "it" : "its lock"); 313 314 c = ynq(qbuf); 315 if(c == 'q') return(0); 316 if(c == 'n') continue; 317 318 if (otmp->obroken) { 319 You_cant("fix its broken lock with %s.", doname(pick)); 320 return 0; 321 } 322#ifdef TOURIST 323 else if (picktyp == CREDIT_CARD && !otmp->olocked) { 324 /* credit cards are only good for unlocking */ 325 You_cant("do that with %s.", doname(pick)); 326 return 0; 327 } 328#endif 329 switch(picktyp) { 330#ifdef TOURIST 331 case CREDIT_CARD: 332 ch = ACURR(A_DEX) + 20*Role_if(PM_ROGUE); 333 break; 334#endif 335 case LOCK_PICK: 336 ch = 4*ACURR(A_DEX) + 25*Role_if(PM_ROGUE); 337 break; 338 case SKELETON_KEY: 339 ch = 75 + ACURR(A_DEX); 340 break; 341 default: ch = 0; 342 } 343 if(otmp->cursed) ch /= 2; 344 345 xlock.picktyp = picktyp; 346 xlock.box = otmp; 347 xlock.door = 0; 348 break; 349 } 350 if (c != 'y') { 351 if (!count) 352 There("doesn't seem to be any sort of lock here."); 353 return(0); /* decided against all boxes */ 354 } 355 } else { /* pick the lock in a door */ 356 struct monst *mtmp; 357 358 if (u.utrap && u.utraptype == TT_PIT) { 359 You_cant("reach over the edge of the pit."); 360 return(0); 361 } 362 363 door = &levl[cc.x][cc.y]; 364 if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp) 365 && mtmp->m_ap_type != M_AP_FURNITURE 366 && mtmp->m_ap_type != M_AP_OBJECT) { 367#ifdef TOURIST 368 if (picktyp == CREDIT_CARD && 369 (mtmp->isshk || mtmp->data == &mons[PM_ORACLE])) 370 verbalize("No checks, no credit, no problem."); 371 else 372#endif 373 pline("I don't think %s would appreciate that.", mon_nam(mtmp)); 374 return(0); 375 } 376 if(!IS_DOOR(door->typ)) { 377 if (is_drawbridge_wall(cc.x,cc.y) >= 0) 378 You("%s no lock on the drawbridge.", 379 Blind ? "feel" : "see"); 380 else 381 You("%s no door there.", 382 Blind ? "feel" : "see"); 383 return(0); 384 } 385 switch (door->doormask) { 386 case D_NODOOR: 387 pline("This doorway has no door."); 388 return(0); 389 case D_ISOPEN: 390 You("cannot lock an open door."); 391 return(0); 392 case D_BROKEN: 393 pline("This door is broken."); 394 return(0); 395 default: 396#ifdef TOURIST 397 /* credit cards are only good for unlocking */ 398 if(picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) { 399 You_cant("lock a door with a credit card."); 400 return(0); 401 } 402#endif 403 404 Sprintf(qbuf,"%sock it?", 405 (door->doormask & D_LOCKED) ? "Unl" : "L" ); 406 407 c = yn(qbuf); 408 if(c == 'n') return(0); 409 410 switch(picktyp) { 411#ifdef TOURIST 412 case CREDIT_CARD: 413 ch = 2*ACURR(A_DEX) + 20*Role_if(PM_ROGUE); 414 break; 415#endif 416 case LOCK_PICK: 417 ch = 3*ACURR(A_DEX) + 30*Role_if(PM_ROGUE); 418 break; 419 case SKELETON_KEY: 420 ch = 70 + ACURR(A_DEX); 421 break; 422 default: ch = 0; 423 } 424 xlock.door = door; 425 xlock.box = 0; 426 } 427 } 428 flags.move = 0; 429 xlock.chance = ch; 430 xlock.picktyp = picktyp; 431 xlock.usedtime = 0; 432 set_occupation(picklock, lock_action(), 0); 433 return(1); 434} 435 436int 437doforce() /* try to force a chest with your weapon */ 438{ 439 register struct obj *otmp; 440 register int c, picktyp; 441 char qbuf[QBUFSZ]; 442 443 if(!uwep || /* proper type test */ 444 (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep) && 445 uwep->oclass != ROCK_CLASS) || 446 (objects[uwep->otyp].oc_skill < P_DAGGER) || 447 (objects[uwep->otyp].oc_skill > P_LANCE) || 448 uwep->otyp == FLAIL || uwep->otyp == AKLYS 449#ifdef KOPS 450 || uwep->otyp == RUBBER_HOSE 451#endif 452 ) { 453 You_cant("force anything without a %sweapon.", 454 (uwep) ? "proper " : ""); 455 return(0); 456 } 457 458 picktyp = is_blade(uwep); 459 if(xlock.usedtime && xlock.box && picktyp == xlock.picktyp) { 460 You("resume your attempt to force the lock."); 461 set_occupation(forcelock, "forcing the lock", 0); 462 return(1); 463 } 464 465 /* A lock is made only for the honest man, the thief will break it. */ 466 xlock.box = (struct obj *)0; 467 for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) 468 if(Is_box(otmp)) { 469 if (otmp->obroken || !otmp->olocked) { 470 There("is %s here, but its lock is already %s.", 471 doname(otmp), otmp->obroken ? "broken" : "unlocked"); 472 continue; 473 } 474 Sprintf(qbuf,"There is %s here, force its lock?", 475 safe_qbuf("", sizeof("There is here, force its lock?"), 476 doname(otmp), an(simple_typename(otmp->otyp)), 477 "a box")); 478 479 c = ynq(qbuf); 480 if(c == 'q') return(0); 481 if(c == 'n') continue; 482 483 if(picktyp) 484 You("force your %s into a crack and pry.", xname(uwep)); 485 else 486 You("start bashing it with your %s.", xname(uwep)); 487 xlock.box = otmp; 488 xlock.chance = objects[uwep->otyp].oc_wldam * 2; 489 xlock.picktyp = picktyp; 490 xlock.usedtime = 0; 491 break; 492 } 493 494 if(xlock.box) set_occupation(forcelock, "forcing the lock", 0); 495 else You("decide not to force the issue."); 496 return(1); 497} 498 499int 500doopen() /* try to open a door */ 501{ 502 coord cc; 503 register struct rm *door; 504 struct monst *mtmp; 505 506 if (nohands(youmonst.data)) { 507 You_cant("open anything -- you have no hands!"); 508 return 0; 509 } 510 511 if (u.utrap && u.utraptype == TT_PIT) { 512 You_cant("reach over the edge of the pit."); 513 return 0; 514 } 515 516 if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0); 517 518 if((cc.x == u.ux) && (cc.y == u.uy)) return(0); 519 520 if ((mtmp = m_at(cc.x,cc.y)) && 521 mtmp->m_ap_type == M_AP_FURNITURE && 522 (mtmp->mappearance == S_hcdoor || 523 mtmp->mappearance == S_vcdoor) && 524 !Protection_from_shape_changers) { 525 526 stumble_onto_mimic(mtmp); 527 return(1); 528 } 529 530 door = &levl[cc.x][cc.y]; 531 532 if(!IS_DOOR(door->typ)) { 533 if (is_db_wall(cc.x,cc.y)) { 534 There("is no obvious way to open the drawbridge."); 535 return(0); 536 } 537 You("%s no door there.", 538 Blind ? "feel" : "see"); 539 return(0); 540 } 541 542 if (!(door->doormask & D_CLOSED)) { 543 const char *mesg; 544 545 switch (door->doormask) { 546 case D_BROKEN: mesg = " is broken"; break; 547 case D_NODOOR: mesg = "way has no door"; break; 548 case D_ISOPEN: mesg = " is already open"; break; 549 default: mesg = " is locked"; break; 550 } 551 pline("This door%s.", mesg); 552 if (Blind) feel_location(cc.x,cc.y); 553 return(0); 554 } 555 556 if(verysmall(youmonst.data)) { 557 pline("You're too small to pull the door open."); 558 return(0); 559 } 560 561 /* door is known to be CLOSED */ 562 if (rnl(20) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) { 563 pline_The("door opens."); 564 if(door->doormask & D_TRAPPED) { 565 b_trapped("door", FINGER); 566 door->doormask = D_NODOOR; 567 if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); 568 } else 569 door->doormask = D_ISOPEN; 570 if (Blind) 571 feel_location(cc.x,cc.y); /* the hero knows she opened it */ 572 else 573 newsym(cc.x,cc.y); 574 unblock_point(cc.x,cc.y); /* vision: new see through there */ 575 } else { 576 exercise(A_STR, TRUE); 577 pline_The("door resists!"); 578 } 579 580 return(1); 581} 582 583STATIC_OVL 584boolean 585obstructed(x,y) 586register int x, y; 587{ 588 register struct monst *mtmp = m_at(x, y); 589 590 if(mtmp && mtmp->m_ap_type != M_AP_FURNITURE) { 591 if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere; 592 pline("%s stands in the way!", !canspotmon(mtmp) ? 593 "Some creature" : Monnam(mtmp)); 594 if (!canspotmon(mtmp)) 595 map_invisible(mtmp->mx, mtmp->my); 596 return(TRUE); 597 } 598 if (OBJ_AT(x, y)) { 599objhere: pline("%s's in the way.", Something); 600 return(TRUE); 601 } 602 return(FALSE); 603} 604 605int 606doclose() /* try to close a door */ 607{ 608 register int x, y; 609 register struct rm *door; 610 struct monst *mtmp; 611 612 if (nohands(youmonst.data)) { 613 You_cant("close anything -- you have no hands!"); 614 return 0; 615 } 616 617 if (u.utrap && u.utraptype == TT_PIT) { 618 You_cant("reach over the edge of the pit."); 619 return 0; 620 } 621 622 if(!getdir((char *)0)) return(0); 623 624 x = u.ux + u.dx; 625 y = u.uy + u.dy; 626 if((x == u.ux) && (y == u.uy)) { 627 You("are in the way!"); 628 return(1); 629 } 630 631 if ((mtmp = m_at(x,y)) && 632 mtmp->m_ap_type == M_AP_FURNITURE && 633 (mtmp->mappearance == S_hcdoor || 634 mtmp->mappearance == S_vcdoor) && 635 !Protection_from_shape_changers) { 636 637 stumble_onto_mimic(mtmp); 638 return(1); 639 } 640 641 door = &levl[x][y]; 642 643 if(!IS_DOOR(door->typ)) { 644 if (door->typ == DRAWBRIDGE_DOWN) 645 There("is no obvious way to close the drawbridge."); 646 else 647 You("%s no door there.", 648 Blind ? "feel" : "see"); 649 return(0); 650 } 651 652 if(door->doormask == D_NODOOR) { 653 pline("This doorway has no door."); 654 return(0); 655 } 656 657 if(obstructed(x, y)) return(0); 658 659 if(door->doormask == D_BROKEN) { 660 pline("This door is broken."); 661 return(0); 662 } 663 664 if(door->doormask & (D_CLOSED | D_LOCKED)) { 665 pline("This door is already closed."); 666 return(0); 667 } 668 669 if(door->doormask == D_ISOPEN) { 670 if(verysmall(youmonst.data) 671#ifdef STEED 672 && !u.usteed 673#endif 674 ) { 675 pline("You're too small to push the door closed."); 676 return(0); 677 } 678 if ( 679#ifdef STEED 680 u.usteed || 681#endif 682 rn2(25) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) { 683 pline_The("door closes."); 684 door->doormask = D_CLOSED; 685 if (Blind) 686 feel_location(x,y); /* the hero knows she closed it */ 687 else 688 newsym(x,y); 689 block_point(x,y); /* vision: no longer see there */ 690 } 691 else { 692 exercise(A_STR, TRUE); 693 pline_The("door resists!"); 694 } 695 } 696 697 return(1); 698} 699 700boolean /* box obj was hit with spell effect otmp */ 701boxlock(obj, otmp) /* returns true if something happened */ 702register struct obj *obj, *otmp; /* obj *is* a box */ 703{ 704 register boolean res = 0; 705 706 switch(otmp->otyp) { 707 case WAN_LOCKING: 708 case SPE_WIZARD_LOCK: 709 if (!obj->olocked) { /* lock it; fix if broken */ 710 pline("Klunk!"); 711 obj->olocked = 1; 712 obj->obroken = 0; 713 res = 1; 714 } /* else already closed and locked */ 715 break; 716 case WAN_OPENING: 717 case SPE_KNOCK: 718 if (obj->olocked) { /* unlock; couldn't be broken */ 719 pline("Klick!"); 720 obj->olocked = 0; 721 res = 1; 722 } else /* silently fix if broken */ 723 obj->obroken = 0; 724 break; 725 case WAN_POLYMORPH: 726 case SPE_POLYMORPH: 727 /* maybe start unlocking chest, get interrupted, then zap it; 728 we must avoid any attempt to resume unlocking it */ 729 if (xlock.box == obj) 730 reset_pick(); 731 break; 732 } 733 return res; 734} 735 736boolean /* Door/secret door was hit with spell effect otmp */ 737doorlock(otmp,x,y) /* returns true if something happened */ 738struct obj *otmp; 739int x, y; 740{ 741 register struct rm *door = &levl[x][y]; 742 boolean res = TRUE; 743 int loudness = 0; 744 const char *msg = (const char *)0; 745 const char *dustcloud = "A cloud of dust"; 746 const char *quickly_dissipates = "quickly dissipates"; 747 748 if (door->typ == SDOOR) { 749 switch (otmp->otyp) { 750 case WAN_OPENING: 751 case SPE_KNOCK: 752 case WAN_STRIKING: 753 case SPE_FORCE_BOLT: 754 door->typ = DOOR; 755 door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); 756 newsym(x,y); 757 if (cansee(x,y)) pline("A door appears in the wall!"); 758 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) 759 return TRUE; 760 break; /* striking: continue door handling below */ 761 case WAN_LOCKING: 762 case SPE_WIZARD_LOCK: 763 default: 764 return FALSE; 765 } 766 } 767 768 switch(otmp->otyp) { 769 case WAN_LOCKING: 770 case SPE_WIZARD_LOCK: 771#ifdef REINCARNATION 772 if (Is_rogue_level(&u.uz)) { 773 boolean vis = cansee(x,y); 774 /* Can't have real locking in Rogue, so just hide doorway */ 775 if (vis) pline("%s springs up in the older, more primitive doorway.", 776 dustcloud); 777 else 778 You_hear("a swoosh."); 779 if (obstructed(x,y)) { 780 if (vis) pline_The("cloud %s.",quickly_dissipates); 781 return FALSE; 782 } 783 block_point(x, y); 784 door->typ = SDOOR; 785 if (vis) pline_The("doorway vanishes!"); 786 newsym(x,y); 787 return TRUE; 788 } 789#endif 790 if (obstructed(x,y)) return FALSE; 791 /* Don't allow doors to close over traps. This is for pits */ 792 /* & trap doors, but is it ever OK for anything else? */ 793 if (t_at(x,y)) { 794 /* maketrap() clears doormask, so it should be NODOOR */ 795 pline( 796 "%s springs up in the doorway, but %s.", 797 dustcloud, quickly_dissipates); 798 return FALSE; 799 } 800 801 switch (door->doormask & ~D_TRAPPED) { 802 case D_CLOSED: 803 msg = "The door locks!"; 804 break; 805 case D_ISOPEN: 806 msg = "The door swings shut, and locks!"; 807 break; 808 case D_BROKEN: 809 msg = "The broken door reassembles and locks!"; 810 break; 811 case D_NODOOR: 812 msg = 813 "A cloud of dust springs up and assembles itself into a door!"; 814 break; 815 default: 816 res = FALSE; 817 break; 818 } 819 block_point(x, y); 820 door->doormask = D_LOCKED | (door->doormask & D_TRAPPED); 821 newsym(x,y); 822 break; 823 case WAN_OPENING: 824 case SPE_KNOCK: 825 if (door->doormask & D_LOCKED) { 826 msg = "The door unlocks!"; 827 door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); 828 } else res = FALSE; 829 break; 830 case WAN_STRIKING: 831 case SPE_FORCE_BOLT: 832 if (door->doormask & (D_LOCKED | D_CLOSED)) { 833 if (door->doormask & D_TRAPPED) { 834 if (MON_AT(x, y)) 835 (void) mb_trapped(m_at(x,y)); 836 else if (flags.verbose) { 837 if (cansee(x,y)) 838 pline("KABOOM!! You see a door explode."); 839 else if (flags.soundok) 840 You_hear("a distant explosion."); 841 } 842 door->doormask = D_NODOOR; 843 unblock_point(x,y); 844 newsym(x,y); 845 loudness = 40; 846 break; 847 } 848 door->doormask = D_BROKEN; 849 if (flags.verbose) { 850 if (cansee(x,y)) 851 pline_The("door crashes open!"); 852 else if (flags.soundok) 853 You_hear("a crashing sound."); 854 } 855 unblock_point(x,y); 856 newsym(x,y); 857 /* force vision recalc before printing more messages */ 858 if (vision_full_recalc) vision_recalc(0); 859 loudness = 20; 860 } else res = FALSE; 861 break; 862 default: impossible("magic (%d) attempted on door.", otmp->otyp); 863 break; 864 } 865 if (msg && cansee(x,y)) pline(msg); 866 if (loudness > 0) { 867 /* door was destroyed */ 868 wake_nearto(x, y, loudness); 869 if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); 870 } 871 872 if (res && picking_at(x, y)) { 873 /* maybe unseen monster zaps door you're unlocking */ 874 stop_occupation(); 875 reset_pick(); 876 } 877 return res; 878} 879 880STATIC_OVL void 881chest_shatter_msg(otmp) 882struct obj *otmp; 883{ 884 const char *disposition; 885 const char *thing; 886 long save_Blinded; 887 888 if (otmp->oclass == POTION_CLASS) { 889 You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename())); 890 if (!breathless(youmonst.data) || haseyes(youmonst.data)) 891 potionbreathe(otmp); 892 return; 893 } 894 /* We have functions for distant and singular names, but not one */ 895 /* which does _both_... */ 896 save_Blinded = Blinded; 897 Blinded = 1; 898 thing = singular(otmp, xname); 899 Blinded = save_Blinded; 900 switch (objects[otmp->otyp].oc_material) { 901 case PAPER: disposition = "is torn to shreds"; 902 break; 903 case WAX: disposition = "is crushed"; 904 break; 905 case VEGGY: disposition = "is pulped"; 906 break; 907 case FLESH: disposition = "is mashed"; 908 break; 909 case GLASS: disposition = "shatters"; 910 break; 911 case WOOD: disposition = "splinters to fragments"; 912 break; 913 default: disposition = "is destroyed"; 914 break; 915 } 916 pline("%s %s!", An(thing), disposition); 917} 918 919#endif /* OVLB */ 920 921/*lock.c*/ 922