Accessibility: Add location info to messages

Adds a new boolean option, accessiblemsg.  If on, some game messages
are prefixed with direction or location information, for example:

   (west): The newt bites!
   (northwest): You find a hidden door.

I added the info to the most common messages, but several are
still missing it.
This commit is contained in:
Pasi Kallinen
2024-01-02 18:59:25 +02:00
parent d86e6e9717
commit dc8d9d6cd0
18 changed files with 138 additions and 29 deletions
+4
View File
@@ -3746,6 +3746,8 @@ applies only to new games.
.\" Ones less that 8 should be enclosed within double quotes and padded with
.\" trailing spaces.
.
.lp accessiblemsg
Add location or direction information to messages (default is off).
.lp acoustics
Enable messages about what your character hears (default on).
Note that this has nothing to do with your computer's audio capabilities.
@@ -5934,6 +5936,8 @@ option and use the traditional
Rogue-like commands.
.lp paranoid_confirmation:swim
Prevent walking into water or lava.
.lp accessiblemsg
Adds direction or location information to messages.
.lp autodescribe
Automatically describe the terrain under the cursor when targeting.
.lp mention_walls
+6
View File
@@ -4082,6 +4082,9 @@ applies only to new games.
\blist{}
%.lp
\item[\ib{accessiblemsg}]
Add location or direction information to messages (default is off).
%.lp
\item[\ib{acoustics}]
Enable messages about what your character hears (default on).
Note that this has nothing to do with your computer's audio capabilities.
@@ -6529,6 +6532,9 @@ traditional Rogue-like commands.
\item[\ib{paranoid\verb+_+confirmation:swim}]
Prevent walking into water or lava.
%.lp
\item[\ib{accessiblemsg}]
Adds direction or location information to messages.
%.lp
\item[\ib{autodescribe}]
Automatically describe the terrain under the cursor when targeting.
%.lp
+4
View File
@@ -2336,6 +2336,10 @@ extern void dumplogmsg(const char *);
extern void dumplogfreemessages(void);
#endif
extern void pline(const char *, ...) PRINTF_F(1, 2);
extern void pline_dir(int, const char *, ...) PRINTF_F(2, 3);
extern void pline_xy(coordxy, coordxy, const char *, ...) PRINTF_F(3, 4);
extern void set_msg_dir(int);
extern void set_msg_xy(coordxy, coordxy);
extern void custompline(unsigned, const char *, ...) PRINTF_F(2, 3);
extern void urgent_pline(const char *, ...) PRINTF_F(1, 2);
extern void Norep(const char *, ...) PRINTF_F(1, 2);
+6
View File
@@ -188,6 +188,11 @@ struct debug_flags {
#endif
};
struct accessibility_data {
boolean accessiblemsg; /* use msg_loc for plined messages */
coord msg_loc; /* accessiblemsg: location */
};
/*
* Stuff that really isn't option or platform related and does not
* get saved and restored. They are set and cleared during the game
@@ -438,6 +443,7 @@ struct instance_flags {
extern NEARDATA struct flag flags;
extern NEARDATA struct instance_flags iflags;
extern NEARDATA struct accessibility_data a11y;
/* last_msg values
* Usage:
+3
View File
@@ -135,6 +135,9 @@ static int optfn_##a(int, int, boolean, char *, char *);
"your starting alignment (lawful, neutral, or chaotic)")
/* end of special ordering; remainder of entries are in alphabetical order
*/
NHOPTB(accessiblemsg, Advanced, 0, opt_out, set_in_game,
Off, Yes, No, No, NoAlias, &a11y.accessiblemsg, Term_False,
"add location information to messages")
NHOPTB(acoustics, Advanced, 0, opt_out, set_in_game,
On, Yes, No, No, NoAlias, &flags.acoustics, Term_False,
"can your character hear anything")
+2
View File
@@ -104,6 +104,7 @@ const schar dirs_ord[N_DIRS] =
NEARDATA boolean has_strong_rngseed = FALSE;
struct engr *head_engr;
NEARDATA struct instance_flags iflags;
NEARDATA struct accessibility_data a11y;
/* NOTE: the order of these words exactly corresponds to the
order of oc_material values #define'd in objclass.h. */
const char *materialnm[] = { "mysterious", "liquid", "wax", "organic",
@@ -1057,6 +1058,7 @@ decl_globals_init(void)
ZERO(flags);
ZERO(iflags);
ZERO(a11y);
ZERO(u);
ZERO(ubirthday);
ZERO(urealtime);
+6
View File
@@ -1824,6 +1824,7 @@ find_trap(struct trap *trap)
cleared = TRUE;
}
set_msg_xy(trap->tx, trap->ty);
You("find %s.", an(trapname(trap->ttyp, FALSE)));
if (cleared) {
@@ -1852,6 +1853,7 @@ mfind0(struct monst *mtmp, boolean via_warning)
|| hides_under(mtmp->data)
|| mtmp->data->mlet == S_EEL)) {
if (via_warning && found_something) {
set_msg_xy(x, y);
Your("danger sense causes you to take a second %s.",
Blind ? "to check nearby" : "look close by");
display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
@@ -1871,8 +1873,10 @@ mfind0(struct monst *mtmp, boolean via_warning)
exercise(A_WIS, TRUE);
if (!canspotmon(mtmp)) {
map_invisible(x, y);
set_msg_xy(x, y);
You_feel("an unseen monster!");
} else if (!sensemon(mtmp)) {
set_msg_xy(x, y);
You("find %s.", mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp));
}
return 1;
@@ -1914,6 +1918,7 @@ dosearch0(int aflag) /* intrinsic autosearch vs explicit searching */
exercise(A_WIS, TRUE);
nomul(0);
feel_location(x, y); /* make sure it shows up */
set_msg_xy(x, y);
You("find a hidden door.");
} else if (levl[x][y].typ == SCORR) {
if (rnl(7 - fund))
@@ -1923,6 +1928,7 @@ dosearch0(int aflag) /* intrinsic autosearch vs explicit searching */
exercise(A_WIS, TRUE);
nomul(0);
feel_newsym(x, y); /* make sure it shows up */
set_msg_xy(x, y);
You("find a hidden passage.");
} else {
/* Be careful not to find anything in an SCORR or SDOOR */
+1 -1
View File
@@ -437,7 +437,7 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist)
char *otmpname = distant_name(otmp, doname);
if (flags.verbose)
pline("%s picks up %s.",
pline_xy(omx, omy, "%s picks up %s.",
Monnam(mtmp), otmpname);
}
obj_extract_self(otmp);
+12 -6
View File
@@ -976,7 +976,7 @@ test_move(
Sprintf(buf, "solid stone");
else
Sprintf(buf, "%s", an(firstmatch));
pline("It's %s.", buf);
pline_dir(xytod(dx, dy), "It's %s.", buf);
}
}
return FALSE;
@@ -1116,7 +1116,7 @@ test_move(
if (mode != TEST_TRAV && gc.context.run >= 2
&& !(Blind || Hallucination) && !could_move_onto_boulder(x, y)) {
if (mode == DO_MOVE && flags.mention_walls)
pline("A boulder blocks your path.");
pline_dir(xytod(dx,dy), "A boulder blocks your path.");
return FALSE;
}
if (mode == DO_MOVE) {
@@ -2194,9 +2194,11 @@ avoid_moving_on_trap(coordxy x, coordxy y, boolean msg)
struct trap *trap;
if ((trap = t_at(x, y)) && trap->tseen) {
if (msg && flags.mention_walls)
if (msg && flags.mention_walls) {
set_msg_xy(x, y);
You("stop in front of %s.",
an(trapname(trap->ttyp, FALSE)));
}
return TRUE;
}
return FALSE;
@@ -2222,9 +2224,11 @@ avoid_moving_on_liquid(
polyforms are allowed to move over water */
return FALSE; /* liquid is safe to traverse */
} else if (is_pool_or_lava(x, y) && levl[x][y].seenv) {
if (msg && flags.mention_walls)
if (msg && flags.mention_walls) {
set_msg_xy(x, y);
You("stop at the edge of the %s.",
hliquid(is_pool(x,y) ? "water" : "lava"));
}
return TRUE;
}
return FALSE;
@@ -3522,7 +3526,7 @@ lookaround(void)
if ((gc.context.run != 1 && !is_safemon(mtmp))
|| (infront && !gc.context.travel)) {
if (flags.mention_walls)
pline("%s blocks your path.",
pline_xy(x, y, "%s blocks your path.",
upstart(a_monnam(mtmp)));
goto stop;
}
@@ -3553,8 +3557,10 @@ lookaround(void)
if (x != u.ux && y != u.uy)
continue;
if (gc.context.run != 1 && !gc.context.travel) {
if (flags.mention_walls)
if (flags.mention_walls) {
set_msg_xy(x, y);
You("stop in front of the door.");
}
goto stop;
}
/* we're orthogonal to a closed door, consider it a corridor */
+3
View File
@@ -860,6 +860,7 @@ doopen_indir(coordxy x, coordxy y)
locked = TRUE;
break;
}
set_msg_xy(cc.x, cc.y);
pline("This door%s.", mesg);
if (locked && flags.autounlock) {
struct obj *unlocktool;
@@ -887,6 +888,7 @@ doopen_indir(coordxy x, coordxy y)
/* door is known to be CLOSED */
if (rnl(20) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) {
set_msg_xy(cc.x, cc.y);
pline_The("door opens.");
if (door->doormask & D_TRAPPED) {
b_trapped("door", FINGER);
@@ -899,6 +901,7 @@ doopen_indir(coordxy x, coordxy y)
unblock_point(cc.x, cc.y); /* vision: new see through there */
} else {
exercise(A_STR, TRUE);
set_msg_xy(cc.x, cc.y);
pline_The("door resists!");
}
+7 -4
View File
@@ -63,7 +63,8 @@ cursetxt(struct monst *mtmp, boolean undirected)
else
point_msg = "at you, then curses";
pline("%s points %s.", Monnam(mtmp), point_msg);
pline_xy(mtmp->mx, mtmp->my,
"%s points %s.", Monnam(mtmp), point_msg);
} else if ((!(gm.moves % 4) || !rn2(4))) {
if (!Deaf)
Norep("You hear a mumbled curse."); /* Deaf-aware */
@@ -238,7 +239,7 @@ castmu(
penalizing mspec_used. */
if (!foundyou && thinks_it_foundyou
&& !is_undirected_spell(mattk->adtyp, spellnum)) {
pline("%s casts a spell at %s!",
pline_xy(mtmp->mx, mtmp->my, "%s casts a spell at %s!",
canseemon(mtmp) ? Monnam(mtmp) : "Something",
is_waterwall(mtmp->mux,mtmp->muy) ? "empty water"
: "thin air");
@@ -248,12 +249,14 @@ castmu(
nomul(0);
if (rn2(ml * 10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */
Soundeffect(se_air_crackles, 60);
if (canseemon(mtmp) && !Deaf)
if (canseemon(mtmp) && !Deaf) {
set_msg_xy(mtmp->mx, mtmp->my);
pline_The("air crackles around %s.", mon_nam(mtmp));
}
return M_ATTK_MISS;
}
if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) {
pline("%s casts a spell%s!",
pline_xy(mtmp->mx, mtmp->my, "%s casts a spell%s!",
canspotmon(mtmp) ? Monnam(mtmp) : "Something",
is_undirected_spell(mattk->adtyp, spellnum)
? ""
+6 -5
View File
@@ -35,7 +35,7 @@ hitmsg(struct monst *mtmp, struct attack *mattk)
if same gender, "engagingly" for nymph, normal msg for others. */
if ((compat = could_seduce(mtmp, &gy.youmonst, mattk)) != 0
&& !mtmp->mcan && !mtmp->mspec_used) {
pline("%s %s you %s.", Monst_name,
pline_xy(mtmp->mx, mtmp->my, "%s %s you %s.", Monst_name,
!Blind ? "smiles at" : !Deaf ? "talks to" : "touches",
(compat == 2) ? "engagingly" : "seductively");
} else {
@@ -73,7 +73,7 @@ hitmsg(struct monst *mtmp, struct attack *mattk)
&& gh.hitmsg_prev != NULL
&& mattk == gh.hitmsg_prev + 1
&& mattk->aatyp == gh.hitmsg_prev->aatyp) ? " again" : "";
pline("%s %s%s%s", Monst_name, verb, again, punct);
pline_xy(mtmp->mx, mtmp->my, "%s %s%s%s", Monst_name, verb, again, punct);
}
gh.hitmsg_mid = mtmp->m_id;
gh.hitmsg_prev = mattk;
@@ -90,9 +90,9 @@ missmu(struct monst *mtmp, boolean nearmiss, struct attack *mattk)
map_invisible(mtmp->mx, mtmp->my);
if (could_seduce(mtmp, &gy.youmonst, mattk) && !mtmp->mcan)
pline("%s pretends to be friendly.", Monnam(mtmp));
pline_xy(mtmp->mx, mtmp->my, "%s pretends to be friendly.", Monnam(mtmp));
else
pline("%s %smisses!", Monnam(mtmp),
pline_xy(mtmp->mx, mtmp->my, "%s %smisses!", Monnam(mtmp),
(nearmiss && flags.verbose) ? "just " : "");
stop_occupation();
@@ -132,7 +132,7 @@ mswings(
boolean bash) /* True: polearm used at too close range */
{
if (flags.verbose && !Blind && mon_visible(mtmp)) {
pline("%s %s %s%s %s.", Monnam(mtmp), mswings_verb(otemp, bash),
pline_xy(mtmp->mx, mtmp->my, "%s %s %s%s %s.", Monnam(mtmp), mswings_verb(otemp, bash),
(otemp->quan > 1L) ? "one of " : "", mhis(mtmp), xname(otemp));
}
}
@@ -198,6 +198,7 @@ wildmiss(struct monst *mtmp, struct attack *mattk)
? could_seduce(mtmp, &gy.youmonst, mattk) : 0);
Monst_name = Monnam(mtmp);
set_msg_xy(mtmp->mx, mtmp->my);
if (unotseen) { /* !mtmp->cansee || (Invis && !perceives(mtmp->data)) */
const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
: (mattk->aatyp == AT_KICK) ? "kicks"
+5 -3
View File
@@ -1606,8 +1606,9 @@ mpickgold(register struct monst* mtmp)
add_to_minv(mtmp, gold);
if (cansee(mtmp->mx, mtmp->my)) {
if (flags.verbose && !mtmp->isgd)
pline("%s picks up some %s.", Monnam(mtmp),
mat_idx == GOLD ? "gold" : "money");
pline_xy(mtmp->mx, mtmp->my,
"%s picks up some %s.", Monnam(mtmp),
mat_idx == GOLD ? "gold" : "money");
newsym(mtmp->mx, mtmp->my);
}
}
@@ -1666,7 +1667,8 @@ mpickstuff(struct monst *mtmp)
char *otmpname = distant_name(otmp, doname);
if (flags.verbose)
pline("%s picks up %s.", Monnam(mtmp), otmpname);
pline_xy(mtmp->mx, mtmp->my,
"%s picks up %s.", Monnam(mtmp), otmpname);
}
obj_extract_self(otmp3); /* remove from floor */
(void) mpickobj(mtmp, otmp3); /* may merge and free otmp3 */
+1 -1
View File
@@ -1023,7 +1023,7 @@ thrwmu(struct monst* mtmp)
if (canseemon(mtmp)) {
onm = xname(otmp);
pline("%s %s %s.", Monnam(mtmp),
pline_xy(mtmp->mx, mtmp->my, "%s %s %s.", Monnam(mtmp),
/* "thrusts" or "swings", or "bashes with" if adjacent */
mswings_verb(otmp, (rang <= 2) ? TRUE : FALSE),
obj_is_pname(otmp) ? the(onm) : an(onm));
+59
View File
@@ -92,6 +92,47 @@ pline(const char *line, ...)
va_end(the_args);
}
void
pline_dir(int dir, const char *line, ...)
{
va_list the_args;
set_msg_dir(dir);
va_start(the_args, line);
vpline(line, the_args);
va_end(the_args);
}
void
pline_xy(coordxy x, coordxy y, const char *line, ...)
{
va_list the_args;
set_msg_xy(x, y);
va_start(the_args, line);
vpline(line, the_args);
va_end(the_args);
}
/* set the direction where next message happens */
void
set_msg_dir(int dir)
{
dtoxy(&a11y.msg_loc, dir);
a11y.msg_loc.x += u.ux;
a11y.msg_loc.y += u.uy;
}
/* set the coordinate where next message happens */
void
set_msg_xy(coordxy x, coordxy y)
{
a11y.msg_loc.x = x;
a11y.msg_loc.y = y;
}
static void
vpline(const char *line, va_list the_args)
{
@@ -110,6 +151,24 @@ vpline(const char *line, va_list the_args)
if (gp.program_state.wizkit_wishing)
return;
if (a11y.accessiblemsg && isok(a11y.msg_loc.x,a11y.msg_loc.y)) {
char *tmp;
char *dirstr;
static char dirstrbuf[BUFSZ];
int g = (iflags.getpos_coords == GPCOORDS_NONE)
? GPCOORDS_COMFULL : iflags.getpos_coords;
dirstr = coord_desc(a11y.msg_loc.x, a11y.msg_loc.y, dirstrbuf, g);
a11y.msg_loc.x = a11y.msg_loc.y = 0;
tmp = (char *)alloc(strlen(line) + sizeof ": " + strlen(dirstr));
Strcpy(tmp, dirstr);
Strcat(tmp, ": ");
Strcat(tmp, line);
vpline(tmp, the_args);
free((genericptr_t) tmp);
return;
}
if (!strchr(line, '%')) {
/* format does not specify any substitutions; use it as-is */
ln = (int) strlen(line);
+1 -1
View File
@@ -758,7 +758,7 @@ mdrop_obj(
}
/* obj_no_longer_held(obj); -- done by place_object */
if (verbosely && cansee(omx, omy))
pline("%s drops %s.", Monnam(mon), obj_name);
pline_xy(mon->mx, mon->my, "%s drops %s.", Monnam(mon), obj_name);
if (!flooreffects(obj, omx, omy, "fall")) {
place_object(obj, omx, omy);
stackobj(obj);
+11 -7
View File
@@ -1808,7 +1808,8 @@ trapeffect_pit(
/* openfallingtrap; not inescapable here */
if (in_sight) {
seetrap(trap);
pline("%s doesn't fall into the pit.", Monnam(mtmp));
pline_xy(mtmp->mx, mtmp->my,
"%s doesn't fall into the pit.", Monnam(mtmp));
}
return Trap_Effect_Finished;
}
@@ -1819,8 +1820,9 @@ trapeffect_pit(
if (!passes_walls(mptr))
mtmp->mtrapped = 1;
if (in_sight) {
pline("%s %s into %s pit!", Monnam(mtmp), fallverb,
a_your[trap->madeby_u]);
pline_xy(mtmp->mx, mtmp->my,
"%s %s into %s pit!", Monnam(mtmp), fallverb,
a_your[trap->madeby_u]);
if (mptr == &mons[PM_PIT_VIPER]
|| mptr == &mons[PM_PIT_FIEND])
pline("How pitiful. Isn't that the pits?");
@@ -1872,18 +1874,20 @@ trapeffect_hole(
if (in_sight) {
seetrap(trap);
if (tt == TRAPDOOR)
pline(
pline_xy(mtmp->mx, mtmp->my,
"A trap door opens, but %s doesn't fall through.",
mon_nam(mtmp));
else /* (tt == HOLE) */
pline("%s doesn't fall through the hole.",
Monnam(mtmp));
pline_xy(mtmp->mx, mtmp->my,
"%s doesn't fall through the hole.",
Monnam(mtmp));
}
return Trap_Effect_Finished; /* inescapable = FALSE; */
}
if (inescapable) { /* sokoban hole */
if (in_sight) {
pline("%s seems to be yanked down!", Monnam(mtmp));
pline_xy(mtmp->mx, mtmp->my,
"%s seems to be yanked down!", Monnam(mtmp));
/* suppress message in mlevel_tele_trap() */
in_sight = FALSE;
seetrap(trap);
+1 -1
View File
@@ -4761,7 +4761,7 @@ dobuzz(
goto buzzmonst;
} else if (zap_hit((int) u.uac, 0)) {
range -= 2;
pline("%s hits you!", The(flash_str(fltyp, FALSE)));
pline_dir(xytod(-dx,-dy), "%s hits you!", The(flash_str(fltyp, FALSE)));
if (Reflecting) {
if (!Blind) {
(void) ureflects("But %s reflects from your %s!",