OSDN Git Service

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