]> granicus.if.org Git - nethack/commitdiff
fix #H7065 - clairvoyance shows trap over monsters
authorPatR <rankin@nethack.org>
Sun, 11 Nov 2018 22:28:54 +0000 (14:28 -0800)
committerPatR <rankin@nethack.org>
Sun, 11 Nov 2018 22:28:54 +0000 (14:28 -0800)
and over the hero.  3.6.0's clairvoyance tried to show things in
a non-standard sequence, which was intentional but had unintended
side-effects like the disappearing monsters complained about in the
report.  To make it work as intended would have required --More--
whenever it kicked in, which is much too intrusive when it happens
every N turns rather than when explicitly casting the spell.

Redo it substantially, and give preference to monsters over objects,
objects over traps, and traps over underlying terrain like normal
vision-based display does.  It now detects all monsters within its
bounding box but shows ones which aren't directly in view as
"unseen monster" unless via spell cast at skilled or expert, or at
basic when also having intrinsic clairvoyance.

doc/fixes36.2
src/detect.c
src/drawing.c
src/pager.c

index 2de78d988c5f66c2b2c147a59335c7f25695ad5a..fb2cf76b0deb528eddc59481aa6f30b03f45c0b5 100644 (file)
@@ -194,6 +194,8 @@ avoid potential buffer overflow if object with very long name knocks other
        objects down stairs when dropped, thrown, or kicked there
 #wizintrinsic for 'flying' didn't update status line when flying ended
 #wizintrinsic for 'warn_of_mon' didn't set any type of monster (now grid bugs)
+clairvoyance would show trap instead of a monster on/in that trap, which was
+       intentional, but when clairvoyance finished the monster wasn't shown
 
 
 Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository
index ca6eda709aadb148485f64d341ab33e24f29a925..57ee916ceb88c7f07be73e8301229ed6300726f8 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 detect.c        $NHDT-Date: 1541144458 2018/11/02 07:40:58 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */
+/* NetHack 3.6 detect.c        $NHDT-Date: 1522891623 2018/04/05 01:27:03 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2018. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -1300,25 +1300,82 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */
 {
     register int zx, zy;
     struct monst *mtmp;
+    struct obj *otmp;
+    long save_EDetect_mons;
+    char save_viz_uyux;
     boolean unconstrained, refresh = FALSE, mdetected = FALSE,
-            extended = (sobj && sobj->blessed);
-    int lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
+            /* fake spellbook 'sobj' implies hero has cast the spell;
+               when book is blessed, casting is skilled or expert level;
+               if already clairvoyant, non-skilled spell acts like skilled */
+            extended = (sobj && (sobj->blessed || Clairvoyant));
+    int newglyph, oldglyph,
+        lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
         hi_y = ((u.uy + 6 >= ROWNO) ? ROWNO - 1 : u.uy + 6),
         lo_x = ((u.ux - 9 < 1) ? 1 : u.ux - 9), /* avoid column 0 */
         hi_x = ((u.ux + 10 >= COLNO) ? COLNO - 1 : u.ux + 10),
         ter_typ = TER_DETECT | TER_MAP | TER_TRP | TER_OBJ;
 
+    /*
+     * 3.6.0 attempted to emphasize terrain over transient map
+     * properties (monsters and objects) but that led to problems.
+     * Notably, known trap would be displayed instead of a monster
+     * on or in it and then the display remained that way after the
+     * clairvoyant snapshot finished.  That could have been fixed by
+     * issuing --More-- and then regular vision update, but we want
+     * to avoid that when having a clairvoyant episode every N turns
+     * (from donating to a temple priest or by carrying the Amulet).
+     * Unlike when casting the spell, it is much too intrustive when
+     * in the midst of walking around or combatting monsters.
+     *
+     * For 3.6.2, show terrain, then object, then monster like regular
+     * map updating, except in this case the map locations get marked
+     * as seen from every direction rather than just from direction of
+     * hero.  Skilled spell marks revealed objects as 'seen up close'
+     * (but for piles, only the top item) and shows monsters as if
+     * detected.  Non-skilled and timed clairvoyance reveals non-visible
+     * monsters as 'remembered, unseen'.
+     */
+
+    /* if hero is engulfed, show engulfer at <u.ux,u.uy> */
+    save_viz_uyux = viz_array[u.uy][u.ux];
+    if (u.uswallow)
+        viz_array[u.uy][u.ux] |= IN_SIGHT; /* <x,y> are reversed to [y][x] */
+    save_EDetect_mons = EDetect_monsters;
+    /* for skilled spell, getpos() scanning of the map will display all
+       monsters within range; otherwise, "unseen creature" will be shown */
+    EDetect_monsters |= I_SPECIAL;
     unconstrained = unconstrain_map();
     for (zx = lo_x; zx <= hi_x; zx++)
         for (zy = lo_y; zy <= hi_y; zy++) {
+            oldglyph = glyph_at(zx, zy);
+            /* this will remove 'remembered, unseen mon' (and objects) */
             show_map_spot(zx, zy);
-
-            if (extended && (mtmp = m_at(zx, zy)) != 0
+            /* if there are any objects here, see the top one */
+            if (OBJ_AT(zx, zy)) {
+                /* not vobj_at(); this is not vision-based access;
+                   unlike object detection, we don't notice buried items */
+                otmp = level.objects[zx][zy];
+                if (extended)
+                    otmp->dknown = 1;
+                map_object(otmp, TRUE);
+            }
+            /* if there is a monster here, see or detect it,
+               possibly as "remembered, unseen monster" */
+            if ((mtmp = m_at(zx, zy)) != 0
                 && mtmp->mx == zx && mtmp->my == zy) { /* skip worm tails */
-                int oldglyph = glyph_at(zx, zy);
-
-                map_monst(mtmp, FALSE);
-                if (glyph_at(zx, zy) != oldglyph)
+                /* if we're going to offer browse_map()/getpos() scanning of
+                   the map and we're not doing extended/blessed clairvoyance
+                   (hence must be swallowed or underwater), show "unseen
+                   creature" unless map already displayed a monster here */
+                if ((unconstrained || !level.flags.hero_memory)
+                    && !extended && (zx != u.ux || zy != u.uy)
+                    && !glyph_is_monster(oldglyph))
+                    map_invisible(zx, zy);
+                else
+                    map_monst(mtmp, FALSE);
+                newglyph = glyph_at(zx, zy);
+                if (extended && newglyph != oldglyph
+                    && !glyph_is_invisible(newglyph))
                     mdetected = TRUE;
             }
         }
@@ -1331,13 +1388,26 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */
         You("sense your surroundings.");
         if (extended || glyph_is_monster(glyph_at(u.ux, u.uy)))
             ter_typ |= TER_MON;
-        if (extended)
-            EDetect_monsters |= I_SPECIAL;
         browse_map(ter_typ, "anything of interest");
-        EDetect_monsters &= ~I_SPECIAL;
         refresh = TRUE;
     }
     reconstrain_map();
+    EDetect_monsters = save_EDetect_mons;
+    viz_array[u.uy][u.ux] = save_viz_uyux;
+
+    /* replace monsters with remembered,unseen monster, then run
+       see_monsters() to update visible ones and warned-of ones */
+    for (zx = lo_x; zx <= hi_x; zx++)
+        for (zy = lo_y; zy <= hi_y; zy++) {
+            if (zx == u.ux && zy == u.uy)
+                continue;
+            newglyph = glyph_at(zx, zy);
+            if (glyph_is_monster(newglyph)
+                && glyph_to_mon(newglyph) != PM_LONG_WORM_TAIL)
+                map_invisible(zx, zy);
+        }
+    see_monsters();
+
     if (refresh)
         docrt();
 }
