]> granicus.if.org Git - nethack/commitdiff
fix #K669 - 'nasty' monster summoning
authorPatR <rankin@nethack.org>
Sat, 28 Mar 2020 02:05:52 +0000 (19:05 -0700)
committerPatR <rankin@nethack.org>
Sat, 28 Mar 2020 02:05:52 +0000 (19:05 -0700)
Report complained about multiple Archons causing his character to
be swarmed by monsters on the Plane of Fire.  I don't think that
the behavior has changed significantly from how it worked in 3.4.3.
Nobody can summon an Archon directly because they're excluded from
the nasties[] list.  But whenever summoning picks a genocided
'nasty', the result gets replaced by random monster of appropriate
difficulty for the level (which could be an Archon for a high level
character in the endgame).  [Note that that won't pick an Archon
in Gehennom or at arch-lich outside of there because the random
monster creation honors the only-in-hell and never-in-hell flags;
picking from the nasties[] list doesn't.]

This prevents that for any creature (except arch-lich or the Wizard)
casting the summon nasties spell.  If a replacement creature is a
spellcaster it now has to have lower difficulty than the summoner.
If not, it will be discarded even though its difficulty is classified
as appropriate.  So to summon an Archon, the summoner has to have
higher difficulty than an Archon; arch-lich and the Wizard are the
only ones meeting that criterium.  When summoner is an arch-lich,
it can't summon another arch-lich (since that wouldn't have lower
difficulty than the summoner) and can summon (via replacement for
genocided type, and only if outside of Gehennom) at most one Archon.
When summoner is the Wizard, he could summon an arch-lich (when in
Gehennom; demoted to master lich elsewhere--see below) or an Archon
(outside Gehennom only), but at most one per summoning.

For post-Wizard harassment, which effectively has infinite
difficulty level, it could still happen.  However, each instance of
harassment is only allowed to create at most one Archon or arch-lich
now, so chain summoning should be lessoned.  Also if it tries to
pick an arch-lich when outside of Gehennom it will switch to master
lich instead (which won't be allowed to summon an Archon or an arch-
lich or even another master lich).

(The monmove.c bit is unrelated, just some comment formatting that
I had laying around that got mixed in.)

doc/fixes37.0
include/extern.h
src/makemon.c
src/mkobj.c
src/mon.c
src/monmove.c
src/sp_lev.c
src/wizard.c

index 0544ed75f3eb74446b63180164c54bacc8d30678..d9c52681e906404390b165cb6f36465f161519d9 100644 (file)
@@ -1,4 +1,4 @@
-$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.142 $ $NHDT-Date: 1584872363 2020/03/22 10:19:23 $
+$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.144 $ $NHDT-Date: 1585361048 2020/03/28 02:04:08 $
 
 General Fixes and Modified Features
 -----------------------------------
@@ -92,6 +92,8 @@ praying on an unaligned altar outside of Gehennom behaved like an ordinary
 Discworld typo: Moving Pictures passage 12 "or" -> "of"
 unicorn corpses and wraith corpses could be sacrificed even if "too old"
 hero polymorphed into a hider and hiding was not unhidden when teleporting
+impose tighter restraints on 'summon nasties', both for spellcasting monsters
+       and post-Wizard harassment
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 015450055b96b51583dbead440535f14a18b9774..18443b0a25241a395b7f07c08ed0c3fbc6be7267 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 extern.h        $NHDT-Date: 1584405113 2020/03/17 00:31:53 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.814 $ */
+/* NetHack 3.6 extern.h        $NHDT-Date: 1585361043 2020/03/28 02:04:03 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.815 $ */
 /* Copyright (c) Steve Creps, 1988.                              */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1218,6 +1218,7 @@ E struct mextra *NDECL(newmextra);
 E void FDECL(copy_mextra, (struct monst *, struct monst *));
 E void FDECL(dealloc_mextra, (struct monst *));
 E struct monst *FDECL(makemon, (struct permonst *, int, int, int));
+E struct monst *FDECL(unmakemon, (struct monst *, int));
 E boolean FDECL(create_critters, (int, struct permonst *, BOOLEAN_P));
 E struct permonst *NDECL(rndmonst);
 E struct permonst *FDECL(mkclass, (CHAR_P, int));
@@ -1406,7 +1407,7 @@ E boolean FDECL(is_flammable, (struct obj *));
 E boolean FDECL(is_rottable, (struct obj *));
 E void FDECL(place_object, (struct obj *, int, int));
 E void FDECL(remove_object, (struct obj *));
-E void FDECL(discard_minvent, (struct monst *));
+E void FDECL(discard_minvent, (struct monst *, BOOLEAN_P));
 E void FDECL(obj_extract_self, (struct obj *));
 E void FDECL(extract_nobj, (struct obj *, struct obj **));
 E void FDECL(extract_nexthere, (struct obj *, struct obj **));
@@ -3037,7 +3038,7 @@ E int FDECL(tactics, (struct monst *));
 E boolean FDECL(has_aggravatables, (struct monst *));
 E void NDECL(aggravate);
 E void NDECL(clonewiz);
-E int NDECL(pick_nasty);
+E int FDECL(pick_nasty, (int));
 E int FDECL(nasty, (struct monst *));
 E void NDECL(resurrect);
 E void NDECL(intervene);
index 959e54869eeaed14c865092055dc56e62ea97c30..ef544ca2be2b60ab64434ee6ced341f986cbfc77 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 makemon.c       $NHDT-Date: 1574722863 2019/11/25 23:01:03 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.142 $ */
+/* NetHack 3.6 makemon.c       $NHDT-Date: 1585361050 2020/03/28 02:04:10 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.162 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -923,20 +923,20 @@ int mndx;
 boolean tally;
 boolean ghostly;
 {
-    boolean result;
-    uchar lim = mbirth_limit(mndx);
-    boolean gone = (g.mvitals[mndx].mvflags & G_GONE) != 0; /* geno'd|extinct */
+    boolean gone, result;
+    int lim = mbirth_limit(mndx);
 
-    result = (((int) g.mvitals[mndx].born < lim) && !gone) ? TRUE : FALSE;
+    gone = (g.mvitals[mndx].mvflags & G_GONE) != 0; /* geno'd|extinct */
+    result = ((int) g.mvitals[mndx].born < lim && !gone) ? TRUE : FALSE;
 
     /* if it's unique, don't ever make it again */
-    if ((mons[mndx].geno & G_UNIQ) && mndx != PM_HIGH_PRIEST)
+    if ((mons[mndx].geno & G_UNIQ) != 0 && mndx != PM_HIGH_PRIEST)
         g.mvitals[mndx].mvflags |= G_EXTINCT;
 
-    if (g.mvitals[mndx].born < 255 && tally
-        && (!ghostly || (ghostly && result)))
+    if (g.mvitals[mndx].born < 255 && tally && (!ghostly || result))
         g.mvitals[mndx].born++;
