Fandom

Wikihack

Source:SLASH'EM 0.0.7E7F2/trap.c

2,034pages on
this wiki
Add New Page
Talk0

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 [[SLASH'EM 0.0.7E7F2/trap.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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*/

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.