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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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-- */
|
||||
|
||||
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