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