Skip to content

Commit

Permalink
fix #2242 and #2292 - levitation exceptions (trunk only)
Browse files Browse the repository at this point in the history
     From a bug report.  The first report complained about levitation
allowing you to move through water on the Plane of Water, something that's
come up in the newsgroup lots of times (mostly about how levitation is
the best way to get around, only occasionally wondering why it works:
water walking doesn't work there because there's no surface, so where are
you levitating such that you're kept dry?)  The second report complained
about being told you were floating up if you put on a ring of levitation
while stuck inside a wall (perhaps after being stranded when polymorph
into xorn form ended).

     This implements intrinsic blocking for levitation and also for
flying.  Being inside solid rock (or closed door) anywhere and being in
water on the Plane of Water are the things that do it for levitation;
those two and levitating are what do it for flying.  Entering such
terrain turns off ability to float/fly, and leaving there turns it back
on; starting levitation blocks flight, ending it unblocks (levitation
has always overridden flying's ability to reach the floor).  Being able
to phase through rock doesn't prevent levitation and flight from being
blocked while in rock; you aren't floating or flying in that situation.
  • Loading branch information
nethack.rankin committed Oct 15, 2011
1 parent 30b3e5a commit f48de2f
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 37 deletions.
2 changes: 2 additions & 0 deletions doc/fixes35.0
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ if hero was blind, killing the vault guard while in his temporary corridor
would leave hero encased in solid rock without informing player
if hero dragged iron ball into temporary corridor and then killed vault guard,
the portion of corridor currently in existence would become permanent
on Plane of Water, restrict levitation and flying to air bubbles;
elsewhere, restrict them such that they don't work inside solid rock


Platform- and/or Interface-Specific Fixes
Expand Down
11 changes: 7 additions & 4 deletions include/youprop.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@

#define HLevitation u.uprops[LEVITATION].intrinsic
#define ELevitation u.uprops[LEVITATION].extrinsic
#define Levitation (HLevitation || ELevitation)
#define BLevitation u.uprops[LEVITATION].blocked
#define Levitation ((HLevitation || ELevitation) && !BLevitation)
/* Can't touch surface, can't go under water; overrides all others */
#define Lev_at_will (((HLevitation & I_SPECIAL) != 0L || \
(ELevitation & W_ARTI) != 0L) && \
Expand All @@ -226,11 +227,13 @@

#define HFlying u.uprops[FLYING].intrinsic
#define EFlying u.uprops[FLYING].extrinsic
#define BFlying u.uprops[FLYING].blocked
#ifdef STEED
# define Flying (HFlying || EFlying || \
(u.usteed && is_flyer(u.usteed->data)))
# define Flying ((HFlying || EFlying || \
(u.usteed && is_flyer(u.usteed->data))) && \
!BFlying)
#else
# define Flying (HFlying || EFlying)
# define Flying ((HFlying || EFlying) && !BFlying)
#endif
/* May touch surface; does not override any others */

Expand Down
37 changes: 31 additions & 6 deletions src/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1415,12 +1415,8 @@ int final;
you_are("levitating, at will", "");
else
enl_msg(youtoo, are, were, "levitating", from_what(LEVITATION));
}
if (Flying) {
if (Levitation)
you_can("also fly", from_what(FLYING));
else
enl_msg(youtoo, are, were, "flying", from_what(FLYING));
} else if (Flying) { /* can only fly when not levitating */
enl_msg(youtoo, are, were, "flying", from_what(FLYING));
}
if (Underwater) {
you_are("underwater", "");
Expand Down Expand Up @@ -1621,6 +1617,8 @@ attributes_enlightenment(mode, final)
int mode;
int final;
{
static NEARDATA const char
if_surroundings_permitted[] = " if surroundings permitted";
int ltmp, armpro;
char buf[BUFSZ];

Expand Down Expand Up @@ -1762,6 +1760,33 @@ int final;
if (Teleportation) you_can("teleport",from_what(TELEPORT));
if (Teleport_control)
you_have("teleport control",from_what(TELEPORT_CONTROL));
/* actively levitating handled earlier as a status condition */
if (BLevitation) { /* levitation is blocked */
long save_BLev = BLevitation;

BLevitation = 0L;
if (Levitation)
enl_msg(You_, "would levitate", "would have levitated",
if_surroundings_permitted, "");
BLevitation = save_BLev;
}
/* actively flying handled earlier as a status condition */
if (BFlying) { /* flight is blocked */
long save_BFly = BFlying;

BFlying = 0L;
if (Flying) {
Sprintf(buf, "%s%s%s",
(save_BFly & I_SPECIAL) ?
" if you weren't levitating" : "",
((save_BFly & (FROMOUTSIDE|I_SPECIAL)) ==
(FROMOUTSIDE|I_SPECIAL)) ? " and" : "",
(save_BFly & FROMOUTSIDE) ?
if_surroundings_permitted : (const char *)"");
enl_msg(You_, "would fly", "would have flown", buf, "");
}
BFlying = save_BFly;
}
/* actively walking on water handled earlier as a status condition */
if (Wwalking && !walking_on_water())
you_can("walk on water",from_what(WWALKING));
Expand Down
13 changes: 8 additions & 5 deletions src/do_wear.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ Boots_on(VOID_ARGS)
incr_itimeout(&HFumbling, rnd(20));
break;
case LEVITATION_BOOTS:
if (!oldprop && !HLevitation) {
if (!oldprop && !HLevitation && !BLevitation) {
makeknown(uarmf->otyp);
float_up();
spoteffects(FALSE);
Expand Down Expand Up @@ -241,7 +241,8 @@ Boots_off(VOID_ARGS)
HFumbling = EFumbling = 0;
break;
case LEVITATION_BOOTS:
if (!oldprop && !HLevitation && !context.takeoff.cancelled_don) {
if (!oldprop && !HLevitation && !BLevitation &&
!context.takeoff.cancelled_don) {
(void) float_down(0L, 0L);
makeknown(otyp);
}
Expand Down Expand Up @@ -875,7 +876,7 @@ register struct obj *obj;
}
break;
case RIN_LEVITATION:
if (!oldprop && !HLevitation) {
if (!oldprop && !HLevitation && !BLevitation) {
float_up();
learnring(obj, TRUE);
spoteffects(FALSE); /* for sinks */
Expand Down Expand Up @@ -987,8 +988,10 @@ boolean gone;
}
break;
case RIN_LEVITATION:
(void) float_down(0L, 0L);
if (!Levitation) learnring(obj, TRUE);
if (!BLevitation) {
(void) float_down(0L, 0L);
if (!Levitation) learnring(obj, TRUE);
}
break;
case RIN_GAIN_STRENGTH:
which = A_STR;
Expand Down
39 changes: 39 additions & 0 deletions src/hack.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ STATIC_DCL void NDECL(dosinkfall);
#endif
STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
STATIC_DCL boolean FDECL(trapmove, (int,int,struct trap *));
STATIC_DCL void NDECL(switch_terrain);
STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *,int));
STATIC_DCL boolean FDECL(doorless_door, (int,int));
STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
Expand Down Expand Up @@ -1640,6 +1641,40 @@ invocation_message()
}
}

/* moving onto different terrain;
might be going into solid rock, inhibiting levitation or flight,
or coming back out of such, reinstating levitation/flying */
STATIC_OVL void
switch_terrain()
{
struct rm *lev = &levl[u.ux][u.uy];
boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy) ||
(Is_waterlevel(&u.uz) && lev->typ == WATER));

if (blocklev) {
/* called from spoteffects(), skip float_down() */
if (Levitation) You_cant("levitate in here.");
BLevitation |= FROMOUTSIDE;
} else if (BLevitation) {
BLevitation &= ~FROMOUTSIDE;
if (Levitation) float_up();
}
/* the same terrain that blocks levitation also blocks flight */
if (blocklev) {
if (Flying) You_cant("fly in here.");
BFlying |= FROMOUTSIDE;
} else if (BFlying) {
BFlying &= ~FROMOUTSIDE;
/* in case BFlying got set due to levitation which then went away
while blocked; there'd be no float_down() with reset of BFlying */
if (!HLevitation && !ELevitation) BFlying &= ~I_SPECIAL;
/* [minor bug: we don't know whether this is beginning flight or
resuming it; that could be tracked so that this message could
be adjusted to "resume flying", but isn't worth the effort...] */
if (Flying) You("start flying.");
}
}

/* extracted from spoteffects; called by spoteffects to check for entering or
leaving a pool of water/lava, and by moveloop to check for staying on one */
boolean
Expand Down Expand Up @@ -1741,6 +1776,10 @@ boolean pick;
spotterrain = levl[u.ux][u.uy].typ;
spotloc.x = u.ux, spotloc.y = u.uy;

