From 2b04cc9f5b8ce794d0a37665bd2ca4d8a226478d Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 15 Sep 2022 18:02:07 -0700 Subject: [PATCH] fix issue #843 - vampire revival sequencing Reported by Umbire: |You kill SpaceMannSpiff! SpaceMannSpiff puts on a dwarvish cloak. |SpaceMannSpiff puts on a dwarvish iron helm. |The seemingly dead SpaceMannSpiff suddenly transforms and rises as | a Vampire. This was tough to reproduce but I finally managed it. The issue text mentions that it was fixed by copperwater in xNetHack with commit 8c4af50f0aa3e72522f3eb98df039ff25c2a1ea0 to the repository for that variant. My attempt to cherry-pick that failed--I'm not even sure whether it should have been expected to work--and some of the code has been impinged upon by changes, so I ended up applying the contents of that commit manually. The commit changes how/when monsters put on new armor rather than anything directly related to vampires. Circumstances similar to the example above now yield: |You kill SpaceMannSpiff! |The seemingly dead SpaceMannSpiff suddenly transforms and rises as | a Vampire. on one turn, then on the next turn the revived vampire produces: |SpaceMannSpiff puts on a dwarvish cloak. My test case only had one item of interest; I assume that the second item of armor gets worn on a subsequent turn rather than at the same time as the first one. Fixes #843 --- doc/fixes3-7-0.txt | 3 +++ include/extern.h | 1 + src/dogmove.c | 2 +- src/mon.c | 34 ++++++++++++++++++++++++++-------- src/worn.c | 2 +- src/zap.c | 5 +++-- 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index bc79815cd..1154b5954 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1988,6 +1988,9 @@ vampire shapeshifting in a door (pr #794 by entrez) split "act_on_act" into separate function (pr #777 by argrath) unnecessary null-check on parsesymbols() (pr #793 by argrath) split cleaning-up on gd_move() into separate function (pr #791 by argrath) +from xNetHack: better handling for monsters putting on equipment; fixes + issue #843: "Mon dies. Mon puts on . The seemingly dead Mon + rises as a vampire." Code Cleanup and Reorganization diff --git a/include/extern.h b/include/extern.h index bbb337376..d92650bfb 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1603,6 +1603,7 @@ extern boolean angry_guards(boolean); extern void pacify_guards(void); extern void decide_to_shapeshift(struct monst *, int); extern boolean vamp_stone(struct monst *); +extern void check_gear_next_turn(struct monst *); /* ### mondata.c ### */ diff --git a/src/dogmove.c b/src/dogmove.c index 5bfea859e..9aaff21b0 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -502,7 +502,7 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist) mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } - m_dowear(mtmp, FALSE); + check_gear_next_turn(mtmp); } } } diff --git a/src/mon.c b/src/mon.c index 6e54e60ce..123b930a2 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1009,11 +1009,18 @@ movemon_singlemon(struct monst *mtmp) if (mtmp->misc_worn_check & I_SPECIAL) { long oldworn; - mtmp->misc_worn_check &= ~I_SPECIAL; - oldworn = mtmp->misc_worn_check; - m_dowear(mtmp, FALSE); - if (mtmp->misc_worn_check != oldworn || !mtmp->mcanmove) - return FALSE; + /* hostiles only try to equip things if they think hero isn't + * nearby; if they think hero is nearby, leave the flag intact so + * that it can be checked again on subsequent moves until the hero + * is perceived to be farther away. */ + if (mtmp->mpeaceful || mtmp->mtame + || dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > (3 * 3)) { + mtmp->misc_worn_check &= ~I_SPECIAL; + oldworn = mtmp->misc_worn_check; + m_dowear(mtmp, FALSE); + if (mtmp->misc_worn_check != oldworn || !mtmp->mcanmove) + return FALSE; /* is spending this turn equipping */ + } } if (is_hider(mtmp->data)) { @@ -1636,7 +1643,8 @@ mpickstuff(struct monst *mtmp, const char *str) } obj_extract_self(otmp3); /* remove from floor */ (void) mpickobj(mtmp, otmp3); /* may merge and free otmp3 */ - m_dowear(mtmp, FALSE); + /* let them try and equip it on the next turn */ + check_gear_next_turn(mtmp); newsym(mtmp->mx, mtmp->my); return TRUE; /* pick only one object */ } @@ -2519,7 +2527,7 @@ lifesaved_monster(struct monst* mtmp) } m_useup(mtmp, lifesave); /* equip replacement amulet, if any, on next move */ - mtmp->misc_worn_check |= I_SPECIAL; + check_gear_next_turn(mtmp); surviver = !(g.mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); mtmp->mcanmove = 1; @@ -4757,7 +4765,7 @@ newcham( if (!(mtmp->misc_worn_check & W_ARMG)) mselftouch(mtmp, "No longer petrify-resistant, ", !g.context.mon_moving); - m_dowear(mtmp, FALSE); + check_gear_next_turn(mtmp); /* This ought to re-test can_carry() on each item in the inventory * rather than just checking ex-giants & boulders, but that'd be @@ -5160,4 +5168,14 @@ usmellmon(struct permonst* mdat) return msg_given ? TRUE : FALSE; } +/* setting misc_worn_check's I_SPECIAL bit flags a monster to reassess + and potentially re-equip gear at the start of its next move; + this hides the details of that */ +void +check_gear_next_turn(mon) +struct monst *mon; +{ + mon->misc_worn_check |= I_SPECIAL; +} + /*mon.c*/ diff --git a/src/worn.c b/src/worn.c index 45afbb51c..ca056fefa 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1145,7 +1145,7 @@ extract_from_minvent( mon->misc_worn_check &= ~unwornmask; /* give monster a chance to wear other equipment on its next move instead of waiting until it picks something up */ - mon->misc_worn_check |= I_SPECIAL; + check_gear_next_turn(mon); } obj_no_longer_held(obj); if (unwornmask & W_WEP) { diff --git a/src/zap.c b/src/zap.c index afa1f6ba3..5e18c01a8 100644 --- a/src/zap.c +++ b/src/zap.c @@ -178,7 +178,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) if (disguised_mimic) seemimic(mtmp); mon_adjust_speed(mtmp, -1, otmp); - m_dowear(mtmp, FALSE); /* might want speed boots */ + check_gear_next_turn(mtmp); /* might want speed boots */ + if (engulfing_u(mtmp) && is_whirly(mtmp->data)) { You("disrupt %s!", mon_nam(mtmp)); pline("A huge hole opens up..."); @@ -191,7 +192,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) if (disguised_mimic) seemimic(mtmp); mon_adjust_speed(mtmp, 1, otmp); - m_dowear(mtmp, FALSE); /* might want speed boots */ + check_gear_next_turn(mtmp); /* might want speed boots */ } if (mtmp->mtame) helpful_gesture = TRUE;