From: PatR Date: Tue, 18 Sep 2018 01:28:49 +0000 (-0700) Subject: fix #H7060 - polymorph zap vs long worm X-Git-Tag: NetHack-3.6.2_Released~197^2~14 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b34400094b348693fa7f57b44b6e9740847b8555;p=nethack fix #H7060 - polymorph zap vs long worm 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.) --- diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 8fb98475e..4a4fd0fc3 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -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 diff --git a/src/worn.c b/src/worn.c index e7860c655..1eb1ed671 100644 --- a/src/worn.c +++ b/src/worn.c @@ -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; diff --git a/src/zap.c b/src/zap.c index 37b38e8ab..7a5ab3416 100644 --- 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: