1 /*      SCCS Id: @(#)lock.c     3.2     96/05/31        */
  2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3 /* NetHack may be freely redistributed.  See license for details. */
  4 
  5 #include "hack.h"
  6 
  7 STATIC_PTR int NDECL(picklock);
  8 STATIC_PTR int NDECL(forcelock);
  9 
 10 /* at most one of `door' and `box' should be non-null at any given time */
 11 STATIC_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 
 19 static const char *NDECL(lock_action);
 20 static boolean FDECL(obstructed,(int,int));
 21 static void FDECL(chest_shatter_msg, (struct obj *));
 22 
 23 boolean
 24 picking_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 
 37 boolean
 38 picking_at(x, y)
 39 int 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 */
 45 static const char *
 46 lock_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 
 74 STATIC_PTR
 75 int
 76 picklock()      /* 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(uasmon)) {
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 
129 STATIC_PTR
130 int
131 forcelock()     /* 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(uasmon)) {
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-(int)uwep->oeroded*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 zorkmids for objects destroyed.", 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 
214 void
215 reset_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 
225 int
226 pick_lock(pick) /* pick a lock with a given object */
227         register struct obj     *pick;
228 {
229         int x, y, picktyp, c, ch;
230         struct rm       *door;
231         struct obj      *otmp;
232         char qbuf[QBUFSZ];
233 
234         picktyp = pick->otyp;
235 
236         /* check whether we're resuming an interrupted previous attempt */
237         if (xlock.usedtime && picktyp == xlock.picktyp) {
238             static char no_longer[] = "Unfortunately, you can no longer %s %s.";
239 
240             if (nohands(uasmon)) {
241                 const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";
242 #ifdef TOURIST
243                 if (picktyp == CREDIT_CARD) what = "card";
244 #endif
245                 pline(no_longer, "hold the", what);
246                 reset_pick();
247                 return 0;
248             } else if (xlock.box && !can_reach_floor()) {
249                 pline(no_longer, "reach the", "lock");
250                 reset_pick();
251                 return 0;
252             } else {
253                 const char *action = lock_action();
254                 You("resume your attempt at %s.", action);
255                 set_occupation(picklock, action, 0);
256                 return(1);
257             }
258         }
259 
260         if(nohands(uasmon)) {
261                 You_cant("hold %s -- you have no hands!", doname(pick));
262                 return(0);
263         }
264 
265         if((picktyp != LOCK_PICK &&
266 #ifdef TOURIST
267             picktyp != CREDIT_CARD &&
268 #endif
269             picktyp != SKELETON_KEY)) {
270                 impossible("picking lock with object %d?", picktyp);
271                 return(0);
272         }
273         if(!getdir((char *)0)) return(0);
274 
275         ch = 0;         /* lint suppression */
276         x = u.ux + u.dx;
277         y = u.uy + u.dy;
278         if (x == u.ux && y == u.uy) {   /* pick lock on a container */
279             const char *verb;
280             boolean it;
281             int count;
282 
283             if (u.dz < 0) {
284                 pline("There isn't any sort of lock up %s.",
285                       Levitation ? "here" : "there");
286                 return 0;
287             } else if (is_lava(u.ux, u.uy)) {
288                 pline("Doing that would probably melt your %s.",
289                       xname(pick));
290                 return 0;
291             } else if (is_pool(u.ux, u.uy) && !Underwater) {
292                 pline_The("water has no lock.");
293                 return 0;
294             }
295 
296             count = 0;
297             c = 'n';                    /* in case there are no boxes here */
298             for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
299                 if (Is_box(otmp)) {
300                     ++count;
301                     if (!can_reach_floor()) {
302                         You_cant("reach %s from up here.", the(xname(otmp)));
303                         return 0;
304                     }
305                     it = 0;
306                     if (otmp->obroken) verb = "fix";
307                     else if (!otmp->olocked) verb = "lock", it = 1;
308                     else if (picktyp != LOCK_PICK) verb = "unlock", it = 1;
309                     else verb = "pick";
310                     Sprintf(qbuf, "There is %s here, %s %s?",
311                             doname(otmp), verb, it ? "it" : "its lock");
312 
313                     c = ynq(qbuf);
314                     if(c == 'q') return(0);
315                     if(c == 'n') continue;
316 
317                     if (otmp->obroken) {
318                         You_cant("fix its broken lock with %s.", doname(pick));
319                         return 0;
320                     }
321 #ifdef TOURIST
322                     else if (picktyp == CREDIT_CARD && !otmp->olocked) {
323                         /* credit cards are only good for unlocking */
324                         You_cant("do that with %s.", doname(pick));
325                         return 0;
326                     }
327 #endif
328                     switch(picktyp) {
329 #ifdef TOURIST
330                         case CREDIT_CARD:
331                             ch = ACURR(A_DEX) + 20*Role_is('R');
332                             break;
333 #endif
334                         case LOCK_PICK:
335                             ch = 4*ACURR(A_DEX) + 25*Role_is('R');
336                             break;
337                         case SKELETON_KEY:
338                             ch = 75 + ACURR(A_DEX);
339                             break;
340                         default:        ch = 0;
341                     }
342                     if(otmp->cursed) ch /= 2;
343 
344                     xlock.picktyp = picktyp;
345                     xlock.box = otmp;
346                     xlock.door = 0;
347                     break;
348                 }
349             if (c != 'y') {
350                 if (!count)
351                     pline("There doesn't seem to be any sort of lock here.");
352                 return(0);              /* decided against all boxes */
353             }
354         } else {                        /* pick the lock in a door */
355             struct monst *mtmp;
356 
357             door = &levl[x][y];
358             if ((mtmp = m_at(x, y)) && canseemon(mtmp)
359                         && mtmp->m_ap_type != M_AP_FURNITURE
360                         && mtmp->m_ap_type != M_AP_OBJECT) {
361 #ifdef TOURIST
362                 if (picktyp == CREDIT_CARD &&
363                     (mtmp->isshk || mtmp->data == &mons[PM_ORACLE]))
364                     verbalize("No checks, no credit, no problem.");
365                 else
366 #endif
367                     pline("I don't think %s would appreciate that.", mon_nam(mtmp));
368                 return(0);
369             }
370             if(!IS_DOOR(door->typ)) {
371                 if (is_drawbridge_wall(x,y) >= 0)
372                     You("%s no lock on the drawbridge.",
373                                 Blind ? "feel" : "see");
374                 else
375                     You("%s no door there.",
376                                 Blind ? "feel" : "see");
377                 return(0);
378             }
379             switch (door->doormask) {
380                 case D_NODOOR:
381                     pline("This doorway has no door.");
382                     return(0);
383                 case D_ISOPEN:
384                     You("cannot lock an open door.");
385                     return(0);
386                 case D_BROKEN:
387                     pline("This door is broken.");
388                     return(0);
389                 default:
390 #ifdef TOURIST
391                     /* credit cards are only good for unlocking */
392                     if(picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) {
393                         You_cant("lock a door with a credit card.");
394                         return(0);
395                     }
396 #endif
397 
398                     Sprintf(qbuf,"%sock it?",
399                         (door->doormask & D_LOCKED) ? "Unl" : "L" );
400 
401                     c = yn(qbuf);
402                     if(c == 'n') return(0);
403 
404                     switch(picktyp) {
405 #ifdef TOURIST
406                         case CREDIT_CARD:
407                             ch = 2*ACURR(A_DEX) + 20*Role_is('R');
408                             break;
409 #endif
410                         case LOCK_PICK:
411                             ch = 3*ACURR(A_DEX) + 30*Role_is('R');
412                             break;
413                         case SKELETON_KEY:
414                             ch = 70 + ACURR(A_DEX);
415                             break;
416                         default:    ch = 0;
417                     }
418                     xlock.door = door;
419                     xlock.box = 0;
420             }
421         }
422         flags.move = 0;
423         xlock.chance = ch;
424         xlock.picktyp = picktyp;
425         xlock.usedtime = 0;
426         set_occupation(picklock, lock_action(), 0);
427         return(1);
428 }
429 
430 int
431 doforce()               /* try to force a chest with your weapon */
432 {
433         register struct obj *otmp;
434         register int c, picktyp;
435         char qbuf[QBUFSZ];
436 
437         if(!uwep ||     /* proper type test */
438            (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep) &&
439             uwep->oclass != ROCK_CLASS) ||
440            (uwep->oclass != ROCK_CLASS &&
441             (objects[uwep->otyp].oc_wepcat == WEP_BOW ||
442              objects[uwep->otyp].oc_wepcat == WEP_AMMO ||
443              objects[uwep->otyp].oc_wepcat == WEP_MISSILE))
444            || (uwep->otyp > QUARTERSTAFF && uwep->otyp < BULLWHIP)
445 #ifdef KOPS
446            || uwep->otyp == RUBBER_HOSE
447 #endif
448           ) {
449             You_cant("force anything without a %sweapon.",
450                   (uwep) ? "proper " : "");
451             return(0);
452         }
453 
454         picktyp = is_blade(uwep);
455         if(xlock.usedtime && xlock.box && picktyp == xlock.picktyp) {
456             You("resume your attempt to force the lock.");
457             set_occupation(forcelock, "forcing the lock", 0);
458             return(1);
459         }
460 
461         /* A lock is made only for the honest man, the thief will break it. */
462         xlock.box = (struct obj *)0;
463         for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere)
464             if(Is_box(otmp)) {
465                 if (otmp->obroken || !otmp->olocked) {
466                     pline("There is %s here, but its lock is already %s.",
467                           doname(otmp), otmp->obroken ? "broken" : "unlocked");
468                     continue;
469                 }
470                 Sprintf(qbuf,"There is %s here, force its lock?", doname(otmp));
471 
472                 c = ynq(qbuf);
473                 if(c == 'q') return(0);
474                 if(c == 'n') continue;
475 
476                 if(picktyp)
477                     You("force your %s into a crack and pry.", xname(uwep));
478                 else
479                     You("start bashing it with your %s.", xname(uwep));
480                 xlock.box = otmp;
481                 xlock.chance = objects[otmp->otyp].oc_wldam * 2;
482                 xlock.picktyp = picktyp;
483                 xlock.usedtime = 0;
484                 break;
485             }
486 
487         if(xlock.box)   set_occupation(forcelock, "forcing the lock", 0);
488         else            You("decide not to force the issue.");
489         return(1);
490 }
491 
492 int
493 doopen()                /* try to open a door */
494 {
495         register int x, y;
496         register struct rm *door;
497         struct monst *mtmp;
498 
499         if (u.utrap && u.utraptype == TT_PIT) {
500             You_cant("reach over the edge of the pit.");
501             return 0;
502         }
503 
504         if(!getdir((char *)0)) return(0);
505 
506         x = u.ux + u.dx;
507         y = u.uy + u.dy;
508         if((x == u.ux) && (y == u.uy)) return(0);
509 
510         if ((mtmp = m_at(x,y))                          &&
511                 mtmp->m_ap_type == M_AP_FURNITURE       &&
512                 (mtmp->mappearance == S_hcdoor ||
513                         mtmp->mappearance == S_vcdoor)  &&
514                 !Protection_from_shape_changers)         {
515 
516             stumble_onto_mimic(mtmp);
517             return(1);
518         }
519 
520         door = &levl[x][y];
521 
522         if(!IS_DOOR(door->typ)) {
523                 if (is_db_wall(x,y)) {
524                     pline("There is no obvious way to open the drawbridge.");
525                     return(0);
526                 }
527                 You("%s no door there.",
528                                 Blind ? "feel" : "see");
529                 return(0);
530         }
531 
532         if (!(door->doormask & D_CLOSED)) {
533             const char *mesg;
534 
535             switch (door->doormask) {
536             case D_BROKEN: mesg = " is broken"; break;
537             case D_NODOOR: mesg = "way has no door"; break;
538             case D_ISOPEN: mesg = " is already open"; break;
539             default:       mesg = " is locked"; break;
540             }
541             pline("This door%s.", mesg);
542             if (Blind) feel_location(x,y);
543             return(0);
544         }
545 
546         if(verysmall(uasmon)) {
547             pline("You're too small to pull the door open.");
548             return(0);
549         }
550 
551         /* door is known to be CLOSED */
552         if (rnl(20) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
553             pline_The("door opens.");
554             if(door->doormask & D_TRAPPED) {
555                 b_trapped("door", FINGER);
556                 door->doormask = D_NODOOR;
557                 if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
558             } else
559                 door->doormask = D_ISOPEN;
560             if (Blind)
561                 feel_location(x,y);     /* the hero knows she opened it  */
562             else
563                 newsym(x,y);
564             unblock_point(x,y);         /* vision: new see through there */
565         } else {
566             exercise(A_STR, TRUE);
567             pline_The("door resists!");
568         }
569 
570         return(1);
571 }
572 
573 static
574 boolean
575 obstructed(x,y)
576 register int x, y;
577 {
578         register struct monst *mtmp = m_at(x, y);
579 
580         if(mtmp && mtmp->m_ap_type != M_AP_FURNITURE) {
581                 if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere;
582                 pline("%s stands in the way!", Blind ?
583                         "Some creature" : Monnam(mtmp));
584                 return(TRUE);
585         }
586         if (OBJ_AT(x, y)) {
587 objhere:        pline("%s's in the way.", Something);
588                 return(TRUE);
589         }
590         return(FALSE);
591 }
592 
593 int
594 doclose()               /* try to close a door */
595 {
596         register int x, y;
597         register struct rm *door;
598         struct monst *mtmp;
599 
600         if (u.utrap && u.utraptype == TT_PIT) {
601             You_cant("reach over the edge of the pit.");
602             return 0;
603         }
604 
605         if(!getdir((char *)0)) return(0);
606 
607         x = u.ux + u.dx;
608         y = u.uy + u.dy;
609         if((x == u.ux) && (y == u.uy)) {
610                 You("are in the way!");
611                 return(1);
612         }
613 
614         if ((mtmp = m_at(x,y))                          &&
615                 mtmp->m_ap_type == M_AP_FURNITURE       &&
616                 (mtmp->mappearance == S_hcdoor ||
617                         mtmp->mappearance == S_vcdoor)  &&
618                 !Protection_from_shape_changers)         {
619 
620             stumble_onto_mimic(mtmp);
621             return(1);
622         }
623 
624         door = &levl[x][y];
625 
626         if(!IS_DOOR(door->typ)) {
627                 if (door->typ == DRAWBRIDGE_DOWN)
628                     pline("There is no obvious way to close the drawbridge.");
629                 else
630                     You("%s no door there.",
631                                 Blind ? "feel" : "see");
632                 return(0);
633         }
634 
635         if(door->doormask == D_NODOOR) {
636             pline("This doorway has no door.");
637             return(0);
638         }
639 
640         if(obstructed(x, y)) return(0);
641 
642         if(door->doormask == D_BROKEN) {
643             pline("This door is broken.");
644             return(0);
645         }
646 
647         if(door->doormask & (D_CLOSED | D_LOCKED)) {
648             pline("This door is already closed.");
649             return(0);
650         }
651 
652         if(door->doormask == D_ISOPEN) {
653             if(verysmall(uasmon)) {
654                  pline("You're too small to push the door closed.");
655                  return(0);
656             }
657             if (rn2(25) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
658                 pline_The("door closes.");
659                 door->doormask = D_CLOSED;
660                 if (Blind)
661                     feel_location(x,y); /* the hero knows she closed it */
662                 else
663                     newsym(x,y);
664                 block_point(x,y);       /* vision:  no longer see there */
665             }
666             else {
667                 exercise(A_STR, TRUE);
668                 pline_The("door resists!");
669             }
670         }
671 
672         return(1);
673 }
674 
675 boolean                 /* box obj was hit with spell effect otmp */
676 boxlock(obj, otmp)      /* returns true if something happened */
677 register struct obj *obj, *otmp;        /* obj *is* a box */
678 {
679         register boolean res = 0;
680 
681         switch(otmp->otyp) {
682         case WAN_LOCKING:
683         case SPE_WIZARD_LOCK:
684             if (!obj->olocked) {        /* lock it; fix if broken */
685                 pline("Klunk!");
686                 obj->olocked = 1;
687                 obj->obroken = 0;
688                 res = 1;
689             } /* else already closed and locked */
690             break;
691         case WAN_OPENING:
692         case SPE_KNOCK:
693             if (obj->olocked) {         /* unlock; couldn't be broken */
694                 pline("Klick!");
695                 obj->olocked = 0;
696                 res = 1;
697             } else                      /* silently fix if broken */
698                 obj->obroken = 0;
699             break;
700         case WAN_POLYMORPH:
701         case SPE_POLYMORPH:
702             /* maybe start unlocking chest, get interrupted, then zap it;
703                we must avoid any attempt to resume unlocking it */
704             if (xlock.box == obj)
705                 reset_pick();
706             break;
707         }
708         return res;
709 }
710 
711 boolean                 /* Door/secret door was hit with spell effect otmp */
712 doorlock(otmp,x,y)      /* returns true if something happened */
713 struct obj *otmp;
714 int x, y;
715 {
716         register struct rm *door = &levl[x][y];
717         boolean res = TRUE;
718         int loudness = 0;
719         const char *msg = (const char *)0;
720         const char *dustcloud = "A cloud of dust";
721         const char *quickly_dissipates = "quickly dissipates";
722         
723         if (door->typ == SDOOR) {
724             switch (otmp->otyp) {
725             case WAN_OPENING:
726             case SPE_KNOCK:
727             case WAN_STRIKING:
728             case SPE_FORCE_BOLT:
729                 door->typ = DOOR;
730                 door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
731                 newsym(x,y);
732                 if (cansee(x,y)) pline("A door appears in the wall!");
733                 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK)
734                     return TRUE;
735                 break;          /* striking: continue door handling below */
736             case WAN_LOCKING:
737             case SPE_WIZARD_LOCK:
738             default:
739                 return FALSE;
740             }
741         }
742 
743         switch(otmp->otyp) {
744         case WAN_LOCKING:
745         case SPE_WIZARD_LOCK:
746 #ifdef REINCARNATION
747             if (Is_rogue_level(&u.uz)) {
748                 /* Can't have real locking in Rogue, so just hide doorway */
749                 pline("%s springs up in the older, more primitive doorway.",
750                         dustcloud);
751                 if (obstructed(x,y)) {
752                         pline_The("cloud %s.",quickly_dissipates);
753                         return FALSE;
754                 }
755                 block_point(x, y);
756                 door->typ = SDOOR;
757                 if (cansee(x,y)) pline_The("doorway vanishes!");
758                 newsym(x,y);
759                 return TRUE;
760             }
761 #endif
762             if (obstructed(x,y)) return FALSE;
763             /* Don't allow doors to close over traps.  This is for pits */
764             /* & trap doors, but is it ever OK for anything else? */
765             if (t_at(x,y)) {
766                 /* maketrap() clears doormask, so it should be NODOOR */
767                 pline(
768                 "%s springs up in the doorway, but %s.",
769                 dustcloud, quickly_dissipates);
770                 return FALSE;
771             }
772 
773             switch (door->doormask & ~D_TRAPPED) {
774             case D_CLOSED:
775                 msg = "The door locks!";
776                 break;
777             case D_ISOPEN:
778                 msg = "The door swings shut, and locks!";
779                 break;
780             case D_BROKEN:
781                 msg = "The broken door reassembles and locks!";
782                 break;
783             case D_NODOOR:
784                 msg =
785                 "A cloud of dust springs up and assembles itself into a door!";
786                 break;
787             default:
788                 res = FALSE;
789                 break;
790             }
791             block_point(x, y);
792             door->doormask = D_LOCKED | (door->doormask & D_TRAPPED);
793             newsym(x,y);
794             break;
795         case WAN_OPENING:
796         case SPE_KNOCK:
797             if (door->doormask & D_LOCKED) {
798                 msg = "The door unlocks!";
799                 door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
800             } else res = FALSE;
801             break;
802         case WAN_STRIKING:
803         case SPE_FORCE_BOLT:
804             if (door->doormask & (D_LOCKED | D_CLOSED)) {
805                 if (door->doormask & D_TRAPPED) {
806                     if (MON_AT(x, y))
807                         (void) mb_trapped(m_at(x,y));
808                     else if (flags.verbose) {
809                         if (cansee(x,y))
810                             pline("KABOOM!!  You see a door explode.");
811                         else if (flags.soundok)
812                             You_hear("a distant explosion.");
813                     }
814                     door->doormask = D_NODOOR;
815                     unblock_point(x,y);
816                     newsym(x,y);
817                     loudness = 40;
818                     break;
819                 }
820                 door->doormask = D_BROKEN;
821                 if (flags.verbose) {
822                     if (cansee(x,y))
823                         pline_The("door crashes open!");
824                     else if (flags.soundok)
825                         You_hear("a crashing sound.");
826                 }
827                 unblock_point(x,y);
828                 newsym(x,y);
829                 loudness = 20;
830             } else res = FALSE;
831             break;
832         default: impossible("magic (%d) attempted on door.", otmp->otyp);
833             break;
834         }
835         if (msg && cansee(x,y)) pline(msg);
836         if (loudness > 0) {
837             /* door was destroyed */
838             wake_nearto(x, y, loudness);
839             if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
840         }
841 
842         if (res && picking_at(x, y)) {
843             /* maybe unseen monster zaps door you're unlocking */
844             stop_occupation();
845             reset_pick();
846         }
847         return res;
848 }
849 
850 static void
851 chest_shatter_msg(otmp)
852 struct obj *otmp;
853 {
854         const char *disposition, *article = (otmp->quan > 1L) ? "A" : "The";
855         const char *thing;
856         long save_Blinded;
857 
858         if (otmp->oclass == POTION_CLASS) {
859                 You("%s a flask shatter!", Blind ? "hear" : "see");
860                 potionbreathe(otmp);
861                 return;
862         }
863         /* We have functions for distant and singular names, but not one */
864         /* which does _both_... */
865         save_Blinded = Blinded;
866         Blinded = 1;
867         thing = singular(otmp, xname);
868         Blinded = save_Blinded;
869         switch (objects[otmp->otyp].oc_material) {
870         case PAPER:     disposition = "is torn to shreds";
871                 break;
872         case WAX:       disposition = "is crushed";
873                 break;
874         case VEGGY:     disposition = "is pulped";
875                 break;
876         case FLESH:     disposition = "is mashed";
877                 break;
878         case GLASS:     disposition = "shatters";
879                 break;
880         case WOOD:      disposition = "splinters to fragments";
881                 break;
882         default:        disposition = "is destroyed";
883                 break;
884         }
885         pline("%s %s %s!", article, thing, disposition);
886 }
887 
888 #endif /* OVLB */
889 
890 /*lock.c*/
891 


