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.)
This commit is contained in:
PatR
2018-09-17 18:28:49 -07:00
parent 7123812327
commit b34400094b
3 changed files with 42 additions and 3 deletions

View 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

View 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;

View File

@@ -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: