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

@@ -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;
}