last? role/race/&c option values update

Keep track of how a role|race|gender|alignment option got its value
so that role:!Tourist in .nethackrc and role:!Priest in NETHACKOPTIONS
yield 'role:!Priest' rather than merging into 'role:!Priest !Tourist'.
It also doesn't write the value into new config file for #saveoptions
if that value comes from environment or command line (not applicable
since the command line arguments for role,&c don't go through options
handling).  Also, the old config file value takes precedence over
the current game's value file so that 'role:random' doesn't become
'role:Healer' or such in a new config after the random value gets
picked for play.

This only tracks the role, race, gender, and alignment options but the
concept could be extended to all options.  The data would need to be
saved and restored if values set interactively need to be retained in
restore sessions (doesn't apply to role,&c since those don't change
during play).
This commit is contained in:
PatR
2022-12-22 15:07:33 -08:00
parent 37f6eee147
commit 91e2ab13b2
7 changed files with 397 additions and 85 deletions

View File

@@ -1278,7 +1278,7 @@ struct instance_globals_o {
/* options.c */
/* options processing */
int opt_phase; /* builtin_opt, syscf_, rc_file_, environ_, play_opt */
boolean opt_initial;
boolean opt_from_file;
boolean opt_need_redraw; /* for doset() */

View File

@@ -1992,6 +1992,7 @@ extern void initoptions(void);
extern void initoptions_init(void);
extern void initoptions_finish(void);
extern boolean parseoptions(char *, boolean, boolean);
extern void freeroleoptvals(void);
extern char *get_option_value(const char *, boolean);
extern int doset_simple(void);
extern int doset(void);
@@ -2410,7 +2411,8 @@ extern int pick_align(int, int, int, int);
extern void rigid_role_checks(void);
extern boolean setrolefilter(const char *);
extern boolean gotrolefilter(void);
extern void clearrolefilter(void);
extern char *rolefilterstring(char *, int);
extern void clearrolefilter(int);
extern char *root_plselection_prompt(char *, int, int, int, int, int);
extern char *build_plselection_prompt(char *, int, int, int, int, int);
extern void plnamesuffix(void);

View File

@@ -115,16 +115,16 @@ static int optfn_##a(int, int, boolean, char *, char *);
No, Yes, No, No, NoAlias,
"your character's name (e.g., name:Merlin-W)")
NHOPTC(role, Advanced, PL_CSIZ, opt_in, set_gameview,
Yes, Yes, No, No, "character",
Yes, Yes, Yes, No, "character",
"your starting role (e.g., Barbarian, Valkyrie)")
NHOPTC(race, Advanced, PL_CSIZ, opt_in, set_gameview,
Yes, Yes, No, No, NoAlias,
Yes, Yes, Yes, No, NoAlias,
"your starting race (e.g., Human, Elf)")
NHOPTC(gender, Advanced, 8, opt_in, set_gameview,
Yes, Yes, No, No, NoAlias,
Yes, Yes, Yes, No, NoAlias,
"your starting gender (male or female)")
NHOPTC(alignment, Advanced, 8, opt_in, set_gameview,
Yes, Yes, No, No, "align",
Yes, Yes, Yes, No, "align",
"your starting alignment (lawful, neutral, or chaotic)")
/* end of special ordering; remainder of entries are in alphabetical order
*/

View File

