Source:NetHack 3.2.0/lock.c

From NetHackWiki
(Redirected from NetHack 3.2.0/lock.c)
Jump to navigation Jump to search

Below is the full text to lock.c from the source code of NetHack 3.2.0.

Warning! This is the source code from an old release. For newer releases, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)lock.c	3.2	95/10/04	*/
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.  	  switch(door->doormask) {
534.  	     case D_BROKEN: pline("This door is broken."); break;
535.  	     case D_NODOOR: pline("This doorway has no door."); break;
536.  	     case D_ISOPEN: pline("This door is already open."); break;
537.  	     default:	    pline("This door is locked."); break;
538.  	  }
539.  	    if(Blind) feel_location(x,y);
540.  	  return(0);
541.  	}
542.  
543.  	if(verysmall(uasmon)) {
544.  	    pline("You're too small to pull the door open.");
545.  	    return(0);
546.  	}
547.  
548.  	/* door is known to be CLOSED */
549.  	if (rnl(20) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
550.  	    pline_The("door opens.");
551.  	    if(door->doormask & D_TRAPPED) {
552.  		b_trapped("door", FINGER);
553.  		door->doormask = D_NODOOR;
554.  		if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
555.  	    } else
556.  		door->doormask = D_ISOPEN;
557.  	    if (Blind)
558.  		feel_location(x,y);	/* the hero knows she opened it  */
559.  	    else
560.  		newsym(x,y);
561.  	    unblock_point(x,y);		/* vision: new see through there */
562.  	} else {
563.  	    exercise(A_STR, TRUE);
564.  	    pline_The("door resists!");
565.  	}
566.  
567.  	return(1);
568.  }
569.  
570.  static
571.  boolean
572.  obstructed(x,y)
573.  register int x, y;
574.  {
575.  	register struct monst *mtmp = m_at(x, y);
576.  
577.  	if(mtmp && mtmp->m_ap_type != M_AP_FURNITURE) {
578.  		if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere;
579.  		pline("%s stands in the way!", Blind ?
580.  			"Some creature" : Monnam(mtmp));
581.  		return(TRUE);
582.  	}
583.  	if (OBJ_AT(x, y)) {
584.  objhere:	pline("%s's in the way.", Something);
585.  		return(TRUE);
586.  	}
587.  	return(FALSE);
588.  }
589.  
590.  int
591.  doclose()		/* try to close a door */
592.  {
593.  	register int x, y;
594.  	register struct rm *door;
595.  	struct monst *mtmp;
596.  
597.  	if (u.utrap && u.utraptype == TT_PIT) {
598.  	    You_cant("reach over the edge of the pit.");
599.  	    return 0;
600.  	}
601.  
602.  	if(!getdir((char *)0)) return(0);
603.  
604.  	x = u.ux + u.dx;
605.  	y = u.uy + u.dy;
606.  	if((x == u.ux) && (y == u.uy)) {
607.  		You("are in the way!");
608.  		return(1);
609.  	}
610.  
611.  	if ((mtmp = m_at(x,y))				&&
612.  		mtmp->m_ap_type == M_AP_FURNITURE	&&
613.  		(mtmp->mappearance == S_hcdoor ||
614.  			mtmp->mappearance == S_vcdoor)	&&
615.  		!Protection_from_shape_changers)	 {
616.  
617.  	    stumble_onto_mimic(mtmp);
618.  	    return(1);
619.  	}
620.  
621.  	door = &levl[x][y];
622.  
623.  	if(!IS_DOOR(door->typ)) {
624.  		if (door->typ == DRAWBRIDGE_DOWN)
625.  		    pline("There is no obvious way to close the drawbridge.");
626.  		else
627.  		    You("%s no door there.",
628.  				Blind ? "feel" : "see");
629.  		return(0);
630.  	}
631.  
632.  	if(door->doormask == D_NODOOR) {
633.  	    pline("This doorway has no door.");
634.  	    return(0);
635.  	}
636.  
637.  	if(obstructed(x, y)) return(0);
638.  
639.  	if(door->doormask == D_BROKEN) {
640.  	    pline("This door is broken.");
641.  	    return(0);
642.  	}
643.  
644.  	if(door->doormask & (D_CLOSED | D_LOCKED)) {
645.  	    pline("This door is already closed.");
646.  	    return(0);
647.  	}
648.  
649.  	if(door->doormask == D_ISOPEN) {
650.  	    if(verysmall(uasmon)) {
651.  		 pline("You're too small to push the door closed.");
652.  		 return(0);
653.  	    }
654.  	    if (rn2(25) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) {
655.  		pline_The("door closes.");
656.  		door->doormask = D_CLOSED;
657.  		if (Blind)
658.  		    feel_location(x,y);	/* the hero knows she closed it */
659.  		else
660.  		    newsym(x,y);
661.  		block_point(x,y);	/* vision:  no longer see there */
662.  	    }
663.  	    else {
664.  	        exercise(A_STR, TRUE);
665.  	        pline_The("door resists!");
666.  	    }
667.  	}
668.  
669.  	return(1);
670.  }
671.  
672.  boolean			/* box obj was hit with spell effect otmp */
673.  boxlock(obj, otmp)	/* returns true if something happened */
674.  register struct obj *obj, *otmp;	/* obj *is* a box */
675.  {
676.  	register boolean res = 0;
677.  
678.  	switch(otmp->otyp) {
679.  	case WAN_LOCKING:
680.  	case SPE_WIZARD_LOCK:
681.  	    if (!obj->olocked) {	/* lock it; fix if broken */
682.  		pline("Klunk!");
683.  		obj->olocked = 1;
684.  		obj->obroken = 0;
685.  		res = 1;
686.  	    } /* else already closed and locked */
687.  	    break;
688.  	case WAN_OPENING:
689.  	case SPE_KNOCK:
690.  	    if (obj->olocked) {		/* unlock; couldn't be broken */
691.  		pline("Klick!");
692.  		obj->olocked = 0;
693.  		res = 1;
694.  	    } else			/* silently fix if broken */
695.  		obj->obroken = 0;
696.  	    break;
697.  	case WAN_POLYMORPH:
698.  	case SPE_POLYMORPH:
699.  	    /* maybe start unlocking chest, get interrupted, then zap it;
700.  	       we must avoid any attempt to resume unlocking it */
701.  	    if (xlock.box == obj)
702.  		reset_pick();
703.  	    break;
704.  	}
705.  	return res;
706.  }
707.  
708.  boolean			/* Door/secret door was hit with spell effect otmp */
709.  doorlock(otmp,x,y)	/* returns true if something happened */
710.  struct obj *otmp;
711.  int x, y;
712.  {
713.  	register struct rm *door = &levl[x][y];
714.  	boolean res = TRUE;
715.  	int loudness = 0;
716.  	const char *msg = (const char *)0;
717.  	const char *dustcloud = "A cloud of dust";
718.  	const char *quickly_dissipates = "quickly dissipates";
719.  	
720.  	if (door->typ == SDOOR) {
721.  	    if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
722.  		door->typ = DOOR;
723.  		door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
724.  		if (cansee(x,y)) pline("A door appears in the wall!");
725.  		newsym(x,y);
726.  		return TRUE;
727.  	    } else
728.  		return FALSE;
729.  	}
730.  
731.  	switch(otmp->otyp) {
732.  	case WAN_LOCKING:
733.  	case SPE_WIZARD_LOCK:
734.  #ifdef REINCARNATION
735.  	    if (Is_rogue_level(&u.uz)) {
736.  		/* Can't have real locking in Rogue, so just hide doorway */
737.  		pline("%s springs up in the older, more primitive doorway.",
738.  			dustcloud);
739.  		if (obstructed(x,y)) {
740.  			pline_The("cloud %s.",quickly_dissipates);
741.  			return FALSE;
742.  		}
743.  		block_point(x, y);
744.  		door->typ = SDOOR;
745.  		if (cansee(x,y)) pline_The("doorway vanishes!");
746.  		newsym(x,y);
747.  		return TRUE;
748.  	    }
749.  #endif
750.  	    if (obstructed(x,y)) return FALSE;
751.  	    /* Don't allow doors to close over traps.  This is for pits */
752.  	    /* & trap doors, but is it ever OK for anything else? */
753.  	    if (t_at(x,y)) {
754.  		/* maketrap() clears doormask, so it should be NODOOR */
755.  		pline(
756.  		"%s springs up in the doorway, but %s.",
757.  		dustcloud, quickly_dissipates);
758.  		return FALSE;
759.  	    }
760.  
761.  	    switch (door->doormask & ~D_TRAPPED) {
762.  	    case D_CLOSED:
763.  		msg = "The door locks!";
764.  		break;
765.  	    case D_ISOPEN:
766.  		msg = "The door swings shut, and locks!";
767.  		break;
768.  	    case D_BROKEN:
769.  		msg = "The broken door reassembles and locks!";
770.  		break;
771.  	    case D_NODOOR:
772.  		msg =
773.  		"A cloud of dust springs up and assembles itself into a door!";
774.  		break;
775.  	    default:
776.  		res = FALSE;
777.  		break;
778.  	    }
779.  	    block_point(x, y);
780.  	    door->doormask = D_LOCKED | (door->doormask & D_TRAPPED);
781.  	    newsym(x,y);
782.  	    break;
783.  	case WAN_OPENING:
784.  	case SPE_KNOCK:
785.  	    if (door->doormask & D_LOCKED) {
786.  		msg = "The door unlocks!";
787.  		door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
788.  	    } else res = FALSE;
789.  	    break;
790.  	case WAN_STRIKING:
791.  	case SPE_FORCE_BOLT:
792.  	    if (door->doormask & (D_LOCKED | D_CLOSED)) {
793.  		if (door->doormask & D_TRAPPED) {
794.  		    if (MON_AT(x, y))
795.  			(void) mb_trapped(m_at(x,y));
796.  		    else if (flags.verbose) {
797.  			if (cansee(x,y))
798.  			    pline("KABOOM!!  You see a door explode.");
799.  			else if (flags.soundok)
800.  			    You_hear("a distant explosion.");
801.  		    }
802.  		    door->doormask = D_NODOOR;
803.  		    unblock_point(x,y);
804.  		    newsym(x,y);
805.  		    loudness = 40;
806.  		    break;
807.  		}
808.  		door->doormask = D_BROKEN;
809.  		if (flags.verbose) {
810.  		    if (cansee(x,y))
811.  			pline_The("door crashes open!");
812.  		    else if (flags.soundok)
813.  			You_hear("a crashing sound.");
814.  		}
815.  		unblock_point(x,y);
816.  		newsym(x,y);
817.  		loudness = 20;
818.  	    } else res = FALSE;
819.  	    break;
820.  	default: impossible("magic (%d) attempted on door.", otmp->otyp);
821.  	    break;
822.  	}
823.  	if (msg && cansee(x,y)) pline(msg);
824.  	if (loudness > 0) {
825.  	    /* door was destroyed */
826.  	    wake_nearto(x, y, loudness);
827.  	    if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
828.  	}
829.  
830.  	if (res && picking_at(x, y)) {
831.  	    /* maybe unseen monster zaps door you're unlocking */
832.  	    stop_occupation();
833.  	    reset_pick();
834.  	}
835.  	return res;
836.  }
837.  
838.  static void
839.  chest_shatter_msg(otmp)
840.  struct obj *otmp;
841.  {
842.  	const char *disposition, *article = (otmp->quan > 1L) ? "A" : "The";
843.  	const char *thing;
844.  	long save_Blinded;
845.  
846.  	if (otmp->oclass == POTION_CLASS) {
847.  		You("%s a flask shatter!", Blind ? "hear" : "see");
848.  		potionbreathe(otmp);
849.  		return;
850.  	}
851.  	/* We have functions for distant and singular names, but not one */
852.  	/* which does _both_... */
853.  	save_Blinded = Blinded;
854.  	Blinded = 1;
855.  	thing = singular(otmp, xname);
856.  	Blinded = save_Blinded;
857.  	switch (objects[otmp->otyp].oc_material) {
858.  	case PAPER:	disposition = "is torn to shreds";
859.  		break;
860.  	case WAX:	disposition = "is crushed";
861.  		break;
862.  	case VEGGY:	disposition = "is pulped";
863.  		break;
864.  	case FLESH:	disposition = "is mashed";
865.  		break;
866.  	case GLASS:	disposition = "shatters";
867.  		break;
868.  	case WOOD:	disposition = "splinters to fragments";
869.  		break;
870.  	default:	disposition = "is destroyed";
871.  		break;
872.  	}
873.  	pline("%s %s %s!", article, thing, disposition);
874.  }
875.  
876.  #endif /* OVLB */
877.  
878.  /*lock.c*/