From: PatR Date: Sun, 20 Dec 2020 01:45:49 +0000 (-0800) Subject: re-implement pull req #334 - sorting discoveries X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4cf6727b4e845b2c43145c9db73b3591f69976ac;p=nethack re-implement pull req #334 - sorting discoveries The pull request changed \ and ` output to unconditionally show discoveries in alphabetical order. That's nearly useless except when looking at prediscovered weapons and armor that fighter types start out knowing. This allows the player to choose sorting order via the new 'sortdiscoveries' option. In addition to setting it via config file or 'O', it can be set via 'm' prefix for \ and `. Choices are: o - sort by class, by order of discovery in class (default); s - sort by 'sortloot' classification which groups sub-class items (so all helmets before any other armor, then all gloves, then boots, and so on); within each sub-class, or whole class for classes which don't subdivide so usefully, partly-discovered types (where a name has been assigned) come before fully ID'd types; c - sort by class, alphabetically within class; a - sort alphabetically across all classes. Turned out to be a large amount of work for fairly little gain, although I suspect that 'sortdiscoveries:s' will eventually be more popular than the default. Invalidates existing save files so that current sort setting can persist across save/restore cycles. Closes #334 --- diff --git a/dat/opthelp b/dat/opthelp index f3debdc5d..c752a8d2e 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -205,6 +205,15 @@ scores the parts of the score list you wish [!own/3 top/2 around] to see when the game ends. You choose a combination of top scores, scores around the top scores, and all of your own scores. +sortdiscoveries preferred order when viewing list of discovered objects [o] + o -- in order of discovery within each class + s -- sortloot's "loot" order + c -- alphabetized within each class + a -- alphabetized across all classes +sortloot preferred order when examining a set of objects [n] + none -- no sorting + loot -- sort piles of objects on floor and in containers + full -- 'loot' plus objects in inventory statushilites whether to display status highlights (when non-zero) and [0] also how many turns to display temporary highlights (for 'up', 'down', and 'changed' hilite_status rules) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 4fab00cd7..dab9e06da 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -35,7 +35,7 @@ .ds vr "NetHack 3.7 .ds f0 "\*(vr .ds f1 -.ds f2 "December 16, 2020 +.ds f2 "December 19, 2020 . .\" A note on some special characters: .\" \(lq = left double quote @@ -1055,8 +1055,12 @@ be added to the end of the list rather than be inserted into the sorted ordering.) .lp \\\\ Show what types of objects have been discovered. +.lp "" +May be preceded by \(oq\f(CRm\fP\(cq to select preferred display order. .lp \` Show discovered types for one class of objects. +.lp "" +May be preceded by \(oq\f(CRm\fP\(cq to select preferred display order. .lp ! Escape to a shell. See \(lq#shell\(rq below for more details. @@ -1258,10 +1262,16 @@ Default key is \(oq\(haD\(cq, and \(oqk\(cq if is on. .lp "#known " Show what object types have been discovered. -Default key is \(oq\\\(cq. +Default key is \(oq\f(CR\\\fP\(cq. +.lp "" +The \(oq\f(CRm\fP\(cq prefix allows assigning a new value to the +.op sortdiscoveries +option to control the order in which the discoveries are displayed. .lp #knownclass Show discovered types for one class of objects. -Default key is \(oq\`\(cq. +Default key is \(oq\f(CR\`\fP\(cq. +.lp "" +The \(oq\f(CRm\fP\(cq prefix operates the same as for \(lq#known\(rq. .lp #levelchange Change your experience level. Autocompletes. @@ -4109,19 +4119,47 @@ Persistent. Show your approximate accumulated score on bottom line (default off). Persistent. .lp "silent " -Suppress terminal beeps (default on). Persistent. +Suppress terminal beeps (default on). +Persistent. +.lp sortdiscoveries +Controls the sorting behavior for the output of the \(oq\f(CR\\\fP\(cq +and \(oq\f(CR\`\fP\(cq commands. +Persistent. +.lp "" +The possible values are: +.PS o +.PL o +list object types by class, in discovery order within each class; +default; +.PL s +list object types by +.op sortloot +classification: by class, by sub-class within class for classes which +have substantial groupings (like helmets, boots, gloves, and so forth +for armor), with object types partly-discovered via assigned name coming +before fully identified types; +.PL c +list by class, alphabetically within each class; +.PL a +list alphabetically across all classes. +.PE +Can be interactively set via the \(oq\f(CRO\fP\(cq command or via using +the \(oq\f(CRm\fP\(cq prefix before the \(oq\f(CR\\\fP\(cq +or \(oq\f(CR\`\fP\(cq command. .lp sortloot Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. +.lp "" The possible values are: -.PS full +.PS none \" note: with proportional font, "none" is wider than "full" or "loot" .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. +show lists the traditional way without sorting; +default. .PE .lp sortpack Sort the pack contents by type when displaying inventory (default on). diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index a3dd3fecc..b1606a34c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -45,7 +45,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7 by Mike Stephenson and others)} -\date{December 16, 2020} +\date{December 19, 2020} \maketitle @@ -1154,9 +1154,15 @@ ordering.) %.lp \item[\tb{$\backslash$}] Show what types of objects have been discovered. +\\ +%.lp "" +May be preceded by `{\tt m}' to select preferred display order. %.lp \item[\tb{\`}] Show discovered types for one class of objects. +\\ +.lp "" +May be preceded by `{\tt m}' to select preferred display order. %.lp \item[\tb{!}] Escape to a shell. @@ -1340,10 +1346,18 @@ and also `{\tt k}' if {\it number\verb+_+pad\/} is on. \item[\tb{\#known}] Show what object types have been discovered. Default key is `{\tt $\backslash$}'. +\\ +%.lp "" +The `{\tt m}' prefix allows assigning a new value to the +{\it sortdiscoveries\/} +option to control the order in which the discoveries are displayed. %.lp \item[\tb{\#knownclass}] Show discovered types for one class of objects. Default key is `{\tt `}'. +\\ +%.lp "" +The `{\tt m}' prefix operates the same as for \(lq#known\(rq. %.lp \item[\tb{\#levelchange}] Change your experience level. @@ -4450,17 +4464,44 @@ Persistent. \item[\ib{silent}] Suppress terminal beeps (default on). Persistent. %.lp +\item[\ib{sortdiscoveries}] +Controls the sorting behavior for the output of the `{\tt $\backslash$}' +and `{\tt \`}' commands. +Persistent. +\\ +%.lp "" +The possible values are: +%.PS o +%.PL o +(\tt o} --- list object types by class, in discovery order within each class; +default; +%.PL s +{\tt s} --- list object types by {\it sortloot\/} +classification: by class, by sub-class within class for classes which +have substantial groupings (like helmets, boots, gloves, and so forth +for armor), with object types partly-discovered via assigned name coming +before fully identified types; +\\ +%.PL c +{\tt c} --- list by class, alphabetically within each class;\\ +%.PL a +{\tt a} --- list alphabetically across all classes.\\ +%.PE +Can be interactively set via the `{\tt O}' command or via using +the `{\tt m}' prefix before the `{\tt $\backslash$}' +or `{\tt \`}' command. +%.lp \item[\ib{sortloot}] Controls the sorting behavior of pickup lists for inventory and \#loot commands and some others. Persistent. - +\\ 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. +{\tt none} --- show lists the traditional way without sorting; default. %.ei %.ed %.lp diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 9b619329b..23868980b 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -681,6 +681,7 @@ when "?i" (show key bindings) displays commands and their keys, also show assign default key binding for or to execute #terrain assign M-X to #exploremode make #herecmdmenu and #therecmdmenu autocomplete +add 'sortdiscoveries' option to control output of '\' and '`' commands Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index f771e0766..cc7fd8be9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -972,6 +972,7 @@ E void NDECL(ustatusline); /* ### invent.c ### */ +E void FDECL(loot_classify, (Loot *, struct obj *)); E Loot *FDECL(sortloot, (struct obj **, unsigned, BOOLEAN_P, boolean (*)(OBJ_P))); E void FDECL(unsortloot, (Loot **)); @@ -1743,6 +1744,7 @@ E void FDECL(savenames, (NHFILE *)); E void FDECL(restnames, (NHFILE *)); E void FDECL(discover_object, (int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(undiscover_object, (int)); +E int FDECL(choose_disco_sort, (int)); E int NDECL(dodiscovered); E int NDECL(doclassdisco); E void NDECL(rename_disco); diff --git a/include/flag.h b/include/flag.h index 5a0f0213e..4122dd046 100644 --- a/include/flag.h +++ b/include/flag.h @@ -80,6 +80,7 @@ struct flag { #define PARANOID_EATING 0x0200 int pickup_burden; /* maximum burden before prompt */ int pile_limit; /* controls feedback when walking over objects */ + char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */ char sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */ char inv_order[MAXOCLASSES]; char pickup_types[MAXOCLASSES]; @@ -93,8 +94,7 @@ struct flag { char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various info upon exit */ char menu_style; /* User interface style setting */ - boolean made_fruit; /* don't easily let the user overflow the number of - fruits */ + boolean made_fruit; /* don't easily let user overflow fruit limit */ /* KMH, role patch -- Variables used during startup. * diff --git a/include/optlist.h b/include/optlist.h index 7ae20db6e..9bf4a057d 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -406,6 +406,8 @@ pfx_##a, &flags.silent) NHOPTB(softkeyboard, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias, &iflags.wc2_softkeyboard) + NHOPTC(sortdiscoveries, 0, opt_in, set_in_game, Yes, Yes, No, Yes, + NoAlias, "preferred order when displaying discovered objects") NHOPTC(sortloot, 4, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, "sort object selection lists by description") NHOPTB(sortpack, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, diff --git a/include/patchlevel.h b/include/patchlevel.h index 47f5d5235..d6969198b 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 28 +#define EDITLEVEL 29 /* * Development status possibilities. diff --git a/src/cmd.c b/src/cmd.c index 65c05546b..94f5a0068 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3236,6 +3236,8 @@ int NDECL((*cmd_func)); /* 'm' for removing saddle from adjacent monster without checking for containers at */ || cmd_func == doloot + /* offer menu to choose discoveries sort order */ + || cmd_func == dodiscovered || cmd_func == doclassdisco /* travel: pop up a menu of interesting targets in view */ || cmd_func == dotravel /* wait and search: allow even if next to a hostile monster */ diff --git a/src/invent.c b/src/invent.c index f7be4f669..63f7904a9 100644 --- a/src/invent.c +++ b/src/invent.c @@ -13,7 +13,6 @@ #define CONTAINED_SYM '>' /* designator for inside a container */ #define HANDS_SYM '-' -static void FDECL(loot_classify, (Loot *, struct obj *)); static char *FDECL(loot_xname, (struct obj *)); static int FDECL(invletter_value, (CHAR_P)); static int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr, @@ -54,7 +53,7 @@ static char FDECL(obj_to_let, (struct obj *)); static const char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */ /* sortloot() classification; called at most once [per sort] for each object */ -static void +void loot_classify(sort_item, obj) Loot *sort_item; struct obj *obj; diff --git a/src/o_init.c b/src/o_init.c index 0ef30c222..5806e9ee3 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -9,6 +9,8 @@ static void FDECL(setgemprobs, (d_level *)); static void FDECL(shuffle, (int, int, BOOLEAN_P)); static void NDECL(shuffle_all); static boolean FDECL(interesting_to_discover, (int)); +static int FDECL(CFDECLSPEC discovered_cmp, (const genericptr, + const genericptr)); static char *FDECL(oclass_to_name, (CHAR_P, char *)); #ifdef USE_TILES @@ -465,37 +467,167 @@ static const short uniq_objs[] = { BELL_OF_OPENING, }; +/* discoveries qsort comparison function */ +static int CFDECLSPEC +discovered_cmp(v1, v2) +const genericptr v1; +const genericptr v2; +{ + const char *s1 = *(const char **) v1; + const char *s2 = *(const char **) v2; + /* each element starts with "* " or " " but we don't sort by those */ + int res = strcmpi(s1 + 2, s2 + 2); + + if (res == 0) { + ; /* no tie-breaker needed */ + } + return res; +} + +static char * +sortloot_descr(otyp, outbuf) +int otyp; +char *outbuf; +{ + Loot sl_cookie; + struct obj o; + + o = cg.zeroobj; + o.otyp = otyp; + o.oclass = objects[otyp].oc_class; + o.dknown = 1; + o.known = (objects[otyp].oc_name_known || !objects[otyp].oc_uses_known) + ? 1 : 0; + o.corpsenm = NON_PM; /* suppress statue and figurine details */ + /* but suppressing fruit details leads to "bad fruit #0" */ + if (otyp == SLIME_MOLD) + o.spe = g.context.current_fruit; + + (void) memset((genericptr_t) &sl_cookie, 0, sizeof sl_cookie); + sl_cookie.obj = (struct obj *) 0; + sl_cookie.str = (char *) 0; + + loot_classify(&sl_cookie, &o); + Sprintf(outbuf, "%02d%02d%1d ", + sl_cookie.orderclass, sl_cookie.subclass, sl_cookie.disco); + return outbuf; +} + +#define DISCO_BYCLASS 0 /* by discovery order within each class */ +#define DISCO_SORTLOOT 1 /* by discovery order within each subclass */ +#define DISCO_ALPHABYCLASS 2 /* alphabetized within each class */ +#define DISCO_ALPHABETIZED 3 /* alphabetized across all classes */ +/* also used in options.c (optfn_sortdiscoveries) */ +const char disco_order_let[] = "osca"; +const char *const disco_orders_descr[] = { + "by order of discovery within each class", + "sortloot order (by class with some sub-class groupings)", + "alphabetical within each class", + "alphabetical across all classes", + (char *) 0 +}; + +int +choose_disco_sort(mode) +int mode; /* 0 => 'O' cmd, 1 => full discoveries; 2 => class discoveries */ +{ + winid tmpwin; + menu_item *selected; + anything any; + int i, n, choice; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ + for (i = 0; disco_orders_descr[i]; ++i) { + any.a_int = disco_order_let[i]; + add_menu(tmpwin, NO_GLYPH, &any, (char) any.a_int, 0, ATR_NONE, + disco_orders_descr[i], + (disco_order_let[i] == flags.discosort) + ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + if (mode == 2) { + /* called via 'm `' where full alphabetize doesn't make sense + (only showing one class so can't span all classes) but the + chosen sort will stick and also apply to '\' usage */ + any = cg.zeroany; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "", MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "Note: full alphabetical and alphabetical within class", + MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + " are equivalent for single class discovery, but", + MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + " will matter for future use of total discoveries.", + MENU_ITEMFLAGS_NONE); + } + end_menu(tmpwin, "Ordering of discoveries"); + + n = select_menu(tmpwin, PICK_ONE, &selected); + destroy_nhwindow(tmpwin); + if (n > 0) { + choice = selected[0].item.a_int; + /* skip preselected entry if we have more than one item chosen */ + if (n > 1 && choice == (int) flags.discosort) + choice = selected[1].item.a_int; + free((genericptr_t) selected); + flags.discosort = choice; + } + return n; +} + /* the '\' command - show discovered object types */ int dodiscovered() /* free after Robert Viduya */ { - register int i, dis; - int ct = 0; - char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ]; winid tmpwin; + char *s, *p, oclass, prev_class, + classes[MAXOCLASSES], buf[BUFSZ], + *sorted_lines[NUM_OBJECTS]; /* overkill */ + int i, j, sortindx, dis, ct, uniq_ct, arti_ct, sorted_ct; + boolean alphabetized, alphabyclass, lootsort; + + if (!flags.discosort || !(p = index(disco_order_let, flags.discosort))) + flags.discosort = 'o'; + + if (iflags.menu_requested) { + if (choose_disco_sort(1) < 0) + return 0; + } + alphabyclass = (flags.discosort == 'c'); + alphabetized = (flags.discosort == 'a' || alphabyclass); + lootsort = (flags.discosort == 's'); + sortindx = index(disco_order_let, flags.discosort) - disco_order_let; tmpwin = create_nhwindow(NHW_MENU); - putstr(tmpwin, 0, "Discoveries"); + Sprintf(buf, "Discoveries, %s", disco_orders_descr[sortindx]); + putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); /* gather "unique objects" into a pseudo-class; note that they'll also be displayed individually within their regular class */ + uniq_ct = 0; for (i = dis = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { if (!dis++) putstr(tmpwin, iflags.menu_headings, "Unique items"); + ++uniq_ct; Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); - ++ct; } /* display any known artifacts as another pseudo-class */ - ct += disp_artifact_discoveries(tmpwin); + arti_ct = disp_artifact_discoveries(tmpwin); /* several classes are omitted from packorder; one is of interest here */ Strcpy(classes, flags.inv_order); if (!index(classes, VENOM_CLASS)) (void) strkitten(classes, VENOM_CLASS); /* append char to string */ + ct = uniq_ct + arti_ct; + sorted_ct = 0; for (s = classes; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ @@ -504,21 +636,63 @@ dodiscovered() /* free after Robert Viduya */ if ((dis = g.disco[i]) != 0 && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { - putstr(tmpwin, iflags.menu_headings, - let_to_name(oclass, FALSE, FALSE)); - prev_class = oclass; + if ((alphabyclass || lootsort) && sorted_ct) { + /* output previous class */ + qsort(sorted_lines, sorted_ct, sizeof (char *), + discovered_cmp); + for (j = 0; j < sorted_ct; ++j) { + p = sorted_lines[j]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[j]), sorted_lines[j] = 0; + } + sorted_ct = 0; + } + if (!alphabetized || alphabyclass) { + /* header for new class */ + putstr(tmpwin, iflags.menu_headings, + let_to_name(oclass, FALSE, FALSE)); + prev_class = oclass; + } } - Sprintf(buf, "%s %s", - (objects[dis].oc_pre_discovered ? "*" : " "), - obj_typename(dis)); - putstr(tmpwin, 0, buf); + Strcpy(buf, objects[dis].oc_pre_discovered ? "* " : " "); + if (lootsort) + (void) sortloot_descr(dis, &buf[2]); + Strcat(buf, obj_typename(dis)); + + if (!alphabetized && !lootsort) + putstr(tmpwin, 0, buf); + else + sorted_lines[sorted_ct++] = dupstr(buf); } } } if (ct == 0) { You("haven't discovered anything yet..."); - } else + } else { + if (sorted_ct) { + /* if we're alphabetizing by class, we've already shown the + relevant header above; if we're alphabetizing across all + classes, we normally don't need a header; but it we showed + any unique items or any artifacts then we do need one */ + if ((uniq_ct || arti_ct) && !alphabyclass) + putstr(tmpwin, iflags.menu_headings, "Discovered items"); + qsort(sorted_lines, sorted_ct, sizeof (char *), discovered_cmp); + for (j = 0; j < sorted_ct; ++j) { + p = sorted_lines[j]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[j]), sorted_lines[j] = 0; + } + } display_nhwindow(tmpwin, TRUE); + } destroy_nhwindow(tmpwin); return 0; @@ -547,13 +721,24 @@ doclassdisco() havent_discovered_any[] = "haven't discovered any %s yet.", unique_items[] = "unique items", artifact_items[] = "artifacts"; - char *s, c, oclass, menulet, allclasses[MAXOCLASSES], - discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ]; - int i, ct, dis, xtras; - boolean traditional; winid tmpwin = WIN_ERR; - anything any; menu_item *pick_list = 0; + anything any; + char *p, *s, c, oclass, menulet, allclasses[MAXOCLASSES], + discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ], + *sorted_lines[NUM_OBJECTS]; /* overkill */ + int i, ct, dis, xtras, sorted_ct; + boolean traditional, alphabetized, lootsort; + + if (!flags.discosort || !(p = index(disco_order_let, flags.discosort))) + flags.discosort = 'o'; + + if (iflags.menu_requested) { + if (choose_disco_sort(2) < 0) + return 0; + } + alphabetized = (flags.discosort == 'a' || flags.discosort == 'c'); + lootsort = (flags.discosort == 's'); discosyms[0] = '\0'; traditional = (flags.menu_style == MENU_TRADITIONAL @@ -670,9 +855,9 @@ doclassdisco() upstart(strcpy(buf, unique_items))); for (i = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { + ++ct; Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); - ++ct; } if (!ct) You(havent_discovered_any, unique_items); @@ -685,20 +870,40 @@ doclassdisco() break; default: oclass = def_char_to_objclass(c); - Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE)); - putstr(tmpwin, iflags.menu_headings, buf); - for (i = g.bases[(int) oclass]; - i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) { + Sprintf(buf, "Discovered %s in %s", let_to_name(oclass, FALSE, FALSE), + (flags.discosort == 'o') ? "order of discovery" + : (flags.discosort == 's') ? "'sortloot' order" + : "alphabetical order"); + putstr(tmpwin, 0, buf); /* skip iflags.menu_headings */ + sorted_ct = 0; + for (i = g.bases[(int) oclass]; i < g.bases[oclass + 1] - 1; ++i) { if ((dis = g.disco[i]) != 0 && interesting_to_discover(dis)) { - Sprintf(buf, "%s %s", - objects[dis].oc_pre_discovered ? "*" : " ", - obj_typename(dis)); - putstr(tmpwin, 0, buf); ++ct; + Strcpy(buf, objects[dis].oc_pre_discovered ? "* " : " "); + if (lootsort) + (void) sortloot_descr(dis, &buf[2]); + Strcat(buf, obj_typename(dis)); + + if (!alphabetized && !lootsort) + putstr(tmpwin, 0, buf); + else + sorted_lines[sorted_ct++] = dupstr(buf); } } - if (!ct) + if (!ct) { You(havent_discovered_any, oclass_to_name(oclass, buf)); + } else if (sorted_ct) { + qsort(sorted_lines, sorted_ct, sizeof (char *), discovered_cmp); + for (i = 0; i < sorted_ct; ++i) { + p = sorted_lines[i]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[i]), sorted_lines[i] = 0; + } + } break; } if (ct) diff --git a/src/options.c b/src/options.c index 90d2c5b97..c1ce9eefb 100644 --- a/src/options.c +++ b/src/options.c @@ -3256,6 +3256,66 @@ char *op; return optn_ok; } +int +optfn_sortdiscoveries(optidx, req, negated, opts, op) +int optidx; +int req; +boolean negated; +char *opts; +char *op; +{ + if (req == do_init) { + flags.discosort = 'o'; + return optn_ok; + } + if (req == do_set) { + op = string_for_env_opt(allopt[optidx].name, opts, FALSE); + if (negated) { + flags.discosort = 'o'; + } else if (op != empty_optstr) { + switch (lowc(*op)) { + case '0': + case 'o': /* order of discovery */ + flags.discosort = 'o'; + break; + case '1': + case 's': /* sortloot order (subclasses for some classes) */ + flags.discosort = 's'; + break; + case '2': + case 'c': /* alphabetical within each class */ + flags.discosort = 'c'; + break; + case '3': + case 'a': /* alphabetical across all classes */ + flags.discosort = 'a'; + break; + default: + config_error_add("Unknown %s parameter '%s'", + allopt[optidx].name, op); + return optn_silenterr; + } + } else + return optn_err; + return optn_ok; + } + if (req == get_val) { + extern const char *const disco_orders_descr[]; /* o_init.c */ + extern const char disco_order_let[]; + const char *p = index(disco_order_let, flags.discosort); + + if (!p) + flags.discosort = 'o', p = disco_order_let; + Strcpy(opts, disco_orders_descr[p - disco_order_let]); + return optn_ok; + } + if (req == do_handler) { + /* return handler_sortdiscoveries(); */ + (void) choose_disco_sort(0); /* o_init.c */ + } + return optn_ok; +} + int optfn_sortloot(optidx, req, negated, opts, op) int optidx;