From ab7fb9360e19d28707bb57cca36d1f3a5808721e Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 11 Nov 2018 14:28:54 -0800 Subject: [PATCH] fix #H7065 - clairvoyance shows trap over monsters 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 | 2 ++ src/detect.c | 94 ++++++++++++++++++++++++++++++++++++++++++++------- src/drawing.c | 3 +- src/pager.c | 11 ++++-- 4 files changed, 94 insertions(+), 16 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 2de78d988..fb2cf76b0 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -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 diff --git a/src/detect.c b/src/detect.c index ca6eda709..57ee916ce 100644 --- a/src/detect.c +++ b/src/detect.c @@ -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 */ + save_viz_uyux = viz_array[u.uy][u.ux]; + if (u.uswallow) + viz_array[u.uy][u.ux] |= IN_SIGHT; /* 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(); } diff --git a/src/drawing.c b/src/drawing.c index d81ffa2c9..68fdebdad 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -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} diff --git a/src/pager.c b/src/pager.c index c1824d2f8..305cfdc5a 100644 --- a/src/pager.c +++ b/src/pager.c @@ -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)); } } -- 2.40.0