]> granicus.if.org Git - nethack/commitdiff
fix #H7060 - polymorph zap vs long worm
authorPatR <rankin@nethack.org>
Tue, 18 Sep 2018 01:28:49 +0000 (18:28 -0700)
committerPatR <rankin@nethack.org>
Tue, 18 Sep 2018 01:28:49 +0000 (18:28 -0700)
A polymoprh zap which creates a long worm can hit and transform the
same monster again depending upon tail segment placement.  Similar
behavior occurs if monpolycontrol is set in wizard mode and player
chooses 'long worm' for what to transform an existing one into (in
which case polymorph fails and zap might hit that same worm again
in another segment, prompting player to choose its new shape again).

Simplest fix would be to make tail segments be immune to polymorph,
but that would prevent players from deliberately attacking the tail
(for polymorph attacks only).  Next simplest would be to make long
worms M2_NOPOLY so that polymorph can't create them, then just live
with multiple promptings when monpolycontrol is set.  This fix
tracks whether a long worm has just been created via polymorph (or
explicitly retained its shape via monpolycontrol) and makes further
hits on same creature on same zap have no effect.  It does so by
setting mon->mextra->mcorpsenm to PM_LONG_WORM when a long worm is
result of polymorph, and setting context.bypasses to get end-of-zap
cleanup.  (It doesn't bother discarding mon->mextra if reset of
mcorpsenm leaves mextra empty.)

doc/fixes36.2
src/worn.c
src/zap.c

index 8fb98475e65348921647cde18425083c79252d3a..4a4fd0fc3cc9d6436796ad36f1514b49735a9a49 100644 (file)
@@ -125,6 +125,8 @@ poly'd shapechanger and hiding mimic will revert to normal when cancelled,
        like werecreature in beast form and non-Unchanging hero
 cancelled shapeshifter is no longer able to change shape
 cancelled shapeshifter hit by polymorph magic will become uncancelled
+polymorph zap which creates a new long worm (or retains an old one via wizard
+       mode monpolycontrol) can hit that worm multiple times (tail segments)
 
 
 Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository
index e7860c6552f732d66a359ed52f65bafc6ed0f74a..1eb1ed671b3dd213167d23b700dab55eec319b88 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 worn.c  $NHDT-Date: 1526728754 2018/05/19 11:19:14 $  $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.51 $ */
+/* NetHack 3.6 worn.c  $NHDT-Date: 1537234121 2018/09/18 01:28:41 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.55 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2013. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -710,6 +710,13 @@ clear_bypasses()
     struct obj *otmp, *nobj;
     struct monst *mtmp;
 
+    /*
+     * 'Object' bypass is also used for one monster function:
+     * polymorph control of long worms.  Activated via setting
+     * context.bypasses even if no specific object has been
+     * bypassed.
+     */
+
     for (otmp = fobj; otmp; otmp = nobj) {
         nobj = otmp->nobj;
         if (otmp->bypass) {
@@ -741,10 +748,19 @@ clear_bypasses()
             continue;
         for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
             otmp->bypass = 0;
+        /* long worm created by polymorph has mon->mextra->mcorpsenm set
+           to PM_LONG_WORM to flag it as not being subject to further
+           polymorph (so polymorph zap won't hit monster to transform it
+           into a long worm, then hit that worm's tail and transform it
+           again on same zap); clearing mcorpsenm reverts worm to normal */
+        if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp))
+            MCORPSENM(mtmp) = NON_PM;
     }
     for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
         for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
             otmp->bypass = 0;
+        /* no MCORPSENM(mtmp)==PM_LONG_WORM check here; long worms can't
+           be just created by polymorph and migrating at the same time */
     }
     /* billobjs and mydogs chains don't matter here */
     context.bypasses = FALSE;
index 37b38e8ab3838b39a627cb2f2fc6c210eeebe388..7a5ab3416899902e6502d81095d934c2f83a0db0 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 zap.c   $NHDT-Date: 1525012627 2018/04/29 14:37:07 $  $NHDT-Branch: master $:$NHDT-Revision: 1.277 $ */
+/* NetHack 3.6 zap.c   $NHDT-Date: 1537234123 2018/09/18 01:28:43 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.287 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2013. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -222,7 +222,11 @@ struct obj *otmp;
     case WAN_POLYMORPH:
     case SPE_POLYMORPH:
     case POT_POLYMORPH:
-        if (resists_magm(mtmp)) {
+        if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) {
+            /* if a long worm has mcorpsenm set, it was polymophed by
+               the current zap and shouldn't be affected if hit again */
+            ;
+        } else if (resists_magm(mtmp)) {
             /* magic resistance protects from polymorph traps, so make
                it guard against involuntary polymorph attacks too... */
             shieldeff(mtmp->mx, mtmp->my);
@@ -238,6 +242,7 @@ struct obj *otmp;
             if (polyspot)
                 for (obj = mtmp->minvent; obj; obj = obj->nobj)
                     bypass_obj(obj);
+
             /* natural shapechangers aren't affected by system shock
                (unless protection from shapechangers is interfering
                with their metabolism...) */
@@ -261,6 +266,22 @@ struct obj *otmp;
                                  || (u.uswallow && mtmp == u.ustuck)))
                     learn_it = TRUE;
             }
+
+            /* do this even if polymorphed failed (otherwise using
+               flags.mon_polycontrol prompting to force mtmp to remain
+               'long worm' would prompt again if zap hit another segment) */
+            if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_LONG_WORM]) {
+                if (!has_mcorpsenm(mtmp))
+                    newmcorpsenm(mtmp);
+                /* flag to indicate that mtmp became a long worm
+                   on current zap, so further hits (on mtmp's new
+                   tail) don't do further transforms */
+                MCORPSENM(mtmp) = PM_LONG_WORM;
+                /* flag to indicate that cleanup is needed; object
+                   bypass cleanup also clears mon->mextra->mcorpsenm
+                   for all long worms on the level */
+                context.bypasses = TRUE;
+            }
         }
         break;
     case WAN_CANCELLATION: