a fix for issue #1386 - impossible to gen ';' mon
Bug description of #1386 by @copperwater on GitHub: "When generating a random monster from a class using des.monster(), the G_NOGEN in their statblock is suppressed, but because every monster of this class has frequency 0, none of them are actually eligible to get picked. mkclass ends up returning a null pointer and create_monster has to pick a random monster instead. This affects the following levels (all the ones that use random sea monsters): Healer quest start Healer quest locate Plane of Water (difficult to notice, since it has lots of specific sea monsters and only 5 random ones) This can be pretty easily viewed by going to the Healer quest start and detecting monsters: there is a shark and a giant eel, which are specifically defined, but the remaining random sea monster that should be there is absent." Add a tracking array mclass_maxf[MAXMCLASSES] (about 61 entries, the first not being used), and fill it one time in init_mongen_order() with the maximum frequency value seen of any monster in that class. Any mclass_maxf[] entry of zero represents that entire class of monsters having no positive frequency value. Detect that in mkclass_aligned(), and use it to work around the situation to produce the monster being sought by the Lua level description file.
This commit is contained in:
@@ -1747,6 +1747,7 @@ mk_gen_ok(int mndx, unsigned mvflagsmask, unsigned genomask)
|
||||
|
||||
/* monsters in order by mlet & difficulty for mkclass() */
|
||||
static int mongen_order[NUMMONS];
|
||||
static xint8 mclass_maxf[MAXMCLASSES];
|
||||
static boolean mongen_order_init = FALSE;
|
||||
|
||||
staticfn int QSORTCALLBACK
|
||||
@@ -1796,15 +1797,18 @@ check_mongen_order(void)
|
||||
staticfn void
|
||||
init_mongen_order(void)
|
||||
{
|
||||
int i;
|
||||
int i, mlet;
|
||||
|
||||
if (mongen_order_init)
|
||||
return;
|
||||
|
||||
mongen_order_init = TRUE;
|
||||
for (i = LOW_PM; i < NUMMONS; i++)
|
||||
for (i = LOW_PM; i < NUMMONS; i++) {
|
||||
mongen_order[i] = i;
|
||||
|
||||
mlet = mons[i].mlet;
|
||||
if ((xint8) (mons[i].geno & G_FREQ) > mclass_maxf[mlet])
|
||||
mclass_maxf[mlet] = (xint8) (mons[i].geno & G_FREQ);
|
||||
}
|
||||
#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
|
||||
check_mongen_order();
|
||||
#endif
|
||||
@@ -1836,9 +1840,11 @@ dump_mongen(void)
|
||||
Snprintf(nmbuf, sizeof nmbuf, "PM_%s%s",
|
||||
monsdump[MONSi(i)].nm,
|
||||
(i == SPECIAL_PM - 1) ? "" : ",");
|
||||
raw_printf(" %*s /* %c seq=%3d, idx=%3d, sym='%c', diff=%2d %s */",
|
||||
raw_printf(" %*s /* %c seq=%3d, idx=%3d, sym='%c', diff=%2d, freq=%2d[%d] %s */",
|
||||
-nmwidth, nmbuf, (i == MONSi(i)) ? ' ' : '.', i, MONSi(i),
|
||||
mlet, (int) mons[MONSi(i)].difficulty,
|
||||
(int) (mons[MONSi(i)].geno & G_FREQ),
|
||||
(int) mclass_maxf[(int) mons[MONSi(i)].mlet],
|
||||
(special == (G_NOGEN | G_UNIQ)) ? "(G_NOGEN | G_UNIQ)"
|
||||
: (special == G_NOGEN) ? "(G_NOGEN)"
|
||||
: (special == G_UNIQ) ? "(G_UNIQ)"
|
||||
@@ -1869,6 +1875,7 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */
|
||||
int k, nums[SPECIAL_PM + 1]; /* +1: insurance for final return value */
|
||||
int maxmlev, gehennom = Inhell != 0;
|
||||
unsigned mv_mask, gn_mask;
|
||||
boolean zero_freq_for_entire_class;
|
||||
|
||||
(void) memset((genericptr_t) nums, 0, sizeof nums);
|
||||
maxmlev = level_difficulty() >> 1;
|
||||
@@ -1878,6 +1885,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */
|
||||
}
|
||||
|
||||
init_mongen_order();
|
||||
/* the following must come after init_mongen_order() */
|
||||
zero_freq_for_entire_class = (mclass_maxf[(int) class] == 0);
|
||||
|
||||
/* Assumption #1: monsters of a given class are contiguous in the
|
||||
* mons[] array. Player monsters and quest denizens
|
||||
@@ -1927,7 +1936,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */
|
||||
&& mons[MONSi(last)].difficulty > mons[MONSi(last - 1)].difficulty
|
||||
&& rn2(2))
|
||||
break;
|
||||
if ((k = (mons[MONSi(last)].geno & G_FREQ)) > 0) {
|
||||
if ((k = (mons[MONSi(last)].geno & G_FREQ)) > 0
|
||||
|| (k = (zero_freq_for_entire_class ? 1 : 0)) > 0) {
|
||||
/* skew towards lower value monsters at lower exp. levels
|
||||
(this used to be done in the next loop, but that didn't
|
||||
work well when multiple species had the same level and
|
||||
|
||||
Reference in New Issue
Block a user