complicate #vanquished monsters processing...

...to make it more interesting.  Using #vanquished in wizard mode
or answering 'a' to the "disclose vanquished monsters?" prompt will
put up a menu to choose how the list of vanquished monsters should
be ordered.  Right now there are 6 choices:

  Traditional: by monster level, by internal index within level;
  by monster toughness, by internal index within monstr[] rating;
  alphabetically, first unique monsters, then others;
  by monster class, low to high level within class;
  by count, high to low, by internal index within tied count;
  by count, low to high, by internal index within tied count.

Two other orderings are implemented but suppressed from the menu
since they seemed uninteresting (alphabetical with uniques
intermixed with other monsters, and by-class high to low within
class).  The first two are very similar to each other and one of
them should probably be discarded too.  The by-class order(s) have
class-name separator lines between classes.

Options parsing for end of game disclosure has extended current
  +v (always show vanquished monsters)
  -v (never show vanquished monsters)
  yv (prompt about them, with default response 'y')
  nv (prompt about them, with default response 'n')
to include
  #v (always show vanquished monsters and choose the ordering)
  ?v (prompt about them, with default response 'a' to choose ordering)

The 'a' response was picked because it's easy to use ynaq()
instead of ynq(), but it can be considered to mean "ask about sort
order".  (Neither of the two new option values could be "av"; 'a'
for disclosing attributes would become ambiguous.)

