OSDN Git Service

Since struct dirent only holds the last element in the path, build the full path...
[hengband/hengband.git] / src / knowledge / knowledge-features.c
1 /*!
2  * @brief 地形に関する情報を表示する
3  * @date 2020/04/24
4  * @author Hourier
5  */
6
7 #include "knowledge/knowledge-features.h"
8 #include "core/show-file.h"
9 #include "dungeon/dungeon.h"
10 #include "game-option/special-options.h"
11 #include "io-dump/dump-util.h"
12 #include "io/input-key-acceptor.h"
13 #include "knowledge/lighting-level-table.h"
14 #include "monster-race/monster-race.h"
15 #include "term/screen-processor.h"
16 #include "term/term-color-types.h"
17 #include "util/angband-files.h"
18 #include "util/int-char-converter.h"
19 #include "world/world.h"
20
21 /*
22  * Build a list of feature indexes in the given group. Return the number
23  * of features in the group.
24  *
25  * mode & 0x01 : check for non-empty group
26  */
27 static FEAT_IDX collect_features(FEAT_IDX *feat_idx, BIT_FLAGS8 mode)
28 {
29     FEAT_IDX feat_cnt = 0;
30     for (FEAT_IDX i = 0; i < max_f_idx; i++) {
31         feature_type *f_ptr = &f_info[i];
32         if (!f_ptr->name)
33             continue;
34         if (f_ptr->mimic != i)
35             continue;
36
37         feat_idx[feat_cnt++] = i;
38         if (mode & 0x01)
39             break;
40     }
41
42     feat_idx[feat_cnt] = -1;
43     return feat_cnt;
44 }
45
46 /*
47  * Display the features in a group.
48  */
49 static void display_feature_list(int col, int row, int per_page, FEAT_IDX *feat_idx, FEAT_IDX feat_cur, FEAT_IDX feat_top, bool visual_only, int lighting_level)
50 {
51     int lit_col[F_LIT_MAX], i;
52     int f_idx_col = use_bigtile ? 62 : 64;
53
54     lit_col[F_LIT_STANDARD] = use_bigtile ? (71 - F_LIT_MAX) : 71;
55     for (i = F_LIT_NS_BEGIN; i < F_LIT_MAX; i++)
56         lit_col[i] = lit_col[F_LIT_STANDARD] + 2 + (i - F_LIT_NS_BEGIN) * 2 + (use_bigtile ? i : 0);
57
58     for (i = 0; i < per_page && (feat_idx[feat_top + i] >= 0); i++) {
59         TERM_COLOR attr;
60         FEAT_IDX f_idx = feat_idx[feat_top + i];
61         feature_type *f_ptr = &f_info[f_idx];
62         int row_i = row + i;
63         attr = ((i + feat_top == feat_cur) ? TERM_L_BLUE : TERM_WHITE);
64         c_prt(attr, f_name + f_ptr->name, row_i, col);
65         if (per_page == 1) {
66             c_prt(attr, format("(%s)", lighting_level_str[lighting_level]), row_i, col + 1 + strlen(f_name + f_ptr->name));
67             c_prt(attr, format("%02x/%02x", f_ptr->x_attr[lighting_level], f_ptr->x_char[lighting_level]), row_i,
68                 f_idx_col - ((current_world_ptr->wizard || visual_only) ? 6 : 2));
69         }
70         if (current_world_ptr->wizard || visual_only) {
71             c_prt(attr, format("%d", f_idx), row_i, f_idx_col);
72         }
73
74         term_queue_bigchar(lit_col[F_LIT_STANDARD], row_i, f_ptr->x_attr[F_LIT_STANDARD], f_ptr->x_char[F_LIT_STANDARD], 0, 0);
75         term_putch(lit_col[F_LIT_NS_BEGIN], row_i, TERM_SLATE, '(');
76         for (int j = F_LIT_NS_BEGIN + 1; j < F_LIT_MAX; j++) {
77             term_putch(lit_col[j], row_i, TERM_SLATE, '/');
78         }
79
80         term_putch(lit_col[F_LIT_MAX - 1] + (use_bigtile ? 3 : 2), row_i, TERM_SLATE, ')');
81         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
82             term_queue_bigchar(lit_col[j] + 1, row_i, f_ptr->x_attr[j], f_ptr->x_char[j], 0, 0);
83         }
84     }
85
86     for (; i < per_page; i++) {
87         term_erase(col, row + i, 255);
88     }
89 }
90
91 /*
92  * Interact with feature visuals.
93  */
94 void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f_idx, IDX *lighting_level)
95 {
96     TERM_COLOR attr_old[F_LIT_MAX];
97     (void)C_WIPE(attr_old, F_LIT_MAX, TERM_COLOR);
98     SYMBOL_CODE char_old[F_LIT_MAX];
99     (void)C_WIPE(char_old, F_LIT_MAX, SYMBOL_CODE);
100
101     TERM_LEN wid, hgt;
102     term_get_size(&wid, &hgt);
103
104     FEAT_IDX *feat_idx;
105     C_MAKE(feat_idx, max_f_idx, FEAT_IDX);
106
107     concptr feature_group_text[] = { "terrains", NULL };
108     int len;
109     int max = 0;
110     int grp_cnt = 0;
111     int feat_cnt;
112     FEAT_IDX grp_idx[100];
113     TERM_COLOR attr_top = 0;
114     bool visual_list = FALSE;
115     byte char_left = 0;
116     TERM_LEN browser_rows = hgt - 8;
117     if (direct_f_idx < 0) {
118         for (FEAT_IDX i = 0; feature_group_text[i] != NULL; i++) {
119             len = strlen(feature_group_text[i]);
120             if (len > max)
121                 max = len;
122
123             if (collect_features(feat_idx, 0x01)) {
124                 grp_idx[grp_cnt++] = i;
125             }
126         }
127
128         feat_cnt = 0;
129     } else {
130         feature_type *f_ptr = &f_info[direct_f_idx];
131
132         feat_idx[0] = direct_f_idx;
133         feat_cnt = 1;
134         feat_idx[1] = -1;
135
136         (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &f_ptr->x_attr[*lighting_level],
137             &f_ptr->x_char[*lighting_level], need_redraw);
138
139         for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
140             attr_old[i] = f_ptr->x_attr[i];
141             char_old[i] = f_ptr->x_char[i];
142         }
143     }
144
145     grp_idx[grp_cnt] = -1;
146
147     FEAT_IDX old_grp_cur = -1;
148     FEAT_IDX grp_cur = 0;
149     FEAT_IDX grp_top = 0;
150     FEAT_IDX feat_cur = 0;
151     FEAT_IDX feat_top = 0;
152     TERM_LEN column = 0;
153     bool flag = FALSE;
154     bool redraw = TRUE;
155     TERM_COLOR *cur_attr_ptr;
156     SYMBOL_CODE *cur_char_ptr;
157     while (!flag) {
158         char ch;
159         feature_type *f_ptr;
160
161         if (redraw) {
162             clear_from(0);
163
164             prt(_("表示 - 地形", "Visuals - features"), 2, 0);
165             if (direct_f_idx < 0)
166                 prt(_("グループ", "Group"), 4, 0);
167             prt(_("名前", "Name"), 4, max + 3);
168             if (use_bigtile) {
169                 if (current_world_ptr->wizard || visual_only)
170                     prt("Idx", 4, 62);
171                 prt(_("文字 ( l/ d)", "Sym ( l/ d)"), 4, 66);
172             } else {
173                 if (current_world_ptr->wizard || visual_only)
174                     prt("Idx", 4, 64);
175                 prt(_("文字 (l/d)", "Sym (l/d)"), 4, 68);
176             }
177
178             for (FEAT_IDX i = 0; i < 78; i++) {
179                 term_putch(i, 5, TERM_WHITE, '=');
180             }
181
182             if (direct_f_idx < 0) {
183                 for (FEAT_IDX i = 0; i < browser_rows; i++) {
184                     term_putch(max + 1, 6 + i, TERM_WHITE, '|');
185                 }
186             }
187
188             redraw = FALSE;
189         }
190
191         if (direct_f_idx < 0) {
192             if (grp_cur < grp_top)
193                 grp_top = grp_cur;
194             if (grp_cur >= grp_top + browser_rows)
195                 grp_top = grp_cur - browser_rows + 1;
196
197             display_group_list(0, 6, max, browser_rows, grp_idx, feature_group_text, grp_cur, grp_top);
198             if (old_grp_cur != grp_cur) {
199                 old_grp_cur = grp_cur;
200                 feat_cnt = collect_features(feat_idx, 0x00);
201             }
202
203             while (feat_cur < feat_top)
204                 feat_top = MAX(0, feat_top - browser_rows / 2);
205             while (feat_cur >= feat_top + browser_rows)
206                 feat_top = MIN(feat_cnt - browser_rows, feat_top + browser_rows / 2);
207         }
208
209         if (!visual_list) {
210             display_feature_list(max + 3, 6, browser_rows, feat_idx, feat_cur, feat_top, visual_only, F_LIT_STANDARD);
211         } else {
212             feat_top = feat_cur;
213             display_feature_list(max + 3, 6, 1, feat_idx, feat_cur, feat_top, visual_only, *lighting_level);
214             display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
215         }
216
217         prt(format(_("<方向>%s, 'd'で標準光源効果%s, ESC", "<dir>%s, 'd' for default lighting%s, ESC"),
218                 visual_list ? _(", ENTERで決定, 'a'で対象明度変更", ", ENTER to accept, 'a' for lighting level")
219                             : _(", 'v'でシンボル変更", ", 'v' for visuals"),
220                 (attr_idx || char_idx) ? _(", 'c', 'p'でペースト", ", 'c', 'p' to paste") : _(", 'c'でコピー", ", 'c' to copy")),
221             hgt - 1, 0);
222
223         f_ptr = &f_info[feat_idx[feat_cur]];
224         cur_attr_ptr = &f_ptr->x_attr[*lighting_level];
225         cur_char_ptr = &f_ptr->x_char[*lighting_level];
226
227         if (visual_list) {
228             place_visual_list_cursor(max + 3, 7, *cur_attr_ptr, *cur_char_ptr, attr_top, char_left);
229         } else if (!column) {
230             term_gotoxy(0, 6 + (grp_cur - grp_top));
231         } else {
232             term_gotoxy(max + 3, 6 + (feat_cur - feat_top));
233         }
234
235         ch = inkey();
236         if (visual_list && ((ch == 'A') || (ch == 'a'))) {
237             int prev_lighting_level = *lighting_level;
238
239             if (ch == 'A') {
240                 if (*lighting_level <= 0)
241                     *lighting_level = F_LIT_MAX - 1;
242                 else
243                     (*lighting_level)--;
244             } else {
245                 if (*lighting_level >= F_LIT_MAX - 1)
246                     *lighting_level = 0;
247                 else
248                     (*lighting_level)++;
249             }
250
251             if (f_ptr->x_attr[prev_lighting_level] != f_ptr->x_attr[*lighting_level])
252                 attr_top = MAX(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
253
254             if (f_ptr->x_char[prev_lighting_level] != f_ptr->x_char[*lighting_level])
255                 char_left = MAX(0, f_ptr->x_char[*lighting_level] - 10);
256
257             continue;
258         } else if ((ch == 'D') || (ch == 'd')) {
259             TERM_COLOR prev_x_attr = f_ptr->x_attr[*lighting_level];
260             byte prev_x_char = f_ptr->x_char[*lighting_level];
261
262             apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
263
264             if (visual_list) {
265                 if (prev_x_attr != f_ptr->x_attr[*lighting_level])
266                     attr_top = MAX(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
267
268                 if (prev_x_char != f_ptr->x_char[*lighting_level])
269                     char_left = MAX(0, f_ptr->x_char[*lighting_level] - 10);
270             } else
271                 *need_redraw = TRUE;
272
273             continue;
274         } else if (visual_mode_command(ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, cur_attr_ptr, cur_char_ptr, need_redraw)) {
275             switch (ch) {
276             case ESCAPE:
277                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
278                     f_ptr->x_attr[i] = attr_old[i];
279                     f_ptr->x_char[i] = char_old[i];
280                 }
281
282                 /* Fall through */
283             case '\n':
284             case '\r':
285                 if (direct_f_idx >= 0)
286                     flag = TRUE;
287                 else
288                     *lighting_level = F_LIT_STANDARD;
289                 break;
290             case 'V':
291             case 'v':
292                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
293                     attr_old[i] = f_ptr->x_attr[i];
294                     char_old[i] = f_ptr->x_char[i];
295                 }
296                 *lighting_level = F_LIT_STANDARD;
297                 break;
298
299             case 'C':
300             case 'c':
301                 if (!visual_list) {
302                     for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
303                         attr_idx_feat[i] = f_ptr->x_attr[i];
304                         char_idx_feat[i] = f_ptr->x_char[i];
305                     }
306                 }
307                 break;
308
309             case 'P':
310             case 'p':
311                 if (!visual_list) {
312                     for (FEAT_IDX i = F_LIT_NS_BEGIN; i < F_LIT_MAX; i++) {
313                         if (attr_idx_feat[i] || (!(char_idx_feat[i] & 0x80) && char_idx_feat[i]))
314                             f_ptr->x_attr[i] = attr_idx_feat[i];
315                         if (char_idx_feat[i])
316                             f_ptr->x_char[i] = char_idx_feat[i];
317                     }
318                 }
319                 break;
320             }
321             continue;
322         }
323
324         switch (ch) {
325         case ESCAPE: {
326             flag = TRUE;
327             break;
328         }
329
330         default: {
331             browser_cursor(ch, &column, &grp_cur, grp_cnt, &feat_cur, feat_cnt);
332             break;
333         }
334         }
335     }
336
337     C_KILL(feat_idx, max_f_idx, FEAT_IDX);
338 }
339
340 /*
341  * Dungeon
342  */
343 void do_cmd_knowledge_dungeon(player_type *creature_ptr)
344 {
345     FILE *fff = NULL;
346     GAME_TEXT file_name[FILE_NAME_SIZE];
347     if (!open_temporary_file(&fff, file_name))
348         return;
349
350     for (int i = 1; i < current_world_ptr->max_d_idx; i++) {
351         bool seiha = FALSE;
352
353         if (!d_info[i].maxdepth)
354             continue;
355         if (!max_dlv[i])
356             continue;
357         if (d_info[i].final_guardian) {
358             if (!r_info[d_info[i].final_guardian].max_num)
359                 seiha = TRUE;
360         } else if (max_dlv[i] == d_info[i].maxdepth)
361             seiha = TRUE;
362
363         fprintf(fff, _("%c%-12s :  %3d 階\n", "%c%-16s :  level %3d\n"), seiha ? '!' : ' ', d_name + d_info[i].name, (int)max_dlv[i]);
364     }
365
366     angband_fclose(fff);
367     (void)show_file(creature_ptr, TRUE, file_name, _("今までに入ったダンジョン", "Dungeon"), 0, 0);
368     fd_kill(file_name);
369 }