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