fix github issue #352 - geno'd monsters in quest

The recent change to mkclass() was letting genocided monsters be
created when role-specific monsters were chosen for quest levels.

makemon(Null) -> rndmonst() -> qt_montype() -> mkclass() -> mk_gen_ok()
was accepting members of the quest-specified class even when they
should have been rejected.  I'm still not sure why the revised bit
manipulation didn't work as intended; the re-revised code does.

G_IGNORE was a bug waiting to happen since it gets passed to
mkclass() as a mons[].geno flag but is used to control the use of
mvitals[].mvflags values.  It's still being misused but at least
it doesn't conflict with any of the other flags now.

Fixes #352
This commit is contained in:
PatR
2020-05-30 16:00:29 -07:00
parent e9f53ab7f6
commit 8c1120261a
3 changed files with 30 additions and 19 deletions
+2 -1
View File
@@ -1,4 +1,4 @@
$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.226 $ $NHDT-Date: 1590870784 2020/05/30 20:33:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.227 $ $NHDT-Date: 1590879610 2020/05/30 23:00:10 $
General Fixes and Modified Features General Fixes and Modified Features
----------------------------------- -----------------------------------
@@ -251,6 +251,7 @@ fix new "objects[0] class #1 not in order!" panic if plain 'char' is unsigned
only generate shop items on solid floor squares only generate shop items on solid floor squares
avoid gcc 10 warning by removing duplicate definition of 'head_engr' avoid gcc 10 warning by removing duplicate definition of 'head_engr'
if a monster removed a corpse from an ice box, the corpse would never rot away if a monster removed a corpse from an ice box, the corpse would never rot away
monster creation on quest levels could make genocided creatures
tty: redraw unexplored locations as S_unexplored rather than <space> after tty: redraw unexplored locations as S_unexplored rather than <space> after
map has been partially overwritten by popup menu or text display map has been partially overwritten by popup menu or text display
+8 -6
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 monflag.h $NHDT-Date: 1585356420 2020/03/28 00:47:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ /* NetHack 3.6 monflag.h $NHDT-Date: 1590879610 2020/05/30 23:00:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ */
/* Copyright (c) 1989 Mike Threepoint */ /* Copyright (c) 1989 Mike Threepoint */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -194,14 +194,16 @@ enum ms_sounds {
#define G_GENO 0x0020 /* can be genocided */ #define G_GENO 0x0020 /* can be genocided */
#define G_NOCORPSE 0x0010 /* no corpse left ever */ #define G_NOCORPSE 0x0010 /* no corpse left ever */
#define G_FREQ 0x0007 /* creation frequency mask */ #define G_FREQ 0x0007 /* creation frequency mask */
/* note: G_IGNORE controls handling of mvitals[].mvflags bits but is
passed to mkclass() as if it dealt with mons[].geno bits */
#define G_IGNORE 0x8000 /* for mkclass(), ignore G_GENOD|G_EXTINCT */
/* for g.mvitals[].mvflags (variant during game), along with G_NOCORPSE */ /* for g.mvitals[].mvflags (variant during game), along with G_NOCORPSE */
#define G_KNOWN 0x0004 /* have been encountered */ #define G_KNOWN 0x04 /* have been encountered */
#define G_GENOD 0x0002 /* have been genocided */ #define G_GENOD 0x02 /* have been genocided */
#define G_EXTINCT 0x0001 /* population control; create no more */ #define G_EXTINCT 0x01 /* population control; create no more */
#define G_GONE (G_GENOD | G_EXTINCT) #define G_GONE (G_GENOD | G_EXTINCT)
#define MV_KNOWS_EGG 0x0008 /* player recognizes egg of this monster type */ #define MV_KNOWS_EGG 0x08 /* player recognizes egg of this monster type */
#define G_IGNORE 0x1000 /* for mkclass(), ignore G_GENOD|G_EXTINCT */
/* *INDENT-ON* */ /* *INDENT-ON* */
/* clang-format on */ /* clang-format on */
+20 -12
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 makemon.c $NHDT-Date: 1590621476 2020/05/27 23:17:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.171 $ */ /* NetHack 3.6 makemon.c $NHDT-Date: 1590879611 2020/05/30 23:00:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.172 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -16,7 +16,7 @@
static boolean FDECL(uncommon, (int)); static boolean FDECL(uncommon, (int));
static int FDECL(align_shift, (struct permonst *)); static int FDECL(align_shift, (struct permonst *));
static boolean FDECL(mk_gen_ok, (int, int, int)); static boolean FDECL(mk_gen_ok, (int, unsigned, unsigned));
static boolean FDECL(wrong_elem_type, (struct permonst *)); static boolean FDECL(wrong_elem_type, (struct permonst *));
static void FDECL(m_initgrp, (struct monst *, int, int, int, int)); static void FDECL(m_initgrp, (struct monst *, int, int, int, int));
static void FDECL(m_initthrow, (struct monst *, int, int)); static void FDECL(m_initthrow, (struct monst *, int, int));
@@ -1624,11 +1624,12 @@ rndmonst()
/* decide whether it's ok to generate a candidate monster by mkclass() */ /* decide whether it's ok to generate a candidate monster by mkclass() */
static boolean static boolean
mk_gen_ok(mndx, mvflagsmask, genomask) mk_gen_ok(mndx, mvflagsmask, genomask)
int mndx, mvflagsmask, genomask; int mndx;
unsigned mvflagsmask, genomask;
{ {
struct permonst *ptr = &mons[mndx]; struct permonst *ptr = &mons[mndx];
if ((g.mvitals[mndx].mvflags & mvflagsmask) && !(genomask & G_IGNORE)) if (g.mvitals[mndx].mvflags & mvflagsmask)
return FALSE; return FALSE;
if (ptr->geno & genomask) if (ptr->geno & genomask)
return FALSE; return FALSE;
@@ -1658,12 +1659,13 @@ int spc;
struct permonst * struct permonst *
mkclass_aligned(class, spc, atyp) mkclass_aligned(class, spc, atyp)
char class; char class;
int spc; int spc; /* special mons[].geno handling */
aligntyp atyp; aligntyp atyp;
{ {
register int first, last, num = 0; register int first, last, num = 0;
int k, nums[SPECIAL_PM + 1]; /* +1: insurance for final return value */ int k, nums[SPECIAL_PM + 1]; /* +1: insurance for final return value */
int maxmlev, gmask, gehennom = Inhell != 0; int maxmlev, gehennom = Inhell != 0;
unsigned mv_mask, gn_mask;
(void) memset((genericptr_t) nums, 0, sizeof nums); (void) memset((genericptr_t) nums, 0, sizeof nums);
maxmlev = level_difficulty() >> 1; maxmlev = level_difficulty() >> 1;
@@ -1685,6 +1687,13 @@ aligntyp atyp;
return (struct permonst *) 0; return (struct permonst *) 0;
} }
mv_mask = G_GONE; /* G_GENOD | G_EXTINCT */
if ((spc & G_IGNORE) != 0) {
mv_mask = 0; /* mv_mask &= ~G_GONE; */
/* G_IGNORE is not a mons[].geno mask so get rid of it now */
spc &= ~G_IGNORE;
}
/* Assumption #2: monsters of a given class are presented in ascending /* Assumption #2: monsters of a given class are presented in ascending
* order of strength. * order of strength.
*/ */
@@ -1696,13 +1705,12 @@ aligntyp atyp;
the majority of major demons aren't constrained to Gehennom; the majority of major demons aren't constrained to Gehennom;
arch- and master liches are always so constrained (for creation; arch- and master liches are always so constrained (for creation;
lesser liches might grow up into them elsewhere) */ lesser liches might grow up into them elsewhere) */
gmask = (G_NOGEN | G_UNIQ); gn_mask = (G_NOGEN | G_UNIQ);
if (rn2(9) || class == S_LICH) if (rn2(9) || class == S_LICH)
gmask |= (gehennom ? G_NOHELL : G_HELL); gn_mask |= (gehennom ? G_NOHELL : G_HELL);
gmask &= ~spc; gn_mask &= ~spc;
gmask |= (spc & G_IGNORE);
if (mk_gen_ok(last, G_GONE, gmask)) { if (mk_gen_ok(last, mv_mask, gn_mask)) {
/* consider it; don't reject a toostrong() monster if we /* consider it; don't reject a toostrong() monster if we
don't have anything yet (num==0) or if it is the same don't have anything yet (num==0) or if it is the same
(or lower) difficulty as preceding candidate (non-zero (or lower) difficulty as preceding candidate (non-zero
@@ -1748,7 +1756,7 @@ mkclass_poly(class)
int class; int class;
{ {
register int first, last, num = 0; register int first, last, num = 0;
int gmask; unsigned gmask;
for (first = LOW_PM; first < SPECIAL_PM; first++) for (first = LOW_PM; first < SPECIAL_PM; first++)
if (mons[first].mlet == class) if (mons[first].mlet == class)