From: PatR Date: Tue, 20 Nov 2018 21:13:23 +0000 (-0800) Subject: fix #H7530 - corpse from corpseless monster X-Git-Tag: nmake-explicit-path~154 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d15dacc44cd2835e7864522a060f86ca12191801;p=nethack fix #H7530 - corpse from corpseless monster Migrating monster attempting to arrive on a level which is already full of monsters gets killed off. It was leaving a corpse without regard for whether it was a type of of monster which should never leave corpses. I'd prefer that it be put back on the migrating_mons list rather than be killed off, but this just suppresses impossible corpses. --- diff --git a/doc/fixes36.2 b/doc/fixes36.2 index f4cfd00a1..5d18bb3e8 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -202,6 +202,9 @@ a stale gold symbol could be displayed on the status line following a switch to a new symset, as observed and reported for Windows RogueEpyx symset successfully paying for shop damage with shop credit would be followed by impossible "zero payment in money2mon" +if a migrating monster was killed off because there was no room on the + destination level, it would leave a corpse even if it was a type + which should never leave one (demon, golem, blob, &c) Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/dog.c b/src/dog.c index 85e618236..144427e0d 100644 --- a/src/dog.c +++ b/src/dog.c @@ -7,6 +7,11 @@ STATIC_DCL int NDECL(pet_type); +/* cloned from mon.c; used here if mon_arrive() can't place mon */ +#define LEVEL_SPECIFIC_NOCORPSE(mdat) \ + (Is_rogue_level(&u.uz) \ + || (level.flags.graveyard && is_undead(mdat) && rn2(3))) + void newedog(mtmp) struct monst *mtmp; @@ -79,6 +84,7 @@ boolean quietly; do { if (otmp) { /* figurine; otherwise spell */ int mndx = otmp->corpsenm; + pm = &mons[mndx]; /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless @@ -294,6 +300,7 @@ struct monst *mtmp; boolean with_you; { struct trap *t; + struct obj *obj; xchar xlocale, ylocale, xyloc, xyflags, wander; int num_segs; @@ -417,8 +424,10 @@ boolean with_you; /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ char *r = in_rooms(xlocale, ylocale, 0); + if (r && *r) { coord c; + /* somexy() handles irregular rooms */ if (somexy(&rooms[*r - ROOMOFFSET], &c)) xlocale = c.x, ylocale = c.y; @@ -426,6 +435,7 @@ boolean with_you; xlocale = ylocale = 0; } else { /* not in a room */ int i, j; + i = max(1, xlocale - wander); j = min(COLNO - 1, xlocale + wander); xlocale = rn1(j - i, i); @@ -446,8 +456,11 @@ boolean with_you; * Failed to place migrating monster, * probably because the level is full. * Dump the monster's cargo and leave the monster dead. + * + * TODO? Put back on migrating_mons list instead so + * that if hero leaves this level and then returns, + * monster will have another chance to arrive. */ - struct obj *obj; fail_mon_placement: while ((obj = mtmp->minvent) != 0) { obj_extract_self(obj); @@ -462,8 +475,15 @@ fail_mon_placement: impossible("Can't find relocated object."); } } - (void) mkcorpstat(CORPSE, (struct monst *) 0, mtmp->data, xlocale, - ylocale, CORPSTAT_NONE); + /* + * TODO? Maybe switch to make_corpse() [won't be needed if + * we re-migrate as suggested above], probably with new + * CORPSTAT_NOOBJS flag to suppress dragon scales and such. + */ + if (!(mvitals[monsndx(mtmp->data)].mvflags & G_NOCORPSE) + && !LEVEL_SPECIFIC_NOCORPSE(mtmp->data)) + (void) mkcorpstat(CORPSE, mtmp, mtmp->data, + xlocale, ylocale, CORPSTAT_NONE); mtmp->mx = mtmp->my = -1; /* for mongone, mon is not anywhere */ mongone(mtmp); } diff --git a/src/mon.c b/src/mon.c index 785b691b5..64f906e6b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -29,6 +29,7 @@ STATIC_DCL struct obj *FDECL(make_corpse, (struct monst *, unsigned)); STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); STATIC_DCL void FDECL(lifesaved_monster, (struct monst *)); +/* note: duplicated in dog.c */ #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ (Is_rogue_level(&u.uz) \ || (level.flags.graveyard && is_undead(mdat) && rn2(3))) @@ -446,7 +447,8 @@ unsigned corpseflags; } /* All special cases should precede the G_NOCORPSE check */ - if (!obj) return NULL; + if (!obj) + return (struct obj *) 0; /* if polymorph or undead turning has killed this monster, prevent the same attack beam from hitting its corpse */