shapeshifting on rogue level
authorPatR <rankin@nethack.org>
Thu, 4 Jun 2015 22:31:25 +0000 (15:31 -0700)
committerPatR <rankin@nethack.org>
Thu, 4 Jun 2015 22:31:25 +0000 (15:31 -0700)
Limit vampire shapeshifting on rogue level to vampire bats (only
choice represented by uppercase letter) and have other shapeshifting
try for uppercase.  The latter isn't rigorous because shapeshifters
(chameleon=':', doppelganger='@', sandestin='&') aren't uppercase
themselves, so won't be created there under ordinary circumstances.
It applies to the "summon nasties" monster spell and post-invocation/
post-Wizard's-death harassment effect too.

src/makemon.c
src/mon.c
src/wizard.c

index a1fc167fee3fb554ad1837d429a16af1aa1ef057..5aea3392de22ee9e39757243cb3b5b2107684c95 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 makemon.c       $NHDT-Date: 1432685497 2015/05/27 00:11:37 $  $NHDT-Branch: master $:$NHDT-Revision: 1.89 $ */
+/* NetHack 3.6 makemon.c       $NHDT-Date: 1433457069 2015/06/04 22:31:09 $  $NHDT-Branch: master $:$NHDT-Revision: 1.92 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1134,23 +1134,18 @@ register int mmflags;
     mtmp->cham = NON_PM; /* default is "not a shapechanger" */
     if ((mcham = pm_to_cham(mndx)) != NON_PM) {
         /* this is a shapechanger after all */
-        if (Protection_from_shape_changers) {
+        if (Protection_from_shape_changers
+            || mtmp->cham == PM_VLAD_THE_IMPALER) {
             ; /* stuck in its natural form (NON_PM) */
         } else {
             /* Note: shapechanger's initial form used to be
-               chosen with rndmonst(), yielding a monster
+               chosen here with rndmonst(), yielding a monster
                which was approriate to the level's difficulty
                but ignored the changer's usual type selection
-               so would be inppropriate for vampshifters. */
-            mtmp->cham = mcham; /* remember base form */
-            if (mcham != PM_VLAD_THE_IMPALER &&
-                /* select initial shape */
-                (mcham = select_newcham_form(mtmp)) != NON_PM) {
-                /* take on initial shape; if successful,
-                   avoid giving that shape's usual inventory */
-                if (newcham(mtmp, &mons[mcham], FALSE, FALSE))
-                    allow_minvent = FALSE;
-            }
+               so would be inppropriate for vampshifters.
+               Let newcham() pick the shape. */
+            if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE))
+                allow_minvent = FALSE;
         }
     } else if (mndx == PM_WIZARD_OF_YENDOR) {
         mtmp->iswiz = TRUE;
index cf168fd82e3bf6f8633229a81da16362e5fb5ae5..8ca8d16a1ebd7901c6727bab656e3d34e3e6e9ca 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mon.c   $NHDT-Date: 1432512774 2015/05/25 00:12:54 $  $NHDT-Branch: master $:$NHDT-Revision: 1.177 $ */
+/* NetHack 3.6 mon.c   $NHDT-Date: 1433457072 2015/06/04 22:31:12 $  $NHDT-Branch: master $:$NHDT-Revision: 1.178 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -2667,10 +2667,18 @@ boolean construct;
 STATIC_OVL int
 pick_animal()
 {
+    int res;
+
     if (!animal_list)
         mon_animal_list(TRUE);
 
-    return animal_list[rn2(animal_list_count)];
+    res = animal_list[rn2(animal_list_count)];
+    /* rogue level should use monsters represented by uppercase letters
+       only, but since chameleons aren't generated there (not uppercase!)
+       we don't perform a lot of retries */
+    if (Is_rogue_level(&u.uz) && !isupper((uchar) mons[res].mlet))
+        res = animal_list[rn2(animal_list_count)];
+    return res;
 }
 
 void
@@ -2710,6 +2718,9 @@ pickvampshape(mon)
 struct monst *mon;
 {
     int mndx = mon->cham;
+    /* avoid picking monsters with lowercase display symbols ('d' for wolf
+       and 'v' for fog cloud) on rogue level*/
+    boolean uppercase_only = Is_rogue_level(&u.uz);
 
     switch (mndx) {
     case PM_VLAD_THE_IMPALER:
@@ -2718,13 +2729,13 @@ struct monst *mon;
             break; /* leave mndx as is */
     /*FALLTHRU*/
     case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */
-        if (!rn2(10)) {
+        if (!rn2(10) && !uppercase_only) {
             mndx = PM_WOLF;
             break;
         }
     /*FALLTHRU*/
     case PM_VAMPIRE: /* any vampire can become fog or bat */
-        mndx = !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT;
+        mndx = (!rn2(4) && !uppercase_only) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT;
         break;
     }
     return mndx;
@@ -2786,7 +2797,8 @@ int *mndx_p, monclass;
         *mndx_p = PM_VLAD_THE_IMPALER;
         return TRUE;
     }
-    /* basic vampires can't become wolves; any can become fog or bat */
+    /* basic vampires can't become wolves; any can become fog or bat
+       (we don't enforce upper-case only for rogue level here) */
     if (*mndx_p == PM_WOLF)
         return (mon->cham != PM_VAMPIRE);
     if (*mndx_p == PM_FOG_CLOUD || *mndx_p == PM_VAMPIRE_BAT)
@@ -2916,7 +2928,10 @@ struct monst *mon;
         tryct = 50;
         do {
             mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
-        } while (--tryct > 0 && !validspecmon(mon, mndx));
+        } while (--tryct > 0 && !validspecmon(mon, mndx)
+                 /* try harder to select uppercase monster on rogue level */
+                 && (tryct > 40 && Is_rogue_level(&u.uz)
+                     && !isupper((uchar) mons[mndx].mlet)));
     }
     return mndx;
 }
@@ -2995,6 +3010,11 @@ boolean msg;      /* "The oldmon turns into a newmon!" */
         do {
             mndx = select_newcham_form(mtmp);
             mdat = accept_newcham_form(mndx);
+            /* for the first several tries we require upper-case on
+               the rogue level (after that, we take whatever we get) */
+            if (tryct > 15 && Is_rogue_level(&u.uz)
+                && !isupper((uchar) mdat->mlet))
+                mdat = 0;
             if (mdat)
                 break;
         } while (--tryct > 0);
index 261c831b15b5af60148d03afc9206972eabfe1d3..d0a6c371c6c7eec6573997e79c8e817cbe39f4e2 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 wizard.c        $NHDT-Date: 1432512766 2015/05/25 00:12:46 $  $NHDT-Branch: master $:$NHDT-Revision: 1.37 $ */
+/* NetHack 3.6 wizard.c        $NHDT-Date: 1433457074 2015/06/04 22:31:14 $  $NHDT-Branch: master $:$NHDT-Revision: 1.38 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -428,9 +428,19 @@ clonewiz()
 int
 pick_nasty()
 {
+    int res = nasties[rn2(SIZE(nasties))];
+
     /* To do?  Possibly should filter for appropriate forms when
-       in the elemental planes or surrounded by water or lava. */
-    return nasties[rn2(SIZE(nasties))];
+     * in the elemental planes or surrounded by water or lava.
+     *
+     * We want monsters represented by uppercase on rogue level,
+     * but we don't try very hard.
+     */
+    if (Is_rogue_level(&u.uz)
+        && !('A' <= mons[res].mlet && mons[res].mlet <= 'Z'))
+        res = nasties[rn2(SIZE(nasties))];
+
+    return res;
 }
 
 /* create some nasty monsters, aligned or neutral with the caster */