OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / lock.c
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
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_DCL const char *NDECL(lock_action);
20 STATIC_DCL boolean FDECL(obstructed,(int,int));
21 STATIC_DCL 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_OVL 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(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
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(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
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 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
436 int
437 doforce()               /* 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
499 int
500 doopen()                /* 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
583 STATIC_OVL
584 boolean
585 obstructed(x,y)
586 register 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)) {
599 objhere:        pline("%s's in the way.", Something);
600                 return(TRUE);
601         }
602         return(FALSE);
603 }
604
605 int
606 doclose()               /* 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
700 boolean                 /* box obj was hit with spell effect otmp */
701 boxlock(obj, otmp)      /* returns true if something happened */
702 register 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
736 boolean                 /* Door/secret door was hit with spell effect otmp */
737 doorlock(otmp,x,y)      /* returns true if something happened */
738 struct obj *otmp;
739 int 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
880 STATIC_OVL void
881 chest_shatter_msg(otmp)
882 struct 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*/