From fd5526db7c30239c9416240e6355f1d9ffb8e10c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 8 Feb 2024 07:04:15 -0800 Subject: [PATCH] fix for #H9430 and github issue #1207 - gas clouds Reported yesterday as issue #1207 by elunna and over four years ago in #H9430: monsters in gas clouds that should be shown by Warning aren't. And in some discussion of #H9430 back then: monsters adjacent to the hero while in gas clouds aren't shown on the map, but combat and other interaction describes them as if they were. There have been changes since then--to prevent seeing things on the far side of gas clouds as if there were no clouds in the way--but the basic problems with warning and adjacency weren't addressed. This is a band-aid (tm) that probably makes things livable. Don't allow gas region display to override monsters that are sensed via warning or when the hero is next to them. That part doesn't work correctly if the hero isn't blind and is inside the cloud while the monster is adjacent but outside. I think it will take more than a band-aid to deal with that sensibly. Closes #1207 --- doc/fixes3-7-0.txt | 5 +++++ src/display.c | 48 +++++++++++++++++++++++++++++++++++++--------- src/vision.c | 12 +++++++----- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 4727c5b06..7fdc7c9da 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1861,6 +1861,11 @@ if an amulet of flying gets stolen while hero is over lava without other poison gas breath from green dragon or iron golem that hit and was reflected left target enveloped in a gas cloud (reflection now takes precedence; somewhat odd though: gas that misses still leaves target enveloped) +Warning didn't show nearby monsters who were inside poison gas/steam/smoke + regions +map didn't show adjacent monsters if they were inside a gas region unless + they were seen via telepathy or extended monster detection, but they + were described as if visible in messages (combat, for instance) Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/display.c b/src/display.c index c2dc9b74d..6486fc6d2 100644 --- a/src/display.c +++ b/src/display.c @@ -128,6 +128,7 @@ static void display_monster(coordxy, coordxy, struct monst *, int, boolean) NONNULLPTRS; static int swallow_to_glyph(int, int); static void display_warning(struct monst *) NONNULLARG1; +static boolean next_to_gas(struct monst *) NONNULLARG1; static int check_pos(coordxy, coordxy, int); static void get_bkglyph_and_framecolor(coordxy x, coordxy y, int *, uint32 *); @@ -650,6 +651,20 @@ warning_of(struct monst *mon) return wl; } +/* returns True if mon is adjacent and would be seen if vision wasn't + blocked by being in a gas cloud (implicit; caller has already checked) */ +static boolean +next_to_gas(struct monst *mon) +{ + int r = (u.xray_range > 1) ? (u.xray_range + 1) : 2; + + if (distu(mon->mx, mon->my) > r * (r - 1)) + return FALSE; + if (!_mon_visible(mon) && !_see_with_infrared(mon)) + return FALSE; + return TRUE; +} + /* map or status window might not be ready for output during level creation or game restoration (something like u.usteed which affects display of the hero and also a status condition might not be set up yet) */ @@ -907,14 +922,29 @@ newsym(coordxy x, coordxy y) * Normal region shown only on accessible positions, but * poison clouds and steam clouds also shown above lava, * pools and moats. - * However, sensed monsters take precedence over all regions. + * However, sensed monsters (via detection or telepathy or + * warning) take precedence over all regions. + * Adjacent monsters also take precedence if they would be + * seen when there's no gas region. + * + * FIXME: + * The adjacency checking here works when the hero is outside + * the region and the monster is inside, and when they're both + * inside, but not when the hero is inside and monster outside + * (because 'reg' will be Null for mon's ). Checking + * whether hero is inside a region for every newsym() seems + * excessive. The hero is usually blind when in a gas cloud + * so the problem is less noticeable then it might otherwise be. */ - if (reg - && (ACCESSIBLE(lev->typ) - || (reg->visible && is_pool_or_lava(x, y))) - && (!mon || worm_tail || !sensemon(mon))) { - show_region(reg, x, y); - return; + if (reg && (ACCESSIBLE(lev->typ) + || (reg->visible && is_pool_or_lava(x, y)))) { + if (mon && !worm_tail && (sensemon(mon) || mon_warning(mon) + || next_to_gas(mon))) { + ; /* skip region; the 'if' is more comphrehensible this way */ + } else { + show_region(reg, x, y); + return; + } } if (u_at(x, y)) { @@ -944,7 +974,7 @@ newsym(coordxy x, coordxy y) display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail); - } else if (mon && mon_warning(mon) && !is_worm_tail(mon)) { + } else if (mon && mon_warning(mon) && !worm_tail) { display_warning(mon); } else if (glyph_is_invisible(lev->glyph)) { map_invisible(x, y); @@ -963,7 +993,7 @@ newsym(coordxy x, coordxy y) && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) || (see_with_infrared(mon) && mon_visible(mon)))) != 0 - || Detect_monsters)) { + || (Detect_monsters && !is_worm_tail(mon)))) { /* Seen or sensed monsters are printed every time. This also gets rid of any invisibility glyph. */ display_monster(x, y, mon, see_it ? 0 : DETECTED, diff --git a/src/vision.c b/src/vision.c index 004a9d5eb..adc66230f 100644 --- a/src/vision.c +++ b/src/vision.c @@ -134,7 +134,10 @@ vision_init(void) /* * does_block() * - * Returns true if something at (x,y) blocks sight. + * Returns 0 if nothing at (x,y) blocks sight, 1 if anything other than + * an opaque region (gas cloud rather than CLOUD terrain) blocks sight, + * or 2 if an opaque region potions sight. [At present, the rest of the + * code makes no distinction between 1 and 2, just between 0 and non-0.] */ int does_block(int x, int y, struct rm *lev) @@ -158,8 +161,7 @@ does_block(int x, int y, struct rm *lev) #ifdef DEBUG if (gs.seethru != 1) { #endif - if (lev->typ == CLOUD || IS_WATERWALL(lev->typ) - || lev->typ == LAVAWALL + if (lev->typ == CLOUD || IS_WATERWALL(lev->typ) || lev->typ == LAVAWALL || (Underwater && is_moat(x, y))) return 1; #ifdef DEBUG @@ -181,7 +183,7 @@ does_block(int x, int y, struct rm *lev) #endif /* Clouds (poisonous or not) block light. */ if (visible_region_at(x, y)) - return 1; + return 2; #ifdef DEBUG } /* gs.seethru */ #endif @@ -929,7 +931,7 @@ unblock_point(int x, int y) * + If you are a blocked spot, then your right will point to the * right-most blocked spot to your right that is connected to you. * This means that a right-edge (a blocked spot that has an open - * spot on its right) will point to itself. + * spot on its right) will point to itself. */ static void dig_point(int row, int col)