]> granicus.if.org Git - nethack/commitdiff
fix #H2150 - discovering displacement when can't see its effect
authornethack.rankin <nethack.rankin>
Sat, 24 Jul 2010 03:53:52 +0000 (03:53 +0000)
committernethack.rankin <nethack.rankin>
Sat, 24 Jul 2010 03:53:52 +0000 (03:53 +0000)
     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.

doc/fixes35.0
src/do_wear.c

index fd10b0cd2f4d00d7d4c629487c3f3a413fdeec62..5a65e7e62e971c0cfa8fa99bd30817ea50b7d826 100644 (file)
@@ -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
index bd1fc5ea8a85eec9805bc96deacad4949ea8f033..650e93fdd1c4d08ff4ee5d5d88b1073daad19b60 100644 (file)
@@ -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. */
 
@@ -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);
@@ -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.
@@ -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))
@@ -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;
@@ -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))
@@ -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) {
@@ -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);
@@ -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:
@@ -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;
@@ -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:
@@ -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;
@@ -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);
@@ -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) */