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 17:53:40 +03:00
parent 9072e80085
commit 92a7962399
10 changed files with 255 additions and 19 deletions

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).
.lp "silent "
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
Sort the pack contents by type when displaying inventory (default on).
.lp sparkle

View File

@@ -2792,6 +2792,20 @@ Show your approximate accumulated score on bottom line (default off).
\item[\ib{silent}]
Suppress terminal beeps (default on).
%.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}]
Sort the pack contents by type when displaying inventory (default on).
%.lp

View File

@@ -1152,6 +1152,7 @@ adopt/adapt/improve Dungeon Overview
Aardvark Joe's Extended Logfile
Michael Deutschmann's use_darkgray
Clive Crous' dark_room
Jukka Lahtinen's sortloot
Code Cleanup and Reorganization

View File

@@ -857,6 +857,8 @@ E int NDECL(midnight);
/* ### 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 struct obj *FDECL(merge_choice, (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 char *FDECL(corpse_xname, (struct obj *,const char *,unsigned));
E char *FDECL(cxname, (struct obj *));
E char *FDECL(cxname_singular, (struct obj *));
E char *FDECL(killer_xname, (struct obj *));
E char *FDECL(short_oname, (struct obj *,char *(*)(OBJ_P),char *(*)(OBJ_P),
unsigned));

View File

@@ -48,6 +48,7 @@ struct flag {
boolean showexp; /* show experience points */
boolean showscore; /* show score */
boolean silent; /* whether the bell rings or not */
boolean sortloot; /* sort items alphabetically when looting */
boolean sortpack; /* sorted inventory */
boolean sparkle; /* show "resisting" special FX (Scott Bigham) */
boolean standout; /* use standout for --More-- */

View File

@@ -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);

View File

@@ -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);

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,
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)

View File

@@ -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

View File

@@ -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];