From: Michael Meyer Date: Wed, 8 Jun 2022 23:50:48 +0000 (-0400) Subject: Fix: vampire shapeshifting in a door X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bc2427167a75ef349efd361f7ef5bc683cdf5a58;p=nethack Fix: vampire shapeshifting in a door Someone mentioned in #nethack today that a vampire had turned into a fog cloud, moved under a door, then turned back into a vampire while still sharing a space with a closed door. There already existed some code intended to prevent this in cases where the vampire is killed in one form and revives in another, but voluntary transformations (from decide_to_shapeshift) weren't included. The existing code in mondead and vamp_stone also apparently missed a minor edge case: because the code between the definition of in_door and its use included an expels call, it would be outdated/incorrect in cases where expels() placed the fog cloud onto a closed door. --- diff --git a/src/mon.c b/src/mon.c index e41e60ea4..16aa735ff 100644 --- a/src/mon.c +++ b/src/mon.c @@ -938,7 +938,7 @@ m_calcdistress(struct monst *mtmp) if (mtmp->cham >= LOW_PM) decide_to_shapeshift(mtmp, (canspotmon(mtmp) || engulfing_u(mtmp)) - ? SHIFT_MSG : 0); + ? SHIFT_MSG : 0); were_change(mtmp); /* gradually time out temporary problems */ @@ -2494,7 +2494,7 @@ lifesaved_monster(struct monst* mtmp) DISABLE_WARNING_FORMAT_NONLITERAL void -mondead(register struct monst* mtmp) +mondead(struct monst *mtmp) { struct permonst *mptr; boolean be_sad; @@ -2516,15 +2516,13 @@ mondead(register struct monst* mtmp) && !(g.mvitals[mndx].mvflags & G_GENOD)) { coord new_xy; char buf[BUFSZ]; - boolean in_door = (amorphous(mtmp->data) - && closed_door(mtmp->mx, mtmp->my)), - /* alternate message phrasing for some monster types */ - spec_mon = (nonliving(mtmp->data) - || noncorporeal(mtmp->data) - || amorphous(mtmp->data)), - spec_death = (g.disintegested /* disintegrated or digested */ - || noncorporeal(mtmp->data) - || amorphous(mtmp->data)); + /* alternate message phrasing for some monster types */ + boolean spec_mon = (nonliving(mtmp->data) + || noncorporeal(mtmp->data) + || amorphous(mtmp->data)), + spec_death = (g.disintegested /* disintegrated/digested */ + || noncorporeal(mtmp->data) + || amorphous(mtmp->data)); int x = mtmp->mx, y = mtmp->my; /* construct a format string before transformation; @@ -2546,7 +2544,9 @@ mondead(register struct monst* mtmp) else uunstick(); } - if (in_door) { + /* if fog cloud is on a closed door space, move it to a more + appropriate spot for its intended new form */ + if (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)) { if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx])) rloc_to(mtmp, new_xy.x, new_xy.y); } @@ -3220,7 +3220,7 @@ mon_to_stone(struct monst* mtmp) } boolean -vamp_stone(struct monst* mtmp) +vamp_stone(struct monst *mtmp) { if (is_vampshifter(mtmp)) { int mndx = mtmp->cham; @@ -3230,8 +3230,6 @@ vamp_stone(struct monst* mtmp) if (mndx >= LOW_PM && mndx != monsndx(mtmp->data) && !(g.mvitals[mndx].mvflags & G_GENOD)) { char buf[BUFSZ]; - boolean in_door = (amorphous(mtmp->data) - && closed_door(mtmp->mx, mtmp->my)); /* construct a format string before transformation */ Sprintf(buf, "The lapidifying %s %s %s", @@ -3241,7 +3239,7 @@ vamp_stone(struct monst* mtmp) amorphous(mtmp->data) ? "coalesces on the" : is_flyer(mtmp->data) ? "drops to the" : "writhes on the", - surface(x,y)); + surface(x, y)); mtmp->mcanmove = 1; mtmp->mfrozen = 0; set_mon_min_mhpmax(mtmp, 10); /* mtmp->mhpmax=max(m_lev+1,10) */ @@ -3249,7 +3247,7 @@ vamp_stone(struct monst* mtmp) /* this can happen if previously a fog cloud */ if (engulfing_u(mtmp)) expels(mtmp, mtmp->data, FALSE); - if (in_door) { + if (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)) { coord new_xy; if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx])) { @@ -4081,7 +4079,7 @@ pick_animal(void) } void -decide_to_shapeshift(struct monst* mon, int shiftflags) +decide_to_shapeshift(struct monst *mon, int shiftflags) { struct permonst *ptr = 0; int mndx; @@ -4110,9 +4108,9 @@ decide_to_shapeshift(struct monst* mon, int shiftflags) ptr = &mons[mon->cham]; dochng = TRUE; } else if (mon->data == &mons[PM_FOG_CLOUD] - && mon->mhp == mon->mhpmax && !rn2(4) - && (!canseemon(mon) - || distu(mon->mx, mon->my) > BOLT_LIM * BOLT_LIM)) { + && mon->mhp == mon->mhpmax && !rn2(4) + && (!canseemon(mon) + || distu(mon->mx, mon->my) > BOLT_LIM * BOLT_LIM)) { /* if a fog cloud, maybe change to wolf or vampire bat; those are more likely to take damage--at least when tame--and then switch back to vampire; they'll also @@ -4123,6 +4121,14 @@ decide_to_shapeshift(struct monst* mon, int shiftflags) dochng = (ptr != mon->data); } } + if (dochng && amorphous(mon->data) + && closed_door(mon->mx, mon->my)) { + coord new_xy; + + if (enexto(&new_xy, mon->mx, mon->my, ptr)) { + rloc_to(mon, new_xy.x, new_xy.y); + } + } } else { if (mon->mhp >= 9 * mon->mhpmax / 10 && !rn2(6) && (!canseemon(mon)