]> granicus.if.org Git - nethack/commitdiff
reimplement pull request #944 - grave contents
authorPatR <rankin@nethack.org>
Mon, 23 Jan 2023 19:38:15 +0000 (11:38 -0800)
committerPatR <rankin@nethack.org>
Mon, 23 Jan 2023 19:38:15 +0000 (11:38 -0800)
Pull request from entrez:  if bones left dead hero's corpse on top
of a new grave, don't find a corpse or summon a zombie when digging
the grave up.  It also removed the chance that a ghoul might be
summoned when engraving on a headstone, switching to zombie or mummy
instead.

Rather than adopting the pull request, this retains summoning a
ghoul via engraving and adds the possibly of doing so when kicking
a headstone.  Having a ghoul prowl around the grave is independent
of whether there is a corpse or zombie inside the grave.  To achieve
this, another flag in 'struct rm' is needed; the single bit for
'disturbed' isn't sufficient.  The bigger 'flags' field wasn't in
use for graves so commandeer that for new 'emptygrave'.  'disturbed'
still uses the 'horizontal' bit in order to have engraving and/or
kicking summon at most one ghoul.

Closes #944

doc/fixes3-7-0.txt
include/extern.h
include/rm.h
src/dig.c
src/dokick.c
src/end.c
src/engrave.c

index cd32946cd631c97289600ddb0e0dd6044a5a6a19..5c3478a999fe2b19c991d70f87bce4d63c8772b5 100644 (file)
@@ -1094,6 +1094,9 @@ demon gating happens more in Gehennom and less outside it
 intelligent peacefuls avoid digging shop or temple walls
 fix bug making random subrooms never touching the right or bottom
        wall of the parent room
+if a grave is created with the corpse lying on top (bones), don't find a
+       corpse or release a zombie or mummy when digging it up
+kicking a headstone might summon a ghoul
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index e6505b3132098651f81f7e5287c633fc92d635c0..90b1e0109aa7f197eb7e80c04b1d5cc2d4c620f6 100644 (file)
@@ -828,6 +828,7 @@ extern void engr_stats(const char *, char *, long *, long *);
 extern void del_engr(struct engr *);
 extern void rloc_engr(struct engr *);
 extern void make_grave(coordxy, coordxy, const char *);
+extern void disturb_grave(coordxy, coordxy);
 
 /* ### exper.c ### */
 
index 792f28727e44ae670de34fd7d58955689bbd095d..f3945149f8f49b011183962f2e47499b53448051 100644 (file)
@@ -328,10 +328,12 @@ struct rm {
 #define drawbridgemask flags /* what's underneath when the span is open */
 #define looted     flags /* used for throne, tree, fountain, sink, door */
 #define icedpool   flags /* used for ice (in case it melts) */
+#define emptygrave flags /* no corpse in grave */
 /* horizonal applies to walls, doors (including sdoor); also to iron bars
    even though they don't have separate symbols for horizontal and vertical */
 #define blessedftn horizontal /* a fountain that grants attribs */
-#define disturbed  horizontal /* a grave that has been disturbed */
+#define disturbed  horizontal /* kicking or engraving on a grave's headstone
+                               * has summoned a ghoul */
 
 struct damage {
     struct damage *next;
index 0bac89aa7cc28f2045f283d6663acc98561a7110..9fe99c7a197bfcb81b64751261aee445a6f3c8aa 100644 (file)
--- a/src/dig.c
+++ b/src/dig.c
@@ -908,6 +908,7 @@ static void
 dig_up_grave(coord *cc)
 {
     struct obj *otmp;
+    int what_happens;
     coordxy dig_x, dig_y;
 
     if (!cc) {
@@ -928,12 +929,15 @@ dig_up_grave(coord *cc)
     } else if (Role_if(PM_SAMURAI)) {
         adjalign(-sgn(u.ualign.type));
         You("disturb the honorable dead!");
-    } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) {
-        adjalign(-sgn(u.ualign.type));
+    } else if (u.ualign.type == A_LAWFUL) {
+        if (u.ualign.record > -10)
+            adjalign(-1);
         You("have violated the sanctity of this grave!");
     }
 
-    switch (rn2(5)) {
+    /* -1: force default case for empty grave */
+    what_happens = levl[dig_x][dig_y].emptygrave ? -1 : rn2(5);
+    switch (what_happens) {
     case 0:
     case 1:
         You("unearth a corpse.");
@@ -942,22 +946,24 @@ dig_up_grave(coord *cc)
         break;
     case 2:
         if (!Blind)
-            pline(Hallucination ? "Dude!  The living dead!"
-                                : "The grave's owner is very upset!");
+            pline("%s!", Hallucination ? "Dude!  The living dead"
+                                       : "The grave's owner is very upset");
         (void) makemon(mkclass(S_ZOMBIE, 0), dig_x, dig_y, MM_NOMSG);
         break;
     case 3:
         if (!Blind)
-            pline(Hallucination ? "I want my mummy!"
-                                : "You've disturbed a tomb!");
+            pline("%s!", Hallucination ? "I want my mummy"
+                                       : "You've disturbed a tomb");
         (void) makemon(mkclass(S_MUMMY, 0), dig_x, dig_y, MM_NOMSG);
         break;
     default:
         /* No corpse */
-        pline_The("grave seems unused.  Strange....");
+        pline_The("grave is unoccupied.  Strange...");
         break;
     }
-    levl[dig_x][dig_y].typ = ROOM, levl[dig_x][dig_y].flags = 0;
+    levl[dig_x][dig_y].typ = ROOM;
+    levl[dig_x][dig_y].emptygrave = 0; /* clear 'flags' */
+    levl[dig_x][dig_y].disturbed = 0; /* clear 'horizontal' */
     del_engr_at(dig_x, dig_y);
     newsym(dig_x, dig_y);
     return;
index 676764114038f9d67e097f85ce9980a57f929206..c310833c560811b19a3319aa352cf977b6386b73 100644 (file)
@@ -874,6 +874,7 @@ kick_ouch(coordxy x, coordxy y, const char *kickobjnam)
             (void) find_drawbridge(&x, &y);
             gm.maploc = &levl[x][y];
         }
+        wake_nearto(x, y, 5 * 5);
     }
     if (!rn2(3))
         set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
@@ -1098,9 +1099,8 @@ dokick(void)
                 pline("Crash!  %s a secret door!",
                       /* don't "kick open" when it's locked
                          unless it also happens to be trapped */
-                      (gm.maploc->doormask & (D_LOCKED | D_TRAPPED)) == D_LOCKED
-                          ? "Your kick uncovers"
-                          : "You kick open");
+                      ((gm.maploc->doormask & (D_LOCKED | D_TRAPPED))
+                       == D_LOCKED) ? "Your kick uncovers" : "You kick open");
                 exercise(A_DEX, TRUE);
                 if (gm.maploc->doormask & D_TRAPPED) {
                     gm.maploc->doormask = D_NODOOR;
@@ -1217,26 +1217,33 @@ dokick(void)
         if (IS_GRAVE(gm.maploc->typ)) {
             if (Levitation) {
                 kick_dumb(x, y);
-                return ECMD_TIME;
-            }
-            if (rn2(4)) {
+            } else if (rn2(4)) {
+                /* minor injury */
                 kick_ouch(x, y, "");
-                return ECMD_TIME;
-            }
-            exercise(A_WIS, FALSE);
-            if (Role_if(PM_ARCHEOLOGIST) || Role_if(PM_SAMURAI)
-                || ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10))) {
-                adjalign(-sgn(u.ualign.type));
-            }
-            gm.maploc->typ = ROOM;
-            gm.maploc->doormask = 0;
-            (void) mksobj_at(ROCK, x, y, TRUE, FALSE);
-            del_engr_at(x, y);
-            if (Blind)
-                pline("Crack!  %s broke!", Something);
-            else {
-                pline_The("headstone topples over and breaks!");
-                newsym(x, y);
+            } else if (!gm.maploc->disturbed && !rn2(2)) {
+                /* disturb the grave: summon a ghoul (once only), same as
+                   when engraving */
+                disturb_grave(x, y);
+            } else {
+                /* destroy the headstone, implicitly destroying any
+                   not-yet-created contents (including zombie or mummy);
+                   any already created contents will still be buried here */
+                exercise(A_WIS, FALSE);
+                if (Role_if(PM_ARCHEOLOGIST) || Role_if(PM_SAMURAI)
+                    || (u.ualign.type == A_LAWFUL && u.ualign.record > -10))
+                    adjalign(-sgn(u.ualign.type));
+                gm.maploc->typ = ROOM;
+                gm.maploc->emptygrave = 0; /* clear 'flags' */
+                gm.maploc->disturbed = 0; /* clear 'horizontal' */
+                (void) mksobj_at(ROCK, x, y, TRUE, FALSE);
+                del_engr_at(x, y);
+                if (Blind) {
+                    /* [feel this happen if Deaf?] */
+                    pline("Crack!  %s broke!", Something);
+                } else {
+                    pline_The("headstone topples over and breaks!");
+                    newsym(x, y);
+                }
             }
             return ECMD_TIME;
         }