@@ -596,6 +596,7 @@ const struct instance_globals_o g_init_o = {
/* o_init.c */
DUMMY, /* oclass_prob_totals */
/* options.c */
0, /* opt_phase */
FALSE, /* opt_initial */
FALSE, /* opt_from_file */
FALSE, /* opt_need_redraw */

View File

@@ -85,8 +85,22 @@ enum window_option_types {
TEXT_OPTION
};
enum {optn_silenterr = -1, optn_err = 0, optn_ok};
enum requests {do_nothing, do_init, do_set, do_handler, get_val, get_cnf_val};
enum optn_result {
optn_silenterr = -1, optn_err = 0, optn_ok
};
enum requests {
do_nothing, do_init, do_set, do_handler, get_val, get_cnf_val
};
/* these aren't the same as set_xxx in optlist.h */
enum option_phases {
builtin_opt, /* compiled-in default value of an option */
syscf_opt, /* sysconf setting of an option, overrides builtin */
rc_file_opt, /* player's run-time config file setting, overrides syscf */
environ_opt, /* player's environment NETHACKOPTIONS, overrides rc_file */
cmdline_opt, /* program invocation command-line, overrides environ */
play_opt, /* 'O' command, interactively set so overrides all */
num_opt_phases
};
static struct allopt_t allopt[SIZE(allopt_init)];
@@ -105,10 +119,11 @@ extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
#endif
static char empty_optstr[] = { '\0' };
boolean duplicate, using_alias;
static boolean duplicate, using_alias;
static boolean give_opt_msg = TRUE;
static boolean opt_set_in_config[OPTCOUNT];
static char *roleoptvals[4][num_opt_phases]; /* 4: role,race,gend,algn */
static NEARDATA const char *OptS_type[OptS_Advanced+1] = {
"General", "Behavior", "Map", "Status", "Advanced"
@@ -281,6 +296,10 @@ static void complain_about_duplicate(int);
static int length_without_val(const char *, int len);
static void determine_ambiguities(void);
static int check_misc_menu_command(char *, char *);
static int opt2roleopt(int);
static char *getoptstr(int, int);
static void saveoptstr(int, const char *);
static void unsaveoptstr(int, int);
static int shared_menu_optfn(int, int, boolean, char *, char *);
static int spcfn_misc_menu_cmd(int, int, boolean, char *, char *);
@@ -295,7 +314,8 @@ static boolean test_regex_pattern(const char *, const char *);
static boolean add_menu_coloring_parsed(const char *, int, int);
static void free_one_menu_coloring(int);
static int count_menucolors(void);
static boolean parse_role_opts(int, boolean, const char *, char *, char **);
static boolean parse_role_opt(int, boolean, const char *, char *, char **);
static char *get_cnf_role_opt(int);
static unsigned int longest_option_name(int, int);
static int doset_simple_menu(void);
static void doset_add_menu(winid, const char *, const char *, int, int);
@@ -396,10 +416,7 @@ parseoptions(
}
negated = FALSE;
while ((*opts == '!') || !strncmpi(opts, "no", 2)) {
if (*opts == '!')
opts++;
else
opts += 2;
opts += (*opts == '!') ? 1 : (opts[2] != '-') ? 2 : 3;
negated = !negated;
}
optlen = (int) strlen(opts);
@@ -566,6 +583,141 @@ check_misc_menu_command(char *opts, char *op UNUSED)
return -1;
}
static int roleopt2opt[4] = {
opt_role, opt_race, opt_gender, opt_alignment
};
/* role => 0, race => 1, gender => 2, alignment =>3 */
static int
opt2roleopt(int roleopt)
{
switch (roleopt) {
case opt_role:
return 0;
case opt_race:
return 1;
case opt_gender:
return 2;
case opt_alignment:
return 3;
default:
break;
}
return 0;
}
/* fetch saved option string for a particular option phase */
static char *
getoptstr(int optidx, int ophase)
{
int roleoptindx = opt2roleopt(optidx);
if (ophase == num_opt_phases) { /* any source */
int phase;
/* find non-Null, in order optvals[][play_opt], [cmdline_opt],
[environ_opt], [rc_file_opt], [syscf_opt], [builtin_opt] */
for (phase = num_opt_phases; phase >= 0; --phase)
if (roleoptvals[roleoptindx][phase]) {
ophase = phase;
break;
}
}
return roleoptvals[roleoptindx][ophase];
}
/* to track some unparsed option settings in case #saveoptions needs them */
static void
saveoptstr(int optidx, const char *optstr)
{
int phase = go.opt_phase, roleoptindx = opt2roleopt(optidx);
const char *p = strchr(optstr, ':'), *q = strchr(optstr, '=');
/* strip away "optname:" from optname:optstr */
if (!p || (q && q < p))
p = q;
if (p)
optstr = p + 1;
if (roleoptvals[roleoptindx][phase])
free((genericptr_t) roleoptvals[roleoptindx][phase]);
roleoptvals[roleoptindx][phase] = dupstr(optstr);
}
/* discard specific saved option string */
static void
unsaveoptstr(int optidx, int ophase)
{
int roleoptindx = opt2roleopt(optidx);
if (roleoptvals[roleoptindx][ophase])
free((genericptr_t) roleoptvals[roleoptindx][ophase]),
roleoptvals[roleoptindx][ophase] = 0;
}
/* discard all saved option strings */
void
freeroleoptvals(void)
{
int i, j;
for (i = 0; i < 4; ++i)
for (j = 0; j < num_opt_phases; ++j)
unsaveoptstr(roleopt2opt[i], j);
}
#if 0 /* not needed */
/* put roleoptvals[][] into save file; will be needed if #saveoptions
takes place after restore */
void
saveoptvals(NHFILE *nhfp)
{
if (perform_bwrite(nhfp)) {
char *val;
unsigned len;
int i, j;
for (i = 0; i < 4; ++i)
for (j = 0; j < num_opt_phases; ++j) {
val = roleoptvals[i][j];
len = val ? Strlen(val) + 1 : 0;
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &len, sizeof len);
if (val)
bwrite(nhfp->fd, (genericptr_t) val, len);
}
}
}
if (release_data(nhfp))
freeroleoptvals();
}
/* get roleoptvals[][] from save file */
void
restoptvals(NHFILE *nhfp)
{
char *val;
unsigned len;
int i, j;
if (nhfp->structlevel) {
for (i = 0; i < 4; ++i)
for (j = 0; j < num_opt_phases; ++j) {
/* len includes terminating '\0' for non-Null values */
mread(nhfp->fd, (genericptr_t) &len, sizeof len);
if (len) {
val = roleoptvals[i][j] = (char *) alloc(len);
mread(nhfp->fd, (genericptr_t) val, len);
} else {
roleoptvals[i][j] = NULL;
}
}
}
}
#endif /* 0 */
/*
**********************************
*
@@ -586,21 +738,30 @@ optfn_alignment(
return optn_ok;
}
if (req == do_set) {
if (parse_role_opts(optidx, negated, allopt[optidx].name, opts, &op)) {
/* alignment:string */
if (!parse_role_opt(optidx, negated, allopt[optidx].name, opts, &op))
return optn_silenterr;
if (*op != '!') {
if ((flags.initalign = str2align(op)) == ROLE_NONE) {
config_error_add("Unknown %s '%s'", allopt[optidx].name, op);
return optn_err;
}
} else
return optn_silenterr;
saveoptstr(optidx, rolestring(flags.initalign, aligns, adj));
}
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (req == get_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", rolestring(flags.initalign, aligns, adj));
return optn_ok;
}
if (req == get_cnf_val) {
op = get_cnf_role_opt(optidx);
Strcpy(opts, op ? op : "none");
return optn_ok;
}
return optn_ok;
}
@@ -1423,29 +1584,42 @@ optfn_fruit(int optidx UNUSED, int req, boolean negated,
}
static int
optfn_gender(int optidx, int req, boolean negated, char *opts, char *op)
optfn_gender(
int optidx,
int req,
boolean negated,
char *opts,
char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
/* gender:string */
if (parse_role_opts(optidx, negated, allopt[optidx].name, opts, &op)) {
if (!parse_role_opt(optidx, negated, allopt[optidx].name, opts, &op))
return optn_silenterr;
if (*op != '!') {
if ((flags.initgend = str2gend(op)) == ROLE_NONE) {
config_error_add("Unknown %s '%s'", allopt[optidx].name, op);
return optn_err;
} else
flags.female = flags.initgend;
} else
return optn_silenterr;
}
flags.female = flags.initgend;
saveoptstr(optidx, rolestring(flags.initgend, genders, adj));
}
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (req == get_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", rolestring(flags.initgend, genders, adj));
return optn_ok;
}
if (req == get_cnf_val) {
op = get_cnf_role_opt(optidx);
Strcpy(opts, op ? op : "none");
return optn_ok;
}
return optn_ok;
}
@@ -2906,29 +3080,42 @@ optfn_playmode(int optidx, int req, boolean negated, char *opts, char *op)
}
static int
optfn_race(int optidx, int req, boolean negated, char *opts, char *op)
optfn_race(
int optidx,
int req,
boolean negated,
char *opts,
char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
/* race:string */
if (parse_role_opts(optidx, negated, allopt[optidx].name, opts, &op)) {
if (!parse_role_opt(optidx, negated, allopt[optidx].name, opts, &op))
return optn_silenterr;
if (*op != '!') {
if ((flags.initrace = str2race(op)) == ROLE_NONE) {
config_error_add("Unknown %s '%s'", allopt[optidx].name, op);
return optn_err;
} else /* Backwards compatibility */
gp.pl_race = *op;
} else
return optn_silenterr;
}
gp.pl_race = *op; /* Backwards compatibility */
saveoptstr(optidx, rolestring(flags.initrace, races, noun));
}
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (req == get_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", rolestring(flags.initrace, races, noun));
return optn_ok;
}
if (req == get_cnf_val) {
op = get_cnf_role_opt(optidx);
Strcpy(opts, op ? op : "none");
return optn_ok;
}
return optn_ok;
}
@@ -2961,7 +3148,8 @@ optfn_roguesymset(int optidx, int req, boolean negated UNUSED,
if (!opts)
return optn_err;
Sprintf(opts, "%s",
gs.symset[ROGUESET].name ? gs.symset[ROGUESET].name : "default");
gs.symset[ROGUESET].name ? gs.symset[ROGUESET].name
: "default");
if (gc.currentgraphics == ROGUESET && gs.symset[ROGUESET].name)
Strcat(opts, ", active");
return optn_ok;
@@ -2973,28 +3161,42 @@ optfn_roguesymset(int optidx, int req, boolean negated UNUSED,
}
static int
optfn_role(int optidx, int req, boolean negated, char *opts, char *op)
optfn_role(
int optidx,
int req,
boolean negated,
char *opts,
char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
if (parse_role_opts(optidx, negated, allopt[optidx].name, opts, &op)) {
/* role:string */
if (!parse_role_opt(optidx, negated, allopt[optidx].name, opts, &op))
return optn_silenterr;
if (*op != '!') {
if ((flags.initrole = str2role(op)) == ROLE_NONE) {
config_error_add("Unknown %s '%s'", allopt[optidx].name, op);
return optn_err;
} else /* Backwards compatibility */
nmcpy(gp.pl_character, op, PL_NSIZ);
} else
return optn_silenterr;
}
nmcpy(gp.pl_character, op, PL_NSIZ); /* Backwards compat */
saveoptstr(optidx, rolestring(flags.initrole, roles, name.m));
}
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (req == get_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", rolestring(flags.initrole, roles, name.m));
return optn_ok;
}
if (req == get_cnf_val) {
op = get_cnf_role_opt(optidx);
Strcpy(opts, op ? op : "none");
return optn_ok;
}
return optn_ok;
}
@@ -3063,9 +3265,9 @@ optfn_scores(int optidx, int req, boolean negated, char *opts, char *op)
while (*op) {
int inum = 1;
negated = (*op == '!');
negated = (*op == '!') || !strncmpi(op, "no", 2);
if (negated)
op++;
op += (*op == '!') ? 1 : (op[2] != '-') ? 2 : 3;
if (digit(*op)) {
inum = atoi(op);
@@ -6209,11 +6411,22 @@ txt2key(char *txt)
void
initoptions(void)
{
#ifdef SYSCF_FILE
int i;
#endif
go.opt_phase = builtin_opt;
initoptions_init();
/*
* Call each option function with an init flag and give it a chance
* to make any preparations that it might require. We do this
* whether or not the option itself is ever specified; that's
* irrelevant for the init call. Doing this allows the prep code for
* option settings to remain adjacent to, and in the same function as,
* the code that processes those options.
*/
for (i = 0; i < OPTCOUNT; ++i) {
if (allopt[i].optfn)
(*allopt[i].optfn)(i, do_init, FALSE, empty_optstr, empty_optstr);
}
#ifdef SYSCF
/* someday there may be other SYSCF alternatives besides text file */
#ifdef SYSCF_FILE
@@ -6221,19 +6434,8 @@ initoptions(void)
assure_syscf_file();
config_error_init(TRUE, SYSCF_FILE, FALSE);
/* Call each option function with an init flag and give it a chance
to make any preparations that it might require. We do this
whether or not the option itself is ever specified; that's
irrelevant for the init call. Doing this allows the prep code for
option settings to remain adjacent to, and in the same function as,
the code that processes those options */
for (i = 0; i < OPTCOUNT; ++i) {
if (allopt[i].optfn)
(*allopt[i].optfn)(i, do_init, FALSE, empty_optstr, empty_optstr);
}
/* ... and _must_ parse correctly. */
go.opt_phase = syscf_opt;
if (!read_config_file(SYSCF_FILE, set_in_sysconf)) {
if (config_error_done() && !iflags.initoptions_noterminate)
nh_terminate(EXIT_FAILURE);
@@ -6284,6 +6486,7 @@ initoptions_init(void)
init_random(rn2);
init_random(rn2_on_display_rng);
go.opt_phase = builtin_opt;
for (i = 0; allopt[i].name; i++) {
if (allopt[i].addr)
*(allopt[i].addr) = allopt[i].initval;
@@ -6463,6 +6666,7 @@ initoptions_finish(void)
messages, if any were to be delivered while accessing the file,
from potentially overflowing buffers */
if (nameval && (int) strlen(nameval) >= BUFSZ / 2) {
go.opt_phase = rc_file_opt;
config_error_init(TRUE, namesrc, FALSE);
config_error_add(
"nethackrc file name \"%.40s\"... too long; using default",
@@ -6476,6 +6680,7 @@ initoptions_finish(void)
config_error_done();
if (xtraopts) {
/* NETHACKOPTIONS is present and not a file name */
go.opt_phase = environ_opt;
config_error_init(FALSE, envname, FALSE);
(void) parseoptions(xtraopts, TRUE, FALSE);
config_error_done();
@@ -6483,6 +6688,7 @@ initoptions_finish(void)
/* after .nethackrc and NETHACKOPTIONS so that cmdline takes precedence */
if (gc.cmdline_windowsys) {
go.opt_phase = cmdline_opt;
config_error_init(FALSE, "command line", FALSE);
choose_windows(gc.cmdline_windowsys);
config_error_done();
@@ -7470,15 +7676,20 @@ count_menucolors(void)
/* parse 'role' or 'race' or 'gender' or 'alignment' */
static boolean
parse_role_opts(
parse_role_opt(
int optidx,
boolean negated,
const char *fullname,
char *opts,
char **opp)
{
static char role_random[] = "random"; /* not 'const' but never modified */
char *op = *opp;
static char neg_opt[] = "!"; /* not 'const' but never modified */
char *preval, *op = *opp;
int which = (optidx == opt_role) ? RS_ROLE
: (optidx == opt_race) ? RS_RACE
: (optidx == opt_gender) ? RS_GENDER
: (optidx == opt_alignment) ? RS_ALGNMNT
: RS_filter; /* none of the above */
boolean ok = FALSE;
/*
@@ -7498,13 +7709,16 @@ parse_role_opts(
char *sp;
boolean val_negated, prev_negated = FALSE, first = TRUE;
mungspaces(op);
while (*op) {
if (*op == ' ')
++op;
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
while (*op == '!' || !strncmpi(op, "no", 2)) {
val_negated = !val_negated;
op += (*op == '!') ? 1 : (op[2] != '-') ? 2 : 3;
}
if (!*op) {
if (!*op || *op == ' ') {
config_error_add("Negated nothing for '%s'", fullname);
return FALSE;
}
@@ -7523,21 +7737,43 @@ parse_role_opts(
first = FALSE;
prev_negated = val_negated;
/* hide rest of list, if any */
sp = strchr(op, ' ');
if (sp)
*sp = '\0';
preval = getoptstr(optidx, go.opt_phase);
if (val_negated || negated) {
char negbuf[BUFSZ];
/* for negative value, clear filter if there is a prior
value from a different phase; for same phase, duplicates
are allowed and setrolefilter() merges them */
if (!preval || *preval != '!')
clearrolefilter(which);
if (!setrolefilter(op)) {
config_error_add("Invalid '%s'", fullname);
config_error_add("Invalid %s '%s'", fullname, op);
return FALSE;
}
saveoptstr(optidx, rolefilterstring(negbuf, which));
*opp = neg_opt;
} else {
if (duplicate && !allopt[optidx].dupeok)
complain_about_duplicate(optidx);
/* for positive value, allow duplicate if prior value
was a negative one or came from a different phase;
reject if prior value was positive and from same phase */
if (duplicate) {
if (preval && *preval == '!') {
complain_about_duplicate(optidx);
return FALSE;
}
}
/* save raw string value; caller will validate it and
if it's ok, replace it with canonical form */
saveoptstr(optidx, op);
*opp = op;
ok = TRUE;
/* don't return yet; value might be a list which follows
this with something else, making it invalid */
/* don't return yet; value might be a list that follows
this with something else which might make it invalid */
}
if (sp) {
@@ -7547,19 +7783,29 @@ parse_role_opts(
op += strlen(op); /* break; */
}
}
if (!ok) {
/* '!ok' without config_error_add() implies a valid negation;
in case NETHACKOPTIONS=role:!Val overrides config file
OPTIONS=role:Val we need a positive result which will yield
someting other than ROLE_NONE from str2role(),str2race(),&c */
*opp = role_random;
ok = TRUE;
}
/* '!ok' without config_error_add() implies a valid negation */
ok = TRUE;
}
return ok;
}
/* fetch a saved role|race|gender|alignment value suitable for writing into
a new run-time config file */
static char *
get_cnf_role_opt(int optidx)
{
int phase;
char *op = 0;
for (phase = num_opt_phases - 1; phase >= 0 && !op; --phase) {
if (phase == cmdline_opt || phase == environ_opt
|| phase == builtin_opt)
continue;
op = getoptstr(optidx, phase);
}
return op;
}
/* Check if character c is illegal as a menu command key */
static boolean
illegal_menu_cmd_key(uchar c)
@@ -8191,6 +8437,7 @@ doset_simple(void)
return doset();
}
go.opt_phase = play_opt;
/* select and change one option at a time, then reprocess the menu
with updated settings to offer chance for further change */
give_opt_msg = FALSE;
@@ -8241,6 +8488,7 @@ doset(void) /* changing options via menu by Per Liboriussen */
return doset_simple();
}
go.opt_phase = play_opt;
/* if we offer '?' as a choice and it is the only thing chosen,
we'll end up coming back here after showing the explanatory text */
rerun:

View File

@@ -1307,14 +1307,71 @@ gotrolefilter(void)
return FALSE;
}
void
clearrolefilter(void)
/* create a string like " !Bar !Kni" or " !chaotic" that can be
put back into an RC file by #saveoptions */
char *
rolefilterstring(char *outbuf, int which)
{
int i;
for (i = 0; i < SIZE(roles); ++i)
gr.rfilter.roles[i] = FALSE;
gr.rfilter.mask = 0;
outbuf[0] = outbuf[1] = '\0';
switch (which) {
case RS_ROLE:
for (i = 0; i < SIZE(roles); ++i) {
if (gr.rfilter.roles[i])
Sprintf(eos(outbuf), " !%.3s", roles[i].name.m);
}
break;
case RS_RACE:
for (i = 0; i < SIZE(races); ++i) {
if ((gr.rfilter.mask & races[i].selfmask) != 0)
Sprintf(eos(outbuf), " !%s", races[i].noun);
}
break;
case RS_GENDER:
for (i = 0; i < SIZE(genders); ++i) {
if ((gr.rfilter.mask & genders[i].allow) != 0)
Sprintf(eos(outbuf), " !%s", genders[i].adj);
}
break;
case RS_ALGNMNT:
for (i = 0; i < SIZE(aligns); ++i) {
if ((gr.rfilter.mask & aligns[i].allow) != 0)
Sprintf(eos(outbuf), " !%s", aligns[i].adj);
}
break;
default:
impossible("rolefilterstring: bad role aspect (%d)", which);
Strcpy(outbuf, " ?");
break;
}
/* constructed with a leading space; drop it */
return &outbuf[1];
}
void
clearrolefilter(int which)
{
int i;
switch (which) {
case RS_filter:
gr.rfilter.mask = 0; /* clear race, gender, and alignment filters */
/*FALLTHRU*/
case RS_ROLE:
for (i = 0; i < SIZE(roles); ++i)
gr.rfilter.roles[i] = FALSE;
break;
case RS_RACE:
gr.rfilter.mask &= ~ROLE_RACEMASK;
break;
case RS_GENDER:
gr.rfilter.mask &= ~ROLE_GENDMASK;
break;
case RS_ALGNMNT:
gr.rfilter.mask &= ~ROLE_ALIGNMASK;
break;
}
}
static char *
@@ -2690,7 +2747,7 @@ reset_role_filtering(void)
n = select_menu(win, PICK_ANY, &selected);
if (n >= 0) { /* n==0: clear current filters and don't set new ones */
clearrolefilter();
clearrolefilter(RS_filter);
for (i = 0; i < n; i++)
setrolefilter(selected[i].item.a_string);

View File

@@ -271,7 +271,7 @@ save_gamelog(NHFILE *nhfp)
}
static void
savegamestate(NHFILE* nhfp)
savegamestate(NHFILE *nhfp)
{
unsigned long uid;
@@ -327,14 +327,17 @@ savegamestate(NHFILE* nhfp)
save_oracles(nhfp);
if (gu.ustuck_id) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &gu.ustuck_id, sizeof gu.ustuck_id);
bwrite(nhfp->fd, (genericptr_t) &gu.ustuck_id,
sizeof gu.ustuck_id);
}
if (gu.usteed_id) {
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &gu.usteed_id, sizeof gu.usteed_id);
bwrite(nhfp->fd, (genericptr_t) &gu.usteed_id,
sizeof gu.usteed_id);
}
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) gp.pl_character, sizeof gp.pl_character);
bwrite(nhfp->fd, (genericptr_t) gp.pl_character,
sizeof gp.pl_character);
bwrite(nhfp->fd, (genericptr_t) gp.pl_fruit, sizeof gp.pl_fruit);
}
savefruitchn(nhfp);
@@ -1205,6 +1208,7 @@ freedynamicdata(void)
free_dungeons();
free_CapMons();
free_rect();
freeroleoptvals(); /* saveoptvals(&tnhfp) */
/* some pointers in iflags */
if (iflags.wc_font_map)