From 12e4e732caf5939a361a16d981dd33a088d28383 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 22 Feb 2016 15:50:34 -0800 Subject: [PATCH] nasty() again Even out the summoning distribution by adding more lawful candidates. There used to be only 4; now there are 10. Chaotics have 14, so are still more likely to get "neutral or own alignment" and stop, but the difference is now pretty small once you factor in the 18 neutral ones. --- src/wizard.c | 99 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/src/wizard.c b/src/wizard.c index d5237a6d9..2f7d2e7e4 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wizard.c $NHDT-Date: 1455934524 2016/02/20 02:15:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $ */ +/* NetHack 3.6 wizard.c $NHDT-Date: 1456185030 2016/02/22 23:50:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -20,21 +20,37 @@ STATIC_DCL boolean FDECL(you_have, (int)); STATIC_DCL unsigned long FDECL(target_on, (int, struct monst *)); STATIC_DCL unsigned long FDECL(strategy, (struct monst *)); +/* adding more neutral creatures will tend to reduce the number of monsters + summoned by nasty(); adding more lawful creatures will reduce the number + of monsters summoned by lawfuls; adding more chaotic creatures will reduce + the number of monsters summoned by chaotics; prior to 3.6.1, there were + only four lawful candidates, so lawful summoners tended to summon more + (trying to get lawful or neutral but obtaining chaotic instead) than + their chaotic counterparts */ static NEARDATA const int nasties[] = { - PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON, - PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM, - PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD, - PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON, - PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT, - PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER, - PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING, PM_OLOG_HAI, - PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, PM_DISENCHANTER + /* neutral */ + PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, + PM_OWLBEAR, PM_PURPLE_WORM, PM_XAN, PM_UMBER_HULK, + PM_XORN, PM_ZRUTY, PM_LEOCROTTA, PM_BALUCHITHERIUM, + PM_CARNIVOROUS_APE, PM_FIRE_ELEMENTAL, PM_JABBERWOCK, + PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, + /* chaotic */ + PM_BLACK_DRAGON, PM_RED_DRAGON, PM_ARCH_LICH, PM_VAMPIRE_LORD, + PM_MASTER_MIND_FLAYER, PM_DISENCHANTER, PM_WINGED_GARGOYLE, + PM_STORM_GIANT, PM_OLOG_HAI, PM_ELF_LORD, PM_ELVENKING, + PM_OGRE_KING, PM_CAPTAIN, PM_GREMLIN, + /* lawful */ + PM_SILVER_DRAGON, PM_ORANGE_DRAGON, PM_GREEN_DRAGON, + PM_YELLOW_DRAGON, PM_GUARDIAN_NAGA, PM_FIRE_GIANT, + PM_ALEAX, PM_COUATL, PM_HORNED_DEVIL, PM_BARBED_DEVIL, + /* (titans, ki-rin, and golden nagas are suitably nasty, but + they're summoners so would aggravate excessive summoning) */ }; static NEARDATA const unsigned wizapp[] = { PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE, PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK, PM_XORN, PM_XAN, - PM_COCKATRICE, PM_FLOATING_EYE, PM_GUARDIAN_NAGA, PM_TRAPPER + PM_COCKATRICE, PM_FLOATING_EYE, PM_GUARDIAN_NAGA, PM_TRAPPER, }; /* If you've found the Amulet, make the Wizard appear after some time */ @@ -506,54 +522,85 @@ pick_nasty() } /* create some nasty monsters, aligned with the caster or neutral; chaotic - and unaligned are treated as equivalent; default caster is chaotic */ + and unaligned are treated as equivalent; if summoner is Null, this is + for late-game harassment (after the Wizard has been killed at least once + or the invocation ritual has been performed), in which case we treat + 'summoner' as neutral, since that will produce the greatest number of + creatures on average (in 3.6.0 and earlier, Null was treated as chaotic); + returns the number of monsters created */ int -nasty(mcast) -struct monst *mcast; +nasty(summoner) +struct monst *summoner; { register struct monst *mtmp; register int i, j; - int castalign = (mcast ? sgn(mcast->data->maligntyp) : -1); + int castalign = (summoner ? sgn(summoner->data->maligntyp) : 0); coord bypos; - int count, census, tmp; + int count, census, tmp, makeindex, s_cls, m_cls; -#define MAXNASTIES 8 /* more than this can be created if any come in groups */ +#define MAXNASTIES 10 /* more than this can be created */ /* some candidates may be created in groups, so simple count of non-null makemon() return is inadequate */ census = monster_census(FALSE); if (!rn2(10) && Inhell) { + /* this might summon a demon prince or lord */ count = msummon((struct monst *) 0); /* summons like WoY */ } else { count = 0; - tmp = (u.ulevel > 3) ? u.ulevel / 3 : 1; /* just in case -- rph */ - /* if we don't have a casting monster, nasties appear around you */ + s_cls = summoner ? summoner->data->mlet : 0; + tmp = (u.ulevel > 3) ? u.ulevel / 3 : 1; + /* if we don't have a casting monster, nasties appear around hero, + otherwise they'll appear around spot summoner thinks she's at */ bypos.x = u.ux; bypos.y = u.uy; - for (i = rnd(tmp); i > 0; --i) + for (i = rnd(tmp); i > 0 && count < MAXNASTIES; --i) + /* Of the 42 nasties[], 10 are lawful, 14 are chaotic, + * and 18 are neutral. + * + * Neutral caster, used for late-game harrassment, + * has 18/42 chance to stop the inner loop on each + * critter, 24/42 chance for another iteration. + * Lawful caster has 28/42 chance to stop unless the + * summoner is an angel or demon, in which case the + * chance is 26/42. + * Chaotic or unaligned caster has 32/42 chance to + * stop, so will summon fewer creatures on average. + * + * The outer loop potentially gives chaotic/unaligned + * a chance to even things up since others will hit + * MAXNASTIES sooner, but its number of iterations is + * randomized so it won't always do so. + */ for (j = 0; j < 20; j++) { - int makeindex; - /* Don't create more spellcasters of the monsters' level or * higher--avoids chain summoners filling up the level. */ do { makeindex = pick_nasty(); - } while (mcast && attacktype(&mons[makeindex], AT_MAGC) - && monstr[makeindex] >= monstr[mcast->mnum]); + m_cls = mons[makeindex].mlet; + } while (summoner + && ((attacktype(&mons[makeindex], AT_MAGC) + && monstr[makeindex] >= monstr[summoner->mnum]) + || (s_cls == S_DEMON && m_cls == S_ANGEL) + || (s_cls == S_ANGEL && m_cls == S_DEMON))); /* do this after picking the monster to place */ - if (mcast && !enexto(&bypos, mcast->mux, mcast->muy, - &mons[makeindex])) + if (summoner && !enexto(&bypos, summoner->mux, summoner->muy, + &mons[makeindex])) continue; + /* this honors genocide but overrides extinction; it ignores + inside-hell-only (G_HELL) & outside-hell-only (G_NOHELL) */ if ((mtmp = makemon(&mons[makeindex], bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); - } else /* GENOD? */ + } else /* random monster to substitute for geno'd selection */ mtmp = makemon((struct permonst *) 0, bypos.x, bypos.y, NO_MM_FLAGS); if (mtmp) { + /* delay first use of spell or breath attack */ + mtmp->mspec_used = rnd(4); if (++count >= MAXNASTIES || mtmp->data->maligntyp == 0 || sgn(mtmp->data->maligntyp) == castalign) -- 2.40.0