-    if ((int) g.mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN)
+    if ((int) g.mvitals[mndx].born >= lim
+        && !(mons[mndx].geno & G_NOGEN)
         && !(g.mvitals[mndx].mvflags & G_EXTINCT)) {
         if (wizard) {
             debugpline1("Automatically extinguished %s.",
@@ -1391,7 +1391,7 @@ int mmflags;
     } else {
         /* no initial inventory is allowed */
         if (mtmp->minvent)
-            discard_minvent(mtmp);
+            discard_minvent(mtmp, TRUE);
         mtmp->minvent = (struct obj *) 0; /* caller expects this */
     }
     if (ptr->mflags3 && !(mmflags & MM_NOWAIT)) {
@@ -1412,6 +1412,34 @@ int mmflags;
     return mtmp;
 }
 
+/* caller rejects makemon()'s result; always returns Null */
+struct monst *
+unmakemon(mon, mmflags)
+struct monst *mon;
+int mmflags;
+{
+    boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
+    int mndx = monsndx(mon->data);
+
+    /* if count has reached the limit of 255, we don't know whether
+       that just happened when creating this monster or the threshold
+       had already been reached and further incrments were suppressed;
+       assume the latter */
+    if (countbirth && g.mvitals[mndx].born > 0 && g.mvitals[mndx].born < 255)
+        g.mvitals[mndx].born -= 1;
+    if ((mon->data->geno & G_UNIQ) != 0)
+        g.mvitals[mndx].mvflags &= ~G_EXTINCT;
+
+    mon->mhp = 0; /* let discard_minvent() know that mon isn't being kept */
+    /* uncreate any artifact that the monster was provided with; unlike
+       mongone(), this doesn't protect special items like the Amulet
+       by dropping them so caller should handle them when applicable */
+    discard_minvent(mon, TRUE);
+
+    mongone(mon);
+    return (struct monst *) 0;
+}
+
 int
 mbirth_limit(mndx)
 int mndx;
index 0248c873e0212eb7329dfa9db3d37e2c02a1f3e8..bb875ddb585adda035cd3c2a0e12b6efb93b2e0f 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mkobj.c $NHDT-Date: 1578895344 2020/01/13 06:02:24 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.174 $ */
+/* NetHack 3.6 mkobj.c $NHDT-Date: 1585361051 2020/03/28 02:04:11 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.176 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -1935,11 +1935,12 @@ register struct obj *otmp;
 
 /* throw away all of a monster's inventory */
 void
-discard_minvent(mtmp)
+discard_minvent(mtmp, uncreate_artifacts)
 struct monst *mtmp;
+boolean uncreate_artifacts;
 {
     struct obj *otmp, *mwep = MON_WEP(mtmp);
-    boolean keeping_mon = (!DEADMONSTER(mtmp));
+    boolean keeping_mon = !DEADMONSTER(mtmp);
 
     while ((otmp = mtmp->minvent) != 0) {
         /* this has now become very similar to m_useupall()... */
@@ -1953,6 +1954,8 @@ struct monst *mtmp;
             }
             otmp->owornmask = 0L; /* obfree() expects this */
         }
+        if (uncreate_artifacts && otmp->oartifact)
+            artifact_exists(otmp, safe_oname(otmp), FALSE);
         obfree(otmp, (struct obj *) 0); /* dealloc_obj() isn't sufficient */
     }
 }
index 3fe0697b1f7e9de142a07384ddb28d5f3c8af258..5567048b948f25cc5f335b9a1f2396055cebaecb 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mon.c   $NHDT-Date: 1581886863 2020/02/16 21:01:03 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.324 $ */
+/* NetHack 3.6 mon.c   $NHDT-Date: 1585361052 2020/03/28 02:04:12 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.327 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -2197,7 +2197,7 @@ struct monst *mdef;
        can't remove them from the game */
     mdrop_special_objs(mdef);
     /* release rest of monster's inventory--it is removed from game */
-    discard_minvent(mdef);
+    discard_minvent(mdef, FALSE);
     m_detach(mdef, mdef->data);
 }
 
@@ -3534,11 +3534,11 @@ struct monst *mon;
     switch (mon->cham) {
     case PM_SANDESTIN:
         if (rn2(7))
-            mndx = pick_nasty();
+            mndx = pick_nasty(mons[PM_ARCHON].difficulty - 1);
         break;
     case PM_DOPPELGANGER:
         if (!rn2(7)) {
-            mndx = pick_nasty();
+            mndx = pick_nasty(mons[PM_JABBERWOCK].difficulty - 1);
         } else if (rn2(3)) { /* role monsters */
             mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, PM_ARCHEOLOGIST);
         } else if (!rn2(3)) { /* quest guardians */
index f9c1686573eb7b1d263616e3d93960d4a6648909..e88ab046445bcbce921d0624407b488843c46fb5 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 monmove.c       $NHDT-Date: 1580633722 2020/02/02 08:55:22 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.129 $ */
+/* NetHack 3.6 monmove.c       $NHDT-Date: 1585361053 2020/03/28 02:04:13 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.133 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Michael Allison, 2006. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -874,16 +874,15 @@ register int after;
     if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10))
         return 0; /* do not leave hiding place */
 
-    set_apparxy(mtmp);
-    /* where does mtmp think you are? */
-    /* Not necessary if m_move called from this file, but necessary in
-     * other calls of m_move (ex. leprechauns dodging)
-     */
+    /* Where does 'mtmp' think you are?  Not necessary if m_move() called
+       from this file, but needed for other calls of m_move(). */
+    set_apparxy(mtmp); /* set mtmp->mux, mtmp->muy */
+
     if (!Is_rogue_level(&u.uz))
         can_tunnel = tunnels(ptr);
     can_open = !(nohands(ptr) || verysmall(ptr));
-    can_unlock =
-        ((can_open && monhaskey(mtmp, TRUE)) || mtmp->iswiz || is_rider(ptr));
+    can_unlock = ((can_open && monhaskey(mtmp, TRUE))
+                  || mtmp->iswiz || is_rider(ptr));
     doorbuster = is_giant(ptr);
     if (mtmp->wormno)
         goto not_special;
@@ -1469,7 +1468,7 @@ register int after;
                         add_damage(mtmp->mx, mtmp->my, 0L);
                 }
             } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) {
-                /* As of 3.6.2: was using may_dig() but it doesn't handle bars */
+                /* 3.6.2: was using may_dig() but it doesn't handle bars */
                 if (!(levl[mtmp->mx][mtmp->my].wall_info & W_NONDIGGABLE)
                     && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) {
                     if (canseemon(mtmp))
index a60a17c3d07212d86153863205054cde3dbfed9a..f5078c7d4a477d48ff97adbbff3e77d2de4638ee 100755 (executable)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 sp_lev.c        $NHDT-Date: 1584655714 2020/03/19 22:08:34 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.181 $ */
+/* NetHack 3.6 sp_lev.c        $NHDT-Date: 1585361055 2020/03/28 02:04:15 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.183 $ */
 /*      Copyright (c) 1989 by Jean-Christophe Collet */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1981,7 +1981,7 @@ struct mkroom *croom;
         }
 
         if (m->has_invent) {
-            discard_minvent(mtmp);
+            discard_minvent(mtmp, TRUE);
             invent_carrying_monster = mtmp;
         }
     }