index d81ffa2c9d7ba5971c0a5ce624a96f6589717525..68fdebdadb76f4f79f29b7a372be806346a2b54d 100644 (file)
@@ -26,7 +26,8 @@ nhsym l_syms[SYM_MAX] = DUMMY;   /* loaded symbols          */
 nhsym r_syms[SYM_MAX] = DUMMY;   /* rogue symbols           */
 
 nhsym warnsyms[WARNCOUNT] = DUMMY; /* the current warning display symbols */
-const char invisexplain[] = "remembered, unseen, creature";
+const char invisexplain[] = "remembered, unseen, creature",
+           altinvisexplain[] = "unseen creature"; /* for clairvoyance */
 
 /* Default object class symbols.  See objclass.h.
  * {symbol, name, explain}
index c1824d2f867b811bc952489106bd1741375ee3ad..305cfdc5a883a38a4358c35f875eb2a2e693054d 100644 (file)
@@ -895,12 +895,17 @@ struct permonst **for_supplement;
     }
 
     if (sym == DEF_INVISIBLE) {
+        extern const char altinvisexplain[]; /* drawing.c */
+        /* for active clairvoyance, use alternate "unseen creature" */
+        boolean usealt = (EDetect_monsters & I_SPECIAL) != 0L;
+        const char *unseen_explain = !usealt ? invisexplain : altinvisexplain;
+
         if (!found) {
-            Sprintf(out_str, "%s%s", prefix, an(invisexplain));
-            *firstmatch = invisexplain;
+            Sprintf(out_str, "%s%s", prefix, an(unseen_explain));
+            *firstmatch = unseen_explain;
             found++;
         } else {
-            found += append_str(out_str, an(invisexplain));
+            found += append_str(out_str, an(unseen_explain));
         }
     }