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
#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) && \
#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 */
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", "");
int mode;
int final;
{
+ static NEARDATA const char
+ if_surroundings_permitted[] = " if surroundings permitted";
int ltmp, armpro;
char buf[BUFSZ];
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));
incr_itimeout(&HFumbling, rnd(20));
break;
case LEVITATION_BOOTS:
- if (!oldprop && !HLevitation) {
+ if (!oldprop && !HLevitation && !BLevitation) {
makeknown(uarmf->otyp);
float_up();
spoteffects(FALSE);
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);
}
}
break;
case RIN_LEVITATION:
- if (!oldprop && !HLevitation) {
+ if (!oldprop && !HLevitation && !BLevitation) {
float_up();
learnring(obj, TRUE);
spoteffects(FALSE); /* for sinks */
}
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;
#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));
}
}
+/* 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
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);
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
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;
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)
}
}
#endif
+ if (Flying) You("are no longer able to control your flight.");
+ BFlying |= I_SPECIAL;
return;
}
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");