fix issue #1434 - engulfed gas spore explosion

Issue reported by Umbire:  a gas spore that got swallowed and killed
didn't die but exploded anyway, with the explosion affecting the map
instead of being contained in the swallower.

There was code to handle that but it wasn't being executed.  This fix
feels unclean but seems to work.

I couldn't reproduce the survival of the gas spore but since that
isn't wanted I won't worry about it.

Fixes #1434
This commit is contained in:
PatR
2025-08-05 13:30:17 -07:00
parent 5fe746a0d6
commit 695c6ef3ac
7 changed files with 38 additions and 9 deletions

View File

@@ -1523,6 +1523,8 @@ monsters trapped in pits cannot kick
create familiar spell can create harder creatures
a vampire lord could choose to take on wolf form while flying over water or
lava, then revert to vampire lord form and teleport unnecessarily
a gas spore that was killed when an engulfer swallowed it produced an explosion
on the map rather than inside the engulfer
Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -604,6 +604,9 @@ struct instance_globals_m {
/* dokick.c */
struct rm *maploc;
/* mhitm.c */
struct monst *mswallower; /* for gas spore explosion when it's swallowed*/
/* mhitu.c */
int mhitu_dieroll;

View File

@@ -508,6 +508,8 @@ static const struct instance_globals_m g_init_m = {
UNDEFINED_PTR, /* migrating_mons */
/* dokick.c */
UNDEFINED_PTR, /* maploc */
/* mhitm.c */
UNDEFINED_PTR, /* mswallower */
/* mhitu.c */
UNDEFINED_VALUE, /* mhitu_dieroll */
/* mklev.c */

View File

@@ -906,7 +906,9 @@ gulpmm(
newsym(ax, ay); /* erase old position */
newsym(dx, dy); /* update new position */
gm.mswallower = magr; /* corpse_chance() wants this */
status = mdamagem(magr, mdef, mattk, (struct obj *) 0, 0);
gm.mswallower = (struct monst *) 0; /* reset */
if ((status & (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED))
== (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED)) {

View File

@@ -1271,7 +1271,7 @@ gulp_blnd_check(void)
return FALSE;
}
/* monster swallows you, or damage if u.uswallow */
/* monster swallows you, or damage if already swallowed (u.uswallow != 0) */
staticfn int
gulpmu(struct monst *mtmp, struct attack *mattk)
{
@@ -1537,7 +1537,9 @@ gulpmu(struct monst *mtmp, struct attack *mattk)
if (physical_damage)
tmp = Maybe_Half_Phys(tmp);
gm.mswallower = mtmp; /* match gulpmm() */
mdamageu(mtmp, tmp);
gm.mswallower = 0;
if (tmp)
stop_occupation();

View File

@@ -2204,8 +2204,7 @@ mfndpos(
if (IS_DOOR(ntyp)
/* an amorphous creature can only move under/through a
closed door if it doesn't currently have hero engulfed */
&& !((amorphous(mdat) || can_fog(mon))
&& (mon != u.ustuck || !u.uswallow))
&& !((amorphous(mdat) || can_fog(mon)) && !engulfing_u(mon))
&& (((levl[nx][ny].doormask & D_CLOSED) && !(flag & OPENDOOR))
|| ((levl[nx][ny].doormask & D_LOCKED)
&& !(flag & UNLOCKDOOR))) && !thrudoor)
@@ -2670,11 +2669,25 @@ mon_leaving_level(struct monst *mon)
remove_monster(mx, my);
#if 0 /* mustn't do this; too many places assume that the stale
monst->mx,my values are still valid */
* monst->mx,my values are still valid */
mon->mx = mon->my = 0; /* off normal map */
#endif
}
if (onmap) {
/* gulpmm() tries to deal with this, but without this extra
place_monster() the messages for exploding engulfed gas spore
are delivered without the engulfer being shown on the map */
if (gm.mswallower && gm.mswallower != mon) {
if (gm.mswallower != &gy.youmonst) {
place_monster(gm.mswallower,
gm.mswallower->mx, gm.mswallower->my);
} else {
u_on_newpos(u.ux, u.uy);
if (canspotself())
display_self();
}
}
mon->mundetected = 0; /* for migration; doesn't matter for death */
/* unhide mimic in case its shape has been blocking line of sight
or it is accompanying the hero to another level */
@@ -3146,6 +3159,9 @@ corpse_chance(
struct permonst *mdat = mon->data;
int i, tmp;
if (!magr && gm.mswallower && attacktype(gm.mswallower->data, AT_ENGL))
magr = gm.mswallower, was_swallowed = TRUE; /* for gas spore boom */
if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) {
if (cansee(mon->mx, mon->my) && !was_swallowed)
pline_mon(mon, "%s body crumbles into dust.",
@@ -3162,7 +3178,10 @@ corpse_chance(
tmp = d((int) mdat->mlevel + 1, (int) mdat->mattk[i].damd);
else
tmp = 0;
if (was_swallowed && magr) {
/* mdef is a gas spore (AT_BOOM) that is exploding inside an
engulfer; suppress usual explosion since it's contained */
if (magr == &gy.youmonst) {
There("is an explosion in your %s!", body_part(STOMACH));
Sprintf(svk.killer.name, "%s explosion",
@@ -3176,14 +3195,11 @@ corpse_chance(
mondied(magr);
if (DEADMONSTER(magr)) { /* maybe lifesaved */
if (canspotmon(magr))
pline_mon(magr, "%s rips open!",
Monnam(magr));
pline_mon(magr, "%s rips open!", Monnam(magr));
} else if (canseemon(magr))
pline_mon(magr,
"%s seems to have indigestion.",
pline_mon(magr, "%s seems to have indigestion.",
Monnam(magr));
}
return FALSE;
}

View File

@@ -5005,6 +5005,7 @@ gulpum(struct monst *mdef, struct attack *mattk)
"you totally digest <mdef>" will be coming soon (after
several turns) but the level-gain message seems out of
order if the kill message is left implicit */
gm.mswallower = &gy.youmonst;
xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE);
if (!DEADMONSTER(mdef)) { /* monster lifesaved */
You("hurriedly regurgitate the sizzling in your %s.",
@@ -5045,6 +5046,7 @@ gulpum(struct monst *mdef, struct attack *mattk)
} else
exercise(A_CON, TRUE);
}
gm.mswallower = (struct monst *) 0;
end_engulf();
return M_ATTK_DEF_DIED;
case AD_PHYS: