From 60a3263a85e62410bc569272272caf346d2535a8 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 6 Jul 2023 13:18:19 -0700 Subject: [PATCH] fix github issue #1070 - Minetown achievement Issue reported by vultur-cadens: arriving on the Mine Town level via falling or level teleport won't register the "entered Minetown" achievement if hero doesn't arrive inside a room. Reorder some code in check_special_room() so that town entry will be tested before the early return if no room entry has occurred. This adds 'level.flags.has_town' to make the town test be cheaper when the hero hasn't attained the achievement yet and is wandering around the mines. Fixes #1070 --- doc/fixes3-7-0.txt | 3 +++ include/patchlevel.h | 2 +- include/rm.h | 8 +++++--- src/hack.c | 23 +++++++++++++++++------ src/mklev.c | 6 ++++++ src/mkmaze.c | 11 ++++++++--- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 79af17a36..0243a7c5e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1637,6 +1637,9 @@ Lua selection operations 'subtract' and 'xor' didn't always work as intended accept 'true' or 'false' as value for des.object field 'trapped' special level loader didn't check for bad coordinates supplied by .lua file thorougnly enough +hero might not be credited with "entered Mine Town" achievement for the town + variations which treat the whole level as the town if that level gets + entered via falling or level teleport Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/include/patchlevel.h b/include/patchlevel.h index b882ce523..376b90eb5 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 87 +#define EDITLEVEL 88 /* * Development status possibilities. diff --git a/include/rm.h b/include/rm.h index 3b4ac2253..df30650f3 100644 --- a/include/rm.h +++ b/include/rm.h @@ -410,13 +410,15 @@ struct levelflags { Bitfield(is_maze_lev, 1); Bitfield(is_cavernous_lev, 1); Bitfield(arboreal, 1); /* Trees replace rock */ + Bitfield(has_town, 1); /* level contains a town */ Bitfield(wizard_bones, 1); /* set if level came from a bones file - which was created in wizard mode (or - normal mode descendant of such) */ + * which was created in wizard mode (or + * normal mode descendant of such) */ Bitfield(corrmaze, 1); /* Whether corridors are used for the maze - rather than ROOM */ + * rather than ROOM */ Bitfield(rndmongen, 1); /* random monster generation allowed? */ Bitfield(deathdrops, 1); /* monsters may drop corpses/death drops */ + Bitfield(noautosearch, 1); /* automatic searching disabled */ Bitfield(fumaroles, 1); /* lava emits poison gas at random */ Bitfield(stormy, 1); /* clouds create lightning bolts at random */ diff --git a/src/hack.c b/src/hack.c index 0d1d6fc43..4112076a4 100644 --- a/src/hack.c +++ b/src/hack.c @@ -3069,11 +3069,10 @@ in_rooms(register coordxy x, register coordxy y, register int typewanted) boolean in_town(coordxy x, coordxy y) { - s_level *slev = Is_special(&u.uz); register struct mkroom *sroom; boolean has_subrooms = FALSE; - if (!slev || !slev->flags.town) + if (!gl.level.flags.has_town) return FALSE; /* @@ -3140,15 +3139,27 @@ check_special_room(boolean newlev) if (*u.ushops0) u_left_shop(u.ushops_left, newlev); - if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ - return; /* no entrance messages necessary */ - - if (!gc.context.achieveo.minetn_reached + /* + * Check for attaining 'entered Mine Town' achievement. + * Most of the Mine Town variations have the town in one large room + * containing a bunch of subrooms; we check for entering that large + * room. However, two of the variations cover the whole level rather + * than include a room with subrooms. We need to check for town entry + * before the possible early return for not having entered a room in + * case we have arrived in the town but have not entered any room. + * + * TODO: change the minetn variants which don't include any town + * boundary to have such. + */ + if (gl.level.flags.has_town && !gc.context.achieveo.minetn_reached && In_mines(&u.uz) && in_town(u.ux, u.uy)) { record_achievement(ACH_TOWN); gc.context.achieveo.minetn_reached = TRUE; } + if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ + return; /* no entrance messages necessary */ + /* Did we just enter a shop? */ if (*u.ushops_entered) u_entered_shop(u.ushops_entered); diff --git a/src/mklev.c b/src/mklev.c index 3176092dd..7c4886c96 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -793,8 +793,14 @@ clear_level_structures(void) gl.level.flags.is_maze_lev = 0; gl.level.flags.is_cavernous_lev = 0; gl.level.flags.arboreal = 0; + gl.level.flags.has_town = 0; gl.level.flags.wizard_bones = 0; gl.level.flags.corrmaze = 0; + gl.level.flags.rndmongen = 0; + gl.level.flags.deathdrops = 0; + gl.level.flags.noautosearch = 0; + gl.level.flags.fumaroles = 0; + gl.level.flags.stormy = 0; gn.nroom = 0; gr.rooms[0].hx = -1; diff --git a/src/mkmaze.c b/src/mkmaze.c index ea2192aa2..42ca9ce9d 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -524,6 +524,7 @@ void fixup_special(void) { lev_region *r = gl.lregions; + s_level *sp; struct d_level lev; int x, y; struct mkroom *croom; @@ -547,8 +548,7 @@ fixup_special(void) lev = u.uz; lev.dlevel = atoi(r->rname.str); } else { - s_level *sp = find_level(r->rname.str); - + sp = find_level(r->rname.str); lev = sp->dlevel; } /*FALLTHRU*/ @@ -648,6 +648,9 @@ fixup_special(void) stolen_booty(); } + if ((sp = Is_special(&u.uz)) != 0 && sp->flags.town) /* Mine Town */ + gl.level.flags.has_town = 1; + if (gl.lregions) free((genericptr_t) gl.lregions), gl.lregions = 0; gn.num_lregions = 0; @@ -1076,6 +1079,7 @@ makemaz(const char *s) /* SPLEVTYPE format is "level-choice,level-choice"... */ if (wizard && *protofile && sp && sp->rndlevs) { char *ep = getenv("SPLEVTYPE"); /* not nh_getenv */ + if (ep) { /* strrchr always succeeds due to code in prior block */ int len = (int) ((strrchr(protofile, '-') - protofile) + 1); @@ -1083,6 +1087,7 @@ makemaz(const char *s) while (ep && *ep) { if (!strncmp(ep, protofile, len)) { int pick = atoi(ep + len); + /* use choice only if valid */ if (pick > 0 && pick <= (int) sp->rndlevs) Sprintf(protofile + len, "%d", pick); @@ -1109,7 +1114,7 @@ makemaz(const char *s) impossible("Couldn't load \"%s\" - making a maze.", protofile); } - gl.level.flags.is_maze_lev = TRUE; + gl.level.flags.is_maze_lev = 1; gl.level.flags.corrmaze = !rn2(3); if (!Invocation_lev(&u.uz) && rn2(2)) {