(unsigned, struct obj *, struct obj *));
#endif
+/* mintrap() should take a flags argument, but for time being we use this */
+STATIC_VAR int force_mintrap = 0;
+
STATIC_VAR const char * const a_your[2] = { "a", "your" };
STATIC_VAR const char * const A_Your[2] = { "A", "Your" };
STATIC_VAR const char tower_of_flame[] = "tower of flame";
if (webmsgok) {
char verbbuf[BUFSZ];
+ if (forcetrap) {
+ Strcpy(verbbuf, "are caught by");
#ifdef STEED
- if (u.usteed)
- Sprintf(verbbuf, "lead %s",
+ } else if (u.usteed) {
+ Sprintf(verbbuf, "lead %s into",
x_monnam(u.usteed, steed_article,
"poor", SUPPRESS_SADDLE, FALSE));
- else
#endif
-
- Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" :
- locomotion(youmonst.data, "stumble"));
- You("%s into %s spider web!",
- verbbuf, a_your[trap->madeby_u]);
+ } else {
+ Sprintf(verbbuf, "%s into",
+ Levitation ? (const char *)"float" :
+ locomotion(youmonst.data, "stumble"));
+ }
+ You("%s %s spider web!", verbbuf, a_your[trap->madeby_u]);
}
u.utraptype = TT_WEB;
} else {
register int tt = trap->ttyp;
boolean in_sight, tear_web, see_it,
- inescapable = ((tt == HOLE || tt == PIT) &&
+ inescapable = force_mintrap ||
+ ((tt == HOLE || tt == PIT) &&
In_sokoban(&u.uz) && !trap->madeby_u);
const char *fallverb;
&& !Deaf)
You_hear("the roaring of an angry bear!");
}
+ } else if (force_mintrap) {
+ if (in_sight) {
+ pline("%s evades %s bear trap!",
+ Monnam(mtmp), a_your[trap->madeby_u]);
+ seetrap(trap);
+ }
}
break;
if (is_flyer(mptr) || is_floater(mptr) ||
(mtmp->wormno && count_wsegs(mtmp) > 5) ||
is_clinger(mptr)) {
+ if (force_mintrap && !In_sokoban(&u.uz)) {
+ /* openfallingtrap; not inescapable here */
+ if (in_sight) {
+ seetrap(trap);
+ pline("%s doesn't fall into the pit.",
+ Monnam(mtmp));
+ }
+ break; /* inescapable = FALSE; */
+ }
if (!inescapable) break; /* avoids trap */
fallverb = "is dragged"; /* sokoban pit */
}
mptr == &mons[PM_WUMPUS] ||
(mtmp->wormno && count_wsegs(mtmp) > 5) ||
mptr->msize >= MZ_HUGE) {
+ if (force_mintrap && !In_sokoban(&u.uz)) {
+ /* openfallingtrap; not inescapable here */
+ if (in_sight) {
+ seetrap(trap);
+ if (tt == TRAPDOOR)
+ pline(
+ "A trap door opens, but %s doesn't fall through.",
+ mon_nam(mtmp));
+ else /* (tt == HOLE) */
+ pline(
+ "%s doesn't fall through the hole.",
+ Monnam(mtmp));
+ }
+ break; /* inescapable = FALSE; */
+ }
if (inescapable) { /* sokoban hole */
if (in_sight) {
pline("%s seems to be yanked down!",
Monnam(mtmp), a_your[trap->madeby_u]);
deltrap(trap);
newsym(mtmp->mx, mtmp->my);
+ } else if (force_mintrap && !mtmp->mtrapped) {
+ if (in_sight) {
+ pline("%s avoids %s spider web!",
+ Monnam(mtmp), a_your[trap->madeby_u]);
+ seetrap(trap);
+ }
}
break;
}
}
+/* for magic unlocking; returns true if targetted monster (which might
+ be hero) gets untrapped; the trap remains intact */
+boolean
+openholdingtrap(mon, noticed)
+struct monst *mon;
+boolean *noticed; /* set to true iff hero notices the effect; */
+{ /* otherwise left with its previous value intact */
+ struct trap *t;
+ char buf[BUFSZ];
+ const char *trapdescr, *which;
+ boolean ishero = (mon == &youmonst);
+
+#ifdef STEED
+ if (mon == u.usteed) ishero = TRUE;
+#endif
+ t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my);
+ /* if no trap here or it's not a holding trap, we're done */
+ if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) return FALSE;
+
+ trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation;
+ which = t->tseen ? the_your[t->madeby_u] :
+ index(vowels, *trapdescr) ? "an" : "a";
+
+ if (ishero) {
+ if (!u.utrap) return FALSE;
+ u.utrap = 0; /* released regardless of type */
+ *noticed = TRUE;
+ /* give message only if trap was the expected type */
+ if (u.utraptype == TT_BEARTRAP || u.utraptype == TT_WEB) {
+#ifdef STEED
+ if (u.usteed)
+ Sprintf(buf, "%s is", noit_Monnam(u.usteed));
+ else
+#endif
+ Strcpy(buf, "You are");
+ pline("%s released from %s %s.", buf, which, trapdescr);
+ }
+ } else {
+ if (!mon->mtrapped) return FALSE;
+ mon->mtrapped = 0;
+ if (canspotmon(mon)) {
+ *noticed = TRUE;
+ pline("%s is released from %s %s.",
+ Monnam(mon), which, trapdescr);
+ } else if (cansee(t->tx, t->ty) && t->tseen) {
+ *noticed = TRUE;
+ if (t->ttyp == WEB)
+ pline("%s is released from %s %s.",
+ Something, which, trapdescr);
+ else /* BEAR_TRAP */
+ pline("%s %s opens.", upstart(strcpy(buf, which)), trapdescr);
+ }
+ /* might pacify monster if adjacent */
+ if (rn2(2) && distu(mon->mx, mon->my) <= 2) reward_untrap(t, mon);
+ }
+ return TRUE;
+}
+
+/* for magic locking; returns true if targetted monster (which might
+ be hero) gets hit by a trap (might avoid actually becoming trapped) */
+boolean
+closeholdingtrap(mon, noticed)
+struct monst *mon;
+boolean *noticed; /* set to true iff hero notices the effect; */
+{ /* otherwise left with its previous value intact */
+ struct trap *t;
+ unsigned dotrapflags;
+ boolean ishero = (mon == &youmonst), result;
+
+#ifdef STEED
+ if (mon == u.usteed) ishero = TRUE;
+#endif
+ t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my);
+ /* if no trap here or it's not a holding trap, we're done */
+ if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) return FALSE;
+
+ if (ishero) {
+ if (u.utrap) return FALSE; /* already trapped */
+ *noticed = TRUE;
+ dotrapflags = FORCETRAP;
+#ifdef STEED
+ /* dotrap calls mintrap when mounted hero encounters a web */
+ if (u.usteed) dotrapflags |= NOWEBMSG;
+#endif
+ ++force_mintrap;
+ dotrap(t, dotrapflags);
+ --force_mintrap;
+ result = (u.utrap != 0);
+ } else {
+ if (mon->mtrapped) return FALSE; /* already trapped */
+ /* you notice it if you see the trap close/tremble/whatever
+ or if you sense the monster who becomes trapped */
+ *noticed = cansee(t->tx, t->ty) || canspotmon(mon);
+ ++force_mintrap;
+ result = (mintrap(mon) != 0);
+ --force_mintrap;
+ }
+ return result;
+}
+
+/* for magic unlocking; returns true if targetted monster (which might
+ be hero) gets hit by a trap (target might avoid its effect) */
+boolean
+openfallingtrap(mon, trapdoor_only, noticed)
+struct monst *mon;
+boolean trapdoor_only;
+boolean *noticed; /* set to true iff hero notices the effect; */
+{ /* otherwise left with its previous value intact */
+ struct trap *t;
+ boolean ishero = (mon == &youmonst), result;
+
+#ifdef STEED
+ if (mon == u.usteed) ishero = TRUE;
+#endif
+ t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my);
+ /* if no trap here or it's not a falling trap, we're done
+ (note: falling rock traps have a trapdoor in the ceiling) */
+ if (!t || ((t->ttyp != TRAPDOOR && t->ttyp != ROCKTRAP) &&
+ (trapdoor_only ||
+ (t->ttyp != HOLE && t->ttyp != PIT && t->ttyp != SPIKED_PIT))))
+ return FALSE;
+
+ if (ishero) {
+ if (u.utrap) return FALSE; /* already trapped */
+ *noticed = TRUE;
+ dotrap(t, FORCETRAP);
+ result = (u.utrap != 0);
+ } else {
+ if (mon->mtrapped) return FALSE; /* already trapped */
+ /* you notice it if you see the trap close/tremble/whatever
+ or if you sense the monster who becomes trapped */
+ *noticed = cansee(t->tx, t->ty) || canspotmon(mon);
+ /* monster will be angered; mintrap doesn't handle that */
+ wakeup(mon);
+ ++force_mintrap;
+ result = (mintrap(mon) != 0);
+ --force_mintrap;
+ /* mon might now be on the migrating monsters list */
+ }
+ return TRUE;
+}
+
/* only called when the player is doing something to the chest directly */
boolean
chest_trap(obj, bodypart, disarm)
}
break;
}
- case WAN_NOTHING:
case WAN_LOCKING:
case SPE_WIZARD_LOCK:
- wake = FALSE;
+ wake = closeholdingtrap(mtmp, &learn_it);
break;
case WAN_PROBING:
wake = FALSE;
else pline("%s opens its mouth!", Monnam(mtmp));
}
expels(mtmp, mtmp->data, TRUE);
+ /* zap which hits steed will only release saddle if it
+ doesn't hit a holding or falling trap; playability
+ here overrides the more logical target ordering */
+ } else if (openholdingtrap(mtmp, &learn_it)) {
+ break;
+ } else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
+ /* mtmp might now be on the migrating monsters list */
+ break;
#ifdef STEED
- } else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
+ } else if ((obj = which_armor(mtmp, W_SADDLE)) != 0) {
mtmp->misc_worn_check &= ~obj->owornmask;
update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
obj->owornmask = 0L;
}
}
break;
+ case WAN_NOTHING:
+ wake = FALSE;
+ break;
default:
impossible("What an interesting effect (%d)", otyp);
break;
learn_it = TRUE;
unpunish();
}
+ if (u.utrap) { /* escape web or bear trap */
+ (void) openholdingtrap(&youmonst, &learn_it);
+ } else { /* trigger previously escaped trapdoor */
+ (void) openfallingtrap(&youmonst, TRUE, &learn_it);
+ }
+ break;
+ case WAN_LOCKING:
+ case SPE_WIZARD_LOCK:
+ if (!u.utrap) {
+ (void) closeholdingtrap(&youmonst, &learn_it);
+ }
break;
case WAN_DIGGING:
case SPE_DIG:
case SPE_DETECT_UNSEEN:
case WAN_NOTHING:
- case WAN_LOCKING:
- case SPE_WIZARD_LOCK:
break;
case WAN_PROBING:
{
pline_The("stairs seem to ripple momentarily.");
disclose = TRUE;
}
+ /* down will release you from bear trap or web */
+ if (u.dz > 0 && u.utrap) {
+ (void) openholdingtrap(&youmonst, &disclose);
+ /* down will trigger trapdoor, hole, or [spiked-] pit */
+ } else if (u.dz > 0 && !u.utrap) {
+ (void) openfallingtrap(&youmonst, FALSE, &disclose);
+ }
break;
case WAN_STRIKING:
case SPE_FORCE_BOLT:
case WAN_LOCKING:
case SPE_WIZARD_LOCK:
/* down at open bridge or up or down at open portcullis */
- if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
- (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) &&
+ if (((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
+ (is_drawbridge_wall(x,y) && !is_db_wall(x,y))) &&
find_drawbridge(&xx, &yy)) {
if (!striking)
close_drawbridge(xx, yy);
stackobj(otmp);
}
newsym(x, y);
- } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) {
- if (!Blind) {
- if (ttmp->tseen) {
- pline("A trap door beneath you closes up then vanishes.");
- disclose = TRUE;
- } else {
- You_see("a swirl of %s beneath you.",
- is_ice(x,y) ? "frost" : "dust");
- }
- } else {
- You_hear("a twang followed by a thud.");
+ } else if (u.dz > 0 && ttmp) {
+ if (!striking && closeholdingtrap(&youmonst, &disclose)) {
+ ; /* now stuck in web or bear trap */
+ } else if (striking && ttmp->ttyp == TRAPDOOR) {
+ /* striking transforms trapdoor into hole */
+ if (Blind && !ttmp->tseen) {
+ pline("%s beneath you shatters.", Something);
+ } else if (!ttmp->tseen) { /* => !Blind */
+ pline("There's a trapdoor beneath you; it shatters.");
+ } else {
+ pline("The trapdoor beneath you shatters.");
+ disclose = TRUE;
+ }
+ ttmp->ttyp = HOLE;
+ ttmp->tseen = 1;
+ newsym(x, y);
+ /* might fall down hole */
+ dotrap(ttmp, 0);
+ } else if (!striking && ttmp->ttyp == HOLE) {
+ /* locking transforms hole into trapdoor */
+ ttmp->ttyp = TRAPDOOR;
+ if (Blind || !ttmp->tseen) {
+ pline("Some %s swirls beneath you.",
+ is_ice(x,y) ? "frost" : "dust");
+ } else {
+ ttmp->tseen = 1;
+ newsym(x, y);
+ pline("A trapdoor appears beneath you.");
+ disclose = TRUE;
+ }
+ /* hadn't fallen down hole; won't fall now */
}
- deltrap(ttmp);
- ttmp = (struct trap *)0;
- newsym(x, y);
}
break;
case SPE_STONE_TO_FLESH: