fix #H4468 - [no-]autopickup in shop

Autopickup for pickup_types is disabled for unpaid shop goods, but
always-pick-up autopickup_exception still picked things up, as did
pickup_thrown for thrown objects.  Now they'll only work in shops
for no_charge items (dropped by hero and shk didn't want, or hero
declined to sell).

costly_spot() was being recalculated for every item which passed
pickup_types.  This changes autopickup to check it once for a given
autopickup operation and cache the result.  [Whenever the hero moves,
a room entry check is performed.  That ought to be extended to cache
costly_spot() for <u.ux,u.uy> in iflags or u.]
This commit is contained in:
PatR
2016-08-05 19:17:47 -07:00
parent 694b32cae2
commit 7f8e8293f9
2 changed files with 33 additions and 17 deletions
+2
View File
@@ -346,6 +346,8 @@ fix for long lines in config file (28-Jan-2016) made 'O' command's 'list' and
message types, and autopickup exceptions subject to buffer overflow message types, and autopickup exceptions subject to buffer overflow
when picking a destination for #jump, '$' to show valid dest. is more accurate when picking a destination for #jump, '$' to show valid dest. is more accurate
enchant armor gave "your pair of boots/gloves glow", should have been "glows" enchant armor gave "your pair of boots/gloves glow", should have been "glows"
when autopickup is overridden in a shop, always-pick-up exceptions and
pickup_thrown still picked unpaid items up
Platform- and/or Interface-Specific Fixes Platform- and/or Interface-Specific Fixes
+31 -17
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pickup.c $NHDT-Date: 1461919368 2016/04/29 08:42:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.177 $ */ /* NetHack 3.6 pickup.c $NHDT-Date: 1470449858 2016/08/06 02:17:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.184 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -21,7 +21,7 @@ STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
#if 0 /* not used */ #if 0 /* not used */
STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *)); STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
#endif #endif
STATIC_DCL boolean FDECL(autopick_testobj, (struct obj *)); STATIC_DCL boolean FDECL(autopick_testobj, (struct obj *, BOOLEAN_P));
STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **)); STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **));
STATIC_DCL int FDECL(count_categories, (struct obj *, int)); STATIC_DCL int FDECL(count_categories, (struct obj *, int));
STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long, STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
@@ -685,30 +685,42 @@ boolean grab; /* forced pickup, rather than forced leave behind? */
/* /*
* Does the text description of this match an exception? * Does the text description of this match an exception?
*/ */
char *objdesc = makesingular(doname(obj));
struct autopickup_exception struct autopickup_exception
*ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB] *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB]
: iflags.autopickup_exceptions[AP_LEAVE]; : iflags.autopickup_exceptions[AP_LEAVE];
while (ape) { if (ape) {
if (regex_match(objdesc, ape->regex)) char *objdesc = makesingular(doname(obj));
return TRUE;
ape = ape->next; while (ape) {
if (regex_match(objdesc, ape->regex))
return TRUE;
ape = ape->next;
}
} }
return FALSE; return FALSE;
} }
boolean STATIC_OVL boolean
autopick_testobj(otmp) autopick_testobj(otmp, calc_costly)
struct obj *otmp; struct obj *otmp;
boolean calc_costly;
{ {
static boolean costly = FALSE;
const char *otypes = flags.pickup_types; const char *otypes = flags.pickup_types;
/* pick if in pickup_types and not unpaid item in shop */ boolean pickit;
boolean pickit = ((!*otypes || index(otypes, otmp->oclass))
&& !(otmp->where == OBJ_FLOOR /* calculate 'costly' just once for a given autopickup operation */
&& !otmp->no_charge if (calc_costly)
&& isok(otmp->ox, otmp->oy) costly = (otmp->where == OBJ_FLOOR
&& costly_spot(otmp->ox, otmp->oy))); && costly_spot(otmp->ox, otmp->oy));
/* first check: reject if an unpaid item in a shop */
if (costly && !otmp->no_charge)
return FALSE;
/* check for pickup_types */
pickit = (!*otypes || index(otypes, otmp->oclass));
/* check for "always pick up */ /* check for "always pick up */
if (!pickit) if (!pickit)
pickit = is_autopickup_exception(otmp, TRUE); pickit = is_autopickup_exception(otmp, TRUE);
@@ -737,17 +749,19 @@ menu_item **pick_list; /* list of objects and counts to pick up */
menu_item *pi; /* pick item */ menu_item *pi; /* pick item */
struct obj *curr; struct obj *curr;
int n; int n;
boolean check_costly = TRUE;
/* first count the number of eligible items */ /* first count the number of eligible items */
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) { for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
if (autopick_testobj(curr)) if (autopick_testobj(curr, check_costly))
++n; ++n;
check_costly = FALSE; /* only need to check once per autopickup */
} }
if (n) { if (n) {
*pick_list = pi = (menu_item *) alloc(sizeof (menu_item) * n); *pick_list = pi = (menu_item *) alloc(sizeof (menu_item) * n);
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) { for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
if (autopick_testobj(curr)) { if (autopick_testobj(curr, FALSE)) {
pi[n].item.a_obj = curr; pi[n].item.a_obj = curr;
pi[n].count = curr->quan; pi[n].count = curr->quan;
n++; n++;