Add whatis_filter option to filter eligible map locations for travel

Compound option whatis_filter, filters the eligible map locations
when getting a cursor location for targeting. Accepts 'n' (none),
'v' (map locations in view), or 'a' (map locations in the same area,
eg. room or corridor).
This commit is contained in:
Pasi Kallinen
2017-07-31 16:58:23 +03:00
parent 6b851e0503
commit 439028dcae
13 changed files with 285 additions and 43 deletions

View File

@@ -3741,7 +3741,7 @@ struct {
{ NHKF_GETPOS_INTERESTING_NEXT, 'a', "getpos.all.next" },
{ NHKF_GETPOS_INTERESTING_PREV, 'A', "getpos.all.prev" },
{ NHKF_GETPOS_HELP, '?', "getpos.help" },
{ NHKF_GETPOS_LIMITVIEW, '"', "getpos.inview" },
{ NHKF_GETPOS_LIMITVIEW, '"', "getpos.filter" },
{ NHKF_GETPOS_MENU, '!', "getpos.menu" }
};
@@ -5030,10 +5030,14 @@ dotravel(VOID_ARGS)
}
iflags.getloc_travelmode = TRUE;
if (iflags.menu_requested) {
if (!getpos_menu(&cc, TRUE, GLOC_INTERESTING)) {
int gf = iflags.getloc_filter;
iflags.getloc_filter = GFILTER_VIEW;
if (!getpos_menu(&cc, GLOC_INTERESTING)) {
iflags.getloc_filter = gf;
iflags.getloc_travelmode = FALSE;
return 0;
}
iflags.getloc_filter = gf;
} else {
pline("Where do you want to travel to?");
if (getpos(&cc, TRUE, "the desired destination") < 0) {

View File

@@ -54,6 +54,11 @@ const char *const gloc_descr[NUM_GLOCS][4] = {
"anything interesting" }
};
const char *const gloc_filtertxt[NUM_GFILTER] = {
"",
" in view",
" in this area"
};
void
getpos_help_keyxhelp(tmpwin, k1, k2, gloc)
@@ -69,7 +74,7 @@ int gloc;
iflags.getloc_usemenu ? "get a menu of "
: "move the cursor to ",
gloc_descr[gloc][2 + iflags.getloc_usemenu],
iflags.getloc_limitview ? " in view" : "");
gloc_filtertxt[iflags.getloc_filter]);
putstr(tmpwin, 0, sbuf);
}
@@ -125,7 +130,7 @@ const char *goal;
visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
putstr(tmpwin, 0, sbuf);
Sprintf(sbuf,
"Use '%s' to toggle limiting possible targets to in view only.",
"Use '%s' to change the mode of limiting possible targets.",
visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
putstr(tmpwin, 0, sbuf);
if (!iflags.terrainmode) {
@@ -214,6 +219,99 @@ const void *b;
&& glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
&& !levl[(x)][(y)].seenv)
static struct opvar *gloc_filter_map = (struct opvar *) 0;
#define GLOC_SAME_AREA(x,y) \
(isok((x), (y)) \
&& (selection_getpoint((x),(y), gloc_filter_map)))
static int gloc_filter_floodfill_match_glyph;
int
gloc_filter_classify_glyph(glyph)
int glyph;
{
int c;
if (!glyph_is_cmap(glyph))
return 0;
c = glyph_to_cmap(glyph);
if (is_cmap_room(c) || is_cmap_furniture(c))
return 1;
else if (is_cmap_wall(c) || c == S_tree)
return 2;
else if (is_cmap_corr(c))
return 3;
else if (is_cmap_water(c))
return 4;
else if (is_cmap_lava(c))
return 5;
return 0;
}
STATIC_OVL int
gloc_filter_floodfill_matcharea(x,y)
int x,y;
{
int glyph = back_to_glyph(x, y);
if (!levl[x][y].seenv)
return FALSE;
if (glyph == gloc_filter_floodfill_match_glyph)
return TRUE;
if (gloc_filter_classify_glyph(glyph) == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph))
return TRUE;
return FALSE;
}
void
gloc_filter_floodfill(x,y)
int x,y;
{
gloc_filter_floodfill_match_glyph = back_to_glyph(x,y);
set_selection_floodfillchk(gloc_filter_floodfill_matcharea);
selection_floodfill(gloc_filter_map, x,y, FALSE);
}
void
gloc_filter_init()
{
if (iflags.getloc_filter == GFILTER_AREA) {
if (!gloc_filter_map) {
gloc_filter_map = selection_opvar(NULL);
}
/* special case: if we're in a doorway, try to figure out which
direction we're moving, and use that side of the doorway */
if (IS_DOOR(levl[u.ux][u.uy].typ)) {
if (u.dx || u.dy) {
gloc_filter_floodfill(u.ux + u.dx, u.uy + u.dy);
} else {
/* TODO: maybe add both sides of the doorway? */
}
} else {
gloc_filter_floodfill(u.ux, u.uy);
}
}
}
void
gloc_filter_done()
{
if (gloc_filter_map) {
opvar_free_x(gloc_filter_map);
gloc_filter_map = NULL;
}
}
STATIC_OVL boolean
gather_locs_interesting(x,y, gloc)
int x,y, gloc;
@@ -223,7 +321,13 @@ int x,y, gloc;
*/
int glyph = glyph_at(x, y);
if (iflags.getloc_limitview && !cansee(x,y))
if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x,y))
return FALSE;
if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x,y)
&& !GLOC_SAME_AREA(x-1,y)
&& !GLOC_SAME_AREA(x,y-1)
&& !GLOC_SAME_AREA(x+1,y)
&& !GLOC_SAME_AREA(x,y+1))
return FALSE;
switch (gloc) {
@@ -297,6 +401,9 @@ int gloc;
* Hero's spot will always sort to array[0] because it will always
* be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
*/
gloc_filter_init();
*cnt_p = idx = 0;
for (pass = 0; pass < 2; pass++) {
for (x = 1; x < COLNO; x++)
@@ -318,6 +425,8 @@ int gloc;
else /* end of second pass */
qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu);
} /* pass */
gloc_filter_done();
}
char *
@@ -422,9 +531,8 @@ int cx, cy;
}
boolean
getpos_menu(ccp, fovonly, gloc)
getpos_menu(ccp, gloc)
coord *ccp;
boolean fovonly;
int gloc;
{
coord *garr = DUMMY;
@@ -440,7 +548,8 @@ int gloc;
if (gcount < 2) { /* gcount always includes the hero */
free((genericptr_t) garr);
You("cannot %s %s.",
fovonly ? "see" : "detect", gloc_descr[gloc][0]);
iflags.getloc_filter == GFILTER_VIEW ? "see" : "detect",
gloc_descr[gloc][0]);
return FALSE;
}
@@ -466,7 +575,8 @@ int gloc;
}
Sprintf(tmpbuf, "Pick a target %s%s%s",
gloc_descr[gloc][1], fovonly ? " in view" : "",
gloc_descr[gloc][1],
gloc_filtertxt[iflags.getloc_filter],
iflags.getloc_travelmode ? " for travel" : "");
end_menu(tmpwin, tmpbuf);
pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
@@ -646,7 +756,12 @@ const char *goal;
msg_given = TRUE;
goto nxtc;
} else if (c == Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]) {
iflags.getloc_limitview = !iflags.getloc_limitview;
const char *const view_filters[NUM_GFILTER] = {
"Not limiting targets",
"Limiting targets to in sight",
"Limiting targets to in same area"
};
iflags.getloc_filter = (iflags.getloc_filter + 1) % NUM_GFILTER;
for (i = 0; i < NUM_GLOCS; i++) {
if (garr[i]) {
free((genericptr_t) garr[i]);
@@ -654,8 +769,7 @@ const char *goal;
}
gidx[i] = gcount[i] = 0;
}
pline("%s possible targets to those in sight only.",
iflags.getloc_limitview ? "Limiting" : "Not limiting");
pline("%s.", view_filters[iflags.getloc_filter]);
msg_given = TRUE;
goto nxtc;
} else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]) {
@@ -679,7 +793,7 @@ const char *goal;
if (iflags.getloc_usemenu) {
coord tmpcrd;
if (getpos_menu(&tmpcrd, iflags.getloc_limitview, gloc)) {
if (getpos_menu(&tmpcrd, gloc)) {
cx = tmpcrd.x;
cy = tmpcrd.y;
}

View File

@@ -233,7 +233,6 @@ static struct Bool_Opt {
{ "vt_tiledata", (boolean *) 0, FALSE, SET_IN_FILE },
#endif
{ "whatis_menu", &iflags.getloc_usemenu, FALSE, SET_IN_GAME },
{ "whatis_inview", &iflags.getloc_limitview, FALSE, SET_IN_GAME },
{ "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME },
{ "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME },
#ifdef ZEROCOMP
@@ -403,6 +402,8 @@ static struct Comp_Opt {
#endif
{ "whatis_coord", "show coordinates when auto-describing cursor position",
1, SET_IN_GAME },
{ "whatis_filter", "filter coordinate locations when targeting next or previous",
1, SET_IN_GAME },
{ "windowcolors", "the foreground/background colors of windows", /*WC*/
80, DISP_IN_GAME },
{ "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
@@ -2379,7 +2380,7 @@ boolean tinitial, tfrom_file;
}
fullname = "whatis_coord";
if (match_optname(opts, fullname, 6, TRUE)) {
if (match_optname(opts, fullname, 8, TRUE)) {
if (duplicate)
complain_about_duplicate(opts, 1);
if (negated) {
@@ -2399,6 +2400,33 @@ boolean tinitial, tfrom_file;
return;
}
fullname = "whatis_filter";
if (match_optname(opts, fullname, 8, TRUE)) {
if (duplicate)
complain_about_duplicate(opts, 1);
if (negated) {
iflags.getloc_filter = GFILTER_NONE;
return;
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
char c = lowc(*op);
switch (c) {
case 'n':
iflags.getloc_filter = GFILTER_NONE;
break;
case 'v':
iflags.getloc_filter = GFILTER_VIEW;
break;
case 'a':
iflags.getloc_filter = GFILTER_AREA;
break;
default:
badoption(opts);
}
}
return;
}
fullname = "warnings";
if (match_optname(opts, fullname, 5, TRUE)) {
if (duplicate)
@@ -4283,6 +4311,37 @@ boolean setinitial, setfromfile;
free((genericptr_t) window_pick);
}
destroy_nhwindow(tmpwin);
} else if (!strcmp("whatis_filter", optname)) {
menu_item *window_pick = (menu_item *) 0;
int pick_cnt;
char gf = iflags.getloc_filter;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any = zeroany;
any.a_char = (GFILTER_NONE + 1);
add_menu(tmpwin, NO_GLYPH, &any, 'n',
0, ATR_NONE, "no filtering",
(gf == GFILTER_NONE) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = (GFILTER_VIEW + 1);
add_menu(tmpwin, NO_GLYPH, &any, 'v',
0, ATR_NONE, "in view only",
(gf == GFILTER_VIEW) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = (GFILTER_AREA + 1);
add_menu(tmpwin, NO_GLYPH, &any, 'a',
0, ATR_NONE, "in same area",
(gf == GFILTER_AREA) ? MENU_SELECTED : MENU_UNSELECTED);
end_menu(tmpwin,
"Select location filtering when going for next/previous map position:");
if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &window_pick)) > 0) {
iflags.getloc_filter = (window_pick[0].item.a_char - 1);
/* PICK_ONE doesn't unselect preselected entry when
selecting another one */
if (pick_cnt > 1 && iflags.getloc_filter == gf)
iflags.getloc_filter = (window_pick[1].item.a_char - 1);
free((genericptr_t) window_pick);
}
destroy_nhwindow(tmpwin);
} else if (!strcmp("msg_window", optname)) {
#ifdef TTY_GRAPHICS
/* by Christian W. Cooper */
@@ -5057,6 +5116,11 @@ char *buf;
: (iflags.getpos_coords == GPCOORDS_COMFULL) ? "full compass"
: (iflags.getpos_coords == GPCOORDS_SCREEN) ? "screen"
: "none");
} else if (!strcmp(optname, "whatis_filter")) {
Sprintf(buf, "%s",
(iflags.getloc_filter == GFILTER_VIEW) ? "view"
: (iflags.getloc_filter == GFILTER_AREA) ? "area"
: "none");
} else if (!strcmp(optname, "scores")) {
Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around,
flags.end_own ? "/own" : "");

View File

@@ -36,7 +36,6 @@ STATIC_DCL struct opvar *FDECL(opvar_new_coord, (int, int));
#if 0
STATIC_DCL struct opvar * FDECL(opvar_new_region, (int,int, int,int));
#endif /*0*/
STATIC_DCL void FDECL(opvar_free_x, (struct opvar *));
STATIC_DCL struct opvar *FDECL(opvar_clone, (struct opvar *));
STATIC_DCL struct opvar *FDECL(opvar_var_conversion, (struct sp_coder *,
struct opvar *));
@@ -114,8 +113,6 @@ STATIC_DCL void FDECL(spo_altar, (struct sp_coder *));
STATIC_DCL void FDECL(spo_trap, (struct sp_coder *));
STATIC_DCL void FDECL(spo_gold, (struct sp_coder *));
STATIC_DCL void FDECL(spo_corridor, (struct sp_coder *));
STATIC_DCL struct opvar *FDECL(selection_opvar, (char *));
STATIC_DCL xchar FDECL(selection_getpoint, (int, int, struct opvar *));
STATIC_DCL void FDECL(selection_setpoint, (int, int, struct opvar *, XCHAR_P));
STATIC_DCL struct opvar *FDECL(selection_not, (struct opvar *));
STATIC_DCL struct opvar *FDECL(selection_logical_oper, (struct opvar *,
@@ -126,11 +123,8 @@ STATIC_DCL void FDECL(selection_filter_percent, (struct opvar *, int));
STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *,
BOOLEAN_P));
STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int));
STATIC_DCL void FDECL(set_selection_floodfillchk, (int FDECL((*), (int,int))));
STATIC_DCL int FDECL(floodfillchk_match_under, (int, int));
STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int));
STATIC_DCL void FDECL(selection_floodfill, (struct opvar *, int, int,
BOOLEAN_P));
STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int,
int, int, int));
STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long));
@@ -3776,7 +3770,7 @@ int dir;
STATIC_VAR int FDECL((*selection_flood_check_func), (int, int));
STATIC_VAR schar floodfillchk_match_under_typ;
STATIC_OVL void
void
set_selection_floodfillchk(f)
int FDECL((*f), (int, int));
{
@@ -3799,7 +3793,7 @@ int x, y;
|| levl[x][y].typ == SCORR);
}
STATIC_OVL void
void
selection_floodfill(ov, x, y, diagonals)
struct opvar *ov;
int x, y;