From 7bc36ddef41f0bf58ab5440c8d5e4c3892614e2c Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 23 Dec 2018 12:37:26 -0800 Subject: [PATCH 1/3] fix #H6942 - dropx vs hold_another_object Dropping an existing fragile item while levitating will usually break it. Getting a new wished-for fragile item and dropping it because of fumbling or overfull inventory never would. Some callers of hold_another_object() held on to its return value, others discarded that. That return value was unsafe if the item was dropped and fell down a hole (or broke [after this change]). Return Null if we can't be sure of the value, and make sure all callers are prepared to deal with Null. --- doc/fixes36.2 | 1 + include/extern.h | 4 ++-- src/artifact.c | 8 +++++--- src/do.c | 4 ++-- src/dothrow.c | 22 +++++++++++----------- src/invent.c | 24 +++++++++++++++++------- src/mail.c | 16 +++++++++------- src/mkobj.c | 23 +++++++++++++---------- src/pickup.c | 5 +++-- src/potion.c | 3 ++- src/uhitm.c | 5 +++-- 11 files changed, 68 insertions(+), 47 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 01b2f33b7..7be5fc556 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -303,6 +303,7 @@ training riding skill had an off-by-one bug when counting turns riding message sequencing when vampire shifts to fog cloud to pass under closed door: when in sight, give form change message before moving to door spot limit carrying heavy loads from water to land +failing to carry a wished-for item behaved differenctly from dropping one Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 78c7647da..7a239f127 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1545383614 2018/12/21 09:13:34 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.675 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1545597403 2018/12/23 20:36:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.676 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -536,7 +536,7 @@ E void FDECL(impact_drop, (struct obj *, XCHAR_P, XCHAR_P, XCHAR_P)); E int NDECL(dothrow); E int NDECL(dofire); E void FDECL(endmultishot, (BOOLEAN_P)); -E void FDECL(hitfloor, (struct obj *)); +E void FDECL(hitfloor, (struct obj *, BOOLEAN_P)); E void FDECL(hurtle, (int, int, int, BOOLEAN_P)); E void FDECL(mhurtle, (struct monst *, int, int, int)); E boolean FDECL(throwing_weapon, (struct obj *)); diff --git a/src/artifact.c b/src/artifact.c index 80332f325..2a641b8d7 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 artifact.c $NHDT-Date: 1543745353 2018/12/02 10:09:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.127 $ */ +/* NetHack 3.6 artifact.c $NHDT-Date: 1545597414 2018/12/23 20:36:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1479,6 +1479,7 @@ struct obj *obj; } case ENERGY_BOOST: { int epboost = (u.uenmax + 1 - u.uen) / 2; + if (epboost > 120) epboost = 120; /* arbitrary */ else if (epboost < 12) @@ -1598,6 +1599,7 @@ struct obj *obj; otmp->owt = weight(otmp); otmp = hold_another_object(otmp, "Suddenly %s out.", aobjnam(otmp, "fall"), (char *) 0); + nhUse(otmp); break; } } @@ -1621,7 +1623,7 @@ struct obj *obj; } if ((eprop & ~W_ARTI) || iprop) { - nothing_special: + nothing_special: /* you had the property from some other source too */ if (carried(obj)) You_feel("a surge of power, but nothing seems to happen."); @@ -1975,7 +1977,7 @@ boolean loseit; /* whether to drop it if hero can longer touch it */ if (loseit && obj) { if (Levitation) { freeinv(obj); - hitfloor(obj); + hitfloor(obj, TRUE); } else { /* dropx gives a message iff item lands on an altar */ if (!IS_ALTAR(levl[u.ux][u.uy].typ)) diff --git a/src/do.c b/src/do.c index 3438a44b1..b05339df4 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1545043771 2018/12/17 10:49:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.181 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1545597418 2018/12/23 20:36:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.182 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -612,7 +612,7 @@ register struct obj *obj; if (obj->oclass == COIN_CLASS) context.botl = 1; freeinv(obj); - hitfloor(obj); + hitfloor(obj, TRUE); if (levhack) float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART); return 1; diff --git a/src/dothrow.c b/src/dothrow.c index b3a2f8ba4..de1afca9c 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1545044705 2018/12/17 11:05:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.154 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1545597420 2018/12/23 20:37:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.155 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -415,21 +415,21 @@ boolean verbose; } } -/* - * Object hits floor at hero's feet. Called from drop() and throwit(). - */ +/* Object hits floor at hero's feet. + Called from drop(), throwit(), hold_another_object(). */ void -hitfloor(obj) -register struct obj *obj; +hitfloor(obj, verbosely) +struct obj *obj; +boolean verbosely; /* usually True; False if caller has given drop message */ { - if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) { + if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater || u.uswallow) { dropy(obj); return; } if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); - else - pline("%s hit%s the %s.", Doname2(obj), (obj->quan == 1L) ? "s" : "", + else if (verbosely) + pline("%s %s the %s.", Doname2(obj), otense(obj, "hit"), surface(u.ux, u.uy)); if (hero_breaks(obj, u.ux, u.uy, TRUE)) @@ -1047,7 +1047,7 @@ boolean hitsroof; done(STONING); return obj ? TRUE : FALSE; } - hitfloor(obj); + hitfloor(obj, TRUE); thrownobj = 0; losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN); } @@ -1168,7 +1168,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ for dealing with cursed saddle: throw holy water > */ potionhit(u.usteed, obj, POTHIT_HERO_THROW); } else { - hitfloor(obj); + hitfloor(obj, TRUE); } thrownobj = (struct obj *) 0; return; diff --git a/src/invent.c b/src/invent.c index 93939ad86..62ec70401 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1545043772 2018/12/17 10:49:32 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.244 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1545597422 2018/12/23 20:37:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.245 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -975,9 +975,9 @@ const char *drop_fmt, *drop_arg, *hold_msg; } } if (Fumbling) { - if (drop_fmt) - pline(drop_fmt, drop_arg); - dropy(obj); + obj->nomerge = 1; + obj = addinv(obj); /* dropping expects obj to be in invent */ + goto drop_it; } else { long oquan = obj->quan; int prev_encumbr = near_capacity(); /* before addinv() */ @@ -994,12 +994,10 @@ const char *drop_fmt, *drop_arg, *hold_msg; obj = addinv(obj); if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed) && near_capacity() > prev_encumbr)) { - if (drop_fmt) - pline(drop_fmt, drop_arg); /* undo any merge which took place */ if (obj->quan > oquan) obj = splitobj(obj, oquan); - dropx(obj); + goto drop_it; } else { if (flags.autoquiver && !uquiver && !obj->owornmask && (is_missile(obj) || ammo_and_launcher(obj, uwep) @@ -1010,6 +1008,18 @@ const char *drop_fmt, *drop_arg, *hold_msg; } } return obj; + + drop_it: + if (drop_fmt) + pline(drop_fmt, drop_arg); + obj->nomerge = 0; + if (can_reach_floor(TRUE)) { + dropx(obj); + } else { + freeinv(obj); + hitfloor(obj, FALSE); + } + return (struct obj *) 0; /* might be gone */ } /* useup() all of an item regardless of its quantity */ diff --git a/src/mail.c b/src/mail.c index b3f8e97c6..63142ad51 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mail.c $NHDT-Date: 1542765359 2018/11/21 01:55:59 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */ +/* NetHack 3.6 mail.c $NHDT-Date: 1545597424 2018/12/23 20:37:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -186,7 +186,7 @@ coord *startp; */ lax = 0; /* be picky */ max_distance = -1; -retry: + retry: for (row = 0; row < ROWNO; row++) { if (viz_rmin[row] < viz_rmax[row]) { /* There are valid positions on this row. */ @@ -418,15 +418,17 @@ struct mail_info *info; display_nhwindow(WIN_MESSAGE, FALSE); obj = hold_another_object(obj, "Oops!", (const char *) 0, (const char *) 0); + nhUse(obj); } -/* zip back to starting location */ -go_back: + go_back: + /* zip back to starting location */ if (!md_rush(md, start.x, start.y)) md->mx = md->my = 0; /* for mongone, md is not on map */ mongone(md); -/* deliver some classes of messages even if no daemon ever shows up */ -give_up: + + give_up: + /* deliver some classes of messages even if no daemon ever shows up */ if (!message_seen && info->message_typ == MSG_OTHER) pline("Hark! \"%s.\"", info->display_txt); } @@ -609,7 +611,7 @@ boolean adminmsg; else unlink(mailbox); return; -bail: + bail: /* bail out _professionally_ */ if (!adminmsg) pline("It appears to be all gibberish."); diff --git a/src/mkobj.c b/src/mkobj.c index 9a0ec48f2..50140fe1f 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkobj.c $NHDT-Date: 1542798624 2018/11/21 11:10:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.136 $ */ +/* NetHack 3.6 mkobj.c $NHDT-Date: 1545597425 2018/12/23 20:37:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.137 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2168,18 +2168,21 @@ boolean tipping; /* caller emptying entire contents; affects shop handling */ being included in its formatted name during next message */ iflags.suppress_price++; if (!tipping) { - obj = hold_another_object( - obj, u.uswallow ? "Oops! %s out of your reach!" - : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) - || levl[u.ux][u.uy].typ < IRONBARS - || levl[u.ux][u.uy].typ >= ICE) - ? "Oops! %s away from you!" - : "Oops! %s to the floor!", - The(aobjnam(obj, "slip")), (const char *) 0); + obj = hold_another_object(obj, + u.uswallow + ? "Oops! %s out of your reach!" + : (Is_airlevel(&u.uz) + || Is_waterlevel(&u.uz) + || levl[u.ux][u.uy].typ < IRONBARS + || levl[u.ux][u.uy].typ >= ICE) + ? "Oops! %s away from you!" + : "Oops! %s to the floor!", + The(aobjnam(obj, "slip")), (char *) 0); + nhUse(obj); } else { /* assumes this is taking place at hero's location */ if (!can_reach_floor(TRUE)) { - hitfloor(obj); /* does altar check, message, drop */ + hitfloor(obj, TRUE); /* does altar check, message, drop */ } else { if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); /* does its own drop message */ diff --git a/src/pickup.c b/src/pickup.c index 65a541d12..a8b611454 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1543188989 2018/11/25 23:36:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.220 $ */ +/* NetHack 3.6 pickup.c $NHDT-Date: 1545597427 2018/12/23 20:37:07 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.221 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2023,6 +2023,7 @@ boolean *prev_loot; } otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), (const char *) 0); + nhUse(otmp); timepassed = rnd(3); if (prev_loot) *prev_loot = TRUE; @@ -3188,7 +3189,7 @@ struct obj *box; /* or bag */ if (highdrop) { /* might break or fall down stairs; handles altars itself */ - hitfloor(otmp); + hitfloor(otmp, TRUE); } else { if (altarizing) { doaltarobj(otmp); diff --git a/src/potion.c b/src/potion.c index a6bf5f656..482321692 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 potion.c $NHDT-Date: 1545182147 2018/12/19 01:15:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.156 $ */ +/* NetHack 3.6 potion.c $NHDT-Date: 1545597429 2018/12/23 20:37:09 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.157 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2237,6 +2237,7 @@ more_dips: singlepotion = hold_another_object(singlepotion, "You juggle and drop %s!", doname(singlepotion), (const char *) 0); + nhUse(singlepotion); update_inventory(); return 1; } diff --git a/src/uhitm.c b/src/uhitm.c index 01c423593..fa50677dc 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1544840256 2018/12/15 02:17:36 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.196 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1545597432 2018/12/23 20:37:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.197 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1546,7 +1546,8 @@ struct attack *mattk; /* give the object to the character */ otmp = hold_another_object(otmp, "You snatched but dropped %s.", doname(otmp), "You steal: "); - if (otmp->where != OBJ_INVENT) + /* might have dropped otmp, and it might have broken or left level */ + if (!otmp || otmp->where != OBJ_INVENT) continue; if (theft_petrifies(otmp)) break; /* stop thieving even though hero survived */ From f6d5862c0d384489b5ec41249802bb4831ce4e8b Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 23 Dec 2018 17:25:14 -0800 Subject: [PATCH 2/3] implement #H6051 - fake players resist Conflict The rationale is that since the player character resists conflict, fake players should too. [I'm not sure that I buy that. Player character is always the one *causing* conflict and it doesn't affect self. But this is simple as long as no other resistance checks are against attack-by-ring.] --- doc/fixes36.2 | 8 +++++--- src/zap.c | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 7be5fc556..aa0a07c87 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -156,9 +156,6 @@ a wand of polymorph lost its magical ability for the turn just because the much sense floating eye is classified as a flyer but flying is blocked while levitating, so don't set intrinsic flying if hero is polymorphed into one -being trapped (bear trap, web, molten or solidified lava, chained to buried - iron ball) blocks both levitation and flight (note: being stuck in a - pit ends when either of those starts so doesn't apply) change default value for the 'autodescribe' option to 'on' Elbereth hypocrisy penalty doesn't apply if attacking a monster which isn't frightened by Elbereth; normal scuffing of engravings still applies @@ -452,6 +449,11 @@ for ^X and enlightenment, display the information in a menu rather than a needed for interfaces (tty) without text popup scrollbar support; end of game disclosure of attributes remains single-forward-pass for ^X, include current state of 'autopickup' +being trapped (bear trap, web, molten or solidified lava, chained to buried + iron ball) blocks both levitation and flight (note: being stuck in a + pit ends when either of those starts so doesn't apply) +early level traps are sometimes covered by the remains of fake players +fake player characters resist Conflict NetHack Community Patches (or Variation) Included diff --git a/src/zap.c b/src/zap.c index eb61a261c..ba90e34c3 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1545431660 2018/12/21 22:34:20 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.303 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1545614662 2018/12/24 01:24:22 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.304 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5090,6 +5090,11 @@ int damage, tell; int resisted; int alev, dlev; + /* fake players always pass resistance test against Conflict + (this doesn't guarantee that they're never affected by it) */ + if (oclass == RING_CLASS && !damage && !tell && is_mplayer(mtmp->data)) + return 1; + /* attack level */ switch (oclass) { case WAND_CLASS: From e2852f25fd02bb5a1205b2a4f9af5b3ee41ba06f Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 24 Dec 2018 02:08:44 -0800 Subject: [PATCH 3/3] fix temporary strength loss that was permanent Watching the fuzzer, I saw hero's strength plummet to 3 again and not rise above 5 after that. It turns out to be due to life-saving, which was fixing severe hunger but was not restoring the point of strength that's lost when you go from hungry to weak. I'm not sure whether this was caused by 3.6.1's commit 024e9e122576db664e37df0937cfb4c06c436e0c or already behaved that way. Another fuzzer bit: the monk I was watching was bitten by a wererat early on and was still inflicted with lycanthropy when he reached level 19. (I've no idea how his level got to be so high; it jumped from 14 to 19 while I wasn't paying attention.) Extend the earlier hack for drinking a blessed potion of restore ability to recover lost characteristcs to sometimes drink a potion of holy water instead. --- doc/fixes36.2 | 2 ++ src/end.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index aa0a07c87..dbe5691c9 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -301,6 +301,8 @@ message sequencing when vampire shifts to fog cloud to pass under closed door: when in sight, give form change message before moving to door spot limit carrying heavy loads from water to land failing to carry a wished-for item behaved differenctly from dropping one +life-saving while weak/starving/fainting boosted nutrition without restoring + lost point of strength, making temporary loss be permanent Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/end.c b/src/end.c index b89eee7e9..3803a4366 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1545172226 2018/12/18 22:30:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.159 $ */ +/* NetHack 3.6 end.c $NHDT-Date: 1545646111 2018/12/24 10:08:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.160 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -859,16 +859,13 @@ int how; u.uhp = u.uhpmax; if (Upolyd) /* Unchanging, or death which bypasses losing hit points */ u.mh = u.mhmax; - if (u.uhunger < 500) { - u.uhunger = 500; - newuhs(FALSE); + if (u.uhunger < 500 || how == CHOKING) { + init_uhunger(); } /* cure impending doom of sickness hero won't have time to fix */ if ((Sick & TIMEOUT) == 1L) { make_sick(0L, (char *) 0, FALSE, SICK_ALL); } - if (how == CHOKING) - init_uhunger(); nomovemsg = "You survived that attempt on your life."; context.move = 0; if (multi > 0) @@ -1060,9 +1057,12 @@ int how; if (iflags.debug_fuzzer) { if (!(program_state.panicking || how == PANICKED)) { savelife(how); - /* periodically restore characteristics and lost exp levels */ + /* periodically restore characteristics and lost exp levels + or cure lycanthropy */ if (!rn2(10)) { - struct obj *potion = mksobj(POT_RESTORE_ABILITY, TRUE, FALSE); + struct obj *potion = mksobj((u.ulycn > LOW_PM && !rn2(3)) + ? POT_WATER : POT_RESTORE_ABILITY, + TRUE, FALSE); bless(potion); (void) peffects(potion); /* always -1 for restore ability */