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