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. */
7 extern const char * const destroy_strings[]; /* from zap.c */
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));
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 *));
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];
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"};
53 /* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */
54 boolean /* returns TRUE if hit on torso */
62 if (!victim) return 0;
63 #define burn_dmg(obj,descr) rust_dmg(obj, descr, 0, FALSE, victim)
67 item = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH);
69 mat_idx = objects[item->otyp].oc_material;
70 Sprintf(buf,"%s helmet", materialnm[mat_idx] );
72 if (!burn_dmg(item, item ? buf : "helmet")) continue;
75 item = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC);
77 (void) burn_dmg(item, cloak_simple_name(item));
80 item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM);
82 (void) burn_dmg(item, xname(item));
86 item = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU);
88 (void) burn_dmg(item, "shirt");
92 item = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS);
93 if (!burn_dmg(item, "wooden shield")) continue;
96 item = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG);
97 if (!burn_dmg(item, "gloves")) continue;
100 item = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF);
101 if (!burn_dmg(item, "boots")) continue;
104 break; /* Out of while loop */
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.
116 rust_dmg(otmp, ostr, type, print, victim)
117 register struct obj *otmp;
118 register const char *ostr;
121 struct monst *victim;
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);
131 if (!otmp) return(FALSE);
133 case 0: vulnerable = is_flammable(otmp);
135 case 1: vulnerable = is_rustprone(otmp);
138 case 2: vulnerable = is_rottable(otmp);
141 case 3: vulnerable = is_corrodeable(otmp);
146 erosion = is_primary ? otmp->oeroded : otmp->oeroded2;
148 if (!print && (!vulnerable || otmp->oerodeproof || erosion == MAX_ERODE))
153 if (victim == &youmonst)
154 Your("%s %s not affected.", ostr, vtense(ostr, "are"));
156 pline("%s's %s %s not affected.", Monnam(victim), ostr,
157 vtense(ostr, "are"));
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))) {
164 if (victim == &youmonst)
165 pline("Somehow, your %s %s not affected.",
166 ostr, vtense(ostr, "are"));
168 pline("Somehow, %s's %s %s not affected.",
169 mon_nam(victim), ostr, vtense(ostr, "are"));
172 if (victim == &youmonst)
173 Your("%s %s%s!", ostr,
174 vtense(ostr, action[type]),
175 erosion+1 == MAX_ERODE ? " completely" :
176 erosion ? " further" : "");
178 pline("%s's %s %s%s!", Monnam(victim), ostr,
179 vtense(ostr, action[type]),
180 erosion+1 == MAX_ERODE ? " completely" :
181 erosion ? " further" : "");
190 if (victim == &youmonst)
191 Your("%s %s completely %s.", ostr,
192 vtense(ostr, Blind ? "feel" : "look"),
195 pline("%s's %s %s completely %s.",
196 Monnam(victim), ostr,
197 vtense(ostr, "look"), msg[type]);
204 grease_protect(otmp,ostr,victim)
205 register struct obj *otmp;
206 register const char *ostr;
207 struct monst *victim;
209 static const char txt[] = "protected by the layer of grease!";
210 boolean vismon = victim && (victim != &youmonst) && canseemon(victim);
213 if (victim == &youmonst)
214 Your("%s %s %s", ostr, vtense(ostr, "are"), txt);
216 pline("%s's %s %s %s", Monnam(victim),
217 ostr, vtense(ostr, "are"), txt);
219 if (victim == &youmonst)
220 Your("%s %s",aobjnam(otmp,"are"), txt);
222 pline("%s's %s %s", Monnam(victim), aobjnam(otmp,"are"), txt);
227 pline_The("grease dissolves.");
235 register int x, y, typ;
237 register struct trap *ttmp;
238 register struct rm *lev;
239 register boolean oldplace;
241 if ((ttmp = t_at(x,y)) != 0) {
242 if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0;
244 if (u.utrap && (x == u.ux) && (y == u.uy) &&
245 ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) ||
246 (u.utraptype == TT_WEB && typ != WEB) ||
247 (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT)))
254 ttmp->launch.x = -1; /* force error if used before set */
259 case STATUE_TRAP: /* create a "living" statue */
260 { struct monst *mtmp;
261 struct obj *otmp, *statue;
263 statue = mkcorpstat(STATUE, (struct monst *)0,
264 &mons[rndmonnum()], x, y, FALSE);
265 mtmp = makemon(&mons[statue->corpsenm], 0, 0, NO_MM_FLAGS);
266 if (!mtmp) break; /* should never happen */
267 while(mtmp->minvent) {
268 otmp = mtmp->minvent;
270 obj_extract_self(otmp);
271 (void) add_to_container(statue, otmp);
273 statue->owt = weight(statue);
277 case ROLLING_BOULDER_TRAP: /* boulder will roll towards trigger */
278 (void) mkroll_launch(ttmp, x, y, BOULDER, 1L);
285 if (*in_rooms(x, y, SHOPBASE) &&
286 ((typ == HOLE || typ == TRAPDOOR) ||
287 IS_DOOR(lev->typ) || IS_WALL(lev->typ)))
288 add_damage(x, y, /* schedule repair */
289 ((IS_DOOR(lev->typ) || IS_WALL(lev->typ))
290 && !flags.mon_moving) ? 200L : 0L);
291 lev->doormask = 0; /* subsumes altarmask, icedpool... */
292 if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */
296 * some cases which can happen when digging
297 * down while phazing thru solid areas
299 else if (lev->typ == STONE || lev->typ == SCORR)
301 else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
302 lev->typ = level.flags.is_maze_lev ? ROOM :
303 level.flags.is_cavernous_lev ? CORR : DOOR;
308 if (ttmp->ttyp == HOLE) ttmp->tseen = 1; /* You can't hide a hole */
309 else ttmp->tseen = 0;
313 ttmp->dst.dlevel = -1;
323 boolean td; /* td == TRUE : trap door or hole */
327 const char *dont_fall = 0;
328 register int newlevel = dunlev(&u.uz);
330 /* KMH -- You can't escape the Sokoban level traps */
331 if(Blind && Levitation && !In_sokoban(&u.uz)) return;
335 } while(!rn2(4) && newlevel < dunlevs_in_dungeon(&u.uz));
338 struct trap *t=t_at(u.ux,u.uy);
340 if (!In_sokoban(&u.uz)) {
341 if (t->ttyp == TRAPDOOR)
342 pline("A trap door opens up under you!");
344 pline("There's a gaping hole under you!");
346 } else pline_The("%s opens up under you!", surface(u.ux,u.uy));
348 if (In_sokoban(&u.uz) && Can_fall_thru(&u.uz))
349 ; /* KMH -- You can't escape the Sokoban level traps */
350 else if(Levitation || u.ustuck || !Can_fall_thru(&u.uz)
351 || Flying || is_clinger(youmonst.data)
352 || (Inhell && !u.uevent.invoked &&
353 newlevel == dunlevs_in_dungeon(&u.uz))
355 dont_fall = "don't fall in.";
356 } else if (youmonst.data->msize >= MZ_HUGE) {
357 dont_fall = "don't fit through.";
358 } else if (!next_to_u()) {
359 dont_fall = "are jerked back by your pet!";
363 /* hero didn't fall through, but any objects here might */
364 impact_drop((struct obj *)0, u.ux, u.uy, 0);
366 display_nhwindow(WIN_MESSAGE, FALSE);
367 pline_The("opening under you closes up.");
372 if(*u.ushops) shopdig(1);
373 if (Is_stronghold(&u.uz)) {
376 dtmp.dnum = u.uz.dnum;
377 dtmp.dlevel = newlevel;
380 Sprintf(msgbuf, "The hole in the %s above you closes up.",
382 schedule_goto(&dtmp, FALSE, TRUE, 0,
383 (char *)0, !td ? msgbuf : (char *)0);
387 * Animate the given statue. May have been via shatter attempt, trap,
388 * or stone to flesh spell. Return a monster if successfully animated.
389 * If the monster is animated, the object is deleted. If fail_reason
390 * is non-null, then fill in the reason for failure (or success).
392 * The cause of animation is:
394 * ANIMATE_NORMAL - hero "finds" the monster
395 * ANIMATE_SHATTER - hero tries to destroy the statue
396 * ANIMATE_SPELL - stone to flesh spell hits the statue
398 * Perhaps x, y is not needed if we can use get_obj_location() to find
399 * the statue's location... ???
402 animate_statue(statue, x, y, cause, fail_reason)
408 struct permonst *mptr;
409 struct monst *mon = 0;
412 boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC));
413 char statuename[BUFSZ];
415 Strcpy(statuename,the(xname(statue)));
417 if (statue->oxlth && statue->oattached == OATTACHED_MONST) {
419 mon = montraits(statue, &cc);
420 if (mon && mon->mtame && !mon->isminion)
423 /* statue of any golem hit with stone-to-flesh becomes flesh golem */
424 if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL)
425 mptr = &mons[PM_FLESH_GOLEM];
427 mptr = &mons[statue->corpsenm];
429 * Guard against someone wishing for a statue of a unique monster
430 * (which is allowed in normal play) and then tossing it onto the
431 * [detected or guessed] location of a statue trap. Normally the
432 * uppermost statue is the one which would be activated.
434 if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) {
435 if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE;
436 return (struct monst *)0;
438 if (cause == ANIMATE_SPELL &&
439 ((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) {
440 /* Statues of quest guardians or unique monsters
441 * will not stone-to-flesh as the real thing.
443 mon = makemon(&mons[PM_DOPPELGANGER], x, y,
444 NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK);
446 /* makemon() will set mon->cham to
447 * CHAM_ORDINARY if hero is wearing
448 * ring of protection from shape changers
449 * when makemon() is called, so we have to
450 * check the field before calling newcham().
452 if (mon->cham == CHAM_DOPPELGANGER)
453 (void) newcham(mon, mptr, FALSE, FALSE);
456 mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ?
457 (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT);
461 if (fail_reason) *fail_reason = AS_NO_MON;
462 return (struct monst *)0;
465 /* in case statue is wielded and hero zaps stone-to-flesh at self */
466 if (statue->owornmask) remove_worn_item(statue, TRUE);
468 /* allow statues to be of a specific gender */
469 if (statue->spe & STATUE_MALE)
471 else if (statue->spe & STATUE_FEMALE)
473 /* if statue has been named, give same name to the monster */
474 if (statue->onamelth)
475 mon = christen_monst(mon, ONAME(statue));
476 /* transfer any statue contents to monster's inventory */
477 while ((item = statue->cobj) != 0) {
478 obj_extract_self(item);
479 (void) add_to_minv(mon, item);
484 /* mimic statue becomes seen mimic; other hiders won't be hidden */
485 if (mon->m_ap_type) seemimic(mon);
486 else mon->mundetected = FALSE;
487 if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
488 const char *comes_to_life = nonliving(mon->data) ?
489 "moves" : "comes to life";
490 if (cause == ANIMATE_SPELL)
491 pline("%s %s!", upstart(statuename),
492 canspotmon(mon) ? comes_to_life : "disappears");
494 pline_The("statue %s!",
495 canspotmon(mon) ? comes_to_life : "disappears");
497 You_feel("guilty that the historic statue is now gone.");
500 } else if (cause == ANIMATE_SHATTER)
501 pline("Instead of shattering, the statue suddenly %s!",
502 canspotmon(mon) ? "comes to life" : "disappears");
503 else { /* cause == ANIMATE_NORMAL */
504 You("find %s posing as a statue.",
505 canspotmon(mon) ? a_monnam(mon) : something);
508 /* avoid hiding under nothing */
509 if (x == u.ux && y == u.uy &&
510 Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y))
513 if (fail_reason) *fail_reason = AS_OK;
518 * You've either stepped onto a statue trap's location or you've triggered a
519 * statue trap by searching next to it or by trying to break it with a wand
523 activate_statue_trap(trap, x, y, shatter)
528 struct monst *mtmp = (struct monst *)0;
529 struct obj *otmp = sobj_at(STATUE, x, y);
533 * Try to animate the first valid statue. Stop the loop when we
534 * actually create something or the failure cause is not because
535 * the mon was unique.
539 mtmp = animate_statue(otmp, x, y,
540 shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason);
541 if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break;
543 while ((otmp = otmp->nexthere) != 0)
544 if (otmp->otyp == STATUE) break;
547 if (Blind) feel_location(x, y);
554 keep_saddle_with_steedcorpse(steed_mid, objchn, saddle)
556 struct obj *objchn, *saddle;
558 if (!saddle) return FALSE;
560 if(objchn->otyp == CORPSE &&
561 objchn->oattached == OATTACHED_MONST && objchn->oxlth) {
562 struct monst *mtmp = (struct monst *)objchn->oextra;
563 if (mtmp->m_id == steed_mid) {
566 if (get_obj_location(objchn, &x, &y, 0)) {
567 obj_extract_self(saddle);
568 place_object(saddle, x, y);
574 if (Has_contents(objchn) &&
575 keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle))
577 objchn = objchn->nobj;
584 dotrap(trap, trflags)
585 register struct trap *trap;
588 register int ttype = trap->ttyp;
589 register struct obj *otmp;
590 boolean already_seen = trap->tseen;
591 boolean webmsgok = (!(trflags & NOWEBMSG));
592 boolean forcebungle = (trflags & FORCEBUNGLE);
596 /* KMH -- You can't escape the Sokoban level traps */
597 if (In_sokoban(&u.uz) &&
598 (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
599 ttype == TRAPDOOR)) {
600 /* The "air currents" message is still appropriate -- even when
601 * the hero isn't flying or levitating -- because it conveys the
602 * reason why the player cannot escape the trap with a dexterity
603 * check, clinging to the ceiling, etc.
605 pline("Air currents pull you down into %s %s!",
606 a_your[trap->madeby_u],
607 defsyms[trap_to_defsym(ttype)].explanation);
608 /* then proceed to normal trap effect */
609 } else if (already_seen) {
610 if ((Levitation || Flying) &&
611 (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE ||
612 ttype == BEAR_TRAP)) {
613 You("%s over %s %s.",
614 Levitation ? "float" : "fly",
615 a_your[trap->madeby_u],
616 defsyms[trap_to_defsym(ttype)].explanation);
619 if(!Fumbling && ttype != MAGIC_PORTAL &&
620 ttype != ANTI_MAGIC && !forcebungle &&
622 ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) {
624 (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" :
625 a_your[trap->madeby_u],
626 defsyms[trap_to_defsym(ttype)].explanation);
632 if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1));
637 if (trap->once && trap->tseen && !rn2(15)) {
638 You_hear("a loud click!");
645 pline("An arrow shoots out at you!");
646 otmp = mksobj(ARROW, TRUE, FALSE);
648 otmp->owt = weight(otmp);
651 if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
654 if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) {
655 obfree(otmp, (struct obj *)0);
657 place_object(otmp, u.ux, u.uy);
658 if (!Blind) otmp->dknown = 1;
664 if (trap->once && trap->tseen && !rn2(15)) {
665 You_hear("a soft click.");
672 pline("A little dart shoots out at you!");
673 otmp = mksobj(DART, TRUE, FALSE);
675 otmp->owt = weight(otmp);
676 if (!rn2(6)) otmp->opoisoned = 1;
678 if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */;
681 if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) {
683 poisoned("dart", A_CON, "little dart", -10);
684 obfree(otmp, (struct obj *)0);
686 place_object(otmp, u.ux, u.uy);
687 if (!Blind) otmp->dknown = 1;
693 if (trap->once && trap->tseen && !rn2(15)) {
694 pline("A trap door in %s opens, but nothing falls out!",
695 the(ceiling(u.ux,u.uy)));
699 int dmg = d(2,6); /* should be std ROCK dmg? */
703 otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE);
705 otmp->owt = weight(otmp);
707 pline("A trap door in %s opens and %s falls on your %s!",
708 the(ceiling(u.ux,u.uy)),
713 if(is_metallic(uarmh)) {
714 pline("Fortunately, you are wearing a hard helmet.");
716 } else if (flags.verbose) {
717 Your("%s does not protect you.", xname(uarmh));
721 if (!Blind) otmp->dknown = 1;
723 newsym(u.ux,u.uy); /* map the rock */
725 losehp(dmg, "falling rock", KILLED_BY_AN);
726 exercise(A_STR, FALSE);
730 case SQKY_BOARD: /* stepped on a squeaky board */
731 if (Levitation || Flying) {
735 You("notice a crease in the linoleum.");
737 You("notice a loose board below you.");
741 pline("A board beneath you squeaks loudly.");
747 if(Levitation || Flying) break;
749 if(amorphous(youmonst.data) || is_whirly(youmonst.data) ||
750 unsolid(youmonst.data)) {
751 pline("%s bear trap closes harmlessly through you.",
752 A_Your[trap->madeby_u]);
759 youmonst.data->msize <= MZ_SMALL) {
760 pline("%s bear trap closes harmlessly over you.",
761 A_Your[trap->madeby_u]);
765 u.utraptype = TT_BEARTRAP;
768 pline("%s bear trap closes on %s %s!",
769 A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)),
770 mbodypart(u.usteed, FOOT));
774 pline("%s bear trap closes on your %s!",
775 A_Your[trap->madeby_u], body_part(FOOT));
776 if(u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR)
777 You("howl in anger!");
779 exercise(A_DEX, FALSE);
784 if(Sleep_resistance || breathless(youmonst.data)) {
785 You("are enveloped in a cloud of gas!");
788 pline("A cloud of gas puts you to sleep!");
789 fall_asleep(-rnd(25), TRUE);
791 (void) steedintrap(trap, (struct obj *)0);
797 if (u.umonnum == PM_IRON_GOLEM) {
800 pline("%s you!", A_gush_of_water_hits);
801 You("are covered with rust!");
802 if (Half_physical_damage) dam = (dam+1) / 2;
803 losehp(dam, "rusting away", KILLED_BY);
805 } else if (u.umonnum == PM_GREMLIN && rn2(3)) {
806 pline("%s you!", A_gush_of_water_hits);
807 (void)split_mon(&youmonst, (struct monst *)0);
811 /* Unlike monsters, traps cannot aim their rust attacks at
812 * you, so instead of looping through and taking either the
813 * first rustable one or the body, we take whatever we get,
814 * even if it is not rustable.
818 pline("%s you on the %s!", A_gush_of_water_hits,
820 (void) rust_dmg(uarmh, "helmet", 1, TRUE, &youmonst);
823 pline("%s your left %s!", A_gush_of_water_hits,
825 if (rust_dmg(uarms, "shield", 1, TRUE, &youmonst))
827 if (u.twoweap || (uwep && bimanual(uwep)))
828 erode_obj(u.twoweap ? uswapwep : uwep, FALSE, TRUE);
829 glovecheck: (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst);
830 /* Not "metal gauntlets" since it gets called
831 * even if it's leather for the message
835 pline("%s your right %s!", A_gush_of_water_hits,
837 erode_obj(uwep, FALSE, TRUE);
840 pline("%s you!", A_gush_of_water_hits);
841 for (otmp=invent; otmp; otmp = otmp->nobj)
842 (void) snuff_lit(otmp);
844 (void) rust_dmg(uarmc, cloak_simple_name(uarmc),
847 (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst);
850 (void) rust_dmg(uarmu, "shirt", 1, TRUE, &youmonst);
858 dofiretrap((struct obj *)0);
863 /* KMH -- You can't escape the Sokoban level traps */
864 if (!In_sokoban(&u.uz) && (Levitation || Flying)) break;
866 if (!In_sokoban(&u.uz) && is_clinger(youmonst.data)) {
868 You("see %s %spit below you.", a_your[trap->madeby_u],
869 ttype == SPIKED_PIT ? "spiked " : "");
871 pline("%s pit %sopens up under you!",
872 A_Your[trap->madeby_u],
873 ttype == SPIKED_PIT ? "full of spikes " : "");
874 You("don't fall in!");
878 if (!In_sokoban(&u.uz)) {
882 if ((trflags & RECURSIVETRAP) != 0)
883 Sprintf(verbbuf, "and %s fall",
885 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
886 (char *)0, SUPPRESS_SADDLE, FALSE));
888 Sprintf(verbbuf,"lead %s",
890 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
891 "poor", SUPPRESS_SADDLE, FALSE));
894 Strcpy(verbbuf,"fall");
895 You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]);
897 /* wumpus reference */
898 if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once &&
899 In_quest(&u.uz) && Is_qlocate(&u.uz)) {
900 pline("Fortunately it has a bottom after all...");
902 } else if (u.umonnum == PM_PIT_VIPER ||
903 u.umonnum == PM_PIT_FIEND)
904 pline("How pitiful. Isn't that the pits?");
905 if (ttype == SPIKED_PIT) {
906 const char *predicament = "on a set of sharp iron spikes";
909 pline("%s lands %s!",
910 upstart(x_monnam(u.usteed,
911 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
912 "poor", SUPPRESS_SADDLE, FALSE)),
916 You("land %s!", predicament);
920 u.utraptype = TT_PIT;
922 if (!steedintrap(trap, (struct obj *)0)) {
924 if (ttype == SPIKED_PIT) {
925 losehp(rnd(10),"fell into a pit of iron spikes",
928 poisoned("spikes", A_STR, "fall onto poison spikes", 8);
930 losehp(rnd(6),"fell into a pit", NO_KILLER_PREFIX);
931 if (Punished && !carried(uball)) {
936 selftouch("Falling, you");
937 vision_full_recalc = 1; /* vision limits change */
938 exercise(A_STR, FALSE);
939 exercise(A_DEX, FALSE);
946 if (!Can_fall_thru(&u.uz)) {
947 seetrap(trap); /* normally done in fall_through */
948 impossible("dotrap: %ss cannot exist on this level.",
949 defsyms[trap_to_defsym(ttype)].explanation);
950 break; /* don't activate it after all */
961 level_tele_trap(trap);
964 case WEB: /* Our luckless player has stumbled into a web. */
966 if (amorphous(youmonst.data) || is_whirly(youmonst.data) ||
967 unsolid(youmonst.data)) {
968 if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE ||
969 u.umonnum == PM_FIRE_ELEMENTAL) {
971 You("%s %s spider web!",
972 (u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve",
973 a_your[trap->madeby_u]);
978 if (webmsgok) You("flow through %s spider web.",
979 a_your[trap->madeby_u]);
982 if (webmaker(youmonst.data)) {
984 pline(trap->madeby_u ? "You take a walk on your web."
985 : "There is a spider web here.");
993 Sprintf(verbbuf,"lead %s",
995 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
996 "poor", SUPPRESS_SADDLE, FALSE));
1000 Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" :
1001 locomotion(youmonst.data, "stumble"));
1002 You("%s into %s spider web!",
1003 verbbuf, a_your[trap->madeby_u]);
1005 u.utraptype = TT_WEB;
1007 /* Time stuck in the web depends on your/steed strength. */
1009 register int str = ACURR(A_STR);
1012 /* If mounted, the steed gets trapped. Use mintrap
1013 * to do all the work. If mtrapped is set as a result,
1014 * unset it and set utrap instead. In the case of a
1015 * strongmonst and mintrap said it's trapped, use a
1016 * short but non-zero trap time. Otherwise, monsters
1017 * have no specific strength, so use player strength.
1018 * This gets skipped for webmsgok, which implies that
1019 * the steed isn't a factor.
1021 if (u.usteed && webmsgok) {
1022 /* mtmp location might not be up to date */
1023 u.usteed->mx = u.ux;
1024 u.usteed->my = u.uy;
1026 /* mintrap currently does not return 2(died) for webs */
1027 if (mintrap(u.usteed)) {
1028 u.usteed->mtrapped = 0;
1029 if (strongmonst(u.usteed->data)) str = 17;
1034 webmsgok = FALSE; /* mintrap printed the messages */
1037 if (str <= 3) u.utrap = rn1(6,6);
1038 else if (str < 6) u.utrap = rn1(6,4);
1039 else if (str < 9) u.utrap = rn1(4,4);
1040 else if (str < 12) u.utrap = rn1(4,2);
1041 else if (str < 15) u.utrap = rn1(2,2);
1042 else if (str < 18) u.utrap = rnd(2);
1043 else if (str < 69) u.utrap = 1;
1047 You("tear through %s web!", a_your[trap->madeby_u]);
1049 newsym(u.ux,u.uy); /* get rid of trap symbol */
1055 (void) activate_statue_trap(trap, u.ux, u.uy, FALSE);
1058 case MAGIC_TRAP: /* A magic trap. */
1062 newsym(u.ux,u.uy); /* update position */
1063 You("are caught in a magical explosion!");
1064 losehp(rnd(10), "magical explosion", KILLED_BY_AN);
1065 Your("body absorbs some of the magical energy!");
1066 u.uen = (u.uenmax += 2);
1067 } else domagictrap();
1069 (void) steedintrap(trap, (struct obj *)0);
1076 shieldeff(u.ux, u.uy);
1077 You_feel("momentarily lethargic.");
1078 } else drain_en(rnd(u.ulevel) + 1);
1082 char verbbuf[BUFSZ];
1086 Sprintf(verbbuf, "lead %s",
1088 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
1089 (char *)0, SUPPRESS_SADDLE, FALSE));
1092 Sprintf(verbbuf,"%s",
1093 Levitation ? (const char *)"float" :
1094 locomotion(youmonst.data, "step"));
1095 You("%s onto a polymorph trap!", verbbuf);
1096 if(Antimagic || Unchanging) {
1097 shieldeff(u.ux, u.uy);
1098 You_feel("momentarily different.");
1099 /* Trap did nothing; don't remove it --KAA */
1102 (void) steedintrap(trap, (struct obj *)0);
1104 deltrap(trap); /* delete trap before polymorph */
1105 newsym(u.ux,u.uy); /* get rid of trap symbol */
1106 You_feel("a change coming over you.");
1113 unsigned steed_mid = 0;
1114 struct obj *saddle = 0;
1116 if (Levitation || Flying) {
1117 if (!already_seen && rn2(3)) break;
1119 pline("%s %s in a pile of soil below you.",
1120 already_seen ? "There is" : "You discover",
1121 trap->madeby_u ? "the trigger of your mine" :
1123 if (already_seen && rn2(3)) break;
1124 pline("KAABLAMM!!! %s %s%s off!",
1125 forcebungle ? "Your inept attempt sets" :
1126 "The air currents set",
1127 already_seen ? a_your[trap->madeby_u] : "",
1128 already_seen ? " land mine" : "it");
1131 /* prevent landmine from killing steed, throwing you to
1132 * the ground, and you being affected again by the same
1133 * mine because it hasn't been deleted yet
1135 static boolean recursive_mine = FALSE;
1137 if (recursive_mine) break;
1140 pline("KAABLAMM!!! You triggered %s land mine!",
1141 a_your[trap->madeby_u]);
1143 if (u.usteed) steed_mid = u.usteed->m_id;
1144 recursive_mine = TRUE;
1145 (void) steedintrap(trap, (struct obj *)0);
1146 recursive_mine = FALSE;
1147 saddle = sobj_at(SADDLE,u.ux, u.uy);
1149 set_wounded_legs(LEFT_SIDE, rn1(35, 41));
1150 set_wounded_legs(RIGHT_SIDE, rn1(35, 41));
1151 exercise(A_DEX, FALSE);
1153 blow_up_landmine(trap);
1155 if (steed_mid && saddle && !u.usteed)
1156 (void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle);
1158 newsym(u.ux,u.uy); /* update trap symbol */
1159 losehp(rnd(16), "land mine", KILLED_BY_AN);
1160 /* fall recursively into the pit... */
1161 if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP);
1162 fill_pit(u.ux, u.uy);
1165 case ROLLING_BOULDER_TRAP: {
1166 int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0);
1169 pline("Click! You trigger a rolling boulder trap!");
1170 if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y,
1171 trap->launch2.x, trap->launch2.y, style)) {
1173 newsym(u.ux,u.uy); /* get rid of trap symbol */
1174 pline("Fortunately for you, no boulder was released.");
1180 domagicportal(trap);
1185 impossible("You hit a trap of type %u", trap->ttyp);
1191 steedintrap(trap, otmp)
1195 struct monst *mtmp = u.usteed;
1196 struct permonst *mptr;
1199 boolean trapkilled = FALSE;
1200 boolean steedhit = FALSE;
1202 if (!u.usteed || !trap) return 0;
1212 impossible("steed hit by non-existant arrow?");
1215 if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1220 impossible("steed hit by non-existant dart?");
1223 if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1227 if (!resists_sleep(mtmp) && !breathless(mptr) &&
1228 !mtmp->msleeping && mtmp->mcanmove) {
1230 mtmp->mfrozen = rnd(25);
1232 pline("%s suddenly falls asleep!",
1239 if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
1245 if (mtmp->mhp <= 0 ||
1246 thitm(0, mtmp, (struct obj *)0,
1247 rnd((tt == PIT) ? 6 : 10), FALSE))
1252 if (!resists_magm(mtmp)) {
1253 if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
1254 (void) newcham(mtmp, (struct permonst *)0,
1256 if (!can_saddle(mtmp) || !can_ride(mtmp)) {
1257 dismount_steed(DISMOUNT_POLY);
1259 You("have to adjust yourself in the saddle on %s.",
1261 mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_A,
1262 (char *)0, SUPPRESS_SADDLE, FALSE));
1273 dismount_steed(DISMOUNT_POLY);
1276 else if(steedhit) return 1;
1281 /* some actions common to both player and monsters for triggered landmine */
1283 blow_up_landmine(trap)
1286 (void)scatter(trap->tx, trap->ty, 4,
1287 MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS,
1289 del_engr_at(trap->tx, trap->ty);
1290 wake_nearto(trap->tx, trap->ty, 400);
1291 if (IS_DOOR(levl[trap->tx][trap->ty].typ))
1292 levl[trap->tx][trap->ty].doormask = D_BROKEN;
1293 /* TODO: destroy drawbridge if present */
1294 /* caller may subsequently fill pit, e.g. with a boulder */
1295 trap->ttyp = PIT; /* explosion creates a pit */
1296 trap->madeby_u = FALSE; /* resulting pit isn't yours */
1297 seetrap(trap); /* and it isn't concealed */
1304 * Move obj from (x1,y1) to (x2,y2)
1306 * Return 0 if no object was launched.
1307 * 1 if an object was launched and placed somewhere.
1308 * 2 if an object was launched, but used up.
1311 launch_obj(otyp, x1, y1, x2, y2, style)
1313 register int x1,y1,x2,y2;
1316 register struct monst *mtmp;
1317 register struct obj *otmp, *otmp2;
1319 struct obj *singleobj;
1320 boolean used_up = FALSE;
1321 boolean otherside = FALSE;
1326 otmp = sobj_at(otyp, x1, y1);
1327 /* Try the other side too, for rolling boulder traps */
1328 if (!otmp && otyp == BOULDER) {
1330 otmp = sobj_at(otyp, x2, y2);
1332 if (!otmp) return 0;
1333 if (otherside) { /* swap 'em */
1341 if (otmp->quan == 1L) {
1342 obj_extract_self(otmp);
1344 otmp = (struct obj *) 0;
1346 singleobj = splitobj(otmp, 1L);
1347 obj_extract_self(singleobj);
1350 /* in case you're using a pick-axe to chop the boulder that's being
1351 launched (perhaps a monster triggered it), destroy context so that
1352 next dig attempt never thinks you're resuming previous effort */
1353 if ((otyp == BOULDER || otyp == STATUE) &&
1354 singleobj->ox == digging.pos.x && singleobj->oy == digging.pos.y)
1355 (void) memset((genericptr_t)&digging, 0, sizeof digging);
1357 dist = distmin(x1,y1,x2,y2);
1363 case ROLL|LAUNCH_UNSEEN:
1364 if (otyp == BOULDER) {
1365 You_hear(Hallucination ?
1366 "someone bowling." :
1367 "rumbling in the distance.");
1369 style &= ~LAUNCH_UNSEEN;
1371 case ROLL|LAUNCH_KNOWN:
1372 /* use otrapped as a flag to ohitmon */
1373 singleobj->otrapped = 1;
1374 style &= ~LAUNCH_KNOWN;
1381 if (!delaycnt) delaycnt = 1;
1382 if (!cansee(bhitpos.x,bhitpos.y)) curs_on_u();
1383 tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
1384 tmp_at(bhitpos.x, bhitpos.y);
1387 /* Set the object in motion */
1388 while(dist-- > 0 && !used_up) {
1390 tmp_at(bhitpos.x, bhitpos.y);
1393 /* dstage@u.washington.edu -- Delay only if hero sees it */
1394 if (cansee(bhitpos.x, bhitpos.y))
1395 while (tmp-- > 0) delay_output();
1399 t = t_at(bhitpos.x, bhitpos.y);
1401 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
1402 if (otyp == BOULDER && throws_rocks(mtmp->data)) {
1404 pline("%s snatches the boulder.",
1406 singleobj->otrapped = 0;
1407 (void) mpickobj(mtmp, singleobj);
1412 if (ohitmon(mtmp,singleobj,
1413 (style==ROLL) ? -1 : dist, FALSE)) {
1417 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
1418 if (multi) nomul(0);
1419 if (thitu(9 + singleobj->spe,
1420 dmgval(singleobj, &youmonst),
1421 singleobj, (char *)0))
1424 if (style == ROLL) {
1425 if (down_gate(bhitpos.x, bhitpos.y) != -1) {
1426 if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){
1431 if (t && otyp == BOULDER) {
1437 cansee(bhitpos.x, bhitpos.y) ?
1438 " The rolling boulder triggers a land mine." : "");
1440 del_engr_at(bhitpos.x,bhitpos.y);
1441 place_object(singleobj, bhitpos.x, bhitpos.y);
1442 singleobj->otrapped = 0;
1443 fracture_rock(singleobj);
1444 (void)scatter(bhitpos.x,bhitpos.y, 4,
1445 MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS,
1447 if (cansee(bhitpos.x,bhitpos.y))
1448 newsym(bhitpos.x,bhitpos.y);
1454 if (cansee(bhitpos.x, bhitpos.y))
1455 pline("Suddenly the rolling boulder disappears!");
1457 You_hear("a rumbling stop abruptly.");
1458 singleobj->otrapped = 0;
1459 if (t->ttyp == TELEP_TRAP)
1462 int newlev = random_teleport_level();
1465 if (newlev == depth(&u.uz) || In_endgame(&u.uz))
1467 add_to_migration(singleobj);
1468 get_level(&dest, newlev);
1469 singleobj->ox = dest.dnum;
1470 singleobj->oy = dest.dlevel;
1471 singleobj->owornmask = (long)MIGR_RANDOM;
1480 /* the boulder won't be used up if there is a
1481 monster in the trap; stop rolling anyway */
1482 x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */
1483 if (flooreffects(singleobj, x2, y2, "fall"))
1485 dist = -1; /* stop rolling immediately */
1488 if (used_up || dist == -1) break;
1490 if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) {
1494 if (otyp == BOULDER &&
1495 (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) {
1497 " as one boulder sets another in motion";
1499 if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist ||
1500 IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ))
1501 bmsg = " as one boulder hits another";
1503 You_hear("a loud crash%s!",
1504 cansee(bhitpos.x, bhitpos.y) ? bmsg : "");
1505 obj_extract_self(otmp2);
1506 /* pass off the otrapped flag to the next boulder */
1507 otmp2->otrapped = singleobj->otrapped;
1508 singleobj->otrapped = 0;
1509 place_object(singleobj, bhitpos.x, bhitpos.y);
1511 otmp2 = (struct obj *)0;
1512 wake_nearto(bhitpos.x, bhitpos.y, 10*10);
1515 if (otyp == BOULDER && closed_door(bhitpos.x,bhitpos.y)) {
1516 if (cansee(bhitpos.x, bhitpos.y))
1517 pline_The("boulder crashes through a door.");
1518 levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN;
1519 if (dist) unblock_point(bhitpos.x, bhitpos.y);
1522 /* if about to hit iron bars, do so now */
1523 if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) &&
1524 levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) {
1525 x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */
1526 if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) {
1527 if (!singleobj) used_up = TRUE;
1532 tmp_at(DISP_END, 0);
1534 singleobj->otrapped = 0;
1535 place_object(singleobj, x2,y2);
1547 register struct trap *trap;
1551 newsym(trap->tx, trap->ty);
1559 mkroll_launch(ttmp, x, y, otyp, ocount)
1572 boolean success = FALSE;
1575 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2;
1576 distance = rn1(5,4); /* 4..8 away */
1577 tmp = rn2(8); /* randomly pick a direction to try first */
1578 while (distance >= mindist) {
1582 /* Prevent boulder from being placed on water */
1583 if (ttmp->ttyp == ROLLING_BOULDER_TRAP
1584 && is_pool(x+distance*dx,y+distance*dy))
1586 else success = isclearpath(&cc, distance, dx, dy);
1587 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
1588 boolean success_otherway;
1589 bcc.x = x; bcc.y = y;
1590 success_otherway = isclearpath(&bcc, distance,
1592 if (!success_otherway) success = FALSE;
1595 if (++tmp > 7) tmp = 0;
1596 if ((++trycount % 8) == 0) --distance;
1599 /* create the trap without any ammo, launch pt at trap location */
1603 otmp = mksobj(otyp, TRUE, FALSE);
1604 otmp->quan = ocount;
1605 otmp->owt = weight(otmp);
1606 place_object(otmp, cc.x, cc.y);
1609 ttmp->launch.x = cc.x;
1610 ttmp->launch.y = cc.y;
1611 if (ttmp->ttyp == ROLLING_BOULDER_TRAP) {
1612 ttmp->launch2.x = bcc.x;
1613 ttmp->launch2.y = bcc.y;
1615 ttmp->launch_otyp = otyp;
1616 newsym(ttmp->launch.x, ttmp->launch.y);
1621 isclearpath(cc,distance,dx,dy)
1631 while (distance-- > 0) {
1634 typ = levl[x][y].typ;
1635 if (!isok(x,y) || !ZAP_POS(typ) || closed_door(x,y))
1647 register struct monst *mtmp;
1649 register struct trap *trap = t_at(mtmp->mx, mtmp->my);
1650 boolean trapkilled = FALSE;
1651 struct permonst *mptr = mtmp->data;
1655 mtmp->mtrapped = 0; /* perhaps teleported? */
1656 } else if (mtmp->mtrapped) { /* is currently in the trap */
1658 cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) &&
1659 (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP ||
1660 trap->ttyp == HOLE || trap->ttyp == PIT ||
1661 trap->ttyp == WEB)) {
1662 /* If you come upon an obviously trapped monster, then
1663 * you must be able to see the trap it's in too.
1669 if (sobj_at(BOULDER, mtmp->mx, mtmp->my) &&
1670 (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) {
1673 if (canseemon(mtmp))
1674 pline("%s pulls free...", Monnam(mtmp));
1675 fill_pit(mtmp->mx, mtmp->my);
1680 } else if (metallivorous(mptr)) {
1681 if (trap->ttyp == BEAR_TRAP) {
1682 if (canseemon(mtmp))
1683 pline("%s eats a bear trap!", Monnam(mtmp));
1687 } else if (trap->ttyp == SPIKED_PIT) {
1688 if (canseemon(mtmp))
1689 pline("%s munches on some spikes!", Monnam(mtmp));
1695 register int tt = trap->ttyp;
1696 boolean in_sight, tear_web, see_it,
1697 inescapable = ((tt == HOLE || tt == PIT) &&
1698 In_sokoban(&u.uz) && !trap->madeby_u);
1699 const char *fallverb;
1702 /* true when called from dotrap, inescapable is not an option */
1703 if (mtmp == u.usteed) inescapable = TRUE;
1706 ((mtmp->mtrapseen & (1 << (tt-1))) != 0 ||
1707 (tt == HOLE && !mindless(mtmp->data)))) {
1708 /* it has been in such a trap - perhaps it escapes */
1709 if(rn2(4)) return(0);
1711 mtmp->mtrapseen |= (1 << (tt-1));
1713 /* Monster is aggravated by being trapped by you.
1714 Recognizing who made the trap isn't completely
1715 unreasonable; everybody has their own style. */
1716 if (trap->madeby_u && rnl(5)) setmangry(mtmp);
1718 in_sight = canseemon(mtmp);
1719 see_it = cansee(mtmp->mx, mtmp->my);
1721 /* assume hero can tell what's going on for the steed */
1722 if (mtmp == u.usteed) in_sight = TRUE;
1726 if (trap->once && trap->tseen && !rn2(15)) {
1727 if (in_sight && see_it)
1728 pline("%s triggers a trap but nothing happens.",
1731 newsym(mtmp->mx, mtmp->my);
1735 otmp = mksobj(ARROW, TRUE, FALSE);
1737 otmp->owt = weight(otmp);
1738 otmp->opoisoned = 0;
1739 if (in_sight) seetrap(trap);
1740 if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1743 if (trap->once && trap->tseen && !rn2(15)) {
1744 if (in_sight && see_it)
1745 pline("%s triggers a trap but nothing happens.",
1748 newsym(mtmp->mx, mtmp->my);
1752 otmp = mksobj(DART, TRUE, FALSE);
1754 otmp->owt = weight(otmp);
1755 if (!rn2(6)) otmp->opoisoned = 1;
1756 if (in_sight) seetrap(trap);
1757 if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE;
1760 if (trap->once && trap->tseen && !rn2(15)) {
1761 if (in_sight && see_it)
1762 pline("A trap door above %s opens, but nothing falls out!",
1765 newsym(mtmp->mx, mtmp->my);
1769 otmp = mksobj(ROCK, TRUE, FALSE);
1771 otmp->owt = weight(otmp);
1772 if (in_sight) seetrap(trap);
1773 if (thitm(0, mtmp, otmp, d(2, 6), FALSE))
1778 if(is_flyer(mptr)) break;
1779 /* stepped on a squeaky board */
1781 pline("A board beneath %s squeaks loudly.", mon_nam(mtmp));
1784 You_hear("a distant squeak.");
1785 /* wake up nearby monsters */
1786 wake_nearto(mtmp->mx, mtmp->my, 40);
1790 if(mptr->msize > MZ_SMALL &&
1791 !amorphous(mptr) && !is_flyer(mptr) &&
1792 !is_whirly(mptr) && !unsolid(mptr)) {
1795 pline("%s is caught in %s bear trap!",
1796 Monnam(mtmp), a_your[trap->madeby_u]);
1799 if((mptr == &mons[PM_OWLBEAR]
1800 || mptr == &mons[PM_BUGBEAR])
1802 You_hear("the roaring of an angry bear!");
1808 if (!resists_sleep(mtmp) && !breathless(mptr) &&
1809 !mtmp->msleeping && mtmp->mcanmove) {
1811 mtmp->mfrozen = rnd(25);
1813 pline("%s suddenly falls asleep!",
1829 pline("%s %s on the %s!", A_gush_of_water_hits,
1830 mon_nam(mtmp), mbodypart(mtmp, HEAD));
1831 target = which_armor(mtmp, W_ARMH);
1832 (void) rust_dmg(target, "helmet", 1, TRUE, mtmp);
1836 pline("%s %s's left %s!", A_gush_of_water_hits,
1837 mon_nam(mtmp), mbodypart(mtmp, ARM));
1838 target = which_armor(mtmp, W_ARMS);
1839 if (rust_dmg(target, "shield", 1, TRUE, mtmp))
1841 target = MON_WEP(mtmp);
1842 if (target && bimanual(target))
1843 erode_obj(target, FALSE, TRUE);
1844 glovecheck: target = which_armor(mtmp, W_ARMG);
1845 (void) rust_dmg(target, "gauntlets", 1, TRUE, mtmp);
1849 pline("%s %s's right %s!", A_gush_of_water_hits,
1850 mon_nam(mtmp), mbodypart(mtmp, ARM));
1851 erode_obj(MON_WEP(mtmp), FALSE, TRUE);
1855 pline("%s %s!", A_gush_of_water_hits,
1857 for (otmp=mtmp->minvent; otmp; otmp = otmp->nobj)
1858 (void) snuff_lit(otmp);
1859 target = which_armor(mtmp, W_ARMC);
1861 (void) rust_dmg(target, cloak_simple_name(target),
1864 target = which_armor(mtmp, W_ARM);
1866 (void) rust_dmg(target, "armor", 1, TRUE, mtmp);
1869 target = which_armor(mtmp, W_ARMU);
1870 (void) rust_dmg(target, "shirt", 1, TRUE, mtmp);
1875 if (mptr == &mons[PM_IRON_GOLEM]) {
1877 pline("%s falls to pieces!", Monnam(mtmp));
1878 else if(mtmp->mtame)
1879 pline("May %s rust in peace.",
1884 } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) {
1885 (void)split_mon(mtmp, (struct monst *)0);
1892 pline("A %s erupts from the %s under %s!",
1894 surface(mtmp->mx,mtmp->my), mon_nam(mtmp));
1895 else if (see_it) /* evidently `mtmp' is invisible */
1896 You("see a %s erupt from the %s!",
1897 tower_of_flame, surface(mtmp->mx,mtmp->my));
1899 if (resists_fire(mtmp)) {
1901 shieldeff(mtmp->mx,mtmp->my);
1902 pline("%s is uninjured.", Monnam(mtmp));
1905 int num = d(2,4), alt;
1906 boolean immolate = FALSE;
1908 /* paper burns very fast, assume straw is tightly
1909 * packed and burns a bit slower */
1910 switch (monsndx(mtmp->data)) {
1911 case PM_PAPER_GOLEM: immolate = TRUE;
1912 alt = mtmp->mhpmax; break;
1913 case PM_STRAW_GOLEM: alt = mtmp->mhpmax / 2; break;
1914 case PM_WOOD_GOLEM: alt = mtmp->mhpmax / 4; break;
1915 case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break;
1916 default: alt = 0; break;
1918 if (alt > num) num = alt;
1920 if (thitm(0, mtmp, (struct obj *)0, num, immolate))
1923 /* we know mhp is at least `num' below mhpmax,
1924 so no (mhp > mhpmax) check is needed here */
1925 mtmp->mhpmax -= rn2(num + 1);
1927 if (burnarmor(mtmp) || rn2(3)) {
1928 (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
1929 (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
1930 (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
1932 if (burn_floor_paper(mtmp->mx, mtmp->my, see_it, FALSE) &&
1933 !see_it && distu(mtmp->mx, mtmp->my) <= 3*3)
1934 You("smell smoke.");
1935 if (is_ice(mtmp->mx,mtmp->my))
1936 melt_ice(mtmp->mx,mtmp->my);
1937 if (see_it) seetrap(trap);
1943 if (is_flyer(mptr) || is_floater(mptr) ||
1944 (mtmp->wormno && count_wsegs(mtmp) > 5) ||
1946 if (!inescapable) break; /* avoids trap */
1947 fallverb = "is dragged"; /* sokoban pit */
1949 if (!passes_walls(mptr))
1952 pline("%s %s into %s pit!",
1953 Monnam(mtmp), fallverb,
1954 a_your[trap->madeby_u]);
1955 if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND])
1956 pline("How pitiful. Isn't that the pits?");
1959 mselftouch(mtmp, "Falling, ", FALSE);
1960 if (mtmp->mhp <= 0 ||
1961 thitm(0, mtmp, (struct obj *)0,
1962 rnd((tt == PIT) ? 6 : 10), FALSE))
1967 if (!Can_fall_thru(&u.uz)) {
1968 impossible("mintrap: %ss cannot exist on this level.",
1969 defsyms[trap_to_defsym(tt)].explanation);
1970 break; /* don't activate it after all */
1972 if (is_flyer(mptr) || is_floater(mptr) ||
1973 mptr == &mons[PM_WUMPUS] ||
1974 (mtmp->wormno && count_wsegs(mtmp) > 5) ||
1975 mptr->msize >= MZ_HUGE) {
1976 if (inescapable) { /* sokoban hole */
1978 pline("%s seems to be yanked down!",
1980 /* suppress message in mlevel_tele_trap() */
1992 mlev_res = mlevel_tele_trap(mtmp, trap,
1993 inescapable, in_sight);
1994 if (mlev_res) return(mlev_res);
1999 mtele_trap(mtmp, trap, in_sight);
2003 /* Monster in a web. */
2004 if (webmaker(mptr)) break;
2005 if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)){
2007 mptr == &mons[PM_GELATINOUS_CUBE] ||
2008 mptr == &mons[PM_FIRE_ELEMENTAL]) {
2010 pline("%s %s %s spider web!",
2012 (mptr == &mons[PM_FIRE_ELEMENTAL]) ?
2013 "burns" : "dissolves",
2014 a_your[trap->madeby_u]);
2016 newsym(mtmp->mx, mtmp->my);
2020 pline("%s flows through %s spider web.",
2022 a_your[trap->madeby_u]);
2028 switch (monsndx(mptr)) {
2029 case PM_OWLBEAR: /* Eric Backus */
2032 You_hear("the roaring of a confused bear!");
2038 if (mptr->mlet == S_GIANT ||
2039 (mptr->mlet == S_DRAGON &&
2040 extra_nasty(mptr)) || /* excl. babies */
2041 (mtmp->wormno && count_wsegs(mtmp) > 5)) {
2043 } else if (in_sight) {
2044 pline("%s is caught in %s spider web.",
2046 a_your[trap->madeby_u]);
2049 mtmp->mtrapped = tear_web ? 0 : 1;
2051 /* this list is fairly arbitrary; it deliberately
2052 excludes wumpus & giant/ettin zombies/mummies */
2053 case PM_TITANOTHERE:
2054 case PM_BALUCHITHERIUM:
2055 case PM_PURPLE_WORM:
2066 pline("%s tears through %s spider web!",
2067 Monnam(mtmp), a_your[trap->madeby_u]);
2069 newsym(mtmp->mx, mtmp->my);
2077 /* A magic trap. Monsters usually immune. */
2078 if (!rn2(21)) goto mfiretrap;
2085 break; /* monsters usually don't set it off */
2086 if(is_flyer(mptr)) {
2087 boolean already_seen = trap->tseen;
2088 if (in_sight && !already_seen) {
2089 pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp));
2094 newsym(mtmp->mx, mtmp->my);
2095 pline_The("air currents set %s off!",
2096 already_seen ? "a land mine" : "it");
2098 } else if(in_sight) {
2099 newsym(mtmp->mx, mtmp->my);
2100 pline("KAABLAMM!!! %s triggers %s land mine!",
2101 Monnam(mtmp), a_your[trap->madeby_u]);
2104 pline("Kaablamm! You hear an explosion in the distance!");
2105 blow_up_landmine(trap);
2106 if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE))
2109 /* monsters recursively fall into new pit */
2110 if (mintrap(mtmp) == 2) trapkilled=TRUE;
2112 /* a boulder may fill the new pit, crushing monster */
2113 fill_pit(trap->tx, trap->ty);
2114 if (mtmp->mhp <= 0) trapkilled = TRUE;
2115 if (unconscious()) {
2117 nomovemsg="The explosion awakens you!";
2122 if (resists_magm(mtmp)) {
2123 shieldeff(mtmp->mx, mtmp->my);
2124 } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) {
2125 (void) newcham(mtmp, (struct permonst *)0,
2127 if (in_sight) seetrap(trap);
2131 case ROLLING_BOULDER_TRAP:
2132 if (!is_flyer(mptr)) {
2133 int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN);
2135 newsym(mtmp->mx,mtmp->my);
2137 pline("Click! %s triggers %s.", Monnam(mtmp),
2139 "a rolling boulder trap" :
2141 if (launch_obj(BOULDER, trap->launch.x, trap->launch.y,
2142 trap->launch2.x, trap->launch2.y, style)) {
2143 if (in_sight) trap->tseen = TRUE;
2144 if (mtmp->mhp <= 0) trapkilled = TRUE;
2147 newsym(mtmp->mx,mtmp->my);
2153 impossible("Some monster encountered a strange trap of type %d.", tt);
2156 if(trapkilled) return 2;
2157 return mtmp->mtrapped;
2163 /* Combine cockatrice checks into single functions to avoid repeating code. */
2168 if (Stone_resistance) return;
2169 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2171 You("turn to stone...");
2172 killer_format = KILLED_BY;
2178 minstapetrify(mon,byplayer)
2182 if (resists_ston(mon)) return;
2183 if (poly_when_stoned(mon->data)) {
2188 /* give a "<mon> is slowing down" message and also remove
2189 intrinsic speed (comparable to similar effect on the hero) */
2190 mon_adjust_speed(mon, -3, (struct obj *)0);
2192 if (cansee(mon->mx, mon->my))
2193 pline("%s turns to stone.", Monnam(mon));
2197 } else monstone(mon);
2206 if(uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm])
2207 && !Stone_resistance) {
2208 pline("%s touch the %s corpse.", arg,
2209 mons[uwep->corpsenm].mname);
2210 Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname));
2213 /* Or your secondary weapon, if wielded */
2214 if(u.twoweap && uswapwep && uswapwep->otyp == CORPSE &&
2215 touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance){
2216 pline("%s touch the %s corpse.", arg,
2217 mons[uswapwep->corpsenm].mname);
2218 Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname));
2224 mselftouch(mon,arg,byplayer)
2229 struct obj *mwep = MON_WEP(mon);
2231 if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm])) {
2232 if (cansee(mon->mx, mon->my)) {
2233 pline("%s%s touches the %s corpse.",
2234 arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon),
2235 mons[mwep->corpsenm].mname);
2237 minstapetrify(mon, byplayer);
2245 if(u.utraptype == TT_PIT) {
2247 You("float up, out of the pit!");
2248 vision_full_recalc = 1; /* vision limits change */
2249 fill_pit(u.ux, u.uy);
2250 } else if (u.utraptype == TT_INFLOOR) {
2251 Your("body pulls upward, but your %s are still stuck.",
2252 makeplural(body_part(LEG)));
2254 You("float up, only your %s is still stuck.",
2258 else if(Is_waterlevel(&u.uz))
2259 pline("It feels as though you've lost some weight.");
2263 You(is_animal(u.ustuck->data) ?
2264 "float away from the %s." :
2265 "spiral up into %s.",
2266 is_animal(u.ustuck->data) ?
2267 surface(u.ux, u.uy) :
2269 else if (Hallucination)
2270 pline("Up, up, and awaaaay! You're walking on air!");
2271 else if(Is_airlevel(&u.uz))
2272 You("gain control over your movements.");
2274 You("start to float in the air!");
2276 if (u.usteed && !is_floater(u.usteed->data) &&
2277 !is_flyer(u.usteed->data)) {
2279 pline("%s magically floats up!", Monnam(u.usteed));
2281 You("cannot stay on %s.", mon_nam(u.usteed));
2282 dismount_steed(DISMOUNT_GENERIC);
2296 if ((t = t_at(x, y)) &&
2297 ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) &&
2298 (otmp = sobj_at(BOULDER, x, y))) {
2299 obj_extract_self(otmp);
2300 (void) flooreffects(otmp, x, y, "settle");
2305 float_down(hmask, emask)
2306 long hmask, emask; /* might cancel timeout */
2308 register struct trap *trap = (struct trap *)0;
2309 d_level current_dungeon_level;
2310 boolean no_msg = FALSE;
2312 HLevitation &= ~hmask;
2313 ELevitation &= ~emask;
2314 if(Levitation) return(0); /* maybe another ring/potion/boots */
2316 You("float down, but you are still %s.",
2317 is_animal(u.ustuck->data) ? "swallowed" : "engulfed");
2321 if (Punished && !carried(uball) &&
2322 (is_pool(uball->ox, uball->oy) ||
2323 ((trap = t_at(uball->ox, uball->oy)) &&
2324 ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) ||
2325 (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) {
2330 movobj(uchain, uball->ox, uball->oy);
2331 newsym(u.ux0, u.uy0);
2332 vision_full_recalc = 1; /* in case the hero moved. */
2334 /* check for falling into pool - added by GAN 10/20/86 */
2336 if (!u.uswallow && u.ustuck) {
2337 if (sticks(youmonst.data))
2338 You("aren't able to maintain your hold on %s.",
2341 pline("Startled, %s can no longer hold you!",
2346 * drown() and lava_effects() print various messages almost
2347 * every time they're called which conflict with the "fall
2348 * into" message below. Thus, we want to avoid printing
2349 * confusing, duplicate or out-of-order messages.
2350 * Use knowledge of the two routines as a hack -- this
2351 * should really be handled differently -dlc
2353 if(is_pool(u.ux,u.uy) && !Wwalking && !Swimming && !u.uinwater)
2356 if(is_lava(u.ux,u.uy)) {
2357 (void) lava_effects();
2362 trap = t_at(u.ux,u.uy);
2363 if(Is_airlevel(&u.uz))
2364 You("begin to tumble in place.");
2365 else if (Is_waterlevel(&u.uz) && !no_msg)
2366 You_feel("heavier.");
2367 /* u.uinwater msgs already in spoteffects()/drown() */
2368 else if (!u.uinwater && !no_msg) {
2370 if (!(emask & W_SADDLE))
2373 boolean sokoban_trap = (In_sokoban(&u.uz) && trap);
2375 pline("Bummer! You've %s.",
2376 is_pool(u.ux,u.uy) ?
2377 "splashed down" : sokoban_trap ? "crashed" :
2381 You("float gently to the %s.",
2382 surface(u.ux, u.uy));
2384 /* Justification elsewhere for Sokoban traps
2385 * is based on air currents. This is
2386 * consistent with that.
2387 * The unexpected additional force of the
2388 * air currents once leviation
2389 * ceases knocks you off your feet.
2392 losehp(rnd(2), "dangerous winds", KILLED_BY);
2394 if (u.usteed) dismount_steed(DISMOUNT_FELL);
2396 selftouch("As you fall, you");
2403 /* can't rely on u.uz0 for detecting trap door-induced level change;
2404 it gets changed to reflect the new level before we can check it */
2405 assign_level(¤t_dungeon_level, &u.uz);
2408 switch(trap->ttyp) {
2413 if(!Can_fall_thru(&u.uz) || u.ustuck)
2415 /* fall into next case */
2417 if (!u.utrap) /* not already in the trap */
2421 if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow &&
2422 /* falling through trap door calls goto_level,
2423 and goto_level does its own pickup() call */
2424 on_level(&u.uz, ¤t_dungeon_level))
2431 struct obj *box; /* null for floor trap */
2433 boolean see_it = !Blind;
2436 /* Bug: for box case, the equivalent of burn_floor_paper() ought
2437 * to be done upon its contents.
2440 if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) {
2441 pline("A cascade of steamy bubbles erupts from %s!",
2442 the(box ? xname(box) : surface(u.ux,u.uy)));
2443 if (Fire_resistance) You("are uninjured.");
2444 else losehp(rnd(3), "boiling water", KILLED_BY);
2447 pline("A %s %s from %s!", tower_of_flame,
2448 box ? "bursts" : "erupts",
2449 the(box ? xname(box) : surface(u.ux,u.uy)));
2450 if (Fire_resistance) {
2451 shieldeff(u.ux, u.uy);
2453 } else if (Upolyd) {
2455 switch (u.umonnum) {
2456 case PM_PAPER_GOLEM: alt = u.mhmax; break;
2457 case PM_STRAW_GOLEM: alt = u.mhmax / 2; break;
2458 case PM_WOOD_GOLEM: alt = u.mhmax / 4; break;
2459 case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break;
2460 default: alt = 0; break;
2462 if (alt > num) num = alt;
2463 if (u.mhmax > mons[u.umonnum].mlevel)
2464 u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1;
2467 if (u.uhpmax > u.ulevel)
2468 u.uhpmax -= rn2(min(u.uhpmax,num + 1)), flags.botl = 1;
2471 You("are uninjured.");
2473 losehp(num, tower_of_flame, KILLED_BY_AN);
2476 if (burnarmor(&youmonst) || rn2(3)) {
2477 destroy_item(SCROLL_CLASS, AD_FIRE);
2478 destroy_item(SPBOOK_CLASS, AD_FIRE);
2479 destroy_item(POTION_CLASS, AD_FIRE);
2481 if (!box && burn_floor_paper(u.ux, u.uy, see_it, TRUE) && !see_it)
2482 You("smell paper burning.");
2483 if (is_ice(u.ux, u.uy))
2484 melt_ice(u.ux, u.uy);
2490 register int fate = rnd(20);
2492 /* What happened to the poor sucker? */
2495 /* Most of the time, it creates some monsters. */
2496 register int cnt = rnd(4);
2498 if (!resists_blnd(&youmonst)) {
2499 You("are momentarily blinded by a flash of light!");
2500 make_blinded((long)rn1(5,10),FALSE);
2501 if (!Blind) Your(vision_clears);
2502 } else if (!Blind) {
2503 You("see a flash of light!");
2505 You_hear("a deafening roar!");
2507 (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS);
2514 /* sometimes nothing happens */
2516 case 12: /* a flash of fire */
2517 dofiretrap((struct obj *)0);
2521 case 13: pline("A shiver runs up and down your %s!",
2524 case 14: You_hear(Hallucination ?
2525 "the moon howling at you." :
2526 "distant howling.");
2528 case 15: if (on_level(&u.uz, &qstart_level))
2529 You_feel("%slike the prodigal son.",
2530 (flags.female || (Upolyd && is_neuter(youmonst.data))) ?
2533 You("suddenly yearn for %s.",
2534 Hallucination ? "Cleveland" :
2535 (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ?
2536 "your nearby homeland" :
2537 "your distant homeland");
2539 case 16: Your("pack shakes violently!");
2541 case 17: You(Hallucination ?
2542 "smell hamburgers." :
2543 "smell charred flesh.");
2545 case 18: You_feel("tired.");
2548 /* very occasionally something nice happens. */
2551 /* tame nearby monsters */
2553 register struct monst *mtmp;
2555 (void) adjattrib(A_CHA,1,FALSE);
2556 for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) {
2557 if(!isok(u.ux+i, u.uy+j)) continue;
2558 mtmp = m_at(u.ux+i, u.uy+j);
2560 (void) tamedog(mtmp, (struct obj *)0);
2567 { struct obj pseudo;
2568 long save_conf = HConfusion;
2570 pseudo = zeroobj; /* neither cursed nor blessed */
2571 pseudo.otyp = SCR_REMOVE_CURSE;
2573 (void) seffects(&pseudo);
2574 HConfusion = save_conf;
2582 * Scrolls, spellbooks, potions, and flammable items
2583 * may get affected by the fire.
2585 * Return number of objects destroyed. --ALI
2588 fire_damage(chain, force, here, x, y)
2590 boolean force, here;
2594 struct obj *obj, *otmp, *nobj, *ncobj;
2596 int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */
2599 for (obj = chain; obj; obj = nobj) {
2600 nobj = here ? obj->nexthere : obj->nobj;
2602 /* object might light in a controlled manner */
2606 if (Is_container(obj)) {
2607 switch (obj->otyp) {
2609 continue; /* Immune */
2622 if (!force && (Luck + 5) > rn2(chance))
2624 /* Container is burnt up - dump contents out */
2625 if (in_sight) pline("%s catches fire and burns.", Yname2(obj));
2626 if (Has_contents(obj)) {
2627 if (in_sight) pline("Its contents fall out.");
2628 for (otmp = obj->cobj; otmp; otmp = ncobj) {
2630 obj_extract_self(otmp);
2631 if (!flooreffects(otmp, x, y, ""))
2632 place_object(otmp, x, y);
2637 } else if (!force && (Luck + 5) > rn2(20)) {
2638 /* chance per item of sustaining damage:
2639 * max luck (full moon): 5%
2640 * max luck (elsewhen): 10%
2641 * avg luck (Luck==0): 75%
2642 * awful luck (Luck<-4): 100%
2645 } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
2646 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
2648 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
2649 if (in_sight) pline("Smoke rises from %s.", the(xname(obj)));
2652 dindx = (obj->oclass == SCROLL_CLASS) ? 2 : 3;
2654 pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
2655 destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
2658 } else if (obj->oclass == POTION_CLASS) {
2661 pline("%s %s.", Yname2(obj), (obj->quan > 1) ?
2662 destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]);
2665 } else if (is_flammable(obj) && obj->oeroded < MAX_ERODE &&
2666 !(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
2668 pline("%s %s%s.", Yname2(obj), otense(obj, "burn"),
2669 obj->oeroded+1 == MAX_ERODE ? " completely" :
2670 obj->oeroded ? " further" : "");
2676 if (retval && !in_sight)
2677 You("smell smoke.");
2682 water_damage(obj, force, here)
2683 register struct obj *obj;
2684 register boolean force, here;
2688 /* Scrolls, spellbooks, potions, weapons and
2689 pieces of armor may get affected by the water */
2690 for (; obj; obj = otmp) {
2691 otmp = here ? obj->nexthere : obj->nobj;
2693 (void) snuff_lit(obj);
2695 if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) {
2697 } else if(obj->greased) {
2698 if (force || !rn2(2)) obj->greased = 0;
2699 } else if(Is_container(obj) && !Is_box(obj) &&
2700 (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) {
2701 water_damage(obj->cobj, force, FALSE);
2702 } else if (!force && (Luck + 5) > rn2(20)) {
2703 /* chance per item of sustaining damage:
2704 * max luck (full moon): 5%
2705 * max luck (elsewhen): 10%
2706 * avg luck (Luck==0): 75%
2707 * awful luck (Luck<-4): 100%
2710 } else if (obj->oclass == SCROLL_CLASS) {
2712 if (obj->otyp != SCR_MAIL)
2715 obj->otyp = SCR_BLANK_PAPER;
2718 } else if (obj->oclass == SPBOOK_CLASS) {
2719 if (obj->otyp == SPE_BOOK_OF_THE_DEAD)
2720 pline("Steam rises from %s.", the(xname(obj)));
2721 else obj->otyp = SPE_BLANK_PAPER;
2722 } else if (obj->oclass == POTION_CLASS) {
2723 if (obj->otyp == POT_ACID) {
2724 /* damage player/monster? */
2725 pline("A potion explodes!");
2728 } else if (obj->odiluted) {
2729 obj->otyp = POT_WATER;
2730 obj->blessed = obj->cursed = 0;
2732 } else if (obj->otyp != POT_WATER)
2734 } else if (is_rustprone(obj) && obj->oeroded < MAX_ERODE &&
2735 !(obj->oerodeproof || (obj->blessed && !rnl(4)))) {
2736 /* all metal stuff and armor except (body armor
2737 protected by oilskin cloak) */
2738 if(obj->oclass != ARMOR_CLASS || obj != uarm ||
2739 !uarmc || uarmc->otyp != OILSKIN_CLOAK ||
2740 (uarmc->cursed && !rn2(3)))
2747 * This function is potentially expensive - rolling
2748 * inventory list multiple times. Luckily it's seldom needed.
2749 * Returns TRUE if disrobing made player unencumbered enough to
2750 * crawl out of the current predicament.
2753 emergency_disrobe(lostsome)
2756 int invc = inv_cnt();
2758 while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) {
2759 register struct obj *obj, *otmp = (struct obj *)0;
2762 /* Pick a random object */
2765 for (obj = invent; obj; obj = obj->nobj) {
2767 * Undroppables are: body armor, boots, gloves,
2768 * amulets, and rings because of the time and effort
2769 * in removing them + loadstone and other cursed stuff
2770 * for obvious reasons.
2772 if (!((obj->otyp == LOADSTONE && obj->cursed) ||
2773 obj == uamul || obj == uleft || obj == uright ||
2774 obj == ublindf || obj == uarm || obj == uarmc ||
2775 obj == uarmg || obj == uarmf ||
2779 (obj->cursed && (obj == uarmh || obj == uarms)) ||
2782 /* reached the mark and found some stuff to drop? */
2783 if (--i < 0 && otmp) break;
2790 /* Nothing available left to drop; try gold */
2792 pline("In desperation, you drop your purse.");
2793 /* Hack: gold is not in the inventory, so make a gold object
2794 * and put it at the head of the inventory list.
2796 obj = mkgoldobj(u.ugold); /* removes from u.ugold */
2798 u.ugold = obj->quan; /* put the gold back */
2799 assigninvlet(obj); /* might end up as NOINVSYM */
2804 continue; /* Try again */
2806 /* We can't even drop gold! */
2810 if (!otmp) return (FALSE); /* nothing to drop! */
2812 if (otmp->owornmask) remove_worn_item(otmp, FALSE);
2821 * return(TRUE) == player relocated
2826 boolean inpool_ok = FALSE, crawl_ok;
2829 /* happily wading in the same contiguous pool */
2830 if (u.uinwater && is_pool(u.ux-u.dx,u.uy-u.dy) &&
2831 (Swimming || Amphibious)) {
2832 /* water effects on objects every now and then */
2833 if (!rn2(5)) inpool_ok = TRUE;
2838 You("%s into the water%c",
2839 Is_waterlevel(&u.uz) ? "plunge" : "fall",
2840 Amphibious || Swimming ? '.' : '!');
2841 if (!Swimming && !Is_waterlevel(&u.uz))
2842 You("sink like %s.",
2843 Hallucination ? "the Titanic" : "a rock");
2846 water_damage(invent, FALSE, FALSE);
2848 if (u.umonnum == PM_GREMLIN && rn2(3))
2849 (void)split_mon(&youmonst, (struct monst *)0);
2850 else if (u.umonnum == PM_IRON_GOLEM) {
2853 if (u.mhmax > i) u.mhmax -= i;
2854 losehp(i, "rusting away", KILLED_BY);
2856 if (inpool_ok) return(FALSE);
2858 if ((i = number_leashed()) > 0) {
2859 pline_The("leash%s slip%s loose.",
2860 (i > 1) ? "es" : "",
2861 (i > 1) ? "" : "s");
2865 if (Amphibious || Swimming) {
2868 pline("But you aren't drowning.");
2869 if (!Is_waterlevel(&u.uz)) {
2871 Your("keel hits the bottom.");
2873 You("touch bottom.");
2880 vision_recalc(2); /* unsee old position */
2883 vision_full_recalc = 1;
2886 if ((Teleportation || can_teleport(youmonst.data)) &&
2887 !u.usleep && (Teleport_control || rn2(3) < Luck+2)) {
2888 You("attempt a teleport spell."); /* utcsri!carroll */
2889 if (!level.flags.noteleport) {
2891 if(!is_pool(u.ux,u.uy))
2893 } else pline_The("attempted teleport spell fails.");
2897 dismount_steed(DISMOUNT_GENERIC);
2898 if(!is_pool(u.ux,u.uy))
2903 x = y = 0; /* lint suppression */
2904 /* if sleeping, wake up now so that we don't crawl out of water
2905 while still asleep; we can't do that the same way that waking
2906 due to combat is handled; note unmul() clears u.usleep */
2907 if (u.usleep) unmul("Suddenly you wake up!");
2908 /* can't crawl if unable to move (crawl_ok flag stays false) */
2909 if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl;
2910 /* look around for a place to crawl to */
2911 for (i = 0; i < 100; i++) {
2912 x = rn1(3,u.ux - 1);
2913 y = rn1(3,u.uy - 1);
2914 if (goodpos(x, y, &youmonst, 0)) {
2920 for (x = u.ux - 1; x <= u.ux + 1; x++)
2921 for (y = u.uy - 1; y <= u.uy + 1; y++)
2922 if (goodpos(x, y, &youmonst, 0)) {
2928 boolean lost = FALSE;
2929 /* time to do some strip-tease... */
2930 boolean succ = Is_waterlevel(&u.uz) ? TRUE :
2931 emergency_disrobe(&lost);
2933 You("try to crawl out of the water.");
2935 You("dump some of your gear to lose weight...");
2937 pline("Pheew! That was close.");
2941 /* still too much weight */
2942 pline("But in vain.");
2946 killer_format = KILLED_BY_AN;
2947 killer = (levl[u.ux][u.uy].typ == POOL || Is_medusa_level(&u.uz)) ?
2948 "pool of water" : "moat";
2950 /* oops, we're still alive. better get out of the water. */
2951 while (!safe_teleds(TRUE)) {
2952 pline("You're still drowning.");
2957 You("find yourself back %s.", Is_waterlevel(&u.uz) ?
2958 "in an air bubble" : "on land");
2967 if (!u.uenmax) return;
2968 You_feel("your magical energy drain away!");
2972 if(u.uenmax < 0) u.uenmax = 0;
2979 dountrap() /* disarm a trap */
2981 if (near_capacity() >= HVY_ENCUMBER) {
2982 pline("You're too strained to do that.");
2985 if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) {
2986 pline("And just how do you expect to do that?");
2988 } else if (u.ustuck && sticks(youmonst.data)) {
2989 pline("You'll have to let go of %s first.", mon_nam(u.ustuck));
2992 if (u.ustuck || (welded(uwep) && bimanual(uwep))) {
2993 Your("%s seem to be too busy for that.",
2994 makeplural(body_part(HAND)));
2997 return untrap(FALSE);
3002 /* Probability of disabling a trap. Helge Hafting */
3009 /* Only spiders know how to deal with webs reliably */
3010 if (ttmp->ttyp == WEB && !webmaker(youmonst.data))
3012 if (Confusion || Hallucination) chance++;
3013 if (Blind) chance++;
3014 if (Stunned) chance += 2;
3015 if (Fumbling) chance *= 2;
3016 /* Your own traps are better known than others. */
3017 if (ttmp && ttmp->madeby_u) chance--;
3018 if (Role_if(PM_ROGUE)) {
3019 if (rn2(2 * MAXULEV) < u.ulevel) chance--;
3020 if (u.uhave.questart && chance > 1) chance--;
3021 } else if (Role_if(PM_RANGER) && chance > 1) chance--;
3025 /* Replace trap with object(s). Helge Hafting */
3027 cnv_trap_obj(otyp, cnt, ttmp)
3032 struct obj *otmp = mksobj(otyp, TRUE, FALSE);
3034 otmp->owt = weight(otmp);
3035 /* Only dart traps are capable of being poisonous */
3037 otmp->opoisoned = 0;
3038 place_object(otmp, ttmp->tx, ttmp->ty);
3039 /* Sell your own traps only... */
3040 if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty);
3042 newsym(ttmp->tx, ttmp->ty);
3046 /* while attempting to disarm an adjacent trap, we've fallen into it */
3048 move_into_trap(ttmp)
3052 xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy;
3055 /* we know there's no monster in the way, and we're not trapped */
3056 if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused,
3058 u.ux0 = u.ux, u.uy0 = u.uy;
3061 newsym(u.ux0, u.uy0);
3063 check_leash(u.ux0, u.uy0);
3064 if (Punished) move_bc(0, bc, bx, by, cx, cy);
3065 spoteffects(FALSE); /* dotrap() */
3066 exercise(A_WIS, FALSE);
3070 /* 0: doesn't even try
3071 * 1: tries and fails
3075 try_disarm(ttmp, force_failure)
3077 boolean force_failure;
3079 struct monst *mtmp = m_at(ttmp->tx,ttmp->ty);
3080 int ttype = ttmp->ttyp;
3081 boolean under_u = (!u.dx && !u.dy);
3082 boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB);
3084 /* Test for monster first, monsters are displayed instead of trap. */
3085 if (mtmp && (!mtmp->mtrapped || !holdingtrap)) {
3086 pline("%s is in the way.", Monnam(mtmp));
3089 /* We might be forced to move onto the trap's location. */
3090 if (sobj_at(BOULDER, ttmp->tx, ttmp->ty)
3091 && !Passes_walls && !under_u) {
3092 There("is a boulder in your way.");
3095 /* duplicate tight-space checks from test_move */
3097 bad_rock(youmonst.data,u.ux,ttmp->ty) &&
3098 bad_rock(youmonst.data,ttmp->tx,u.uy)) {
3099 if ((invent && (inv_weight() + weight_cap() > 600)) ||
3100 bigmonst(youmonst.data)) {
3101 /* don't allow untrap if they can't get thru to it */
3102 You("are unable to reach the %s!",
3103 defsyms[trap_to_defsym(ttype)].explanation);
3107 /* untrappable traps are located on the ground. */
3108 if (!can_reach_floor()) {
3110 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
3111 You("aren't skilled enough to reach from %s.",
3115 You("are unable to reach the %s!",
3116 defsyms[trap_to_defsym(ttype)].explanation);
3120 /* Will our hero succeed? */
3121 if (force_failure || untrap_prob(ttmp)) {
3124 if (mtmp) { /* must be a trap that holds monsters */
3125 if (ttype == BEAR_TRAP) {
3126 if (mtmp->mtame) abuse_dog(mtmp);
3127 if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp);
3128 } else if (ttype == WEB) {
3129 if (!webmaker(youmonst.data)) {
3130 struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB);
3132 pline_The("webbing sticks to you. You're caught too!");
3133 dotrap(ttmp2, NOWEBMSG);
3135 if (u.usteed && u.utrap) {
3136 /* you, not steed, are trapped */
3137 dismount_steed(DISMOUNT_FELL);
3142 pline("%s remains entangled.", Monnam(mtmp));
3144 } else if (under_u) {
3147 move_into_trap(ttmp);
3150 pline("%s %s is difficult to %s.",
3151 ttmp->madeby_u ? "Your" : under_u ? "This" : "That",
3152 defsyms[trap_to_defsym(ttype)].explanation,
3153 (ttype == WEB) ? "remove" : "disarm");
3161 reward_untrap(ttmp, mtmp)
3165 if (!ttmp->madeby_u) {
3166 if (rnl(10) < 8 && !mtmp->mpeaceful &&
3167 !mtmp->msleeping && !mtmp->mfrozen &&
3168 !mindless(mtmp->data) &&
3169 mtmp->data->mlet != S_HUMAN) {
3170 mtmp->mpeaceful = 1;
3171 set_malign(mtmp); /* reset alignment */
3172 pline("%s is grateful.", Monnam(mtmp));
3174 /* Helping someone out of a trap is a nice thing to do,
3175 * A lawful may be rewarded, but not too often. */
3176 if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) {
3178 You_feel("that you did the right thing.");
3184 disarm_holdingtrap(ttmp) /* Helge Hafting */
3188 int fails = try_disarm(ttmp, FALSE);
3190 if (fails < 2) return fails;
3192 /* ok, disarm it. */
3194 /* untrap the monster, if any.
3195 There's no need for a cockatrice test, only the trap is touched */
3196 if ((mtmp = m_at(ttmp->tx,ttmp->ty)) != 0) {
3198 You("remove %s %s from %s.", the_your[ttmp->madeby_u],
3199 (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing",
3201 reward_untrap(ttmp, mtmp);
3203 if (ttmp->ttyp == BEAR_TRAP) {
3204 You("disarm %s bear trap.", the_your[ttmp->madeby_u]);
3205 cnv_trap_obj(BEARTRAP, 1, ttmp);
3206 } else /* if (ttmp->ttyp == WEB) */ {
3207 You("succeed in removing %s web.", the_your[ttmp->madeby_u]);
3211 newsym(u.ux + u.dx, u.uy + u.dy);
3216 disarm_landmine(ttmp) /* Helge Hafting */
3219 int fails = try_disarm(ttmp, FALSE);
3221 if (fails < 2) return fails;
3222 You("disarm %s land mine.", the_your[ttmp->madeby_u]);
3223 cnv_trap_obj(LAND_MINE, 1, ttmp);
3227 /* getobj will filter down to cans of grease and known potions of oil */
3228 static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 };
3230 /* it may not make much sense to use grease on floor boards, but so what? */
3232 disarm_squeaky_board(ttmp)
3239 obj = getobj(oil, "untrap with");
3242 bad_tool = (obj->cursed ||
3243 ((obj->otyp != POT_OIL || obj->lamplit) &&
3244 (obj->otyp != CAN_OF_GREASE || !obj->spe)));
3246 fails = try_disarm(ttmp, bad_tool);
3247 if (fails < 2) return fails;
3249 /* successfully used oil or grease to fix squeaky board */
3250 if (obj->otyp == CAN_OF_GREASE) {
3251 consume_obj_charge(obj, TRUE);
3253 useup(obj); /* oil */
3256 You("repair the squeaky board."); /* no madeby_u */
3258 newsym(u.ux + u.dx, u.uy + u.dy);
3259 more_experienced(1, 5);
3264 /* removes traps that shoot arrows, darts, etc. */
3266 disarm_shooting_trap(ttmp, otyp)
3270 int fails = try_disarm(ttmp, FALSE);
3272 if (fails < 2) return fails;
3273 You("disarm %s trap.", the_your[ttmp->madeby_u]);
3274 cnv_trap_obj(otyp, 50-rnl(50), ttmp);
3278 /* Is the weight too heavy?
3279 * Formula as in near_capacity() & check_capacity() */
3281 try_lift(mtmp, ttmp, wt, stuff)
3287 int wc = weight_cap();
3289 if (((wt * 2) / wc) >= HVY_ENCUMBER) {
3290 pline("%s is %s for you to lift.", Monnam(mtmp),
3291 stuff ? "carrying too much" : "too heavy");
3292 if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove &&
3293 !mindless(mtmp->data) &&
3294 mtmp->data->mlet != S_HUMAN && rnl(10) < 3) {
3295 mtmp->mpeaceful = 1;
3296 set_malign(mtmp); /* reset alignment */
3297 pline("%s thinks it was nice of you to try.", Monnam(mtmp));
3304 /* Help trapped monster (out of a (spiked) pit) */
3306 help_monster_out(mtmp, ttmp)
3315 * This works when levitating too -- consistent with the ability
3316 * to hit monsters while levitating.
3318 * Should perhaps check that our hero has arms/hands at the
3319 * moment. Helping can also be done by engulfing...
3321 * Test the monster first - monsters are displayed before traps.
3323 if (!mtmp->mtrapped) {
3324 pline("%s isn't trapped.", Monnam(mtmp));
3327 /* Do you have the necessary capacity to lift anything? */
3328 if (check_capacity((char *)0)) return 1;
3330 /* Will our hero succeed? */
3331 if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) {
3332 You("try to reach out your %s, but %s backs away skeptically.",
3333 makeplural(body_part(ARM)),
3339 /* is it a cockatrice?... */
3340 if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) {
3341 You("grab the trapped %s using your bare %s.",
3342 mtmp->data->mname, makeplural(body_part(HAND)));
3344 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
3345 display_nhwindow(WIN_MESSAGE, FALSE);
3349 Sprintf(kbuf, "trying to help %s out of a pit",
3350 an(mtmp->data->mname));
3355 /* need to do cockatrice check first if sleeping or paralyzed */
3357 You("try to grab %s, but cannot get a firm grasp.",
3359 if (mtmp->msleeping) {
3360 mtmp->msleeping = 0;
3361 pline("%s awakens.", Monnam(mtmp));
3366 You("reach out your %s and grab %s.",
3367 makeplural(body_part(ARM)), mon_nam(mtmp));
3369 if (mtmp->msleeping) {
3370 mtmp->msleeping = 0;
3371 pline("%s awakens.", Monnam(mtmp));
3372 } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) {
3373 /* After such manhandling, perhaps the effect wears off */
3376 pline("%s stirs.", Monnam(mtmp));
3379 /* is the monster too heavy? */
3380 wt = inv_weight() + mtmp->data->cwt;
3381 if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1;
3383 /* is the monster with inventory too heavy? */
3384 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
3386 if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1;
3388 You("pull %s out of the pit.", mon_nam(mtmp));
3390 fill_pit(mtmp->mx, mtmp->my);
3391 reward_untrap(ttmp, mtmp);
3399 register struct obj *otmp;
3400 register boolean confused = (Confusion > 0 || Hallucination > 0);
3405 boolean trap_skipped = FALSE;
3406 boolean box_here = FALSE;
3407 boolean deal_with_floor_trap = FALSE;
3408 char the_trap[BUFSZ], qbuf[QBUFSZ];
3409 int containercnt = 0;
3411 if(!getdir((char *)0)) return(0);
3415 for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
3416 if(Is_box(otmp) && !u.dx && !u.dy) {
3419 if (containercnt > 1) break;
3423 if ((ttmp = t_at(x,y)) && ttmp->tseen) {
3424 deal_with_floor_trap = TRUE;
3425 Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
3427 if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) {
3428 You_cant("do much about %s%s.",
3430 " that you're stuck in" :
3431 " while standing on the edge of it");
3432 trap_skipped = TRUE;
3433 deal_with_floor_trap = FALSE;
3435 Sprintf(qbuf, "There %s and %s here. %s %s?",
3436 (containercnt == 1) ? "is a container" : "are containers",
3437 an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation),
3438 ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap);
3439 switch (ynq(qbuf)) {
3440 case 'q': return(0);
3441 case 'n': trap_skipped = TRUE;
3442 deal_with_floor_trap = FALSE;
3447 if (deal_with_floor_trap) {
3449 You("cannot deal with %s while trapped%s!", the_trap,
3450 (x == u.ux && y == u.uy) ? " in it" : "");
3453 switch(ttmp->ttyp) {
3456 return disarm_holdingtrap(ttmp);
3458 return disarm_landmine(ttmp);
3460 return disarm_squeaky_board(ttmp);
3462 return disarm_shooting_trap(ttmp, DART);
3464 return disarm_shooting_trap(ttmp, ARROW);
3467 if (!u.dx && !u.dy) {
3468 You("are already on the edge of the pit.");
3471 if (!(mtmp = m_at(x,y))) {
3472 pline("Try filling the pit instead.");
3475 return help_monster_out(mtmp, ttmp);
3477 You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this");
3483 if(!u.dx && !u.dy) {
3484 for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
3486 Sprintf(qbuf, "There is %s here. Check it for traps?",
3487 safe_qbuf("", sizeof("There is here. Check it for traps?"),
3488 doname(otmp), an(simple_typename(otmp->otyp)), "a box"));
3489 switch (ynq(qbuf)) {
3490 case 'q': return(0);
3494 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
3495 You("aren't skilled enough to reach from %s.",
3500 if((otmp->otrapped && (force || (!confused
3501 && rn2(MAXULEV + 1 - u.ulevel) < 10)))
3502 || (!force && confused && !rn2(3))) {
3503 You("find a trap on %s!", the(xname(otmp)));
3504 if (!confused) exercise(A_WIS, TRUE);
3506 switch (ynq("Disarm it?")) {
3507 case 'q': return(1);
3508 case 'n': trap_skipped = TRUE; continue;
3511 if(otmp->otrapped) {
3512 exercise(A_DEX, TRUE);
3513 ch = ACURR(A_DEX) + u.ulevel;
3514 if (Role_if(PM_ROGUE)) ch *= 2;
3515 if(!force && (confused || Fumbling ||
3516 rnd(75+level_difficulty()/2) > ch)) {
3517 (void) chest_trap(otmp, FINGER, TRUE);
3522 } else pline("That %s was not trapped.", xname(otmp));
3525 You("find no traps on %s.", the(xname(otmp)));
3530 You(trap_skipped ? "find no other traps here."
3531 : "know of no traps here.");
3535 if ((mtmp = m_at(x,y)) &&
3536 mtmp->m_ap_type == M_AP_FURNITURE &&
3537 (mtmp->mappearance == S_hcdoor ||
3538 mtmp->mappearance == S_vcdoor) &&
3539 !Protection_from_shape_changers) {
3541 stumble_onto_mimic(mtmp);
3545 if (!IS_DOOR(levl[x][y].typ)) {
3546 if ((ttmp = t_at(x,y)) && ttmp->tseen)
3547 You("cannot disable that trap.");
3549 You("know of no traps there.");
3553 switch (levl[x][y].doormask) {
3555 You("%s no door there.", Blind ? "feel" : "see");
3558 pline("This door is safely open.");
3561 pline("This door is broken.");
3565 if ((levl[x][y].doormask & D_TRAPPED
3567 (!confused && rn2(MAXULEV - u.ulevel + 11) < 10)))
3568 || (!force && confused && !rn2(3))) {
3569 You("find a trap on the door!");
3570 exercise(A_WIS, TRUE);
3571 if (ynq("Disarm it?") != 'y') return(1);
3572 if (levl[x][y].doormask & D_TRAPPED) {
3573 ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel*3 : u.ulevel);
3574 exercise(A_DEX, TRUE);
3575 if(!force && (confused || Fumbling ||
3576 rnd(75+level_difficulty()/2) > ch)) {
3578 b_trapped("door", FINGER);
3579 levl[x][y].doormask = D_NODOOR;
3580 unblock_point(x, y);
3582 /* (probably ought to charge for this damage...) */
3583 if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L);
3586 levl[x][y].doormask &= ~D_TRAPPED;
3588 } else pline("This door was not trapped.");
3591 You("find no traps on the door.");
3598 /* only called when the player is doing something to the chest directly */
3600 chest_trap(obj, bodypart, disarm)
3601 register struct obj *obj;
3602 register int bodypart;
3605 register struct obj *otmp = obj, *otmp2;
3610 if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */
3611 obj->ox = cc.x, obj->oy = cc.y;
3613 otmp->otrapped = 0; /* trap is one-shot; clear flag first in case
3614 chest kills you and ends up in bones file */
3615 You(disarm ? "set it off!" : "trigger a trap!");
3616 display_nhwindow(WIN_MESSAGE, FALSE);
3617 if (Luck > -13 && rn2(13+Luck) > 7) { /* saved by luck */
3618 /* trap went off, but good luck prevents damage */
3621 case 11: msg = "explosive charge is a dud"; break;
3623 case 9: msg = "electric charge is grounded"; break;
3625 case 7: msg = "flame fizzles out"; break;
3628 case 4: msg = "poisoned needle misses"; break;
3632 case 0: msg = "gas cloud blows away"; break;
3633 default: impossible("chest disarm bug"); msg = (char *)0;
3636 if (msg) pline("But luckily the %s!", msg);
3638 switch(rn2(20) ? ((Luck >= 13) ? 0 : rn2(13-Luck)) : rn2(26)) {
3644 struct monst *shkp = 0;
3646 boolean costly, insider;
3647 register xchar ox = obj->ox, oy = obj->oy;
3649 /* the obj location need not be that of player */
3650 costly = (costly_spot(ox, oy) &&
3651 (shkp = shop_keeper(*in_rooms(ox, oy,
3652 SHOPBASE))) != (struct monst *)0);
3653 insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
3654 *in_rooms(ox, oy, SHOPBASE) == *u.ushops);
3656 pline("%s!", Tobjnam(obj, "explode"));
3657 Sprintf(buf, "exploding %s", xname(obj));
3660 loss += stolen_value(obj, ox, oy,
3661 (boolean)shkp->mpeaceful, TRUE);
3662 delete_contents(obj);
3663 /* we're about to delete all things at this location,
3664 * which could include the ball & chain.
3665 * If we attempt to call unpunish() in the
3666 * for-loop below we can end up with otmp2
3667 * being invalid once the chain is gone.
3668 * Deal with ball & chain right now instead.
3670 if (Punished && !carried(uball) &&
3671 ((uchain->ox == u.ux && uchain->oy == u.uy) ||
3672 (uball->ox == u.ux && uball->oy == u.uy)))
3675 for(otmp = level.objects[u.ux][u.uy];
3676 otmp; otmp = otmp2) {
3677 otmp2 = otmp->nexthere;
3679 loss += stolen_value(otmp, otmp->ox,
3680 otmp->oy, (boolean)shkp->mpeaceful,
3685 losehp(d(6,6), buf, KILLED_BY_AN);
3686 exercise(A_STR, FALSE);
3687 if(costly && loss) {
3689 You("owe %ld %s for objects destroyed.",
3690 loss, currency(loss));
3692 You("caused %ld %s worth of damage!",
3693 loss, currency(loss));
3694 make_angry_shk(shkp, ox, oy);
3703 pline("A cloud of noxious gas billows from %s.",
3705 poisoned("gas cloud", A_STR, "cloud of poison gas",15);
3706 exercise(A_CON, FALSE);
3712 You_feel("a needle prick your %s.",body_part(bodypart));
3713 poisoned("needle", A_CON, "poisoned needle",10);
3714 exercise(A_CON, FALSE);
3727 You("are jolted by a surge of electricity!");
3728 if(Shock_resistance) {
3729 shieldeff(u.ux, u.uy);
3730 You("don't seem to be affected.");
3734 destroy_item(RING_CLASS, AD_ELEC);
3735 destroy_item(WAND_CLASS, AD_ELEC);
3736 if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN);
3743 pline("Suddenly you are frozen in place!");
3745 exercise(A_DEX, FALSE);
3746 nomovemsg = You_can_move_again;
3747 } else You("momentarily stiffen.");
3752 pline("A cloud of %s gas billows from %s.",
3753 Blind ? blindgas[rn2(SIZE(blindgas))] :
3754 rndcolor(), the(xname(obj)));
3757 pline("What a groovy feeling!");
3759 You("%s and get dizzy...",
3760 stagger(youmonst.data, "stagger"));
3762 You("%s and your vision blurs...",
3763 stagger(youmonst.data, "stagger"));
3765 make_stunned(HStun + rn1(7, 16),FALSE);
3766 (void) make_hallucinated(HHallucination + rn1(5, 16),FALSE,0L);
3768 default: impossible("bad chest trap");
3771 bot(); /* to get immediate botl re-display */
3784 register struct trap *trap = ftrap;
3786 if(trap->tx == x && trap->ty == y) return(trap);
3789 return((struct trap *)0);
3797 register struct trap *trap;
3799 register struct trap *ttmp;
3802 ftrap = ftrap->ntrap;
3804 for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
3805 ttmp->ntrap = trap->ntrap;
3812 register struct trap *ttmp;
3814 /* Destroy a trap that emanates from the floor. */
3815 /* some of these are arbitrary -dlc */
3816 if (ttmp && ((ttmp->ttyp == SQKY_BOARD) ||
3817 (ttmp->ttyp == BEAR_TRAP) ||
3818 (ttmp->ttyp == LANDMINE) ||
3819 (ttmp->ttyp == FIRE_TRAP) ||
3820 (ttmp->ttyp == PIT) ||
3821 (ttmp->ttyp == SPIKED_PIT) ||
3822 (ttmp->ttyp == HOLE) ||
3823 (ttmp->ttyp == TRAPDOOR) ||
3824 (ttmp->ttyp == TELEP_TRAP) ||
3825 (ttmp->ttyp == LEVEL_TELEP) ||
3826 (ttmp->ttyp == WEB) ||
3827 (ttmp->ttyp == MAGIC_TRAP) ||
3828 (ttmp->ttyp == ANTI_MAGIC))) {
3829 register struct monst *mtmp;
3831 if (ttmp->tx == u.ux && ttmp->ty == u.uy) {
3834 } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) {
3843 /* used for doors (also tins). can be used for anything else that opens. */
3845 b_trapped(item, bodypart)
3846 register const char *item;
3847 register int bodypart;
3849 register int lvl = level_difficulty();
3850 int dmg = rnd(5 + (lvl < 5 ? lvl : 2+lvl/2));
3852 pline("KABOOM!! %s was booby-trapped!", The(item));
3854 losehp(dmg, "explosion", KILLED_BY_AN);
3855 exercise(A_STR, FALSE);
3856 if (bodypart) exercise(A_CON, FALSE);
3857 make_stunned(HStun + dmg, TRUE);
3860 /* Monster is hit by trap. */
3861 /* Note: doesn't work if both obj and d_override are null */
3863 thitm(tlev, mon, obj, d_override, nocorpse)
3871 boolean trapkilled = FALSE;
3873 if (d_override) strike = 1;
3874 else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20));
3875 else strike = (find_mac(mon) + tlev <= rnd(20));
3877 /* Actually more accurate than thitu, which doesn't take
3878 * obj->spe into account.
3881 if (obj && cansee(mon->mx, mon->my))
3882 pline("%s is almost hit by %s!", Monnam(mon), doname(obj));
3886 if (obj && cansee(mon->mx, mon->my))
3887 pline("%s is hit by %s!", Monnam(mon), doname(obj));
3888 if (d_override) dam = d_override;
3890 dam = dmgval(obj, mon);
3891 if (dam < 1) dam = 1;
3893 if ((mon->mhp -= dam) <= 0) {
3897 monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
3898 if (mon->mhp <= 0) {
3904 if (obj && (!strike || d_override)) {
3905 place_object(obj, mon->mx, mon->my);
3907 } else if (obj) dealloc_obj(obj);
3915 return((boolean)(multi < 0 && (!nomovemsg ||
3917 !strncmp(nomovemsg,"You regain con", 14) ||
3918 !strncmp(nomovemsg,"You are consci", 14))));
3921 static const char lava_killer[] = "molten lava";
3926 register struct obj *obj, *obj2;
3931 if (likes_lava(youmonst.data)) return FALSE;
3933 if (!Fire_resistance) {
3936 pline_The("lava here burns you!");
3938 losehp(dmg, lava_killer, KILLED_BY);
3942 You("fall into the lava!");
3944 usurvive = Lifesaved || discover;
3946 if (wizard) usurvive = TRUE;
3948 for(obj = invent; obj; obj = obj2) {
3950 if(is_organic(obj) && !obj->oerodeproof) {
3951 if(obj->owornmask) {
3953 Your("%s into flame!", aobjnam(obj, "burst"));
3955 if(obj == uarm) (void) Armor_gone();
3956 else if(obj == uarmc) (void) Cloak_off();
3957 else if(obj == uarmh) (void) Helmet_off();
3958 else if(obj == uarms) (void) Shield_off();
3959 else if(obj == uarmg) (void) Gloves_off();
3960 else if(obj == uarmf) (void) Boots_off();
3962 else if(obj == uarmu) setnotworn(obj);
3964 else if(obj == uleft) Ring_gone(obj);
3965 else if(obj == uright) Ring_gone(obj);
3966 else if(obj == ublindf) Blindf_off(obj);
3967 else if(obj == uamul) Amulet_off();
3968 else if(obj == uwep) uwepgone();
3969 else if (obj == uquiver) uqwepgone();
3970 else if (obj == uswapwep) uswapwepgone();
3978 killer_format = KILLED_BY;
3979 killer = lava_killer;
3980 You("burn to a crisp...");
3982 while (!safe_teleds(TRUE)) {
3983 pline("You're still burning.");
3986 You("find yourself back on solid %s.", surface(u.ux, u.uy));
3991 u.utrap = rn1(4, 4) + (rn1(4, 12) << 8);
3992 u.utraptype = TT_LAVA;
3993 You("sink into the lava, but it only burns slightly!");
3995 losehp(1, lava_killer, KILLED_BY);
3997 /* just want to burn boots, not all armor; destroy_item doesn't work on
4000 if(uarmf && !uarmf->oerodeproof && is_organic(uarmf)) {
4001 /* save uarmf value because Boots_off() sets uarmf to null */
4003 Your("%s bursts into flame!", xname(obj));
4007 destroy_item(SCROLL_CLASS, AD_FIRE);
4008 destroy_item(SPBOOK_CLASS, AD_FIRE);
4009 destroy_item(POTION_CLASS, AD_FIRE);