From a3a676a6bd547e875a5292b39bacf4f04aa286ce Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 17 Dec 2018 00:45:00 -0800 Subject: [PATCH 1/3] more dropping unpaid shop items inside engulfer I thought that the earlier fix for #H2504 was too easy for anything shop related. It didn't deal sensibly with containers owned by hero but holding unpaid shop goods. --- include/extern.h | 3 ++- src/do.c | 7 +++---- src/invent.c | 5 ++--- src/shk.c | 29 ++++++++++++++++++++++------- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/include/extern.h b/include/extern.h index df9477b62..6e2960ea2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1544998887 2018/12/16 22:21:27 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.671 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1545036280 2018/12/17 08:44:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.672 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -974,6 +974,7 @@ E boolean NDECL(have_lizard); E struct obj *NDECL(u_have_novel); E struct obj *FDECL(o_on, (unsigned int, struct obj *)); E boolean FDECL(obj_here, (struct obj *, int, int)); +E int FDECL(ckunpaid, (struct obj *)); E boolean NDECL(wearing_armor); E boolean FDECL(is_worn, (struct obj *)); E struct obj *FDECL(g_at, (int, int)); diff --git a/src/do.c b/src/do.c index 8e9679f1c..732e1ed73 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1545005168 2018/12/17 00:06:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.179 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1545036287 2018/12/17 08:44:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.180 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -588,8 +588,7 @@ register struct obj *obj; /* doname can call s_suffix, reusing its buffer */ Strcpy(monbuf, s_suffix(mon_nam(u.ustuck))); - onam_p = obj->unpaid ? yobjnam(obj, (char *) 0) : doname(obj); - + onam_p = ckunpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj); You("drop %s into %s %s.", onam_p, monbuf, mbodypart(u.ustuck, STOMACH)); } @@ -684,7 +683,7 @@ boolean with_impact; could_grow = (obj->corpsenm == PM_WRAITH); could_heal = (obj->corpsenm == PM_NURSE); } - if (obj->unpaid) + if (ckunpaid(obj)) (void) stolen_value(obj, u.ux, u.uy, TRUE, FALSE); (void) mpickobj(u.ustuck, obj); if (is_animal(u.ustuck->data)) { diff --git a/src/invent.c b/src/invent.c index 718e1feb5..5d89e5545 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1541145517 2018/11/02 07:58:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.241 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1545036289 2018/12/17 08:44:49 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.243 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -25,7 +25,6 @@ STATIC_DCL boolean FDECL(only_here, (struct obj *)); STATIC_DCL void FDECL(compactify, (char *)); STATIC_DCL boolean FDECL(taking_off, (const char *)); STATIC_DCL boolean FDECL(putting_on, (const char *)); -STATIC_PTR int FDECL(ckunpaid, (struct obj *)); STATIC_PTR int FDECL(ckvalidcat, (struct obj *)); STATIC_PTR char *FDECL(safeq_xprname, (struct obj *)); STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *)); @@ -1825,7 +1824,7 @@ struct obj *otmp; return (int) allow_category(otmp); } -STATIC_PTR int +int ckunpaid(otmp) struct obj *otmp; { diff --git a/src/shk.c b/src/shk.c index c2895a29f..1a50616e9 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1542853899 2018/11/22 02:31:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1545036290 2018/12/17 08:44:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.143 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2763,6 +2763,15 @@ boolean peaceful, silent; char roomno = *in_rooms(x, y, SHOPBASE); struct bill_x *bp; struct monst *shkp = 0; + boolean was_unpaid; + long c_count = 0L, u_count = 0L; + + /* gather information for message(s) prior to manipulating bill */ + was_unpaid = obj->unpaid ? TRUE : FALSE; + if (Has_contents(obj)) { + c_count = count_contents(obj, TRUE, FALSE, TRUE); + u_count = count_contents(obj, TRUE, FALSE, FALSE); + } if (!billable(&shkp, obj, roomno, FALSE)) { /* things already on the bill yield a not-billable result, so @@ -2810,6 +2819,7 @@ boolean peaceful, silent; ESHK(shkp)->debit += value; if (!silent) { + char buf[BUFSZ]; const char *still = ""; if (credit_use) { @@ -2823,12 +2833,17 @@ boolean peaceful, silent; } still = "still "; } - if (obj->oclass == COIN_CLASS) - You("%sowe %s %ld %s!", still, shkname(shkp), value, - currency(value)); - else - You("%sowe %s %ld %s for %s!", still, shkname(shkp), - value, currency(value), (obj->quan > 1L) ? "them" : "it"); + Sprintf(buf, "%sowe %s %ld %s", still, shkname(shkp), + value, currency(value)); + if (u_count) /* u_count > 0 implies Has_contents(obj) */ + Sprintf(eos(buf), " for %s%sits contents", + was_unpaid ? "it and " : "", + (c_count > u_count) ? "some of " : ""); + else if (obj->oclass != COIN_CLASS) + Sprintf(eos(buf), " for %s", + (obj->quan > 1L) ? "them" : "it"); + + You("%s!", buf); /* "You owe N zorkmids for it!" */ } } else { ESHK(shkp)->robbed += value; From f9cef53758740fe3c35a53db58d8d04781849b6e Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 17 Dec 2018 02:49:38 -0800 Subject: [PATCH 2/3] yet more dropping while inside engulfer I don't know why we have two different functions which do exactly the same thing (checking whether an item is unpaid or is a container that holds at least one unpaid item), but switch the #H2504 fix to use 'the other one' and reverse one of the changes made when using the inventory one. --- include/extern.h | 3 +-- src/do.c | 6 +++--- src/invent.c | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/extern.h b/include/extern.h index 6e2960ea2..f8a81c7b7 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1545036280 2018/12/17 08:44:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.672 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1545043771 2018/12/17 10:49:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.673 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -974,7 +974,6 @@ E boolean NDECL(have_lizard); E struct obj *NDECL(u_have_novel); E struct obj *FDECL(o_on, (unsigned int, struct obj *)); E boolean FDECL(obj_here, (struct obj *, int, int)); -E int FDECL(ckunpaid, (struct obj *)); E boolean NDECL(wearing_armor); E boolean FDECL(is_worn, (struct obj *)); E struct obj *FDECL(g_at, (int, int)); diff --git a/src/do.c b/src/do.c index 732e1ed73..3438a44b1 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1545036287 2018/12/17 08:44:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.180 $ */ +/* 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 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -588,7 +588,7 @@ register struct obj *obj; /* doname can call s_suffix, reusing its buffer */ Strcpy(monbuf, s_suffix(mon_nam(u.ustuck))); - onam_p = ckunpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj); + onam_p = is_unpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj); You("drop %s into %s %s.", onam_p, monbuf, mbodypart(u.ustuck, STOMACH)); } @@ -683,7 +683,7 @@ boolean with_impact; could_grow = (obj->corpsenm == PM_WRAITH); could_heal = (obj->corpsenm == PM_NURSE); } - if (ckunpaid(obj)) + if (is_unpaid(obj)) (void) stolen_value(obj, u.ux, u.uy, TRUE, FALSE); (void) mpickobj(u.ustuck, obj); if (is_animal(u.ustuck->data)) { diff --git a/src/invent.c b/src/invent.c index 5d89e5545..93939ad86 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1545036289 2018/12/17 08:44:49 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.243 $ */ +/* 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 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -26,6 +26,7 @@ STATIC_DCL void FDECL(compactify, (char *)); STATIC_DCL boolean FDECL(taking_off, (const char *)); STATIC_DCL boolean FDECL(putting_on, (const char *)); STATIC_PTR int FDECL(ckvalidcat, (struct obj *)); +STATIC_PTR int FDECL(ckunpaid, (struct obj *)); STATIC_PTR char *FDECL(safeq_xprname, (struct obj *)); STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *)); STATIC_DCL char FDECL(display_pickinv, (const char *, const char *, @@ -1824,7 +1825,7 @@ struct obj *otmp; return (int) allow_category(otmp); } -int +STATIC_PTR int ckunpaid(otmp) struct obj *otmp; { From 942961e3e28d06b50e85daba585ca22e1a159643 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 17 Dec 2018 03:05:10 -0800 Subject: [PATCH 3/3] throwing recoil inside shop Another bug from seven years ago, sent directly to devteam so no #H number. Report stated that throwing recoil could move a levitating hero diagonally through a shop's doorway to exit it. If the thrown item was unpaid, it remained unpaid after landing on shop's floor and was an unlisted item on shop's bill. Moving diagonally out the door seems to have been fixed, but the same effect still occurred if you were far enough from the door to have the shopkeeper vacate his door-blocking spot and throwing recoil took hero to that spot. The thrown unpaid item remained unpaid, and walking out the door was treated as shop robbery. --- doc/fixes36.2 | 5 +++++ src/dothrow.c | 15 ++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 1e8d84cb6..e7b109d05 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -278,6 +278,11 @@ while inside a shop, dropping an unpaid item inside an engulfer would leave the engulfer was killed; treat dropping shop items inside an engulfer as stealing them and giving them to that engulfer--hero must pay for for them and shop retains ownership of them +while levitating inside a shop, throwing an unpaid item and having recoil move + hero out of shop (or to shopkeeper's spot in front of door) would + leave the item unpaid on shop floor and also on the shop's bill but + not visible via 'Iu' or 'Ix'; leaving the shop after that would anger + the shopkeeper and summon kops Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/dothrow.c b/src/dothrow.c index 48220a4fb..b3a2f8ba4 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1544401268 2018/12/10 00:21:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.153 $ */ +/* 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 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -893,21 +893,26 @@ struct obj *obj; xchar x, y; boolean broken; { + boolean costly_xy; struct monst *shkp = shop_keeper(*u.ushops); if (!shkp) return; - if (broken || !costly_spot(x, y) - || *in_rooms(x, y, SHOPBASE) != *u.ushops) { + costly_xy = costly_spot(x, y); + if (broken || !costly_xy || *in_rooms(x, y, SHOPBASE) != *u.ushops) { /* thrown out of a shop or into a different shop */ if (is_unpaid(obj)) (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful, FALSE); if (broken) obj->no_charge = 1; - } else { - if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) { + } else if (costly_xy) { + char *oshops = in_rooms(x, y, SHOPBASE); + + /* ushops0: in case we threw while levitating and recoiled + out of shop (most likely to the shk's spot in front of door) */ + if (*oshops == *u.ushops || *oshops == *u.ushops0) { if (is_unpaid(obj)) subfrombill(obj, shkp); else if (x != shkp->mx || y != shkp->my)