Accessibility: Pick travel/cursor targets from a menu
Adds two new configurable keys to the cursor targeting: 'A' (getpos.menu) and 'a' (getpos.menu.cansee). First one shows a menu of all interesting glyphs on the map, second one shows only those in sight. Travel command also now obeys the "request menu" -prefix, showing the menu with interesting targets in sight, and then traveling there. Idea via the NetHack accessibility research by Alexei Pepers.
This commit is contained in:
+8
-1
@@ -586,7 +586,8 @@ A few other commands (eat food, offer sacrifice, apply tinning-kit) use
|
|||||||
the `m' prefix to skip checking for applicable objects on the floor
|
the `m' prefix to skip checking for applicable objects on the floor
|
||||||
and go straight to checking inventory,
|
and go straight to checking inventory,
|
||||||
or (for ``#loot'' to remove a saddle),
|
or (for ``#loot'' to remove a saddle),
|
||||||
skip containers and go straight to adjacent monsters.
|
skip containers and go straight to adjacent monsters. The prefix will
|
||||||
|
make ``#travel'' command show a menu of interesting targets in sight.
|
||||||
.lp F[yuhjklbn]
|
.lp F[yuhjklbn]
|
||||||
Prefix: fight a monster (even if you only guess one is there).
|
Prefix: fight a monster (even if you only guess one is there).
|
||||||
.lp M[yuhjklbn]
|
.lp M[yuhjklbn]
|
||||||
@@ -1119,6 +1120,8 @@ Tip over a container (bag or box) to pour out its contents.
|
|||||||
Autocompletes. Default key is 'M-T'.
|
Autocompletes. Default key is 'M-T'.
|
||||||
.lp #travel
|
.lp #travel
|
||||||
Travel to a specific location on the map. Default key is '_'.
|
Travel to a specific location on the map. Default key is '_'.
|
||||||
|
Using the ``request menu'' prefix shows a menu of interesting targets in sight
|
||||||
|
without asking to move the cursor.
|
||||||
.lp #turn
|
.lp #turn
|
||||||
Turn undead away. Autocompletes. Default key is 'M-t'.
|
Turn undead away. Autocompletes. Default key is 'M-t'.
|
||||||
.lp #twoweapon
|
.lp #twoweapon
|
||||||
@@ -3212,6 +3215,10 @@ When asked for a location, the key to go to previous closest monster. Default is
|
|||||||
When asked for a location, the key to go to next closest object. Default is 'o'.
|
When asked for a location, the key to go to next closest object. Default is 'o'.
|
||||||
.lp getpos.obj.prev
|
.lp getpos.obj.prev
|
||||||
When asked for a location, the key to go to previous closest object. Default is 'O'.
|
When asked for a location, the key to go to previous closest object. Default is 'O'.
|
||||||
|
.lp getpos.menu
|
||||||
|
When asked for a location, show a menu of all interesting targets. Default is 'A'.
|
||||||
|
.lp getpos.menu.cansee
|
||||||
|
When asked for a location, show a menu of interesting targets in view. Default is 'a'.
|
||||||
.lp getpos.pick
|
.lp getpos.pick
|
||||||
When asked for a location, the key to choose the location, and possibly ask for more info. Default is '.'.
|
When asked for a location, the key to choose the location, and possibly ask for more info. Default is '.'.
|
||||||
.lp getpos.pick.once
|
.lp getpos.pick.once
|
||||||
|
|||||||
+10
-1
@@ -706,7 +706,8 @@ A few other commands (eat food, offer sacrifice, apply tinning-kit) use
|
|||||||
the `{\tt m}' prefix to skip checking for applicable objects on the floor
|
the `{\tt m}' prefix to skip checking for applicable objects on the floor
|
||||||
and go straight to checking inventory,
|
and go straight to checking inventory,
|
||||||
or (for ``{\tt \#loot}'' to remove a saddle),
|
or (for ``{\tt \#loot}'' to remove a saddle),
|
||||||
skip containers and go straight to adjacent monsters.
|
skip containers and go straight to adjacent monsters. The prefix will
|
||||||
|
make ``{\tt \#travel}'' command show a menu of interesting targets in sight.
|
||||||
%.lp
|
%.lp
|
||||||
\item[\tb{F[yuhjklbn]}]
|
\item[\tb{F[yuhjklbn]}]
|
||||||
Prefix: fight a monster (even if you only guess one is there).
|
Prefix: fight a monster (even if you only guess one is there).
|
||||||
@@ -1386,6 +1387,8 @@ Autocompletes. Default key is '{\tt M-T}'.
|
|||||||
%.lp
|
%.lp
|
||||||
\item[\tb{\#travel}]
|
\item[\tb{\#travel}]
|
||||||
Travel to a specific location on the map. Default key is '{\tt _}'.
|
Travel to a specific location on the map. Default key is '{\tt _}'.
|
||||||
|
Using the ``request menu'' prefix shows a menu of interesting targets in sight
|
||||||
|
without asking to move the cursor.
|
||||||
%.lp
|
%.lp
|
||||||
\item[\tb{\#turn}]
|
\item[\tb{\#turn}]
|
||||||
Turn undead away. Autocompletes. Default key is '{\tt M-t}'.
|
Turn undead away. Autocompletes. Default key is '{\tt M-t}'.
|
||||||
@@ -3935,6 +3938,12 @@ When asked for a location, the key to go to next closest object. Default is ``{\
|
|||||||
\item{\bb{getpos.obj.prev}}
|
\item{\bb{getpos.obj.prev}}
|
||||||
When asked for a location, the key to go to previous closest object. Default is ``{\tt O}''.
|
When asked for a location, the key to go to previous closest object. Default is ``{\tt O}''.
|
||||||
%.lp
|
%.lp
|
||||||
|
\item{\bb{getpos.menu}}
|
||||||
|
When asked for a location, show a menu of all interesting targets. Default is '{\tt A}'.
|
||||||
|
%.lp
|
||||||
|
\item{\bb{getpos.menu.cansee}}
|
||||||
|
When asked for a location, show a menu of interesting targets in view. Default is '{\tt a}'.
|
||||||
|
%.lp
|
||||||
\item{\bb{getpos.pick}}
|
\item{\bb{getpos.pick}}
|
||||||
When asked for a location, the key to choose the location, and possibly ask for more info. Default is ``{\tt .}''.
|
When asked for a location, the key to choose the location, and possibly ask for more info. Default is ``{\tt .}''.
|
||||||
%.lp
|
%.lp
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ E void NDECL(heal_legs);
|
|||||||
/* ### do_name.c ### */
|
/* ### do_name.c ### */
|
||||||
|
|
||||||
E char *FDECL(coord_desc, (int, int, char *, CHAR_P));
|
E char *FDECL(coord_desc, (int, int, char *, CHAR_P));
|
||||||
|
E boolean FDECL(getpos_menu, (coord *, boolean));
|
||||||
E int FDECL(getpos, (coord *, BOOLEAN_P, const char *));
|
E int FDECL(getpos, (coord *, BOOLEAN_P, const char *));
|
||||||
E void FDECL(getpos_sethilite, (void (*f)(int)));
|
E void FDECL(getpos_sethilite, (void (*f)(int)));
|
||||||
E void FDECL(new_mname, (struct monst *, int));
|
E void FDECL(new_mname, (struct monst *, int));
|
||||||
|
|||||||
@@ -468,6 +468,8 @@ enum nh_keyfunc {
|
|||||||
NHKF_GETPOS_UNEX_NEXT,
|
NHKF_GETPOS_UNEX_NEXT,
|
||||||
NHKF_GETPOS_UNEX_PREV,
|
NHKF_GETPOS_UNEX_PREV,
|
||||||
NHKF_GETPOS_HELP,
|
NHKF_GETPOS_HELP,
|
||||||
|
NHKF_GETPOS_MENU,
|
||||||
|
NHKF_GETPOS_MENU_FOV,
|
||||||
|
|
||||||
NUM_NHKF
|
NUM_NHKF
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -230,6 +230,7 @@
|
|||||||
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
|
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
|
||||||
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
|
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
|
||||||
#define is_cmap_door(i) ((i) >= S_vodoor && (i) <= S_hcdoor)
|
#define is_cmap_door(i) ((i) >= S_vodoor && (i) <= S_hcdoor)
|
||||||
|
#define is_cmap_wall(i) ((i) >= S_stone && (i) <= S_trwall)
|
||||||
|
|
||||||
struct symdef {
|
struct symdef {
|
||||||
uchar sym;
|
uchar sym;
|
||||||
|
|||||||
@@ -3500,7 +3500,9 @@ struct {
|
|||||||
{ NHKF_GETPOS_DOOR_PREV, 'D', "getpos.door.prev" },
|
{ NHKF_GETPOS_DOOR_PREV, 'D', "getpos.door.prev" },
|
||||||
{ NHKF_GETPOS_UNEX_NEXT, 'x', "getpos.unexplored.next" },
|
{ NHKF_GETPOS_UNEX_NEXT, 'x', "getpos.unexplored.next" },
|
||||||
{ NHKF_GETPOS_UNEX_PREV, 'X', "getpos.unexplored.prev" },
|
{ NHKF_GETPOS_UNEX_PREV, 'X', "getpos.unexplored.prev" },
|
||||||
{ NHKF_GETPOS_HELP, '?', "getpos.help" }
|
{ NHKF_GETPOS_HELP, '?', "getpos.help" },
|
||||||
|
{ NHKF_GETPOS_MENU, 'A', "getpos.menu" },
|
||||||
|
{ NHKF_GETPOS_MENU_FOV, 'a', "getpos.menu.cansee" }
|
||||||
};
|
};
|
||||||
|
|
||||||
boolean
|
boolean
|
||||||
@@ -3763,6 +3765,8 @@ int NDECL((*cmd_func));
|
|||||||
/* 'm' for removing saddle from adjacent monster without checking
|
/* 'm' for removing saddle from adjacent monster without checking
|
||||||
for containers at <u.ux,u.uy> */
|
for containers at <u.ux,u.uy> */
|
||||||
|| cmd_func == doloot
|
|| cmd_func == doloot
|
||||||
|
/* travel: pop up a menu of interesting targets in view */
|
||||||
|
|| cmd_func == dotravel
|
||||||
/* 'm' prefix allowed for some extended commands */
|
/* 'm' prefix allowed for some extended commands */
|
||||||
|| cmd_func == doextcmd || cmd_func == doextlist)
|
|| cmd_func == doextcmd || cmd_func == doextlist)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -4665,11 +4669,18 @@ dotravel(VOID_ARGS)
|
|||||||
cc.y = u.uy;
|
cc.y = u.uy;
|
||||||
}
|
}
|
||||||
iflags.getloc_travelmode = TRUE;
|
iflags.getloc_travelmode = TRUE;
|
||||||
pline("Where do you want to travel to?");
|
if (iflags.menu_requested) {
|
||||||
if (getpos(&cc, TRUE, "the desired destination") < 0) {
|
if (!getpos_menu(&cc, TRUE)) {
|
||||||
/* user pressed ESC */
|
iflags.getloc_travelmode = FALSE;
|
||||||
iflags.getloc_travelmode = FALSE;
|
return 0;
|
||||||
return 0;
|
}
|
||||||
|
} else {
|
||||||
|
pline("Where do you want to travel to?");
|
||||||
|
if (getpos(&cc, TRUE, "the desired destination") < 0) {
|
||||||
|
/* user pressed ESC */
|
||||||
|
iflags.getloc_travelmode = FALSE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iflags.getloc_travelmode = FALSE;
|
iflags.getloc_travelmode = FALSE;
|
||||||
iflags.travelcc.x = u.tx = cc.x;
|
iflags.travelcc.x = u.tx = cc.x;
|
||||||
|
|||||||
+90
-1
@@ -88,6 +88,12 @@ const char *goal;
|
|||||||
visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]));
|
visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]));
|
||||||
putstr(tmpwin, 0, sbuf);
|
putstr(tmpwin, 0, sbuf);
|
||||||
}
|
}
|
||||||
|
Sprintf(sbuf, "Use '%s' for a menu of interesting targets in view.",
|
||||||
|
visctrl(Cmd.spkeys[NHKF_GETPOS_MENU_FOV]));
|
||||||
|
putstr(tmpwin, 0, sbuf);
|
||||||
|
Sprintf(sbuf, "Use '%s' for a menu of all interesting targets.",
|
||||||
|
visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
|
||||||
|
putstr(tmpwin, 0, sbuf);
|
||||||
if (!iflags.terrainmode) {
|
if (!iflags.terrainmode) {
|
||||||
char kbuf[BUFSZ];
|
char kbuf[BUFSZ];
|
||||||
if (getpos_hilitefunc) {
|
if (getpos_hilitefunc) {
|
||||||
@@ -174,7 +180,10 @@ enum gloctypes {
|
|||||||
GLOC_DOOR,
|
GLOC_DOOR,
|
||||||
GLOC_EXPLORE,
|
GLOC_EXPLORE,
|
||||||
|
|
||||||
NUM_GLOCS
|
NUM_GLOCS,
|
||||||
|
|
||||||
|
GLOC_INTERESTING,
|
||||||
|
GLOC_INTERESTING_FOV
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -222,6 +231,23 @@ int x,y, gloc;
|
|||||||
|| IS_UNEXPLORED_LOC(x - 1, y)
|
|| IS_UNEXPLORED_LOC(x - 1, y)
|
||||||
|| IS_UNEXPLORED_LOC(x, y + 1)
|
|| IS_UNEXPLORED_LOC(x, y + 1)
|
||||||
|| IS_UNEXPLORED_LOC(x, y - 1)));
|
|| IS_UNEXPLORED_LOC(x, y - 1)));
|
||||||
|
case GLOC_INTERESTING_FOV:
|
||||||
|
if (!cansee(x,y))
|
||||||
|
return FALSE;
|
||||||
|
case GLOC_INTERESTING:
|
||||||
|
return gather_locs_interesting(x,y, GLOC_DOOR)
|
||||||
|
|| !(glyph_is_cmap(glyph)
|
||||||
|
&& (is_cmap_wall(glyph_to_cmap(glyph))
|
||||||
|
|| glyph_to_cmap(glyph) == S_tree
|
||||||
|
|| glyph_to_cmap(glyph) == S_ice
|
||||||
|
|| glyph_to_cmap(glyph) == S_air
|
||||||
|
|| glyph_to_cmap(glyph) == S_cloud
|
||||||
|
|| (glyph_to_cmap(glyph) == S_water && Is_waterlevel(&u.uz))
|
||||||
|
|| glyph_to_cmap(glyph) == S_ndoor
|
||||||
|
|| glyph_to_cmap(glyph) == S_room
|
||||||
|
|| glyph_to_cmap(glyph) == S_darkroom
|
||||||
|
|| glyph_to_cmap(glyph) == S_corr
|
||||||
|
|| glyph_to_cmap(glyph) == S_litcorr));
|
||||||
}
|
}
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -370,6 +396,61 @@ int cx, cy;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean
|
||||||
|
getpos_menu(ccp, fovonly)
|
||||||
|
coord *ccp;
|
||||||
|
boolean fovonly;
|
||||||
|
{
|
||||||
|
coord *garr = DUMMY;
|
||||||
|
int gcount = 0;
|
||||||
|
winid tmpwin;
|
||||||
|
anything any;
|
||||||
|
int i, pick_cnt;
|
||||||
|
menu_item *picks = (menu_item *) 0;
|
||||||
|
char tmpbuf[BUFSZ];
|
||||||
|
|
||||||
|
gather_locs(&garr, &gcount,
|
||||||
|
fovonly ? GLOC_INTERESTING_FOV : GLOC_INTERESTING);
|
||||||
|
if (gcount < 2) { /* gcount always includes the hero */
|
||||||
|
You("cannot %s anything interesting.", fovonly ? "see" : "detect");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpwin = create_nhwindow(NHW_MENU);
|
||||||
|
start_menu(tmpwin);
|
||||||
|
any = zeroany;
|
||||||
|
|
||||||
|
for (i = 0; i < gcount; i++) {
|
||||||
|
char fullbuf[BUFSZ];
|
||||||
|
coord tmpcc;
|
||||||
|
const char *firstmatch = "unknown";
|
||||||
|
int sym = 0;
|
||||||
|
any.a_int = i + 1;
|
||||||
|
tmpcc.x = garr[i].x;
|
||||||
|
tmpcc.y = garr[i].y;
|
||||||
|
if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) {
|
||||||
|
(void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords);
|
||||||
|
Sprintf(fullbuf, "%s%s%s", firstmatch, (*tmpbuf ? " " : ""), tmpbuf);
|
||||||
|
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf,
|
||||||
|
MENU_UNSELECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprintf(tmpbuf, "Pick a target%s%s",
|
||||||
|
fovonly ? " in view" : "",
|
||||||
|
iflags.getloc_travelmode ? " for travel" : "");
|
||||||
|
end_menu(tmpwin, tmpbuf);
|
||||||
|
pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
|
||||||
|
destroy_nhwindow(tmpwin);
|
||||||
|
if (pick_cnt > 0) {
|
||||||
|
ccp->x = garr[picks->item.a_int - 1].x;
|
||||||
|
ccp->y = garr[picks->item.a_int - 1].y;
|
||||||
|
free((genericptr_t) picks);
|
||||||
|
}
|
||||||
|
free((genericptr_t) garr);
|
||||||
|
return (pick_cnt > 0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
getpos(ccp, force, goal)
|
getpos(ccp, force, goal)
|
||||||
coord *ccp;
|
coord *ccp;
|
||||||
@@ -533,6 +614,14 @@ const char *goal;
|
|||||||
show_goal_msg = TRUE;
|
show_goal_msg = TRUE;
|
||||||
msg_given = TRUE;
|
msg_given = TRUE;
|
||||||
goto nxtc;
|
goto nxtc;
|
||||||
|
} else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]
|
||||||
|
|| c == Cmd.spkeys[NHKF_GETPOS_MENU_FOV]) {
|
||||||
|
coord tmpcrd;
|
||||||
|
if (getpos_menu(&tmpcrd, (c == Cmd.spkeys[NHKF_GETPOS_MENU_FOV]))) {
|
||||||
|
cx = tmpcrd.x;
|
||||||
|
cy = tmpcrd.y;
|
||||||
|
}
|
||||||
|
goto nxtc;
|
||||||
} else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
|
} else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
|
||||||
/* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
|
/* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
|
||||||
to achieve that except by manually cycling through all spots */
|
to achieve that except by manually cycling through all spots */
|
||||||
|
|||||||
Reference in New Issue
Block a user