diff --git a/.travis.yml b/.travis.yml index 501c0f7df..00a6c1153 100644 --- a/.travis.yml +++ b/.travis.yml @@ -101,11 +101,12 @@ deploy: provider: releases api_key: secure: "U0Dt2CXrcG8Yi4taUCT/6AnM+0IJtdCv6IVG/2rGooUY3pZjNWE9XDM6X9ZeAmbI79aN6FPTppjUf3KbB/upYeJt+8mrjnxEk/ZTO1xXDDW8iL/DiqnczoFsMGmPsTM+Fkeak8bu0SifI7Qkx9i1N+zOyl2VdlaxGjchPfl/OJw2jcQs7rOGRfr23/rapZKTcFq+BFlxMiIHa0dXbCJ9vagdlyAeclOCtPjw1VoH/Cb/+0/Xlx2MFPncw4/1P+bO/fPantHyehh3/WCDVCnI4M7ftONpsTVRrQ+Hml89teUH9/1xXUOpbCeVghWr1rumLcQzMqLKNj2lP/gm9co2/DKpxiUPUzBfO/9Jvl1CNoEwPYQBRNb38kggDvAT4vKX38Oi5sZvumFEO4L0y7o4cW6SA4/CYIykfxOdkrryt8ltfWwopdy3I/DothYw31vJ9GsZOCAShFRAy3hJxYUbHhT+7SDUBadVSEkb4UqxQ+7zntAVT+Lp4DXLAfvsWxZGrQoP/IrWAgNOLRKILubpzh+YpadMH3Ygha2JRAeJAEZ3DnXf3vOOAucWnk4mNXDbW35GTDTAJDWMvddZCfsrUI/uHxgaRjFs9fLX1X5tqhGnsr27sKLWyX+zrIPVV0TPl3AzYPAf6Bc8Okeu+JEGQERvvgSasCuYcmhgYznBVJI=" + file_glob: true file: - - "NetHack.zip" + - "NetHack-x86-beta$TRAVIS_TAG.zip" skip_cleanup: true on: tags: true prerelease: true - name: "Pre-release build of NetHack 3.6.3" - body: "This is auto generated pre-release build of NetHack 3.6.3 and as such has not been tested." + name: "Pre-release build of NetHack 3.6.3" + body: "This is auto generated pre-release build of NetHack 3.6.3 and as such has not been tested." diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index d50b20b29..7777ed29d 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -24,7 +24,7 @@ .ds vr "NetHack 3.7 .ds f0 "\*(vr .ds f1 -.ds f2 "October 1, 2019 +.ds f2 "October 27, 2019 . .\" A note on some special characters: .\" \(lq = left double quote @@ -2731,7 +2731,7 @@ See the \(lqConfiguring Message Types\(rq section. .lp MENUCOLOR Highlight menu lines with different colors. See the \(lqConfiguring Menu Colors\(rq section. -.lp SYMBOLS +.lp SYMBOLS, ROGUESYMBOLS Override one or more symbols in the symbols files. See the \(lqModifying NetHack Symbols\(rq section. .pg @@ -4372,8 +4372,8 @@ Set the name of the symbol set that you want to load. Set the name of the symbol set that you want to load for display on the rogue level. .pg -You can also override one or more symbols using the SYMBOLS config -file option. Symbols are specified as name:value pairs. +You can also override one or more symbols using the SYMBOLS and +ROGUESYMBOLS config file options. Symbols are specified as name:value pairs. Note that NetHack escape-processes the value string in conventional C fashion. This means that \\ is a prefix to take the following character literally. @@ -4567,6 +4567,8 @@ X S_xorn (xorn) Y S_yeti (apelike creature) Z S_zombie (zombie) z S_zruty (zruty) + S_pet_override (pet override if sysconf accessibility is set) + S_player_override (player override if sysconf accessibility is set) .\"TABLE_END Do not delete this line. .TE .pg @@ -4609,7 +4611,12 @@ configuration file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via \fBSYMBOLS=\fP +and \fBROGUESYMBOLS=\fP in your configuration file to better suit your preferences. +See the previous section for the special symbols S_pet_override +to force a consistent symbol for all pets and and +S_player_override to force a unique symbol for the player character +if \fBaccessibility\fP is enabled in the sysconf file. The most crucial settings to make the game accessible are: .pg .lp symset:NHAccess diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 5bbeff926..a82a3895e 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.6 by Mike Stephenson and others)} -\date{October 1, 2019} +\date{October 22, 2019} \maketitle @@ -3000,7 +3000,7 @@ See the ``Configuring Message Types`` section. Highlight menu lines with different colors. See the ``Configuring Menu Colors`` section. %.lp -\item[\bb{SYMBOLS}] +\item[\bb{SYMBOLS},\bb{ROGUESYMBOLS}] Override one or more symbols in the symbols files. See the ``Modifying {\it NetHack\/} Symbols'' section. %.pg @@ -4866,11 +4866,12 @@ Set the name of the symbol set that you want to load for display on the rogue level. \elist -You can also override one or more symbols using the {\it SYMBOLS\/} config -file option. Symbols are specified as {\it name:value\/} pairs. Note that -{\it NetHack\/} escape-processes the {\it value\/} string in conventional C -fashion. This means that `\verb+\+' is a prefix to take the following -character literally. Thus `\verb+\+' needs to be represented as `\verb+\\+'. +You can also override one or more symbols using the {\it SYMBOLS\/} and +{\it ROGUESYMBOLS\/} config file options. Symbols are specified as +{\it name:value\/} pairs. Note that {\it NetHack\/} escape-processes +the {\it value\/} string in conventional C fashion. This means that `\verb+\+' +is a prefix to take the following character literally. Thus `\verb+\+' needs +to be represented as `\verb+\\+'. The special prefix `\verb+\m+' switches on the meta bit in the symbol value, and the `{\tt \^{}}' prefix causes the following character to be treated as a control @@ -5056,7 +5057,9 @@ Default & Symbol Name & Description\\ \verb@X@ & S\verb+_+xorn & (xorn)\\ \verb@Y@ & S\verb+_+yeti & (apelike creature)\\ \verb@Z@ & S\verb+_+zombie & (zombie)\\ -\verb@z@ & S\verb+_+zruty & (zruty) +\verb@z@ & S\verb+_+zruty & (zruty)\\ +\verb@ @ & S\verb+_+pet\verb+_+override & (pet override if sysconf accessibility is set)\\ +\verb@ @ & S\verb+_+player\verb+_+override & (player override if sysconf accessibility is set) \end{longtable}% } @@ -5101,7 +5104,12 @@ is a symset called {\it NHAccess\/}. Selecting that symset in your configuration file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via {\it SYMBOLS=\/} +and {\it ROGUESYMBOLS=\/} in your configuration file to better suit your preferences. +See the previous section for the special symbols S\verb+_+pet\verb+_+override +to force a consistent symbol for all pets and S\verb+_+player\verb+_+override +to force a unique symbol for the player character if {\it accessibility\/} +is enabled in the {\it sysconf\/} file. The most crucial settings to make the game accessible are: %.pg \blist{} diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 1f8077ee2..5940e16aa 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -379,6 +379,9 @@ curses+'perm_invent': since persistent inventory is narrow, strip off "a", curses+'curses': change the curses map display to use new symbol set 'curses' instead of hard-coded values; it attempts to show IBMgraphics-style map using DECgraphics characters; DECgraphics can also be used as-is +fulfill a request from a blind player to have a unique overriding SYMBOL for pets + and for the player +ROGUESYMBOLS can be overridden in config files like SYMBOLS can NetHack Community Patches (or Variation) Included diff --git a/include/decl.h b/include/decl.h index 66ada6cae..f5b2aa5b6 100644 --- a/include/decl.h +++ b/include/decl.h @@ -903,8 +903,10 @@ struct instance_globals { struct symsetentry symset[NUM_GRAPHICS]; int currentgraphics; nhsym showsyms[SYM_MAX]; /* symbols to be displayed */ - nhsym l_syms[SYM_MAX]; /* loaded symbols */ - nhsym r_syms[SYM_MAX]; /* rogue symbols */ + nhsym primary_syms[SYM_MAX]; /* loaded primary symbols */ + nhsym rogue_syms[SYM_MAX]; /* loaded rogue symbols */ + nhsym ov_primary_syms[SYM_MAX]; /* loaded primary symbols */ + nhsym ov_rogue_syms[SYM_MAX]; /* loaded rogue symbols */ nhsym warnsyms[WARNCOUNT]; /* the current warning display symbols */ /* dungeon.c */ diff --git a/include/extern.h b/include/extern.h index 3f55bdd0d..243a5d44c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -585,15 +585,19 @@ E int FDECL(def_char_to_monclass, (CHAR_P)); #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(switch_symbols, (int)); E void FDECL(assign_graphics, (int)); -E void NDECL(init_r_symbols); E void NDECL(init_symbols); -E void NDECL(update_bouldersym); E void NDECL(init_showsyms); -E void NDECL(init_l_symbols); +E void NDECL(init_primary_symbols); +E void NDECL(init_rogue_symbols); +E void NDECL(init_ov_primary_symbols); +E void NDECL(init_ov_rogue_symbols); E void FDECL(clear_symsetentry, (int, BOOLEAN_P)); -E void FDECL(update_l_symset, (struct symparse *, int)); -E void FDECL(update_r_symset, (struct symparse *, int)); +E void FDECL(update_primary_symset, (struct symparse *, int)); +E void FDECL(update_rogue_symset, (struct symparse *, int)); +E void FDECL(update_ov_primary_symset, (struct symparse *, int)); +E void FDECL(update_ov_rogue_symset, (struct symparse *, int)); E boolean FDECL(cursed_object_at, (int, int)); +E nhsym FDECL(get_othersym, (int, int)); /* ### dungeon.c ### */ @@ -1780,7 +1784,7 @@ E int FDECL(add_autopickup_exception, (const char *)); E void NDECL(free_autopickup_exceptions); E int FDECL(load_symset, (const char *, int)); E void NDECL(free_symsets); -E boolean FDECL(parsesymbols, (char *)); +E boolean FDECL(parsesymbols, (char *, int)); E struct symparse *FDECL(match_sym, (char *)); E void NDECL(set_playmode); E int FDECL(sym_val, (const char *)); diff --git a/include/rm.h b/include/rm.h index e914b6c32..c5ae88d8e 100644 --- a/include/rm.h +++ b/include/rm.h @@ -266,7 +266,9 @@ struct symparse { /* misc symbol definitions */ #define SYM_BOULDER 0 #define SYM_INVISIBLE 1 -#define MAXOTHER 2 +#define SYM_PET_OVERRIDE 2 +#define SYM_PLAYER_OVERRIDE 3 +#define MAXOTHER 4 /* linked list of symsets and their characteristics */ struct symsetentry { @@ -306,6 +308,10 @@ extern const struct symdef defsyms[MAXPCHARS]; /* defaults */ #define WARNCOUNT 6 /* number of different warning levels */ extern const struct symdef def_warnsyms[WARNCOUNT]; #define SYMHANDLING(ht) (g.symset[g.currentgraphics].handling == (ht)) +extern nhsym primary_syms[]; +extern nhsym rogue_syms[]; +extern nhsym ov_primary_syms[]; +extern nhsym ov_rogue_syms[]; /* * The 5 possible states of doors diff --git a/include/sys.h b/include/sys.h index f7bd0b469..855de36b8 100644 --- a/include/sys.h +++ b/include/sys.h @@ -45,6 +45,10 @@ struct sysopt { /* save and bones format */ int saveformat[2]; /* primary and onetime conversion */ int bonesformat[2]; /* primary and onetime conversion */ + + /* enable accessibility options */ + int accessibility; + }; extern struct sysopt sysopt; diff --git a/src/decl.c b/src/decl.c index 9d57ab989..4f9ed6eb3 100644 --- a/src/decl.c +++ b/src/decl.c @@ -391,8 +391,10 @@ const struct instance_globals g_init = { DUMMY, /* symset */ 0, /* currentgraphics */ DUMMY, /* showsyms */ - DUMMY, /* l_syms */ - DUMMY, /* r_syms */ + DUMMY, /* primary_syms */ + DUMMY, /* rogue_syms */ + DUMMY, /* ov_primary_syms */ + DUMMY, /* ov_rogue_syms */ DUMMY, /* warnsyms */ /* dungeon.c */ diff --git a/src/detect.c b/src/detect.c index 4ceca787b..6b4cd342a 100644 --- a/src/detect.c +++ b/src/detect.c @@ -598,13 +598,13 @@ int class; /* an object class, 0 for all */ } /* Special boulder symbol check - does the class symbol happen - * to match iflags.bouldersym which is a user-defined? + * to match showsyms[SYM_BOULDER + SYM_OFF_X] which is user-defined. * If so, that means we aren't sure what they really wanted to * detect. Rather than trump anything, show both possibilities. * We can exclude checking the buried obj chain for boulders below. */ sym = class ? def_oc_syms[class].sym : 0; - if (sym && iflags.bouldersym && sym == iflags.bouldersym) + if (sym && g.showsyms[SYM_BOULDER + SYM_OFF_X] && sym == g.showsyms[SYM_BOULDER + SYM_OFF_X]) boulder = ROCK_CLASS; if (Hallucination || (Confusion && class == SCROLL_CLASS)) @@ -1206,7 +1206,8 @@ struct obj **optr; ret = object_detect((struct obj *) 0, class); else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES) ret = monster_detect((struct obj *) 0, class); - else if (iflags.bouldersym && (ch == iflags.bouldersym)) + else if (g.showsyms[SYM_BOULDER + SYM_OFF_X] + && (ch == g.showsyms[SYM_BOULDER + SYM_OFF_X])) ret = object_detect((struct obj *) 0, ROCK_CLASS); else switch (ch) { diff --git a/src/drawing.c b/src/drawing.c index 3bc5e95f0..0c00de2f5 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -17,9 +17,13 @@ #define C(n) #endif +nhsym primary_syms[SYM_MAX] = DUMMY; /* primary symbols */ +nhsym rogue_syms[SYM_MAX] = DUMMY; /* rogue symbols */ +nhsym ov_primary_syms[SYM_MAX] = DUMMY; /* overides via config SYMBOL */ +nhsym ov_rogue_syms[SYM_MAX] = DUMMY; /* overides via config ROGUESYMBOL */ const char invisexplain[] = "remembered, unseen, creature", altinvisexplain[] = "unseen creature"; /* for clairvoyance */ - + /* Default object class symbols. See objclass.h. * {symbol, name, explain} * name: used in object_detect(). @@ -297,7 +301,7 @@ char ch; * init_symbols() * Sets the current display symbols, the * loadable symbols to the default NetHack - * symbols, including the r_syms rogue level + * symbols, including the rogue_syms rogue level * symbols. This would typically be done * immediately after execution begins. Any * previously loaded external symbol sets are @@ -313,8 +317,8 @@ char ch; * * If (arg != 0), which is the normal expected * usage, then showsyms are taken from the - * adjustable display symbols found in l_syms. - * l_syms may have been loaded from an external + * adjustable display symbols found in primary_syms. + * primary_syms may have been loaded from an external * symbol file by config file options or interactively * in the Options menu. * @@ -324,37 +328,33 @@ char ch; * out of other {rogue} level display modes. * * If arg is ROGUESET, this places the rogue level - * symbols from r_syms into showsyms. + * symbols from rogue_syms into showsyms. * * If arg is PRIMARY, this places the symbols * from l_monsyms into showsyms. * - * update_l_symset() - * Update a member of the loadable (l_*) symbol set. + * update_primary_symset() + * Update a member of the primary(primary_*) symbol set. * - * update_r_symset() - * Update a member of the rogue (r_*) symbol set. + * update_rogue_symset() + * Update a member of the rogue (rogue_*) symbol set. + * + * update_ov_primary_symset() + * Update a member of the overrides for primary symbol set. + * + * update_ov_rogue_symset() + * Update a member of the overrides for rogue symbol set. * */ void init_symbols() { - init_l_symbols(); + init_ov_primary_symbols(); + init_ov_rogue_symbols(); + init_primary_symbols(); init_showsyms(); - init_r_symbols(); -} - -void -update_bouldersym() -{ - nhsym boulder = (nhsym) iflags.bouldersym; - - if (!boulder) - boulder = def_oc_syms[ROCK_CLASS].sym; /* (nhsym) ROCK_SYM */ - g.showsyms[SYM_BOULDER + SYM_OFF_X] = boulder; - g.l_syms[SYM_BOULDER + SYM_OFF_X] = boulder; - g.r_syms[SYM_BOULDER + SYM_OFF_X] = boulder; + init_rogue_symbols(); } void @@ -370,44 +370,78 @@ init_showsyms() g.showsyms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) g.showsyms[i + SYM_OFF_W] = def_warnsyms[i].sym; - for (i = 0; i < MAXOTHER; i++) { - if (i == SYM_BOULDER) - g.showsyms[i + SYM_OFF_X] = iflags.bouldersym - ? iflags.bouldersym - : def_oc_syms[ROCK_CLASS].sym; - else if (i == SYM_INVISIBLE) - g.showsyms[i + SYM_OFF_X] = DEF_INVISIBLE; - } + for (i = 0; i < MAXOTHER; i++) + g.showsyms[i + SYM_OFF_X] = get_othersym(i, PRIMARY); } -/* initialize defaults for the loadable symset */ +/* initialize defaults for the overrides to the rogue symset */ void -init_l_symbols() +init_ov_rogue_symbols() +{ + register int i; + + for (i = 0; i < SYM_MAX; i++) + ov_rogue_syms[i] = (nhsym) 0; +} +/* initialize defaults for the overrides to the primary symset */ +void +init_ov_primary_symbols() +{ + register int i; + + for (i = 0; i < SYM_MAX; i++) + ov_primary_syms[i] = (nhsym) 0; +} + +nhsym +get_othersym(idx, which_set) +int idx, which_set; +{ + nhsym sym = (nhsym) 0; + int oidx = idx + SYM_OFF_X; + + if (which_set == ROGUESET) + sym = ov_rogue_syms[oidx] ? ov_rogue_syms[oidx] + : rogue_syms[oidx]; + else + sym = ov_primary_syms[oidx] ? ov_primary_syms[oidx] + : primary_syms[oidx]; + if (!sym) { + switch(idx) { + case SYM_BOULDER: + sym = def_oc_syms[ROCK_CLASS].sym; + break; + case SYM_INVISIBLE: + sym = DEF_INVISIBLE; + break; + } + } + return sym; +} + +/* initialize defaults for the primary symset */ +void +init_primary_symbols() { register int i; for (i = 0; i < MAXPCHARS; i++) - g.l_syms[i + SYM_OFF_P] = defsyms[i].sym; + primary_syms[i + SYM_OFF_P] = defsyms[i].sym; for (i = 0; i < MAXOCLASSES; i++) - g.l_syms[i + SYM_OFF_O] = def_oc_syms[i].sym; + primary_syms[i + SYM_OFF_O] = def_oc_syms[i].sym; for (i = 0; i < MAXMCLASSES; i++) - g.l_syms[i + SYM_OFF_M] = def_monsyms[i].sym; + primary_syms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) - g.l_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; - for (i = 0; i < MAXOTHER; i++) { - if (i == SYM_BOULDER) - g.l_syms[i + SYM_OFF_X] = iflags.bouldersym - ? iflags.bouldersym - : def_oc_syms[ROCK_CLASS].sym; - else if (i == SYM_INVISIBLE) - g.l_syms[i + SYM_OFF_X] = DEF_INVISIBLE; - } + primary_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; + for (i = 0; i < MAXOTHER; i++) + primary_syms[i + SYM_OFF_X] = get_othersym(i, PRIMARY); clear_symsetentry(PRIMARY, FALSE); } +/* initialize defaults for the rogue symset */ void -init_r_symbols() +init_rogue_symbols() { register int i; @@ -415,24 +449,18 @@ init_r_symbols() later by the roguesymbols option */ for (i = 0; i < MAXPCHARS; i++) - g.r_syms[i + SYM_OFF_P] = defsyms[i].sym; - g.r_syms[S_vodoor] = g.r_syms[S_hodoor] = g.r_syms[S_ndoor] = '+'; - g.r_syms[S_upstair] = g.r_syms[S_dnstair] = '%'; + rogue_syms[i + SYM_OFF_P] = defsyms[i].sym; + rogue_syms[S_vodoor] = rogue_syms[S_hodoor] = rogue_syms[S_ndoor] = '+'; + rogue_syms[S_upstair] = rogue_syms[S_dnstair] = '%'; for (i = 0; i < MAXOCLASSES; i++) - g.r_syms[i + SYM_OFF_O] = def_r_oc_syms[i]; + rogue_syms[i + SYM_OFF_O] = def_r_oc_syms[i]; for (i = 0; i < MAXMCLASSES; i++) - g.r_syms[i + SYM_OFF_M] = def_monsyms[i].sym; + rogue_syms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) - g.r_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; - for (i = 0; i < MAXOTHER; i++) { - if (i == SYM_BOULDER) - g.r_syms[i + SYM_OFF_X] = iflags.bouldersym - ? iflags.bouldersym - : def_oc_syms[ROCK_CLASS].sym; - else if (i == SYM_INVISIBLE) - g.r_syms[i + SYM_OFF_X] = DEF_INVISIBLE; - } + rogue_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; + for (i = 0; i < MAXOTHER; i++) + rogue_syms[i + SYM_OFF_X] = get_othersym(i, ROGUESET); clear_symsetentry(ROGUESET, FALSE); /* default on Rogue level is no color @@ -452,7 +480,8 @@ int whichset; /* Adjust graphics display characters on Rogue levels */ for (i = 0; i < SYM_MAX; i++) - g.showsyms[i] = g.r_syms[i]; + g.showsyms[i] = ov_rogue_syms[i] ? ov_rogue_syms[i] + : rogue_syms[i]; #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) @@ -464,7 +493,8 @@ int whichset; case PRIMARY: default: for (i = 0; i < SYM_MAX; i++) - g.showsyms[i] = g.l_syms[i]; + g.showsyms[i] = ov_primary_syms[i] ? ov_primary_syms[i] + : primary_syms[i]; #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) @@ -483,7 +513,8 @@ int nondefault; if (nondefault) { for (i = 0; i < SYM_MAX; i++) - g.showsyms[i] = g.l_syms[i]; + g.showsyms[i] = ov_primary_syms[i] ? ov_primary_syms[i] + : primary_syms[i]; #ifdef PC9800 if (SYMHANDLING(H_IBM) && ibmgraphics_mode_callback) (*ibmgraphics_mode_callback)(); @@ -504,25 +535,41 @@ int nondefault; # endif #endif } else { - init_l_symbols(); + init_primary_symbols(); init_showsyms(); } } void -update_l_symset(symp, val) +update_ov_primary_symset(symp, val) struct symparse *symp; int val; { - g.l_syms[symp->idx] = val; + ov_primary_syms[symp->idx] = val; } void -update_r_symset(symp, val) +update_ov_rogue_symset(symp, val) struct symparse *symp; int val; { - g.r_syms[symp->idx] = val; + ov_rogue_syms[symp->idx] = val; +} + +void +update_primary_symset(symp, val) +struct symparse *symp; +int val; +{ + primary_syms[symp->idx] = val; +} + +void +update_rogue_symset(symp, val) +struct symparse *symp; +int val; +{ + rogue_syms[symp->idx] = val; } void @@ -763,6 +810,8 @@ const struct symparse loadsyms[] = { { SYM_MON, S_MIMIC_DEF + SYM_OFF_M, "S_mimic_def" }, { SYM_OTH, SYM_BOULDER + SYM_OFF_X, "S_boulder" }, { SYM_OTH, SYM_INVISIBLE + SYM_OFF_X, "S_invisible" }, + { SYM_OTH, SYM_PET_OVERRIDE + SYM_OFF_X, "S_pet_override" }, + { SYM_OTH, SYM_PLAYER_OVERRIDE + SYM_OFF_X, "S_player_override" }, { 0, 0, (const char *) 0 } /* fence post */ }; diff --git a/src/files.c b/src/files.c index bc7d46ad7..6b7c791b0 100644 --- a/src/files.c +++ b/src/files.c @@ -2775,10 +2775,18 @@ char *origbuf; } else if (src == SET_IN_SYS && match_varname(buf, "BONESFORMAT", 11)) { parseformat(sysopt.bonesformat, bufp); + } else if (src == SET_IN_SYS + && match_varname(buf, "ACCESSIBILITY", 13)) { + n = atoi(bufp); + if (n < 0 || n > 1) { + config_error_add("Illegal value in ACCESSIBILITY (not 0,1)."); + return FALSE; + } + sysopt.accessibility = n; #endif /* SYSCF */ } else if (match_varname(buf, "BOULDER", 3)) { - (void) get_uchars(bufp, &iflags.bouldersym, TRUE, 1, + (void) get_uchars(bufp, &g.ov_primary_syms[SYM_BOULDER + SYM_OFF_X], TRUE, 1, "BOULDER"); } else if (match_varname(buf, "MENUCOLOR", 9)) { if (!add_menu_coloring(bufp)) @@ -2792,8 +2800,14 @@ char *origbuf; (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); assign_warnings(translate); + } else if (match_varname(buf, "ROGUESYMBOLS", 4)) { + if (!parsesymbols(bufp, ROGUESET)) { + config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp); + retval = FALSE; + } + switch_symbols(TRUE); } else if (match_varname(buf, "SYMBOLS", 4)) { - if (!parsesymbols(bufp)) { + if (!parsesymbols(bufp, PRIMARY)) { config_error_add("Error in SYMBOLS definition '%s'", bufp); retval = FALSE; } @@ -3567,9 +3581,9 @@ int which_set; g.chosen_symset_start = TRUE; /* these init_*() functions clear symset fields too */ if (which_set == ROGUESET) - init_r_symbols(); + init_rogue_symbols(); else if (which_set == PRIMARY) - init_l_symbols(); + init_primary_symbols(); } break; case 1: @@ -3622,9 +3636,9 @@ int which_set; val = sym_val(bufp); if (g.chosen_symset_start) { if (which_set == PRIMARY) { - update_l_symset(symp, val); + update_primary_symset(symp, val); } else if (which_set == ROGUESET) { - update_r_symset(symp, val); + update_rogue_symset(symp, val); } } } diff --git a/src/mapglyph.c b/src/mapglyph.c index 59512dbbb..b6ec9f601 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -66,11 +66,12 @@ unsigned *ospecial; { register int offset, idx; int color = NO_COLOR; - nhsym ch; + nhsym ch, ovsym; unsigned special = 0; /* condense multiple tests in macro version down to single */ - boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS; - boolean has_rogue_color = (has_rogue_ibm_graphics + boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS, + is_you = (x == u.ux && y == u.uy), + has_rogue_color = (has_rogue_ibm_graphics && g.symset[g.currentgraphics].nocolor == 0); /* @@ -206,7 +207,7 @@ unsigned *ospecial; } else { /* a monster */ idx = mons[glyph].mlet + SYM_OFF_M; if (has_rogue_color && iflags.use_color) { - if (x == u.ux && y == u.uy) + if (is_you) /* actually player should be yellow-on-gray if in corridor */ color = CLR_YELLOW; else @@ -215,13 +216,26 @@ unsigned *ospecial; mon_color(glyph); #ifdef TEXTCOLOR /* special case the hero for `showrace' option */ - if (iflags.use_color && x == u.ux && y == u.uy - && flags.showrace && !Upolyd) + if (iflags.use_color && is_you && flags.showrace && !Upolyd) color = HI_DOMESTIC; #endif } } + /* These were requested by a blind player to enhance screen reader use */ + if (sysopt.accessibility == 1) { + ovsym = Is_rogue_level(&u.uz) + ? g.ov_rogue_syms[SYM_PET_OVERRIDE + SYM_OFF_X] + : g.ov_primary_syms[SYM_PET_OVERRIDE + SYM_OFF_X]; + if (ovsym && (special & MG_PET)) + idx = SYM_PET_OVERRIDE + SYM_OFF_X; + ovsym = Is_rogue_level(&u.uz) + ? g.ov_rogue_syms[SYM_PLAYER_OVERRIDE + SYM_OFF_X] + : g.ov_primary_syms[SYM_PLAYER_OVERRIDE + SYM_OFF_X]; + if (ovsym && is_you) + idx = SYM_PLAYER_OVERRIDE + SYM_OFF_X; + } + ch = g.showsyms[idx]; #ifdef TEXTCOLOR /* Turn off color if no color defined, or rogue level w/o PC graphics. */ diff --git a/src/options.c b/src/options.c index 4a02922ef..93fa8cce8 100644 --- a/src/options.c +++ b/src/options.c @@ -728,11 +728,12 @@ initoptions_init() flags.initrole = flags.initrace = flags.initgend = flags.initalign = ROLE_NONE; + init_ov_primary_symbols(); + init_ov_rogue_symbols(); /* Set the default monster and object class symbols. */ init_symbols(); for (i = 0; i < WARNCOUNT; i++) g.warnsyms[i] = def_warnsyms[i].sym; - iflags.bouldersym = 0; /* for "special achievement" tracking (see obj.h, create_object(sp_lev.c), addinv_core1(invent.c) */ @@ -750,7 +751,7 @@ initoptions_init() for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO; switch_symbols(FALSE); /* set default characters */ - init_r_symbols(); + init_rogue_symbols(); #if defined(UNIX) && defined(TTY_GRAPHICS) /* * Set defaults for some options depending on what we can @@ -814,6 +815,7 @@ initoptions_init() void initoptions_finish() { + nhsym sym = 0; #ifndef MAC char *opts = getenv("NETHACKOPTIONS"); @@ -857,8 +859,10 @@ initoptions_finish() */ obj_descr[SLIME_MOLD].oc_name = "fruit"; - if (iflags.bouldersym) - update_bouldersym(); + sym = get_othersym(SYM_BOULDER, + Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY); + if (sym) + g.showsyms[SYM_BOULDER + SYM_OFF_X] = sym; reglyph_darkroom(); #ifdef STATUS_HILITES @@ -2729,12 +2733,16 @@ boolean tinitial, tfrom_file; /* * Override the default boulder symbol. */ - iflags.bouldersym = (uchar) opts[0]; - /* for 'initial', update_bouldersym() is done in + g.ov_primary_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0]; + g.ov_rogue_syms[SYM_BOULDER + SYM_OFF_X] = (nhsym) opts[0]; + /* for 'initial', update of BOULDER symbol is done in initoptions_finish(), after all symset options have been processed */ if (!g.opt_initial) { - update_bouldersym(); + nhsym sym = get_othersym(SYM_BOULDER, + Is_rogue_level(&u.uz) ? ROGUESET : PRIMARY); + if (sym) + g.showsyms[SYM_BOULDER + SYM_OFF_X] = sym; g.opt_need_redraw = TRUE; } } @@ -4076,12 +4084,14 @@ boolean tinitial, tfrom_file; } } +#if 0 /* Is it a symbol? */ - if (strstr(opts, "S_") == opts && parsesymbols(opts)) { + if (strstr(opts, "S_") == opts && parsesymbols(opts, PRIMARY)) { switch_symbols(TRUE); check_gold_symbol(); return retval; } +#endif /* out of valid options */ config_error_add("Unknown option '%s'", opts); @@ -5479,9 +5489,9 @@ boolean setinitial, setfromfile; /* Set default symbols and clear the handling value */ if (rogueflag) - init_r_symbols(); + init_rogue_symbols(); else - init_l_symbols(); + init_primary_symbols(); if (g.symset[which_set].name) { /* non-default symbols */ @@ -5548,8 +5558,8 @@ char *buf; #ifdef BACKWARD_COMPAT else if (!strcmp(optname, "boulder")) Sprintf(buf, "%c", - iflags.bouldersym - ? iflags.bouldersym + g.ov_primary_syms[SYM_BOULDER + SYM_OFF_X] + ? g.ov_primary_syms[SYM_BOULDER + SYM_OFF_X] : g.showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]); #endif else if (!strcmp(optname, "catname")) @@ -6030,16 +6040,20 @@ free_symsets() /* Parse the value of a SYMBOLS line from a config file */ boolean -parsesymbols(opts) +parsesymbols(opts, which_set) register char *opts; +int which_set; { int val; char *op, *symname, *strval; struct symparse *symp; +#ifdef DEBUG + int sym_max = SYM_MAX; +#endif if ((op = index(opts, ',')) != 0) { *op++ = 0; - if (!parsesymbols(op)) + if (!parsesymbols(op, which_set)) return FALSE; } @@ -6062,7 +6076,10 @@ register char *opts; if (symp->range && symp->range != SYM_CONTROL) { val = sym_val(strval); - update_l_symset(symp, val); + if (which_set == ROGUESET) + update_ov_rogue_symset(symp, val); + else + update_ov_primary_symset(symp, val); } return TRUE; } diff --git a/src/pager.c b/src/pager.c index dd2b07060..2cbc89337 100644 --- a/src/pager.c +++ b/src/pager.c @@ -813,11 +813,12 @@ struct permonst **for_supplement; unreconnoitered[] = "unreconnoitered"; static char look_buf[BUFSZ]; char prefix[BUFSZ]; - int i, alt_i, glyph = NO_GLYPH, + int i, alt_i, j, glyph = NO_GLYPH, skipped_venom = 0, found = 0; /* count of matching syms found */ boolean hit_trap, need_to_look = FALSE, submerged = (Underwater && !Is_waterlevel(&u.uz)); const char *x_str; + nhsym tmpsym; if (looked) { int oc; @@ -881,7 +882,7 @@ struct permonst **for_supplement; if (x_str == unreconnoitered) goto didlook; } - + check_monsters: /* Check for monsters */ if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) { for (i = 1; i < MAXMCLASSES; i++) { @@ -1034,8 +1035,53 @@ struct permonst **for_supplement; } } + /* Finally, handle some optional overriding symbols */ + for (j = SYM_OFF_X; j < SYM_MAX; ++j) { + if (j == (SYM_INVISIBLE + SYM_OFF_X)) + continue; /* already handled above */ + tmpsym = Is_rogue_level(&u.uz) ? g.ov_rogue_syms[j] : g.ov_primary_syms[j]; + if (tmpsym && sym == tmpsym) { + switch(j) { + case SYM_BOULDER + SYM_OFF_X: + if (!found) { + *firstmatch = "boulder"; + Sprintf(out_str, "%s%s", prefix, an(*firstmatch)); + found++; + } else { + found += append_str(out_str, "boulder"); + } + break; + case SYM_PET_OVERRIDE + SYM_OFF_X: + if (looked) { + int oc = 0; + unsigned os = 0; + nhsym save_override; + + if (Is_rogue_level(&u.uz)) { + save_override = g.ov_rogue_syms[SYM_PET_OVERRIDE + SYM_OFF_X]; + g.ov_rogue_syms[SYM_PET_OVERRIDE + SYM_OFF_X] = 0; + } else { + save_override = g.ov_primary_syms[SYM_PET_OVERRIDE + SYM_OFF_X]; + g.ov_primary_syms[SYM_PET_OVERRIDE + SYM_OFF_X] = 0; + } + /* convert to symbol without the override in effect */ + (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y); + if (Is_rogue_level(&u.uz)) + g.ov_rogue_syms[SYM_PET_OVERRIDE + SYM_OFF_X] = save_override; + else + g.ov_primary_syms[SYM_PET_OVERRIDE + SYM_OFF_X] = save_override; + goto check_monsters; + } + break; + case SYM_PLAYER_OVERRIDE + SYM_OFF_X: + sym = g.showsyms[S_HUMAN + SYM_OFF_M]; + goto check_monsters; + } + } + } +#if 0 /* handle optional boulder symbol as a special case */ - if (iflags.bouldersym && sym == iflags.bouldersym) { + if (o_syms[SYM_BOULDER + SYM_OFF_X] && sym == o_syms[SYM_BOULDER + SYM_OFF_X]) { if (!found) { *firstmatch = "boulder"; Sprintf(out_str, "%s%s", prefix, an(*firstmatch)); @@ -1044,6 +1090,7 @@ struct permonst **for_supplement; found += append_str(out_str, "boulder"); } } +#endif /* * If we are looking at the screen, follow multiple possibilities or diff --git a/src/sys.c b/src/sys.c index 520f4c758..6dd668dc5 100644 --- a/src/sys.c +++ b/src/sys.c @@ -80,6 +80,7 @@ sys_early_init() sysopt.check_plname = 0; sysopt.seduce = 1; /* if it's compiled in, default to on */ sysopt_seduce_set(sysopt.seduce); + sysopt.accessibility = 0; return; } diff --git a/sys/unix/sysconf b/sys/unix/sysconf index 5986f54a5..66df42c63 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -61,6 +61,11 @@ MAXPLAYERS=10 # incubi to use nymphs' charm behavior rather than their own seduce behavior. #SEDUCE=0 +# Uncomment the next line to enable some accessibility features such +# as S_player_override and S_pet_override symbols for screen readers +# in the user config file. +#ACCESSIBILITY=1 + # Uncomment to disable savefile UID checking. #CHECK_SAVE_UID=0 diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index bf4294547..2ce343f62 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1606,8 +1606,8 @@ check_font_widths() boolean used[256]; memset(used, 0, sizeof(used)); for (int i = 0; i < SYM_MAX; i++) { - used[g.l_syms[i]] = TRUE; - used[g.r_syms[i]] = TRUE; + used[g.primary_syms[i]] = TRUE; + used[g.rogue_syms[i]] = TRUE; } int wcUsedCount = 0; diff --git a/sys/winnt/sysconf b/sys/winnt/sysconf index 283a55df4..93aaa1ddc 100644 --- a/sys/winnt/sysconf +++ b/sys/winnt/sysconf @@ -52,6 +52,11 @@ WIZARDS=* # Uncomment the next line to disable the SEDUCE option. #SEDUCE=0 +# Uncomment the next line to enable some accessibility features such +# as S_player_override and S_pet_override symbols for screen readers +# in the user config file. +#ACCESSIBILITY=1 + # Record (high score) file options. # CAUTION: changing these after people have started playing games can # lead to lost high scores! diff --git a/win/win32/vs2017/travisci.sh b/win/win32/vs2017/travisci.sh index 09b4b9822..e17de0efa 100644 --- a/win/win32/vs2017/travisci.sh +++ b/win/win32/vs2017/travisci.sh @@ -1,3 +1,4 @@ +set -x export VSVER=2017 export MSVER=14.16.27023 export SDKVER=10.0.17763.0 @@ -26,8 +27,10 @@ export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/um/x86:$LIB git clone --depth 1 https://github.com/wmcbrine/PDCurses.git ../pdcurses export ADD_CURSES=Y export PDCURSES_TOP=../../pdcurses +export cd src cp ../sys/winnt/Makefile.msc ./Makefile nmake install cd .. -powershell -Command "Compress-Archive -U -Path binary/*.* -DestinationPath NetHack.zip" +powershell -Command "Compress-Archive -U -Path binary/*.* -DestinationPath NetHack-x86-beta$TRAVIS_TAG.zip" +