From 1f9e4d246888c867c54dbef1f2bc01e1cb7a17c0 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Apr 2020 12:24:02 -0700 Subject: [PATCH 1/2] corpse revival nitpicks Testing a forthcoming extension of monsters using wands of undead turning revealed a couple of pre-existing bugs. Previously only noticeable if hero zaps self or breaks a wand of undead turning so unlikely to have happened much. "Your corpse comes alive" was given even if it was revived as an undead. Also, it was "your corpse" instead of "one of your corpses" even when one from a stack was involved. If done by hero to self that message follows "one of your corpses glows iridescently" so the comes alive message was ok but verbose. Change that to "it comes alive" or "it reanimates" when following the glow message. --- doc/fixes37.0 | 4 +++- src/zap.c | 46 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index c888f8353..6feb94b74 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.172 $ $NHDT-Date: 1586384219 2020/04/08 22:16:59 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.175 $ $NHDT-Date: 1586633039 2020/04/11 19:23:59 $ General Fixes and Modified Features ----------------------------------- @@ -124,6 +124,8 @@ object taking erosion damage might give feedback message when out of view inventory when out-of-view ice melted] it's possible to wish for tins of the Riders in wizard mode; eating one is fatal but if you're life-saved or decline to die, the game crashed +revival via undead turning of corpse carried by hero said "your corpse + comes alive" even when revived monster was undead Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/zap.c b/src/zap.c index 998781488..52c65cb34 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1580322890 2020/01/29 18:34:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.330 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1586633039 2020/04/11 19:23:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.335 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -852,6 +852,7 @@ boolean by_hero; if (one_of) /* could be simplified to ''corpse->quan = 1L;'' */ corpse->quan--; pline("%s glows iridescently.", upstart(buf)); + iflags.last_msg = PLNMSG_OBJ_GLOWS; /* usually for BUC change */ } else if (shkp) { /* need some prior description of the corpse since stolen_value() will refer to the object as "it" */ @@ -957,11 +958,11 @@ struct monst *mon; struct obj *otmp, *otmp2; struct monst *mtmp2; char owner[BUFSZ], corpse[BUFSZ]; - boolean youseeit; - int res = 0; + boolean youseeit, different_type, is_u = (mon == &g.youmonst); + int corpsenm, res = 0; - youseeit = (mon == &g.youmonst) ? TRUE : canseemon(mon); - otmp2 = (mon == &g.youmonst) ? g.invent : mon->minvent; + youseeit = is_u ? TRUE : canseemon(mon); + otmp2 = is_u ? g.invent : mon->minvent; owner[0] = corpse[0] = '\0'; /* lint suppression */ while ((otmp = otmp2) != 0) { @@ -972,20 +973,43 @@ struct monst *mon; continue; /* save the name; the object is liable to go away */ if (youseeit) { - Strcpy(corpse, - corpse_xname(otmp, (const char *) 0, CXN_SINGULAR)); - Shk_Your(owner, otmp); /* includes a trailing space */ + Strcpy(corpse, corpse_xname(otmp, (const char *) 0, CXN_NORMAL)); + /* shk_your/Shk_Your produces a value with a trailing space */ + if (otmp->quan > 1L) { + Strcpy(owner, "One of "); + (void) shk_your(eos(owner), otmp); + } else + (void) Shk_Your(owner, otmp); } - - /* for a stack, only one is revived */ + /* for a stack, only one is revived; if is_u, revive() calls + useup() which calls update_inventory() but not encumber_msg() */ + corpsenm = otmp->corpsenm; if ((mtmp2 = revive(otmp, !g.context.mon_moving)) != 0) { ++res; + /* might get revived as a zombie rather than corpse's monster */ + different_type = (mtmp2->data != &mons[corpsenm]); + if (iflags.last_msg == PLNMSG_OBJ_GLOWS) { + /* when hero zaps undead turning at self (or breaks + non-empty wand), revive() reports "[one of] your + corpse[s] glows iridescently"; override saved corpse + and owner names to say "It comes alive" [note: we did + earlier setup because corpse gets used up but need to + do the override here after revive() sets 'last_msg'] */ + Strcpy(corpse, "It"); + owner[0] = '\0'; + } if (youseeit) - pline("%s%s suddenly comes alive!", owner, corpse); + pline("%s%s suddenly %s%s%s!", owner, corpse, + nonliving(mtmp2->data) ? "reanimates" : "comes alive", + different_type ? " as " : "", + different_type ? an(mtmp2->data->mname) : ""); else if (canseemon(mtmp2)) pline("%s suddenly appears!", Amonnam(mtmp2)); } } + if (is_u && res) + (void) encumber_msg(); + return res; } From d83f1c178b6832d91c95df21a2067f1360dacd7e Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Apr 2020 12:34:32 -0700 Subject: [PATCH 2/2] refinement of monster use of undead turning Instead of just picking up wands of undead turning when one or more corpses are in hero's inventory, have monsters also pick those up if hero has a cockatrice corpse in a carried container. And instead of only zapping such wands (as defensive measure) when hero is wielding a cockatrice corpse, also zap them (as offensive measure) if hero is carrying any corpse in open inventory. --- src/muse.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/muse.c b/src/muse.c index db124f0a3..ede7b9ed3 100644 --- a/src/muse.c +++ b/src/muse.c @@ -28,6 +28,7 @@ static struct permonst *FDECL(muse_newcham_mon, (struct monst *)); static int FDECL(mloot_container, (struct monst *mon, struct obj *, BOOLEAN_P)); static void FDECL(you_aggravate, (struct monst *)); +static boolean FDECL(necrophiliac, (struct obj *, BOOLEAN_P)); static void FDECL(mon_consume_unstone, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P)); static boolean FDECL(cures_stoning, (struct monst *, struct obj *, @@ -285,7 +286,7 @@ struct obj *otmp; #define MUSE_UNICORN_HORN 17 #define MUSE_POT_FULL_HEALING 18 #define MUSE_LIZARD_CORPSE 19 -#define MUSE_WAN_UNDEAD_TURNING 20 +#define MUSE_WAN_UNDEAD_TURNING 20 /* also an offensive item */ /* #define MUSE_INNATE_TPT 9999 * We cannot use this. Since monsters get unlimited teleportation, if they @@ -1092,6 +1093,8 @@ struct monst *mtmp; /*#define MUSE_WAN_TELEPORTATION 15*/ #define MUSE_POT_SLEEPING 16 #define MUSE_SCR_EARTH 17 +/*#define MUSE_WAN_UNDEAD_TURNING 20*/ /* also a defensive item so don't + * redefine; nonconsecutive value is ok */ /* Select an offensive item/action for a monster. Returns TRUE iff one is * found. @@ -1166,6 +1169,35 @@ struct monst *mtmp; g.m.has_offense = MUSE_WAN_MAGIC_MISSILE; } } + nomore(MUSE_WAN_UNDEAD_TURNING); + if (obj->otyp == WAN_UNDEAD_TURNING && obj->spe > 0 + /* not necrophiliac(); unlike deciding whether to pick this + type of wand up, we aren't interested in corpses within + carried containers until they're moved into open inventory; + we don't check whether hero is poly'd into an undead--the + wand's turning effect is too weak to be a useful direct + attack--only whether hero is carrying at least one corpse */ + && carrying(CORPSE)) { + /* + * Hero is carrying one or more corpses but isn't wielding + * a cockatrice corpse (unless being hit by one won't do + * the monster much harm); otherwise we'd be using this wand + * as a defensive item with higher priority. + * + * Might be cockatrice intended as a weapon (or being denied + * to glove-wearing monsters for use as a weapon) or lizard + * intended as a cure or lichen intended as veggy food or + * sacrifice fodder being lugged to an altar. Zapping with + * this will deprive hero of one from each stack although + * they might subsequently be recovered after killing again. + * In the sacrifice fodder case, it could even be to the + * player's advantage (fresher corpse if a new one gets + * dropped; player might not choose to spend a wand charge + * on that when/if hero acquires this wand). + */ + g.m.offensive = obj; + g.m.has_offense = MUSE_WAN_UNDEAD_TURNING; + } nomore(MUSE_WAN_STRIKING); if (obj->otyp == WAN_STRIKING && obj->spe > 0) { g.m.offensive = obj; @@ -1486,6 +1518,7 @@ struct monst *mtmp; g.m_using = FALSE; return (DEADMONSTER(mtmp)) ? 1 : 2; case MUSE_WAN_TELEPORTATION: + case MUSE_WAN_UNDEAD_TURNING: case MUSE_WAN_STRIKING: g.zap_oseen = oseen; mzapwand(mtmp, otmp, FALSE); @@ -2222,6 +2255,23 @@ struct monst *mtmp; return 0; } +/* check whether hero is carrying a corpse or contained petrifier corpse */ +static boolean +necrophiliac(objlist, any_corpse) +struct obj *objlist; +boolean any_corpse; +{ + while (objlist) { + if (objlist->otyp == CORPSE + && (any_corpse || touch_petrifies(&mons[objlist->corpsenm]))) + return TRUE; + if (Has_contents(objlist) && necrophiliac(objlist->cobj, FALSE)) + return TRUE; + objlist = objlist->nobj; + } + return FALSE; +} + boolean searches_for_item(mon, obj) struct monst *mon; @@ -2258,7 +2308,8 @@ struct obj *obj; || typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER) return TRUE; if (typ == WAN_UNDEAD_TURNING) - return carrying(CORPSE) || (Upolyd && is_undead(g.youmonst.data)); + return (necrophiliac(g.invent, TRUE) + || (Upolyd && is_undead(g.youmonst.data))); break; case POTION_CLASS: if (typ == POT_HEALING || typ == POT_EXTRA_HEALING