Source:SLASH'EM 0.0.7E7F2/trap.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to trap.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[Source:SLASH'EM 0.0.7E7F2/trap.c#line123]], for example.

Source code for vanilla NetHack is at 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: @(#)trap.c	3.4	2003/10/20	*/
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.    extern const char * const destroy_strings[];	/* from zap.c */
8.    
9.    STATIC_DCL void FDECL(dofiretrap, (struct obj *));
10.   STATIC_DCL void NDECL(domagictrap);
11.   STATIC_DCL boolean FDECL(emergency_disrobe,(boolean *));
12.   STATIC_DCL int FDECL(untrap_prob, (struct trap *ttmp));
13.   STATIC_DCL void FDECL(cnv_trap_obj, (int, int, struct trap *));
14.   STATIC_DCL void FDECL(move_into_trap, (struct trap *));
15.   STATIC_DCL int FDECL(try_disarm, (struct trap *,BOOLEAN_P));
16.   STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *));
17.   STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *));
18.   STATIC_DCL int FDECL(disarm_rust_trap, (struct trap *));
19.   STATIC_DCL int FDECL(disarm_fire_trap, (struct trap *));
20.   STATIC_DCL int FDECL(disarm_landmine, (struct trap *));
21.   STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *));
22.   STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int));
23.   STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P));
24.   STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *));
25.   STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P));
26.   STATIC_DCL int FDECL(mkroll_launch,
27.   			(struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long));
28.   STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P));
29.   #ifdef STEED
30.   STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *));
31.   STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse,
32.   			(unsigned, struct obj *, struct obj *));
33.   #endif
34.   
35.   #ifndef OVLB
36.   STATIC_VAR const char *a_your[2];
37.   STATIC_VAR const char *A_Your[2];
38.   STATIC_VAR const char tower_of_flame[];
39.   STATIC_VAR const char *A_gush_of_water_hits;
40.   STATIC_VAR const char * const blindgas[6];
41.   
42.   #else
43.   
44.   STATIC_VAR const char * const a_your[2] = { "a", "your" };
45.   STATIC_VAR const char * const A_Your[2] = { "A", "Your" };
46.   STATIC_VAR const char tower_of_flame[] = "tower of flame";
47.   STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits";
48.   STATIC_VAR const char * const blindgas[6] = 
49.   	{"humid", "odorless", "pungent", "chilling", "acrid", "biting"};
50.   
51.   #endif /* OVLB */
52.   
53.   #ifdef OVLB
54.   
55.   /* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */
56.   boolean			/* returns TRUE if hit on torso */
57.   burnarmor(victim)
58.   struct monst *victim;
59.   {
60.       struct obj *item;
61.       char buf[BUFSZ];
62.       int mat_idx;
63.       
64.       if (!victim) return 0;
65.   #define burn_dmg(obj,descr) rust_dmg(obj, descr, 0, FALSE, victim)
66.       while (1) {
67.   	switch (rn2(5)) {
68.   	case 0:
69.   	    item = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH);
70.   	    if (item) {
71.   		mat_idx = objects[item->otyp].oc_material;
72.   	    	Sprintf(buf,"%s helmet", materialnm[mat_idx] );
73.   	    }
74.   	    if (!burn_dmg(item, item ? buf : "helmet")) continue;
75.   	    break;
76.   	case 1:
77.   	    item = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC);
78.   	    if (item) {
79.   		(void) burn_dmg(item, cloak_simple_name(item));
80.   		return TRUE;
81.   	    }
82.   	    item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM);
83.   	    if (item) {
84.   		(void) burn_dmg(item, xname(item));
85.   		return TRUE;
86.   	    }
87.   #ifdef TOURIST
88.   	    item = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU);
89.   	    if (item)
90.   		(void) burn_dmg(item, "shirt");
91.   #endif
92.   	    return TRUE;
93.   	case 2:
94.   	    item = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS);
95.   	    if (!burn_dmg(item, "wooden shield")) continue;
96.   	    break;
97.   	case 3:
98.   	    item = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG);
99.   	    if (!burn_dmg(item, "gloves")) continue;
100.  	    break;
101.  	case 4:
102.  	    item = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF);
103.  	    if (!burn_dmg(item, "boots")) continue;
104.  	    break;
105.  	}
106.  	break; /* Out of while loop */
107.      }
108.      return FALSE;
109.  #undef burn_dmg
110.  }
111.  
112.  
113.  /* Generic rust-armor function.  Returns TRUE if a message was printed;
114.   * "print", if set, means to print a message (and thus to return TRUE) even
115.   * if the item could not be rusted; otherwise a message is printed and TRUE is
116.   * returned only for rustable items.
117.   */
118.  boolean
119.  rust_dmg(otmp, ostr, type, print, victim)
120.  register struct obj *otmp;
121.  register const char *ostr;
122.  int type;
123.  boolean print;
124.  struct monst *victim;
125.  {
126.  	static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" };
127.  	static NEARDATA const char * const msg[] =  { "burnt", "rusted", "rotten", "corroded" };
128.  	boolean vulnerable = FALSE;
129.  	boolean grprot = FALSE;
130.  	boolean is_primary = TRUE;
131.  	boolean vismon = (victim != &youmonst) && canseemon(victim);
132.  	int erosion;
133.  
134.  	if (!otmp) return(FALSE);
135.  	switch(type) {
136.  		case 0: vulnerable = is_flammable(otmp);
137.  			break;
138.  		case 1: vulnerable = is_rustprone(otmp);
139.  			grprot = TRUE;
140.  			break;
141.  		case 2: vulnerable = is_rottable(otmp);
142.  			is_primary = FALSE;
143.  			break;
144.  		case 3: vulnerable = is_corrodeable(otmp);
145.  			grprot = TRUE;
146.  			is_primary = FALSE;
147.  			break;
148.  	}
149.  	erosion = is_primary ? otmp->oeroded : otmp->oeroded2;
150.  
151.  	if (!print && (!vulnerable || otmp->oerodeproof || erosion == MAX_ERODE))
152.  		return FALSE;
153.  
154.  	if (!vulnerable) {
155.  	    if (flags.verbose) {
156.  		if (victim == &youmonst)
157.  		    Your("%s %s not affected.", ostr, vtense(ostr, "are"));
158.  		else if (vismon)
159.  		    pline("%s's %s %s not affected.", Monnam(victim), ostr,
160.  			  vtense(ostr, "are"));
161.  	    }
162.  	} else if (erosion < MAX_ERODE) {
163.  	    if (grprot && otmp->greased) {
164.  		grease_protect(otmp,ostr,victim);
165.  	    } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) {
166.  		if (flags.verbose) {
167.  		    if (victim == &youmonst)
168.  			pline("Somehow, your %s %s not affected.",
169.  			      ostr, vtense(ostr, "are"));
170.  		    else if (vismon)
171.  			pline("Somehow, %s's %s %s not affected.",
172.  			      mon_nam(victim), ostr, vtense(ostr, "are"));
173.  		}
174.  	    } else {
175.  		if (victim == &youmonst)
176.  		    Your("%s %s%s!", ostr,
177.  			 vtense(ostr, action[type]),
178.  			 erosion+1 == MAX_ERODE ? " completely" :
179.  			    erosion ? " further" : "");
180.  		else if (vismon)
181.  		    pline("%s's %s %s%s!", Monnam(victim), ostr,
182.  			vtense(ostr, action[type]),
183.  			erosion+1 == MAX_ERODE ? " completely" :
184.  			  erosion ? " further" : "");
185.  		if (is_primary)
186.  		    otmp->oeroded++;
187.  		else
188.  		    otmp->oeroded2++;
189.  		update_inventory();
190.  	    }
191.  	} else {
192.  	    if (flags.verbose) {
193.  		if (victim == &youmonst)
194.  		    Your("%s %s completely %s.", ostr,
195.  			 vtense(ostr, Blind ? "feel" : "look"),
196.  			 msg[type]);
197.  		else if (vismon)
198.  		    pline("%s's %s %s completely %s.",
199.  			  Monnam(victim), ostr,
200.  			  vtense(ostr, "look"), msg[type]);
201.  	    }
202.  	}
203.  	return(TRUE);
204.  }
205.  
206.  void
207.  grease_protect(otmp,ostr,victim)
208.  register struct obj *otmp;
209.  register const char *ostr;
210.  struct monst *victim;
211.  {
212.  	static const char txt[] = "protected by the layer of grease!";
213.  	boolean vismon = victim && (victim != &youmonst) && canseemon(victim);
214.  
215.  	if (ostr) {
216.  	    if (victim == &youmonst)
217.  		Your("%s %s %s", ostr, vtense(ostr, "are"), txt);
218.  	    else if (vismon)
219.  		pline("%s's %s %s %s", Monnam(victim),
220.  		    ostr, vtense(ostr, "are"), txt);
221.  	} else {
222.  	    if (victim == &youmonst)
223.  		Your("%s %s",aobjnam(otmp,"are"), txt);
224.  	    else if (vismon)
225.  		pline("%s's %s %s", Monnam(victim), aobjnam(otmp,"are"), txt);
226.  	}
227.  	if (!rn2(2)) {
228.  	    otmp->greased = 0;
229.  	    if (carried(otmp)) {
230.  		pline_The("grease dissolves.");
231.  		update_inventory();
232.  	    }
233.  	}
234.  }
235.  
236.  struct trap *
237.  maketrap(x,y,typ)
238.  register int x, y, typ;
239.  {
240.  	register struct trap *ttmp;
241.  	register struct rm *lev;
242.  	register boolean oldplace;
243.  
244.  	if ((ttmp = t_at(x,y)) != 0) {
245.  	    if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0;
246.  	    oldplace = TRUE;
247.  	    if (u.utrap && (x == u.ux) && (y == u.uy) &&
248.  	      ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) ||
249.  	      (u.utraptype == TT_WEB && typ != WEB) ||
250.  	      (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT)))
251.  		    u.utrap = 0;
252.  	} else {
253.  	    oldplace = FALSE;
254.  	    ttmp = newtrap();
255.  	    ttmp->tx = x;
256.  	    ttmp->ty = y;
257.  	    ttmp->launch.x = -1;	/* force error if used before set */
258.  	    ttmp->launch.y = -1;
259.  	}
260.  	ttmp->ttyp = typ;
261.  	switch(typ) {
262.  	    case STATUE_TRAP:	    /* create a "living" statue */
263.  	      { struct monst *mtmp;
264.  		struct obj *otmp, *statue;
265.  
266.  		statue = mkcorpstat(STATUE, (struct monst *)0,
267.  					&mons[rndmonnum()], x, y, FALSE);
268.  		mtmp = makemon(&mons[statue->corpsenm], 0, 0, NO_MM_FLAGS);
269.  		if (!mtmp) break; /* should never happen */
270.  		while(mtmp->minvent) {
271.  		    otmp = mtmp->minvent;
272.  		    otmp->owornmask = 0;
273.  		    obj_extract_self(otmp);
274.  		    (void) add_to_container(statue, otmp);
275.  		}
276.  		statue->owt = weight(statue);
277.  		mongone(mtmp);
278.  		break;
279.  	      }
280.  	    case ROLLING_BOULDER_TRAP:	/* boulder will roll towards trigger */
281.  		(void) mkroll_launch(ttmp, x, y, BOULDER, 1L);
282.  		break;
283.  	    case HOLE:
284.  	    case PIT:
285.  	    case SPIKED_PIT:
286.  	    case TRAPDOOR:
287.  		lev = &levl[x][y];
288.  		if (*in_rooms(x, y, SHOPBASE) &&
289.  			((typ == HOLE || typ == TRAPDOOR) ||
290.  			 IS_DOOR(lev->typ) || IS_WALL(lev->typ)))
291.  		    add_damage(x, y,		/* schedule repair */
292.  			       ((IS_DOOR(lev->typ) || IS_WALL(lev->typ))
293.  				&& !flags.mon_moving) ? 200L : 0L);
294.  		lev->doormask = 0;	/* subsumes altarmask, icedpool... */
295.  		if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */
296.  		    lev->typ = ROOM;
297.  
298.  		/*
299.  		 * some cases which can happen when digging
300.  		 * down while phazing thru solid areas
301.  		 */
302.  		else if (lev->typ == STONE || lev->typ == SCORR)
303.  		    lev->typ = CORR;
304.  		else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
305.  		    lev->typ = level.flags.is_maze_lev ? ROOM :
306.  			       level.flags.is_cavernous_lev ? CORR : DOOR;
307.  
308.  		unearth_objs(x, y);
309.  		break;
310.  	}
311.  	if (ttmp->ttyp == HOLE) ttmp->tseen = 1;  /* You can't hide a hole */
312.  	else ttmp->tseen = 0;
313.  	ttmp->once = 0;
314.  	ttmp->madeby_u = 0;
315.  	ttmp->dst.dnum = -1;
316.  	ttmp->dst.dlevel = -1;
317.  	if (!oldplace) {
318.  	    ttmp->ntrap = ftrap;
319.  	    ftrap = ttmp;
320.  	}
321.  	return(ttmp);
322.  }
323.  
324.  void
325.  fall_through(td)
326.  boolean td;	/* td == TRUE : trap door or hole */
327.  {
328.  	d_level dtmp;
329.  	char msgbuf[BUFSZ];
330.  	const char *dont_fall = 0;
331.  	register int newlevel = dunlev(&u.uz);
332.  
333.  	/* KMH -- You can't escape the Sokoban level traps */
334.  	if(Blind && Levitation && !In_sokoban(&u.uz)) return;
335.  
336.  	do {
337.  	    newlevel++;
338.  	} while(!rn2(4) && newlevel < dunlevs_in_dungeon(&u.uz));
339.  
340.  	if(td) {
341.  	    struct trap *t=t_at(u.ux,u.uy);
342.  	    seetrap(t);
343.  	    if (!In_sokoban(&u.uz)) {
344.  		if (t->ttyp == TRAPDOOR)
345.  			pline("A trap door opens up under you!");
346.  		else 
347.  			pline("There's a gaping hole under you!");
348.  	    }
349.  	} else pline_The("%s opens up under you!", surface(u.ux,u.uy));
350.  
351.  	if (In_sokoban(&u.uz) && Can_fall_thru(&u.uz))
352.  	    ;	/* KMH -- You can't escape the Sokoban level traps */
353.  	else if(Levitation || u.ustuck || !Can_fall_thru(&u.uz)
354.  	   || Flying || is_clinger(youmonst.data)
355.  	   || (Role_if(PM_ARCHEOLOGIST) && uwep && uwep->otyp == BULLWHIP)
356.  	   || (Inhell && !u.uevent.invoked &&
357.  					newlevel == dunlevs_in_dungeon(&u.uz))
358.  		) {
359.  		if (Role_if(PM_ARCHEOLOGIST) && uwep && uwep->otyp == BULLWHIP)            
360.  		pline("But thanks to your trusty whip ...");
361.  	    dont_fall = "don't fall in.";
362.  	} else if (youmonst.data->msize >= MZ_HUGE) {
363.  	    dont_fall = "don't fit through.";
364.  	} else if (!next_to_u()) {
365.  	    dont_fall = "are jerked back by your pet!";
366.  	}
367.  	if (dont_fall) {
368.  	    You(dont_fall);
369.  	    /* hero didn't fall through, but any objects here might */
370.  	    impact_drop((struct obj *)0, u.ux, u.uy, 0);
371.  	    if (!td) {
372.  		display_nhwindow(WIN_MESSAGE, FALSE);
373.  		pline_The("opening under you closes up.");
374.  	    }
375.  	    return;
376.  	}
377.  
378.  	if(*u.ushops) shopdig(1);
379.  	if (Is_stronghold(&u.uz)) {
380.  	    find_hell(&dtmp);
381.  	} else {
382.  	    dtmp.dnum = u.uz.dnum;
383.  	    dtmp.dlevel = newlevel;
384.  	}
385.  	if (!td)
386.  	    Sprintf(msgbuf, "The hole in the %s above you closes up.",
387.  		    ceiling(u.ux,u.uy));
388.  	schedule_goto(&dtmp, FALSE, TRUE, 0,
389.  		      (char *)0, !td ? msgbuf : (char *)0);
390.  }
391.  
392.  /*
393.   * Animate the given statue.  May have been via shatter attempt, trap,
394.   * or stone to flesh spell.  Return a monster if successfully animated.
395.   * If the monster is animated, the object is deleted.  If fail_reason
396.   * is non-null, then fill in the reason for failure (or success).
397.   *
398.   * The cause of animation is:
399.   *
400.   *	ANIMATE_NORMAL  - hero "finds" the monster
401.   *	ANIMATE_SHATTER - hero tries to destroy the statue
402.   *	ANIMATE_SPELL   - stone to flesh spell hits the statue
403.   *
404.   * Perhaps x, y is not needed if we can use get_obj_location() to find
405.   * the statue's location... ???
406.   */
407.  struct monst *
408.  animate_statue(statue, x, y, cause, fail_reason)
409.  struct obj *statue;
410.  xchar x, y;
411.  int cause;
412.  int *fail_reason;
413.  {
414.  	struct permonst *mptr;
415.  	struct monst *mon = 0;
416.  	struct obj *item;
417.  	coord cc;
418.  	boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC));
419.  	char statuename[BUFSZ];
420.  
421.  	Strcpy(statuename,the(xname(statue)));
422.  
423.  	if (statue->oxlth && statue->oattached == OATTACHED_MONST) {
424.  	    cc.x = x,  cc.y = y;
425.  	    mon = montraits(statue, &cc);
426.  	    if (mon && mon->mtame && !mon->isminion)
427.  		wary_dog(mon, TRUE);
428.  	} else {
429.  	    /* statue of any golem hit with stone-to-flesh becomes flesh golem */
430.  	    if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL)
431.  	    	mptr = &mons[PM_FLESH_GOLEM];
432.  	    else
433.  		mptr = &mons[statue->corpsenm];
434.  	    /*
435.  	     * Guard against someone wishing for a statue of a unique monster
436.  	     * (which is allowed in normal play) and then tossing it onto the
437.  	     * [detected or guessed] location of a statue trap.  Normally the
438.  	     * uppermost statue is the one which would be activated.
439.  	     */
440.  	    if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) {
441.  	        if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE;
442.  	        return (struct monst *)0;
443.  	    }
444.  	    if (cause == ANIMATE_SPELL &&
445.  		((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) {
446.  		/* Statues of quest guardians or unique monsters
447.  		 * will not stone-to-flesh as the real thing.
448.  		 */
449.  		mon = makemon(&mons[PM_DOPPELGANGER], x, y,
450.  			NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK);
451.  		if (mon) {
452.  			/* makemon() will set mon->cham to
453.  			 * CHAM_ORDINARY if hero is wearing
454.  			 * ring of protection from shape changers
455.  			 * when makemon() is called, so we have to
456.  			 * check the field before calling newcham().
457.  			 */
458.  			if (mon->cham == CHAM_DOPPELGANGER)
459.  				(void) newcham(mon, mptr, FALSE, FALSE);
460.  		}
461.  	    } else
462.  		mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ?
463.  			(NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT);
464.  	}
465.  
466.  	if (!mon) {
467.  	    if (fail_reason) *fail_reason = AS_NO_MON;
468.  	    return (struct monst *)0;
469.  	}
470.  
471.  	/* in case statue is wielded and hero zaps stone-to-flesh at self */
472.  	if (statue->owornmask) remove_worn_item(statue, TRUE);
473.  
474.  	/* allow statues to be of a specific gender */
475.  	if (statue->spe & STATUE_MALE)
476.  	    mon->female = FALSE;
477.  	else if (statue->spe & STATUE_FEMALE)
478.  	    mon->female = TRUE;
479.  	/* if statue has been named, give same name to the monster */
480.  	if (statue->onamelth)
481.  	    mon = christen_monst(mon, ONAME(statue));
482.  	/* transfer any statue contents to monster's inventory */
483.  	while ((item = statue->cobj) != 0) {
484.  	    obj_extract_self(item);
485.  	    (void) add_to_minv(mon, item);
486.  	}
487.  	m_dowear(mon, TRUE);
488.  	delobj(statue);
489.  
490.  	/* mimic statue becomes seen mimic; other hiders won't be hidden */
491.  	if (mon->m_ap_type) seemimic(mon);
492.  	else mon->mundetected = FALSE;
493.  	if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
494.  	    const char *comes_to_life = nonliving(mon->data) ?
495.  					"moves" : "comes to life"; 
496.  	    if (cause == ANIMATE_SPELL)
497.  	    	pline("%s %s!", upstart(statuename),
498.  	    		canspotmon(mon) ? comes_to_life : "disappears");
499.  	    else
500.  		pline_The("statue %s!",
501.  			canspotmon(mon) ? comes_to_life : "disappears");
502.  	    if (historic) {
503.  		    You_feel("guilty that the historic statue is now gone.");
504.  		    adjalign(-1);
505.  	    }
506.  	} else if (cause == ANIMATE_SHATTER)
507.  	    pline("Instead of shattering, the statue suddenly %s!",
508.  		canspotmon(mon) ? "comes to life" : "disappears");
509.  	else { /* cause == ANIMATE_NORMAL */
510.  	    You("find %s posing as a statue.",
511.  		canspotmon(mon) ? a_monnam(mon) : something);
512.  	    stop_occupation();
513.  	}
514.  	/* avoid hiding under nothing */
515.  	if (x == u.ux && y == u.uy &&
516.  		Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y))
517.  	    u.uundetected = 0;
518.  
519.  	if (fail_reason) *fail_reason = AS_OK;
520.  	return mon;
521.  	}
522.  
523.  /*
524.   * You've either stepped onto a statue trap's location or you've triggered a
525.   * statue trap by searching next to it or by trying to break it with a wand
526.   * or pick-axe.
527.   */
528.  struct monst *
529.  activate_statue_trap(trap, x, y, shatter)
530.  struct trap *trap;
531.  xchar x, y;
532.  boolean shatter;
533.  {
534.  	struct monst *mtmp = (struct monst *)0;
535.  	struct obj *otmp = sobj_at(STATUE, x, y);
536.  	int fail_reason;
537.  
538.  	/*
539.  	 * Try to animate the first valid statue.  Stop the loop when we
540.  	 * actually create something or the failure cause is not because
541.  	 * the mon was unique.
542.  	 */
543.  	deltrap(trap);
544.  	while (otmp) {
545.  	    mtmp = animate_statue(otmp, x, y,
546.  		    shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason);
547.  	    if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break;
548.  
549.  	    while ((otmp = otmp->nexthere) != 0)
550.  		if (otmp->otyp == STATUE) break;
551.  	}
552.  
553.  	if (Blind) feel_location(x, y);
554.  	else newsym(x, y);
555.  	return mtmp;
556.  }
557.  
558.  #ifdef STEED
559.  STATIC_OVL boolean
560.  keep_saddle_with_steedcorpse(steed_mid, objchn, saddle)
561.  unsigned steed_mid;
562.  struct obj *objchn, *saddle;
563.  {
564.  	if (!saddle) return FALSE;
565.  	while(objchn) {
566.  		if(objchn->otyp == CORPSE &&
567.  		   objchn->oattached == OATTACHED_MONST && objchn->oxlth) {
568.  			struct monst *mtmp = (struct monst *)objchn->oextra;
569.  			if (mtmp->m_id == steed_mid) {
570.  				/* move saddle */
571.  				xchar x,y;
572.  				if (get_obj_location(objchn, &x, &y, 0)) {
573.  					obj_extract_self(saddle);
574.  					place_object(saddle, x, y);
575.  					stackobj(saddle);
576.  				}
577.  				return TRUE;
578.  			}
579.  		}
580.  		if (Has_contents(objchn) &&
581.  		    keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle))
582.  			return TRUE;
583.  		objchn = objchn->nobj;
584.  	}
585.  	return FALSE;
586.  }
587.  #endif /*STEED*/
588.  
589.  void
590.  dotrap(trap, trflags)
591.  register struct trap *trap;
592.  unsigned trflags;
593.  {
594.  	register int ttype = trap->ttyp;
595.  	register struct obj *otmp;
596.  	boolean already_seen = trap->tseen;
597.  	boolean webmsgok = (!(trflags & NOWEBMSG));
598.  	boolean forcebungle = (trflags & FORCEBUNGLE);
599.  
600.  	nomul(0);
601.  
602.  	/* KMH -- You can't escape the Sokoban level traps */
603.  	if (In_sokoban(&u.uz) &&
604.  			(ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
605.  			ttype == TRAPDOOR)) {
606.  	    /* The "air currents" message is still appropriate -- even when
607.  	     * the hero isn't flying or levitating -- because it conveys the
608.  	     * reason why the player cannot escape the trap with a dexterity
609.  	     * check, clinging to the ceiling, etc.
610.  	     */
611.  	    pline("Air currents pull you down into %s %s!",
612.  	    	a_your[trap->madeby_u],
613.  	    	defsyms[trap_to_defsym(ttype)].explanation);
614.  	    /* then proceed to normal trap effect */
615.  	} else if (already_seen) {
616.  	    if ((Levitation || Flying) &&
617.  		    (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
618.  		    ttype == BEAR_TRAP)) {
619.  		You("%s over %s %s.",
620.  		    Levitation ? "float" : "fly",
621.  		    a_your[trap->madeby_u],
622.  		    defsyms[trap_to_defsym(ttype)].explanation);
623.  		return;
624.  	    }
625.  	    if(!Fumbling && ttype != MAGIC_PORTAL &&
626.  		ttype != ANTI_MAGIC && !forcebungle &&
627.  		(!rn2(5) ||
628.  	    ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) {
629.  		You("escape %s %s.",
630.  		    (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" :
631.  			a_your[trap->madeby_u],
632.  		    defsyms[trap_to_defsym(ttype)].explanation);
633.  		return;
634.  	    }
635.  	}
636.  
637.  #ifdef STEED
638.  	if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1));
639.  #endif
640.  
641.  	switch(ttype) {
642.  	    case ARROW_TRAP:
643.  		if (trap->once && trap->tseen && !rn2(15)) {
644.  		    You_hear("a loud click!");
645.  		    deltrap(trap);
646.  		    newsym(u.ux,u.uy);
647.  		    break;
648.  		}
649.  		trap->once = 1;
650.  		seetrap(trap);
651.  		pline("An arrow shoots out at you!");
652.  		otmp = mksobj(ARROW, TRUE, FALSE);
653.  		otmp->quan = 1L;
654.  		otmp->owt = weight(otmp);
655.  		otmp->opoisoned = 0;
656.  #ifdef STEED
657.  		if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
658.  		else
659.  #endif
660.  		if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) {
661.  		    obfree(otmp, (struct obj *)0);
662.  		} else {
663.  		    place_object(otmp, u.ux, u.uy);
664.  		    if (!Blind) otmp->dknown = 1;
665.  		    stackobj(otmp);
666.  		    newsym(u.ux, u.uy);
667.  		}
668.  		break;
669.  	    case DART_TRAP:
670.  		if (trap->once && trap->tseen && !rn2(15)) {
671.  		    You_hear("a soft click.");
672.  		    deltrap(trap);
673.  		    newsym(u.ux,u.uy);
674.  		    break;
675.  		}
676.  		trap->once = 1;
677.  		seetrap(trap);
678.  		pline("A little dart shoots out at you!");
679.  		otmp = mksobj(DART, TRUE, FALSE);
680.  		otmp->quan = 1L;
681.  		otmp->owt = weight(otmp);
682.  		if (!rn2(6)) otmp->opoisoned = 1;
683.  #ifdef STEED
684.  		if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
685.  		else
686.  #endif
687.  		if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) {
688.  		    if (otmp->opoisoned)
689.  			poisoned("dart", A_CON, "little dart", -10);
690.  		    obfree(otmp, (struct obj *)0);
691.  		} else {
692.  		    place_object(otmp, u.ux, u.uy);
693.  		    if (!Blind) otmp->dknown = 1;
694.  		    stackobj(otmp);
695.  		    newsym(u.ux, u.uy);
696.  		}
697.  		break;
698.  	    case ROCKTRAP:
699.  		if (trap->once && trap->tseen && !rn2(15)) {
700.  		    pline("A trap door in %s opens, but nothing falls out!",
701.  			  the(ceiling(u.ux,u.uy)));
702.  		    deltrap(trap);
703.  		    newsym(u.ux,u.uy);
704.  		} else {
705.  		    int dmg = d(2,6); /* should be std ROCK dmg? */
706.  
707.  		    trap->once = 1;
708.  		    seetrap(trap);
709.  		    otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE);
710.  		    otmp->quan = 1L;
711.  		    otmp->owt = weight(otmp);
712.  
713.  		    pline("A trap door in %s opens and %s falls on your %s!",
714.  			  the(ceiling(u.ux,u.uy)),
715.  			  an(xname(otmp)),
716.  			  body_part(HEAD));
717.  
718.  		    if (uarmh) {
719.  			if(is_metallic(uarmh)) {
720.  			    pline("Fortunately, you are wearing a hard helmet.");
721.  			    dmg = 2;
722.  			} else if (flags.verbose) {
723.  			    Your("%s does not protect you.", xname(uarmh));
724.  			}
725.  		    }
726.  
727.  		    if (!Blind) otmp->dknown = 1;
728.  		    stackobj(otmp);
729.  		    newsym(u.ux,u.uy);	/* map the rock */
730.  
731.  		    losehp(dmg, "falling rock", KILLED_BY_AN);
732.  		    exercise(A_STR, FALSE);
733.  		}
734.  		break;
735.  
736.  	    case SQKY_BOARD:	    /* stepped on a squeaky board */
737.  		if (Levitation || Flying) {
738.  		    if (!Blind) {
739.  			seetrap(trap);
740.  			if (Hallucination)
741.  				You("notice a crease in the linoleum.");
742.  			else
743.  				You("notice a loose board below you.");
744.  		    }
745.  		} else {
746.  		    seetrap(trap);
747.  		    pline("A board beneath you squeaks loudly.");
748.  		    wake_nearby();
749.  		}
750.  		break;
751.  
752.  	    case BEAR_TRAP:
753.  		if(Levitation || Flying) break;
754.  		seetrap(trap);
755.  		if(amorphous(youmonst.data) || is_whirly(youmonst.data) ||
756.  						    unsolid(youmonst.data)) {
757.  		    pline("%s bear trap closes harmlessly through you.",
758.  			    A_Your[trap->madeby_u]);
759.  		    break;
760.  		}
761.  		if(
762.  #ifdef STEED
763.  		   !u.usteed &&
764.  #endif
765.  		   youmonst.data->msize <= MZ_SMALL) {
766.  		    pline("%s bear trap closes harmlessly over you.",
767.  			    A_Your[trap->madeby_u]);
768.  		    break;
769.  		}
770.  		u.utrap = rn1(4, 4);
771.  		u.utraptype = TT_BEARTRAP;
772.  #ifdef STEED
773.  		if (u.usteed) {
774.  		    pline("%s bear trap closes on %s %s!",
775.  			A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)),
776.  			mbodypart(u.usteed, FOOT));
777.  		} else
778.  #endif
779.  		{
780.  		    pline("%s bear trap closes on your %s!",
781.  			    A_Your[trap->madeby_u], body_part(FOOT));
782.  		    if(u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR)
783.  			You("howl in anger!");
784.  		}
785.  		exercise(A_DEX, FALSE);
786.  		break;
787.  
788.  	    case SLP_GAS_TRAP:
789.  		seetrap(trap);
790.  		if(Sleep_resistance || breathless(youmonst.data)) {
791.  		    You("are enveloped in a cloud of gas!");
792.  		    break;
793.  		}
794.  		pline("A cloud of gas puts you to sleep!");
795.  		fall_asleep(-rnd(25), TRUE);
796.  #ifdef STEED
797.  		(void) steedintrap(trap, (struct obj *)0);
798.  #endif
799.  		break;
800.  
801.  	    case RUST_TRAP:
802.  		seetrap(trap);
803.  		if (u.umonnum == PM_IRON_GOLEM) {
804.  		    int dam = u.mhmax;
805.  
806.  		    pline("%s you!", A_gush_of_water_hits);
807.  		    You("are covered with rust!");
808.  		    if (Half_physical_damage) dam = (dam+1) / 2;
809.  		    losehp(dam, "rusting away", KILLED_BY);
810.  		    break;
811.  		} else if (u.umonnum == PM_FLAMING_SPHERE) {
812.  		    int dam = u.mhmax;
813.  
814.  		    pline("%s you!", A_gush_of_water_hits);
815.  		    You("are extinguished!");
816.  		    if (Half_physical_damage) dam = (dam+1) / 2;
817.  		    losehp(dam, "drenching", KILLED_BY);
818.  		    break;
819.  		} else if (u.umonnum == PM_GREMLIN && rn2(3)) {
820.  		    pline("%s you!", A_gush_of_water_hits);
821.  		    (void)split_mon(&youmonst, (struct monst *)0);
822.  		    break;
823.  		}
824.  
825.  	    /* Unlike monsters, traps cannot aim their rust attacks at
826.  	     * you, so instead of looping through and taking either the
827.  	     * first rustable one or the body, we take whatever we get,
828.  	     * even if it is not rustable.
829.  	     */
830.  		switch (rn2(5)) {
831.  		    case 0:
832.  			pline("%s you on the %s!", A_gush_of_water_hits,
833.  				    body_part(HEAD));
834.  			(void) rust_dmg(uarmh, "helmet", 1, TRUE, &youmonst);
835.  			break;
836.  		    case 1:
837.  			pline("%s your left %s!", A_gush_of_water_hits,
838.  				    body_part(ARM));
839.  			if (rust_dmg(uarms, "shield", 1, TRUE, &youmonst))
840.  			    break;
841.  			if (u.twoweap || (uwep && bimanual(uwep))) {
842.  			    otmp = u.twoweap ? uswapwep : uwep;
843.  			    if (otmp && !snuff_lit(otmp))
844.  				erode_obj(otmp, FALSE, TRUE);
845.  			}
846.  glovecheck:		(void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
847.  			/* Not "metal gauntlets" since it gets called
848.  			 * even if it's leather for the message
849.  			 */
850.  			break;
851.  		    case 2:
852.  			pline("%s your right %s!", A_gush_of_water_hits,
853.  				    body_part(ARM));
854.  			if (uwep && !snuff_lit(uwep))
855.  			    erode_obj(uwep, FALSE, TRUE);
856.  			goto glovecheck;
857.  		    default:
858.  			pline("%s you!", A_gush_of_water_hits);
859.  			for (otmp=invent; otmp; otmp = otmp->nobj)
860.  				    (void) snuff_lit(otmp);
861.  			if (uarmc)
862.  			    (void) rust_dmg(uarmc, cloak_simple_name(uarmc),
863.  						1, TRUE, &youmonst);
864.  			else if (uarm)
865.  			    (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst);
866.  #ifdef TOURIST
867.  			else if (uarmu)
868.  			    (void) rust_dmg(uarmu, "shirt", 1, TRUE, &youmonst);
869.  #endif
870.  		}
871.  		update_inventory();
872.  		break;
873.  
874.  	    case FIRE_TRAP:
875.  		seetrap(trap);
876.  		dofiretrap((struct obj *)0);
877.  		break;
878.  
879.  	    case PIT:
880.  	    case SPIKED_PIT:
881.  		/* KMH -- You can't escape the Sokoban level traps */
882.  		if (!In_sokoban(&u.uz) && (Levitation || Flying)) break;
883.  		seetrap(trap);
884.  		if (!In_sokoban(&u.uz) && is_clinger(youmonst.data)) {
885.  		    if(trap->tseen) {
886.  			You("see %s %spit below you.", a_your[trap->madeby_u],
887.  			    ttype == SPIKED_PIT ? "spiked " : "");
888.  		    } else {
889.  			pline("%s pit %sopens up under you!",
890.  			    A_Your[trap->madeby_u],
891.  			    ttype == SPIKED_PIT ? "full of spikes " : "");
892.  			You("don't fall in!");
893.  		    }
894.  		    break;
895.  		}
896.  		if (!In_sokoban(&u.uz)) {
897.  		   char verbbuf[BUFSZ];
898.  #ifdef STEED
899.  		    if (u.usteed) {
900.  		    	if ((trflags & RECURSIVETRAP) != 0)
901.  			    Sprintf(verbbuf, "and %s fall",
902.  				x_monnam(u.usteed,
903.  				    u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
904.  				    (char *)0, SUPPRESS_SADDLE, FALSE));
905.  			else
906.  			    Sprintf(verbbuf,"lead %s",
907.  				x_monnam(u.usteed,
908.  					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
909.  				 	 "poor", SUPPRESS_SADDLE, FALSE));
910.  		    } else
911.  #endif
912.  		    Strcpy(verbbuf,"fall");
913.  		   You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
914.  		}
915.  		/* wumpus reference */
916.  		if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once &&
917.  			In_quest(&u.uz) && Is_qlocate(&u.uz)) {
918.  		    pline("Fortunately it has a bottom after all...");
919.  		    trap->once = 1;
920.  		} else if (u.umonnum == PM_PIT_VIPER ||
921.  			u.umonnum == PM_PIT_FIEND)
922.  		    pline("How pitiful.  Isn't that the pits?");
923.  		if (ttype == SPIKED_PIT) {
924.  		    const char *predicament = "on a set of sharp iron spikes";
925.  #ifdef STEED
926.  		    if (u.usteed) {
927.  			pline("%s lands %s!",
928.  				upstart(x_monnam(u.usteed,
929.  					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
930.  					 "poor", SUPPRESS_SADDLE, FALSE)),
931.  			      predicament);
932.  		    } else
933.  #endif
934.  		    You("land %s!", predicament);
935.  		}
936.  		if (!Passes_walls)
937.  		    u.utrap = rn1(6,2);
938.  		u.utraptype = TT_PIT;
939.  #ifdef STEED
940.  		if (!steedintrap(trap, (struct obj *)0)) {
941.  #endif
942.  		if (ttype == SPIKED_PIT) {
943.  		    losehp(rnd(10),"fell into a pit of iron spikes",
944.  			NO_KILLER_PREFIX);
945.  		    if (!rn2(6))
946.  			poisoned("spikes", A_STR, "fall onto poison spikes", 8);
947.  		} else
948.  		    losehp(rnd(6),"fell into a pit", NO_KILLER_PREFIX);
949.  		if (Punished && !carried(uball)) {
950.  		    unplacebc();
951.  		    ballfall();
952.  		    placebc();
953.  		}
954.  		selftouch("Falling, you");
955.  		vision_full_recalc = 1;	/* vision limits change */
956.  		exercise(A_STR, FALSE);
957.  		exercise(A_DEX, FALSE);
958.  #ifdef STEED
959.  		}
960.  #endif
961.  		break;
962.  	    case HOLE:
963.  	    case TRAPDOOR:
964.  		if (!Can_fall_thru(&u.uz)) {
965.  		    seetrap(trap);	/* normally done in fall_through */
966.  		    impossible("dotrap: %ss cannot exist on this level.",
967.  			       defsyms[trap_to_defsym(ttype)].explanation);
968.  		    break;		/* don't activate it after all */
969.  		}
970.  		fall_through(TRUE);
971.  		break;
972.  
973.  	    case TELEP_TRAP:
974.  		seetrap(trap);
975.  		tele_trap(trap);
976.  		break;
977.  	    case LEVEL_TELEP:
978.  		seetrap(trap);
979.  		level_tele_trap(trap);
980.  		break;
981.  
982.  	    case WEB: /* Our luckless player has stumbled into a web. */
983.  		seetrap(trap);
984.  		if (amorphous(youmonst.data) || is_whirly(youmonst.data) ||
985.  						    unsolid(youmonst.data)) {
986.  		    if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE ||
987.  			u.umonnum == PM_FIRE_ELEMENTAL) {
988.  			if (webmsgok)
989.  			    You("%s %s spider web!",
990.  				(u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve",
991.  				a_your[trap->madeby_u]);
992.  			deltrap(trap);
993.  			newsym(u.ux,u.uy);
994.  			break;
995.  		    }
996.  		    if (webmsgok) You("flow through %s spider web.",
997.  			    a_your[trap->madeby_u]);
998.  		    break;
999.  		}
1000. 		if (webmaker(youmonst.data)) {
1001. 		    if (webmsgok)
1002. 		    	pline(trap->madeby_u ? "You take a walk on your web."
1003. 					 : "There is a spider web here.");
1004. 		    break;
1005. 		}
1006. 		if (webmsgok) {
1007. 		   char verbbuf[BUFSZ];
1008. 		   verbbuf[0] = '\0';
1009. #ifdef STEED
1010. 		   if (u.usteed)
1011. 		   	Sprintf(verbbuf,"lead %s",
1012. 				x_monnam(u.usteed,
1013. 					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
1014. 				 	 "poor", SUPPRESS_SADDLE, FALSE));
1015. 		   else
1016. #endif
1017. 			
1018. 		    Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" :
1019. 		      		locomotion(youmonst.data, "stumble"));
1020. 		    You("%s into %s spider web!",
1021. 			verbbuf, a_your[trap->madeby_u]);
1022. 		}
1023. 		u.utraptype = TT_WEB;
1024. 
1025. 		/* Time stuck in the web depends on your/steed strength. */
1026. 		{
1027. 		    register int str = ACURR(A_STR);
1028. 
1029. #ifdef STEED
1030. 		    /* If mounted, the steed gets trapped.  Use mintrap
1031. 		     * to do all the work.  If mtrapped is set as a result,
1032. 		     * unset it and set utrap instead.  In the case of a
1033. 		     * strongmonst and mintrap said it's trapped, use a
1034. 		     * short but non-zero trap time.  Otherwise, monsters
1035. 		     * have no specific strength, so use player strength.
1036. 		     * This gets skipped for webmsgok, which implies that
1037. 		     * the steed isn't a factor.
1038. 		     */
1039. 		    if (u.usteed && webmsgok) {
1040. 			/* mtmp location might not be up to date */
1041. 			u.usteed->mx = u.ux;
1042. 			u.usteed->my = u.uy;
1043. 
1044. 			/* mintrap currently does not return 2(died) for webs */
1045. 			if (mintrap(u.usteed)) {
1046. 			    u.usteed->mtrapped = 0;
1047. 			    if (strongmonst(u.usteed->data)) str = 17;
1048. 			} else {
1049. 			    break;
1050. 			}
1051. 
1052. 			webmsgok = FALSE; /* mintrap printed the messages */
1053. 		    }
1054. #endif
1055. 		    if (str <= 3) u.utrap = rn1(6,6);
1056. 		    else if (str < 6) u.utrap = rn1(6,4);
1057. 		    else if (str < 9) u.utrap = rn1(4,4);
1058. 		    else if (str < 12) u.utrap = rn1(4,2);
1059. 		    else if (str < 15) u.utrap = rn1(2,2);
1060. 		    else if (str < 18) u.utrap = rnd(2);
1061. 		    else if (str < 69) u.utrap = 1;
1062. 		    else {
1063. 			u.utrap = 0;
1064. 			if (webmsgok)
1065. 				You("tear through %s web!", a_your[trap->madeby_u]);
1066. 			deltrap(trap);
1067. 			newsym(u.ux,u.uy);	/* get rid of trap symbol */
1068. 		    }
1069. 		}
1070. 		break;
1071. 
1072. 	    case STATUE_TRAP:
1073. 		activate_statue_trap(trap, u.ux, u.uy, FALSE);
1074. 		break;
1075. 
1076. 	    case MAGIC_TRAP:	    /* A magic trap. */
1077. 		seetrap(trap);
1078. 		if (!rn2(30)) {
1079. 		    deltrap(trap);
1080. 		    newsym(u.ux,u.uy);	/* update position */
1081. 		    You("are caught in a magical explosion!");
1082. 		    losehp(rnd(10), "magical explosion", KILLED_BY_AN);
1083. 		    Your("body absorbs some of the magical energy!");
1084. 		    u.uen = (u.uenmax += 2);
1085. 		} else domagictrap();
1086. #ifdef STEED
1087. 		(void) steedintrap(trap, (struct obj *)0);
1088. #endif
1089. 		break;
1090. 
1091. 	    case ANTI_MAGIC:
1092. 		seetrap(trap);
1093. 		if(Antimagic) {
1094. 		    shieldeff(u.ux, u.uy);
1095. 		    You_feel("momentarily lethargic.");
1096. 		} else drain_en(rnd(u.ulevel) + 1);
1097. 		break;
1098. 
1099. 	    case POLY_TRAP: {
1100. 	        char verbbuf[BUFSZ];
1101. 		seetrap(trap);
1102. #ifdef STEED
1103. 		if (u.usteed)
1104. 			Sprintf(verbbuf, "lead %s",
1105. 				x_monnam(u.usteed,
1106. 					 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
1107. 				 	 (char *)0, SUPPRESS_SADDLE, FALSE));
1108. 		else
1109. #endif
1110. 		 Sprintf(verbbuf,"%s",
1111. 		    Levitation ? (const char *)"float" :
1112. 		    locomotion(youmonst.data, "step"));
1113. 		You("%s onto a polymorph trap!", verbbuf);
1114. 		if(Antimagic || Unchanging) {
1115. 		    shieldeff(u.ux, u.uy);
1116. 		    You_feel("momentarily different.");
1117. 		    /* Trap did nothing; don't remove it --KAA */
1118. 		} else {
1119. #ifdef STEED
1120. 		    (void) steedintrap(trap, (struct obj *)0);
1121. #endif
1122. 		    deltrap(trap);	/* delete trap before polymorph */
1123. 		    newsym(u.ux,u.uy);	/* get rid of trap symbol */
1124. 		    You_feel("a change coming over you.");
1125. 		    polyself(FALSE);
1126. 		}
1127. 		break;
1128. 	    }
1129. 	    case LANDMINE: {
1130. #ifdef STEED
1131. 		unsigned steed_mid = 0;
1132. 		struct obj *saddle = 0;
1133. #endif
1134. 		if (Levitation || Flying) {
1135. 		    if (!already_seen && rn2(3)) break;
1136. 		    seetrap(trap);
1137. 		    pline("%s %s in a pile of soil below you.",
1138. 			    already_seen ? "There is" : "You discover",
1139. 			    trap->madeby_u ? "the trigger of your mine" :
1140. 					     "a trigger");
1141. 		    if (already_seen && rn2(3)) break;
1142. 		    pline("KAABLAMM!!!  %s %s%s off!",
1143. 			  forcebungle ? "Your inept attempt sets" :
1144. 					"The air currents set",
1145. 			    already_seen ? a_your[trap->madeby_u] : "",
1146. 			    already_seen ? " land mine" : "it");
1147. 		} else {
1148. #ifdef STEED
1149. 		    /* prevent landmine from killing steed, throwing you to
1150. 		     * the ground, and you being affected again by the same
1151. 		     * mine because it hasn't been deleted yet
1152. 		     */
1153. 		    static boolean recursive_mine = FALSE;
1154. 
1155. 		    if (recursive_mine) break;
1156. #endif
1157. 		    seetrap(trap);
1158. 		    pline("KAABLAMM!!!  You triggered %s land mine!",
1159. 					    a_your[trap->madeby_u]);
1160. #ifdef STEED
1161. 		    if (u.usteed) steed_mid = u.usteed->m_id;
1162. 		    recursive_mine = TRUE;
1163. 		    (void) steedintrap(trap, (struct obj *)0);
1164. 		    recursive_mine = FALSE;
1165. 		    saddle = sobj_at(SADDLE,u.ux, u.uy);
1166. #endif
1167. 		    set_wounded_legs(LEFT_SIDE, rn1(35, 41));
1168. 		    set_wounded_legs(RIGHT_SIDE, rn1(35, 41));
1169. 		    exercise(A_DEX, FALSE);
1170. 		}
1171. 		blow_up_landmine(trap);
1172. #ifdef STEED
1173. 		if (steed_mid && saddle && !u.usteed)
1174. 			(void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle);
1175. #endif
1176. 		newsym(u.ux,u.uy);		/* update trap symbol */
1177. 		losehp(rnd(16), "land mine", KILLED_BY_AN);
1178. 		/* fall recursively into the pit... */
1179. 		if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP);
1180. 		fill_pit(u.ux, u.uy);
1181. 		break;
1182. 	    }
1183. 	    case ROLLING_BOULDER_TRAP: {
1184. 		int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0);
1185. 
1186. 		seetrap(trap);
1187. 		pline("Click! You trigger a rolling boulder trap!");
1188. 		if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y,
1189. 		      trap->launch2.x, trap->launch2.y, style)) {
1190. 		    deltrap(trap);
1191. 		    newsym(u.ux,u.uy);	/* get rid of trap symbol */
1192. 		    pline("Fortunately for you, no boulder was released.");
1193. 		}
1194. 		break;
1195. 	    }
1196. 	    case MAGIC_PORTAL:
1197. 		seetrap(trap);
1198. #if defined(BLACKMARKET) && defined(STEED)
1199. 		if (u.usteed &&
1200. 			(Is_blackmarket(&trap->dst) || Is_blackmarket(&u.uz)))
1201. 		    pline("%s seems to shimmer for a moment.",
1202. 			  Monnam(u.usteed));
1203. 		else
1204. #endif
1205. 		domagicportal(trap);
1206. 		break;
1207. 
1208. 	    default:
1209. 		seetrap(trap);
1210. 		impossible("You hit a trap of type %u", trap->ttyp);
1211. 	}
1212. }
1213. 
1214. #ifdef STEED
1215. STATIC_OVL int
1216. steedintrap(trap, otmp)
1217. struct trap *trap;
1218. struct obj *otmp;
1219. {
1220. 	struct monst *mtmp = u.usteed;
1221. 	struct permonst *mptr;
1222. 	int tt;
1223. 	boolean in_sight;
1224. 	boolean trapkilled = FALSE;
1225. 	boolean steedhit = FALSE;
1226. 
1227. 	if (!u.usteed || !trap) return 0;
1228. 	mptr = mtmp->data;
1229. 	tt = trap->ttyp;
1230. 	mtmp->mx = u.ux;
1231. 	mtmp->my = u.uy;
1232. 
1233. 	in_sight = !Blind;
1234. 	switch (tt) {
1235. 		case ARROW_TRAP:
1236. 			if(!otmp) {
1237. 				impossible("steed hit by non-existant arrow?");
1238. 				return 0;
1239. 			}
1240. 			if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1241. 			steedhit = TRUE;
1242. 			break;
1243. 		case DART_TRAP:
1244. 			if(!otmp) {
1245. 				impossible("steed hit by non-existant dart?");
1246. 				return 0;
1247. 			}
1248. 			if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1249. 			steedhit = TRUE;
1250. 			break;
1251. 		case SLP_GAS_TRAP:
1252. 		    if (!resists_sleep(mtmp) && !breathless(mptr) &&
1253. 				!mtmp->msleeping && mtmp->mcanmove) {
1254. 			    mtmp->mcanmove = 0;
1255. 			    mtmp->mfrozen = rnd(25);
1256. 			    if (in_sight) {
1257. 				pline("%s suddenly falls asleep!",
1258. 				      Monnam(mtmp));
1259. 			    }
1260. 			}
1261. 			steedhit = TRUE;
1262. 			break;
1263. 		case LANDMINE:
1264. 			if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
1265. 			    trapkilled = TRUE;
1266. 			steedhit = TRUE;
1267. 			break;
1268. 		case PIT:
1269. 		case SPIKED_PIT:
1270. 			if (mtmp->mhp <= 0 ||
1271. 				thitm(0, mtmp, (struct obj *)0,
1272. 				      rnd((tt == PIT) ? 6 : 10), FALSE))
1273. 			    trapkilled = TRUE;
1274. 			steedhit = TRUE;
1275. 			break;
1276. 		case POLY_TRAP: 
1277. 		    if (!resists_magm(mtmp)) {
1278. 			if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
1279. 			    (void) mon_spec_poly(mtmp, (struct permonst *)0, 0L, FALSE, FALSE, FALSE, TRUE); 
1280. 			    if (!can_saddle(mtmp) || !can_ride(mtmp)) {
1281. 				dismount_steed(DISMOUNT_POLY);
1282. 			    } else {
1283. 				You("have to adjust yourself in the saddle on %s.",
1284. 					x_monnam(mtmp,
1285. 					mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_A,
1286. 					(char *)0, SUPPRESS_SADDLE, FALSE));
1287. 			    }
1288. 			}
1289. 			steedhit = TRUE;
1290. 		    }
1291. 		    break;
1292. 		default:
1293. 			return 0;
1294. 	}
1295. 	if(trapkilled) {
1296. 		dismount_steed(DISMOUNT_POLY);
1297. 		return 2;
1298. 	}
1299. 	else if(steedhit) return 1;
1300. 	else return 0;
1301. }
1302. #endif /*STEED*/
1303. 
1304. /* some actions common to both player and monsters for triggered landmine */
1305. void
1306. blow_up_landmine(trap)
1307. struct trap *trap;
1308. {
1309. 	(void)scatter(trap->tx, trap->ty, 4,
1310. 		MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS,
1311. 		(struct obj *)0);
1312. 	del_engr_at(trap->tx, trap->ty);
1313. 	wake_nearto(trap->tx, trap->ty, 400);
1314. 	/* ALI - artifact doors */
1315. 	if (IS_DOOR(levl[trap->tx][trap->ty].typ) &&
1316. 		!artifact_door(trap->tx, trap->ty))
1317. 	    levl[trap->tx][trap->ty].doormask = D_BROKEN;
1318. 	/* TODO: destroy drawbridge if present */
1319. 	/* caller may subsequently fill pit, e.g. with a boulder */
1320. 	trap->ttyp = PIT;		/* explosion creates a pit */
1321. 	trap->madeby_u = FALSE;		/* resulting pit isn't yours */
1322. 	seetrap(trap);			/* and it isn't concealed */
1323. }
1324. 
1325. #endif /* OVLB */
1326. #ifdef OVL3
1327. 
1328. /*
1329.  * Move obj from (x1,y1) to (x2,y2)
1330.  *
1331.  * Return 0 if no object was launched.
1332.  *        1 if an object was launched and placed somewhere.
1333.  *        2 if an object was launched, but used up.
1334.  */
1335. int
1336. launch_obj(otyp, x1, y1, x2, y2, style)
1337. short otyp;
1338. register int x1,y1,x2,y2;
1339. int style;
1340. {
1341. 	register struct monst *mtmp;
1342. 	register struct obj *otmp, *otmp2;
1343. 	register int dx,dy;
1344. 	struct obj *singleobj;
1345. 	boolean used_up = FALSE;
1346. 	boolean otherside = FALSE;
1347. 	int dist;
1348. 	int tmp;
1349. 	int delaycnt = 0;
1350. 
1351. 	otmp = sobj_at(otyp, x1, y1);
1352. 	/* Try the other side too, for rolling boulder traps */
1353. 	if (!otmp && otyp == BOULDER) {
1354. 		otherside = TRUE;
1355. 		otmp = sobj_at(otyp, x2, y2);
1356. 	}
1357. 	if (!otmp) return 0;
1358. 	if (otherside) {	/* swap 'em */
1359. 		int tx, ty;
1360. 
1361. 		tx = x1; ty = y1;
1362. 		x1 = x2; y1 = y2;
1363. 		x2 = tx; y2 = ty;
1364. 	}
1365. 
1366. 	if (otmp->quan == 1L) {
1367. 	    obj_extract_self(otmp);
1368. 	    singleobj = otmp;
1369. 	    otmp = (struct obj *) 0;
1370. 	} else {
1371. 	    singleobj = splitobj(otmp, 1L);
1372. 	    obj_extract_self(singleobj);
1373. 	}
1374. 	newsym(x1,y1);
1375. 	/* in case you're using a pick-axe to chop the boulder that's being
1376. 	   launched (perhaps a monster triggered it), destroy context so that
1377. 	   next dig attempt never thinks you're resuming previous effort */
1378. 	if ((otyp == BOULDER || otyp == STATUE) &&
1379. 	    singleobj->ox == digging.pos.x && singleobj->oy == digging.pos.y)
1380. 	    (void) memset((genericptr_t)&digging, 0, sizeof digging);
1381. 
1382. 	dist = distmin(x1,y1,x2,y2);
1383. 	bhitpos.x = x1;
1384. 	bhitpos.y = y1;
1385. 	dx = sgn(x2 - x1);
1386. 	dy = sgn(y2 - y1);
1387. 	switch (style) {
1388. 	    case ROLL|LAUNCH_UNSEEN:
1389. 			if (otyp == BOULDER) {
1390. 			    You_hear(Hallucination ?
1391. 				     "someone bowling." :
1392. 				     "rumbling in the distance.");
1393. 			}
1394. 			style &= ~LAUNCH_UNSEEN;
1395. 			goto roll;
1396. 	    case ROLL|LAUNCH_KNOWN:
1397. 			/* use otrapped as a flag to ohitmon */
1398. 			singleobj->otrapped = 1;
1399. 			style &= ~LAUNCH_KNOWN;
1400. 			/* fall through */
1401. 	    roll:
1402. 	    case ROLL:
1403. 			delaycnt = 2;
1404. 			/* fall through */
1405. 	    default:
1406. 			if (!delaycnt) delaycnt = 1;
1407. 			if (!cansee(bhitpos.x,bhitpos.y)) curs_on_u();
1408. 			tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
1409. 			tmp_at(bhitpos.x, bhitpos.y);
1410. 	}
1411. 
1412. 	/* Set the object in motion */
1413. 	while(dist-- > 0 && !used_up) {
1414. 		struct trap *t;
1415. 		tmp_at(bhitpos.x, bhitpos.y);
1416. 		tmp = delaycnt;
1417. 
1418. 		/* dstage@u.washington.edu -- Delay only if hero sees it */
1419. 		if (cansee(bhitpos.x, bhitpos.y))
1420. 			while (tmp-- > 0) delay_output();
1421. 
1422. 		bhitpos.x += dx;
1423. 		bhitpos.y += dy;
1424. 		t = t_at(bhitpos.x, bhitpos.y);
1425. 		
1426. 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
1427. 			if (otyp == BOULDER && throws_rocks(mtmp->data)) {
1428. 			    if (rn2(3)) {
1429. 				if (cansee(bhitpos.x, bhitpos.y))
1430. 				    pline("%s snatches the boulder.",
1431. 					    Monnam(mtmp));
1432. 				else
1433. 				    You_hear("a rumbling stop abruptly.");
1434. 				singleobj->otrapped = 0;
1435. 				(void) mpickobj(mtmp, singleobj);
1436. 				used_up = TRUE;
1437. 				break;
1438. 			    }
1439. 			}
1440. 			if (ohitmon((struct monst *) 0, mtmp,singleobj,
1441. 					(style==ROLL) ? -1 : dist, FALSE)) {
1442. 				used_up = TRUE;
1443. 				break;
1444. 			}
1445. 		} else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
1446. 			if (multi) nomul(0);
1447. 			if (thitu(9 + singleobj->spe,
1448. 				  dmgval(singleobj, &youmonst),
1449. 				  singleobj, (char *)0))
1450. 			    stop_occupation();
1451. 		}
1452. 		if (style == ROLL) {
1453. 		    if (down_gate(bhitpos.x, bhitpos.y) != -1) {
1454. 		        if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){
1455. 				used_up = TRUE;
1456. 				break;
1457. 			}
1458. 		    }
1459. 		    if (t && otyp == BOULDER) {
1460. 			switch(t->ttyp) {
1461. 			case LANDMINE:
1462. 			    if (rn2(10) > 2) {
1463. 			  	pline(
1464. 				  "KAABLAMM!!!%s",
1465. 				  cansee(bhitpos.x, bhitpos.y) ?
1466. 					" The rolling boulder triggers a land mine." : "");
1467. 				deltrap(t);
1468. 				del_engr_at(bhitpos.x,bhitpos.y);
1469. 				place_object(singleobj, bhitpos.x, bhitpos.y);
1470. 				singleobj->otrapped = 0;
1471. 				fracture_rock(singleobj);
1472. 				(void)scatter(bhitpos.x,bhitpos.y, 4,
1473. 					MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS,
1474. 					(struct obj *)0);
1475. 				if (cansee(bhitpos.x,bhitpos.y))
1476. 					newsym(bhitpos.x,bhitpos.y);
1477. 			        used_up = TRUE;
1478. 			    }
1479. 			    break;		
1480. 			case LEVEL_TELEP:
1481. 			case TELEP_TRAP:
1482. 			    if (cansee(bhitpos.x, bhitpos.y))
1483. 			    	pline("Suddenly the rolling boulder disappears!");
1484. 			    else
1485. 			    	You_hear("a rumbling stop abruptly.");
1486. 			    singleobj->otrapped = 0;
1487. 			    if (t->ttyp == TELEP_TRAP)
1488. 				rloco(singleobj);
1489. 			    else {
1490. 				int newlev = random_teleport_level();
1491. 				d_level dest;
1492. 
1493. 				if (newlev == depth(&u.uz) || In_endgame(&u.uz))
1494. 				    continue;
1495. 				add_to_migration(singleobj);
1496. 				get_level(&dest, newlev);
1497. 				singleobj->ox = dest.dnum;
1498. 				singleobj->oy = dest.dlevel;
1499. 				singleobj->owornmask = (long)MIGR_RANDOM;
1500. 			    }
1501. 		    	    seetrap(t);
1502. 			    used_up = TRUE;
1503. 			    break;
1504. 			case PIT:
1505. 			case SPIKED_PIT:
1506. 			case HOLE:
1507. 			case TRAPDOOR:
1508. 			    /* the boulder won't be used up if there is a
1509. 			       monster in the trap; stop rolling anyway */
1510. 			    x2 = bhitpos.x,  y2 = bhitpos.y;  /* stops here */
1511. 			    if (flooreffects(singleobj, x2, y2, "fall"))
1512. 				used_up = TRUE;
1513. 			    dist = -1;	/* stop rolling immediately */
1514. 			    break;
1515. 			}
1516. 			if (used_up || dist == -1) break;
1517. 		    }
1518. 		    if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) {
1519. 			used_up = TRUE;
1520. 			break;
1521. 		    }
1522. 		    if (otyp == BOULDER &&
1523. 		       (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) {
1524. 			const char *bmsg =
1525. 				" as one boulder sets another in motion";
1526. 
1527. 			if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist ||
1528. 			    IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ))
1529. 			    bmsg = " as one boulder hits another";
1530. 
1531. 		    	You_hear("a loud crash%s!",
1532. 				cansee(bhitpos.x, bhitpos.y) ? bmsg : "");
1533. 			obj_extract_self(otmp2);
1534. 			/* pass off the otrapped flag to the next boulder */
1535. 			otmp2->otrapped = singleobj->otrapped;
1536. 			singleobj->otrapped = 0;
1537. 			place_object(singleobj, bhitpos.x, bhitpos.y);
1538. 			singleobj = otmp2;
1539. 			otmp2 = (struct obj *)0;
1540. 			wake_nearto(bhitpos.x, bhitpos.y, 10*10);
1541. 		    }
1542. 		}
1543. 		if (otyp == BOULDER && closed_door(bhitpos.x,bhitpos.y)) {
1544. 			if (cansee(bhitpos.x, bhitpos.y))
1545. 				pline_The("boulder crashes through a door.");
1546. 			levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN;
1547. 			if (dist) unblock_point(bhitpos.x, bhitpos.y);
1548. 		}
1549. 
1550. 		/* if about to hit iron bars, do so now */
1551. 		if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) &&
1552. 			levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) {
1553. 		    x2 = bhitpos.x,  y2 = bhitpos.y;	/* object stops here */
1554. 		    if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) {
1555. 			if (!singleobj) used_up = TRUE;
1556. 			break;
1557. 		    }
1558. 		}
1559. 	}
1560. 	tmp_at(DISP_END, 0);
1561. 	if (!used_up) {
1562. 		singleobj->otrapped = 0;
1563. 		place_object(singleobj, x2,y2);
1564. 		newsym(x2,y2);
1565. 		return 1;
1566. 	} else
1567. 		return 2;
1568. }
1569. 
1570. #endif /* OVL3 */
1571. #ifdef OVLB
1572. 
1573. void
1574. seetrap(trap)
1575. 	register struct trap *trap;
1576. {
1577. 	if(!trap->tseen) {
1578. 	    trap->tseen = 1;
1579. 	    newsym(trap->tx, trap->ty);
1580. 	}
1581. }
1582. 
1583. #endif /* OVLB */
1584. #ifdef OVL3
1585. 
1586. STATIC_OVL int
1587. mkroll_launch(ttmp, x, y, otyp, ocount)
1588. struct trap *ttmp;
1589. xchar x,y;
1590. short otyp;
1591. long ocount;
1592. {
1593. 	struct obj *otmp;
1594. 	register int tmp;
1595. 	schar dx,dy;
1596. 	int distance;
1597. 	coord cc;
1598. 	coord bcc;
1599. 	int trycount = 0;
1600. 	boolean success = FALSE;
1601. 	int mindist = 4;
1602. 
1603. 	if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2;
1604. 	distance = rn1(5,4);    /* 4..8 away */
1605. 	tmp = rn2(8);		/* randomly pick a direction to try first */
1606. 	while (distance >= mindist) {
1607. 		dx = xdir[tmp];
1608. 		dy = ydir[tmp];
1609. 		cc.x = x; cc.y = y;
1610. 		/* Prevent boulder from being placed on water */
1611. 		if (ttmp->ttyp == ROLLING_BOULDER_TRAP
1612. 				&& is_pool(x+distance*dx,y+distance*dy))
1613. 			success = FALSE;
1614. 		else success = isclearpath(&cc, distance, dx, dy);
1615. 		if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
1616. 			boolean success_otherway;
1617. 			bcc.x = x; bcc.y = y;
1618. 			success_otherway = isclearpath(&bcc, distance,
1619. 						-(dx), -(dy));
1620. 			if (!success_otherway) success = FALSE;
1621. 		}
1622. 		if (success) break;
1623. 		if (++tmp > 7) tmp = 0;
1624. 		if ((++trycount % 8) == 0) --distance;
1625. 	}
1626. 	if (!success) {
1627. 	    /* create the trap without any ammo, launch pt at trap location */
1628. 		cc.x = bcc.x = x;
1629. 		cc.y = bcc.y = y;
1630. 	} else {
1631. 		otmp = mksobj(otyp, TRUE, FALSE);
1632. 		otmp->quan = ocount;
1633. 		otmp->owt = weight(otmp);
1634. 		place_object(otmp, cc.x, cc.y);
1635. 		stackobj(otmp);
1636. 	}
1637. 	ttmp->launch.x = cc.x;
1638. 	ttmp->launch.y = cc.y;
1639. 	if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
1640. 		ttmp->launch2.x = bcc.x;
1641. 		ttmp->launch2.y = bcc.y;
1642. 	} else
1643. 		ttmp->launch_otyp = otyp;
1644. 	newsym(ttmp->launch.x, ttmp->launch.y);
1645. 	return 1;
1646. }
1647. 
1648. STATIC_OVL boolean
1649. isclearpath(cc,distance,dx,dy)
1650. coord *cc;
1651. int distance;
1652. schar dx,dy;
1653. {
1654. 	uchar typ;
1655. 	xchar x, y;
1656. 
1657. 	x = cc->x;
1658. 	y = cc->y;
1659. 	while (distance-- > 0) {
1660. 		x += dx;
1661. 		y += dy;
1662. 		typ = levl[x][y].typ;
1663. 		if (!isok(x,y) || !ZAP_POS(typ) || closed_door(x,y))
1664. 			return FALSE;
1665. 	}
1666. 	cc->x = x;
1667. 	cc->y = y;
1668. 	return TRUE;
1669. }
1670. #endif /* OVL3 */
1671. #ifdef OVL1
1672. 
1673. void
1674. mon_drain_en(mtmp, n)
1675. struct monst *mtmp;
1676. register int n;
1677. {
1678. 	if (!mtmp->m_enmax) return;
1679. 	if (canseemon(mtmp)) 
1680. 		pline("%s looks less powerful!", Monnam(mtmp));
1681. 	mtmp->m_en -= n;
1682. 	if(mtmp->m_en < 0)  {
1683. 		mtmp->m_enmax += mtmp->m_en;
1684. 		if(mtmp->m_enmax < 0) mtmp->m_enmax = 0;
1685. 		mtmp->m_en = 0;
1686. 	}
1687. }
1688. 
1689. 
1690. int
1691. mintrap(mtmp)
1692. register struct monst *mtmp;
1693. {
1694. 	register struct trap *trap = t_at(mtmp->mx, mtmp->my);
1695. 	boolean trapkilled = FALSE;
1696. 	struct permonst *mptr = mtmp->data;
1697. 	struct obj *otmp;
1698. 
1699. 	if (!trap) {
1700. 	    mtmp->mtrapped = 0;	/* perhaps teleported? */
1701. 	} else if (mtmp->mtrapped) {	/* is currently in the trap */
1702. 	    if (!trap->tseen &&
1703. 		cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) &&
1704. 		(trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP ||
1705. 		 trap->ttyp == HOLE || trap->ttyp == PIT ||
1706. 		 trap->ttyp == WEB)) {
1707. 		/* If you come upon an obviously trapped monster, then
1708. 		 * you must be able to see the trap it's in too.
1709. 		 */
1710. 		seetrap(trap);
1711. 	    }
1712. 		
1713. 	    if (!rn2(40)) {
1714. 		if (sobj_at(BOULDER, mtmp->mx, mtmp->my) &&
1715. 			(trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
1716. 		    if (!rn2(2)) {
1717. 			mtmp->mtrapped = 0;
1718. 			if (canseemon(mtmp))
1719. 			    pline("%s pulls free...", Monnam(mtmp));
1720. 			fill_pit(mtmp->mx, mtmp->my);
1721. 		    }
1722. 		} else {
1723. 		    mtmp->mtrapped = 0;
1724. 		}
1725. 	    } else if (metallivorous(mptr)) {
1726. 		if (trap->ttyp == BEAR_TRAP) {
1727. 		    if (canseemon(mtmp))
1728. 			pline("%s eats a bear trap!", Monnam(mtmp));
1729. 		    deltrap(trap);
1730. 		    mtmp->meating = 5;
1731. 		    mtmp->mtrapped = 0;
1732. 		} else if (trap->ttyp == SPIKED_PIT) {
1733. 		    if (canseemon(mtmp))
1734. 			pline("%s munches on some spikes!", Monnam(mtmp));
1735. 		    trap->ttyp = PIT;
1736. 		    mtmp->meating = 5;
1737. 		}
1738. 	    }
1739. 	} else {
1740. 	    register int tt = trap->ttyp;
1741. 	    boolean in_sight, tear_web, see_it,
1742. 		    inescapable = ((tt == HOLE || tt == PIT) &&
1743. 				   In_sokoban(&u.uz) && !trap->madeby_u);
1744. 	    const char *fallverb;
1745. 
1746. #ifdef STEED
1747. 	    /* true when called from dotrap, inescapable is not an option */
1748. 	    if (mtmp == u.usteed) inescapable = TRUE;
1749. #endif
1750. 	    if (!inescapable &&
1751. 		    ((mtmp->mtrapseen & (1 << (tt-1))) != 0 ||
1752. 			(tt == HOLE && !mindless(mtmp->data)))) {
1753. 		/* it has been in such a trap - perhaps it escapes */
1754. 		if(rn2(4)) return(0);
1755. 	    } else {
1756. 		mtmp->mtrapseen |= (1 << (tt-1));
1757. 	    }
1758. 	    /* Monster is aggravated by being trapped by you.
1759. 	       Recognizing who made the trap isn't completely
1760. 	       unreasonable; everybody has their own style. */
1761. 	    if (trap->madeby_u && rnl(5)) setmangry(mtmp);
1762. 
1763. 	    in_sight = canseemon(mtmp);
1764. 	    see_it = cansee(mtmp->mx, mtmp->my);
1765. #ifdef STEED
1766. 	    /* assume hero can tell what's going on for the steed */
1767. 	    if (mtmp == u.usteed) in_sight = TRUE;
1768. #endif
1769. 	    switch (tt) {
1770. 		case ARROW_TRAP:
1771. 			if (trap->once && trap->tseen && !rn2(15)) {
1772. 			    if (in_sight && see_it)
1773. 				pline("%s triggers a trap but nothing happens.",
1774. 				      Monnam(mtmp));
1775. 			    deltrap(trap);
1776. 			    newsym(mtmp->mx, mtmp->my);
1777. 			    break;
1778. 			}
1779. 			trap->once = 1;
1780. 			otmp = mksobj(ARROW, TRUE, FALSE);
1781. 			otmp->quan = 1L;
1782. 			otmp->owt = weight(otmp);
1783. 			otmp->opoisoned = 0;
1784. 			if (in_sight) seetrap(trap);
1785. 			if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1786. 			break;
1787. 		case DART_TRAP:
1788. 			if (trap->once && trap->tseen && !rn2(15)) {
1789. 			    if (in_sight && see_it)
1790. 				pline("%s triggers a trap but nothing happens.",
1791. 				      Monnam(mtmp));
1792. 			    deltrap(trap);
1793. 			    newsym(mtmp->mx, mtmp->my);
1794. 			    break;
1795. 			}
1796. 			trap->once = 1;
1797. 			otmp = mksobj(DART, TRUE, FALSE);
1798. 			otmp->quan = 1L;
1799. 			otmp->owt = weight(otmp);
1800. 			if (!rn2(6)) otmp->opoisoned = 1;
1801. 			if (in_sight) seetrap(trap);
1802. 			if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1803. 			break;
1804. 		case ROCKTRAP:
1805. 			if (trap->once && trap->tseen && !rn2(15)) {
1806. 			    if (in_sight && see_it)
1807. 				pline("A trap door above %s opens, but nothing falls out!",
1808. 				      mon_nam(mtmp));
1809. 			    deltrap(trap);
1810. 			    newsym(mtmp->mx, mtmp->my);
1811. 			    break;
1812. 			}
1813. 			trap->once = 1;
1814. 			otmp = mksobj(ROCK, TRUE, FALSE);
1815. 			otmp->quan = 1L;
1816. 			otmp->owt = weight(otmp);
1817. 			otmp->opoisoned = 0;
1818. 			if (in_sight) seetrap(trap);
1819. 			if (thitm(0, mtmp, otmp, d(2, 6), FALSE))
1820. 			    trapkilled = TRUE;
1821. 			break;
1822. 
1823. 		case SQKY_BOARD:
1824. 			if(is_flyer(mptr)) break;
1825. 			/* stepped on a squeaky board */
1826. 			if (in_sight) {
1827. 			    pline("A board beneath %s squeaks loudly.", mon_nam(mtmp));
1828. 			    seetrap(trap);
1829. 			} else
1830. 			   You_hear("a distant squeak.");
1831. 			/* wake up nearby monsters */
1832. 			wake_nearto(mtmp->mx, mtmp->my, 40);
1833. 			break;
1834. 
1835. 		case BEAR_TRAP:
1836. 			if(mptr->msize > MZ_SMALL &&
1837. 				!amorphous(mptr) && !is_flyer(mptr) &&
1838. 				!is_whirly(mptr) && !unsolid(mptr)) {
1839. 			    mtmp->mtrapped = 1;
1840. 			    if(in_sight) {
1841. 				pline("%s is caught in %s bear trap!",
1842. 				      Monnam(mtmp), a_your[trap->madeby_u]);
1843. 				seetrap(trap);
1844. 			    } else {
1845. 				if((mptr == &mons[PM_OWLBEAR]
1846. 				    || mptr == &mons[PM_BUGBEAR])
1847. 				   && flags.soundok)
1848. 				    You_hear("the roaring of an angry bear!");
1849. 			    }
1850. 			}
1851. 			break;
1852. 
1853. 		case SLP_GAS_TRAP:
1854. 		    if (!resists_sleep(mtmp) && !breathless(mptr) &&
1855. 				!mtmp->msleeping && mtmp->mcanmove) {
1856. 			    mtmp->mcanmove = 0;
1857. 			    mtmp->mfrozen = rnd(25);
1858. 			    if (in_sight) {
1859. 				pline("%s suddenly falls asleep!",
1860. 				      Monnam(mtmp));
1861. 				seetrap(trap);
1862. 			    }
1863. 			}
1864. 			break;
1865. 
1866. 		case RUST_TRAP:
1867. 		    {
1868. 			struct obj *target;
1869. 
1870. 			if (in_sight)
1871. 			    seetrap(trap);
1872. 			switch (rn2(5)) {
1873. 			case 0:
1874. 			    if (in_sight)
1875. 				pline("%s %s on the %s!", A_gush_of_water_hits,
1876. 				    mon_nam(mtmp), mbodypart(mtmp, HEAD));
1877. 			    target = which_armor(mtmp, W_ARMH);
1878. 			    (void) rust_dmg(target, "helmet", 1, TRUE, mtmp);
1879. 			    break;
1880. 			case 1:
1881. 			    if (in_sight)
1882. 				pline("%s %s's left %s!", A_gush_of_water_hits,
1883. 				    mon_nam(mtmp), mbodypart(mtmp, ARM));
1884. 			    target = which_armor(mtmp, W_ARMS);
1885. 			    if (rust_dmg(target, "shield", 1, TRUE, mtmp))
1886. 				break;
1887. 			    target = MON_WEP(mtmp);
1888. 			    if (target && bimanual(target))
1889. 				erode_obj(target, FALSE, TRUE);
1890. glovecheck:		    target = which_armor(mtmp, W_ARMG);
1891. 			    (void) rust_dmg(target, "gauntlets", 1, TRUE, mtmp);
1892. 			    break;
1893. 			case 2:
1894. 			    if (in_sight)
1895. 				pline("%s %s's right %s!", A_gush_of_water_hits,
1896. 				    mon_nam(mtmp), mbodypart(mtmp, ARM));
1897. 			    if (MON_WEP(mtmp) && !snuff_lit(MON_WEP(mtmp)))
1898. 				erode_obj(MON_WEP(mtmp), FALSE, TRUE);
1899. 			    goto glovecheck;
1900. 			default:
1901. 			    if (in_sight)
1902. 				pline("%s %s!", A_gush_of_water_hits,
1903. 				    mon_nam(mtmp));
1904. 			    for (otmp=mtmp->minvent; otmp; otmp = otmp->nobj)
1905. 				(void) snuff_lit(otmp);
1906. 			    target = which_armor(mtmp, W_ARMC);
1907. 			    if (target)
1908. 				(void) rust_dmg(target, cloak_simple_name(target),
1909. 						 1, TRUE, mtmp);
1910. 			    else {
1911. 				target = which_armor(mtmp, W_ARM);
1912. 				if (target)
1913. 				    (void) rust_dmg(target, "armor", 1, TRUE, mtmp);
1914. #ifdef TOURIST
1915. 				else {
1916. 				    target = which_armor(mtmp, W_ARMU);
1917. 				    (void) rust_dmg(target, "shirt", 1, TRUE, mtmp);
1918. 				}
1919. #endif
1920. 			    }
1921. 			}
1922. 			if (mptr == &mons[PM_IRON_GOLEM]) {
1923. 				if (in_sight)
1924. 				    pline("%s falls to pieces!", Monnam(mtmp));
1925. 				else if(mtmp->mtame)
1926. 				    pline("May %s rust in peace.",
1927. 								mon_nam(mtmp));
1928. 				mondied(mtmp);
1929. 				if (mtmp->mhp <= 0)
1930. 					trapkilled = TRUE;
1931. 			} else if (mptr == &mons[PM_FLAMING_SPHERE]) {
1932. 				if (in_sight)
1933. 				    pline("%s is extinguished!", Monnam(mtmp));
1934. 				mondied(mtmp);
1935. 				if (mtmp->mhp <= 0)
1936. 					trapkilled = TRUE;
1937. 			} else if (mptr == &mons[PM_GREMLIN] && rn2(3)) {
1938. 				(void)split_mon(mtmp, (struct monst *)0);
1939. 			}
1940. 			break;
1941. 		    }
1942. 		case FIRE_TRAP:
1943.  mfiretrap:
1944. 			if (in_sight)
1945. 			    pline("A %s erupts from the %s under %s!",
1946. 				  tower_of_flame,
1947. 				  surface(mtmp->mx,mtmp->my), mon_nam(mtmp));
1948. 			else if (see_it)  /* evidently `mtmp' is invisible */
1949. 			    You("see a %s erupt from the %s!",
1950. 				tower_of_flame, surface(mtmp->mx,mtmp->my));
1951. 			if (Slimed) {
1952. 				pline("The slime that covers you is burned away!");
1953. 				Slimed = 0;
1954. 			}
1955. 
1956. 			if (resists_fire(mtmp)) {
1957. 			    if (in_sight) {
1958. 				shieldeff(mtmp->mx,mtmp->my);
1959. 				pline("%s is uninjured.", Monnam(mtmp));
1960. 			    }
1961. 			} else {
1962. 			    int num = d(2,4), alt;
1963. 			    boolean immolate = FALSE;
1964. 
1965. 			    /* paper burns very fast, assume straw is tightly
1966. 			     * packed and burns a bit slower */
1967. 			    switch (monsndx(mtmp->data)) {
1968. 			    case PM_PAPER_GOLEM:   immolate = TRUE;
1969. 						   alt = mtmp->mhpmax; break;
1970. 			    case PM_STRAW_GOLEM:   alt = mtmp->mhpmax / 2; break;
1971. 			    case PM_WOOD_GOLEM:    alt = mtmp->mhpmax / 4; break;
1972. 			    case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break;
1973. 			    default: alt = 0; break;
1974. 			    }
1975. 			    if (alt > num) num = alt;
1976. 
1977. 			    if (thitm(0, mtmp, (struct obj *)0, num, immolate))
1978. 				trapkilled = TRUE;
1979. 			    else
1980. 				/* we know mhp is at least `num' below mhpmax,
1981. 				   so no (mhp > mhpmax) check is needed here */
1982. 				mtmp->mhpmax -= rn2(num + 1);
1983. 			}
1984. 			if (burnarmor(mtmp) || rn2(3)) {
1985. 			    (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
1986. 			    (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
1987. 			    (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
1988. 			}
1989. 			if (burn_floor_paper(mtmp->mx, mtmp->my, see_it, FALSE) &&
1990. 				!see_it && distu(mtmp->mx, mtmp->my) <= 3*3)
1991. 			    You("smell smoke.");
1992. 			if (is_ice(mtmp->mx,mtmp->my))
1993. 			    melt_ice(mtmp->mx,mtmp->my);
1994. 			if (see_it) seetrap(trap);
1995. 			break;
1996. 
1997. 		case PIT:
1998. 		case SPIKED_PIT:
1999. 			fallverb = "falls";
2000. 			if (is_flyer(mptr) || is_floater(mptr) ||
2001. 				(mtmp->wormno && count_wsegs(mtmp) > 5) ||
2002. 				is_clinger(mptr)) {
2003. 			    if (!inescapable) break;	/* avoids trap */
2004. 			    fallverb = "is dragged";	/* sokoban pit */
2005. 			}
2006. 			if (!passes_walls(mptr))
2007. 			    mtmp->mtrapped = 1;
2008. 			if(in_sight) {
2009. 			    pline("%s %s into %s pit!",
2010. 				  Monnam(mtmp), fallverb,
2011. 				  a_your[trap->madeby_u]);
2012. 			    if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND])
2013. 				pline("How pitiful.  Isn't that the pits?");
2014. 			    seetrap(trap);
2015. 			}
2016. 			mselftouch(mtmp, "Falling, ", FALSE);
2017. 			if (mtmp->mhp <= 0 ||
2018. 				thitm(0, mtmp, (struct obj *)0,
2019. 				      rnd((tt == PIT) ? 6 : 10), FALSE))
2020. 			    trapkilled = TRUE;
2021. 			break;
2022. 		case HOLE:
2023. 		case TRAPDOOR:
2024. 			if (!Can_fall_thru(&u.uz)) {
2025. 			 impossible("mintrap: %ss cannot exist on this level.",
2026. 				    defsyms[trap_to_defsym(tt)].explanation);
2027. 			    break;	/* don't activate it after all */
2028. 			}
2029. 			if (is_flyer(mptr) || is_floater(mptr) ||
2030. 				mptr == &mons[PM_WUMPUS] ||
2031. 				(mtmp->wormno && count_wsegs(mtmp) > 5) ||
2032. 				mptr->msize >= MZ_HUGE) {
2033. 			    if (inescapable) {	/* sokoban hole */
2034. 				if (in_sight) {
2035. 				    pline("%s seems to be yanked down!",
2036. 					  Monnam(mtmp));
2037. 				    /* suppress message in mlevel_tele_trap() */
2038. 				    in_sight = FALSE;
2039. 				    seetrap(trap);
2040. 				}
2041. 			    } else
2042. 				break;
2043. 			}
2044. 			/* Fall through */
2045. 		case LEVEL_TELEP:
2046. 		case MAGIC_PORTAL:
2047. 			{
2048. 			    int mlev_res;
2049. 			    mlev_res = mlevel_tele_trap(mtmp, trap,
2050. 							inescapable, in_sight);
2051. 			    if (mlev_res) return(mlev_res);
2052. 			}
2053. 			break;
2054. 
2055. 		case TELEP_TRAP:
2056. 			mtele_trap(mtmp, trap, in_sight);
2057. 			break;
2058. 
2059. 		case WEB:
2060. 			/* Monster in a web. */
2061. 			if (webmaker(mptr)) break;
2062. 			if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)){
2063. 			    if(acidic(mptr) ||
2064. 			       mptr == &mons[PM_GELATINOUS_CUBE] ||
2065. 			       mptr == &mons[PM_FIRE_ELEMENTAL]) {
2066. 				if (in_sight)
2067. 				    pline("%s %s %s spider web!",
2068. 					  Monnam(mtmp),
2069. 					  (mptr == &mons[PM_FIRE_ELEMENTAL]) ?
2070. 					    "burns" : "dissolves",
2071. 					  a_your[trap->madeby_u]);
2072. 				deltrap(trap);
2073. 				newsym(mtmp->mx, mtmp->my);
2074. 				break;
2075. 			    }
2076. 			    if (in_sight) {
2077. 				pline("%s flows through %s spider web.",
2078. 				      Monnam(mtmp),
2079. 				      a_your[trap->madeby_u]);
2080. 				seetrap(trap);
2081. 			    }
2082. 			    break;
2083. 			}
2084. 			tear_web = FALSE;
2085. 			switch (monsndx(mptr)) {
2086. 			    case PM_OWLBEAR: /* Eric Backus */
2087. 			    case PM_BUGBEAR:
2088. 				if (!in_sight) {
2089. 				    You_hear("the roaring of a confused bear!");
2090. 				    mtmp->mtrapped = 1;
2091. 				    break;
2092. 				}
2093. 				/* fall though */
2094. 			    default:
2095. 				if (mptr->mlet == S_GIANT ||
2096. 				    (mptr->mlet == S_DRAGON &&
2097. 					extra_nasty(mptr)) || /* excl. babies */
2098. 				    (mtmp->wormno && count_wsegs(mtmp) > 5)) {
2099. 				    tear_web = TRUE;
2100. 				} else if (in_sight) {
2101. 				    pline("%s is caught in %s spider web.",
2102. 					  Monnam(mtmp),
2103. 					  a_your[trap->madeby_u]);
2104. 				    seetrap(trap);
2105. 				}
2106. 				mtmp->mtrapped = tear_web ? 0 : 1;
2107. 				break;
2108. 			    /* this list is fairly arbitrary; it deliberately
2109. 			       excludes wumpus & giant/ettin zombies/mummies */
2110. 			    case PM_TITANOTHERE:
2111. 			    case PM_BALUCHITHERIUM:
2112. 			    case PM_PURPLE_WORM:
2113. 			    case PM_JABBERWOCK:
2114. 			    case PM_IRON_GOLEM:
2115. 			    case PM_BALROG:
2116. 			    case PM_KRAKEN:
2117. 			    case PM_MASTODON:
2118. 				tear_web = TRUE;
2119. 				break;
2120. 			}
2121. 			if (tear_web) {
2122. 			    if (in_sight)
2123. 				pline("%s tears through %s spider web!",
2124. 				      Monnam(mtmp), a_your[trap->madeby_u]);
2125. 			    deltrap(trap);
2126. 			    newsym(mtmp->mx, mtmp->my);
2127. 			}
2128. 			break;
2129. 
2130. 		case STATUE_TRAP:
2131. 			break;
2132. 
2133. 		case MAGIC_TRAP:
2134. 			/* A magic trap.  Monsters usually immune. */
2135. 			if (!rn2(30)) {
2136. 			    deltrap(trap);
2137. 			    newsym(mtmp->mx, mtmp->my);
2138. 			    if (in_sight) 
2139. 				pline("%s is caught in a magical explosion.",
2140. 				    Monnam(mtmp));
2141. 			    if (thitm(0, mtmp, (struct obj *)0, rnd(10), FALSE))
2142. 				trapkilled = TRUE;
2143. 			    else {
2144. 			    	if (in_sight)
2145. 				    pline("%s looks filled with power.",
2146. 					    Monnam(mtmp));
2147. 			    	mtmp->m_en = (mtmp->m_enmax += 2);
2148. 			    }
2149. 			} else if (!rn2(21)) goto mfiretrap;
2150. 			break;
2151. 		case ANTI_MAGIC:
2152. 			if (in_sight) seetrap(trap);
2153. 		    	if (resists_magm(mtmp)) {
2154. 			    if (in_sight) {
2155. 				shieldeff(mtmp->mx,mtmp->my);
2156. 				pline("%s is uninjured.", Monnam(mtmp));
2157. 			    }
2158. 		    	} else {
2159. 		    	    mon_drain_en(mtmp, 
2160. 				((mtmp->m_lev > 0) ? (rnd(mtmp->m_lev)) : 0) + 1);
2161. 		    	}
2162. 			break;
2163. 		case LANDMINE:
2164. 			if(rn2(3))
2165. 				break; /* monsters usually don't set it off */
2166. 			if(is_flyer(mptr)) {
2167. 				boolean already_seen = trap->tseen;
2168. 				if (in_sight && !already_seen) {
2169. 	pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp));
2170. 					seetrap(trap);
2171. 				}
2172. 				if (rn2(3)) break;
2173. 				if (in_sight) {
2174. 					newsym(mtmp->mx, mtmp->my);
2175. 					pline_The("air currents set %s off!",
2176. 					  already_seen ? "a land mine" : "it");
2177. 				}
2178. 			} else if(in_sight) {
2179. 			    newsym(mtmp->mx, mtmp->my);
2180. 			    pline("KAABLAMM!!!  %s triggers %s land mine!",
2181. 				Monnam(mtmp), a_your[trap->madeby_u]);
2182. 			}
2183. 			if (!in_sight)
2184. 				pline("Kaablamm!  You hear an explosion in the distance!");
2185. 			blow_up_landmine(trap);
2186. 			if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
2187. 				trapkilled = TRUE;
2188. 			else {
2189. 				/* monsters recursively fall into new pit */
2190. 				if (mintrap(mtmp) == 2) trapkilled=TRUE;
2191. 			}
2192. 			/* a boulder may fill the new pit, crushing monster */
2193. 			fill_pit(trap->tx, trap->ty);
2194. 			if (mtmp->mhp <= 0) trapkilled = TRUE;
2195. 			if (unconscious()) {
2196. 				multi = -1;
2197. 				nomovemsg="The explosion awakens you!";
2198. 			}
2199. 			break;
2200. 
2201. 		case POLY_TRAP:
2202. 		    if (resists_magm(mtmp)) {
2203. 			shieldeff(mtmp->mx, mtmp->my);
2204. 		    } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
2205. /*                        (void) newcham(mtmp, (struct permonst *)0, FALSE);*/
2206.                         /* WAC use polymorph code from zap.c*/
2207. #if 0
2208.                         if (!rn2(25) || !mon_poly(mtmp)) {
2209.                                 if (in_sight) {
2210.                                         pline("%s shudders!", Monnam(mtmp));
2211.                                         seetrap(trap);
2212.                                 }
2213.                                 /* no corpse after system shock */
2214.                                 mtmp->mhp -= rnd(30);
2215.                                 if (mtmp->mhp < 0) mondead(mtmp);
2216.                         } else {
2217. #endif
2218. 			mon_poly(mtmp, FALSE, "%s changes!");
2219. 			if (in_sight) seetrap(trap);
2220. 		    }
2221. 		    break;
2222. 
2223. 		case ROLLING_BOULDER_TRAP:
2224. 		    if (!is_flyer(mptr)) {
2225. 			int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN);
2226. 
2227. 		        newsym(mtmp->mx,mtmp->my);
2228. 			if (in_sight)
2229. 			    pline("Click! %s triggers %s.", Monnam(mtmp),
2230. 				  trap->tseen ?
2231. 				  "a rolling boulder trap" :
2232. 				  something);
2233. 			if (launch_obj(BOULDER, trap->launch.x, trap->launch.y,
2234. 				trap->launch2.x, trap->launch2.y, style)) {
2235. 			    if (in_sight) trap->tseen = TRUE;
2236. 			    if (mtmp->mhp <= 0) trapkilled = TRUE;
2237. 			} else {
2238. 			    deltrap(trap);
2239. 			    newsym(mtmp->mx,mtmp->my);
2240. 			}
2241. 		    }
2242. 		    break;
2243. 
2244. 		default:
2245. 			impossible("Some monster encountered a strange trap of type %d.", tt);
2246. 	    }
2247. 	}
2248. 	if(trapkilled) return 2;
2249. 	return mtmp->mtrapped;
2250. }
2251. 
2252. #endif /* OVL1 */
2253. #ifdef OVLB
2254. 
2255. /* Combine cockatrice checks into single functions to avoid repeating code. */
2256. void
2257. instapetrify(str)
2258. const char *str;
2259. {
2260. 	if (Stone_resistance) return;
2261. 	if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2262. 	    return;
2263. 	You("turn to stone...");
2264. 	killer_format = KILLED_BY_AN;
2265. 	killer = str;
2266. 	done(STONING);
2267. }
2268. 
2269. void
2270. minstapetrify(mon,byplayer)
2271. struct monst *mon;
2272. boolean byplayer;
2273. {
2274. 	if (resists_ston(mon)) return;
2275. 	if (poly_when_stoned(mon->data)) {
2276. 		mon_to_stone(mon);
2277. 		return;
2278. 	}
2279. 
2280. 	/* give a "<mon> is slowing down" message and also remove
2281. 	   intrinsic speed (comparable to similar effect on the hero) */
2282. 	mon_adjust_speed(mon, -3, (struct obj *)0);
2283. 
2284. 	if (cansee(mon->mx, mon->my))
2285. 		pline("%s turns to stone.", Monnam(mon));
2286. 	if (byplayer) {
2287. 		stoned = TRUE;
2288. 		xkilled(mon,0);
2289. 	} else monstone(mon);
2290. }
2291. 
2292. void
2293. selftouch(arg)
2294. const char *arg;
2295. {
2296. 	char kbuf[BUFSZ];
2297. 
2298. 	if(uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm])
2299. 			&& !Stone_resistance) {
2300. 		pline("%s touch the %s corpse.", arg,
2301. 		        mons[uwep->corpsenm].mname);
2302. 		Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname));
2303. 		instapetrify(kbuf);
2304. 	}
2305. 	/* Or your secondary weapon, if wielded */
2306. 	if(u.twoweap && uswapwep && uswapwep->otyp == CORPSE &&
2307. 			touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance){
2308. 		pline("%s touch the %s corpse.", arg,
2309. 		        mons[uswapwep->corpsenm].mname);
2310. 		Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
2311. 		instapetrify(kbuf);
2312. 	}
2313. }
2314. 
2315. void
2316. mselftouch(mon,arg,byplayer)
2317. struct monst *mon;
2318. const char *arg;
2319. boolean byplayer;
2320. {
2321. 	struct obj *mwep = MON_WEP(mon);
2322. 
2323. 	if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm])) {
2324. 		if (cansee(mon->mx, mon->my)) {
2325. 			pline("%s%s touches the %s corpse.",
2326. 			    arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon),
2327. 			    mons[mwep->corpsenm].mname);
2328. 		}
2329. 		minstapetrify(mon, byplayer);
2330. 	}
2331. }
2332. 
2333. /* KMH, balance patch -- several ways for the player to fix stoning */
2334. int
2335. uunstone()
2336. {
2337. 	if (Stoned) {
2338. 		Stoned = 0;
2339. 		if (!Hallucination)
2340. 			You_feel("limber!");
2341. 	    else
2342. 		pline("What a pity - you just ruined a future piece of %sart!",
2343. 		      ACURR(A_CHA) > 15 ? "fine " : "");
2344. 		/* The problem was fixed */
2345. 		return (1);
2346. 	}
2347. 	/* No problem to fix */
2348. 	return (0);
2349. }
2350. 
2351. 
2352. void
2353. float_up()
2354. {
2355. 	if(u.utrap) {
2356. 		if(u.utraptype == TT_PIT) {
2357. 			u.utrap = 0;
2358. 			You("float up, out of the pit!");
2359. 			vision_full_recalc = 1;	/* vision limits change */
2360. 			fill_pit(u.ux, u.uy);
2361. 		} else if (u.utraptype == TT_INFLOOR) {
2362. 			Your("body pulls upward, but your %s are still stuck.",
2363. 			     makeplural(body_part(LEG)));
2364. 		} else {
2365. 			You("float up, only your %s is still stuck.",
2366. 				body_part(LEG));
2367. 		}
2368. 	}
2369. 	else if(Is_waterlevel(&u.uz))
2370. 		pline("It feels as though you've lost some weight.");
2371. 	else if(u.uinwater)
2372. 		spoteffects(TRUE);
2373. 	else if(u.uswallow)
2374. 		You(is_animal(u.ustuck->data) ?
2375. 			"float away from the %s."  :
2376. 			"spiral up into %s.",
2377. 		    is_animal(u.ustuck->data) ?
2378. 			surface(u.ux, u.uy) :
2379. 			mon_nam(u.ustuck));
2380. 	else if (Hallucination)
2381. 		pline("Up, up, and awaaaay!  You're walking on air!");
2382. 	else if(Is_airlevel(&u.uz))
2383. 		You("gain control over your movements.");
2384. 	else
2385. 		You("start to float in the air!");
2386. #ifdef STEED
2387. 	if (u.usteed && !is_floater(u.usteed->data) &&
2388. 						!is_flyer(u.usteed->data)) {
2389. 	    if (Lev_at_will)
2390. 	    	pline("%s magically floats up!", Monnam(u.usteed));
2391. 	    else {
2392. 	    	You("cannot stay on %s.", mon_nam(u.usteed));
2393. 	    	dismount_steed(DISMOUNT_GENERIC);
2394. 	    }
2395. 	}
2396. #endif
2397. 	return;
2398. }
2399. 
2400. void
2401. fill_pit(x, y)
2402. int x, y;
2403. {
2404. 	struct obj *otmp;
2405. 	struct trap *t;
2406. 
2407. 	if ((t = t_at(x, y)) &&
2408. 	    ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) &&
2409. 	    (otmp = sobj_at(BOULDER, x, y))) {
2410. 		obj_extract_self(otmp);
2411. 		(void) flooreffects(otmp, x, y, "settle");
2412. 	}
2413. }
2414. 
2415. int
2416. float_down(hmask, emask)
2417. long hmask, emask;     /* might cancel timeout */
2418. {
2419. 	register struct trap *trap = (struct trap *)0;
2420. 	d_level current_dungeon_level;
2421. 	boolean no_msg = FALSE;
2422. 
2423. 	HLevitation &= ~hmask;
2424. 	ELevitation &= ~emask;
2425. 	if(Levitation) return(0); /* maybe another ring/potion/boots */
2426. 	if(u.uswallow) {
2427. 	    You("float down, but you are still %s.",
2428. 		is_animal(u.ustuck->data) ? "swallowed" : "engulfed");
2429. 	    return(1);
2430. 	}
2431. 
2432. 	if (Punished && !carried(uball) &&
2433. 	    (is_pool(uball->ox, uball->oy) ||
2434. 	     ((trap = t_at(uball->ox, uball->oy)) &&
2435. 	      ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) ||
2436. 	       (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) {
2437. 			u.ux0 = u.ux;
2438. 			u.uy0 = u.uy;
2439. 			u.ux = uball->ox;
2440. 			u.uy = uball->oy;
2441. 			movobj(uchain, uball->ox, uball->oy);
2442. 			newsym(u.ux0, u.uy0);
2443. 			vision_full_recalc = 1;	/* in case the hero moved. */
2444. 	}
2445. 	/* check for falling into pool - added by GAN 10/20/86 */
2446. 	if(!Flying) {
2447. 		if (!u.uswallow && u.ustuck) {
2448. 			if (sticks(youmonst.data))
2449. 				You("aren't able to maintain your hold on %s.",
2450. 					mon_nam(u.ustuck));
2451. 			else
2452. 				pline("Startled, %s can no longer hold you!",
2453. 					mon_nam(u.ustuck));
2454. 			u.ustuck = 0;
2455. 		}
2456. 		/* kludge alert:
2457. 		 * drown() and lava_effects() print various messages almost
2458. 		 * every time they're called which conflict with the "fall
2459. 		 * into" message below.  Thus, we want to avoid printing
2460. 		 * confusing, duplicate or out-of-order messages.
2461. 		 * Use knowledge of the two routines as a hack -- this
2462. 		 * should really be handled differently -dlc
2463. 		 */
2464. 		if(is_pool(u.ux,u.uy) && !Wwalking && !Swimming && !u.uinwater)
2465. 			no_msg = drown();
2466. 
2467. 		if(is_lava(u.ux,u.uy)) {
2468. 			(void) lava_effects();
2469. 			no_msg = TRUE;
2470. 		}
2471. 	}
2472. 	if (!trap) {
2473. 	    trap = t_at(u.ux,u.uy);
2474. 	    if(Is_airlevel(&u.uz))
2475. 		You("begin to tumble in place.");
2476. 	    else if (Is_waterlevel(&u.uz) && !no_msg)
2477. 		You_feel("heavier.");
2478. 	    /* u.uinwater msgs already in spoteffects()/drown() */
2479. 	    else if (!u.uinwater && !no_msg) {
2480. #ifdef STEED
2481. 		if (!(emask & W_SADDLE))
2482. #endif
2483. 		{
2484. 		    boolean sokoban_trap = (In_sokoban(&u.uz) && trap);
2485. 		    if (Hallucination)
2486. 			pline("Bummer!  You've %s.",
2487. 			      is_pool(u.ux,u.uy) ?
2488. 			      "splashed down" : sokoban_trap ? "crashed" :
2489. 			      "hit the ground");
2490. 		    else {
2491. 			if (!sokoban_trap)
2492. 			    You("float gently to the %s.",
2493. 				surface(u.ux, u.uy));
2494. 			else {
2495. 			    /* Justification elsewhere for Sokoban traps
2496. 			     * is based on air currents. This is
2497. 			     * consistent with that.
2498. 			     * The unexpected additional force of the
2499. 			     * air currents once leviation
2500. 			     * ceases knocks you off your feet.
2501. 			     */
2502. 			    You("fall over.");
2503. 			    losehp(rnd(2), "dangerous winds", KILLED_BY);
2504. #ifdef STEED
2505. 			    if (u.usteed) dismount_steed(DISMOUNT_FELL);
2506. #endif
2507. 			    selftouch("As you fall, you");
2508. 			}
2509. 		    }
2510. 		}
2511. 	    }
2512. 	}
2513. 
2514. 	/* can't rely on u.uz0 for detecting trap door-induced level change;
2515. 	   it gets changed to reflect the new level before we can check it */
2516. 	assign_level(&current_dungeon_level, &u.uz);
2517. 
2518. 	if(trap)
2519. 		switch(trap->ttyp) {
2520. 		case STATUE_TRAP:
2521. 			break;
2522. 		case HOLE:
2523. 		case TRAPDOOR:
2524. 			if(!Can_fall_thru(&u.uz) || u.ustuck)
2525. 				break;
2526. 			/* fall into next case */
2527. 		default:
2528. 			if (!u.utrap) /* not already in the trap */
2529. 				dotrap(trap, 0);
2530. 	}
2531. 
2532. 	if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow &&
2533. 		/* falling through trap door calls goto_level,
2534. 		   and goto_level does its own pickup() call */
2535. 		on_level(&u.uz, &current_dungeon_level))
2536. 	    (void) pickup(1);
2537. 	return 1;
2538. }
2539. 
2540. STATIC_OVL void
2541. dofiretrap(box)
2542. struct obj *box;	/* null for floor trap */
2543. {
2544. 	boolean see_it = !Blind;
2545. 	int num, alt;
2546. 
2547. /* Bug: for box case, the equivalent of burn_floor_paper() ought
2548.  * to be done upon its contents.
2549.  */
2550. 
2551. 	if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) {
2552. 	    pline("A cascade of steamy bubbles erupts from %s!",
2553. 		    the(box ? xname(box) : surface(u.ux,u.uy)));
2554. 	    if (Fire_resistance) You("are uninjured.");
2555. 	    else losehp(rnd(3), "boiling water", KILLED_BY);
2556. 	    return;
2557. 	}
2558. 	pline("A %s %s from %s!", tower_of_flame,
2559. 	      box ? "bursts" : "erupts",
2560. 	      the(box ? xname(box) : surface(u.ux,u.uy)));
2561. 	if (Slimed) {        
2562. 	      pline("The slime that covers you is burned away!");
2563. 	      Slimed = 0;
2564. 	}
2565. 	if (Fire_resistance) {
2566. 	    shieldeff(u.ux, u.uy);
2567. 	    num = rn2(2);
2568. 	} else if (Upolyd) {
2569. 	    num = d(2,4);
2570. 	    switch (u.umonnum) {
2571. 	    case PM_PAPER_GOLEM:   alt = u.mhmax; break;
2572. 	    case PM_STRAW_GOLEM:   alt = u.mhmax / 2; break;
2573. 	    case PM_WOOD_GOLEM:    alt = u.mhmax / 4; break;
2574. 	    case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break;
2575. 	    default: alt = 0; break;
2576. 	    }
2577. 	    if (alt > num) num = alt;
2578. 	    if (u.mhmax > mons[u.umonnum].mlevel)
2579. 		u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1;
2580. 	} else {
2581. 	    num = d(2,4);
2582. 	    if (u.uhpmax > u.ulevel)
2583. 		u.uhpmax -= rn2(min(u.uhpmax,num + 1)), flags.botl = 1;
2584. 	}
2585. 	if (!num)
2586. 	    You("are uninjured.");
2587. 	else
2588. 	    losehp(num, tower_of_flame, KILLED_BY_AN);
2589. 	burn_away_slime();
2590. 
2591. 	if (burnarmor(&youmonst) || rn2(3)) {
2592. 	    destroy_item(SCROLL_CLASS, AD_FIRE);
2593. 	    destroy_item(SPBOOK_CLASS, AD_FIRE);
2594. 	    destroy_item(POTION_CLASS, AD_FIRE);
2595. 	}
2596. 	if (!box && burn_floor_paper(u.ux, u.uy, see_it, TRUE) && !see_it)
2597. 	    You("smell paper burning.");
2598. 	if (is_ice(u.ux, u.uy))
2599. 	    melt_ice(u.ux, u.uy);
2600. }
2601. 
2602. STATIC_OVL void
2603. domagictrap()
2604. {
2605. 	register int fate = rnd(20);
2606. 
2607. 	/* What happened to the poor sucker? */
2608. 
2609. 	if (fate < 10) {
2610. 	  /* Most of the time, it creates some monsters. */
2611. 	  register int cnt = rnd(4);
2612. 
2613. 	  if (!resists_blnd(&youmonst)) {
2614. 		You("are momentarily blinded by a flash of light!");
2615. 		make_blinded((long)rn1(5,10),FALSE);
2616. 		if (!Blind) Your(vision_clears);
2617. 	  } else if (!Blind) {
2618. 		You("see a flash of light!");
2619. 	  }  else
2620. 		You_hear("a deafening roar!");
2621. 	  while(cnt--)
2622. 		(void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS);
2623. 	}
2624. 	else
2625. 	  switch (fate) {
2626. 
2627. 	     case 10:
2628. 	     case 11:
2629. 		      /* sometimes nothing happens */
2630. 			break;
2631. 	     case 12: /* a flash of fire */
2632. 			dofiretrap((struct obj *)0);
2633. 			break;
2634. 
2635. 	     /* odd feelings */
2636. 	     case 13:	pline("A shiver runs up and down your %s!",
2637. 			      body_part(SPINE));
2638. 			break;
2639. 	     case 14:	You_hear(Hallucination ?
2640. 				"the moon howling at you." :
2641. 				"distant howling.");
2642. 			break;
2643. 	     case 15:	if (on_level(&u.uz, &qstart_level))
2644. 			    You_feel("%slike the prodigal son.",
2645. 			      (flags.female || (Upolyd && is_neuter(youmonst.data))) ?
2646. 				     "oddly " : "");
2647. 			else
2648. 			    You("suddenly yearn for %s.",
2649. 				Hallucination ? "Cleveland" :
2650. 			    (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ?
2651. 						"your nearby homeland" :
2652. 						"your distant homeland");
2653. 			break;
2654. 	     case 16:
2655. 			{
2656. 				int dmg;
2657. 
2658. 				Your("pack shakes violently!");
2659. /* KMH, balance patch -- Idea by Wolfgang von Hansen <wvh@geodesy.inka.de> */
2660. 				dmg = jumble_pack();
2661. 				if (dmg)
2662. 					losehp(dmg, "violence", KILLED_BY);
2663. 			break;
2664. 			}
2665. 	     case 17:	You(Hallucination ?
2666. 				"smell hamburgers." :
2667. 				"smell charred flesh.");
2668. 			break;
2669. 	     case 18:	You_feel("tired.");
2670. 			break;
2671. 
2672. 	     /* very occasionally something nice happens. */
2673. 
2674. 	     case 19:
2675. 		    /* tame nearby monsters */
2676. 		   {   register int i,j;
2677. 		       register struct monst *mtmp;
2678. 
2679. 		       (void) adjattrib(A_CHA,1,FALSE);
2680. 		       for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) {
2681. 			   if(!isok(u.ux+i, u.uy+j)) continue;
2682. 			   mtmp = m_at(u.ux+i, u.uy+j);
2683. 			   if(mtmp)
2684. 			       (void) tamedog(mtmp, (struct obj *)0);
2685. 		       }
2686. 		       break;
2687. 		   }
2688. 
2689. 	     case 20:
2690. 		    /* uncurse stuff */
2691. 		   {	struct obj pseudo;
2692. 			long save_conf = HConfusion;
2693. 
2694. 			pseudo = zeroobj;   /* neither cursed nor blessed */
2695. 			pseudo.otyp = SCR_REMOVE_CURSE;
2696. 			HConfusion = 0L;
2697. 			(void) seffects(&pseudo);
2698. 			HConfusion = save_conf;
2699. 			break;
2700. 		   }
2701. 	     default: break;
2702. 	  }
2703. }
2704. 
2705. /*
2706.  * Scrolls, spellbooks, potions, and flammable items
2707.  * may get affected by the fire.
2708.  *
2709.  * Return number of objects destroyed. --ALI
2710.  */
2711. int
2712. fire_damage(chain, force, here, x, y)
2713. struct obj *chain;
2714. boolean force, here;
2715. xchar x, y;
2716. {
2717.     int chance;
2718.     struct obj *obj, *otmp, *nobj, *ncobj;
2719.     int retval = 0;
2720.     int in_sight = !Blind && couldsee(x, y);	/* Don't care if it's lit */
2721.     int dindx;
2722. 
2723.     for (obj = chain; obj; obj = nobj) {
2724. 	nobj = here ? obj->nexthere : obj->nobj;
2725. 
2726. 	/* object might light in a controlled manner */
2727. 	if (catch_lit(obj))
2728. 	    continue;
2729. 
2730. 	if (Is_container(obj)) {
2731. 	    switch (obj->otyp) {
2732. 	    case ICE_BOX:
2733. 		continue;		/* Immune */
2734. 		/*NOTREACHED*/
2735. 		break;
2736. 	    case CHEST:
2737. 		chance = 40;
2738. 		break;
2739. 	    case LARGE_BOX:
2740. 		chance = 30;
2741. 		break;
2742. 	    default:
2743. 		chance = 20;
2744. 		break;
2745. 	    }
2746. 	    if (!force && (Luck + 5) > rn2(chance))
2747. 		continue;
2748. 	    /* Container is burnt up - dump contents out */
2749. 	    if (in_sight) pline("%s catches fire and burns.", Yname2(obj));
2750. 	    if (Has_contents(obj)) {
2751. 		if (in_sight) pline("Its contents fall out.");
2752. 		for (otmp = obj->cobj; otmp; otmp = ncobj) {
2753. 		    ncobj = otmp->nobj;
2754. 		    obj_extract_self(otmp);
2755. 		    if (!flooreffects(otmp, x, y, ""))
2756. 			place_object(otmp, x, y);
2757. 		}
2758. 	    }
2759. 	    delobj(obj);
2760. 	    retval++;
2761. 	} else if (!force && (Luck + 5) > rn2(20)) {
2762. 	    /*  chance per item of sustaining damage:
2763. 	     *	max luck (full moon):	 5%
2764. 	     *	max luck (elsewhen):	10%
2765. 	     *	avg luck (Luck==0):	75%
2766. 	     *	awful luck (Luck<-4):  100%
2767. 	     */
2768. 	    continue;
2769. 	} else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
2770. 	    if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
2771. 		continue;
2772. 	    if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
2773. 		if (in_sight) pline("Smoke rises from %s.", the(xname(obj)));
2774. 		continue;
2775. 	    }
2776. 	    dindx = (obj->oclass == SCROLL_CLASS) ? 2 : 3;
2777. 	    if (in_sight)
2778. 		pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
2779. 		      destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
2780. 	    delobj(obj);
2781. 	    retval++;
2782. 	} else if (obj->oclass == POTION_CLASS) {
2783. 	    dindx = 1;
2784. 	    if (in_sight)
2785. 		pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
2786. 		      destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
2787. 	    delobj(obj);
2788. 	    retval++;
2789. 	} else if (is_flammable(obj) && obj->oeroded < MAX_ERODE &&
2790. 		   !(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
2791. 	    if (in_sight) {
2792. 		pline("%s %s%s.", Yname2(obj), otense(obj, "burn"),
2793. 		      obj->oeroded+1 == MAX_ERODE ? " completely" :
2794. 		      obj->oeroded ? " further" : "");
2795. 	    }
2796. 	    obj->oeroded++;
2797. 	}
2798.     }
2799. 
2800.     if (retval && !in_sight)
2801. 	You("smell smoke.");
2802.     return retval;
2803. }
2804. 
2805. void
2806. water_damage(obj, force, here)
2807. register struct obj *obj;
2808. register boolean force, here;
2809. {
2810. 	/* Dips in the Lethe are a very poor idea */
2811. 	int luckpenalty = level.flags.lethe? 7 : 0;
2812. 	struct obj *otmp;
2813. 
2814. 	/* Scrolls, spellbooks, potions, weapons and
2815. 	   pieces of armor may get affected by the water */
2816. 	for (; obj; obj = otmp) {
2817. 		otmp = here ? obj->nexthere : obj->nobj;
2818. 
2819. 		(void) snuff_lit(obj);
2820. 
2821. 		if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) {
2822. 			continue;
2823. 		} else if(obj->greased) {
2824. 			if (force || !rn2(2)) obj->greased = 0;
2825. 		} else if(Is_container(obj) && !Is_box(obj) &&
2826. 			(obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) {
2827. 			water_damage(obj->cobj, force, FALSE);
2828. 		} else if (!force && (Luck - luckpenalty + 5) > rn2(20)) {
2829. 			/*  chance per item of sustaining damage:
2830. 			 *	max luck (full moon):	 5%
2831. 			 *	max luck (elsewhen):	10%
2832. 			 *	avg luck (Luck==0):	75%
2833. 			 *	awful luck (Luck<-4):  100%
2834. 			 *  If this is the Lethe, things are much worse.
2835. 			 */
2836. 			continue;
2837. 		/* An oil skin cloak protects your body armor  */
2838. 		} else if( obj->oclass == ARMOR_CLASS
2839. 			&& obj == uarm
2840. 			&& uarmc
2841. 			&& uarmc->otyp == OILSKIN_CLOAK
2842. 			&& (!uarmc->cursed || rn2(3))) {
2843. 		    continue;
2844. 		} else {
2845. 		    /* The Lethe strips blessed and cursed status... */
2846. 		    if (level.flags.lethe) {
2847. 			uncurse(obj);
2848. 			unbless(obj);
2849. 		    }
2850. 
2851. 		    switch (obj->oclass) {
2852. 		    case SCROLL_CLASS:
2853. #ifdef MAIL
2854. 		    if (obj->otyp != SCR_MAIL)
2855. #endif
2856. 		    {
2857. 			    /* The Lethe sometimes does a little rewrite */
2858. 			    obj->otyp = (level.flags.lethe && !rn2(10)) ?
2859. 					SCR_AMNESIA : SCR_BLANK_PAPER;
2860. 			obj->spe = 0;
2861. 		    }
2862. 			break;
2863. 		    case SPBOOK_CLASS:
2864. 			/* Spell books get blanked... */
2865. 			if (obj->otyp == SPE_BOOK_OF_THE_DEAD)
2866. 				pline("Steam rises from %s.", the(xname(obj)));
2867. 			else obj->otyp = SPE_BLANK_PAPER;
2868. 			break;
2869. 		    case POTION_CLASS:
2870. 			if (obj->otyp == POT_ACID) {
2871. 				/* damage player/monster? */
2872. 				pline("A potion explodes!");
2873. 				delobj(obj);
2874. 				continue;
2875. 			} else
2876. 			/* Potions turn to water or amnesia... */
2877. 			if (level.flags.lethe) {
2878. 			    if (obj->otyp == POT_WATER)
2879. 				obj->otyp = POT_AMNESIA;
2880. 			    else if (obj->otyp != POT_AMNESIA) {
2881. 				obj->otyp = POT_WATER;
2882. 				obj->odiluted = 0;
2883. 			    }
2884. 			} else if (obj->odiluted || obj->otyp == POT_AMNESIA) {
2885. 				obj->otyp = POT_WATER;
2886. 				obj->blessed = obj->cursed = 0;
2887. 				obj->odiluted = 0;
2888. 			} else if (obj->otyp != POT_WATER)
2889. 				obj->odiluted++;
2890. 			break;
2891. 		    case GEM_CLASS:
2892. 			if (level.flags.lethe && (obj->otyp == LUCKSTONE
2893. 					|| obj->otyp == LOADSTONE
2894. 					|| obj->otyp == HEALTHSTONE
2895. 					|| obj->otyp == TOUCHSTONE))
2896. 			    obj->otyp = FLINT;
2897. 			break;
2898. 		    case TOOL_CLASS:
2899. 			if (level.flags.lethe) {
2900. 			    switch (obj->otyp) {
2901. 			    case MAGIC_LAMP:
2902. 				obj->otyp = OIL_LAMP;
2903. 				break;
2904. 			    case MAGIC_CANDLE:
2905. 				obj->otyp = rn2(2)? WAX_CANDLE : TALLOW_CANDLE;
2906. 				break;
2907. 			    case MAGIC_WHISTLE:
2908. 				obj->otyp = TIN_WHISTLE;
2909. 				break;	
2910. 			    case MAGIC_FLUTE:
2911. 				obj->otyp = WOODEN_FLUTE;
2912. 				obj->spe  = 0;
2913. 				break;	
2914. 			    case MAGIC_HARP:
2915. 				obj->otyp = WOODEN_HARP;
2916. 				obj->spe  = 0;
2917. 				break;
2918. 			    case FIRE_HORN:
2919. 			    case FROST_HORN:
2920. 			    case HORN_OF_PLENTY:
2921. 				obj->otyp = TOOLED_HORN;
2922. 				obj->spe  = 0;
2923. 				break;
2924. 			    case DRUM_OF_EARTHQUAKE:
2925. 				obj->otyp = LEATHER_DRUM;
2926. 				obj->spe  = 0;
2927. 				break;
2928. 			    }
2929. 			}
2930. 
2931. 			/* Drop through */
2932. 			/* Weapons, armor and tools may be disenchanted... */
2933. 			/* Wands and rings lose a charge... */
2934. 		    case WEAPON_CLASS:
2935. 		    case ARMOR_CLASS:
2936. 		    case WAND_CLASS:
2937. 		    case RING_CLASS:
2938. 			if ( level.flags.lethe
2939. 					&& ( obj->oclass == WEAPON_CLASS
2940. 						|| obj->oclass == ARMOR_CLASS
2941. 						|| obj->oclass == WAND_CLASS
2942. 						|| obj->oclass == RING_CLASS
2943. 						|| is_weptool(obj) )) {
2944. 
2945. 			    /* Shift enchantment one step closer to 0 */
2946. 			    if (obj->spe > 0) drain_item(obj);
2947. 			}
2948. 
2949. 			/* Magic markers run... */
2950. 			if ( level.flags.lethe
2951. 					&& obj->otyp == MAGIC_MARKER ) {
2952. 			    obj->spe -= (3 + rn2(10));
2953. 			    if (obj->spe < 0) obj->spe = 0;
2954. 			}
2955. 
2956. 			/* Drop through for rusting effects... */
2957. 			/* Weapons, armor, tools and other things may rust... */
2958. 		    default:
2959. 			if (is_rustprone(obj) && obj->oeroded < MAX_ERODE &&
2960. 					!(obj->oerodeproof || 
2961. 					 (obj->blessed && !rnl(4))))
2962. 				obj->oeroded++;
2963. 			/* The Lethe may unfooproof the item... */
2964. 			if (level.flags.lethe
2965. 					&& obj->oerodeproof && !rn2(5))
2966. 			    obj->oerodeproof = FALSE;
2967. 		    }
2968. 		}
2969. 	}
2970. }
2971. 
2972. /*
2973.  * This function is potentially expensive - rolling
2974.  * inventory list multiple times.  Luckily it's seldom needed.
2975.  * Returns TRUE if disrobing made player unencumbered enough to
2976.  * crawl out of the current predicament.
2977.  */
2978. STATIC_OVL boolean
2979. emergency_disrobe(lostsome)
2980. boolean *lostsome;
2981. {
2982. 	int invc = inv_cnt();
2983. 
2984. 	while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) {
2985. 	    register struct obj *obj, *otmp = (struct obj *)0;
2986. 	    register int i;
2987. 
2988. 	    /* Pick a random object */
2989. 	    if (invc > 0) {
2990. 		i = rn2(invc);
2991. 		for (obj = invent; obj; obj = obj->nobj) {
2992. 		    /*
2993. 		     * Undroppables are: body armor, boots, gloves,
2994. 		     * amulets, and rings because of the time and effort
2995. 		     * in removing them + loadstone and other cursed stuff
2996. 		     * for obvious reasons.
2997. 		     */
2998. 		    if (!((obj->otyp == LOADSTONE && obj->cursed) ||
2999. 			  obj == uamul || obj == uleft || obj == uright ||
3000. 			  obj == ublindf || obj == uarm || obj == uarmc ||
3001. 			  obj == uarmg || obj == uarmf ||
3002. #ifdef TOURIST
3003. 			  obj == uarmu ||
3004. #endif
3005. 			  (obj->cursed && (obj == uarmh || obj == uarms)) ||
3006. 			  welded(obj)))
3007. 			otmp = obj;
3008. 		    /* reached the mark and found some stuff to drop? */
3009. 		    if (--i < 0 && otmp) break;
3010. 
3011. 		    /* else continue */
3012. 		}
3013. 	    }
3014. #ifndef GOLDOBJ
3015. 	    if (!otmp) {
3016. 		/* Nothing available left to drop; try gold */
3017. 		if (u.ugold) {
3018. 		    pline("In desperation, you drop your purse.");
3019. 		    /* Hack: gold is not in the inventory, so make a gold object
3020. 		     * and put it at the head of the inventory list.
3021. 		     */
3022. 		    obj = mkgoldobj(u.ugold);    /* removes from u.ugold */
3023. 		    obj->in_use = TRUE;
3024. 		    u.ugold = obj->quan;         /* put the gold back */
3025. 		    assigninvlet(obj);           /* might end up as NOINVSYM */
3026. 		    obj->nobj = invent;
3027. 		    invent = obj;
3028. 		    *lostsome = TRUE;
3029. 		    dropx(obj);
3030. 		    continue;                    /* Try again */
3031. 		}
3032. 		/* We can't even drop gold! */
3033. 		return (FALSE);
3034. 	    }
3035. #else
3036. 	    if (!otmp) return (FALSE); /* nothing to drop! */	
3037. #endif
3038. 	    if (otmp->owornmask) remove_worn_item(otmp, FALSE);
3039. 	    *lostsome = TRUE;
3040. 	    dropx(otmp);
3041. 	    invc--;
3042. 	}
3043. 	return(TRUE);
3044. }
3045. 
3046. /*
3047.  *  return(TRUE) == player relocated
3048.  */
3049. boolean
3050. drown()
3051. {
3052. 	boolean inpool_ok = FALSE, crawl_ok;
3053. 	int i, x, y;
3054. 	const char *sparkle = level.flags.lethe? "sparkling " : "";
3055. 
3056. 	/* happily wading in the same contiguous pool */
3057. 	if (u.uinwater && is_pool(u.ux-u.dx,u.uy-u.dy) &&
3058. 	    (Swimming || Amphibious)) {
3059. 		/* water effects on objects every now and then */
3060. 		if (!rn2(5)) inpool_ok = TRUE;
3061. 		else return(FALSE);
3062. 	}
3063. 
3064. 	if (!u.uinwater) {
3065. 	    You("%s into the %swater%c",
3066. 		Is_waterlevel(&u.uz) ? "plunge" : "fall",
3067. 		sparkle,
3068. 		Amphibious || Swimming ? '.' : '!');
3069. 	    if (!Swimming && !Is_waterlevel(&u.uz))
3070. 		    You("sink like %s.",
3071. 			Hallucination ? "the Titanic" : "a rock");
3072. 	}
3073. 
3074. 	if (level.flags.lethe) {
3075. 	    /* Bad idea */
3076. 	    You_feel("the sparkling waters of the Lethe sweep away your "
3077. 			    "cares!");
3078. 	    forget(25);
3079. 	}
3080. 
3081. 	water_damage(invent, FALSE, FALSE);
3082. 
3083. 	if (u.umonnum == PM_GREMLIN && rn2(3))
3084. 	    (void)split_mon(&youmonst, (struct monst *)0);
3085. 	else if (u.umonnum == PM_IRON_GOLEM) {
3086. 	    You("rust!");
3087. 	    i = d(2,6);
3088. 	    if (u.mhmax > i) u.mhmax -= i;
3089. 	    losehp(i, "rusting away", KILLED_BY);
3090. 	}
3091. 	if (inpool_ok) return(FALSE);
3092. 
3093. 	if ((i = number_leashed()) > 0) {
3094. 		pline_The("leash%s slip%s loose.",
3095. 			(i > 1) ? "es" : "",
3096. 			(i > 1) ? "" : "s");
3097. 		unleash_all();
3098. 	}
3099. 
3100. 	if (Amphibious || Swimming) {
3101. 		if (Amphibious) {
3102. 			if (flags.verbose)
3103. 				pline("But you aren't drowning.");
3104. 			if (!Is_waterlevel(&u.uz)) {
3105. 				if (Hallucination)
3106. 					Your("keel hits the bottom.");
3107. 				else
3108. 					You("touch bottom.");
3109. 			}
3110. 		}
3111. 		if (Punished) {
3112. 			unplacebc();
3113. 			placebc();
3114. 		}
3115. 		vision_recalc(2);	/* unsee old position */
3116. 		u.uinwater = 1;
3117. 		under_water(1);
3118. 		vision_full_recalc = 1;
3119. 		return(FALSE);
3120. 	}
3121. 	else if (Swimming && !Is_waterlevel(&u.uz)) {
3122. 		if (Punished) {
3123. 			unplacebc();
3124. 			placebc();
3125. 		}
3126. 		u.uinwater = 1;
3127. 		under_water(1);
3128. 		vision_full_recalc = 1;
3129. 		return(FALSE);
3130. 	}
3131. 	if ((Teleportation || can_teleport(youmonst.data)) &&
3132. 		    !u.usleep && (Teleport_control || rn2(3) < Luck+2)) {
3133. 		You("attempt a teleport spell.");	/* utcsri!carroll */
3134. 		if (!level.flags.noteleport) {
3135. 			(void) dotele();
3136. 			if(!is_pool(u.ux,u.uy))
3137. 				return(TRUE);
3138. 		} else pline_The("attempted teleport spell fails.");
3139. 	}
3140. #ifdef STEED
3141. 	if (u.usteed) {
3142. 		dismount_steed(DISMOUNT_GENERIC);
3143. 		if(!is_pool(u.ux,u.uy))
3144. 			return(TRUE);
3145. 	}
3146. #endif
3147. 	crawl_ok = FALSE;
3148. 	x = y = 0;		/* lint suppression */
3149. 	/* if sleeping, wake up now so that we don't crawl out of water
3150. 	   while still asleep; we can't do that the same way that waking
3151. 	   due to combat is handled; note unmul() clears u.usleep */
3152. 	if (u.usleep) unmul("Suddenly you wake up!");
3153. 	/* can't crawl if unable to move (crawl_ok flag stays false) */
3154. 	if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl;
3155. 	/* look around for a place to crawl to */
3156. 	for (i = 0; i < 100; i++) {
3157. 		x = rn1(3,u.ux - 1);
3158. 		y = rn1(3,u.uy - 1);
3159. 		if (goodpos(x, y, &youmonst, 0)) {
3160. 			crawl_ok = TRUE;
3161. 			goto crawl;
3162. 		}
3163. 	}
3164. 	/* one more scan */
3165. 	for (x = u.ux - 1; x <= u.ux + 1; x++)
3166. 		for (y = u.uy - 1; y <= u.uy + 1; y++)
3167. 			if (goodpos(x, y, &youmonst, 0)) {
3168. 				crawl_ok = TRUE;
3169. 				goto crawl;
3170. 			}
3171.  crawl:
3172. 	if (crawl_ok) {
3173. 		boolean lost = FALSE;
3174. 		/* time to do some strip-tease... */
3175. 		boolean succ = Is_waterlevel(&u.uz) ? TRUE :
3176. 				emergency_disrobe(&lost);
3177. 
3178. 		You("try to crawl out of the water.");
3179. 		if (lost)
3180. 			You("dump some of your gear to lose weight...");
3181. 		if (succ) {
3182. 			pline("Pheew!  That was close.");
3183. 			teleds(x,y,TRUE);
3184. 			return(TRUE);
3185. 		}
3186. 		/* still too much weight */
3187. 		pline("But in vain.");
3188. 	}
3189. 	u.uinwater = 1;
3190. 	You("drown.");
3191. 	/* [ALI] Vampires return to vampiric form on drowning.
3192. 	 */
3193. 	if (Upolyd && !Unchanging && Race_if(PM_VAMPIRE)) {
3194. 		rehumanize();
3195. 		u.uinwater = 0;
3196. 		You("fly up out of the water!");
3197. 		return (TRUE);
3198. 	}
3199. 	killer_format = KILLED_BY_AN;
3200. 	killer = (levl[u.ux][u.uy].typ == POOL || Is_medusa_level(&u.uz)) ?
3201. 	    "pool of water" : "moat";
3202. 	done(DROWNING);
3203. 	/* oops, we're still alive.  better get out of the water. */
3204. 	while (!safe_teleds(TRUE)) {
3205. 		pline("You're still drowning.");
3206. 		done(DROWNING);
3207. 	}
3208. 	if (u.uinwater) {
3209. 	u.uinwater = 0;
3210. 	You("find yourself back %s.", Is_waterlevel(&u.uz) ?
3211. 		"in an air bubble" : "on land");
3212. 	}
3213. 	return(TRUE);
3214. 	
3215. }
3216. 
3217. void
3218. drain_en(n)
3219. register int n;
3220. {
3221. 	if (!u.uenmax) return;
3222. 	You_feel("your magical energy drain away!");
3223. 	u.uen -= n;
3224. 	if(u.uen < 0)  {
3225. 		u.uenmax += u.uen;
3226. 		if(u.uenmax < 0) u.uenmax = 0;
3227. 		u.uen = 0;
3228. 	}
3229. 	flags.botl = 1;
3230. }
3231. 
3232. int
3233. dountrap()	/* disarm a trap */
3234. {
3235. 	if (near_capacity() >= HVY_ENCUMBER) {
3236. 	    pline("You're too strained to do that.");
3237. 	    return 0;
3238. 	}
3239. 	if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) {
3240. 	    pline("And just how do you expect to do that?");
3241. 	    return 0;
3242. 	} else if (u.ustuck && sticks(youmonst.data)) {
3243. 	    pline("You'll have to let go of %s first.", mon_nam(u.ustuck));
3244. 	    return 0;
3245. 	}
3246. 	if (u.ustuck || (welded(uwep) && bimanual(uwep))) {
3247. 	    Your("%s seem to be too busy for that.",
3248. 		 makeplural(body_part(HAND)));
3249. 	    return 0;
3250. 	}
3251. 	return untrap(FALSE);
3252. }
3253. #endif /* OVLB */
3254. #ifdef OVL2
3255. 
3256. /* Probability of disabling a trap.  Helge Hafting */
3257. STATIC_OVL int
3258. untrap_prob(ttmp)
3259. struct trap *ttmp;
3260. {
3261. 	int chance = 3;
3262. 
3263. 	/* Only spiders know how to deal with webs reliably */
3264. 	if (ttmp->ttyp == WEB && !webmaker(youmonst.data))
3265. 	 	chance = 30;
3266. 	if (Confusion || Hallucination) chance++;
3267. 	if (Blind) chance++;
3268. 	if (Stunned) chance += 2;
3269. 	if (Fumbling) chance *= 2;
3270. 	/* Your own traps are better known than others. */
3271. 	if (ttmp && ttmp->madeby_u) chance--;
3272. 	if (Role_if(PM_ROGUE)) {
3273. 	    if (rn2(2 * MAXULEV) < u.ulevel) chance--;
3274. 	    if (u.uhave.questart && chance > 1) chance--;
3275. 	} else if (Role_if(PM_RANGER) && chance > 1) chance--;
3276. 	return rn2(chance);
3277. }
3278. 
3279. /* Replace trap with object(s).  Helge Hafting */
3280. STATIC_OVL void
3281. cnv_trap_obj(otyp, cnt, ttmp)
3282. int otyp;
3283. int cnt;
3284. struct trap *ttmp;
3285. {
3286. 	struct obj *otmp = mksobj(otyp, TRUE, FALSE);
3287. 	/* [ALI] Only dart traps are capable of being poisonous */
3288. 	if (otyp != DART)
3289. 	    otmp->opoisoned = 0;
3290. 	otmp->quan=cnt;
3291. 	otmp->owt = weight(otmp);
3292. 	/* Only dart traps are capable of being poisonous */
3293. 	if (otyp != DART)
3294. 	    otmp->opoisoned = 0;
3295. 	place_object(otmp, ttmp->tx, ttmp->ty);
3296. 	/* Sell your own traps only... */
3297. 	if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty);
3298. 	stackobj(otmp);
3299. 	newsym(ttmp->tx, ttmp->ty);
3300. 	deltrap(ttmp);
3301. }
3302. 
3303. /* while attempting to disarm an adjacent trap, we've fallen into it */
3304. STATIC_OVL void
3305. move_into_trap(ttmp)
3306. struct trap *ttmp;
3307. {
3308. 	int bc;
3309. 	xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy;
3310. 	boolean unused;
3311. 
3312. 	/* we know there's no monster in the way, and we're not trapped */
3313. 	if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused,
3314. 		TRUE)) {
3315. 	    u.ux0 = u.ux,  u.uy0 = u.uy;
3316. 	    u.ux = x,  u.uy = y;
3317. 	    u.umoved = TRUE;
3318. 	    newsym(u.ux0, u.uy0);
3319. 	    vision_recalc(1);
3320. 	    check_leash(u.ux0, u.uy0);
3321. 	    if (Punished) move_bc(0, bc, bx, by, cx, cy);
3322. 	    spoteffects(FALSE);	/* dotrap() */
3323. 	    exercise(A_WIS, FALSE);
3324. 	}
3325. }
3326. 
3327. /* 0: doesn't even try
3328.  * 1: tries and fails
3329.  * 2: succeeds
3330.  */
3331. STATIC_OVL int
3332. try_disarm(ttmp, force_failure)
3333. struct trap *ttmp;
3334. boolean force_failure;
3335. {
3336. 	struct monst *mtmp = m_at(ttmp->tx,ttmp->ty);
3337. 	int ttype = ttmp->ttyp;
3338. 	boolean under_u = (!u.dx && !u.dy);
3339. 	boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB);
3340. 	
3341. 	/* Test for monster first, monsters are displayed instead of trap. */
3342. 	if (mtmp && (!mtmp->mtrapped || !holdingtrap)) {
3343. 		pline("%s is in the way.", Monnam(mtmp));
3344. 		return 0;
3345. 	}
3346. 	/* We might be forced to move onto the trap's location. */
3347. 	if (sobj_at(BOULDER, ttmp->tx, ttmp->ty)
3348. 				&& !Passes_walls && !under_u) {
3349. 		There("is a boulder in your way.");
3350. 		return 0;
3351. 	}
3352. 	/* duplicate tight-space checks from test_move */
3353. 	if (u.dx && u.dy &&
3354. 	    bad_rock(&youmonst, u.ux, ttmp->ty) &&
3355. 	    bad_rock(&youmonst, ttmp->tx, u.uy)) {
3356. 	    if ((invent && (inv_weight() + weight_cap() > 600)) ||
3357. 		bigmonst(youmonst.data)) {
3358. 		/* don't allow untrap if they can't get thru to it */
3359. 		You("are unable to reach the %s!",
3360. 		    defsyms[trap_to_defsym(ttype)].explanation);
3361. 		return 0;
3362. 	    }
3363. 	}
3364. 	/* untrappable traps are located on the ground. */
3365. 	if (!can_reach_floor()) {
3366. #ifdef STEED
3367. 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
3368. 			You("aren't skilled enough to reach from %s.",
3369. 				mon_nam(u.usteed));
3370. 		else
3371. #endif
3372. 		You("are unable to reach the %s!",
3373. 			defsyms[trap_to_defsym(ttype)].explanation);
3374. 		return 0;
3375. 	}
3376. 
3377. 	/* Will our hero succeed? */
3378. 	if (force_failure || untrap_prob(ttmp)) {
3379. 		if (rnl(5)) {
3380. 		    pline("Whoops...");
3381. 		    if (mtmp) {		/* must be a trap that holds monsters */
3382. 			if (ttype == BEAR_TRAP) {
3383. 			    if (mtmp->mtame) abuse_dog(mtmp);
3384. 			    if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp);
3385. 			} else if (ttype == WEB) {
3386. 			    if (!webmaker(youmonst.data)) {
3387. 				struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB);
3388. 				if (ttmp2) {
3389. 				    pline_The("webbing sticks to you. You're caught too!");
3390. 				    dotrap(ttmp2, NOWEBMSG);
3391. #ifdef STEED
3392. 				    if (u.usteed && u.utrap) {
3393. 					/* you, not steed, are trapped */
3394. 					dismount_steed(DISMOUNT_FELL);
3395. 				    }
3396. #endif
3397. 				}
3398. 			    } else
3399. 				pline("%s remains entangled.", Monnam(mtmp));
3400. 			}
3401. 		    } else if (under_u) {
3402. 			dotrap(ttmp, 0);
3403. 		    } else {
3404. 			move_into_trap(ttmp);
3405. 		    }
3406. 		} else {
3407. 		    pline("%s %s is difficult to %s.",
3408. 			  ttmp->madeby_u ? "Your" : under_u ? "This" : "That",
3409. 			  defsyms[trap_to_defsym(ttype)].explanation,
3410. 			  (ttype == WEB) ? "remove" : "disarm");
3411. 		}
3412. 		return 1;
3413. 	}
3414. 	return 2;
3415. }
3416. 
3417. STATIC_OVL void
3418. reward_untrap(ttmp, mtmp)
3419. struct trap *ttmp;
3420. struct monst *mtmp;
3421. {
3422. 	if (!ttmp->madeby_u) {
3423. 	    if (rnl(10) < 8 && !mtmp->mpeaceful &&
3424. 		    !mtmp->msleeping && !mtmp->mfrozen &&
3425. 		    !mindless(mtmp->data) &&
3426. 		    mtmp->data->mlet != S_HUMAN) {
3427. 		mtmp->mpeaceful = 1;
3428. 		set_malign(mtmp);	/* reset alignment */
3429. 		pline("%s is grateful.", Monnam(mtmp));
3430. 	    }
3431. 	    /* Helping someone out of a trap is a nice thing to do,
3432. 	     * A lawful may be rewarded, but not too often.  */
3433. 	    if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) {
3434. 		adjalign(1);
3435. 		You_feel("that you did the right thing.");
3436. 	    }
3437. 	}
3438. }
3439. 
3440. STATIC_OVL int
3441. disarm_holdingtrap(ttmp) /* Helge Hafting */
3442. struct trap *ttmp;
3443. {
3444. 	struct monst *mtmp;
3445. 	int fails = try_disarm(ttmp, FALSE);
3446. 
3447. 	if (fails < 2) return fails;
3448. 
3449. 	/* ok, disarm it. */
3450. 
3451. 	/* untrap the monster, if any.
3452. 	   There's no need for a cockatrice test, only the trap is touched */
3453. 	if ((mtmp = m_at(ttmp->tx,ttmp->ty)) != 0) {
3454. 		mtmp->mtrapped = 0;
3455. 		You("remove %s %s from %s.", the_your[ttmp->madeby_u],
3456. 			(ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing",
3457. 			mon_nam(mtmp));
3458. 		reward_untrap(ttmp, mtmp);
3459. 	} else {
3460. 		if (ttmp->ttyp == BEAR_TRAP) {
3461. 			You("disarm %s bear trap.", the_your[ttmp->madeby_u]);
3462. 			cnv_trap_obj(BEARTRAP, 1, ttmp);
3463. 		} else /* if (ttmp->ttyp == WEB) */ {
3464. 			You("succeed in removing %s web.", the_your[ttmp->madeby_u]);
3465. 			deltrap(ttmp);
3466. 		}
3467. 	}
3468. 	newsym(u.ux + u.dx, u.uy + u.dy);
3469. 	return 1;
3470. }
3471. 
3472. STATIC_OVL int
3473. disarm_landmine(ttmp) /* Helge Hafting */
3474. struct trap *ttmp;
3475. {
3476. 	int fails = try_disarm(ttmp, FALSE);
3477. 
3478. 	if (fails < 2) return fails;
3479. 	You("disarm %s land mine.", the_your[ttmp->madeby_u]);
3480. 	cnv_trap_obj(LAND_MINE, 1, ttmp);
3481. 	return 1;
3482. }
3483. 
3484. STATIC_OVL int
3485. disarm_rust_trap(ttmp) /* Paul Sonier */
3486. struct trap *ttmp;
3487. {
3488. 	xchar trapx = ttmp->tx, trapy = ttmp->ty;
3489. 	int fails = try_disarm(ttmp, FALSE);
3490. 
3491. 	if (fails < 2) return fails;
3492. 	You("disarm the water trap!");
3493. 	deltrap(ttmp);
3494. 	levl[trapx][trapy].typ = FOUNTAIN;
3495. 	newsym(trapx, trapy);
3496. 	level.flags.nfountains++;
3497. 	return 1;
3498. }
3499. 
3500. /* getobj will filter down to cans of grease and known potions of oil */
3501. 
3502. static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 };
3503. static NEARDATA const char disarmpotion[] = { ALL_CLASSES, POTION_CLASS, 0 };
3504. 
3505. /* water disarms, oil will explode */
3506. STATIC_OVL int
3507. disarm_fire_trap(ttmp) /* Paul Sonier */
3508. struct trap *ttmp;
3509. {
3510. 	int fails;
3511. 	struct obj *obj;
3512. 	boolean bad_tool;
3513. 
3514. 	obj = getobj(disarmpotion, "untrap with");
3515. 	if (!obj) return 0;
3516. 
3517. 	if (obj->otyp == POT_OIL)
3518. 	{
3519. 		Your("potion of oil explodes!");
3520. 		splatter_burning_oil(ttmp->tx,ttmp->ty);
3521. 		delobj(obj);
3522. 		return 1;
3523. 	}
3524. 
3525. 	bad_tool = (obj->cursed ||
3526. 				(obj->otyp != POT_WATER));
3527. 	fails = try_disarm(ttmp, bad_tool);
3528. 	if (fails < 2) return fails;
3529. 
3530. 	useup(obj);
3531. 	makeknown(POT_WATER);
3532. 	You("manage to extinguish the pilot light!");
3533. 	cnv_trap_obj(POT_OIL, 4 - rnl(4), ttmp);
3534. 	more_experienced(1, 5);
3535. 	newexplevel();
3536. 	return 1;
3537. }
3538. 
3539. /* it may not make much sense to use grease on floor boards, but so what? */
3540. STATIC_OVL int
3541. disarm_squeaky_board(ttmp)
3542. struct trap *ttmp;
3543. {
3544. 	struct obj *obj;
3545. 	boolean bad_tool;
3546. 	int fails, trapx = ttmp->tx, trapy = ttmp->ty;
3547. 
3548. 	obj = getobj(oil, "untrap with");
3549. 	if (!obj) return 0;
3550. 
3551. 	bad_tool = (obj->cursed ||
3552. 			((obj->otyp != POT_OIL || obj->lamplit) &&
3553. 			 (obj->otyp != CAN_OF_GREASE || !obj->spe)));
3554. 
3555. 	fails = try_disarm(ttmp, bad_tool);
3556. 	if (fails < 2) return fails;
3557. 
3558. 	/* successfully used oil or grease to fix squeaky board */
3559. 	if (obj->otyp == CAN_OF_GREASE) {
3560. 	    consume_obj_charge(obj, TRUE);
3561. 	} else {
3562. 	    useup(obj);	/* oil */
3563. 	    makeknown(POT_OIL);
3564. 	}
3565. 	You("repair the squeaky board.");	/* no madeby_u */
3566. 	deltrap(ttmp);
3567. 	newsym(trapx, trapy);
3568. 	more_experienced(1, 5);
3569. 	return 1;
3570. }
3571. 
3572. /* removes traps that shoot arrows, darts, etc. */
3573. STATIC_OVL int
3574. disarm_shooting_trap(ttmp, otyp)
3575. struct trap *ttmp;
3576. int otyp;
3577. {
3578. 	int fails = try_disarm(ttmp, FALSE);
3579. 
3580. 	if (fails < 2) return fails;
3581. 	You("disarm %s trap.", the_your[ttmp->madeby_u]);
3582. 	cnv_trap_obj(otyp, 50-rnl(50), ttmp);
3583. 	return 1;
3584. }
3585. 
3586. /* Is the weight too heavy?
3587.  * Formula as in near_capacity() & check_capacity() */
3588. STATIC_OVL int
3589. try_lift(mtmp, ttmp, wt, stuff)
3590. struct monst *mtmp;
3591. struct trap *ttmp;
3592. int wt;
3593. boolean stuff;
3594. {
3595. 	int wc = weight_cap();
3596. 
3597. 	if (((wt * 2) / wc) >= HVY_ENCUMBER) {
3598. 	    pline("%s is %s for you to lift.", Monnam(mtmp),
3599. 		  stuff ? "carrying too much" : "too heavy");
3600. 	    if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove &&
3601. 		    !mindless(mtmp->data) &&
3602. 		    mtmp->data->mlet != S_HUMAN && rnl(10) < 3) {
3603. 		mtmp->mpeaceful = 1;
3604. 		set_malign(mtmp);		/* reset alignment */
3605. 		pline("%s thinks it was nice of you to try.", Monnam(mtmp));
3606. 	    }
3607. 	    return 0;
3608. 	}
3609. 	return 1;
3610. }
3611. 
3612. /* Help trapped monster (out of a (spiked) pit) */
3613. STATIC_OVL int
3614. help_monster_out(mtmp, ttmp)
3615. struct monst *mtmp;
3616. struct trap *ttmp;
3617. {
3618. 	int wt;
3619. 	struct obj *otmp;
3620. 	boolean uprob;
3621. 
3622. 	/*
3623. 	 * This works when levitating too -- consistent with the ability
3624. 	 * to hit monsters while levitating.
3625. 	 *
3626. 	 * Should perhaps check that our hero has arms/hands at the
3627. 	 * moment.  Helping can also be done by engulfing...
3628. 	 *
3629. 	 * Test the monster first - monsters are displayed before traps.
3630. 	 */
3631. 	if (!mtmp->mtrapped) {
3632. 		pline("%s isn't trapped.", Monnam(mtmp));
3633. 		return 0;
3634. 	}
3635. 	/* Do you have the necessary capacity to lift anything? */
3636. 	if (check_capacity((char *)0)) return 1;
3637. 
3638. 	/* Will our hero succeed? */
3639. 	if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) {
3640. 		You("try to reach out your %s, but %s backs away skeptically.",
3641. 			makeplural(body_part(ARM)),
3642. 			mon_nam(mtmp));
3643. 		return 1;
3644. 	}
3645. 
3646. 
3647. 	/* is it a cockatrice?... */
3648. 	if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) {
3649. 		You("grab the trapped %s using your bare %s.",
3650. 				mtmp->data->mname, makeplural(body_part(HAND)));
3651. 
3652. 		if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
3653. 			display_nhwindow(WIN_MESSAGE, FALSE);
3654. 		else {
3655. 			char kbuf[BUFSZ];
3656. 
3657. 			Sprintf(kbuf, "trying to help %s out of a pit",
3658. 					an(mtmp->data->mname));
3659. 			instapetrify(kbuf);
3660. 			return 1;
3661. 		}
3662. 	}
3663. 	/* need to do cockatrice check first if sleeping or paralyzed */
3664. 	if (uprob) {
3665. 	    You("try to grab %s, but cannot get a firm grasp.",
3666. 		mon_nam(mtmp));
3667. 	    if (mtmp->msleeping) {
3668. 		mtmp->msleeping = 0;
3669. 		pline("%s awakens.", Monnam(mtmp));
3670. 	    }
3671. 	    return 1;
3672. 	}
3673. 
3674. 	You("reach out your %s and grab %s.",
3675. 	    makeplural(body_part(ARM)), mon_nam(mtmp));
3676. 
3677. 	if (mtmp->msleeping) {
3678. 	    mtmp->msleeping = 0;
3679. 	    pline("%s awakens.", Monnam(mtmp));
3680. 	} else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) {
3681. 	    /* After such manhandling, perhaps the effect wears off */
3682. 	    mtmp->mcanmove = 1;
3683. 	    mtmp->mfrozen = 0;
3684. 	    pline("%s stirs.", Monnam(mtmp));
3685. 	}
3686. 
3687. 	/* is the monster too heavy? */
3688. 	wt = inv_weight() + mtmp->data->cwt;
3689. 	if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1;
3690. 
3691. 	/* is the monster with inventory too heavy? */
3692. 	for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
3693. 		wt += otmp->owt;
3694. 	if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1;
3695. 
3696. 	You("pull %s out of the pit.", mon_nam(mtmp));
3697. 	mtmp->mtrapped = 0;
3698. 	fill_pit(mtmp->mx, mtmp->my);
3699. 	reward_untrap(ttmp, mtmp);
3700. 	return 1;
3701. }
3702. 
3703. int
3704. untrap(force)
3705. boolean force;
3706. {
3707. 	register struct obj *otmp;
3708. 	register boolean confused = (Confusion > 0 || Hallucination > 0);
3709. 	register int x,y;
3710. 	int ch;
3711. 	struct trap *ttmp;
3712. 	struct monst *mtmp;
3713. 	boolean trap_skipped = FALSE;
3714. 	boolean box_here = FALSE;
3715. 	boolean deal_with_floor_trap = FALSE;
3716. 	char the_trap[BUFSZ], qbuf[QBUFSZ];
3717. 	int containercnt = 0;
3718. 
3719. 	if(!getdir((char *)0)) return(0);
3720. 	x = u.ux + u.dx;
3721. 	y = u.uy + u.dy;
3722. 
3723. 	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
3724. 		if(Is_box(otmp) && !u.dx && !u.dy) {
3725. 			box_here = TRUE;
3726. 			containercnt++;
3727. 			if (containercnt > 1) break;
3728. 		}
3729. 	}
3730. 
3731. 	if ((ttmp = t_at(x,y)) && ttmp->tseen) {
3732. 		deal_with_floor_trap = TRUE;
3733. 		Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
3734. 		if (box_here) {
3735. 			if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) {
3736. 			    You_cant("do much about %s%s.",
3737. 					the_trap, u.utrap ?
3738. 					" that you're stuck in" :
3739. 					" while standing on the edge of it");
3740. 			    trap_skipped = TRUE;
3741. 			    deal_with_floor_trap = FALSE;
3742. 			} else {
3743. 			    Sprintf(qbuf, "There %s and %s here. %s %s?",
3744. 				(containercnt == 1) ? "is a container" : "are containers",
3745. 				an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation),
3746. 				ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap);
3747. 			    switch (ynq(qbuf)) {
3748. 				case 'q': return(0);
3749. 				case 'n': trap_skipped = TRUE;
3750. 					  deal_with_floor_trap = FALSE;
3751. 					  break;
3752. 			    }
3753. 			}
3754. 		}
3755. 		if (deal_with_floor_trap) {
3756. 		if (u.utrap) {
3757. 			You("cannot deal with %s while trapped%s!", the_trap,
3758. 				(x == u.ux && y == u.uy) ? " in it" : "");
3759. 			return 1;
3760. 		}
3761. 		switch(ttmp->ttyp) {
3762. 			case BEAR_TRAP:
3763. 			case WEB:
3764. 				return disarm_holdingtrap(ttmp);
3765. 			case LANDMINE:
3766. 				return disarm_landmine(ttmp);
3767. 			case SQKY_BOARD:
3768. 				return disarm_squeaky_board(ttmp);
3769. 			case DART_TRAP:
3770. 				return disarm_shooting_trap(ttmp, DART);
3771. 			case ARROW_TRAP:
3772. 				return disarm_shooting_trap(ttmp, ARROW);
3773. 			case RUST_TRAP:
3774. 				return disarm_rust_trap(ttmp);
3775. 			case FIRE_TRAP:
3776. 				return disarm_fire_trap(ttmp);
3777. 			case PIT:
3778. 			case SPIKED_PIT:
3779. 				if (!u.dx && !u.dy) {
3780. 				    You("are already on the edge of the pit.");
3781. 				    return 0;
3782. 				}
3783. 				if (!(mtmp = m_at(x,y))) {
3784. 				    pline("Try filling the pit instead.");
3785. 				    return 0;
3786. 				}
3787. 				return help_monster_out(mtmp, ttmp);
3788. 			default:
3789. 				You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this");
3790. 				return 0;
3791. 		    }
3792. 		}
3793. 	} /* end if */
3794. 
3795. 	if(!u.dx && !u.dy) {
3796. 	    for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
3797. 		if(Is_box(otmp)) {
3798. 		    Sprintf(qbuf, "There is %s here. Check it for traps?",
3799. 			safe_qbuf("", sizeof("There is  here. Check it for traps?"),
3800. 				doname(otmp), an(simple_typename(otmp->otyp)), "a box"));
3801. 		    switch (ynq(qbuf)) {
3802. 			case 'q': return(0);
3803. 			case 'n': continue;
3804. 		    }
3805. #ifdef STEED
3806. 		    if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
3807. 			You("aren't skilled enough to reach from %s.",
3808. 				mon_nam(u.usteed));
3809. 			return(0);
3810. 		    }
3811. #endif
3812. 		    if((otmp->otrapped && (force || (!confused
3813. 				&& rn2(MAXULEV + 1 - u.ulevel) < 10)))
3814. 		       || (!force && confused && !rn2(3))) {
3815. 			You("find a trap on %s!", the(xname(otmp)));
3816. 			if (!confused) exercise(A_WIS, TRUE);
3817. 
3818. 			switch (ynq("Disarm it?")) {
3819. 			    case 'q': return(1);
3820. 			    case 'n': trap_skipped = TRUE;  continue;
3821. 			}
3822. 
3823. 			if(otmp->otrapped) {
3824. 			    exercise(A_DEX, TRUE);
3825. 			    ch = ACURR(A_DEX) + u.ulevel;
3826. 			    if (Role_if(PM_ROGUE)) ch *= 2;
3827. 			    if(!force && (confused || Fumbling ||
3828. 				rnd(75+level_difficulty()/2) > ch)) {
3829. 				(void) chest_trap(otmp, FINGER, TRUE);
3830. 			    } else {
3831. 				You("disarm it!");
3832. 				otmp->otrapped = 0;
3833. 			    }
3834. 			} else pline("That %s was not trapped.", xname(otmp));
3835. 			return(1);
3836. 		    } else {
3837. 			You("find no traps on %s.", the(xname(otmp)));
3838. 			return(1);
3839. 		    }
3840. 		}
3841. 
3842. 	    You(trap_skipped ? "find no other traps here."
3843. 			     : "know of no traps here.");
3844. 	    return(0);
3845. 	}
3846. 
3847. 	if ((mtmp = m_at(x,y))				&&
3848. 		mtmp->m_ap_type == M_AP_FURNITURE	&&
3849. 		(mtmp->mappearance == S_hcdoor ||
3850. 			mtmp->mappearance == S_vcdoor)	&&
3851. 		!Protection_from_shape_changers)	 {
3852. 
3853. 	    stumble_onto_mimic(mtmp);
3854. 	    return(1);
3855. 	}
3856. 
3857. 	if (!IS_DOOR(levl[x][y].typ)) {
3858. 	    if ((ttmp = t_at(x,y)) && ttmp->tseen)
3859. 		You("cannot disable that trap.");
3860. 	    else
3861. 		You("know of no traps there.");
3862. 	    return(0);
3863. 	}
3864. 
3865. 	switch (levl[x][y].doormask) {
3866. 	    case D_NODOOR:
3867. 		You("%s no door there.", Blind ? "feel" : "see");
3868. 		return(0);
3869. 	    case D_ISOPEN:
3870. 		pline("This door is safely open.");
3871. 		return(0);
3872. 	    case D_BROKEN:
3873. 		pline("This door is broken.");
3874. 		return(0);
3875. 	}
3876. 
3877. 	if ((levl[x][y].doormask & D_TRAPPED
3878. 	     && (force ||
3879. 		 (!confused && rn2(MAXULEV - u.ulevel + 11) < 10)))
3880. 	    || (!force && confused && !rn2(3))) {
3881. 		You("find a trap on the door!");
3882. 		exercise(A_WIS, TRUE);
3883. 		if (ynq("Disarm it?") != 'y') return(1);
3884. 		if (levl[x][y].doormask & D_TRAPPED) {
3885. 		    ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel*3 : u.ulevel);
3886. 		    exercise(A_DEX, TRUE);
3887. 		    if(!force && (confused || Fumbling ||
3888. 				     rnd(75+level_difficulty()/2) > ch)) {
3889. 			You("set it off!");
3890. 			b_trapped("door", FINGER);
3891. 			levl[x][y].doormask = D_NODOOR;
3892. 			unblock_point(x, y);
3893. 			newsym(x, y);
3894. 			/* (probably ought to charge for this damage...) */
3895. 			if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
3896. 		    } else {
3897. 			You("disarm it!");
3898. 			levl[x][y].doormask &= ~D_TRAPPED;
3899. 		    }
3900. 		} else pline("This door was not trapped.");
3901. 		return(1);
3902. 	} else {
3903. 		You("find no traps on the door.");
3904. 		return(1);
3905. 	}
3906. }
3907. #endif /* OVL2 */
3908. #ifdef OVLB
3909. 
3910. /* only called when the player is doing something to the chest directly */
3911. boolean
3912. chest_trap(obj, bodypart, disarm)
3913. register struct obj *obj;
3914. register int bodypart;
3915. boolean disarm;
3916. {
3917. 	register struct obj *otmp = obj, *otmp2;
3918. 	char	buf[80];
3919. 	const char *msg;
3920. 	coord cc;
3921. 
3922. 	if (get_obj_location(obj, &cc.x, &cc.y, 0))	/* might be carried */
3923. 	    obj->ox = cc.x,  obj->oy = cc.y;
3924. 
3925. 	otmp->otrapped = 0;	/* trap is one-shot; clear flag first in case
3926. 				   chest kills you and ends up in bones file */
3927. 	You(disarm ? "set it off!" : "trigger a trap!");
3928. 	display_nhwindow(WIN_MESSAGE, FALSE);
3929. 	if (Luck > -13 && rn2(13+Luck) > 7) {	/* saved by luck */
3930. 	    /* trap went off, but good luck prevents damage */
3931. 	    switch (rn2(13)) {
3932. 		case 12:
3933. 		case 11:  msg = "explosive charge is a dud";  break;
3934. 		case 10:
3935. 		case  9:  msg = "electric charge is grounded";  break;
3936. 		case  8:
3937. 		case  7:  msg = "flame fizzles out";  break;
3938. 		case  6:
3939. 		case  5:
3940. 		case  4:  msg = "poisoned needle misses";  break;
3941. 		case  3:
3942. 		case  2:
3943. 		case  1:
3944. 		case  0:  msg = "gas cloud blows away";  break;
3945. 		default:  impossible("chest disarm bug");  msg = (char *)0;
3946. 			  break;
3947. 	    }
3948. 	    if (msg) pline("But luckily the %s!", msg);
3949. 	} else {
3950. 	    switch(rn2(20) ? ((Luck >= 13) ? 0 : rn2(13-Luck)) : rn2(26)) {
3951. 		case 25:
3952. 		case 24:
3953. 		case 23:
3954. 		case 22:
3955. 		case 21: {
3956. 			  struct monst *shkp = 0;
3957. 			  long loss = 0L;
3958. 			  boolean costly, insider;
3959. 			  register xchar ox = obj->ox, oy = obj->oy;
3960. 
3961. 			  /* the obj location need not be that of player */
3962. 			  costly = (costly_spot(ox, oy) &&
3963. 				   (shkp = shop_keeper(*in_rooms(ox, oy,
3964. 				    SHOPBASE))) != (struct monst *)0);
3965. 			  insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
3966. 				    *in_rooms(ox, oy, SHOPBASE) == *u.ushops);
3967. 
3968. 			  pline("%s!", Tobjnam(obj, "explode"));
3969. 			  Sprintf(buf, "exploding %s", xname(obj));
3970. 
3971. 			  if(costly)
3972. 			      loss += stolen_value(obj, ox, oy,
3973. 				      (boolean)shkp->mpeaceful, TRUE, TRUE);
3974. 			  delete_contents(obj);
3975. 			  /* we're about to delete all things at this location,
3976. 			   * which could include the ball & chain.
3977. 			   * If we attempt to call unpunish() in the
3978. 			   * for-loop below we can end up with otmp2
3979. 			   * being invalid once the chain is gone.
3980. 			   * Deal with ball & chain right now instead.
3981. 			   */
3982. 			  if (Punished && !carried(uball) &&
3983. 				((uchain->ox == u.ux && uchain->oy == u.uy) ||
3984. 				 (uball->ox == u.ux && uball->oy == u.uy)))
3985. 				unpunish();
3986. 
3987. 			  for(otmp = level.objects[u.ux][u.uy];
3988. 							otmp; otmp = otmp2) {
3989. 			      otmp2 = otmp->nexthere;
3990. 			      if(costly)
3991. 				  loss += stolen_value(otmp, otmp->ox,
3992. 					  otmp->oy, (boolean)shkp->mpeaceful,
3993. 					  TRUE, TRUE);
3994. 			      delobj(otmp);
3995. 			  }
3996. 			  wake_nearby();
3997. 			  losehp(d(6,6), buf, KILLED_BY_AN);
3998. 			  exercise(A_STR, FALSE);
3999. 			  if(costly && loss) {
4000. 			      if(insider)
4001. 			      You("owe %ld %s for objects destroyed.",
4002. 							loss, currency(loss));
4003. 			      else {
4004. 				  You("caused %ld %s worth of damage!",
4005. 							loss, currency(loss));
4006. 				  make_angry_shk(shkp, ox, oy);
4007. 			      }
4008. 			  }
4009. 			  return TRUE;
4010. 			}
4011. 		case 20:
4012. 		case 19:
4013. 		case 18:
4014. 		case 17:
4015. 			pline("A cloud of noxious gas billows from %s.",
4016. 							the(xname(obj)));
4017. 			poisoned("gas cloud", A_STR, "cloud of poison gas",15);
4018. 			exercise(A_CON, FALSE);
4019. 			break;
4020. 		case 16:
4021. 		case 15:
4022. 		case 14:
4023. 		case 13:
4024. 			You_feel("a needle prick your %s.",body_part(bodypart));
4025. 			poisoned("needle", A_CON, "poisoned needle",10);
4026. 			exercise(A_CON, FALSE);
4027. 			break;
4028. 		case 12:
4029. 		case 11:
4030. 		case 10:
4031. 		case 9:
4032. 			dofiretrap(obj);
4033. 			break;
4034. 		case 8:
4035. 		case 7:
4036. 		case 6: {
4037. 			int dmg;
4038. 
4039. 			You("are jolted by a surge of electricity!");
4040. 			if(Shock_resistance)  {
4041. 			    shieldeff(u.ux, u.uy);
4042. 			    You("don't seem to be affected.");
4043. 			    dmg = 0;
4044. 			} else
4045. 			    dmg = d(4, 4);
4046. 			destroy_item(RING_CLASS, AD_ELEC);
4047. 			destroy_item(WAND_CLASS, AD_ELEC);
4048. 			if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN);
4049. 			break;
4050. 		      }
4051. 		case 5:
4052. 		case 4:
4053. 		case 3:
4054. 			if (!Free_action) {                        
4055. 			if (!Free_action) {                        
4056. 			pline("Suddenly you are frozen in place!");
4057. 			nomul(-d(5, 6));
4058. 			exercise(A_DEX, FALSE);
4059. 			nomovemsg = You_can_move_again;
4060. 			} else You("momentarily stiffen.");
4061. 			} else You("momentarily stiffen.");                        
4062. 			break;
4063. 		case 2:
4064. 		case 1:
4065. 		case 0:
4066. 			pline("A cloud of %s gas billows from %s.",
4067. 				Blind ? blindgas[rn2(SIZE(blindgas))] :
4068. 				rndcolor(), the(xname(obj)));
4069. 			if(!Stunned) {
4070. 			    if (Hallucination)
4071. 				pline("What a groovy feeling!");
4072. 			    else if (Blind)
4073. 				You("%s and get dizzy...",
4074. 				    stagger(youmonst.data, "stagger"));
4075. 			    else
4076. 				You("%s and your vision blurs...",
4077. 				    stagger(youmonst.data, "stagger"));
4078. 			}
4079. 			make_stunned(HStun + rn1(7, 16),FALSE);
4080. 			(void) make_hallucinated(HHallucination + rn1(5, 16),FALSE,0L);
4081. 			break;
4082. 		default: impossible("bad chest trap");
4083. 			break;
4084. 	    }
4085. 	    bot();			/* to get immediate botl re-display */
4086. 	}
4087. 	return FALSE;
4088. }
4089. 
4090. #endif /* OVLB */
4091. #ifdef OVL0
4092. 
4093. struct trap *
4094. t_at(x,y)
4095. register int x, y;
4096. {
4097. 	register struct trap *trap = ftrap;
4098. 	while(trap) {
4099. 		if(trap->tx == x && trap->ty == y) return(trap);
4100. 		trap = trap->ntrap;
4101. 	}
4102. 	return((struct trap *)0);
4103. }
4104. 
4105. #endif /* OVL0 */
4106. #ifdef OVLB
4107. 
4108. void
4109. deltrap(trap)
4110. register struct trap *trap;
4111. {
4112. 	register struct trap *ttmp;
4113. 
4114. 	if(trap == ftrap)
4115. 		ftrap = ftrap->ntrap;
4116. 	else {
4117. 		for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
4118. 		ttmp->ntrap = trap->ntrap;
4119. 	}
4120. 	dealloc_trap(trap);
4121. }
4122. 
4123. boolean
4124. delfloortrap(ttmp)
4125. register struct trap *ttmp;
4126. {
4127. 	/* Destroy a trap that emanates from the floor. */
4128. 	/* some of these are arbitrary -dlc */
4129. 	if (ttmp && ((ttmp->ttyp == SQKY_BOARD) ||
4130. 		     (ttmp->ttyp == BEAR_TRAP) ||
4131. 		     (ttmp->ttyp == LANDMINE) ||
4132. 		     (ttmp->ttyp == FIRE_TRAP) ||
4133. 		     (ttmp->ttyp == PIT) ||
4134. 		     (ttmp->ttyp == SPIKED_PIT) ||
4135. 		     (ttmp->ttyp == HOLE) ||
4136. 		     (ttmp->ttyp == TRAPDOOR) ||
4137. 		     (ttmp->ttyp == TELEP_TRAP) ||
4138. 		     (ttmp->ttyp == LEVEL_TELEP) ||
4139. 		     (ttmp->ttyp == WEB) ||
4140. 		     (ttmp->ttyp == MAGIC_TRAP) ||
4141. 		     (ttmp->ttyp == ANTI_MAGIC))) {
4142. 	    register struct monst *mtmp;
4143. 
4144. 	    if (ttmp->tx == u.ux && ttmp->ty == u.uy) {
4145. 		u.utrap = 0;
4146. 		u.utraptype = 0;
4147. 	    } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) {
4148. 		mtmp->mtrapped = 0;
4149. 	    }
4150. 	    deltrap(ttmp);
4151. 	    return TRUE;
4152. 	} else
4153. 	    return FALSE;
4154. }
4155. 
4156. /* used for doors (also tins).  can be used for anything else that opens. */
4157. void
4158. b_trapped(item, bodypart)
4159. register const char *item;
4160. register int bodypart;
4161. {
4162. 	register int lvl = level_difficulty();
4163. 	int dmg = rnd(5 + (lvl < 5 ? lvl : 2+lvl/2));
4164. 
4165. 	pline("KABOOM!!  %s was booby-trapped!", The(item));
4166. 	wake_nearby();
4167. 	losehp(dmg, "explosion", KILLED_BY_AN);
4168. 	exercise(A_STR, FALSE);
4169. 	if (bodypart) exercise(A_CON, FALSE);
4170. 	make_stunned(HStun + dmg, TRUE);
4171. }
4172. 
4173. /* Monster is hit by trap. */
4174. /* Note: doesn't work if both obj and d_override are null */
4175. STATIC_OVL boolean
4176. thitm(tlev, mon, obj, d_override, nocorpse)
4177. int tlev;
4178. struct monst *mon;
4179. struct obj *obj;
4180. int d_override;
4181. boolean nocorpse;
4182. {
4183. 	int strike;
4184. 	boolean trapkilled = FALSE;
4185. 
4186. 	if (d_override) strike = 1;
4187. 	else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20));
4188. 	else strike = (find_mac(mon) + tlev <= rnd(20));
4189. 
4190. 	/* Actually more accurate than thitu, which doesn't take
4191. 	 * obj->spe into account.
4192. 	 */
4193. 	if(!strike) {
4194. 		if (obj && cansee(mon->mx, mon->my))
4195. 		    pline("%s is almost hit by %s!", Monnam(mon), doname(obj));
4196. 	} else {
4197. 		int dam = 1;
4198. 
4199. 		if (obj && cansee(mon->mx, mon->my))
4200. 			pline("%s is hit by %s!", Monnam(mon), doname(obj));
4201. 		if (d_override) dam = d_override;
4202. 		else if (obj) {
4203. 			dam = dmgval(obj, mon);
4204. 			if (dam < 1) dam = 1;
4205. 		}
4206. 		if ((mon->mhp -= dam) <= 0) {
4207. 			int xx = mon->mx;
4208. 			int yy = mon->my;
4209. 
4210. 			monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
4211. 			if (mon->mhp <= 0) {
4212. 				newsym(xx, yy);
4213. 				trapkilled = TRUE;
4214. 			}
4215. 		}
4216. 	}
4217. 	if (obj && (!strike || d_override)) {
4218. 		place_object(obj, mon->mx, mon->my);
4219. 		stackobj(obj);
4220. 	} else if (obj) dealloc_obj(obj);
4221. 
4222. 	return trapkilled;
4223. }
4224. 
4225. boolean
4226. unconscious()
4227. {
4228. 	return((boolean)(multi < 0 && (!nomovemsg ||
4229. 		u.usleep ||
4230. 		!strncmp(nomovemsg,"You regain con", 14) ||
4231. 		!strncmp(nomovemsg,"You are consci", 14))));
4232. }
4233. 
4234. static const char lava_killer[] = "molten lava";
4235. 
4236. boolean
4237. lava_effects()
4238. {
4239.     register struct obj *obj, *obj2;
4240.     int dmg;
4241.     boolean usurvive;
4242. 
4243.     burn_away_slime();
4244.     if (likes_lava(youmonst.data)) return FALSE;
4245. 
4246. 
4247.     if (Slimed) {
4248. 	pline("The slime boils away!");
4249. 	Slimed = 0;
4250.     }
4251. 
4252.     if (!Fire_resistance) {
4253. 
4254. 	if(Wwalking) {
4255. 	    dmg = d(6,6);
4256. 	    pline_The("lava here burns you!");
4257. 	    if(dmg < u.uhp) {
4258. 		losehp(dmg, lava_killer, KILLED_BY);
4259. 		goto burn_stuff;
4260. 	    }
4261. 	} else
4262. 	    You("fall into the lava!");
4263. 
4264. 	usurvive = Lifesaved || discover;
4265. #ifdef WIZARD
4266. 	if (wizard) usurvive = TRUE;
4267. #endif
4268. 	for(obj = invent; obj; obj = obj2) {
4269. 	    obj2 = obj->nobj;
4270. 	    if(is_organic(obj) && !obj->oerodeproof) {
4271. 		if(obj->owornmask) {
4272. 		    if (usurvive)
4273. 			Your("%s into flame!", aobjnam(obj, "burst"));
4274. 
4275. 		    if(obj == uarm) (void) Armor_gone();
4276. 		    else if(obj == uarmc) (void) Cloak_off();
4277. 		    else if(obj == uarmh) (void) Helmet_off();
4278. 		    else if(obj == uarms) (void) Shield_off();
4279. 		    else if(obj == uarmg) (void) Gloves_off();
4280. 		    else if(obj == uarmf) (void) Boots_off();
4281. #ifdef TOURIST
4282. 		    else if(obj == uarmu) setnotworn(obj);
4283. #endif
4284. 		    else if(obj == uleft) Ring_gone(obj);
4285. 		    else if(obj == uright) Ring_gone(obj);
4286. 		    else if(obj == ublindf) Blindf_off(obj);
4287. 		    else if(obj == uamul) Amulet_off();
4288. 		    else if(obj == uwep) uwepgone();
4289. 		    else if (obj == uquiver) uqwepgone();
4290. 		    else if (obj == uswapwep) uswapwepgone();
4291. 		}
4292. 		useupall(obj);
4293. 	    }
4294. 	}
4295. 
4296. 	/* s/he died... */
4297. 	u.uhp = -1;
4298. 	killer_format = KILLED_BY;
4299. 	killer = lava_killer;
4300. 	You("burn to a crisp...");
4301. 	done(BURNING);
4302. 	while (!safe_teleds(TRUE)) {
4303. 		pline("You're still burning.");
4304. 		done(BURNING);
4305. 	}
4306. 	You("find yourself back on solid %s.", surface(u.ux, u.uy));
4307. 	return(TRUE);
4308.     }
4309. 
4310.     if (!Wwalking) {
4311. 	u.utrap = rn1(4, 4) + (rn1(4, 12) << 8);
4312. 	u.utraptype = TT_LAVA;
4313. 	You("sink into the lava, but it only burns slightly!");
4314. 	if (u.uhp > 1)
4315. 	    losehp(1, lava_killer, KILLED_BY);
4316.     }
4317.     /* just want to burn boots, not all armor; destroy_item doesn't work on
4318.        armor anyway */
4319. burn_stuff:
4320.     if(uarmf && !uarmf->oerodeproof && is_organic(uarmf)) {
4321. 	/* save uarmf value because Boots_off() sets uarmf to null */
4322. 	obj = uarmf;
4323. 	Your("%s bursts into flame!", xname(obj));
4324. 	(void) Boots_off();
4325. 	useup(obj);
4326.     }
4327.     destroy_item(SCROLL_CLASS, AD_FIRE);
4328.     destroy_item(SPBOOK_CLASS, AD_FIRE);
4329.     destroy_item(POTION_CLASS, AD_FIRE);
4330.     return(FALSE);
4331. }
4332. 
4333. #endif /* OVLB */
4334. 
4335. /*trap.c*/