Add sortloot -patch
Adds the "sortloot" compound option, with possible values of "none", "loot", or "full". It controls the sorting of item pickup lists for inventory and looting.
This commit is contained in:
26
src/end.c
26
src/end.c
@@ -1237,6 +1237,9 @@ struct obj *list;
|
||||
boolean identified, all_containers, reportempty;
|
||||
{
|
||||
register struct obj *box, *obj;
|
||||
struct obj **oarray;
|
||||
int i,j,n;
|
||||
char *invlet;
|
||||
char buf[BUFSZ];
|
||||
boolean cat, deadcat;
|
||||
|
||||
@@ -1256,10 +1259,30 @@ boolean identified, all_containers, reportempty;
|
||||
continue; /* wrong type of container */
|
||||
} else if (box->cobj) {
|
||||
winid tmpwin = create_nhwindow(NHW_MENU);
|
||||
|
||||
/* count the number of items */
|
||||
for (n = 0, obj = box->cobj; obj; obj = obj->nobj) n++;
|
||||
/* Make a temporary array to store the objects sorted */
|
||||
oarray = objarr_init(n);
|
||||
|
||||
/* Add objects to the array */
|
||||
i = 0;
|
||||
invlet = flags.inv_order;
|
||||
nextclass:
|
||||
for (obj = box->cobj; obj; obj = obj->nobj) {
|
||||
if (!flags.sortpack || obj->oclass == *invlet) {
|
||||
objarr_set(obj, i++, oarray, (flags.sortloot == 'f' || flags.sortloot == 'l') );
|
||||
}
|
||||
} /* for loop */
|
||||
if (flags.sortpack) {
|
||||
if (*++invlet) goto nextclass;
|
||||
}
|
||||
|
||||
Sprintf(buf, "Contents of %s:", the(xname(box)));
|
||||
putstr(tmpwin, 0, buf);
|
||||
putstr(tmpwin, 0, "");
|
||||
for (obj = box->cobj; obj; obj = obj->nobj) {
|
||||
for (i = 0; i < n; i++) {
|
||||
obj = oarray[i];
|
||||
if (identified) {
|
||||
makeknown(obj->otyp);
|
||||
obj->known = obj->bknown =
|
||||
@@ -1269,6 +1292,7 @@ boolean identified, all_containers, reportempty;
|
||||
}
|
||||
putstr(tmpwin, 0, doname(obj));
|
||||
}
|
||||
free(oarray);
|
||||
if (cat) putstr(tmpwin, 0, "Schroedinger's cat");
|
||||
else if (deadcat) putstr(tmpwin, 0, "Schroedinger's dead cat");
|
||||
display_nhwindow(tmpwin, TRUE);
|
||||
|
||||
126
src/invent.c
126
src/invent.c
@@ -8,6 +8,7 @@
|
||||
#define NOINVSYM '#'
|
||||
#define CONTAINED_SYM '>' /* designator for inside a container */
|
||||
|
||||
STATIC_DCL int FDECL(sortloot_cmp, (struct obj *, struct obj *));
|
||||
STATIC_DCL void NDECL(reorder_invent);
|
||||
STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
|
||||
STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
|
||||
@@ -42,6 +43,88 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
|
||||
*/
|
||||
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
|
||||
|
||||
|
||||
int
|
||||
sortloot_cmp(obj1, obj2)
|
||||
struct obj *obj1;
|
||||
struct obj *obj2;
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 0;
|
||||
|
||||
/* Sort object names in lexicographical order, ignoring quantity. */
|
||||
int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
|
||||
|
||||
if (name_cmp != 0) {
|
||||
return name_cmp;
|
||||
}
|
||||
|
||||
/* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown to 0. */
|
||||
val1 = obj1->bknown ? (obj1->blessed << 2) + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed : 0;
|
||||
val2 = obj2->bknown ? (obj2->blessed << 2) + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed : 0;
|
||||
if (val1 != val2) {
|
||||
return val2 - val1; /* Because bigger is better. */
|
||||
}
|
||||
|
||||
/* Sort by greasing. This will put the objects in degreasing order. */
|
||||
val1 = obj1->greased;
|
||||
val2 = obj2->greased;
|
||||
if (val1 != val2) {
|
||||
return val2 - val1; /* Because bigger is better. */
|
||||
}
|
||||
|
||||
/* Sort by erosion. The effective amount is what matters. */
|
||||
val1 = greatest_erosion(obj1);
|
||||
val2 = greatest_erosion(obj2);
|
||||
if (val1 != val2) {
|
||||
return val1 - val2; /* Because bigger is WORSE. */
|
||||
}
|
||||
|
||||
/* Sort by erodeproofing. Map known-invulnerable to 1, and both
|
||||
* known-vulnerable and unknown-vulnerability to 0, because that's how they're displayed. */
|
||||
val1 = obj1->rknown && obj1->oerodeproof;
|
||||
val2 = obj2->rknown && obj2->oerodeproof;
|
||||
if (val1 != val2) {
|
||||
return val2 - val1; /* Because bigger is better. */
|
||||
}
|
||||
|
||||
/* Sort by enchantment. Map unknown to -1000, which is comfortably below the range of ->spe. */
|
||||
val1 = obj1->known ? obj1->spe : -1000;
|
||||
val2 = obj2->known ? obj2->spe : -1000;
|
||||
if (val1 != val2) {
|
||||
return val2 - val1; /* Because bigger is better. */
|
||||
}
|
||||
|
||||
return 0; /* They're identical, as far as we're concerned. */
|
||||
}
|
||||
|
||||
struct obj **
|
||||
objarr_init(n)
|
||||
int n;
|
||||
{
|
||||
return (struct obj **)alloc(n * sizeof(struct obj *));
|
||||
}
|
||||
|
||||
void
|
||||
objarr_set(otmp, idx, oarray, dosort)
|
||||
struct obj *otmp;
|
||||
int idx;
|
||||
struct obj **oarray;
|
||||
boolean dosort;
|
||||
{
|
||||
if (dosort) {
|
||||
int j;
|
||||
for (j = idx; j; j--) {
|
||||
if (sortloot_cmp(otmp, oarray[j-1]) > 0) break;
|
||||
oarray[j] = oarray[j-1];
|
||||
}
|
||||
oarray[j] = otmp;
|
||||
} else {
|
||||
oarray[idx] = otmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
assigninvlet(otmp)
|
||||
register struct obj *otmp;
|
||||
@@ -1722,6 +1805,8 @@ long* out_cnt;
|
||||
static winid local_win = WIN_ERR; /* window for partial menus */
|
||||
anything any;
|
||||
menu_item *selected;
|
||||
struct obj **oarray;
|
||||
int i, j;
|
||||
|
||||
/* overriden by global flag */
|
||||
if (flags.perm_invent) {
|
||||
@@ -1768,6 +1853,19 @@ long* out_cnt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* count the number of items */
|
||||
for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
|
||||
if (!lets || !*lets || index(lets, otmp->invlet)) n++;
|
||||
|
||||
oarray = objarr_init(n);
|
||||
|
||||
/* Add objects to the array */
|
||||
i = 0;
|
||||
for (otmp = invent; otmp; otmp = otmp->nobj)
|
||||
if (!lets || !*lets || index(lets, otmp->invlet)) {
|
||||
objarr_set(otmp, i++, oarray, (flags.sortloot == 'f'));
|
||||
}
|
||||
|
||||
start_menu(win);
|
||||
if (wizard && iflags.override_ID) {
|
||||
char prompt[BUFSZ];
|
||||
@@ -1782,22 +1880,21 @@ long* out_cnt;
|
||||
nextclass:
|
||||
classcount = 0;
|
||||
any = zeroany; /* set all bits to zero */
|
||||
for(otmp = invent; otmp; otmp = otmp->nobj) {
|
||||
ilet = otmp->invlet;
|
||||
if(!lets || !*lets || index(lets, ilet)) {
|
||||
any = zeroany; /* zero */
|
||||
if (!flags.sortpack || otmp->oclass == *invlet) {
|
||||
if (flags.sortpack && !classcount) {
|
||||
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
||||
for(i = 0; i < n; i++) {
|
||||
otmp = oarray[i];
|
||||
ilet = otmp->invlet;
|
||||
any = zeroany; /* zero */
|
||||
if (!flags.sortpack || otmp->oclass == *invlet) {
|
||||
if (flags.sortpack && !classcount) {
|
||||
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
|
||||
let_to_name(*invlet, FALSE, (want_reply && iflags.menu_head_objsym)), MENU_UNSELECTED);
|
||||
classcount++;
|
||||
}
|
||||
any.a_char = ilet;
|
||||
add_menu(win, obj_to_glyph(otmp),
|
||||
&any, ilet, 0, ATR_NONE, doname(otmp),
|
||||
MENU_UNSELECTED);
|
||||
}
|
||||
classcount++;
|
||||
}
|
||||
any.a_char = ilet;
|
||||
add_menu(win, obj_to_glyph(otmp),
|
||||
&any, ilet, 0, ATR_NONE, doname(otmp),
|
||||
MENU_UNSELECTED);
|
||||
}
|
||||
}
|
||||
if (flags.sortpack) {
|
||||
if (*++invlet) goto nextclass;
|
||||
@@ -1806,6 +1903,7 @@ nextclass:
|
||||
goto nextclass;
|
||||
}
|
||||
}
|
||||
free(oarray);
|
||||
end_menu(win, (char *) 0);
|
||||
|
||||
n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
|
||||
|
||||
22
src/objnam.c
22
src/objnam.c
@@ -19,6 +19,8 @@ STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
|
||||
STATIC_DCL boolean FDECL(singplur_lookup, (char *,char *,BOOLEAN_P,
|
||||
const char *const *));
|
||||
STATIC_DCL char *FDECL(singplur_compound, (char *));
|
||||
STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
|
||||
|
||||
|
||||
struct Jitem {
|
||||
int item;
|
||||
@@ -237,7 +239,15 @@ boolean juice; /* whether or not to append " juice" to the name */
|
||||
|
||||
char *
|
||||
xname(obj)
|
||||
struct obj *obj;
|
||||
{
|
||||
return xname_flags(obj, CXN_NORMAL);
|
||||
}
|
||||
|
||||
char *
|
||||
xname_flags(obj, cxn_flags)
|
||||
register struct obj *obj;
|
||||
unsigned cxn_flags; /* bitmask of CXN_xxx values */
|
||||
{
|
||||
register char *buf;
|
||||
register int typ = obj->otyp;
|
||||
@@ -246,7 +256,7 @@ register struct obj *obj;
|
||||
const char *actualn = OBJ_NAME(*ocl);
|
||||
const char *dn = OBJ_DESCR(*ocl);
|
||||
const char *un = ocl->oc_uname;
|
||||
boolean pluralize = (obj->quan != 1L);
|
||||
boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
|
||||
boolean known, dknown, bknown;
|
||||
|
||||
buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */
|
||||
@@ -1066,6 +1076,16 @@ struct obj *obj;
|
||||
return xname(obj);
|
||||
}
|
||||
|
||||
/* like cxname, but ignores quantity */
|
||||
char *
|
||||
cxname_singular(obj)
|
||||
struct obj *obj;
|
||||
{
|
||||
if (obj->otyp == CORPSE)
|
||||
return corpse_xname(obj, (const char *)0, CXN_SINGULAR);
|
||||
return xname_flags(obj, CXN_SINGULAR);
|
||||
}
|
||||
|
||||
/* treat an object as fully ID'd when it might be used as reason for death */
|
||||
char *
|
||||
killer_xname(obj)
|
||||
|
||||
@@ -347,6 +347,7 @@ static struct Comp_Opt
|
||||
{ "scroll_amount", "amount to scroll map when scroll_margin is reached",
|
||||
20, DISP_IN_GAME }, /*WC*/
|
||||
{ "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/
|
||||
{ "sortloot", "sort object selection lists by description", 4, SET_IN_GAME },
|
||||
#ifdef MSDOS
|
||||
{ "soundcard", "type of sound card to use", 20, SET_IN_FILE },
|
||||
#endif
|
||||
@@ -659,6 +660,7 @@ initoptions_init()
|
||||
(genericptr_t)def_inv_order, sizeof flags.inv_order);
|
||||
flags.pickup_types[0] = '\0';
|
||||
flags.pickup_burden = MOD_ENCUMBER;
|
||||
flags.sortloot = 'l'; /* sort only loot by default */
|
||||
|
||||
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
|
||||
flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
|
||||
@@ -2360,6 +2362,22 @@ goodfruit:
|
||||
return;
|
||||
}
|
||||
|
||||
fullname = "sortloot";
|
||||
if (match_optname(opts, fullname, 4, TRUE)) {
|
||||
op = string_for_env_opt(fullname, opts, FALSE);
|
||||
if (op) {
|
||||
switch (tolower(*op)) {
|
||||
case 'n':
|
||||
case 'l':
|
||||
case 'f': flags.sortloot = tolower(*op);
|
||||
break;
|
||||
default: badoption(opts);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fullname = "suppress_alert";
|
||||
if (match_optname(opts, fullname, 4, TRUE)) {
|
||||
if (duplicate) complain_about_duplicate(opts,1);
|
||||
@@ -2896,6 +2914,10 @@ static NEARDATA const char *runmodes[] = {
|
||||
"teleport", "run", "walk", "crawl"
|
||||
};
|
||||
|
||||
static NEARDATA const char *sortltype[] = {
|
||||
"none", "loot", "full"
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert the given string of object classes to a string of default object
|
||||
* symbols.
|
||||
@@ -3204,7 +3226,8 @@ boolean setinitial,setfromfile;
|
||||
char buf[BUFSZ];
|
||||
|
||||
/* Special handling of menustyle, pickup_burden, pickup_types,
|
||||
* disclose, runmode, msg_window, menu_headings, and number_pad options.
|
||||
* disclose, runmode, msg_window, menu_headings, sortloot,
|
||||
* and number_pad options.
|
||||
* Also takes care of interactive autopickup_exception_handling changes.
|
||||
*/
|
||||
if (!strcmp("menustyle", optname)) {
|
||||
@@ -3385,6 +3408,23 @@ boolean setinitial,setfromfile;
|
||||
}
|
||||
destroy_nhwindow(tmpwin);
|
||||
#endif
|
||||
} else if (!strcmp("sortloot", optname)) {
|
||||
const char *sortl_name;
|
||||
menu_item *sortl_pick = (menu_item *)0;
|
||||
tmpwin = create_nhwindow(NHW_MENU);
|
||||
start_menu(tmpwin);
|
||||
for (i = 0; i < SIZE(sortltype); i++) {
|
||||
sortl_name = sortltype[i];
|
||||
any.a_char = *sortl_name;
|
||||
add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0,
|
||||
ATR_NONE, sortl_name, MENU_UNSELECTED);
|
||||
}
|
||||
end_menu(tmpwin, "Select loot sorting type:");
|
||||
if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) {
|
||||
flags.sortloot = sortl_pick->item.a_char;
|
||||
free((genericptr_t)sortl_pick);
|
||||
}
|
||||
destroy_nhwindow(tmpwin);
|
||||
} else if (!strcmp("align_message", optname) ||
|
||||
!strcmp("align_status", optname)) {
|
||||
menu_item *window_pick = (menu_item *)0;
|
||||
@@ -3974,6 +4014,15 @@ char *buf;
|
||||
if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
|
||||
else Strcpy(buf, defopt);
|
||||
}
|
||||
else if (!strcmp(optname, "sortloot")) {
|
||||
char *sortname = (char *)NULL;
|
||||
for (i=0; i < SIZE(sortltype) && sortname==(char *)NULL; i++) {
|
||||
if (flags.sortloot == sortltype[i][0])
|
||||
sortname = (char *)sortltype[i];
|
||||
}
|
||||
if (sortname != (char *)NULL)
|
||||
Sprintf(buf, "%s", sortname);
|
||||
}
|
||||
else if (!strcmp(optname, "player_selection"))
|
||||
Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
|
||||
#ifdef MSDOS
|
||||
|
||||
17
src/pickup.c
17
src/pickup.c
@@ -708,9 +708,10 @@ menu_item **pick_list; /* return list of items picked */
|
||||
int how; /* type of query */
|
||||
boolean FDECL((*allow), (OBJ_P));/* allow function */
|
||||
{
|
||||
int n;
|
||||
int i, j, n;
|
||||
winid win;
|
||||
struct obj *curr, *last, fake_hero_object;
|
||||
struct obj **oarray;
|
||||
char *pack;
|
||||
anything any;
|
||||
boolean printed_type_name,
|
||||
@@ -743,6 +744,16 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
|
||||
return 1;
|
||||
}
|
||||
|
||||
oarray = objarr_init(n);
|
||||
/* Add objects to the array */
|
||||
i = 0;
|
||||
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
|
||||
if ((*allow)(curr)) {
|
||||
objarr_set(curr, i++, oarray, (flags.sortloot == 'f' ||
|
||||
(flags.sortloot == 'l' && !(qflags & USE_INVLET))));
|
||||
}
|
||||
}
|
||||
|
||||
win = create_nhwindow(NHW_MENU);
|
||||
start_menu(win);
|
||||
any = zeroany;
|
||||
@@ -756,7 +767,8 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
|
||||
pack = flags.inv_order;
|
||||
do {
|
||||
printed_type_name = FALSE;
|
||||
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
|
||||
for (i = 0; i < n; i++) {
|
||||
curr = oarray[i];
|
||||
if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE &&
|
||||
will_feel_cockatrice(curr, FALSE)) {
|
||||
destroy_nhwindow(win); /* stop the menu and revert */
|
||||
@@ -784,6 +796,7 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
|
||||
}
|
||||
pack++;
|
||||
} while (sorted && *pack);
|
||||
free(oarray);
|
||||
|
||||
if (engulfer) {
|
||||
char buf[BUFSZ];
|
||||
|
||||
Reference in New Issue
Block a user