fix C343-22 - #untrap while levitating (trunk only)

Revise untrap() to handle being unable to reach the floor.  That
whole routine is a mess and should probably be rewritten.

     Included at no extra charge:  #untrap didn't check whether player
picked a spot off the edge of the map so could go out of array bounds.
This commit is contained in:
nethack.rankin
2007-05-27 03:07:24 +00:00
parent bc4ccd0f44
commit e8012786d0
2 changed files with 59 additions and 33 deletions

View File

@@ -233,6 +233,7 @@ some monsters can't be strangled; self-polymorph can stop/restart strangulation
re-adjust gem generation probabilities when revisiting existing dungeon levels
kick evasion shouldn't move monsters through walls
kick evasion and jousting/staggering blows shouldn't move grid bugs diagonally
#untrap didn't check whether hero could reach the ground
Platform- and/or Interface-Specific Fixes

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)trap.c 3.5 2007/03/30 */
/* SCCS Id: @(#)trap.c 3.5 2007/05/26 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -3823,33 +3823,60 @@ untrap(force)
boolean force;
{
register struct obj *otmp;
register boolean confused = (Confusion > 0 || Hallucination > 0);
register int x,y;
int ch;
struct trap *ttmp;
struct monst *mtmp;
boolean trap_skipped = FALSE;
boolean box_here = FALSE;
boolean deal_with_floor_trap = FALSE;
const char *trapdescr;
boolean here, useplural,
confused = (Confusion || Hallucination),
trap_skipped = FALSE,
deal_with_floor_trap;
int boxcnt = 0;
char the_trap[BUFSZ], qbuf[QBUFSZ];
int containercnt = 0;
if(!getdir((char *)0)) return(0);
x = u.ux + u.dx;
y = u.uy + u.dy;
for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
if(Is_box(otmp) && !u.dx && !u.dy) {
box_here = TRUE;
containercnt++;
if (containercnt > 1) break;
}
if (!isok(x, y)) {
pline_The("perils lurking there are beyond your grasp.");
return 0;
}
ttmp = t_at(x, y);
if (ttmp && !ttmp->tseen) ttmp = 0;
trapdescr = ttmp ? defsyms[trap_to_defsym(ttmp->ttyp)].explanation : 0;
here = (x == u.ux && y == u.uy); /* !u.dx && !u.dy */
if ((ttmp = t_at(x,y)) && ttmp->tseen) {
deal_with_floor_trap = TRUE;
Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
if (box_here) {
if (here) /* are there are one or more containers here? */
for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
if (Is_box(otmp)) {
if (++boxcnt > 1) break;
}
deal_with_floor_trap = can_reach_floor(FALSE);
if (!deal_with_floor_trap) {
*the_trap = '\0';
if (ttmp) Strcat(the_trap, an(trapdescr));
if (ttmp && boxcnt) Strcat(the_trap, " and ");
if (boxcnt) Strcat(the_trap,
(boxcnt == 1) ? "a container" : "containers");
useplural = ((ttmp && boxcnt > 0) || boxcnt > 1);
/* note: boxcnt and useplural will always be 0 for !here case */
if (ttmp || boxcnt)
There("%s %s %s but you can't reach %s%s.",
useplural ? "are" : "is",
the_trap, here ? "here" : "there",
useplural ? "them" : "it",
#ifdef STEED
u.usteed ? " while mounted" :
#endif
"");
trap_skipped = (ttmp != 0);
} else { /* deal_with_floor_trap */
if (ttmp) {
Strcpy(the_trap, the(trapdescr));
if (boxcnt) {
if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) {
You_cant("do much about %s%s.",
the_trap, u.utrap ?
@@ -3859,9 +3886,11 @@ boolean force;
deal_with_floor_trap = FALSE;
} else {
Sprintf(qbuf, "There %s and %s here. %s %s?",
(containercnt == 1) ? "is a container" : "are containers",
an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation),
ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap);
(boxcnt == 1) ? "is a container" :
"are containers",
an(trapdescr),
(ttmp->ttyp == WEB) ? "Remove" : "Disarm",
the_trap);
switch (ynq(qbuf)) {
case 'q': return(0);
case 'n': trap_skipped = TRUE;
@@ -3890,7 +3919,7 @@ boolean force;
return disarm_shooting_trap(ttmp, ARROW);
case PIT:
case SPIKED_PIT:
if (!u.dx && !u.dy) {
if (here) {
You("are already on the edge of the pit.");
return 0;
}
@@ -3900,13 +3929,14 @@ boolean force;
}
return help_monster_out(mtmp, ttmp);
default:
You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this");
You("cannot disable %s trap.",
!here ? "that" : "this");
return 0;
}
}
} /* end if */
if(!u.dx && !u.dy) {
if (boxcnt) {
for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
if(Is_box(otmp)) {
(void)safe_qbuf(qbuf, "There is ",
@@ -3916,12 +3946,7 @@ boolean force;
case 'q': return(0);
case 'n': continue;
}
#ifdef STEED
if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
rider_cant_reach();
return(0);
}
#endif
if((otmp->otrapped && (force || (!confused
&& rn2(MAXULEV + 1 - u.ulevel) < 10)))
|| (!force && confused && !rn2(3))) {
@@ -3962,15 +3987,15 @@ boolean force;
(mtmp->mappearance == S_hcdoor ||
mtmp->mappearance == S_vcdoor) &&
!Protection_from_shape_changers) {
stumble_onto_mimic(mtmp);
return(1);
}
} /* deal_with_floor_trap */
/* doors can be manipulated even while levitating/unskilled riding */
if (!IS_DOOR(levl[x][y].typ)) {
if ((ttmp = t_at(x,y)) && ttmp->tseen)
You("cannot disable that trap.");
else
if (!trap_skipped)
You("know of no traps there.");
return(0);
}