+ * Display the features in a group.
+ */
+static void display_feature_list(int col, int row, int per_page, int *feat_idx,
+ int feat_cur, int feat_top)
+{
+ int i;
+
+ /* Display lines until done */
+ for (i = 0; i < per_page && feat_idx[feat_top + i]; i++)
+ {
+ byte attr;
+
+ /* Get the index */
+ int f_idx = feat_idx[feat_top + i];
+
+ /* Access the index */
+ feature_type *f_ptr = &f_info[f_idx];
+
+ /* Choose a color */
+ attr = ((i + feat_top == feat_cur) ? TERM_L_BLUE : TERM_WHITE);
+
+ /* Display the name */
+ c_prt(attr, f_name + f_ptr->name, row + i, col);
+
+ /* Hack -- visual_list mode */
+ if (per_page == 1)
+ {
+ c_prt(attr, format("%02x/%02x", f_ptr->x_attr, f_ptr->x_char), row + i, 60);
+ }
+
+ /* Display symbol */
+ Term_putch(68, row + i, f_ptr->x_attr, f_ptr->x_char);
+
+ if (use_bigtile)
+ {
+ if (f_ptr->x_attr & 0x80)
+ Term_putch(68 + 1, row + i, 255, -1);
+ else
+ Term_putch(68 + 1, row + i, 0, ' ');
+ }
+ }
+
+ /* Clear remaining lines */
+ for (; i < per_page; i++)
+ {
+ Term_erase(col, row + i, 255);
+ }
+}
+
+
+/*
+ * Interact with feature visuals.
+ */
+static void do_cmd_knowledge_features(void)
+{
+ int i, len, max;
+ int grp_cur, grp_top, old_grp_cur;
+ int feat_cur, feat_top;
+ int grp_cnt, grp_idx[100];
+ int feat_cnt;
+ int *feat_idx;
+
+ int column = 0;
+ bool flag;
+ bool redraw;
+
+ bool visual_list = FALSE;
+ byte attr_top = 0, char_left = 0;
+
+ int browser_rows;
+ int wid, hgt;
+
+ /* Get size */
+ Term_get_size(&wid, &hgt);
+
+ browser_rows = hgt - 8;
+
+ /* Allocate the "feat_idx" array */
+ C_MAKE(feat_idx, max_f_idx, int);
+
+ max = 0;
+ grp_cnt = 0;
+
+ /* Check every group */
+ for (i = 0; feature_group_text[i] != NULL; i++)
+ {
+ /* Measure the label */
+ len = strlen(feature_group_text[i]);
+
+ /* Save the maximum length */
+ if (len > max) max = len;
+
+ /* See if any features are known */
+ if (collect_features(i, feat_idx))
+ {
+ /* Build a list of groups with known features */
+ grp_idx[grp_cnt++] = i;
+ }
+ }
+
+ /* Terminate the list */
+ grp_idx[grp_cnt] = -1;
+
+ old_grp_cur = -1;
+ grp_cur = grp_top = 0;
+ feat_cur = feat_top = 0;
+ feat_cnt = 0;
+
+ flag = FALSE;
+ redraw = TRUE;
+
+ while ((!flag) && (grp_cnt))
+ {
+ char ch;
+ feature_type *f_ptr;
+
+ if (redraw)
+ {
+ clear_from(0);
+
+ prt("Visuals - features", 2, 0);
+ prt("Group", 4, 0);
+ prt("Name", 4, max + 3);
+ prt("Sym", 4, 67);
+
+ for (i = 0; i < 78; i++)
+ {
+ Term_putch(i, 5, TERM_WHITE, '=');
+ }
+
+ for (i = 0; i < browser_rows; i++)
+ {
+ Term_putch(max + 1, 6 + i, TERM_WHITE, '|');
+ }
+
+ redraw = FALSE;
+ }
+
+ /* Scroll group list */
+ if (grp_cur < grp_top) grp_top = grp_cur;
+ if (grp_cur >= grp_top + browser_rows) grp_top = grp_cur - browser_rows + 1;
+
+ /* Display a list of feature groups */
+ display_group_list(0, 6, max, browser_rows, grp_idx, feature_group_text, grp_cur, grp_top);
+
+ if (old_grp_cur != grp_cur)
+ {
+ old_grp_cur = grp_cur;
+
+ /* Get a list of features in the current group */
+ feat_cnt = collect_features(grp_idx[grp_cur], feat_idx);
+ }
+
+ /* Scroll feature list */
+ while (feat_cur < feat_top)
+ feat_top = MAX(0, feat_top - browser_rows/2);
+ while (feat_cur >= feat_top + browser_rows)
+ feat_top = MIN(feat_cnt - browser_rows, feat_top + browser_rows/2);
+
+ if (!visual_list)
+ {
+ /* Display a list of features in the current group */
+ display_feature_list(max + 3, 6, browser_rows, feat_idx, feat_cur, feat_top);
+ }
+ else
+ {
+ feat_top = feat_cur;
+
+ /* Display a list of features in the current group */
+ display_feature_list(max + 3, 6, 1, feat_idx, feat_cur, feat_top);
+
+ /* Display visual list below first object */
+ display_visual_list(max + 3, 7, browser_rows-1, wid - (max + 3), attr_top, char_left);
+ }
+
+ /* Prompt */
+#ifdef JP
+ prt(format("<Êý¸þ>%s%s, ESC", visual_list ? ", ENTER¤Ç·èÄê" : ", 'v'¤Ç¥·¥ó¥Ü¥ëÊѹ¹", (attr_idx||char_idx) ? ", 'c', 'p'¤Ç¥Ú¡¼¥¹¥È" : ", 'c'¤Ç¥³¥Ô¡¼"), hgt - 1, 0);
+#else
+ prt(format("<dir>%s%s, ESC", visual_list ? ", ENTER to accept" : ", 'v' for visuals", (attr_idx||char_idx) ? ", 'c', 'p' to paste" : ", 'c' to copy"), hgt - 1, 0);
+#endif
+
+ /* Get the current feature */
+ f_ptr = &f_info[feat_idx[feat_cur]];
+
+ if (visual_list)
+ {
+ int x, y;
+
+ y = 7 + (f_ptr->x_attr - attr_top);
+ if (use_bigtile) x = max + 3 + 2 * (f_ptr->x_char - char_left);
+ else x = max + 3 + (f_ptr->x_char - char_left);
+
+ /* Place the cursor */
+ Term_gotoxy(x, y);
+ }
+ else if (!column)
+ {
+ Term_gotoxy(0, 6 + (grp_cur - grp_top));
+ }
+ else
+ {
+ Term_gotoxy(max + 3, 6 + (feat_cur - feat_top));
+ }
+
+ ch = inkey();
+
+ /* Do visual mode command if needed */
+ if (visual_mode_command(ch, &visual_list, browser_rows-1, wid - (max + 3), &attr_top, &char_left, &f_ptr->x_attr, &f_ptr->x_char)) continue;
+
+ switch (ch)
+ {
+ case ESCAPE:
+ {
+ flag = TRUE;
+ break;
+ }
+
+ default:
+ {
+ /* Move the cursor */
+ browser_cursor(ch, &column, &grp_cur, grp_cnt, &feat_cur, feat_cnt);
+ break;
+ }
+ }
+ }
+
+ /* Prompt */
+ if (!grp_cnt) msg_print("No features known.");
+
+ /* Free the "feat_idx" array */
+ C_KILL(feat_idx, max_f_idx, int);
+}
+
+
+/*
+ * List wanted monsters
+ */