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:
Pasi Kallinen
2015-04-09 18:23:54 +03:00
parent 9072e80085
commit 92a7962399
10 changed files with 255 additions and 19 deletions
+13
View File
@@ -2326,6 +2326,19 @@ the appearance of the display, not the way the game treats you.
Show your approximate accumulated score on bottom line (default off). Show your approximate accumulated score on bottom line (default off).
.lp "silent " .lp "silent "
Suppress terminal beeps (default on). Suppress terminal beeps (default on).
.lp sortloot
Controls the sorting behavior of the pickup lists for inventory
and #loot commands and some others.
The possible values are:
.PS full
.PL full
always sort the lists;
.PL loot
only sort the lists that don't use inventory letters, like with
the #loot and pickup commands;
.PL none
show lists the traditional way without sorting.
.PE
.lp sortpack .lp sortpack
Sort the pack contents by type when displaying inventory (default on). Sort the pack contents by type when displaying inventory (default on).
.lp sparkle .lp sparkle
+14
View File
@@ -2792,6 +2792,20 @@ Show your approximate accumulated score on bottom line (default off).
\item[\ib{silent}] \item[\ib{silent}]
Suppress terminal beeps (default on). Suppress terminal beeps (default on).
%.lp %.lp
\item[\ib{sortloot}]
Controls the sorting behavior of pickup lists for inventory
and \#loot commands and some others.
The possible values are:
%.sd
%.si
{\tt full} --- always sort the lists;\\
{\tt loot} --- only sort the lists that don't use inventory
letters, like with the \#loot and pickup commands;\\
{\tt none} --- show lists the traditional way without sorting.
%.ei
%.ed
%.lp
\item[\ib{sortpack}] \item[\ib{sortpack}]
Sort the pack contents by type when displaying inventory (default on). Sort the pack contents by type when displaying inventory (default on).
%.lp %.lp
+1
View File
@@ -1152,6 +1152,7 @@ adopt/adapt/improve Dungeon Overview
Aardvark Joe's Extended Logfile Aardvark Joe's Extended Logfile
Michael Deutschmann's use_darkgray Michael Deutschmann's use_darkgray
Clive Crous' dark_room Clive Crous' dark_room
Jukka Lahtinen's sortloot
Code Cleanup and Reorganization Code Cleanup and Reorganization
+3
View File
@@ -857,6 +857,8 @@ E int NDECL(midnight);
/* ### invent.c ### */ /* ### invent.c ### */
E struct obj **FDECL(objarr_init, (int));
E void FDECL(objarr_set, (struct obj *, int, struct obj **, BOOLEAN_P));
E void FDECL(assigninvlet, (struct obj *)); E void FDECL(assigninvlet, (struct obj *));
E struct obj *FDECL(merge_choice, (struct obj *,struct obj *)); E struct obj *FDECL(merge_choice, (struct obj *,struct obj *));
E int FDECL(merged, (struct obj **,struct obj **)); E int FDECL(merged, (struct obj **,struct obj **));
@@ -1523,6 +1525,7 @@ E char *FDECL(doname, (struct obj *));
E boolean FDECL(not_fully_identified, (struct obj *)); E boolean FDECL(not_fully_identified, (struct obj *));
E char *FDECL(corpse_xname, (struct obj *,const char *,unsigned)); E char *FDECL(corpse_xname, (struct obj *,const char *,unsigned));
E char *FDECL(cxname, (struct obj *)); E char *FDECL(cxname, (struct obj *));
E char *FDECL(cxname_singular, (struct obj *));
E char *FDECL(killer_xname, (struct obj *)); E char *FDECL(killer_xname, (struct obj *));
E char *FDECL(short_oname, (struct obj *,char *(*)(OBJ_P),char *(*)(OBJ_P), E char *FDECL(short_oname, (struct obj *,char *(*)(OBJ_P),char *(*)(OBJ_P),
unsigned)); unsigned));
+1
View File
@@ -48,6 +48,7 @@ struct flag {
boolean showexp; /* show experience points */ boolean showexp; /* show experience points */
boolean showscore; /* show score */ boolean showscore; /* show score */
boolean silent; /* whether the bell rings or not */ boolean silent; /* whether the bell rings or not */
boolean sortloot; /* sort items alphabetically when looting */
boolean sortpack; /* sorted inventory */ boolean sortpack; /* sorted inventory */
boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */
boolean standout; /* use standout for --More-- */ boolean standout; /* use standout for --More-- */
+25 -1
View File
@@ -1237,6 +1237,9 @@ struct obj *list;
boolean identified, all_containers, reportempty; boolean identified, all_containers, reportempty;
{ {
register struct obj *box, *obj; register struct obj *box, *obj;
struct obj **oarray;
int i,j,n;
char *invlet;
char buf[BUFSZ]; char buf[BUFSZ];
boolean cat, deadcat; boolean cat, deadcat;
@@ -1256,10 +1259,30 @@ boolean identified, all_containers, reportempty;
continue; /* wrong type of container */ continue; /* wrong type of container */
} else if (box->cobj) { } else if (box->cobj) {
winid tmpwin = create_nhwindow(NHW_MENU); 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))); Sprintf(buf, "Contents of %s:", the(xname(box)));
putstr(tmpwin, 0, buf); putstr(tmpwin, 0, buf);
putstr(tmpwin, 0, ""); putstr(tmpwin, 0, "");
for (obj = box->cobj; obj; obj = obj->nobj) { for (i = 0; i < n; i++) {
obj = oarray[i];
if (identified) { if (identified) {
makeknown(obj->otyp); makeknown(obj->otyp);
obj->known = obj->bknown = obj->known = obj->bknown =
@@ -1269,6 +1292,7 @@ boolean identified, all_containers, reportempty;
} }
putstr(tmpwin, 0, doname(obj)); putstr(tmpwin, 0, doname(obj));
} }
free(oarray);
if (cat) putstr(tmpwin, 0, "Schroedinger's cat"); if (cat) putstr(tmpwin, 0, "Schroedinger's cat");
else if (deadcat) putstr(tmpwin, 0, "Schroedinger's dead cat"); else if (deadcat) putstr(tmpwin, 0, "Schroedinger's dead cat");
display_nhwindow(tmpwin, TRUE); display_nhwindow(tmpwin, TRUE);
+112 -14
View File
@@ -8,6 +8,7 @@
#define NOINVSYM '#' #define NOINVSYM '#'
#define CONTAINED_SYM '>' /* designator for inside a container */ #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 void NDECL(reorder_invent);
STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *)); STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
STATIC_DCL void FDECL(noarmor, (BOOLEAN_P)); 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) */ 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 void
assigninvlet(otmp) assigninvlet(otmp)
register struct obj *otmp; register struct obj *otmp;
@@ -1722,6 +1805,8 @@ long* out_cnt;
static winid local_win = WIN_ERR; /* window for partial menus */ static winid local_win = WIN_ERR; /* window for partial menus */
anything any; anything any;
menu_item *selected; menu_item *selected;
struct obj **oarray;
int i, j;
/* overriden by global flag */ /* overriden by global flag */
if (flags.perm_invent) { if (flags.perm_invent) {
@@ -1768,6 +1853,19 @@ long* out_cnt;
return ret; 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); start_menu(win);
if (wizard && iflags.override_ID) { if (wizard && iflags.override_ID) {
char prompt[BUFSZ]; char prompt[BUFSZ];
@@ -1782,22 +1880,21 @@ long* out_cnt;
nextclass: nextclass:
classcount = 0; classcount = 0;
any = zeroany; /* set all bits to zero */ any = zeroany; /* set all bits to zero */
for(otmp = invent; otmp; otmp = otmp->nobj) { for(i = 0; i < n; i++) {
ilet = otmp->invlet; otmp = oarray[i];
if(!lets || !*lets || index(lets, ilet)) { ilet = otmp->invlet;
any = zeroany; /* zero */ any = zeroany; /* zero */
if (!flags.sortpack || otmp->oclass == *invlet) { if (!flags.sortpack || otmp->oclass == *invlet) {
if (flags.sortpack && !classcount) { if (flags.sortpack && !classcount) {
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
let_to_name(*invlet, FALSE, (want_reply && iflags.menu_head_objsym)), MENU_UNSELECTED); let_to_name(*invlet, FALSE, (want_reply && iflags.menu_head_objsym)), MENU_UNSELECTED);
classcount++; classcount++;
}
any.a_char = ilet;
add_menu(win, obj_to_glyph(otmp),
&any, ilet, 0, ATR_NONE, doname(otmp),
MENU_UNSELECTED);
}
} }
any.a_char = ilet;
add_menu(win, obj_to_glyph(otmp),
&any, ilet, 0, ATR_NONE, doname(otmp),
MENU_UNSELECTED);
}
} }
if (flags.sortpack) { if (flags.sortpack) {
if (*++invlet) goto nextclass; if (*++invlet) goto nextclass;
@@ -1806,6 +1903,7 @@ nextclass:
goto nextclass; goto nextclass;
} }
} }
free(oarray);
end_menu(win, (char *) 0); end_menu(win, (char *) 0);
n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
+21 -1
View File
@@ -19,6 +19,8 @@ STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
STATIC_DCL boolean FDECL(singplur_lookup, (char *,char *,BOOLEAN_P, STATIC_DCL boolean FDECL(singplur_lookup, (char *,char *,BOOLEAN_P,
const char *const *)); const char *const *));
STATIC_DCL char *FDECL(singplur_compound, (char *)); STATIC_DCL char *FDECL(singplur_compound, (char *));
STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
struct Jitem { struct Jitem {
int item; int item;
@@ -237,7 +239,15 @@ boolean juice; /* whether or not to append " juice" to the name */
char * char *
xname(obj) xname(obj)
struct obj *obj;
{
return xname_flags(obj, CXN_NORMAL);
}
char *
xname_flags(obj, cxn_flags)
register struct obj *obj; register struct obj *obj;
unsigned cxn_flags; /* bitmask of CXN_xxx values */
{ {
register char *buf; register char *buf;
register int typ = obj->otyp; register int typ = obj->otyp;
@@ -246,7 +256,7 @@ register struct obj *obj;
const char *actualn = OBJ_NAME(*ocl); const char *actualn = OBJ_NAME(*ocl);
const char *dn = OBJ_DESCR(*ocl); const char *dn = OBJ_DESCR(*ocl);
const char *un = ocl->oc_uname; const char *un = ocl->oc_uname;
boolean pluralize = (obj->quan != 1L); boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
boolean known, dknown, bknown; boolean known, dknown, bknown;
buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */
@@ -1066,6 +1076,16 @@ struct obj *obj;
return xname(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 */ /* treat an object as fully ID'd when it might be used as reason for death */
char * char *
killer_xname(obj) killer_xname(obj)
+50 -1
View File
@@ -347,6 +347,7 @@ static struct Comp_Opt
{ "scroll_amount", "amount to scroll map when scroll_margin is reached", { "scroll_amount", "amount to scroll map when scroll_margin is reached",
20, DISP_IN_GAME }, /*WC*/ 20, DISP_IN_GAME }, /*WC*/
{ "scroll_margin", "scroll map when this far from the edge", 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 #ifdef MSDOS
{ "soundcard", "type of sound card to use", 20, SET_IN_FILE }, { "soundcard", "type of sound card to use", 20, SET_IN_FILE },
#endif #endif
@@ -659,6 +660,7 @@ initoptions_init()
(genericptr_t)def_inv_order, sizeof flags.inv_order); (genericptr_t)def_inv_order, sizeof flags.inv_order);
flags.pickup_types[0] = '\0'; flags.pickup_types[0] = '\0';
flags.pickup_burden = MOD_ENCUMBER; flags.pickup_burden = MOD_ENCUMBER;
flags.sortloot = 'l'; /* sort only loot by default */
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++)
flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO; flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO;
@@ -2360,6 +2362,22 @@ goodfruit:
return; 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"; fullname = "suppress_alert";
if (match_optname(opts, fullname, 4, TRUE)) { if (match_optname(opts, fullname, 4, TRUE)) {
if (duplicate) complain_about_duplicate(opts,1); if (duplicate) complain_about_duplicate(opts,1);
@@ -2896,6 +2914,10 @@ static NEARDATA const char *runmodes[] = {
"teleport", "run", "walk", "crawl" "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 * Convert the given string of object classes to a string of default object
* symbols. * symbols.
@@ -3204,7 +3226,8 @@ boolean setinitial,setfromfile;
char buf[BUFSZ]; char buf[BUFSZ];
/* Special handling of menustyle, pickup_burden, pickup_types, /* 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. * Also takes care of interactive autopickup_exception_handling changes.
*/ */
if (!strcmp("menustyle", optname)) { if (!strcmp("menustyle", optname)) {
@@ -3385,6 +3408,23 @@ boolean setinitial,setfromfile;
} }
destroy_nhwindow(tmpwin); destroy_nhwindow(tmpwin);
#endif #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) || } else if (!strcmp("align_message", optname) ||
!strcmp("align_status", optname)) { !strcmp("align_status", optname)) {
menu_item *window_pick = (menu_item *)0; 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); if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin);
else Strcpy(buf, defopt); 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")) else if (!strcmp(optname, "player_selection"))
Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog"); Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog");
#ifdef MSDOS #ifdef MSDOS
+15 -2
View File
@@ -708,9 +708,10 @@ menu_item **pick_list; /* return list of items picked */
int how; /* type of query */ int how; /* type of query */
boolean FDECL((*allow), (OBJ_P));/* allow function */ boolean FDECL((*allow), (OBJ_P));/* allow function */
{ {
int n; int i, j, n;
winid win; winid win;
struct obj *curr, *last, fake_hero_object; struct obj *curr, *last, fake_hero_object;
struct obj **oarray;
char *pack; char *pack;
anything any; anything any;
boolean printed_type_name, boolean printed_type_name,
@@ -743,6 +744,16 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
return 1; 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); win = create_nhwindow(NHW_MENU);
start_menu(win); start_menu(win);
any = zeroany; any = zeroany;
@@ -756,7 +767,8 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
pack = flags.inv_order; pack = flags.inv_order;
do { do {
printed_type_name = FALSE; 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 && if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE &&
will_feel_cockatrice(curr, FALSE)) { will_feel_cockatrice(curr, FALSE)) {
destroy_nhwindow(win); /* stop the menu and revert */ destroy_nhwindow(win); /* stop the menu and revert */
@@ -784,6 +796,7 @@ boolean FDECL((*allow), (OBJ_P));/* allow function */
} }
pack++; pack++;
} while (sorted && *pack); } while (sorted && *pack);
free(oarray);
if (engulfer) { if (engulfer) {
char buf[BUFSZ]; char buf[BUFSZ];