index 3d9b7c7f96e0c60b7f4aa2f6f224a20c99a090d4..6d1bed706939ab06be24976e43c4e99d76585b26 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -1429,12 +1429,15 @@ really_done(int how)
         && !(gm.mvitals[u.umonnum].mvflags & G_NOCORPSE)) {
         /* Base corpse on race when not poly'd since original u.umonnum
            is based on role, and all role monsters are human. */
-        int mnum = !Upolyd ? gu.urace.mnum : u.umonnum;
+        int mnum = !Upolyd ? gu.urace.mnum : u.umonnum,
+            was_already_grave = IS_GRAVE(levl[u.ux][u.uy].typ);
 
         corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, gp.plname);
         Sprintf(pbuf, "%s, ", gp.plname);
         formatkiller(eos(pbuf), sizeof pbuf - Strlen(pbuf), how, TRUE);
         make_grave(u.ux, u.uy, pbuf);
+        if (IS_GRAVE(levl[u.ux][u.uy].typ && !was_already_grave))
+            levl[u.ux][u.uy].emptygrave = 1; /* corpse isn't buried */
     }
     pbuf[0] = '\0'; /* clear grave text; also lint suppression */
 
index 7607aa8669c6ead2d531ba7a0effb8483c9e1b02..c2e0e52081d00df8d45a393711652277abaf3f5e 100644 (file)
@@ -614,10 +614,10 @@ doengrave(void)
                 surface(u.ux, u.uy));
             return ECMD_OK;
         } else if (!levl[u.ux][u.uy].disturbed) {
-            You("disturb the undead!");
-            levl[u.ux][u.uy].disturbed = 1;
-            (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
-            exercise(A_WIS, FALSE);
+            /* disturb the grave: summon a ghoul, same as sometimes
+               happens when kicking; sets levl[ux][uy]->disturbed so
+               that it'll only happen once */
+            disturb_grave(u.ux, u.uy);
             return ECMD_TIME;
         }
     }
@@ -1475,6 +1475,24 @@ make_grave(coordxy x, coordxy y, const char *str)
     return;
 }
 
+/* called when kicking or engraving on a grave's headstone */
+void
+disturb_grave(coordxy x, coordxy y)
+{
+    struct rm *lev = &levl[x][y];
+
+    if (!IS_GRAVE(lev->typ)) {
+        impossible("Disturing grave that isn't a grave? (%d)", lev->typ);
+    } else if (lev->disturbed) {
+        impossible("Disturing already disturbed grave?");
+    } else {
+        You("disturb the undead!");
+        lev->disturbed = 1;
+        (void) makemon(&mons[PM_GHOUL], x, y, NO_MM_FLAGS);
+        exercise(A_WIS, FALSE);
+    }
+}
+
 static const char blind_writing[][21] = {
     {0x44, 0x66, 0x6d, 0x69, 0x62, 0x65, 0x22, 0x45, 0x7b, 0x71,
      0x65, 0x6d, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },