Skip to content

Commit

Permalink
fix #H2150 - discovering displacement when can't see its effect
Browse files Browse the repository at this point in the history
     From a bug report, when putting on a
cloak of displacement you discovered what it was even if you were invisible
and unable to see invisible, hence couldn't see yourself.  It isn't exactly
clear what the hero sees of himself when displaced, but I think it makes
sense that you shouldn't discover the cloak when you can't see yourself,
which suggests that you shouldn't discover it when blind either.

     Discovering it after regaining sight, becoming able to see your
invisible self, or losing invisibility seemed complex and likely to be
bug-prone, so this patch leaves the cloak undiscovered in that situation.
But it does become discovered when taken off (provided that you can see
yourself by then) rather than waiting all the way 'til put back on again.

     Elven cloaks had a comparable issue.  I assume that stealthiness can
be perceived without being able to see yourself, but it shouldn't become
discovered when you're already stealthy from some other means.  (Elven
boots already behaved this way; now elven cloaks work like them.)

     Rings of stealth would never be auto-discovered.  Now they'll be
like elven cloaks and boots and be discovered if put on when not already
steathy or taken off and losing stealth.  In both cases, the ring has to
have its description known; if picked up when blind and still not seen
yet it won't become discovered even when you notice yourself gaining or
losing stealth.

     Not tested:  feedback given when a worn ring or cloak gets dipped
into a potion of polymorph and changes into or away from a stealth or
displacement conferring item.
  • Loading branch information
nethack.rankin committed Jul 24, 2010
1 parent bda97fb commit 8aecc66
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 24 deletions.
3 changes: 3 additions & 0 deletions doc/fixes35.0
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ improve the message sequencing when a thrown poisoned weapon loses is poison
attempting to open, close, or lock/unlock a door while confused or stunned
uses up a move regardless of whether direction choice finds a door
grammar fixes for vault guard messages given after player assigns guard a name
wearing cloak of displacement auto-discovered it even when hero couldn't see
wearing elven cloak auto-discovered it even when already stealthy
putting on ring of stealth never auto-discovered it


Platform- and/or Interface-Specific Fixes
Expand Down
125 changes: 101 additions & 24 deletions src/do_wear.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* NetHack 3.5 do_wear.c $Date$ $Revision$ */
/* SCCS Id: @(#)do_wear.c 3.5 2008/05/25 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */

Expand Down Expand Up @@ -31,6 +30,8 @@ static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP,
WORN_BOOTS, W_SWAPWEP, W_QUIVER, 0L };

STATIC_DCL void FDECL(on_msg, (struct obj *));
STATIC_DCL void FDECL(toggle_stealth, (struct obj *,long,BOOLEAN_P));
STATIC_DCL void FDECL(toggle_displacement, (struct obj *,long,BOOLEAN_P));
STATIC_PTR int NDECL(Armor_on);
STATIC_PTR int NDECL(Boots_on);
STATIC_PTR int NDECL(Cloak_on);
Expand Down Expand Up @@ -79,6 +80,74 @@ struct obj *otmp;
}
}

/* starting equipment gets auto-worn at beginning of new game,
and we don't want stealth or displacement feedback then */
static boolean initial_don = FALSE; /* manipulated in set_wear() */

/* putting on or taking off an item which confers stealth;
give feedback and discover it iff stealth state is changing */
STATIC_OVL
void
toggle_stealth(obj, oldprop, on)
struct obj *obj;
long oldprop; /* prop[].extrinsic, with obj->owornmask stripped by caller */
boolean on;
{
if (on ? initial_don : context.takeoff.cancelled_don) return;

if (!oldprop && /* extrinsic stealth from something else */
!HStealth && /* intrinsic stealth */
!BStealth) { /* stealth blocked by something */
if (obj->otyp == RIN_STEALTH)
learnring(obj, TRUE);
else
makeknown(obj->otyp);

if (on) {
if (!is_boots(obj))
You("move very quietly.");
else if (Levitation || Flying)
You("float imperceptibly.");
else
You("walk very quietly.");
} else {
You("sure are noisy.");
}
}
}

/* putting on or taking off an item which confers displacement;
give feedback and discover it iff displacement state is changing *and*
hero is able to see self (or sense monsters) */
STATIC_OVL
void
toggle_displacement(obj, oldprop, on)
struct obj *obj;
long oldprop; /* prop[].extrinsic, with obj->owornmask stripped by caller */
boolean on;
{
if (on ? initial_don : context.takeoff.cancelled_don) return;

if (!oldprop && /* extrinsic displacement from something else */
!(u.uprops[DISPLACED].intrinsic) && /* (theoretical) */
!(u.uprops[DISPLACED].blocked) && /* (also theoretical) */
/* we don't use canseeself() here because it augments vision
with touch, which isn't appropriate for deciding whether
we'll notice that monsters have trouble spotting the hero */
((!Blind && /* see anything */
!u.uswallow && /* see surroundings */
!Invisible) || /* see self */
/* actively sensing nearby monsters via telepathy or extended
monster detection overrides vision considerations because
hero also senses self in this situation */
(Unblind_telepat || (Blind_telepat && Blind) || Detect_monsters))) {
makeknown(obj->otyp);

You_feel("that monsters%s have difficulty pinpointing your location.",
on ? "" : " no longer");
}
}

/*
* The Type_on() functions should be called *after* setworn().
* The Type_off() functions call setworn() themselves.
Expand Down Expand Up @@ -114,13 +183,7 @@ Boots_on(VOID_ARGS)
}
break;
case ELVEN_BOOTS:
if (!oldprop && !HStealth && !BStealth) {
makeknown(uarmf->otyp);
if (Levitation || Flying)
You("float imperceptibly.");
else
You("walk very quietly.");
}
toggle_stealth(uarmf, oldprop, TRUE);
break;
case FUMBLE_BOOTS:
if (!oldprop && !(HFumbling & ~TIMEOUT))
Expand All @@ -141,7 +204,8 @@ Boots_on(VOID_ARGS)
int
Boots_off(VOID_ARGS)
{
int otyp = uarmf->otyp;
struct obj *otmp = uarmf;
int otyp = otmp->otyp;
long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_BOOTS;

context.takeoff.mask &= ~W_ARMF;
Expand Down Expand Up @@ -170,11 +234,7 @@ Boots_off(VOID_ARGS)
}
break;
case ELVEN_BOOTS:
if (!oldprop && !HStealth && !BStealth &&
!context.takeoff.cancelled_don) {
makeknown(otyp);
You("sure are noisy.");
}
toggle_stealth(otmp, oldprop, FALSE);
break;
case FUMBLE_BOOTS:
if (!oldprop && !(HFumbling & ~TIMEOUT))
Expand Down Expand Up @@ -205,17 +265,21 @@ Cloak_on(VOID_ARGS)
u.uprops[objects[uarmc->otyp].oc_oprop].extrinsic & ~WORN_CLOAK;

switch(uarmc->otyp) {
case ELVEN_CLOAK:
case CLOAK_OF_PROTECTION:
case CLOAK_OF_DISPLACEMENT:
makeknown(uarmc->otyp);
break;
case ORCISH_CLOAK:
case DWARVISH_CLOAK:
case CLOAK_OF_MAGIC_RESISTANCE:
case ROBE:
case LEATHER_CLOAK:
break;
case CLOAK_OF_PROTECTION:
makeknown(uarmc->otyp);
break;
case ELVEN_CLOAK:
toggle_stealth(uarmc, oldprop, TRUE);
break;
case CLOAK_OF_DISPLACEMENT:
toggle_displacement(uarmc, oldprop, TRUE);
break;
case MUMMY_WRAPPING:
/* Note: it's already being worn, so we have to cheat here. */
if ((HInvis || EInvis || pm_invisible(youmonst.data)) && !Blind) {
Expand Down Expand Up @@ -250,23 +314,28 @@ Cloak_on(VOID_ARGS)
int
Cloak_off(VOID_ARGS)
{
int otyp = uarmc->otyp;
struct obj *otmp = uarmc;
int otyp = otmp->otyp;
long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_CLOAK;

context.takeoff.mask &= ~W_ARMC;
/* For mummy wrapping, taking it off first resets `Invisible'. */
setworn((struct obj *)0, W_ARMC);
switch (otyp) {
case ELVEN_CLOAK:
case ORCISH_CLOAK:
case DWARVISH_CLOAK:
case CLOAK_OF_PROTECTION:
case CLOAK_OF_MAGIC_RESISTANCE:
case CLOAK_OF_DISPLACEMENT:
case OILSKIN_CLOAK:
case ROBE:
case LEATHER_CLOAK:
break;
case ELVEN_CLOAK:
toggle_stealth(otmp, oldprop, FALSE);
break;
case CLOAK_OF_DISPLACEMENT:
toggle_displacement(otmp, oldprop, FALSE);
break;
case MUMMY_WRAPPING:
if (Invis && !Blind) {
newsym(u.ux,u.uy);
Expand Down Expand Up @@ -763,7 +832,6 @@ register struct obj *obj;
case RIN_TELEPORTATION:
case RIN_REGENERATION:
case RIN_SEARCHING:
case RIN_STEALTH:
case RIN_HUNGER:
case RIN_AGGRAVATE_MONSTER:
case RIN_POISON_RESISTANCE:
Expand All @@ -779,6 +847,9 @@ register struct obj *obj;
case RIN_SUSTAIN_ABILITY:
case MEAT_RING:
break;
case RIN_STEALTH:
toggle_stealth(obj, oldprop, TRUE);
break;
case RIN_WARNING:
see_monsters();
break;
Expand Down Expand Up @@ -871,7 +942,6 @@ boolean gone;
case RIN_TELEPORTATION:
case RIN_REGENERATION:
case RIN_SEARCHING:
case RIN_STEALTH:
case RIN_HUNGER:
case RIN_AGGRAVATE_MONSTER:
case RIN_POISON_RESISTANCE:
Expand All @@ -887,6 +957,9 @@ boolean gone;
case RIN_SUSTAIN_ABILITY:
case MEAT_RING:
break;
case RIN_STEALTH:
toggle_stealth(obj, (EStealth & ~mask), FALSE);
break;
case RIN_WARNING:
see_monsters();
break;
Expand Down Expand Up @@ -1046,6 +1119,8 @@ void
set_wear(obj)
struct obj *obj; /* if null, do all worn items; otherwise just obj itself */
{
initial_don = !obj;

if (!obj ? ublindf != 0 : (obj == ublindf)) (void) Blindf_on(ublindf);
if (!obj ? uright != 0 : (obj == uright)) (void) Ring_on(uright);
if (!obj ? uleft != 0 : (obj == uleft)) (void) Ring_on(uleft);
Expand All @@ -1060,6 +1135,8 @@ struct obj *obj; /* if null, do all worn items; otherwise just obj itself */
if (!obj ? uarmg != 0 : (obj == uarmg)) (void) Gloves_on();
if (!obj ? uarmh != 0 : (obj == uarmh)) (void) Helmet_on();
if (!obj ? uarms != 0 : (obj == uarms)) (void) Shield_on();

initial_don = FALSE;
}

/* check whether the target object is currently being put on (or taken off) */
Expand Down

0 comments on commit 8aecc66

Please sign in to comment.