1 /* NetHack 3.6 lock.c $NHDT-Date: 1446955300 2015/11/08 04:01:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.67 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_PTR
int NDECL(picklock
);
8 STATIC_PTR
int NDECL(forcelock
);
10 /* at most one of `door' and `box' should be non-null at any given time */
11 STATIC_VAR NEARDATA
struct xlock_s
{
14 int picktyp
, /* key|pick|card for unlock, sharp vs blunt for #force */
18 STATIC_DCL
const char *NDECL(lock_action
);
19 STATIC_DCL boolean
FDECL(obstructed
, (int, int, BOOLEAN_P
));
20 STATIC_DCL
void FDECL(chest_shatter_msg
, (struct obj
*));
26 if (occupation
== picklock
) {
40 return (boolean
) (occupation
== picklock
&& xlock
.door
== &levl
[x
][y
]);
43 /* produce an occupation string appropriate for the current activity */
44 STATIC_OVL
const char *
47 /* "unlocking"+2 == "locking" */
48 static const char *actions
[] = {
49 "unlocking the door", /* [0] */
50 "unlocking the chest", /* [1] */
51 "unlocking the box", /* [2] */
52 "picking the lock" /* [3] */
55 /* if the target is currently unlocked, we're trying to lock it now */
56 if (xlock
.door
&& !(xlock
.door
->doormask
& D_LOCKED
))
57 return actions
[0] + 2; /* "locking the door" */
58 else if (xlock
.box
&& !xlock
.box
->olocked
)
59 return xlock
.box
->otyp
== CHEST
? actions
[1] + 2 : actions
[2] + 2;
60 /* otherwise we're trying to unlock it */
61 else if (xlock
.picktyp
== LOCK_PICK
)
62 return actions
[3]; /* "picking the lock" */
63 else if (xlock
.picktyp
== CREDIT_CARD
)
64 return actions
[3]; /* same as lock_pick */
66 return actions
[0]; /* "unlocking the door" */
68 return xlock
.box
->otyp
== CHEST
? actions
[1] : actions
[2];
73 /* try to open/close a lock */
78 if ((xlock
.box
->ox
!= u
.ux
) || (xlock
.box
->oy
!= u
.uy
)) {
79 return ((xlock
.usedtime
= 0)); /* you or it moved */
82 if (xlock
.door
!= &(levl
[u
.ux
+ u
.dx
][u
.uy
+ u
.dy
])) {
83 return ((xlock
.usedtime
= 0)); /* you moved */
85 switch (xlock
.door
->doormask
) {
87 pline("This doorway has no door.");
88 return ((xlock
.usedtime
= 0));
90 You("cannot lock an open door.");
91 return ((xlock
.usedtime
= 0));
93 pline("This door is broken.");
94 return ((xlock
.usedtime
= 0));
98 if (xlock
.usedtime
++ >= 50 || nohands(youmonst
.data
)) {
99 You("give up your attempt at %s.", lock_action());
100 exercise(A_DEX
, TRUE
); /* even if you don't succeed */
101 return ((xlock
.usedtime
= 0));
104 if (rn2(100) >= xlock
.chance
)
105 return 1; /* still busy */
107 You("succeed in %s.", lock_action());
109 if (xlock
.door
->doormask
& D_TRAPPED
) {
110 b_trapped("door", FINGER
);
111 xlock
.door
->doormask
= D_NODOOR
;
112 unblock_point(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
);
113 if (*in_rooms(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
, SHOPBASE
))
114 add_damage(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
, 0L);
115 newsym(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
);
116 } else if (xlock
.door
->doormask
& D_LOCKED
)
117 xlock
.door
->doormask
= D_CLOSED
;
119 xlock
.door
->doormask
= D_LOCKED
;
121 xlock
.box
->olocked
= !xlock
.box
->olocked
;
122 xlock
.box
->lknown
= 1;
123 if (xlock
.box
->otrapped
)
124 (void) chest_trap(xlock
.box
, FINGER
, FALSE
);
126 exercise(A_DEX
, TRUE
);
127 return ((xlock
.usedtime
= 0));
131 breakchestlock(box
, destroyit
)
135 if (!destroyit
) { /* bill for the box but not for its contents */
136 struct obj
*hide_contents
= box
->cobj
;
139 costly_alteration(box
, COST_BRKLCK
);
140 box
->cobj
= hide_contents
;
144 } else { /* #force has destroyed this box (at <u.ux,u.uy>) */
146 struct monst
*shkp
= (*u
.ushops
&& costly_spot(u
.ux
, u
.uy
))
147 ? shop_keeper(*u
.ushops
)
149 boolean costly
= (boolean
) (shkp
!= 0),
150 peaceful_shk
= costly
&& (boolean
) shkp
->mpeaceful
;
153 pline("In fact, you've totally destroyed %s.", the(xname(box
)));
154 /* Put the contents on ground at the hero's feet. */
155 while ((otmp
= box
->cobj
) != 0) {
156 obj_extract_self(otmp
);
157 if (!rn2(3) || otmp
->oclass
== POTION_CLASS
) {
158 chest_shatter_msg(otmp
);
161 stolen_value(otmp
, u
.ux
, u
.uy
, peaceful_shk
, TRUE
);
162 if (otmp
->quan
== 1L) {
163 obfree(otmp
, (struct obj
*) 0);
168 if (box
->otyp
== ICE_BOX
&& otmp
->otyp
== CORPSE
) {
169 otmp
->age
= monstermoves
- otmp
->age
; /* actual age */
170 start_corpse_timeout(otmp
);
172 place_object(otmp
, u
.ux
, u
.uy
);
176 loss
+= stolen_value(box
, u
.ux
, u
.uy
, peaceful_shk
, TRUE
);
178 You("owe %ld %s for objects destroyed.", loss
, currency(loss
));
183 /* try to force a locked chest */
187 if ((xlock
.box
->ox
!= u
.ux
) || (xlock
.box
->oy
!= u
.uy
))
188 return ((xlock
.usedtime
= 0)); /* you or it moved */
190 if (xlock
.usedtime
++ >= 50 || !uwep
|| nohands(youmonst
.data
)) {
191 You("give up your attempt to force the lock.");
192 if (xlock
.usedtime
>= 50) /* you made the effort */
193 exercise((xlock
.picktyp
) ? A_DEX
: A_STR
, TRUE
);
194 return ((xlock
.usedtime
= 0));
197 if (xlock
.picktyp
) { /* blade */
198 if (rn2(1000 - (int) uwep
->spe
) > (992 - greatest_erosion(uwep
) * 10)
199 && !uwep
->cursed
&& !obj_resists(uwep
, 0, 99)) {
200 /* for a +0 weapon, probability that it survives an unsuccessful
201 * attempt to force the lock is (.992)^50 = .67
203 pline("%sour %s broke!", (uwep
->quan
> 1L) ? "One of y" : "Y",
206 You("give up your attempt to force the lock.");
207 exercise(A_DEX
, TRUE
);
208 return ((xlock
.usedtime
= 0));
211 wake_nearby(); /* due to hammering on the container */
213 if (rn2(100) >= xlock
.chance
)
214 return 1; /* still busy */
216 You("succeed in forcing the lock.");
217 breakchestlock(xlock
.box
, (boolean
) (!xlock
.picktyp
&& !rn2(3)));
219 exercise((xlock
.picktyp
) ? A_DEX
: A_STR
, TRUE
);
220 return ((xlock
.usedtime
= 0));
226 xlock
.usedtime
= xlock
.chance
= xlock
.picktyp
= 0;
231 /* for doapply(); if player gives a direction or resumes an interrupted
232 previous attempt then it costs hero a move even if nothing ultimately
233 happens; when told "can't do that" before being asked for direction
234 or player cancels with ESC while giving direction, it doesn't */
235 #define PICKLOCK_LEARNED_SOMETHING (-1) /* time passes */
236 #define PICKLOCK_DID_NOTHING 0 /* no time passes */
237 #define PICKLOCK_DID_SOMETHING 1
239 /* player is applying a key, lock pick, or credit card */
250 picktyp
= pick
->otyp
;
252 /* check whether we're resuming an interrupted previous attempt */
253 if (xlock
.usedtime
&& picktyp
== xlock
.picktyp
) {
254 static char no_longer
[] = "Unfortunately, you can no longer %s %s.";
256 if (nohands(youmonst
.data
)) {
257 const char *what
= (picktyp
== LOCK_PICK
) ? "pick" : "key";
258 if (picktyp
== CREDIT_CARD
)
260 pline(no_longer
, "hold the", what
);
262 return PICKLOCK_LEARNED_SOMETHING
;
263 } else if (u
.uswallow
|| (xlock
.box
&& !can_reach_floor(TRUE
))) {
264 pline(no_longer
, "reach the", "lock");
266 return PICKLOCK_LEARNED_SOMETHING
;
268 const char *action
= lock_action();
270 You("resume your attempt at %s.", action
);
271 set_occupation(picklock
, action
, 0);
272 return PICKLOCK_DID_SOMETHING
;
276 if (nohands(youmonst
.data
)) {
277 You_cant("hold %s -- you have no hands!", doname(pick
));
278 return PICKLOCK_DID_NOTHING
;
279 } else if (u
.uswallow
) {
280 You_cant("%sunlock %s.", (picktyp
== CREDIT_CARD
) ? "" : "lock or ",
282 return PICKLOCK_DID_NOTHING
;
285 if ((picktyp
!= LOCK_PICK
&& picktyp
!= CREDIT_CARD
286 && picktyp
!= SKELETON_KEY
)) {
287 impossible("picking lock with object %d?", picktyp
);
288 return PICKLOCK_DID_NOTHING
;
290 ch
= 0; /* lint suppression */
292 if (!get_adjacent_loc((char *) 0, "Invalid location!", u
.ux
, u
.uy
, &cc
))
293 return PICKLOCK_DID_NOTHING
;
295 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) { /* pick lock on a container */
302 There("isn't any sort of lock up %s.",
303 Levitation
? "here" : "there");
304 return PICKLOCK_LEARNED_SOMETHING
;
305 } else if (is_lava(u
.ux
, u
.uy
)) {
306 pline("Doing that would probably melt %s.", yname(pick
));
307 return PICKLOCK_LEARNED_SOMETHING
;
308 } else if (is_pool(u
.ux
, u
.uy
) && !Underwater
) {
309 pline_The("water has no lock.");
310 return PICKLOCK_LEARNED_SOMETHING
;
314 c
= 'n'; /* in case there are no boxes here */
315 for (otmp
= level
.objects
[cc
.x
][cc
.y
]; otmp
; otmp
= otmp
->nexthere
)
318 if (!can_reach_floor(TRUE
)) {
319 You_cant("reach %s from up here.", the(xname(otmp
)));
320 return PICKLOCK_LEARNED_SOMETHING
;
325 else if (!otmp
->olocked
)
326 verb
= "lock", it
= 1;
327 else if (picktyp
!= LOCK_PICK
)
328 verb
= "unlock", it
= 1;
332 /* "There is <a box> here; <verb> <it|its lock>?" */
333 Sprintf(qsfx
, " here; %s %s?", verb
, it
? "it" : "its lock");
334 (void) safe_qbuf(qbuf
, "There is ", qsfx
, otmp
, doname
,
335 ansimpleoname
, "a box");
345 You_cant("fix its broken lock with %s.", doname(pick
));
346 return PICKLOCK_LEARNED_SOMETHING
;
347 } else if (picktyp
== CREDIT_CARD
&& !otmp
->olocked
) {
348 /* credit cards are only good for unlocking */
349 You_cant("do that with %s.",
350 an(simple_typename(picktyp
)));
351 return PICKLOCK_LEARNED_SOMETHING
;
355 ch
= ACURR(A_DEX
) + 20 * Role_if(PM_ROGUE
);
358 ch
= 4 * ACURR(A_DEX
) + 25 * Role_if(PM_ROGUE
);
361 ch
= 75 + ACURR(A_DEX
);
369 xlock
.picktyp
= picktyp
;
376 There("doesn't seem to be any sort of lock here.");
377 return PICKLOCK_LEARNED_SOMETHING
; /* decided against all boxes */
379 } else { /* pick the lock in a door */
382 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
383 You_cant("reach over the edge of the pit.");
384 return PICKLOCK_LEARNED_SOMETHING
;
387 door
= &levl
[cc
.x
][cc
.y
];
388 mtmp
= m_at(cc
.x
, cc
.y
);
389 if (mtmp
&& canseemon(mtmp
) && mtmp
->m_ap_type
!= M_AP_FURNITURE
390 && mtmp
->m_ap_type
!= M_AP_OBJECT
) {
391 if (picktyp
== CREDIT_CARD
392 && (mtmp
->isshk
|| mtmp
->data
== &mons
[PM_ORACLE
]))
393 verbalize("No checks, no credit, no problem.");
395 pline("I don't think %s would appreciate that.",
397 return PICKLOCK_LEARNED_SOMETHING
;
398 } else if (mtmp
&& is_door_mappear(mtmp
)) {
399 /* "The door actually was a <mimic>!" */
400 stumble_onto_mimic(mtmp
);
401 /* mimic might keep the key (50% chance, 10% for PYEC) */
402 maybe_absorb_item(mtmp
, pick
, 50, 10);
403 return PICKLOCK_LEARNED_SOMETHING
;
405 if (!IS_DOOR(door
->typ
)) {
406 if (is_drawbridge_wall(cc
.x
, cc
.y
) >= 0)
407 You("%s no lock on the drawbridge.", Blind
? "feel" : "see");
409 You("%s no door there.", Blind
? "feel" : "see");
410 return PICKLOCK_LEARNED_SOMETHING
;
412 switch (door
->doormask
) {
414 pline("This doorway has no door.");
415 return PICKLOCK_LEARNED_SOMETHING
;
417 You("cannot lock an open door.");
418 return PICKLOCK_LEARNED_SOMETHING
;
420 pline("This door is broken.");
421 return PICKLOCK_LEARNED_SOMETHING
;
423 /* credit cards are only good for unlocking */
424 if (picktyp
== CREDIT_CARD
&& !(door
->doormask
& D_LOCKED
)) {
425 You_cant("lock a door with a credit card.");
426 return PICKLOCK_LEARNED_SOMETHING
;
429 Sprintf(qbuf
, "%s it?",
430 (door
->doormask
& D_LOCKED
) ? "Unlock" : "Lock");
438 ch
= 2 * ACURR(A_DEX
) + 20 * Role_if(PM_ROGUE
);
441 ch
= 3 * ACURR(A_DEX
) + 30 * Role_if(PM_ROGUE
);
444 ch
= 70 + ACURR(A_DEX
);
455 xlock
.picktyp
= picktyp
;
457 set_occupation(picklock
, lock_action(), 0);
458 return PICKLOCK_DID_SOMETHING
;
461 /* try to force a chest with your weapon */
465 register struct obj
*otmp
;
466 register int c
, picktyp
;
470 You_cant("force anything from inside here.");
473 if (!uwep
/* proper type test */
474 || ((uwep
->oclass
== WEAPON_CLASS
|| is_weptool(uwep
))
475 ? (objects
[uwep
->otyp
].oc_skill
< P_DAGGER
476 || objects
[uwep
->otyp
].oc_skill
== P_FLAIL
477 || objects
[uwep
->otyp
].oc_skill
> P_LANCE
)
478 : uwep
->oclass
!= ROCK_CLASS
)) {
479 You_cant("force anything %s weapon.",
480 !uwep
? "when not wielding a"
481 : (uwep
->oclass
!= WEAPON_CLASS
&& !is_weptool(uwep
))
486 if (!can_reach_floor(TRUE
)) {
487 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
491 picktyp
= is_blade(uwep
) && !is_pick(uwep
);
492 if (xlock
.usedtime
&& xlock
.box
&& picktyp
== xlock
.picktyp
) {
493 You("resume your attempt to force the lock.");
494 set_occupation(forcelock
, "forcing the lock", 0);
498 /* A lock is made only for the honest man, the thief will break it. */
499 xlock
.box
= (struct obj
*) 0;
500 for (otmp
= level
.objects
[u
.ux
][u
.uy
]; otmp
; otmp
= otmp
->nexthere
)
502 if (otmp
->obroken
|| !otmp
->olocked
) {
503 There("is %s here, but its lock is already %s.", doname(otmp
),
504 otmp
->obroken
? "broken" : "unlocked");
508 (void) safe_qbuf(qbuf
, "There is ", " here; force its lock?",
509 otmp
, doname
, ansimpleoname
, "a box");
519 You("force %s into a crack and pry.", yname(uwep
));
521 You("start bashing it with %s.", yname(uwep
));
523 xlock
.chance
= objects
[uwep
->otyp
].oc_wldam
* 2;
524 xlock
.picktyp
= picktyp
;
530 set_occupation(forcelock
, "forcing the lock", 0);
532 You("decide not to force the issue.");
537 stumble_on_door_mimic(x
, y
)
542 if ((mtmp
= m_at(x
, y
)) && is_door_mappear(mtmp
)
543 && !Protection_from_shape_changers
) {
544 stumble_onto_mimic(mtmp
);
550 /* the 'O' command - try to open a door */
554 return doopen_indir(0, 0);
557 /* try to open a door in direction u.dx/u.dy */
563 register struct rm
*door
;
567 if (nohands(youmonst
.data
)) {
568 You_cant("open anything -- you have no hands!");
572 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
573 You_cant("reach over the edge of the pit.");
577 if (x
> 0 && y
> 0) {
580 } else if (!get_adjacent_loc((char *) 0, (char *) 0, u
.ux
, u
.uy
, &cc
))
583 if ((cc
.x
== u
.ux
) && (cc
.y
== u
.uy
))
586 if (stumble_on_door_mimic(cc
.x
, cc
.y
))
589 /* when choosing a direction is impaired, use a turn
590 regardless of whether a door is successfully targetted */
591 if (Confusion
|| Stunned
)
594 door
= &levl
[cc
.x
][cc
.y
];
595 portcullis
= (is_drawbridge_wall(cc
.x
, cc
.y
) >= 0);
597 int oldglyph
= door
->glyph
;
598 schar oldlastseentyp
= lastseentyp
[cc
.x
][cc
.y
];
600 feel_location(cc
.x
, cc
.y
);
601 if (door
->glyph
!= oldglyph
602 || lastseentyp
[cc
.x
][cc
.y
] != oldlastseentyp
)
603 res
= 1; /* learned something */
606 if (portcullis
|| !IS_DOOR(door
->typ
)) {
607 /* closed portcullis or spot that opened bridge would span */
608 if (is_db_wall(cc
.x
, cc
.y
) || door
->typ
== DRAWBRIDGE_UP
)
609 There("is no obvious way to open the drawbridge.");
610 else if (portcullis
|| door
->typ
== DRAWBRIDGE_DOWN
)
611 pline_The("drawbridge is already open.");
613 You("%s no door there.", Blind
? "feel" : "see");
617 if (!(door
->doormask
& D_CLOSED
)) {
620 switch (door
->doormask
) {
625 mesg
= "way has no door";
628 mesg
= " is already open";
634 pline("This door%s.", mesg
);
638 if (verysmall(youmonst
.data
)) {
639 pline("You're too small to pull the door open.");
643 /* door is known to be CLOSED */
644 if (rnl(20) < (ACURRSTR
+ ACURR(A_DEX
) + ACURR(A_CON
)) / 3) {
645 pline_The("door opens.");
646 if (door
->doormask
& D_TRAPPED
) {
647 b_trapped("door", FINGER
);
648 door
->doormask
= D_NODOOR
;
649 if (*in_rooms(cc
.x
, cc
.y
, SHOPBASE
))
650 add_damage(cc
.x
, cc
.y
, 0L);
652 door
->doormask
= D_ISOPEN
;
653 feel_newsym(cc
.x
, cc
.y
); /* the hero knows she opened it */
654 unblock_point(cc
.x
, cc
.y
); /* vision: new see through there */
656 exercise(A_STR
, TRUE
);
657 pline_The("door resists!");
664 obstructed(x
, y
, quietly
)
668 register struct monst
*mtmp
= m_at(x
, y
);
670 if (mtmp
&& mtmp
->m_ap_type
!= M_AP_FURNITURE
) {
671 if (mtmp
->m_ap_type
== M_AP_OBJECT
)
674 if ((mtmp
->mx
!= x
) || (mtmp
->my
!= y
)) {
676 pline("%s%s blocks the way!",
677 !canspotmon(mtmp
) ? Something
: s_suffix(Monnam(mtmp
)),
678 !canspotmon(mtmp
) ? "" : " tail");
680 pline("%s blocks the way!",
681 !canspotmon(mtmp
) ? "Some creature" : Monnam(mtmp
));
684 if (!canspotmon(mtmp
))
691 pline("%s's in the way.", Something
);
697 /* the 'C' command - try to close a door */
702 register struct rm
*door
;
706 if (nohands(youmonst
.data
)) {
707 You_cant("close anything -- you have no hands!");
711 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
712 You_cant("reach over the edge of the pit.");
716 if (!getdir((char *) 0))
721 if ((x
== u
.ux
) && (y
== u
.uy
)) {
722 You("are in the way!");
729 if (stumble_on_door_mimic(x
, y
))
732 /* when choosing a direction is impaired, use a turn
733 regardless of whether a door is successfully targetted */
734 if (Confusion
|| Stunned
)
738 portcullis
= (is_drawbridge_wall(x
, y
) >= 0);
740 int oldglyph
= door
->glyph
;
741 schar oldlastseentyp
= lastseentyp
[x
][y
];
744 if (door
->glyph
!= oldglyph
|| lastseentyp
[x
][y
] != oldlastseentyp
)
745 res
= 1; /* learned something */
748 if (portcullis
|| !IS_DOOR(door
->typ
)) {
749 /* is_db_wall: closed portcullis */
750 if (is_db_wall(x
, y
) || door
->typ
== DRAWBRIDGE_UP
)
751 pline_The("drawbridge is already closed.");
752 else if (portcullis
|| door
->typ
== DRAWBRIDGE_DOWN
)
753 There("is no obvious way to close the drawbridge.");
756 You("%s no door there.", Blind
? "feel" : "see");
761 if (door
->doormask
== D_NODOOR
) {
762 pline("This doorway has no door.");
764 } else if (obstructed(x
, y
, FALSE
)) {
766 } else if (door
->doormask
== D_BROKEN
) {
767 pline("This door is broken.");
769 } else if (door
->doormask
& (D_CLOSED
| D_LOCKED
)) {
770 pline("This door is already closed.");
774 if (door
->doormask
== D_ISOPEN
) {
775 if (verysmall(youmonst
.data
) && !u
.usteed
) {
776 pline("You're too small to push the door closed.");
780 || rn2(25) < (ACURRSTR
+ ACURR(A_DEX
) + ACURR(A_CON
)) / 3) {
781 pline_The("door closes.");
782 door
->doormask
= D_CLOSED
;
783 feel_newsym(x
, y
); /* the hero knows she closed it */
784 block_point(x
, y
); /* vision: no longer see there */
786 exercise(A_STR
, TRUE
);
787 pline_The("door resists!");
794 /* box obj was hit with spell or wand effect otmp;
795 returns true if something happened */
798 struct obj
*obj
, *otmp
; /* obj *is* a box */
802 switch (otmp
->otyp
) {
804 case SPE_WIZARD_LOCK
:
805 if (!obj
->olocked
) { /* lock it; fix if broken */
809 if (Role_if(PM_WIZARD
))
814 } /* else already closed and locked */
818 if (obj
->olocked
) { /* unlock; couldn't be broken */
822 if (Role_if(PM_WIZARD
))
826 } else /* silently fix if broken */
831 /* maybe start unlocking chest, get interrupted, then zap it;
832 we must avoid any attempt to resume unlocking it */
833 if (xlock
.box
== obj
)
840 /* Door/secret door was hit with spell or wand effect otmp;
841 returns true if something happened */
847 register struct rm
*door
= &levl
[x
][y
];
850 const char *msg
= (const char *) 0;
851 const char *dustcloud
= "A cloud of dust";
852 const char *quickly_dissipates
= "quickly dissipates";
853 boolean mysterywand
= (otmp
->oclass
== WAND_CLASS
&& !otmp
->dknown
);
855 if (door
->typ
== SDOOR
) {
856 switch (otmp
->otyp
) {
862 door
->doormask
= D_CLOSED
| (door
->doormask
& D_TRAPPED
);
865 pline("A door appears in the wall!");
866 if (otmp
->otyp
== WAN_OPENING
|| otmp
->otyp
== SPE_KNOCK
)
868 break; /* striking: continue door handling below */
870 case SPE_WIZARD_LOCK
:
876 switch (otmp
->otyp
) {
878 case SPE_WIZARD_LOCK
:
879 if (Is_rogue_level(&u
.uz
)) {
880 boolean vis
= cansee(x
, y
);
881 /* Can't have real locking in Rogue, so just hide doorway */
883 pline("%s springs up in the older, more primitive doorway.",
886 You_hear("a swoosh.");
887 if (obstructed(x
, y
, mysterywand
)) {
889 pline_The("cloud %s.", quickly_dissipates
);
895 pline_The("doorway vanishes!");
899 if (obstructed(x
, y
, mysterywand
))
901 /* Don't allow doors to close over traps. This is for pits */
902 /* & trap doors, but is it ever OK for anything else? */
904 /* maketrap() clears doormask, so it should be NODOOR */
905 pline("%s springs up in the doorway, but %s.", dustcloud
,
910 switch (door
->doormask
& ~D_TRAPPED
) {
912 msg
= "The door locks!";
915 msg
= "The door swings shut, and locks!";
918 msg
= "The broken door reassembles and locks!";
922 "A cloud of dust springs up and assembles itself into a door!";
929 door
->doormask
= D_LOCKED
| (door
->doormask
& D_TRAPPED
);
934 if (door
->doormask
& D_LOCKED
) {
935 msg
= "The door unlocks!";
936 door
->doormask
= D_CLOSED
| (door
->doormask
& D_TRAPPED
);
942 if (door
->doormask
& (D_LOCKED
| D_CLOSED
)) {
943 if (door
->doormask
& D_TRAPPED
) {
945 (void) mb_trapped(m_at(x
, y
));
946 else if (flags
.verbose
) {
948 pline("KABOOM!! You see a door explode.");
950 You_hear("a distant explosion.");
952 door
->doormask
= D_NODOOR
;
958 door
->doormask
= D_BROKEN
;
961 pline_The("door crashes open!");
963 You_hear("a crashing sound.");
967 /* force vision recalc before printing more messages */
968 if (vision_full_recalc
)
975 impossible("magic (%d) attempted on door.", otmp
->otyp
);
978 if (msg
&& cansee(x
, y
))
981 /* door was destroyed */
982 wake_nearto(x
, y
, loudness
);
983 if (*in_rooms(x
, y
, SHOPBASE
))
984 add_damage(x
, y
, 0L);
987 if (res
&& picking_at(x
, y
)) {
988 /* maybe unseen monster zaps door you're unlocking */
996 chest_shatter_msg(otmp
)
999 const char *disposition
;
1003 if (otmp
->oclass
== POTION_CLASS
) {
1004 You("%s %s shatter!", Blind
? "hear" : "see", an(bottlename()));
1005 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
))
1006 potionbreathe(otmp
);
1009 /* We have functions for distant and singular names, but not one */
1010 /* which does _both_... */
1011 save_Blinded
= Blinded
;
1013 thing
= singular(otmp
, xname
);
1014 Blinded
= save_Blinded
;
1015 switch (objects
[otmp
->otyp
].oc_material
) {
1017 disposition
= "is torn to shreds";
1020 disposition
= "is crushed";
1023 disposition
= "is pulped";
1026 disposition
= "is mashed";
1029 disposition
= "shatters";
1032 disposition
= "splinters to fragments";
1035 disposition
= "is destroyed";
1038 pline("%s %s!", An(thing
), disposition
);