From bf47cc878eb1b9a12c5339d1bfc8b8c547841812 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 12 Jun 2023 15:07:34 -0700 Subject: [PATCH] fountain and sink bookkeeping This replaces most of commit 0ca2af4d8bcf8497f1916c6ac6d46361eafac28e from a couple of days ago with something more robust. That change actually introduced redundant code that caused fountain and/or sink count to be off instead of preventing it. Revise set_levltyp() to update level.flags.nfountains and level.flags.nsinks if setting the type to or from fountain or sink. A bunch of places that were setting levl[x][y].typ directly needed to be revised to use set_levltyp() instead. set_levltyp() itself hadn't been updated to handle LAVAWALL (to force such to be lit). --- include/extern.h | 1 + include/rm.h | 1 + src/do.c | 60 ++++++++++++++++++++++++++---------------------- src/fountain.c | 17 +++++++------- src/mklev.c | 29 +++++++++++++++++++---- src/mkmaze.c | 37 ++++++++++++++++++++--------- src/objnam.c | 16 +++---------- src/sp_lev.c | 24 ++----------------- 8 files changed, 100 insertions(+), 85 deletions(-) diff --git a/include/extern.h b/include/extern.h index 0c982c6be..2ede94ff9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1399,6 +1399,7 @@ extern void add_subroom(struct mkroom *, int, int, int, int, boolean, schar, extern void free_luathemes(boolean); extern void makecorridors(void); extern void add_door(coordxy, coordxy, struct mkroom *); +extern void count_level_features(void); extern void clear_level_structures(void); extern void level_finalize_topology(void); extern void mklev(void); diff --git a/include/rm.h b/include/rm.h index bc02bc8aa..1ee55cbcc 100644 --- a/include/rm.h +++ b/include/rm.h @@ -96,6 +96,7 @@ enum levl_typ_types { #define ZAP_POS(typ) ((typ) >= POOL) #define SPACE_POS(typ) ((typ) > DOOR) #define IS_POOL(typ) ((typ) >= POOL && (typ) <= DRAWBRIDGE_UP) +#define IS_LAVA(typ) ((typ) == LAVAPOOL || (typ) == LAVAWALL) #define IS_THRONE(typ) ((typ) == THRONE) #define IS_FOUNTAIN(typ) ((typ) == FOUNTAIN) #define IS_SINK(typ) ((typ) == SINK) diff --git a/src/do.c b/src/do.c index 88b14e135..ef0ed5377 100644 --- a/src/do.c +++ b/src/do.c @@ -363,27 +363,26 @@ polymorph_sink(void) return; sinklooted = levl[u.ux][u.uy].looted != 0; - gl.level.flags.nsinks--; - levl[u.ux][u.uy].doormask = 0; /* levl[][].flags */ + /* gl.level.flags.nsinks--; // set_levltyp() will update this */ + levl[u.ux][u.uy].flags = 0; switch (rn2(4)) { default: case 0: sym = S_fountain; - levl[u.ux][u.uy].typ = FOUNTAIN; + set_levltyp(u.ux, u.uy, FOUNTAIN); /* updates level.flags.nfountains */ levl[u.ux][u.uy].blessedftn = 0; if (sinklooted) SET_FOUNTAIN_LOOTED(u.ux, u.uy); - gl.level.flags.nfountains++; break; case 1: sym = S_throne; - levl[u.ux][u.uy].typ = THRONE; + set_levltyp(u.ux, u.uy, THRONE); if (sinklooted) levl[u.ux][u.uy].looted = T_LOOTED; break; case 2: sym = S_altar; - levl[u.ux][u.uy].typ = ALTAR; + set_levltyp(u.ux, u.uy, ALTAR); /* 3.6.3: this used to pass 'rn2(A_LAWFUL + 2) - 1' to Align2amask() but that evaluates its argument more than once */ algn = rn2(3) - 1; /* -1 (A_Cha) or 0 (A_Neu) or +1 (A_Law) */ @@ -392,7 +391,7 @@ polymorph_sink(void) break; case 3: sym = S_room; - levl[u.ux][u.uy].typ = ROOM; + set_levltyp(u.ux, u.uy, ROOM); make_grave(u.ux, u.uy, (char *) 0); if (levl[u.ux][u.uy].typ == GRAVE) sym = S_grave; @@ -413,29 +412,36 @@ static boolean teleport_sink(void) { coordxy cx, cy; - int cnt = 0; - struct trap *trp; - struct engr *eng; + unsigned alreadylooted; + int trycnt = 0; do { - cx = rnd(COLNO - 1); - cy = rn2(ROWNO); - trp = t_at(cx, cy); - eng = engr_at(cx, cy); - } while ((levl[cx][cy].typ != ROOM || trp || eng || cansee(cx, cy)) - && cnt++ < 200); +#if 0 /* this isn't incorrect but it is extremely unlikely that spots + * on the level's edge will be ROOM so picking such wastes tries */ + cx = rnd(COLNO - 1); /* 1..COLNO-1 */ + cy = rn2(ROWNO); /* 0..ROWNO-1 */ +#else /* use this instead */ + cx = 1 + rnd((COLNO - 1) - 2); /* 2..COLNO-2 */ + cy = 1 + rn2(ROWNO - 2); /* 1..ROWNO-2 */ +#endif + if (levl[cx][cy].typ == ROOM + && !t_at(cx, cy) && !engr_at(cx, cy) + && (!cansee(cx, cy) || distu(cx, cy) > 3 * 3)) { + /* this ends up having set_levltyp() count all sinks and + fountains on the level twice but that is not a problem */ + alreadylooted = levl[u.ux][u.uy].looted; + /* remove old sink */ + set_levltyp(u.ux, u.uy, ROOM); /* was SINK so updates nsinks */ + levl[u.ux][u.uy].looted = 0; + newsym(u.ux, u.uy); + /* create sink at new position */ + set_levltyp(cx, cy, SINK); /* now SINK so also updates nsinks */ + levl[cx][cy].looted = alreadylooted ? 1 : 0; + newsym(cx, cy); + return TRUE; + } + } while (++trycnt < 200); - if (levl[cx][cy].typ == ROOM && !trp && !eng) { - /* create sink at new position */ - levl[cx][cy].typ = SINK; - levl[cx][cy].looted = levl[u.ux][u.uy].looted; - newsym(cx, cy); - /* remove old sink */ - levl[u.ux][u.uy].typ = ROOM; - levl[u.ux][u.uy].looted = 0; - newsym(u.ux, u.uy); - return TRUE; - } return FALSE; } diff --git a/src/fountain.c b/src/fountain.c index 729c6ba16..13096f095 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -148,7 +148,8 @@ gush(coordxy x, coordxy y, genericptr_t poolcnt) pline("Water gushes forth from the overflowing fountain!"); /* Put a pool at x, y */ - levl[x][y].typ = POOL, levl[x][y].flags = 0; + set_levltyp(x, y, POOL); + levl[x][y].flags = 0; /* No kelp! */ del_engr_at(x, y); water_damage_chain(gl.level.objects[x][y], TRUE); @@ -226,9 +227,9 @@ dryup(coordxy x, coordxy y, boolean isyou) pline_The("fountain dries up!"); } /* replace the fountain with ordinary floor */ - levl[x][y].typ = ROOM, levl[x][y].flags = 0; + set_levltyp(x, y, ROOM); /* updates level.flags.nfountains */ + levl[x][y].flags = 0; levl[x][y].blessedftn = 0; - gl.level.flags.nfountains--; /* The location is seen if the hero/monster is invisible or felt if the hero is blind. */ newsym(x, y); @@ -430,9 +431,9 @@ dipfountain(register struct obj *obj) artiname(ART_EXCALIBUR), lady); } update_inventory(); - levl[u.ux][u.uy].typ = ROOM, levl[u.ux][u.uy].flags = 0; + set_levltyp(u.ux, u.uy, ROOM); /* updates level.flags.nfountains */ + levl[u.ux][u.uy].flags = 0; newsym(u.ux, u.uy); - gl.level.flags.nfountains--; if (in_town(u.ux, u.uy)) (void) angry_guards(FALSE); return; @@ -543,11 +544,11 @@ breaksink(coordxy x, coordxy y) { if (cansee(x, y) || u_at(x, y)) pline_The("pipes break! Water spurts out!"); - gl.level.flags.nsinks--; - levl[x][y].typ = FOUNTAIN, levl[x][y].looted = 0; + /* updates level.flags.nsinks and level.flags.nfountains */ + set_levltyp(x, y, FOUNTAIN); + levl[x][y].looted = 0; levl[x][y].blessedftn = 0; SET_FOUNTAIN_LOOTED(x, y); - gl.level.flags.nfountains++; newsym(x, y); } diff --git a/src/mklev.c b/src/mklev.c index 485f0870b..3176092dd 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -26,7 +26,7 @@ static void mktrap_victim(struct trap *); static struct mkroom *find_branch_room(coord *); static struct mkroom *pos_to_room(coordxy, coordxy); static boolean cardinal_nextto_room(struct mkroom *, coordxy, coordxy); -static boolean place_niche(struct mkroom *, coordxy *, coordxy *, coordxy *); +static boolean place_niche(struct mkroom *, int *, coordxy *, coordxy *); static void makeniche(int); static void make_niches(void); static int QSORTCALLBACK mkroom_cmp(const genericptr, const genericptr); @@ -599,7 +599,10 @@ cardinal_nextto_room(struct mkroom *aroom, coordxy x, coordxy y) } static boolean -place_niche(register struct mkroom *aroom, coordxy *dy, coordxy *xx, coordxy *yy) +place_niche( + struct mkroom *aroom, + int *dy, + coordxy *xx, coordxy *yy) { coord dd; @@ -639,8 +642,8 @@ makeniche(int trap_type) { register struct mkroom *aroom; struct rm *rm; - int vct = 8; - coordxy dy, xx, yy; + int dy, vct = 8; + coordxy xx, yy; struct trap *ttmp; while (vct--) { @@ -721,6 +724,24 @@ makevtele(void) makeniche(TELEP_TRAP); } +/* count the different features (sinks, fountains) in the level */ +void +count_level_features(void) +{ + coordxy x, y; + + gl.level.flags.nfountains = gl.level.flags.nsinks = 0; + for (y = 0; y < ROWNO; y++) + for (x = 0; x < COLNO; x++) { + int typ = levl[x][y].typ; + + if (typ == FOUNTAIN) + gl.level.flags.nfountains++; + else if (typ == SINK) + gl.level.flags.nsinks++; + } +} + /* clear out various globals that keep information on the current level. * some of this is only necessary for some types of levels (maze, normal, * special) but it's easier to put it all in one place than make sure diff --git a/src/mkmaze.c b/src/mkmaze.c index 9045b9458..ea2192aa2 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -69,24 +69,36 @@ is_solid(coordxy x, coordxy y) /* set map terrain type, handling lava lit, ice melt timers, etc */ boolean -set_levltyp(coordxy x, coordxy y, schar typ) +set_levltyp(coordxy x, coordxy y, schar newtyp) { - if (isok(x, y)) { - if ((typ < MAX_TYPE) && CAN_OVERWRITE_TERRAIN(levl[x][y].typ)) { + if (isok(x, y) && newtyp >= STONE && newtyp < MAX_TYPE) { + if (CAN_OVERWRITE_TERRAIN(levl[x][y].typ)) { + schar oldtyp = levl[x][y].typ; boolean was_ice = (levl[x][y].typ == ICE); - levl[x][y].typ = typ; + levl[x][y].typ = newtyp; + /* TODO? + * if oldtyp used flags or horizontal differently from + * from the way newtyp will use them, clear them. + */ - if (typ == LAVAPOOL) + if (IS_LAVA(newtyp)) levl[x][y].lit = 1; - if (was_ice && typ != ICE) + if (was_ice && newtyp != ICE) spot_stop_timers(x, y, MELT_ICE_AWAY); + if ((IS_FOUNTAIN(oldtyp) != IS_FOUNTAIN(newtyp)) + || (IS_SINK(oldtyp) != IS_SINK(newtyp))) + count_level_features(); /* level.flags.nfountains,nsinks */ + return TRUE; } #ifdef EXTRA_SANITY_CHECKS } else { - impossible("set_levltyp(%i,%i,%i) !isok", x, y, typ); + impossible("set_levltyp(%d,%d,%d)%s%s", + (int) x, (int) y, (int) newtyp, + !isok(x, y) ? " not isok()" : "", + (newtyp < STONE || newtyp >= MAX_TYPE) ? " bad type" : ""); #endif /*EXTRA_SANITY_CHECKS*/ } return FALSE; @@ -99,14 +111,17 @@ set_levltyp_lit(coordxy x, coordxy y, schar typ, schar lit) boolean ret = set_levltyp(x, y, typ); if (ret && isok(x, y)) { - /* LAVAPOOL handled in set_levltyp */ - if ((typ != LAVAPOOL) && (lit != SET_LIT_NOCHANGE)) { + if (lit != SET_LIT_NOCHANGE) { #ifdef EXTRA_SANITY_CHECKS if (lit < SET_LIT_NOCHANGE || lit > 1) - impossible("set_levltyp_lit(%i,%i,%i,%i)", x, y, typ, lit); + impossible("set_levltyp_lit(%d,%d,%d,%d)", + (int) x, (int) y, (int) typ, (int) lit); #endif /*EXTRA_SANITY_CHECKS*/ - if (lit == SET_LIT_RANDOM) + if (IS_LAVA(typ)) + lit = 1; + else if (lit == SET_LIT_RANDOM) lit = rn2(2); + levl[x][y].lit = lit; } } diff --git a/src/objnam.c b/src/objnam.c index c9d713e88..d930378b6 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3485,11 +3485,6 @@ wizterrainwish(struct _readobjnam_data *d) if (madeterrain) { feel_newsym(x, y); /* map the spot where the wish occurred */ - if (oldtyp == FOUNTAIN && lev->typ != FOUNTAIN) - gl.level.flags.nfountains--; - else if (oldtyp == SINK && lev->typ != SINK) - gl.level.flags.nsinks--; - /* hero started at but might not be there anymore (create lava, decline to die, and get teleported away to safety) */ if (u.uinwater && !is_pool(u.ux, u.uy)) { @@ -3509,14 +3504,9 @@ wizterrainwish(struct _readobjnam_data *d) } } - /* fixups for replaced terrain that aren't handled above; - for fountain placed on fountain or sink placed on sink, the - increment above gets canceled out by the decrement here; - otherwise if fountain or sink was replaced, there's one less */ - if (IS_FOUNTAIN(oldtyp)) - gl.level.flags.nfountains--; - else if (IS_SINK(oldtyp)) - gl.level.flags.nsinks--; + /* fixups for replaced terrain that aren't handled above */ + if (IS_FOUNTAIN(oldtyp) || IS_SINK(oldtyp)) + count_level_features(); /* update level.flags.nfountains,nsinks */ /* horizontal is overlaid by fountain->blessedftn, grave->disturbed */ if (IS_FOUNTAIN(oldtyp) || IS_GRAVE(oldtyp) || IS_WALL(oldtyp) || oldtyp == IRONBARS diff --git a/src/sp_lev.c b/src/sp_lev.c index 481697614..db20cb745 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -32,7 +32,6 @@ static void flip_vault_guard(int, struct monst *, coordxy, coordxy, coordxy, coordxy); static void sel_set_wall_property(coordxy, coordxy, genericptr_t); static void set_wall_property(coordxy, coordxy, coordxy, coordxy, int); -static void count_features(void); static void remove_boundary_syms(void); static void set_door_orientation(int, int); static boolean shared_with_room(int, int, struct mkroom *); @@ -989,25 +988,6 @@ set_wall_property(coordxy x1, coordxy y1, coordxy x2, coordxy y2, int prop) } } -/* - * Count the different features (sinks, fountains) in the level. - */ -static void -count_features(void) -{ - coordxy x, y; - - gl.level.flags.nfountains = gl.level.flags.nsinks = 0; - for (y = 0; y < ROWNO; y++) - for (x = 0; x < COLNO; x++) { - int typ = levl[x][y].typ; - if (typ == FOUNTAIN) - gl.level.flags.nfountains++; - else if (typ == SINK) - gl.level.flags.nsinks++; - } -} - static void remove_boundary_syms(void) { @@ -6559,7 +6539,7 @@ lspo_finalize_level(lua_State *L UNUSED) if (L) flip_level_rnd(gc.coder->allow_flips, FALSE); - count_features(); + count_level_features(); if (L && gc.coder->solidify) solidify_map(); @@ -7016,7 +6996,7 @@ load_special(const char *name) flip_level_rnd(gc.coder->allow_flips, FALSE); - count_features(); + count_level_features(); if (gc.coder->solidify) solidify_map();