diff --git a/dat/opthelp b/dat/opthelp index 4bcc7d057..1ee667f77 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -251,6 +251,13 @@ 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 +sortvanquished preferred order when viewing vanquished monsters list [t] + t -- traditional, order by monster level + d -- order by monster difficulty rating + a -- alphabetical, first any unique monsters then others + c -- order by class, low to high level within each class + n -- order by count, high to low + z -- order by count, low to high 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 5ecccb83e..eb7bab4d6 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1677,12 +1677,15 @@ List vanquished monsters by type and count. Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you, and omits any which got removed from the game without being killed (perhaps by genocide, or by a mollified -shopkeeper dismissing summoned Kops). +shopkeeper dismissing summoned Kops) or were already corpses when placed +on the map. .lp "" Using the \(lqrequest menu\(rq prefix prior to #vanquished brings up -a menu of sorting orders available. -Whichever one is picked is remembered for subsequent #vanquished commands -during the current play session but not saved and restored across sessions. +a menu of sorting orders available (provided that the vanquished monsters +list contains at least two types of monsters). +Whichever ordering is picked gets assigned to the +.op sortvanquished +option so is remembered for subsequent #vanquished requests. During end-of-game disclosure, when asked whether to show vanquished monsters answering \(oq\f(CRa\fP\(cq will let you choose from the sort menu. .lp "" @@ -4415,20 +4418,20 @@ and \(oq\f(CR\`\fP\(cq commands. Persistent. .lp "" The possible values are: -.PS o -.PL o +.PS \f(CRo\fP +.PL \f(CRo\fP list object types by class, in discovery order within each class; default; -.PL s +.PL \f(CRs\fP 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 +.PL \f(CRc\fP list by class, alphabetically within each class; -.PL a +.PL \f(CRa\fP list alphabetically across all classes. .PE Can be interactively set via the \(oq\f(CRO\fP\(cq command or via using @@ -4452,6 +4455,34 @@ default. .lp sortpack Sort the pack contents by type when displaying inventory (default on). Persistent. +.lp sortvanquisted +Controls the sorting behavior for the output of the #vanquished command. +Persistent. +.lp "" +The possible values are: +.PS \f(CRC\fP +.PL \f(CRt\fP +traditional\(emorder by monster level; ties are broken by internal +monster index; +default; +.PL \f(CRd\fP +order by monster difficulty rating; ties broken by internal index; +.PL \f(CRa\fP +order alphabetically, first any unique monsters then all the others; +.\" note: 'A' and 'C' can be set in RC file or NETHACKOPTIONS but not by 'O' +.\" .PL \f(CRA\fP +.\" order alphabetically, unique monsters intermixed with other monsters; +.\" .PL \f(CRC\fP +.\" order by monster class, by high to low level within each class; +.PL \f(CRc\fP +order by monster class, by low to high level within each class; +.PL \f(CRn\fP +order by count, high to low; ties are broken by internal monster index; +.PL \f(CRz\fP +order by count, low to high; ties broken by internal index. +.PE +Can be interactively set via the \(oq\f(CRm O\fP\(cq command or via using +the \(oq\f(CRm\fP\(cq prefix before the #vanquished command. .lp "sparkle " Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index b8ab4e36a..b813666a6 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1912,6 +1912,8 @@ very large humanoids can wear mummy wrappings for ranger characters, shooting any type of arrow while wielding the Longbow of Diana gets an extra +1 to multi-shot change the #vanquished command from debug-only to general user command +add 'sortvanquished' option to be able to set the preferred sort order without + using 'm #vanquished' and to have it persist across save/restore have 'I u' mention whether there are any unpaid items on the floor (unusual but not impossible); it doesn't itemize them or show shop price diff --git a/include/decl.h b/include/decl.h index 1634a3016..c8ad733f2 100644 --- a/include/decl.h +++ b/include/decl.h @@ -561,14 +561,14 @@ struct trapinfo { }; enum vanq_order_modes { - VANQ_MLVL_MNDX = 0, - VANQ_MSTR_MNDX, - VANQ_ALPHA_SEP, - VANQ_ALPHA_MIX, - VANQ_MCLS_HTOL, - VANQ_MCLS_LTOH, - VANQ_COUNT_H_L, - VANQ_COUNT_L_H, + VANQ_MLVL_MNDX = 0, /* t - traditional: by monster level */ + VANQ_MSTR_MNDX, /* d - by difficulty rating */ + VANQ_ALPHA_SEP, /* a - alphabetical, first uniques, then ordinary */ + VANQ_ALPHA_MIX, /* A - alpha with uniques and ordinary intermixed */ + VANQ_MCLS_HTOL, /* C - by class, high to low within class */ + VANQ_MCLS_LTOH, /* c - by class, low to high within class */ + VANQ_COUNT_H_L, /* n - by count, high to low */ + VANQ_COUNT_L_H, /* z - by count, low to high */ NUM_VANQ_ORDER_MODES }; @@ -1562,7 +1562,6 @@ struct instance_globals_v { /* end.c */ struct val_list valuables[3]; - int vanq_sortmode; /* mhitm.c */ boolean vis; diff --git a/include/extern.h b/include/extern.h index 821ef5900..a292ef146 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1092,6 +1092,7 @@ extern schar achieve_rank(int); extern boolean sokoban_in_play(void); extern int do_gamelog(void); extern void show_gamelog(int); +extern int set_vanq_order(void); extern int dovanquished(void); extern int doborn(void); extern void list_vanquished(char, boolean); diff --git a/include/flag.h b/include/flag.h index a37679590..4d150daad 100644 --- a/include/flag.h +++ b/include/flag.h @@ -87,6 +87,7 @@ struct flag { 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) */ + uchar vanq_sortmode; /* [uint_8] order of vanquished monsters: 0..7 */ char inv_order[MAXOCLASSES]; char pickup_types[MAXOCLASSES]; #define NUM_DISCLOSURE_OPTIONS 6 /* i,a,v,g,c,o (decl.c) */ diff --git a/include/optlist.h b/include/optlist.h index f163c4596..8d47ae35b 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -537,6 +537,9 @@ static int optfn_##a(int, int, boolean, char *, char *); "sort object selection lists by description") NHOPTB(sortpack, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.sortpack) + NHOPTC(sortvanquished, Advanced, 0, opt_in, set_in_game, + Yes, Yes, No, Yes, NoAlias, + "preferred order when displaying vanquished monsters") NHOPTB(sparkle, Map, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.sparkle) NHOPTB(splash_screen, Advanced, 0, opt_out, set_in_config, diff --git a/include/patchlevel.h b/include/patchlevel.h index d390a64a8..6b3ee5faf 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 66 +#define EDITLEVEL 67 /* * Development status possibilities. diff --git a/src/decl.c b/src/decl.c index 6169063c3..8362d0862 100644 --- a/src/decl.c +++ b/src/decl.c @@ -803,7 +803,6 @@ const struct instance_globals_v g_init_v = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* valset */ /* end.c */ { UNDEFINED_VALUES }, /* valuables */ - VANQ_MLVL_MNDX, /* vanq_sortmode */ /* mhitm.c */ FALSE, /* vis */ /* mklev.c */ diff --git a/src/insight.c b/src/insight.c index 4b887b492..992006796 100644 --- a/src/insight.c +++ b/src/insight.c @@ -32,7 +32,6 @@ static void weapon_insight(int); static void attributes_enlightenment(int, int); static void show_achievements(int); static int QSORTCALLBACK vanqsort_cmp(const genericptr, const genericptr); -static int set_vanq_order(void); static int num_extinct(void); extern const char *const hu_stat[]; /* hunger status from eat.c */ @@ -2486,15 +2485,23 @@ show_gamelog(int final) */ /* the two uppercase choices are implemented but suppressed from menu */ -static const char *vanqorders[NUM_VANQ_ORDER_MODES][2] = { - { "t", "traditional: by monster level, by internal monster index" }, - { "d", "by monster difficulty rating, by internal monster index" }, - { "a", "alphabetically, first unique monsters, then others" }, - { "A", "alphabetically, unique monsters and others intermixed" }, - { "C", "by monster class, high to low level within class" }, - { "c", "by monster class, low to high level within class" }, - { "n", "by count, high to low, by internal index within tied count" }, - { "z", "by count, low to high, by internal index within tied count" }, +const char *const vanqorders[NUM_VANQ_ORDER_MODES][3] = { + { "t", "traditional: by monster level", + "traditional: by monster level, by internal monster index" }, + { "d", "by monster difficulty rating", + "by monster difficulty rating, by internal monster index" }, + { "a", "alphabetically, unique monsters separate", + "alphabetically, first unique monsters, then others" }, + { "A", "alphabetically, unique monsters intermixed", + "alphabetically, unique monsters and others intermixed" }, + { "C", "by monster class, high to low level in class", + "by monster class, high to low level within class" }, + { "c", "by monster class, low to high level in class", + "by monster class, low to high level within class" }, + { "n", "by count, high to low", + "by count, high to low, by internal index within tied count" }, + { "z", "by count, low to high", + "by count, low to high, by internal index within tied count" }, }; static int QSORTCALLBACK @@ -2507,7 +2514,7 @@ vanqsort_cmp( const char *name1, *name2, *punct; schar mcls1, mcls2; - switch (gv.vanq_sortmode) { + switch (flags.vanq_sortmode) { default: case VANQ_MLVL_MNDX: /* sort by monster level */ @@ -2564,7 +2571,7 @@ vanqsort_cmp( mlev1 = mons[indx1].mlevel; mlev2 = mons[indx2].mlevel; res = mlev1 - mlev2; /* mlevel low to high */ - if (gv.vanq_sortmode == VANQ_MCLS_HTOL) + if (flags.vanq_sortmode == VANQ_MCLS_HTOL) res = -res; /* mlevel high to low */ } break; @@ -2573,7 +2580,7 @@ vanqsort_cmp( died1 = gm.mvitals[indx1].died; died2 = gm.mvitals[indx2].died; res = died2 - died1; /* dead count high to low */ - if (gv.vanq_sortmode == VANQ_COUNT_L_H) + if (flags.vanq_sortmode == VANQ_COUNT_L_H) res = -res; /* dead count low to high */ break; } @@ -2584,7 +2591,7 @@ vanqsort_cmp( } /* returns -1 if cancelled via ESC */ -static int +int set_vanq_order(void) { winid tmpwin; @@ -2601,8 +2608,8 @@ set_vanq_order(void) continue; any.a_int = i + 1; add_menu(tmpwin, &nul_glyphinfo, &any, *vanqorders[i][0], 0, - ATR_NONE, clr, vanqorders[i][1], - (i == gv.vanq_sortmode) ? MENU_ITEMFLAGS_SELECTED + ATR_NONE, clr, vanqorders[i][2], + (i == flags.vanq_sortmode) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); } end_menu(tmpwin, "Sort order for vanquished monster counts"); @@ -2612,12 +2619,12 @@ set_vanq_order(void) if (n > 0) { choice = selected[0].item.a_int - 1; /* skip preselected entry if we have more than one item chosen */ - if (n > 1 && choice == gv.vanq_sortmode) + if (n > 1 && choice == flags.vanq_sortmode) choice = selected[1].item.a_int - 1; free((genericptr_t) selected); - gv.vanq_sortmode = choice; + flags.vanq_sortmode = choice; } - return (n < 0) ? -1 : gv.vanq_sortmode; + return (n < 0) ? -1 : flags.vanq_sortmode; } /* #vanquished command */ @@ -2709,7 +2716,7 @@ list_vanquished(char defquery, boolean ask) c = ask ? yn_function( "Do you want an account of creatures vanquished?", - ynaqchars, defquery, TRUE) + ynaqchars, defquery, TRUE) : defquery; if (c == 'q') done_stopprint++; @@ -2720,9 +2727,9 @@ list_vanquished(char defquery, boolean ask) if (set_vanq_order() < 0) return; } - uniq_header = (gv.vanq_sortmode == VANQ_ALPHA_SEP); - class_header = ((gv.vanq_sortmode == VANQ_MCLS_LTOH - || gv.vanq_sortmode == VANQ_MCLS_HTOL) + uniq_header = (flags.vanq_sortmode == VANQ_ALPHA_SEP); + class_header = ((flags.vanq_sortmode == VANQ_MCLS_LTOH + || flags.vanq_sortmode == VANQ_MCLS_HTOL) && ntypes > 1); klwin = create_nhwindow(NHW_MENU); @@ -2795,7 +2802,16 @@ list_vanquished(char defquery, boolean ask) display_nhwindow(klwin, TRUE); destroy_nhwindow(klwin); } - } else if (defquery == 'a') { + + /* + * For end-of-game disclosure, we're only called when some monsters + * were vanquished and won't reach these 'else-if's. + * + * If no monsters have been vanquished, we're either called for game + * still in progress, so use present tense via pline(), or for dumplog + * which needs putstr() and past tense. + */ + } else if (!gp.program_state.gameover) { /* #dovanquished rather than final disclosure, so pline() is ok */ pline("No creatures have been vanquished."); #ifdef DUMPLOG diff --git a/src/options.c b/src/options.c index 16f6db2f9..11d294066 100644 --- a/src/options.c +++ b/src/options.c @@ -3460,8 +3460,10 @@ optfn_sortdiscoveries( } static int -optfn_sortloot(int optidx, int req, boolean negated UNUSED, - char *opts, char *op) +optfn_sortloot( + int optidx, int req, + boolean negated UNUSED, + char *opts, char *op) { int i; @@ -3504,6 +3506,62 @@ optfn_sortloot(int optidx, int req, boolean negated UNUSED, return optn_ok; } +static int +optfn_sortvanquished( + int optidx, int req, + boolean negated, + char *opts, char *op) +{ + extern const char *const vanqorders[][3]; /* insight.c */ + static const char vanqmodes[] = "tdaACcnz"; + const char *optname = allopt[optidx].name; + + if (req == do_init) { + flags.vanq_sortmode = VANQ_MLVL_MNDX; /* 0 => 't' */ + return optn_ok; + } + if (req == do_set) { + op = string_for_env_opt(allopt[optidx].name, opts, FALSE); + if (negated) { + flags.vanq_sortmode = VANQ_MLVL_MNDX; /* 0 => 't' */ + } else if (op != empty_optstr) { + const char *p; + int vndx = 0; + + if ((p = strchr(vanqmodes, *op)) != 0) { + vndx = (int) (p - vanqmodes); + } else if (strchr("01234567", *op)) { + vndx = *op - '0'; + } else { + config_error_add("Unknown %s parameter '%s'", optname, op); + return optn_silenterr; + } + flags.vanq_sortmode = (uchar) vndx; + } else + return optn_err; + return optn_ok; + } + if (req == get_val || req == get_cnf_val) { + Strcpy(opts, vanqorders[flags.vanq_sortmode][0]); + if (req == get_val) + Sprintf(eos(opts), ": %s", vanqorders[flags.vanq_sortmode][1]); + return optn_ok; + } + if (req == do_handler) { + uchar prev_sortmode = flags.vanq_sortmode; + + /* return handler_sortvanquished(); */ + (void) set_vanq_order(); /* insight.c */ + pline("'%s' %s \"%s: %s\".", optname, + (flags.vanq_sortmode == prev_sortmode) + ? "not changed, still" + : "changed to", + vanqorders[flags.vanq_sortmode][0], + vanqorders[flags.vanq_sortmode][1]); + } + return optn_ok; +} + static int optfn_statushilites( int optidx UNUSED,