fix #2242 and #2292 - levitation exceptions (trunk only)

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.
This commit is contained in:
nethack.rankin
2011-10-15 03:00:45 +00:00
parent 30b3e5a2ea
commit f48de2f336
8 changed files with 129 additions and 37 deletions

View File

@@ -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));
@@ -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
@@ -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);