From 89237fc96d9632a29474d7f61d906480ba71a931 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 15 Sep 2018 19:23:29 -0700 Subject: [PATCH] fix #H7157 - cancel self as clay golem The report was "doesn't kill even if unchanging", but it does cause rehumanize() when not Unchanging, the same thing that happens when you die due to loss of hit points. But losing the activating word(s) and then having Unchanging retain the clay golem shape does seem wrong, so make losing the word(s) while being unable to revert to normal form be fatal. Poly'd hero (without Unchanging) reverts to normal when cancelled, so make monsters behave that way. Previously, only werecritters in beast form were forced to human form. This changes cancellation to make shapechangers and hiding mimics take on normal form too. Cancelled shapechangers now behave as if the hero has the Protection_from_shape_changes attribute and will be unable to change their shape (after having been forced into normal form). Getting polymorphed in any fashion uncancels them prior to giving new shape. [There may be some newcham() situations that should be disallowed when cancelled rather proceeding and consequently uncancelling.] --- doc/fixes36.2 | 5 +++++ src/mon.c | 10 +++++++++- src/zap.c | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3454dda9e..8fb98475e 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -120,6 +120,11 @@ handle monsters inside the invocation area give monsters who have had a worn item stolen or who have been life-saved (used up amulet) a chance to wear replacement gear on next move instead of having to wait until they pick something up +Unchanging hero in clay golem form will be killed when cancelled +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 Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/mon.c b/src/mon.c index cbdde81ba..9cdf9b6d9 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2900,7 +2900,8 @@ restartcham() for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (!mtmp->mcan) + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && cansee(mtmp->mx, mtmp->my)) { set_mimic_sym(mtmp); @@ -3417,6 +3418,13 @@ boolean msg; /* "The oldmon turns into a newmon!" */ anomalous extinction feedback during final disclsoure */ if (mbirth_limit(monsndx(olddata)) < MAXMONNO) return 0; + /* cancelled shapechangers become uncancelled prior + to being given a new shape */ + if (mtmp->mcan && !Protection_from_shape_changers) { + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (mtmp->cham != NON_PM) + mtmp->mcan = 0; + } } if (msg) { diff --git a/src/zap.c b/src/zap.c index 14b47902a..37b38e8ab 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2306,7 +2306,7 @@ boolean ordinary; case WAN_CANCELLATION: case SPE_CANCELLATION: - (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); + (void) cancel_monst(&youmonst, obj, TRUE, TRUE, TRUE); break; case SPE_DRAIN_LIFE: @@ -2675,25 +2675,45 @@ boolean youattack, allow_cancel_kill, self_cancel; /* now handle special cases */ if (youdefend) { - if (Upolyd) { - if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) - pline(writing_vanishes, your); - - if (Unchanging) + if (Upolyd) { /* includes lycanthrope in creature form */ + /* + * Return to normal form unless Unchanging. + * Hero in clay golem form dies if Unchanging. + * Does not cure lycanthropy or stop timed random polymorph. + */ + if (u.umonnum == PM_CLAY_GOLEM) { + if (!Blind) + pline(writing_vanishes, your); + else /* note: "dark" rather than "heavy" is intentional... */ + You_feel("%s headed.", Hallucination ? "dark" : "light"); + u.mh = 0; /* fatal; death handled by rehumanize() */ + } + if (Unchanging && u.mh > 0) Your("amulet grows hot for a moment, then cools."); else rehumanize(); } } else { - mdef->mcan = TRUE; - - if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) + mdef->mcan = 1; + /* force shapeshifter into its base form */ + if (mdef->m_ap_type != M_AP_NOTHING) + seemimic(mdef); + /* [not 'else if'; chameleon might have been hiding as a mimic] */ + if (mdef->cham >= LOW_PM) { + /* note: newcham() uncancels shapechangers (resets m->mcan + to 0), but only for shapechangers whose m->cham is already + NON_PM and we just verified that it's LOW_PM or higher */ + newcham(mdef, &mons[mdef->cham], FALSE, FALSE); + mdef->cham = NON_PM; /* cancelled shapeshifter can't shift */ + } + if (is_were(mdef->data) && !is_human(mdef->data)) were_change(mdef); if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (canseemon(mdef)) pline(writing_vanishes, s_suffix(mon_nam(mdef))); - + /* !allow_cancel_kill is for Magicbane, where clay golem + will be killed somewhere back up the call/return chain... */ if (allow_cancel_kill) { if (youattack) killed(mdef);