Skip to content

Commit

Permalink
fix github issue #349 - out of depth liches
Browse files Browse the repository at this point in the history
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
  • Loading branch information
PatR committed May 27, 2020
1 parent c63165e commit c29ffe1
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
5 changes: 4 additions & 1 deletion doc/fixes37.0
Original file line number Diff line number Diff line change
@@ -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
-----------------------------------
Expand Down Expand Up @@ -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
Expand Down
27 changes: 21 additions & 6 deletions src/makemon.c
Original file line number Diff line number Diff line change
@@ -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. */
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -1738,21 +1748,26 @@ 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)
break;
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 */

Expand Down

1 comment on commit c29ffe1

@AndrioCelos
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering mausoleums pick a lich using the same mechanism as the Castle liches, yeah. I tested it by increasing the random weight for that themed room type.

Please sign in to comment.