getpos improvements: automatic description

Pressing '@' will move the cursor on top of the hero.
Pressing '#' will toggle automatic description mode, where
the feature under the cursor is automatically described
when the cursor is moved.
This commit is contained in:
Pasi Kallinen
2015-03-11 17:16:05 +02:00
parent 64b3c6460a
commit 3243b332a3
3 changed files with 271 additions and 202 deletions

View File

@@ -1080,6 +1080,9 @@ Add database entry for shuriken and make it match throwing star
Add database entry for fedora
Add database entry for land mine
change command X to twoweapon toggle
pressing @ when cursor positioning moves cursor on top of hero
pressing # when cursor positioning toggles automatic description of features
under the cursor
Platform- and/or Interface-Specific New Features

View File

@@ -40,6 +40,8 @@ const char *goal;
putstr(tmpwin, 0, sbuf);
putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
putstr(tmpwin, 0, "Use @ to move the cursor on yourself.");
putstr(tmpwin, 0, "Use # to toggle automatic description.");
/* disgusting hack; the alternate selection characters work for any
getpos call, but they only matter for dowhatis (and doquickwhatis) */
doing_what_is = (goal == what_is_an_unknown_object);
@@ -63,6 +65,8 @@ const char *goal;
int cx, cy, i, c;
int sidx, tx, ty;
boolean msg_given = TRUE; /* clear message window by default */
boolean auto_msg = FALSE;
boolean show_goal_msg = FALSE;
static const char pick_chars[] = ".,;:";
const char *cp;
@@ -82,7 +86,32 @@ const char *goal;
lock_mouse_cursor(TRUE);
#endif
for (;;) {
if (show_goal_msg) {
pline("Move cursor to %s:", goal);
curs(WIN_MAP, cx, cy);
flush_screen(0);
show_goal_msg = FALSE;
} else if (auto_msg && !msg_given) {
coord cc;
int sym = 0;
char tmpbuf[BUFSZ];
char *firstmatch = NULL;
cc.x = cx;
cc.y = cy;
if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) {
/* there may be an encoded glyph */
putmixed(WIN_MESSAGE, 0, tmpbuf);
curs(WIN_MAP, cx, cy);
flush_screen(0);
}
}
c = nh_poskey(&tx, &ty, &sidx);
if (auto_msg)
msg_given = FALSE;
if (c == '\033') {
cx = cy = -10;
msg_given = TRUE; /* force clear */
@@ -142,8 +171,20 @@ const char *goal;
else /* ^R */
docrt(); /* redraw */
/* update message window to reflect that we're still targetting */
pline("Move cursor to %s:", goal);
show_goal_msg = TRUE;
msg_given = TRUE;
} else if (c == '#') {
auto_msg = !auto_msg;
pline("Automatic description %sis %s.",
flags.verbose ? "of features under cursor " : "",
auto_msg ? "on" : "off");
if (!auto_msg) show_goal_msg = TRUE;
msg_given = TRUE;
goto nxtc;
} else if (c == '@') {
cx = u.ux;
cy = u.uy;
goto nxtc;
} else {
if (!index(quitchars, c)) {
char matching[MAXPCHARS];

View File

@@ -437,6 +437,229 @@ bad_data_file: impossible("'data' file in wrong format");
(void) dlb_fclose(fp);
}
int
do_screen_description(cc, looked, sym, out_str, firstmatch)
coord cc;
boolean looked;
int sym;
char *out_str;
const char **firstmatch;
{
boolean need_to_look = FALSE;
int glyph;
char look_buf[BUFSZ], prefix[BUFSZ];
int found = 0; /* count of matching syms found */
int i;
int skipped_venom = 0;
boolean hit_trap;
const char *x_str;
static const char *mon_interior = "the interior of a monster";
struct permonst *pm = NULL;
if (looked) {
int oc, so;
unsigned os;
glyph = glyph_at(cc.x,cc.y);
/* Convert the glyph at the selected position to a symbol. */
so = mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
}
if (looked)
Sprintf(prefix, "%s ", encglyph(glyph));
else
Sprintf(prefix, "%c ", sym);
/*
* Check all the possibilities, saving all explanations in a buffer.
* When all have been checked then the string is printed.
*/
/* Check for monsters */
for (i = 0; i < MAXMCLASSES; i++) {
if (sym == ((looked) ?
showsyms[i + SYM_OFF_M] : def_monsyms[i].sym) &&
def_monsyms[i].explain) {
need_to_look = TRUE;
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_monsyms[i].explain));
*firstmatch = def_monsyms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_monsyms[i].explain));
}
}
}
/* handle '@' as a special case if it refers to you and you're
playing a character which isn't normally displayed by that
symbol; firstmatch is assumed to already be set for '@' */
if (((looked) ?
(sym == showsyms[S_HUMAN + SYM_OFF_M] && cc.x == u.ux && cc.y == u.uy) :
(sym == def_monsyms[S_HUMAN].sym && !flags.showrace)) &&
!(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
found += append_str(out_str, "you"); /* tack on "or you" */
/*
* Special case: if identifying from the screen, and we're swallowed,
* and looking at something other than our own symbol, then just say
* "the interior of a monster".
*/
if (u.uswallow && (looked) && is_swallow_sym(sym)) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix, mon_interior);
*firstmatch = mon_interior;
} else {
found += append_str(out_str, mon_interior);
}
need_to_look = TRUE;
}
/* Now check for objects */
for (i = 1; i < MAXOCLASSES; i++) {
if (sym == ((looked) ?
showsyms[i + SYM_OFF_O] : def_oc_syms[i].sym)) {
need_to_look = TRUE;
if ((looked) && i == VENOM_CLASS) {
skipped_venom++;
continue;
}
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_oc_syms[i].explain));
*firstmatch = def_oc_syms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_oc_syms[i].explain));
}
}
}
if (sym == DEF_INVISIBLE) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix,
an(invisexplain));
*firstmatch = invisexplain;
found++;
} else {
found += append_str(out_str, an(invisexplain));
}
}
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
/* Now check for graphics symbols */
for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
x_str = defsyms[i].explanation;
if (sym == ((looked) ?
showsyms[i] : defsyms[i].sym) && *x_str) {
/* avoid "an air", "a water", or "a floor of a room" */
int article = (i == S_room) ? 2 : /* 2=>"the" */
!(strcmp(x_str, "air") == 0 || /* 1=>"an" */
strcmp(x_str, "water") == 0); /* 0=>(none)*/
if (!found) {
if (is_cmap_trap(i)) {
Sprintf(out_str, "%sa trap", prefix);
hit_trap = TRUE;
} else {
Sprintf(out_str, "%s%s",
prefix,
article == 2 ? the(x_str) :
article == 1 ? an(x_str) : x_str);
}
*firstmatch = x_str;
found++;
} else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) &&
!(found >= 3 && is_cmap_drawbridge(i))) {
found += append_str(out_str,
article == 2 ? the(x_str) :
article == 1 ? an(x_str) : x_str);
if (is_cmap_trap(i)) hit_trap = TRUE;
}
if (i == S_altar || is_cmap_trap(i))
need_to_look = TRUE;
}
}
/* Now check for warning symbols */
for (i = 1; i < WARNCOUNT; i++) {
x_str = def_warnsyms[i].explanation;
if (sym == ((looked) ?
warnsyms[i] : def_warnsyms[i].sym)) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix, def_warnsyms[i].explanation);
*firstmatch = def_warnsyms[i].explanation;
found++;
} else {
found += append_str(out_str, def_warnsyms[i].explanation);
}
/* Kludge: warning trumps boulders on the display.
Reveal the boulder too or player can get confused */
if ((looked) && sobj_at(BOULDER, cc.x, cc.y))
Strcat(out_str, " co-located with a boulder");
break; /* out of for loop*/
}
}
/* if we ignored venom and list turned out to be short, put it back */
if (skipped_venom && found < 2) {
x_str = def_oc_syms[VENOM_CLASS].explain;
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(x_str));
*firstmatch = x_str;
found++;
} else {
found += append_str(out_str, an(x_str));
}
}
/* handle optional boulder symbol as a special case */
if (iflags.bouldersym && sym == iflags.bouldersym) {
if (!found) {
*firstmatch = "boulder";
Sprintf(out_str, "%s%s",
prefix, an(*firstmatch));
found++;
} else {
found += append_str(out_str, "boulder");
}
}
/*
* If we are looking at the screen, follow multiple possibilities or
* an ambiguous explanation by something more detailed.
*/
if (looked) {
if (found > 1 || need_to_look) {
char monbuf[BUFSZ];
char temp_buf[BUFSZ];
pm = lookat(cc.x, cc.y, look_buf, monbuf);
*firstmatch = look_buf;
if (*(*firstmatch)) {
Sprintf(temp_buf, " (%s)", *firstmatch);
(void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
found = 1; /* we have something to look up */
}
if (monbuf[0]) {
Sprintf(temp_buf, " [seen: %s]", monbuf);
(void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
}
}
}
return found;
}
/* getpos() return values */
#define LOOK_TRADITIONAL 0 /* '.' -- ask about "more info?" */
#define LOOK_QUICK 1 /* ',' -- skip "more info?" */
@@ -453,19 +676,15 @@ do_look(mode, click_cc)
{
boolean quick = (mode == 1); /* use cursor && don't search for "more info" */
boolean clicklook = (mode == 2); /* right mouse-click method */
char out_str[BUFSZ], look_buf[BUFSZ], prefix[BUFSZ];
const char *x_str, *firstmatch = 0;
char out_str[BUFSZ];
const char *firstmatch = 0;
struct permonst *pm = 0;
int glyph; /* glyph at selected position */
int i, ans = 0;
int sym; /* typed symbol or converted glyph */
int found; /* count of matching syms found */
coord cc; /* screen pos of unknown glyph */
boolean save_verbose; /* saved value of flags.verbose */
boolean from_screen; /* question from the screen */
boolean need_to_look; /* need to get explan. from glyph */
boolean hit_trap; /* true if found trap explanation */
int skipped_venom; /* non-zero if we ignored "splash of venom" */
static const char *mon_interior = "the interior of a monster";
if (!clicklook) {
@@ -506,9 +725,7 @@ do_look(mode, click_cc)
*/
do {
/* Reset some variables. */
need_to_look = FALSE;
pm = (struct permonst *)0;
skipped_venom = 0;
found = 0;
out_str[0] = '\0';
@@ -529,201 +746,9 @@ do_look(mode, click_cc)
}
flags.verbose = FALSE; /* only print long question once */
}
glyph = glyph_at(cc.x,cc.y);
/* Convert the glyph at the selected position to a symbol. */
so = mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
}
if (from_screen || clicklook)
Sprintf(prefix, "%s ", encglyph(glyph));
else
Sprintf(prefix, "%c ", sym);
/*
* Check all the possibilities, saving all explanations in a buffer.
* When all have been checked then the string is printed.
*/
/* Check for monsters */
for (i = 0; i < MAXMCLASSES; i++) {
if (sym == ((from_screen || clicklook) ?
showsyms[i + SYM_OFF_M] : def_monsyms[i].sym) &&
def_monsyms[i].explain) {
need_to_look = TRUE;
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_monsyms[i].explain));
firstmatch = def_monsyms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_monsyms[i].explain));
}
}
}
/* handle '@' as a special case if it refers to you and you're
playing a character which isn't normally displayed by that
symbol; firstmatch is assumed to already be set for '@' */
if (((from_screen || clicklook) ?
(sym == showsyms[S_HUMAN + SYM_OFF_M] && cc.x == u.ux && cc.y == u.uy) :
(sym == def_monsyms[S_HUMAN].sym && !flags.showrace)) &&
!(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
found += append_str(out_str, "you"); /* tack on "or you" */
/*
* Special case: if identifying from the screen, and we're swallowed,
* and looking at something other than our own symbol, then just say
* "the interior of a monster".
*/
if (u.uswallow && (from_screen || clicklook) && is_swallow_sym(sym)) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix, mon_interior);
firstmatch = mon_interior;
} else {
found += append_str(out_str, mon_interior);
}
need_to_look = TRUE;
}
/* Now check for objects */
for (i = 1; i < MAXOCLASSES; i++) {
if (sym == ((from_screen || clicklook) ?
showsyms[i + SYM_OFF_O] : def_oc_syms[i].sym)) {
need_to_look = TRUE;
if ((from_screen || clicklook) && i == VENOM_CLASS) {
skipped_venom++;
continue;
}
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_oc_syms[i].explain));
firstmatch = def_oc_syms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_oc_syms[i].explain));
}
}
}
if (sym == DEF_INVISIBLE) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix,
an(invisexplain));
firstmatch = invisexplain;
found++;
} else {
found += append_str(out_str, an(invisexplain));
}
}
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
/* Now check for graphics symbols */
for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
x_str = defsyms[i].explanation;
if (sym == ((from_screen || clicklook) ?
showsyms[i] : defsyms[i].sym) && *x_str) {
/* avoid "an air", "a water", or "a floor of a room" */
int article = (i == S_room) ? 2 : /* 2=>"the" */
!(strcmp(x_str, "air") == 0 || /* 1=>"an" */
strcmp(x_str, "water") == 0); /* 0=>(none)*/
if (!found) {
if (is_cmap_trap(i)) {
Sprintf(out_str, "%sa trap", prefix);
hit_trap = TRUE;
} else {
Sprintf(out_str, "%s%s",
prefix,
article == 2 ? the(x_str) :
article == 1 ? an(x_str) : x_str);
}
firstmatch = x_str;
found++;
} else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) &&
!(found >= 3 && is_cmap_drawbridge(i))) {
found += append_str(out_str,
article == 2 ? the(x_str) :
article == 1 ? an(x_str) : x_str);
if (is_cmap_trap(i)) hit_trap = TRUE;
}
if (i == S_altar || is_cmap_trap(i))
need_to_look = TRUE;
}
}
/* Now check for warning symbols */
for (i = 1; i < WARNCOUNT; i++) {
x_str = def_warnsyms[i].explanation;
if (sym == ((from_screen || clicklook) ?
warnsyms[i] : def_warnsyms[i].sym)) {
if (!found) {
Sprintf(out_str, "%s%s",
prefix, def_warnsyms[i].explanation);
firstmatch = def_warnsyms[i].explanation;
found++;
} else {
found += append_str(out_str, def_warnsyms[i].explanation);
}
/* Kludge: warning trumps boulders on the display.
Reveal the boulder too or player can get confused */
if ((from_screen || clicklook) && sobj_at(BOULDER, cc.x, cc.y))
Strcat(out_str, " co-located with a boulder");
break; /* out of for loop*/
}
}
/* if we ignored venom and list turned out to be short, put it back */
if (skipped_venom && found < 2) {
x_str = def_oc_syms[VENOM_CLASS].explain;
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(x_str));
firstmatch = x_str;
found++;
} else {
found += append_str(out_str, an(x_str));
}
}
/* handle optional boulder symbol as a special case */
if (iflags.bouldersym && sym == iflags.bouldersym) {
if (!found) {
firstmatch = "boulder";
Sprintf(out_str, "%s%s",
prefix, an(firstmatch));
found++;
} else {
found += append_str(out_str, "boulder");
}
}
/*
* If we are looking at the screen, follow multiple possibilities or
* an ambiguous explanation by something more detailed.
*/
if (from_screen || clicklook) {
if (found > 1 || need_to_look) {
char monbuf[BUFSZ];
char temp_buf[BUFSZ];
pm = lookat(cc.x, cc.y, look_buf, monbuf);
firstmatch = look_buf;
if (*firstmatch) {
Sprintf(temp_buf, " (%s)", firstmatch);
(void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
found = 1; /* we have something to look up */
}
if (monbuf[0]) {
Sprintf(temp_buf, " [seen: %s]", monbuf);
(void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
}
}
}
found = do_screen_description(cc, (from_screen||clicklook), sym, out_str, &firstmatch);
/* Finally, print out our explanation. */
if (found) {