From 9993fa97ecbd1fea417385ebdd5b0cc844ce5d31 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 26 Jan 2024 13:40:34 -0800 Subject: [PATCH] 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 | if cansee whatever | unblock | if cansee whatever and the cansee test wasn't accurate if 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. --- doc/fixes3-7-0.txt | 4 ++- src/region.c | 65 +++++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 0e9617183..2880203ad 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -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 " +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 diff --git a/src/region.c b/src/region.c index 36d186503..dac0bd116 100644 --- a/src/region.c +++ b/src/region.c @@ -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; }