+v or answering 'y' for any of yv, nv, or ?v uses the most recent
sort ordering (if #vanquished has been used in wizard mode) or the
traditional one (normal mode, or #vanquished not used).  Players
will probably want to specify a default order and then use +v
rather than choose the final order from a menu.  That hasn't been
implemented here.  Count high to low might be a better default than
level high to low.

While looking through Guidebook.tex to try to determine whether
the new text needed special handling, I spotted multiple mistakes
in the existing text.  Probably all from earlier updates of mine;
this attempts to fix them.  As usual of late, Guidebook.mn has been
tested and Guidebook.tex hasn't.
This commit is contained in:
PatR
2016-05-03 01:12:32 -07:00
parent a952162a7b
commit b98427955c
6 changed files with 241 additions and 31 deletions

View File

@@ -2140,6 +2140,20 @@ lets you refine how it behaves. Here are the valid prefixes:
.CC - "do not disclose it and do not prompt."
.ei
.ed
The listing of vanquished monsters can be sorted,
so there are two additional choices for `v':
.sd
.si
.CC ? "prompt you and default to ask on the prompt;"
.CC # "disclose it without prompting, ask for sort order."
.ei
.ed
Asking refers to picking one of the orderings from a menu.
The `+' disclose without prompting choice,
or being prompted and answering `y' rather than `a',
will default to showing monsters in the traditional order,
from high level to low level.
.lp ""
Omitted categories are implicitly added with `n' prefix.
Specified categories with omitted prefix implicitly use `+' prefix.
Order of the disclosure categories does not matter, program display for

View File

@@ -636,7 +636,7 @@ will give a brief reminder about how it works.
If the
{\it autodescribe\/}
option is on, a short description of what you see at each location is
shown as you move the cursor. Typing `{\tt #}' while picking a location will
shown as you move the cursor. Typing `{\tt \#}' while picking a location will
toggle that option on or off.
The
{\it whatis\verb+_+coord\/}
@@ -953,10 +953,11 @@ the exchange still takes place.
\item[\tb{X}]
Toggle two-weapon combat, if your character can do it. Also available
via the ``{\tt \#twoweapon}'' extended command.\\
+.lp ""
+(In versions prior to 3.6 this was the command to switch from normal
+play to ``explore mode'', also known as ``discovery mode'', which has now
+been moved to ``{\tt \#explore}''.)
%.lp ""
(In versions prior to 3.6 this was the command to switch from normal
play to ``explore mode'', also known as ``discovery mode'', which has now
been moved to ``{\tt \#explore}''.)
%.lp
\item[\tb{\^{}X}]
Display basic information about your character.\\
@@ -2569,6 +2570,22 @@ lets you refine how it behaves. Here are the valid prefixes:
%.ei
%.ed
The listing of vanquished monsters can be sorted,
so there are two additional choices for `{\tt v}':
%.sd
%.si
{\tt ?} --- prompt you and default to ask on the prompt;\\
{\tt\#} --- disclose it without prompting, ask for sort order.
%.ei
%.ed
Asking refers to picking one of the orderings from a menu.
The `{\tt +}' disclose without prompting choice,
or being prompted and answering `{\tt y}' rather than `{\tt a}',
will default to showing monsters in the traditional order,
from high level to low level.
.lp ""
%.lp ""
(ex.\ ``{\tt disclose:yi na +v -g o}'')
The example sets
@@ -3083,15 +3100,15 @@ The possibile settings are:
%.sd
%.si
{\tt c} --- \verb#compass ('east' or '3s' or '2n,4w')#;
{\tt m} --- \verb#map <x,y> (map column x=0 is not used)#;
{\tt s} --- \verb#screen [row,column] (row is offset to match tty usage)#;
{\tt c} --- \verb#compass ('east' or '3s' or '2n,4w')#;\\
{\tt m} --- \verb#map <x,y> (map column x=0 is not used)#;\\
{\tt s} --- \verb#screen [row,column] (row is offset to match tty usage)#;\\
{\tt n} --- \verb#none (no coordinates shown) [default]#.
%.ei
%.ed
%.lp ""
+The
The
{\it whatis\verb+_+coord\/}
option is also used with
the `{\tt /m}', `{\tt /M}', `{\tt /o}', and `{\tt /O}' sub-commands

View File

@@ -323,6 +323,8 @@ extend wizard-mode '#stats' command
stack and leave 1 wielded, otherwise it requires confirmation
'Q' will accept an item count to manually split a stack as part of it being
quivered, provided the stack isn't already in the quiver slot
during end of game disclosure, the vanquished monsters list can be sorted in
one of several ways by answering 'a' to "disclose vanquished monsters?"
Platform- and/or Interface-Specific New Features

View File

@@ -76,8 +76,10 @@ struct flag {
#define NUM_DISCLOSURE_OPTIONS 6 /* i,a,v,g,c,o (decl.c) */
#define DISCLOSE_PROMPT_DEFAULT_YES 'y'
#define DISCLOSE_PROMPT_DEFAULT_NO 'n'
#define DISCLOSE_PROMPT_DEFAULT_SPECIAL '?' /* v, default a */
#define DISCLOSE_YES_WITHOUT_PROMPT '+'
#define DISCLOSE_NO_WITHOUT_PROMPT '-'
#define DISCLOSE_SPECIAL_WITHOUT_PROMPT '#' /* v, use a */
char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various
info upon exit */
char menu_style; /* User interface style setting */

170
src/end.c
View File

@@ -52,6 +52,7 @@ STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
STATIC_DCL void FDECL(savelife, (int));
STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
const genericptr));
STATIC_DCL void NDECL(set_vanq_order);
STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *));
@@ -629,7 +630,7 @@ int category;
char *defquery;
{
int idx;
char *dop;
char disclose, *dop;
*defquery = 'n';
if ((dop = index(disclosure_options, category)) != 0) {
@@ -641,15 +642,22 @@ char *defquery;
*defquery = DISCLOSE_PROMPT_DEFAULT_YES;
return TRUE;
}
if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
disclose = flags.end_disclose[idx];
if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
*defquery = 'y';
return FALSE;
} else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
} else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
*defquery = 'a';
return FALSE;
} else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
*defquery = 'n';
return FALSE;
} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
} else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
*defquery = 'y';
return TRUE;
} else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
*defquery = 'a';
return TRUE;
} else {
*defquery = 'n';
return TRUE;
@@ -1426,23 +1434,140 @@ int status;
nethack_exit(status);
}
extern const int monstr[];
static const char *vanqorders[] = {
"traditional: by monster level, by internal monster index",
#define VANQ_MLVL_MNDX 0
"by monster toughness, by internal monster index",
#define VANQ_MSTR_MNDX 1
"alphabetically, first unique monsters, then others",
#define VANQ_ALPHA_SEP 2
"alphabetically, unique monsters and others intermixed",
#define VANQ_ALPHA_MIX 3
"by monster class, high to low level within class",
#define VANQ_MCLS_HTOL 4
"by monster class, low to high level within class",
#define VANQ_MCLS_LTOH 5
"by count, high to low, by internal index within tied count",
#define VANQ_COUNT_H_L 6
"by count, low to high, by internal index within tied count",
#define VANQ_COUNT_L_H 7
};
static int vanq_sortmode = VANQ_MLVL_MNDX;
STATIC_PTR int CFDECLSPEC
vanqsort_cmp(vptr1, vptr2)
const genericptr vptr1;
const genericptr vptr2;
{
int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel,
res;
mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
const char *name1, *name2, *punct;
schar mcls1, mcls2;
/* sort by monster level */
res = mlev2 - mlev1; /* mlevel high to low */
switch (vanq_sortmode) {
default:
case VANQ_MLVL_MNDX:
/* sort by monster level */
mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
res = mlev2 - mlev1; /* mlevel high to low */
break;
case VANQ_MSTR_MNDX:
/* sort by monster toughness */
mstr1 = monstr[indx1], mstr2 = monstr[indx2];
res = mstr2 - mstr1; /* monstr high to low */
break;
case VANQ_ALPHA_SEP:
uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
res = uniq2 - uniq1;
break;
} /* else both unique or neither unique */
/*FALLTHRU*/
case VANQ_ALPHA_MIX:
name1 = mons[indx1].mname, name2 = mons[indx2].mname;
res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
break;
case VANQ_MCLS_HTOL:
case VANQ_MCLS_LTOH:
/* mons[].mlet is a small integer, 1..N, of type plain char;
if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
an inappropriate result when mlet2 is greater than mlet1,
so force our copies (mcls1, mcls2) to be signed */
mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
/* S_ANT through S_ZRUTY correspond to lowercase monster classes,
S_ANGEL through S_ZOMBIE correspond to uppercase, and various
punctuation characters are used for classes beyond those */
if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
/* force a specific order to the punctuation classes that's
different from the internal order;
internal order is ok if neither or just one is punctuation
since letters have lower values so come out before punct */
static const char punctclasses[] = {
S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
};
if ((punct = index(punctclasses, mcls1)) != 0)
mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
if ((punct = index(punctclasses, mcls2)) != 0)
mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
}
res = mcls1 - mcls2; /* class */
if (res == 0) {
mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
res = mlev1 - mlev2; /* mlevel low to high */
if (vanq_sortmode == VANQ_MCLS_HTOL)
res = -res; /* mlevel high to low */
}
break;
case VANQ_COUNT_H_L:
case VANQ_COUNT_L_H:
died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
res = died2 - died1; /* dead count high to low */
if (vanq_sortmode == VANQ_COUNT_L_H)
res = -res; /* dead count low to high */
break;
}
/* tiebreaker: internal mons[] index */
if (res == 0)
res = indx1 - indx2; /* tiebreaker, mons[] index low to high */
res = indx1 - indx2; /* mndx low to high */
return res;
}
STATIC_OVL void
set_vanq_order()
{
winid tmpwin;
menu_item *selected;
anything any;
int i, n, choice;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any = zeroany; /* zero out all bits */
for (i = 0; i < SIZE(vanqorders); i++) {
if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
continue;
any.a_int = i + 1;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
(i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
}
end_menu(tmpwin, "Sort order for vanquished monster counts");
n = select_menu(tmpwin, PICK_ONE, &selected);
destroy_nhwindow(tmpwin);
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 == vanq_sortmode)
choice = selected[1].item.a_int - 1;
free((genericptr_t) selected);
vanq_sortmode = choice;
}
}
/* #vanquished command */
int
dovanquished()
@@ -1477,9 +1602,12 @@ boolean ask;
* includes all dead monsters, not just those killed by the player
*/
if (ntypes != 0) {
char mlet, prev_mlet = 0; /* used as small integer, not character */
boolean class_header, uniq_header, was_uniq = FALSE;
c = ask ? yn_function(
"Do you want an account of creatures vanquished?",
ynqchars, defquery)
ynaqchars, defquery)
: defquery;
if (c == 'q')
done_stopprint++;
@@ -1488,10 +1616,23 @@ boolean ask;
putstr(klwin, 0, "Vanquished creatures:");
putstr(klwin, 0, "");
if (c == 'a')
set_vanq_order(); /* menu to choose value for vanq_sortmode */
uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
class_header = (vanq_sortmode == VANQ_MCLS_LTOH
|| vanq_sortmode == VANQ_MCLS_HTOL);
qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
for (ni = 0; ni < ntypes; ni++) {
i = mindx[ni];
nkilled = mvitals[i].died;
mlet = mons[i].mlet;
if (class_header && mlet != prev_mlet) {
Strcpy(buf, def_monsyms[(int) mlet].explain);
putstr(klwin, ask ? 0 : iflags.menu_headings,
upstart(buf));
prev_mlet = mlet;
}
if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
Sprintf(buf, "%s%s",
!type_is_pname(&mons[i]) ? "the " : "",
@@ -1509,7 +1650,12 @@ boolean ask;
break;
}
}
was_uniq = TRUE;
} else {
if (uniq_header && was_uniq) {
putstr(klwin, 0, "");
was_uniq = FALSE;
}
/* trolls or undead might have come back,
but we don't keep track of that */
if (nkilled == 1)
@@ -1523,6 +1669,8 @@ boolean ask;
: !strncmpi(buf, "an ", 3) ? 1
: !strncmpi(buf, "a ", 2) ? 2
: !isdigit(buf[2]) ? 4 : 0;
if (class_header)
++pfx;
Sprintf(buftoo, "%*s%s", pfx, "", buf);
putstr(klwin, 0, buftoo);
}

View File

@@ -2815,7 +2815,9 @@ boolean tinitial, tfrom_file;
while (*op && num < sizeof flags.end_disclose - 1) {
static char valid_settings[] = {
DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0'
DISCLOSE_PROMPT_DEFAULT_SPECIAL,
DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT,
DISCLOSE_SPECIAL_WITHOUT_PROMPT, '\0'
};
register char c, *dop;
@@ -2832,6 +2834,12 @@ boolean tinitial, tfrom_file;
continue;
}
if (prefix_val != -1) {
if (*dop != 'v') {
if (prefix_val == DISCLOSE_PROMPT_DEFAULT_SPECIAL)
prefix_val = DISCLOSE_PROMPT_DEFAULT_YES;
if (prefix_val == DISCLOSE_SPECIAL_WITHOUT_PROMPT)
prefix_val = DISCLOSE_YES_WITHOUT_PROMPT;
}
flags.end_disclose[idx] = prefix_val;
prefix_val = -1;
} else
@@ -4016,6 +4024,7 @@ boolean setinitial, setfromfile;
};
int disc_cat[NUM_DISCLOSURE_OPTIONS];
int pick_cnt, pick_idx, opt_idx;
char c;
menu_item *disclosure_pick = (menu_item *) 0;
tmpwin = create_nhwindow(NHW_MENU);
@@ -4043,6 +4052,7 @@ boolean setinitial, setfromfile;
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
if (disc_cat[i]) {
c = flags.end_disclose[i];
Sprintf(buf, "Disclosure options for %s:",
disclosure_names[i]);
tmpwin = create_nhwindow(NHW_MENU);
@@ -4050,24 +4060,41 @@ boolean setinitial, setfromfile;
any = zeroany;
/* 'y','n',and '+' work as alternate selectors; '-' doesn't */
any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
add_menu(tmpwin, NO_GLYPH, &any, 'a', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Never disclose, without prompting",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
add_menu(tmpwin, NO_GLYPH, &any, 'b', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Always disclose, without prompting",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
if (*disclosure_names[i] == 'v') {
any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Always disclose, pick sort order from menu",
(c == any.a_char) ? MENU_SELECTED
: MENU_UNSELECTED);
}
any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
add_menu(tmpwin, NO_GLYPH, &any, 'c', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"No\"",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
add_menu(tmpwin, NO_GLYPH, &any, 'd', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"Yes\"",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
if (*disclosure_names[i] == 'v') {
any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"Ask\" to request sort menu",
(c == any.a_char) ? MENU_SELECTED
: MENU_UNSELECTED);
}
end_menu(tmpwin, buf);
if (select_menu(tmpwin, PICK_ONE, &disclosure_pick) > 0) {
flags.end_disclose[i] = disclosure_pick->item.a_char;
n = select_menu(tmpwin, PICK_ONE, &disclosure_pick);
if (n > 0) {
flags.end_disclose[i] = disclosure_pick[0].item.a_char;
if (n > 1 && flags.end_disclose[i] == c)
flags.end_disclose[i] = disclosure_pick[1].item.a_char;
free((genericptr_t) disclosure_pick);
}
destroy_nhwindow(tmpwin);