]> granicus.if.org Git - nethack/commitdiff
fix #H7530 - corpse from corpseless monster
authorPatR <rankin@nethack.org>
Tue, 20 Nov 2018 21:13:23 +0000 (13:13 -0800)
committerPatR <rankin@nethack.org>
Tue, 20 Nov 2018 21:13:23 +0000 (13:13 -0800)
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.

doc/fixes36.2
src/dog.c
src/mon.c

index f4cfd00a16db0a4192e0f751616914609a1a910a..5d18bb3e87555ca007ee698f73d74bf3018d5bfe 100644 (file)
@@ -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
index 85e61823625a4f79116fe6e02a9154e943f434d4..144427e0d5ac03944f15121dce21685c2ef6c421 100644 (file)
--- 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);
         }
index 785b691b51134628092a5c23d7a1a0b750b7abe5..64f906e6bd34130b72c890e339b174565f77491b 100644 (file)
--- 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 */