revise the role, race, gender, align options

Using role:!wizard to limit which roles would be candidates for
random selection didn't work as I expected.  It required a separate
option setting for role to exclude.  This implements how I thought
it worked:
|OPTIONS=role:!ranger !samurai !wizard
will exclude multiple roles with a space-separated list in a single
option setting.  It also adds support for
|OPTIONS=!role:ranger samurai wizard
to do the same thing.  (OPTIONS=!role:!ranger isn't allowed.)

I thought 'OPTIONS=role:barbarian caveman knight' could be used to
limit random selection to those choices, but that doesn't work and
I haven't attempted to implement it.

This also renames the 'align' option to 'alignment'.  That made the
truncation to 'align' become ambiguous, so it got added back as an
alias for the full name.

Guidebook.tex is lagging; I'm burned out.
This commit is contained in:
PatR
2022-12-14 13:14:54 -08:00
parent 9dbb21cfcb
commit 96f5f03287
3 changed files with 139 additions and 50 deletions

View File

@@ -3671,12 +3671,16 @@ applies only to new games.
Enable messages about what your character hears (default on).
Note that this has nothing to do with your computer's audio capabilities.
Persistent.
.lp align
Your starting alignment (align:lawful, align:neutral, or align:chaotic).
.lp alignment
Your starting alignment (\f(CRalign:lawful\fP, \f(CRalign:neutral\fP, or
\f(CRalign:chaotic\fP).
You may specify just the first letter.
The default is to randomly pick an appropriate alignment.
If you prefix the value with \(oq!\(cq or \(lqno\(rq, you will
exclude that alignment from being picked randomly.
Many roles and the non-human races restrict which alignments are allowed.
See
.op role
for a description of how to use negation to exclude choices.
.lp ""
Default is random.
Cannot be set with the \(oqO\(cq command.
Persistent.
.lp autodescribe
@@ -3877,14 +3881,21 @@ You should set this to something you find more appetizing than slime mold.
Apples, oranges, pears, bananas, and melons
already exist in NetHack, so don't use those.
.lp gender
Your starting gender (gender:male or gender:female).
Your starting gender (\f(CRgender:male\fP or \f(CRgender:female\fP).
You may specify just the first letter.
Although you can
still denote your gender using the \(lqmale\(rq and \(lqfemale\(rq
options, the \(lqgender\(rq option will take precedence.
The default is to randomly pick an appropriate gender.
If you prefix the value with \(oq!\(cq or \(lqno\(rq, you will
exclude that gender from being picked randomly.
still denote your gender using either of the deprecated
.op male
and
.op female
options, if the
.op gender
option is also present it will take precedence.
See
.op role
for a description of how to use negation to exclude choices.
.lp ""
Default is random.
Cannot be set with the \(oqO\(cq command.
Persistent.
.lp "goldX "
@@ -4287,23 +4298,50 @@ It does not affect the clairvoyance spell where pausing to examine revealed
objects or monsters is less intrusive.
Default is off. Persistent.
.lp "race "
Selects your race (for example, \(lqrace:human\(rq).
Selects your race (for example, \f(CRrace:human\fP).
Choices are \f(CRhuman\fP, \f(CRdwarf\fP, \f(CRelf\fP, \f(CRgnome\fP, and
\f(CRorc\fP but most roles restrict which of the non-human races are allowed.
See
.op role
for a description of how to use negation to exclude choices.
.lp ""
Default is random.
If you prefix the value with \(oq!\(cq or \(lqno\(rq, you will
exclude that race from being picked randomly.
Cannot be set with the \(oqO\(cq command.
Persistent.
.lp rest_on_space
Make the space bar a synonym for the \(oq.\(cq (#wait) command (default off).
Persistent.
.lp "role "
Pick your type of character (for example \(lqrole:Samurai\(rq);
synonym for \(lqcharacter\(rq.
See \(lqname\(rq for an alternate method of specifying your role.
Normally only the first letter of the value is examined; \(oqr\(cq is an
exception with \(lqRogue\(rq, \(lqRanger\(rq, and \(lqrandom\(rq values.
If you prefix the value with \(oq!\(cq or \(lqno\(rq, you will
exclude that role from being picked randomly.
Pick your type of character (for example, \f(CRrole:Samurai\fP);
synonym for
.op character.
See
.op name
for an alternate method of specifying your role.
.\" Normally only the first letter of the value is examined; \(oqr\(cq is an
.\" exception with \(lqRogue\(rq, \(lqRanger\(rq, and \(lqrandom\(rq values.
.lp ""
This option can also be used to limit selection when role is chosen
randomly.
Use a space-separated list of roles and either negate each one or negate
the option itself instead.
Negation is accomplished in the same manner as with \fIboolean options\fP,
by prefixing the option or its value(s) with \(oq!\(cq or \(lqno\(rq.
.BR 0
Examples:
.sd
.ft CR \" constant-width Roman
OPTIONS=role:!arc !bar !kni
OPTIONS=!role:arc bar kni
.ft \" revert to previous font
.ed
There can be multiple instances of the
.op role
option if they're all negations.
.\" Only one positive value is allowed, and if present, it overrides any
.\" negations.
.lp ""
Default is \f(CRrandom\fP.
Cannot be set with the \(oqO\(cq command.
Persistent.
.lp roguesymset

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,
No, Yes, No, No, "character",
Yes, Yes, No, No, "character",
"your starting role (e.g., Barbarian, Valkyrie)")
NHOPTC(race, Advanced, PL_CSIZ, opt_in, set_gameview,
No, Yes, No, No, NoAlias,
Yes, Yes, No, No, NoAlias,
"your starting race (e.g., Human, Elf)")
NHOPTC(gender, Advanced, 8, opt_in, set_gameview,
No, Yes, No, No, NoAlias,
Yes, Yes, No, No, NoAlias,
"your starting gender (male or female)")
NHOPTC(align, Advanced, 8, opt_in, set_gameview,
No, Yes, No, No, NoAlias,
NHOPTC(alignment, Advanced, 8, opt_in, set_gameview,
Yes, Yes, No, No, "align",
"your starting alignment (lawful, neutral, or chaotic)")
/* end of special ordering; remainder of entries are in alphabetical order
*/

View File

@@ -575,7 +575,12 @@ check_misc_menu_command(char *opts, char *op UNUSED)
*/
static int
optfn_align(int optidx, int req, boolean negated, char *opts, char *op)
optfn_alignment(
int optidx,
int req,
boolean negated,
char *opts,
char *op)
{
if (req == do_init) {
return optn_ok;
@@ -7463,38 +7468,84 @@ count_menucolors(void)
return count;
}
/* parse 'role' or 'race' or 'gender' or 'alignment' */
static boolean
parse_role_opts(int optidx, boolean negated, const char *fullname,
char *opts, char **opp)
parse_role_opts(
int optidx,
boolean negated,
const char *fullname,
char *opts,
char **opp)
{
char *op = *opp;
boolean ok = FALSE;
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE))
!= empty_optstr) {
boolean val_negated = FALSE;
/*
* Accepts multiple forms
* role:priest -- play as priest
* race:!orc -- any race other than orc
* role:!cav !mon -- any role other than caveman/cavewoman or monk
* !role:tour -- any role other than tourist
* !role:tou rog wiz -- any role other than tourist or rogue or wizard
* TODO: add support for
* role:arc bar kni -- only role archeologist or barbarian or knight
* Rejected:
* role:sam !val -+ invalid; need either positive or negative subset
* !role:!sam +- not a mixture of the two and not dual negation.
*/
if ((op = string_for_env_opt(fullname, opts, FALSE)) != empty_optstr) {
char *sp;
boolean val_negated, prev_negated = FALSE, first = TRUE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op)) {
config_error_add("Unknown negated parameter '%s'", op);
while (*op) {
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
val_negated = !val_negated;
op += (*op == '!') ? 1 : (op[2] != '-') ? 2 : 3;
}
if (!*op) {
config_error_add("Negated nothing for '%s'", fullname);
return FALSE;
}
} else {
if (duplicate && !allopt[optidx].dupeok)
complain_about_duplicate(optidx);
*opp = op;
return TRUE;
if (!first) {
if ((val_negated ^ prev_negated)
|| (negated && val_negated)) {
config_error_add("Invalid mixed negation for '%s%s'",
negated ? "!" : "", fullname);
return FALSE;
} else if (!negated && !val_negated) {
config_error_add(
"Multiple role values only allowed when list is negated");
return FALSE;
}
}
first = FALSE;
prev_negated = val_negated;
sp = strchr(op, ' ');
if (sp)
*sp = '\0';
if (val_negated || negated) {
if (!setrolefilter(op)) {
config_error_add("Invalid '%s'", fullname);
return FALSE;
}
} else {
if (duplicate && !allopt[optidx].dupeok)
complain_about_duplicate(optidx);
*opp = op;
ok = TRUE;
}
if (sp) {
*sp = ' ';
op = sp + 1;
} else {
op += strlen(op); /* break; */
}
}
}
return FALSE;
return ok;
}
/* Check if character c is illegal as a menu command key */