/* moving onto different terrain might cause Levitation to toggle */
if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0))
switch_terrain();

if (pooleffects(TRUE)) goto spotdone;

check_special_room(FALSE);
Expand Down
5 changes: 5 additions & 0 deletions src/polyself.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ set_uasmon()
PROPSET(PASSES_WALLS, passes_walls(mdat));
PROPSET(REGENERATION, regenerates(mdat));
PROPSET(REFLECTING, (mdat == &mons[PM_SILVER_DRAGON]));
/* levitation overrides flight */
if (HLevitation || ELevitation)
BFlying |= I_SPECIAL;
else
BFlying &= ~I_SPECIAL;

#undef PROPSET

Expand Down
47 changes: 25 additions & 22 deletions src/potion.c
Original file line number Diff line number Diff line change
Expand Up @@ -904,33 +904,36 @@ peffects(otmp)
case POT_LEVITATION:
case SPE_LEVITATION:
if (otmp->cursed) HLevitation &= ~I_SPECIAL;
if(!Levitation) {
/* kludge to ensure proper operation of float_up() */
set_itimeout(&HLevitation, 1L);
float_up();
/* reverse kludge */
set_itimeout(&HLevitation, 0L);
if (otmp->cursed && !Is_waterlevel(&u.uz)) {
if((u.ux != xupstair || u.uy != yupstair)
&& (u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up)
&& (!xupladder || u.ux != xupladder || u.uy != yupladder)
) {
int dmg = uarmh ? 1 : rnd(10);
You("hit your %s on the %s.",
body_part(HEAD),
ceiling(u.ux,u.uy));
losehp(Maybe_Half_Phys(dmg),
"colliding with the ceiling",
KILLED_BY);
} else (void) doup();
if (!Levitation && !BLevitation) {
/* kludge to ensure proper operation of float_up() */
set_itimeout(&HLevitation, 1L);
float_up();
/* reverse kludge */
set_itimeout(&HLevitation, 0L);
if (otmp->cursed) {
if ((u.ux == xupstair && u.uy == yupstair) ||
(sstairs.up && u.ux == sstairs.sx &&
u.uy == sstairs.sy) ||
(xupladder && u.ux == xupladder &&
u.uy == yupladder)) {
(void) doup();
} else if (has_ceiling(&u.uz)) {
int dmg = uarmh ? 1 : rnd(10);

You("hit your %s on the %s.",
body_part(HEAD), ceiling(u.ux,u.uy));
losehp(Maybe_Half_Phys(dmg),
"colliding with the ceiling", KILLED_BY);
}
} /*cursed*/
} else
nothing++;
nothing++;
if (otmp->blessed) {
incr_itimeout(&HLevitation, rn1(50,250));
HLevitation |= I_SPECIAL;
} else incr_itimeout(&HLevitation, rn1(140,10));
spoteffects(FALSE); /* for sinks */
} else
incr_itimeout(&HLevitation, rn1(140,10));
if (Levitation) spoteffects(FALSE); /* for sinks */
break;
case POT_GAIN_ENERGY: /* M. Stephenson */
{ register int num;
Expand Down
12 changes: 12 additions & 0 deletions src/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2609,8 +2609,10 @@ float_up()
body_part(LEG));
}
}
#if 0
else if(Is_waterlevel(&u.uz))
pline("It feels as though you've lost some weight.");
#endif
else if(u.uinwater)
spoteffects(TRUE);
else if(u.uswallow)
Expand All @@ -2637,6 +2639,8 @@ float_up()
}
}
#endif
if (Flying) You("are no longer able to control your flight.");
BFlying |= I_SPECIAL;
return;
}

Expand Down Expand Up @@ -2667,6 +2671,14 @@ long hmask, emask; /* might cancel timeout */
ELevitation &= ~emask;
if(Levitation) return(0); /* maybe another ring/potion/boots */
nomul(0); /* stop running or resting */
if (BFlying) {
/* controlled flight no longer overridden by levitation */
BFlying &= ~I_SPECIAL;
if (Flying) {
You("have stopped levitating and are now flying.");
return 1;
}
}
if(u.uswallow) {
You("float down, but you are still %s.",
is_animal(u.ustuck->data) ? "swallowed" : "engulfed");
Expand Down

0 comments on commit f48de2f

Please sign in to comment.