From 218c0d4a3ba03a296139e3c08255419e28ad0aa2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 31 Jan 2022 19:00:15 +0200 Subject: [PATCH] Stinking clouds block line of sight ... you will also get a message when a seen stinking cloud or the one surrounding the hero dissipates. Original feature comes from Fourk, but this version (with some minor changes) comes from xnethack by copperwater --- doc/fixes3-7-0.txt | 1 + include/decl.h | 2 ++ include/extern.h | 1 + src/decl.c | 2 ++ src/region.c | 35 ++++++++++++++++++++++++++++++++--- src/vision.c | 14 ++++++++++++-- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 507945cb7..98289dcfd 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -762,6 +762,7 @@ when already at level 30 and gaining another level--which doesn't increase don't stop running when next to a peaceful, unless it blocks the way mindless monsters shouldn't cringe stepping on squeaky boards falling down a hole or trapdoor will cause damage proportional to fall height +stinking gas clouds block line-of-sight Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/include/decl.h b/include/decl.h index 3f18f9db6..a46b0b8a8 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1113,6 +1113,8 @@ struct instance_globals { NhRegion **regions; int n_regions; int max_regions; + boolean gas_cloud_diss_within; + int gas_cloud_diss_seen; /* restore.c */ int n_ids_mapped; diff --git a/include/extern.h b/include/extern.h index e855fddb1..1285bf5e1 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2220,6 +2220,7 @@ extern void split_rects(NhRect *, NhRect *); /* ## region.c ### */ +extern boolean inside_region(NhRegion *, int, int); extern void clear_regions(void); extern void run_regions(void); extern boolean in_out_region(xchar, xchar); diff --git a/src/decl.c b/src/decl.c index 12bf56252..8859919bc 100644 --- a/src/decl.c +++ b/src/decl.c @@ -577,6 +577,8 @@ const struct instance_globals g_init = { NULL, /* regions */ 0, /* n_regions */ 0, /* max_regions */ + FALSE, /* gas_cloud_diss_within */ + 0, /* gas_cloud_diss_seen */ /* restore.c */ 0, /* n_ids_mapped */ diff --git a/src/region.c b/src/region.c index fbf5572bb..bcae7c0d8 100644 --- a/src/region.c +++ b/src/region.c @@ -15,7 +15,6 @@ boolean inside_gas_cloud(genericptr, genericptr); boolean expire_gas_cloud(genericptr, genericptr); boolean inside_rect(NhRect *, int, int); -boolean inside_region(NhRegion *, int, int); NhRegion *create_region(NhRect *, int); void add_rect_to_reg(NhRegion *, NhRect *); void add_mon_to_reg(NhRegion *, struct monst *); @@ -290,13 +289,16 @@ add_region(NhRegion *reg) /* Check for monsters inside the region */ for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { + boolean is_inside = inside_region(reg, i, j); + /* Some regions can cross the level boundaries */ if (!isok(i, j)) continue; - if (MON_AT(i, j) && inside_region(reg, i, j)) + if (is_inside && MON_AT(i, j)) add_mon_to_reg(reg, g.level.monsters[i][j]); if (reg->visible) { - /*block_point(i, j);*/ + if (is_inside) + block_point(i, j); if (cansee(i, j)) newsym(i, j); } @@ -371,6 +373,10 @@ run_regions(void) register int i, j, k; int f_indx; + /* reset some messaging variables */ + g.gas_cloud_diss_within = FALSE; + g.gas_cloud_diss_seen = 0; + /* End of life ? */ /* Do it backward because the array will be modified */ for (i = g.n_regions - 1; i >= 0; i--) { @@ -407,6 +413,13 @@ run_regions(void) } } } + + if (g.gas_cloud_diss_within) + pline_The("gas cloud around you dissipates."); + if (g.gas_cloud_diss_seen) + You_see("%s dissipate.", + g.gas_cloud_diss_seen == 1 + ? "a gas cloud" : "some gas clouds"); } /* @@ -952,6 +965,7 @@ expire_gas_cloud(genericptr_t p1, genericptr_t p2 UNUSED) { NhRegion *reg; int damage; + xchar x, y; reg = (NhRegion *) p1; damage = reg->arg.a_int; @@ -964,6 +978,21 @@ expire_gas_cloud(genericptr_t p1, genericptr_t p2 UNUSED) reg->ttl = 2L; /* Here's the trick : reset ttl */ 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 (x == u.ux && y == u.uy) + g.gas_cloud_diss_within = TRUE; + if (cansee(x, y)) + g.gas_cloud_diss_seen++; + } + } + } + return TRUE; /* OK, it's gone, you can free it! */ } diff --git a/src/vision.c b/src/vision.c index f819ecde6..de93a8ba2 100644 --- a/src/vision.c +++ b/src/vision.c @@ -134,14 +134,14 @@ vision_init(void) /* * does_block() * - * Returns true if the level feature, object, or monster at (x,y) blocks - * sight. + * Returns true if something at (x,y) blocks sight. */ int does_block(int x, int y, struct rm *lev) { struct obj *obj; struct monst *mon; + int i; /* Features that block . . */ if (IS_ROCK(lev->typ) || lev->typ == TREE @@ -163,6 +163,16 @@ does_block(int x, int y, struct rm *lev) && is_lightblocker_mappear(mon)) return 1; + /* Clouds (poisonous or not) block light. */ + for (i = 0; i < g.n_regions; i++) { + /* Ignore regions with ttl == 0 - expire_gas_cloud must unblock its + * points prior to being removed itself. */ + if (g.regions[i]->ttl > 0 && g.regions[i]->visible + && inside_region(g.regions[i], x, y)) { + return 1; + } + } + return 0; }