From: Pasi Kallinen Date: Wed, 11 Mar 2015 15:16:05 +0000 (+0200) Subject: getpos improvements: automatic description X-Git-Tag: NetHack-3.6.0_RC01~614 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3243b332a3b25fcab04ee462977af6e0ad586d19;p=nethack 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. --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index f6519a6f7..89646e389 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/src/do_name.c b/src/do_name.c index 4face203e..ce538adb4 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -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]; diff --git a/src/pager.c b/src/pager.c index 459a6daf4..af36ba6e0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -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) {