From c29ffe1d823b338956de2517057b7e87ef64795e Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 27 May 2020 14:05:42 -0700 Subject: [PATCH] fix github issue #349 - out of depth liches Change mkclass() to always honor the hell-only monster generation flag for L class, preventing master and arch-liches outside Gehennom. For other classes, honor hell-only and outside-hell-only most (89%) of the time. When not honored (11%), it allows demons and devils to appear outside of Gehennom as they have in the past. [That part might need to be re-done since it is done for all monsters in the class on any mkclass() call instead of being done on a class-member by class-member basis within each such call.] This prevents out of depth liches in the Castle and ought to do same for themed rooms of type 'Mausoleum' although I haven't figured out how to test that. Fixes #349 --- doc/fixes37.0 | 5 ++++- src/makemon.c | 27 +++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 6ad854424..d9ad5e44c 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.223 $ $NHDT-Date: 1589827569 2020/05/18 18:46:09 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.225 $ $NHDT-Date: 1590613502 2020/05/27 21:05:02 $ General Fixes and Modified Features ----------------------------------- @@ -187,6 +187,9 @@ hold_another_object used hardcoded Stressed to limit carrying instead of using the 'pickup_burden' option for that when hold_another_object fails while hero is swallowed, drop the item into swallower's inventory instead of onto the floor +change mkclass() to usually honor (always honor for L class) the hell-only and + never-in-hell monster creation flags; no more achi-lich in the Castle + (nor master lich there unless demilich gets a potion of gain level) Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/makemon.c b/src/makemon.c index eafcf2360..4dd4221fe 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1587024537 2020/04/16 08:08:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.168 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1590613502 2020/05/27 21:05:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.170 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1663,8 +1663,7 @@ aligntyp atyp; { register int first, last, num = 0; int k, nums[SPECIAL_PM + 1]; /* +1: insurance for final return value */ - int ignore = (spc & G_IGNORE); - int maxmlev, mask = (G_NOGEN | G_UNIQ) & ~spc; + int maxmlev, gmask; (void) memset((genericptr_t) nums, 0, sizeof nums); maxmlev = level_difficulty() >> 1; @@ -1686,13 +1685,24 @@ aligntyp atyp; return (struct permonst *) 0; } + gmask = (G_NOGEN | G_UNIQ); + /* traditionally mkclass() ignored hell-only and never-in-hell; + now we usually honor those but not all the time, mostly so that + the majority of major demons aren't constrained to Gehennom; + arch- and master liches are always so constrained (for creation; + lesser liches might grow up into them elsewhere) */ + if (rn2(9) || class == S_LICH) + gmask |= (Inhell ? G_NOHELL : G_HELL); + gmask &= ~spc; + gmask |= (spc & G_IGNORE); + /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) { if (atyp != A_NONE && sgn(mons[last].maligntyp) != sgn(atyp)) continue; - if (mk_gen_ok(last, G_GONE, mask|ignore)) { + if (mk_gen_ok(last, G_GONE, gmask)) { /* consider it; don't reject a toostrong() monster if we don't have anything yet (num==0) or if it is the same (or lower) difficulty as preceding candidate (non-zero @@ -1738,6 +1748,7 @@ mkclass_poly(class) int class; { register int first, last, num = 0; + int gmask; for (first = LOW_PM; first < SPECIAL_PM; first++) if (mons[first].mlet == class) @@ -1745,14 +1756,18 @@ int class; if (first == SPECIAL_PM) return NON_PM; + gmask = (G_NOGEN | G_UNIQ); + if (rn2(9) || class == S_LICH) + gmask |= (Inhell ? G_NOHELL : G_HELL); + for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) - if (mk_gen_ok(last, G_GENOD, (G_NOGEN | G_UNIQ))) + if (mk_gen_ok(last, G_GENOD, gmask)) num += mons[last].geno & G_FREQ; if (!num) return NON_PM; for (num = rnd(num); num > 0; first++) - if (mk_gen_ok(first, G_GENOD, (G_NOGEN | G_UNIQ))) + if (mk_gen_ok(first, G_GENOD, gmask)) num -= mons[first].geno & G_FREQ; first--; /* correct an off-by-one error */