From 79ff4cd9c30a5b93b15f7c316e88907608b15f91 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 3 Jul 2019 18:30:55 -0700 Subject: [PATCH] fix github issue #202 - worn items inside engulfer Fixes #202 When swallowed, you can take things from the engulfer's inventory, if there are any, via pickup. Items might be worn by the engulfer and when "picked up" those weren't being unworn before being added to hero's inventory. Then they would be formatted as "(being worn)" and could trigger warnings or worse. Conceptually they should be worn on the outside and not be accessible from the inside, so I've made attempts to pick up worn items fail rather than fix up the unwearing. Using ':' when swallowed to look at the engulfer's inventory describes that inventory as "contents of 's stomach". That's weird for any worn items, but the situation is so rare I haven't made any attempt to deal with it. --- doc/fixes36.3 | 6 +++++- src/invent.c | 17 ++++++++++++++++- src/pickup.c | 44 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 22532246b..52aa675e4 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.83 $ $NHDT-Date: 1562114348 2019/07/03 00:39:08 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.84 $ $NHDT-Date: 1562203850 2019/07/04 01:30:50 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -94,6 +94,10 @@ saving bones with 'perm_invent' On could result in "Bad fruit #N" warnings update persistent inventory window immediately if 'sortpack' option is toggled grammar bit for wizard mode final disclosure; attribute section could show "You had N experience points, 1 more were needed to attain level X+1." +if an engulfer has any worn items, hero could pick them up from inside and + they wouldn't be unworn properly, eventually triggering warnings or + worse (Juiblex will wear an amulet if created with one; a shapechanger + might wear one and then turn into an engulfer) Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/src/invent.c b/src/invent.c index fc76a57a4..fe21fa7b4 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1561751391 2019/06/28 19:49:51 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.260 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1562203850 2019/07/04 01:30:50 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.261 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3372,6 +3372,21 @@ boolean picked_some; if (u.uswallow && u.ustuck) { struct monst *mtmp = u.ustuck; + /* + * FIXME? + * Engulfer's inventory can include worn items (specific case is + * Juiblex being created with an amulet as random defensive item) + * which will be flagged as "(being worn)". This code includes + * such a worn item under the header "Contents of 's stomach", + * a nifty trick for how/where to wear stuff. The situation is + * rare enough to turn a blind eye. + * + * 3.6.3: Pickup has been changed to decline to pick up a worn + * item from inside an engulfer, but if player tries, it just + * says "you can't" without giving a reason why (which would be + * something along the lines of "because it's worn on the outside + * so is unreachable from in here..."). + */ Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); /* Skip "Contents of " by using fbuf index 12 */ diff --git a/src/pickup.c b/src/pickup.c index 77356b1fe..fe25f8a0f 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1559675617 2019/06/04 19:13:37 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.228 $ */ +/* NetHack 3.6 pickup.c $NHDT-Date: 1562203851 2019/07/04 01:30:51 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.229 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -840,7 +840,8 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ anything any; boolean printed_type_name, first, sorted = (qflags & INVORDER_SORT) != 0, - engulfer = (qflags & INCLUDE_HERO) != 0; + engulfer = (qflags & INCLUDE_HERO) != 0, + engulfer_minvent; unsigned sortflags; Loot *sortedolist, *srtoli; @@ -854,6 +855,13 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ last = curr; n++; } + /* can't depend upon 'engulfer' because that's used to indicate whether + hero should be shown as an extra, fake item */ + engulfer_minvent = (olist && olist->where == OBJ_MINVENT + && u.uswallow && olist->ocarry == u.ustuck); + if (engulfer_minvent && n == 1 && olist->owornmask != 0L) { + qflags &= ~AUTOSELECT_SINGLE; + } if (engulfer) { ++n; /* don't autoselect swallowed hero if it's the only choice */ @@ -957,10 +965,20 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ /* fix up counts: -1 means no count used => pick all; if fake_hero_object was picked, discard that choice */ for (i = k = 0, mi = *pick_list; i < n; i++, mi++) { - if (mi->item.a_obj == &fake_hero_object) + curr = mi->item.a_obj; + if (curr == &fake_hero_object) { + /* this isn't actually possible; fake item representing + hero is only included for look here (':'), not pickup, + and that's PICK_NONE so we can't get here from there */ + You_cant("pick yourself up!"); continue; - if (mi->count == -1L || mi->count > mi->item.a_obj->quan) - mi->count = mi->item.a_obj->quan; + } + if (engulfer_minvent && curr->owornmask != 0L) { + You_cant("pick %s up.", ysimple_name(curr)); + continue; + } + if (mi->count == -1L || mi->count > curr->quan) + mi->count = curr->quan; if (k < i) (*pick_list)[k] = *mi; ++k; @@ -971,10 +989,14 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ *pick_list = 0; n = 0; } else if (k < n) { - /* other stuff plus fake_hero; last slot is now unused */ - (*pick_list)[k].item = zeroany; - (*pick_list)[k].count = 0L; - n = k; + /* other stuff plus fake_hero; last slot is now unused + (could be more than one if player tried to pick items + worn by engulfer) */ + while (n > k) { + --n; + (*pick_list)[n].item = zeroany; + (*pick_list)[n].count = 0L; + } } } else if (n < 0) { /* -1 is used for SIGNAL_NOMENU, so callers don't expect it @@ -1474,6 +1496,10 @@ boolean telekinesis; /* not picking it up directly by hand */ if (obj == uchain) { /* do not pick up attached chain */ return 0; + } else if (obj->where == OBJ_MINVENT && obj->owornmask != 0L + && u.uswallow && obj->ocarry == u.ustuck) { + You_cant("pick %s up.", ysimple_name(obj)); + return 0; } else if (obj->oartifact && !touch_artifact(obj, &youmonst)) { return 0; } else if (obj->otyp == CORPSE) {