vision vs gas cloud dissipation

Reported directly to dev-team:  vapor cloud dissipation didn't always
update vision properly.

Region removal affecting visibility needs to make two passes, the
first unblocking all no longer blocked spots, then the second deciding
whether spots are visible.

Attempting to do that in one pass was doing
| unblock <x1,y1>
| if cansee <x1,y1> whatever
| unblock <x2,y2>
| if cansee <x2,y2> whatever
and the cansee <x1,y1> test wasn't accurate if <x2,y2> blocked it and
hadn't been unblocked yet.

Testing with steam didn't seem to trigger the problem but with poison
vapor trail from green dragon breath did.  The order of evaporation
mattered too; sometimes the single pass unblocking plus vision-testing
worked ok by coincidence.
This commit is contained in:
PatR
2024-01-26 13:40:34 -08:00
parent 524ae27c99
commit 9993fa97ec
2 changed files with 44 additions and 25 deletions

View File

@@ -1,4 +1,4 @@
$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1361 $ $NHDT-Date: 1705357506 2024/01/15 22:25:06 $
$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1368 $ $NHDT-Date: 1706272459 2024/01/26 12:34:19 $
General Fixes and Modified Features
-----------------------------------
@@ -1355,6 +1355,8 @@ if a covetous monster tried to teleport next to the hero but the level was
if loadstone was unIDed but had been assigned a type name and you failed to
pick one up, the message referred to it as "gray stone" rather than
"stone called <assigned name>"
when a vision blocking gas cloud dissipated, the screen didn't necessarily
get updated to show newly visible locations in a timely fashion
Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 region.c $NHDT-Date: 1683832331 2023/05/11 19:12:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.81 $ */
/* NetHack 3.7 region.c $NHDT-Date: 1706272460 2024/01/26 12:34:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.88 $ */
/* Copyright (c) 1996 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */
@@ -332,22 +332,32 @@ remove_region(NhRegion *reg)
/* Update screen if necessary */
reg->ttl = -2L; /* for visible_region_at */
if (reg->visible)
for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
if (isok(x, y) && inside_region(reg, x, y)) {
/*if (!sobj_at(BOULDER, x, y))
unblock_point(x, y);*/
if (cansee(x, y))
newsym(x, y);
}
if (reg->visible) {
int pass;
/* need to process the region's spots twice, first unblocking all
locations which no longer block line-of-sight, then redrawing
spots within revised line-of-sight; skip second pass if blind */
for (pass = 1; pass <= (Blind ? 1 : 2); ++pass) {
for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
if (isok(x, y) && inside_region(reg, x, y)) {
if (pass == 1) {
if (!does_block(x, y, &levl[x][y]))
unblock_point(x, y);
} else { /* pass==2 */
if (cansee(x, y))
newsym(x, y);
}
}
}
}
free_region(reg);
}
/*
* Remove all regions and clear all related data (This must be down
* when changing level, for instance).
* Remove all regions and clear all related data. This must be done
* when changing level, for instance.
*/
void
clear_regions(void)
@@ -965,7 +975,7 @@ boolean
expire_gas_cloud(genericptr_t p1, genericptr_t p2 UNUSED)
{
NhRegion *reg;
int damage;
int damage, pass;
coordxy x, y;
reg = (NhRegion *) p1;
@@ -980,16 +990,22 @@ expire_gas_cloud(genericptr_t p1, genericptr_t p2 UNUSED)
return FALSE; /* THEN return FALSE, means "still there" */
}
/* The cloud no longer blocks vision. */
for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) {
for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) {
if (inside_region(reg, x, y)) {
if (!does_block(x, y, &levl[x][y]))
unblock_point(x, y);
if (u_at(x, y))
gg.gas_cloud_diss_within = TRUE;
if (cansee(x, y))
gg.gas_cloud_diss_seen++;
/* The cloud no longer blocks vision. cansee() checks shouldn't be made
until all blocked spots have been unblocked, so we need two passes */
for (pass = 1; pass <= (Blind ? 1 : 2); ++pass) {
for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) {
for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) {
if (inside_region(reg, x, y)) {
if (pass == 1) {
if (!does_block(x, y, &levl[x][y]))
unblock_point(x, y);
if (u_at(x, y))
gg.gas_cloud_diss_within = TRUE;
} else { /* pass==2 */
if (cansee(x, y))
gg.gas_cloud_diss_seen++;
}
}
}
}
}
@@ -1077,7 +1093,8 @@ is_hero_inside_gas_cloud(void)
int i;
for (i = 0; i < gn.n_regions; i++)
if (hero_inside(gr.regions[i]) && gr.regions[i]->inside_f == INSIDE_GAS_CLOUD)
if (hero_inside(gr.regions[i])
&& gr.regions[i]->inside_f == INSIDE_GAS_CLOUD)
return TRUE;
return FALSE;
}