From: PatR Date: Mon, 23 Jan 2023 19:38:15 +0000 (-0800) Subject: reimplement pull request #944 - grave contents X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c5aad9fe5641ad6f5746c52cedf79b3b23128a75;p=nethack reimplement pull request #944 - grave contents 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 --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index cd32946cd..5c3478a99 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -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 diff --git a/include/extern.h b/include/extern.h index e6505b313..90b1e0109 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 ### */ diff --git a/include/rm.h b/include/rm.h index 792f28727..f3945149f 100644 --- a/include/rm.h +++ b/include/rm.h @@ -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; diff --git a/src/dig.c b/src/dig.c index 0bac89aa7..9fe99c7a1 100644 --- 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; diff --git a/src/dokick.c b/src/dokick.c index 676764114..c310833c5 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -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; } diff --git a/src/end.c b/src/end.c index 3d9b7c7f9..6d1bed706 100644 --- 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 */ diff --git a/src/engrave.c b/src/engrave.c index 7607aa866..c2e0e5208 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -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 },