index 0cf531ea823da7664f78eaf1ad17049c0669fc82..e8dfa776a98ffaddf91c22c52bdfa50f09237a55 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 wizard.c        $NHDT-Date: 1561336025 2019/06/24 00:27:05 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.56 $ */
+/* NetHack 3.6 wizard.c        $NHDT-Date: 1585361057 2020/03/28 02:04:17 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2016. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -41,7 +41,7 @@ static NEARDATA const int nasties[] = {
     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
+    /* (Archons, titans, ki-rin, and golden nagas are suitably nasty, but
        they're summoners so would aggravate excessive summoning) */
 };
 
@@ -512,9 +512,10 @@ clonewiz()
 
 /* also used by newcham() */
 int
-pick_nasty()
+pick_nasty(difcap)
+int difcap; /* if non-zero, try to make difficulty be lower than this */
 {
-    int res = nasties[rn2(SIZE(nasties))];
+    int alt, res = nasties[rn2(SIZE(nasties))];
 
     /* To do?  Possibly should filter for appropriate forms when
      * in the elemental planes or surrounded by water or lava.
@@ -526,6 +527,33 @@ pick_nasty()
         && !('A' <= mons[res].mlet && mons[res].mlet <= 'Z'))
         res = nasties[rn2(SIZE(nasties))];
 
+    /* if genocided or too difficult or out of place, try a substitute
+       when a suitable one exists
+           arch-lich -> master lich,
+           master mind flayer -> mind flayer,
+       but the substitutes are likely to be genocided too */
+    alt = res;
+    if ((g.mvitals[res].mvflags & G_GENOD) != 0
+        || (difcap > 0 && mons[res].difficulty >= difcap)
+         /* note: nasty() -> makemon() ignores G_HELL|G_NOHELL;
+            arch-lich and master lich are both flagged as hell-only;
+            this filtering demotes arch-lich to master lich when
+            outside of Gehennom (unless the latter has been genocided) */
+        || (mons[res].geno & (Inhell ? G_NOHELL : G_HELL)) != 0)
+        alt = big_to_little(res);
+    if (alt != res && (g.mvitals[alt].mvflags & G_GENOD) == 0) {
+        const char *mname = mons[alt].mname,
+                   *lastspace = rindex(mname, ' ');
+
+        /* only non-juveniles can become alternate choice */
+        if (strncmp(mname, "baby ", 5)
+            && (!lastspace
+                || (strcmp(lastspace, " hatchling")
+                    && strcmp(lastspace, " pup")
+                    && strcmp(lastspace, " cub"))))
+            res = alt;
+    }
+
     return res;
 }
 
@@ -540,11 +568,10 @@ int
 nasty(summoner)
 struct monst *summoner;
 {
-    register struct monst *mtmp;
-    register int i, j;
-    int castalign = (summoner ? sgn(summoner->data->maligntyp) : 0);
+    struct monst *mtmp;
     coord bypos;
-    int count, census, tmp, makeindex, s_cls, m_cls;
+    int i, j, count, census, tmp, makeindex,
+        s_cls, m_cls, difcap, trylimit, castalign;
 
 #define MAXNASTIES 10 /* more than this can be created */
 
@@ -558,12 +585,14 @@ struct monst *summoner;
     } else {
         count = 0;
         s_cls = summoner ? summoner->data->mlet : 0;
+        difcap = summoner ? summoner->data->difficulty : 0; /* spellcasters */
+        castalign = summoner ? sgn(summoner->data->maligntyp) : 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 && count < MAXNASTIES; --i)
+        for (i = rnd(tmp); i > 0 && count < MAXNASTIES; --i) {
             /* Of the 42 nasties[], 10 are lawful, 14 are chaotic,
              * and 18 are neutral.
              *
@@ -585,15 +614,16 @@ struct monst *summoner;
                 /* Don't create more spellcasters of the monsters' level or
                  * higher--avoids chain summoners filling up the level.
                  */
+                trylimit = 10 + 1; /* 10 tries */
                 do {
-                    makeindex = pick_nasty();
+                    if (!--trylimit)
+                        goto nextj; /* break this loop, continue outer one */
+                    makeindex = pick_nasty(difcap);
                     m_cls = mons[makeindex].mlet;
-                } while (summoner
-                         && ((attacktype(&mons[makeindex], AT_MAGC)
-                              && mons[makeindex].difficulty
-                                 >= mons[summoner->mnum].difficulty)
-                             || (s_cls == S_DEMON && m_cls == S_ANGEL)
-                             || (s_cls == S_ANGEL && m_cls == S_DEMON)));
+                } while ((difcap > 0 && mons[makeindex].difficulty >= difcap
+                          && attacktype(&mons[makeindex], AT_MAGC))
+                         || (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 (summoner && !enexto(&bypos, summoner->mux, summoner->muy,
                                         &mons[makeindex]))
@@ -604,18 +634,46 @@ struct monst *summoner;
                                     NO_MM_FLAGS)) != 0) {
                     mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0;
                     set_malign(mtmp);
-                } else /* random monster to substitute for geno'd selection */
-                    mtmp = makemon((struct permonst *) 0, bypos.x, bypos.y,
-                                   NO_MM_FLAGS);
+                } else {
+                    /* random monster to substitute for geno'd selection;
+                       unlike direct choice, not forced to be hostile [why?];
+                       limit spellcasters to inhibit chain summoning */
+                    if ((mtmp = makemon((struct permonst *) 0,
+                                        bypos.x, bypos.y,
+                                        NO_MM_FLAGS)) != 0) {
+                        m_cls = mtmp->data->mlet;
+                        if ((difcap > 0 && mtmp->data->difficulty >= difcap
+                             && attacktype(mtmp->data, AT_MAGC))
+                            || (s_cls == S_DEMON && m_cls == S_ANGEL)
+                            || (s_cls == S_ANGEL && m_cls == S_DEMON))
+                            mtmp = unmakemon(mtmp, NO_MM_FLAGS); /* Null */
+                    }
+                }
+
                 if (mtmp) {
+                    /* create at most one arch-lich or Archon regardless
+                       of who is doing the summoning (note: Archon is
+                       not in nasties[] but could be chosen as random
+                       replacement for a genocided selection) */
+                    if (mtmp->data == &mons[PM_ARCH_LICH]
+                        || mtmp->data == &mons[PM_ARCHON]) {
+                        tmp = min(mons[PM_ARCHON].difficulty, /* A:26 */
+                                  mons[PM_ARCH_LICH].difficulty); /* L:31 */
+                        if (!difcap || difcap > tmp)
+                            difcap = tmp; /* rest must be lower difficulty */
+                    }
                     /* 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)
                         break;
                 }
-            }
+ nextj:
+                ; /* empty; label must be followed by a statement */
+            } /* for j */
+        } /* for i */
     }
 
     if (count)