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
This commit is contained in:
PatR
2024-02-08 07:04:15 -08:00
parent b37f1408d8
commit fd5526db7c
3 changed files with 51 additions and 14 deletions

View File

@@ -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

View File

@@ -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 <x,y>). 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,

View File

@@ -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)