more '*' and perminv_mode==inuse

If any items are in use and hero isn't wielding anything, include
| - bare hands
in the primary weapon slot of the display of used items as an alert.
More useful for perm_invent than for #seeall.

If no items at all are in use, continue to show "not using any items"
without any specific weaponless alert.

When sortloot() is called for inuse_only, pass a filter that screens
out items which aren't in use so they won't be needlessly sorted.
This commit is contained in:
PatR
2023-11-25 14:11:43 -08:00
parent 99ccb7a26f
commit 6c5b5c0688
2 changed files with 137 additions and 90 deletions
+1
View File
@@ -1178,6 +1178,7 @@ extern struct obj *o_on(unsigned int, struct obj *);
extern boolean obj_here(struct obj *, coordxy, coordxy); extern boolean obj_here(struct obj *, coordxy, coordxy);
extern boolean wearing_armor(void); extern boolean wearing_armor(void);
extern boolean is_worn(struct obj *); extern boolean is_worn(struct obj *);
extern boolean is_inuse(struct obj *);
extern struct obj *g_at(coordxy, coordxy); extern struct obj *g_at(coordxy, coordxy);
extern boolean splittable(struct obj *); extern boolean splittable(struct obj *);
extern int any_obj_ok(struct obj *); extern int any_obj_ok(struct obj *);
+136 -90
View File
@@ -73,83 +73,78 @@ static const char *const inuse_headers[] = { /* [4] shown first, [1] last */
static void static void
inuse_classify(Loot *sort_item, struct obj *obj) inuse_classify(Loot *sort_item, struct obj *obj)
{ {
/* in-use; only applicable to hero's inventory */ long w_mask = (obj->owornmask & (W_ACCESSORY | W_WEAPONS | W_ARMOR));
if (carried(obj) && (is_worn(obj) || tool_being_used(obj))) { int rating = 0, altclass = 0;
long w_mask = (obj->owornmask & (W_ACCESSORY | W_WEAPONS | W_ARMOR));
int rating = 0, altclass = 0;
#define USE_RATING(test) \ #define USE_RATING(test) \
do { \ do { \
/* 'rating' advances for each USE_RATING() call */ \ /* 'rating' advances for each USE_RATING() call */ \
++rating; \ ++rating; \
if ((test) != 0) \ if ((test) != 0) \
goto assign_rating; \ goto assign_rating; \
} while (0) } while (0)
/*
* In order of importance, least to most, somewhat arbitrarily.
*
* For instance, all accessories are grouped together even
* though they're usually less important than other stuff, so
* that they appear earlier within displayed list of used items.
* Amulet is rated as most important primarily because the
* default 'packorder' puts amulets first (possibly because one
* might be The Amulet). Non-wielded alternate weapon and
* quiver are grouped with primary weapon. Weapons are rated
* above armor because of default 'packorder'.
*
* These ratings don't match either subclasses or 'packorder'.
*
* USE_RATING() sets up 'rating' then jumps to 'assign_rating'
* if 'obj' warrants that.
*/
/* "Miscellaneous" */
++altclass; /* 1 */
/* lamp and leash might be used doubly, as a tool and also wielded
or readied-in-quiver; these tests for used-as-tool only pass
when owornmask is 0 so that used-as-weapon takes precedence */
USE_RATING(!w_mask && obj->otyp == LEASH && obj->leashmon);
USE_RATING(!w_mask && obj->oclass == TOOL_CLASS && obj->lamplit);
/* "Armor" */
++altclass; /* 2 */
USE_RATING(w_mask & WORN_SHIRT);
USE_RATING(w_mask & WORN_BOOTS);
USE_RATING(w_mask & WORN_GLOVES);
USE_RATING(w_mask & WORN_HELMET);
USE_RATING(w_mask & WORN_SHIELD);
USE_RATING(w_mask & WORN_CLOAK);
USE_RATING(w_mask & WORN_ARMOR);
/* "Weapons" */
++altclass; /* 3 */
/* could get more complicated: if uswapwep is just alternate weapon
rather than wielded secondary, swap order with quiver (unless
quiver is ammo for uswapwep without also being ammo for uwep) */
USE_RATING(w_mask & W_QUIVER);
USE_RATING(w_mask & W_SWAPWEP);
USE_RATING(w_mask & W_WEP);
/* "Accessories" */
++altclass; /* 4 */
USE_RATING(w_mask & WORN_BLINDF);
USE_RATING(w_mask & LEFT_RING);
USE_RATING(w_mask & RIGHT_RING);
USE_RATING(w_mask & WORN_AMUL);
/* if we get here, the USE_RATING() checks failed to find a match */
rating = 0;
altclass = -1; /* 'orderclass' must end up non-zero */
/*
* In order of importance, least to most, somewhat arbitrarily.
*
* For instance, all accessories are grouped together even
* though they're usually less important than other stuff, so
* that they appear earlier within displayed list of used items.
* Amulet is rated as most important primarily because the
* default 'packorder' puts amulets first (possibly because one
* might be The Amulet). Non-wielded alternate weapon and
* quiver are grouped with primary weapon. Weapons are rated
* above armor because of default 'packorder'.
*
* These ratings don't match either subclasses or 'packorder'.
*
* USE_RATING() sets up 'rating' then jumps to 'assign_rating'
* if 'obj' warrants that.
*/
/* "Miscellaneous" */
++altclass; /* 1 */
/* lamp and leash might be used doubly, as a tool and also wielded
or readied-in-quiver; these tests for used-as-tool only pass
when owornmask is 0 so that used-as-weapon takes precedence */
USE_RATING(!w_mask && obj->otyp == LEASH && obj->leashmon);
USE_RATING(!w_mask && obj->oclass == TOOL_CLASS && obj->lamplit);
/* "Armor" */
++altclass; /* 2 */
USE_RATING(w_mask & WORN_SHIRT);
USE_RATING(w_mask & WORN_BOOTS);
USE_RATING(w_mask & WORN_GLOVES);
USE_RATING(w_mask & WORN_HELMET);
USE_RATING(w_mask & WORN_SHIELD);
USE_RATING(w_mask & WORN_CLOAK);
USE_RATING(w_mask & WORN_ARMOR);
/* "Weapons" */
++altclass; /* 3 */
/* could get more complicated: if uswapwep is just alternate weapon
rather than wielded secondary, swap order with quiver (unless
quiver is ammo for uswapwep without also being ammo for uwep) */
USE_RATING(w_mask & W_QUIVER);
USE_RATING(w_mask & W_SWAPWEP);
USE_RATING(w_mask & W_WEP);
/* "Accessories" */
++altclass; /* 4 */
USE_RATING(w_mask & WORN_BLINDF);
USE_RATING(w_mask & LEFT_RING);
USE_RATING(w_mask & RIGHT_RING);
USE_RATING(w_mask & WORN_AMUL);
/* if we get here, the USE_RATING() checks failed to find a match;
obj might have an owornmask of W_BALL or W_ART|W_ARTI; doprinuse()
doesn't list such items so give it a rating of 0 to suppress */
rating = 0;
altclass = -1; /* 'orderclass' must end up non-zero */
assign_rating: assign_rating:
sort_item->inuse = rating; sort_item->inuse = rating;
sort_item->orderclass = altclass; /* used for alternate headings */ sort_item->orderclass = altclass; /* used for alternate headings */
#undef USE_RATING
} else { /* 'obj' is not in use by hero */
sort_item->inuse = 0;
sort_item->orderclass = -1; /* non-zero => has been classified */
}
/* not applicable for in-use */ /* not applicable for in-use */
sort_item->subclass = 0; sort_item->subclass = 0;
sort_item->disco = 0; sort_item->disco = 0;
#undef USE_RATING
} }
/* sortloot() classification; called at most once [per sort] for each object; /* sortloot() classification; called at most once [per sort] for each object;
@@ -2102,6 +2097,15 @@ is_worn(struct obj *otmp)
: FALSE; : FALSE;
} }
/* is 'obj' being used by the hero? worn, wielded, active lamp or leash;
not to be confused with obj->in_use, which finishes using up an item
(destroys it) if restoring a save file finds that bit set */
boolean
is_inuse(struct obj *obj)
{
return (carried(obj) && (is_worn(obj) || tool_being_used(obj)));
}
/* extra xprname() input that askchain() can't pass through safe_qbuf() */ /* extra xprname() input that askchain() can't pass through safe_qbuf() */
static struct xprnctx { static struct xprnctx {
char let; char let;
@@ -3431,7 +3435,7 @@ display_pickinv(
not_carrying_anything[] = "Not carrying anything", not_carrying_anything[] = "Not carrying anything",
not_using_anything[] = "Not using any items", not_using_anything[] = "Not using any items",
only_carrying_gold[] = "Only carrying gold"; only_carrying_gold[] = "Only carrying gold";
struct obj *otmp, wizid_fakeobj; struct obj *otmp, wizid_fakeobj, inuse_fakeobj;
char ilet, ret, *formattedobj; char ilet, ret, *formattedobj;
const char *invlet = flags.inv_order; const char *invlet = flags.inv_order;
int n, classcount, inusecount = 0; int n, classcount, inusecount = 0;
@@ -3441,6 +3445,8 @@ display_pickinv(
unsigned sortflags; unsigned sortflags;
Loot *sortedinvent, *srtinv; Loot *sortedinvent, *srtinv;
int8_t prevorderclass; int8_t prevorderclass;
boolean (*filter)(struct obj *) = (boolean (*)(OBJ_P)) 0;
boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE; boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE;
int clr = NO_COLOR, menu_behavior = MENU_BEHAVE_STANDARD; int clr = NO_COLOR, menu_behavior = MENU_BEHAVE_STANDARD;
boolean show_gold = TRUE, inuse_only = FALSE, skipped_gold = FALSE, boolean show_gold = TRUE, inuse_only = FALSE, skipped_gold = FALSE,
@@ -3494,8 +3500,9 @@ display_pickinv(
: lets ? (int) strlen(lets) : lets ? (int) strlen(lets)
: !gi.invent ? 0 : !gi.invent->nobj ? 1 : 2; : !gi.invent ? 0 : !gi.invent->nobj ? 1 : 2;
/* for xtra_choice, there's another 'item' not included in initial 'n'; /* for xtra_choice, there's another 'item' not included in initial 'n';
for !lets (full invent) and for override_ID (wizard mode identify), for !lets (full invent or inuse_only) and for override_ID (wizard
skip message_menu handling of single item even if item count was 1 */ mode identify), skip message_menu handling of single item even if
item count was 1 */
if (xtra_choice || (n == 1 && (!lets || wizid))) if (xtra_choice || (n == 1 && (!lets || wizid)))
++n; ++n;
@@ -3547,10 +3554,37 @@ display_pickinv(
if (inuse_only) { if (inuse_only) {
flags.sortpack = FALSE; flags.sortpack = FALSE;
sortflags = SORTLOOT_INUSE; /* override */ sortflags = SORTLOOT_INUSE; /* override */
filter = is_inuse;
if (!uwep) {
/*
* inuse_only and not wielding anything: insert "bare hands"
* into primary weapon slot. Unlike adding an extra menu
* entry for 'xtra_choice' at top of menu, we need an object
* in invent for it to be sorted into desired position.
* It will need custom formatting below.
*/
inuse_fakeobj = cg.zeroobj; /* STRANGE_OBJECT, ILLOBJ_CLASS */
inuse_fakeobj.invlet = HANDS_SYM; /* '-' */
inuse_fakeobj.owornmask = W_WEP; /* inuse_classify needs this */
inuse_fakeobj.where = OBJ_INVENT; /* is_inuse filter needs this */
inuse_fakeobj.nobj = gi.invent;
gi.invent = &inuse_fakeobj;
}
}
sortedinvent = sortloot(&gi.invent, sortflags, FALSE, filter);
/* inuse_only: if we inserted bare hands as a fake weapon, remove them;
although the fake object will no longer be in invent, sortedinvent
will still contain a pointer to it */
if (gi.invent == &inuse_fakeobj) {
gi.invent = inuse_fakeobj.nobj;
inuse_fakeobj.nobj = (struct obj *) 0;
/* if inuse_fakeobj is the only thing present in sortedinvent, get
rid of it in order to produce "not using any items" */
if (sortedinvent[0].obj == &inuse_fakeobj && !sortedinvent[1].obj)
sortedinvent[0].obj = (struct obj *) 0;
} }
sortedinvent = sortloot(&gi.invent, sortflags, FALSE,
(boolean (*)(OBJ_P)) 0);
start_menu(win, menu_behavior); start_menu(win, menu_behavior);
any = cg.zeroany; any = cg.zeroany;
if (wizid) { if (wizid) {
@@ -3601,10 +3635,6 @@ display_pickinv(
int tmpglyph; int tmpglyph;
glyph_info tmpglyphinfo = nul_glyphinfo; glyph_info tmpglyphinfo = nul_glyphinfo;
/* for in-use-only, sorting puts all in-use items before any not-in-
use items, so once a not-in-use item is encountered, we're done */
if (inuse_only && srtinv->orderclass < 1)
break;
/* for showing a set of specific letters, skip ones not in the set */ /* for showing a set of specific letters, skip ones not in the set */
if (lets && !strchr(lets, otmp->invlet)) if (lets && !strchr(lets, otmp->invlet))
continue; continue;
@@ -3623,10 +3653,9 @@ display_pickinv(
continue; continue;
} }
} }
any = cg.zeroany; /* all bits zero */ /* maybe insert a class header */
ilet = otmp->invlet; if (inuse_only ? (srtinv->orderclass != prevorderclass)
if ((flags.sortpack && !classcount) : (flags.sortpack && !classcount)) {
|| (inuse_only && srtinv->orderclass != prevorderclass)) {
boolean withsym = (want_reply && iflags.menu_head_objsym); boolean withsym = (want_reply && iflags.menu_head_objsym);
const char *class_header = inuse_only const char *class_header = inuse_only
? inuse_headers[(int) srtinv->orderclass] ? inuse_headers[(int) srtinv->orderclass]
@@ -3636,16 +3665,33 @@ display_pickinv(
classcount++; classcount++;
prevorderclass = srtinv->orderclass; prevorderclass = srtinv->orderclass;
} }
ilet = otmp->invlet;
any = cg.zeroany; /* all bits zero */
if (wizid) if (wizid)
any.a_obj = otmp; any.a_obj = otmp;
else else
any.a_char = ilet; any.a_char = ilet;
tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng);
map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo); if (otmp == &inuse_fakeobj) {
formattedobj = doname(otmp); /* fake item to format as "bare|gloved hands" */
add_menu(win, &tmpglyphinfo, &any, ilet, char barehands[QBUFSZ];
wizid ? def_oc_syms[(int) otmp->oclass].sym : 0,
ATR_NONE, clr, formattedobj, MENU_ITEMFLAGS_NONE); /* like doname() below, makeplural() returns an obuf[] */
formattedobj = makeplural(body_part(HAND));
Sprintf(barehands, "%s %s (no weapon)",
uarmg ? "gloved" : "bare", formattedobj);
add_menu(win, &nul_glyphinfo, &any, ilet, 0,
ATR_NONE, clr, barehands, MENU_ITEMFLAGS_NONE);
} else {
/* normal inventory item */
tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng);
map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo);
formattedobj = doname(otmp);
add_menu(win, &tmpglyphinfo, &any, ilet,
wizid ? def_oc_syms[(int) otmp->oclass].sym : 0,
ATR_NONE, clr, formattedobj, MENU_ITEMFLAGS_NONE);
}
/* doname() uses a static pool of obuf[] output buffers and /* doname() uses a static pool of obuf[] output buffers and
we don't want inventory display to overwrite all of them, we don't want inventory display to overwrite all of them,
so when we've used one we release it for re-use */ so when we've used one we release it for re-use */
@@ -4972,7 +5018,7 @@ doprinuse(void)
char lets[52 + 1]; char lets[52 + 1];
for (otmp = gi.invent; otmp; otmp = otmp->nobj) for (otmp = gi.invent; otmp; otmp = otmp->nobj)
if (is_worn(otmp) || tool_being_used(otmp)) { if (is_inuse(otmp)) {
/* we could be carrying more than 52 items; theoretically they /* we could be carrying more than 52 items; theoretically they
might all be lit candles so avoid potential lets[] overflow */ might all be lit candles so avoid potential lets[] overflow */
if (ct >= (int) sizeof lets - 1) if (ct >= (int) sizeof lets - 1)
@@ -4986,7 +5032,7 @@ doprinuse(void)
/* no longer need to collect letters; sortloot() takes care of it, but /* no longer need to collect letters; sortloot() takes care of it, but
still need to count far enough to know whether anything is in use */ still need to count far enough to know whether anything is in use */
for (otmp = gi.invent; otmp; otmp = otmp->nobj) for (otmp = gi.invent; otmp; otmp = otmp->nobj)
if (is_worn(otmp) || tool_being_used(otmp)) { if (is_inuse(otmp)) {
++ct; ++ct;
break; break;
} }