OSDN Git Service

Merge pull request #1539 from habu1010/feature/refactor-monster-evol-spoiler
[hengbandforosx/hengbandosx.git] / src / knowledge / knowledge-items.cpp
1 /*!
2  * @brief 既知のアイテムとアーティファクトを表示する
3  * @date 2020/04/23
4  * @author Hourier
5  */
6
7 #include "knowledge/knowledge-items.h"
8 #include "core/show-file.h"
9 #include "core/stuff-handler.h"
10 #include "flavor/flavor-describer.h"
11 #include "flavor/object-flavor-types.h"
12 #include "flavor/object-flavor.h"
13 #include "game-option/special-options.h"
14 #include "inventory/inventory-slot-types.h"
15 #include "io-dump/dump-util.h"
16 #include "io/input-key-acceptor.h"
17 #include "knowledge/object-group-table.h"
18 #include "object-enchant/special-object-flags.h"
19 #include "object/object-kind-hook.h"
20 #include "object/object-kind.h"
21 #include "perception/identification.h"
22 #include "perception/object-perception.h"
23 #include "system/artifact-type-definition.h"
24 #include "system/floor-type-definition.h"
25 #include "system/grid-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "term/screen-processor.h"
28 #include "term/term-color-types.h"
29 #include "util/angband-files.h"
30 #include "util/int-char-converter.h"
31 #include "util/sort.h"
32 #include "view/display-messages.h"
33 #include "world/world.h"
34
35 /*! 
36  * @brief Check the status of "artifacts"
37  * @param player_ptr プレイヤーへの参照ポインタ
38  * @todo okay = 既知のアーティファクト? と思われるが確証がない分かりやすい変数名へ変更求む&万が一未知である旨の配列なら負論理なのでゴソッと差し替えるべき
39  */
40 void do_cmd_knowledge_artifacts(player_type *player_ptr)
41 {
42     FILE *fff = nullptr;
43     GAME_TEXT file_name[FILE_NAME_SIZE];
44     if (!open_temporary_file(&fff, file_name))
45         return;
46
47     ARTIFACT_IDX *who;
48     C_MAKE(who, max_a_idx, ARTIFACT_IDX);
49     bool *okay;
50     C_MAKE(okay, max_a_idx, bool);
51
52     for (ARTIFACT_IDX k = 0; k < max_a_idx; k++) {
53         artifact_type *a_ptr = &a_info[k];
54         okay[k] = false;
55         if (a_ptr->name.empty())
56             continue;
57         if (!a_ptr->cur_num)
58             continue;
59
60         okay[k] = true;
61     }
62
63     for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++) {
64         for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
65             grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
66             for (const auto this_o_idx : g_ptr->o_idx_list) {
67                 object_type *o_ptr;
68                 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
69                 if (!o_ptr->is_fixed_artifact())
70                     continue;
71                 if (o_ptr->is_known())
72                     continue;
73
74                 okay[o_ptr->name1] = false;
75             }
76         }
77     }
78
79     for (ARTIFACT_IDX i = 0; i < INVEN_TOTAL; i++) {
80         object_type *o_ptr = &player_ptr->inventory_list[i];
81         if (!o_ptr->k_idx)
82             continue;
83         if (!o_ptr->is_fixed_artifact())
84             continue;
85         if (o_ptr->is_known())
86             continue;
87
88         okay[o_ptr->name1] = false;
89     }
90
91     int n = 0;
92     for (ARTIFACT_IDX k = 0; k < max_a_idx; k++) {
93         if (okay[k])
94             who[n++] = k;
95     }
96
97     uint16_t why = 3;
98     ang_sort(player_ptr, who, &why, n, ang_sort_art_comp, ang_sort_art_swap);
99     for (ARTIFACT_IDX k = 0; k < n; k++) {
100         artifact_type *a_ptr = &a_info[who[k]];
101         GAME_TEXT base_name[MAX_NLEN];
102         strcpy(base_name, _("未知の伝説のアイテム", "Unknown Artifact"));
103         ARTIFACT_IDX z = lookup_kind(a_ptr->tval, a_ptr->sval);
104         if (z) {
105             object_type forge;
106             object_type *q_ptr;
107             q_ptr = &forge;
108             q_ptr->prep(z);
109             q_ptr->name1 = who[k];
110             q_ptr->ident |= IDENT_STORE;
111             describe_flavor(player_ptr, base_name, q_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
112         }
113
114         fprintf(fff, _("     %s\n", "     The %s\n"), base_name);
115     }
116
117     C_KILL(who, max_a_idx, ARTIFACT_IDX);
118     C_KILL(okay, max_a_idx, bool);
119     angband_fclose(fff);
120     (void)show_file(player_ptr, true, file_name, _("既知の伝説のアイテム", "Artifacts Seen"), 0, 0);
121     fd_kill(file_name);
122 }
123
124 /*
125  * Build a list of object indexes in the given group. Return the number
126  * of objects in the group.
127  *
128  * mode & 0x01 : check for non-empty group
129  * mode & 0x02 : visual operation only
130  */
131 static KIND_OBJECT_IDX collect_objects(int grp_cur, KIND_OBJECT_IDX object_idx[], BIT_FLAGS8 mode)
132 {
133     KIND_OBJECT_IDX object_cnt = 0;
134     byte group_tval = object_group_tval[grp_cur];
135     for (KIND_OBJECT_IDX i = 0; i < max_k_idx; i++) {
136         object_kind *k_ptr = &k_info[i];
137         if (k_ptr->name.empty())
138             continue;
139
140         if (!(mode & 0x02)) {
141             if (!w_ptr->wizard) {
142                 if (!k_ptr->flavor)
143                     continue;
144                 if (!k_ptr->aware)
145                     continue;
146             }
147
148             int k = 0;
149             for (int j = 0; j < 4; j++)
150                 k += k_ptr->chance[j];
151             if (!k)
152                 continue;
153         }
154
155         if (TV_LIFE_BOOK == group_tval) {
156             if (TV_LIFE_BOOK <= k_ptr->tval && k_ptr->tval <= TV_HEX_BOOK) {
157                 object_idx[object_cnt++] = i;
158             } else
159                 continue;
160         } else if (k_ptr->tval == group_tval) {
161             object_idx[object_cnt++] = i;
162         } else
163             continue;
164
165         if (mode & 0x01)
166             break;
167     }
168
169     object_idx[object_cnt] = -1;
170     return object_cnt;
171 }
172
173 /*
174  * Display the objects in a group.
175  */
176 static void display_object_list(int col, int row, int per_page, IDX object_idx[], int object_cur, int object_top, bool visual_only)
177 {
178     int i;
179     for (i = 0; i < per_page && (object_idx[object_top + i] >= 0); i++) {
180         GAME_TEXT o_name[MAX_NLEN];
181         TERM_COLOR a;
182         SYMBOL_CODE c;
183         object_kind *flavor_k_ptr;
184         KIND_OBJECT_IDX k_idx = object_idx[object_top + i];
185         object_kind *k_ptr = &k_info[k_idx];
186         TERM_COLOR attr = ((k_ptr->aware || visual_only) ? TERM_WHITE : TERM_SLATE);
187         byte cursor = ((k_ptr->aware || visual_only) ? TERM_L_BLUE : TERM_BLUE);
188         if (!visual_only && k_ptr->flavor) {
189             flavor_k_ptr = &k_info[k_ptr->flavor];
190         } else {
191             flavor_k_ptr = k_ptr;
192         }
193
194         attr = ((i + object_top == object_cur) ? cursor : attr);
195         if (!k_ptr->flavor || (!visual_only && k_ptr->aware)) {
196             strip_name(o_name, k_idx);
197         } else {
198             strcpy(o_name, flavor_k_ptr->flavor_name.c_str());
199         }
200
201         c_prt(attr, o_name, row + i, col);
202         if (per_page == 1) {
203             c_prt(attr, format("%02x/%02x", flavor_k_ptr->x_attr, flavor_k_ptr->x_char), row + i, (w_ptr->wizard || visual_only) ? 64 : 68);
204         }
205
206         if (w_ptr->wizard || visual_only) {
207             c_prt(attr, format("%d", k_idx), row + i, 70);
208         }
209
210         a = flavor_k_ptr->x_attr;
211         c = flavor_k_ptr->x_char;
212
213         term_queue_bigchar(use_bigtile ? 76 : 77, row + i, a, c, 0, 0);
214     }
215
216     for (; i < per_page; i++) {
217         term_erase(col, row + i, 255);
218     }
219 }
220
221 /*
222  * Describe fake object
223  */
224 static void desc_obj_fake(player_type *player_ptr, KIND_OBJECT_IDX k_idx)
225 {
226     object_type *o_ptr;
227     object_type object_type_body;
228     o_ptr = &object_type_body;
229     o_ptr->wipe();
230     o_ptr->prep(k_idx);
231
232     o_ptr->ident |= IDENT_KNOWN;
233     handle_stuff(player_ptr);
234
235     if (screen_object(player_ptr, o_ptr, SCROBJ_FAKE_OBJECT | SCROBJ_FORCE_DETAIL))
236         return;
237
238     msg_print(_("特に変わったところはないようだ。", "You see nothing special."));
239     msg_print(nullptr);
240 }
241
242 /**
243  * @brief Display known objects
244  */
245 void do_cmd_knowledge_objects(player_type *player_ptr, bool *need_redraw, bool visual_only, KIND_OBJECT_IDX direct_k_idx)
246 {
247     KIND_OBJECT_IDX object_old, object_top;
248     KIND_OBJECT_IDX grp_idx[100];
249     int object_cnt;
250     OBJECT_IDX *object_idx;
251
252     bool visual_list = false;
253     TERM_COLOR attr_top = 0;
254     byte char_left = 0;
255     byte mode;
256
257     TERM_LEN wid, hgt;
258     term_get_size(&wid, &hgt);
259
260     int browser_rows = hgt - 8;
261     C_MAKE(object_idx, max_k_idx, KIND_OBJECT_IDX);
262
263     int len;
264     int max = 0;
265     int grp_cnt = 0;
266     if (direct_k_idx < 0) {
267         mode = visual_only ? 0x03 : 0x01;
268         for (IDX i = 0; object_group_text[i] != nullptr; i++) {
269             len = strlen(object_group_text[i]);
270             if (len > max)
271                 max = len;
272
273             if (collect_objects(i, object_idx, mode)) {
274                 grp_idx[grp_cnt++] = i;
275             }
276         }
277
278         object_old = -1;
279         object_cnt = 0;
280     } else {
281         object_kind *k_ptr = &k_info[direct_k_idx];
282         object_kind *flavor_k_ptr;
283
284         if (!visual_only && k_ptr->flavor) {
285             flavor_k_ptr = &k_info[k_ptr->flavor];
286         } else {
287             flavor_k_ptr = k_ptr;
288         }
289
290         object_idx[0] = direct_k_idx;
291         object_old = direct_k_idx;
292         object_cnt = 1;
293         object_idx[1] = -1;
294         (void)visual_mode_command(
295             'v', &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &flavor_k_ptr->x_attr, &flavor_k_ptr->x_char, need_redraw);
296     }
297
298     grp_idx[grp_cnt] = -1;
299     mode = visual_only ? 0x02 : 0x00;
300     IDX old_grp_cur = -1;
301     IDX grp_cur = 0;
302     IDX grp_top = 0;
303     IDX object_cur = object_top = 0;
304     bool flag = false;
305     bool redraw = true;
306     int column = 0;
307     while (!flag) {
308         object_kind *k_ptr, *flavor_k_ptr;
309
310         if (redraw) {
311             clear_from(0);
312
313 #ifdef JP
314             prt(format("%s - アイテム", !visual_only ? "知識" : "表示"), 2, 0);
315             if (direct_k_idx < 0)
316                 prt("グループ", 4, 0);
317             prt("名前", 4, max + 3);
318             if (w_ptr->wizard || visual_only)
319                 prt("Idx", 4, 70);
320             prt("文字", 4, 74);
321 #else
322             prt(format("%s - objects", !visual_only ? "Knowledge" : "Visuals"), 2, 0);
323             if (direct_k_idx < 0)
324                 prt("Group", 4, 0);
325             prt("Name", 4, max + 3);
326             if (w_ptr->wizard || visual_only)
327                 prt("Idx", 4, 70);
328             prt("Sym", 4, 75);
329 #endif
330
331             for (IDX i = 0; i < 78; i++) {
332                 term_putch(i, 5, TERM_WHITE, '=');
333             }
334
335             if (direct_k_idx < 0) {
336                 for (IDX i = 0; i < browser_rows; i++) {
337                     term_putch(max + 1, 6 + i, TERM_WHITE, '|');
338                 }
339             }
340
341             redraw = false;
342         }
343
344         if (direct_k_idx < 0) {
345             if (grp_cur < grp_top)
346                 grp_top = grp_cur;
347             if (grp_cur >= grp_top + browser_rows)
348                 grp_top = grp_cur - browser_rows + 1;
349
350             display_group_list(0, 6, max, browser_rows, grp_idx, object_group_text, grp_cur, grp_top);
351             if (old_grp_cur != grp_cur) {
352                 old_grp_cur = grp_cur;
353                 object_cnt = collect_objects(grp_idx[grp_cur], object_idx, mode);
354             }
355
356             while (object_cur < object_top)
357                 object_top = MAX(0, object_top - browser_rows / 2);
358             while (object_cur >= object_top + browser_rows)
359                 object_top = MIN(object_cnt - browser_rows, object_top + browser_rows / 2);
360         }
361
362         if (!visual_list) {
363             display_object_list(max + 3, 6, browser_rows, object_idx, object_cur, object_top, visual_only);
364         } else {
365             object_top = object_cur;
366             display_object_list(max + 3, 6, 1, object_idx, object_cur, object_top, visual_only);
367             display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
368         }
369
370         k_ptr = &k_info[object_idx[object_cur]];
371
372         if (!visual_only && k_ptr->flavor) {
373             flavor_k_ptr = &k_info[k_ptr->flavor];
374         } else {
375             flavor_k_ptr = k_ptr;
376         }
377
378 #ifdef JP
379         prt(format("<方向>%s%s%s, ESC", (!visual_list && !visual_only) ? ", 'r'で詳細を見る" : "", visual_list ? ", ENTERで決定" : ", 'v'でシンボル変更",
380                 (attr_idx || char_idx) ? ", 'c', 'p'でペースト" : ", 'c'でコピー"),
381             hgt - 1, 0);
382 #else
383         prt(format("<dir>%s%s%s, ESC", (!visual_list && !visual_only) ? ", 'r' to recall" : "", visual_list ? ", ENTER to accept" : ", 'v' for visuals",
384                 (attr_idx || char_idx) ? ", 'c', 'p' to paste" : ", 'c' to copy"),
385             hgt - 1, 0);
386 #endif
387
388         if (!visual_only) {
389             if (object_cnt)
390                 object_kind_track(player_ptr, object_idx[object_cur]);
391
392             if (object_old != object_idx[object_cur]) {
393                 handle_stuff(player_ptr);
394                 object_old = object_idx[object_cur];
395             }
396         }
397
398         if (visual_list) {
399             place_visual_list_cursor(max + 3, 7, flavor_k_ptr->x_attr, flavor_k_ptr->x_char, attr_top, char_left);
400         } else if (!column) {
401             term_gotoxy(0, 6 + (grp_cur - grp_top));
402         } else {
403             term_gotoxy(max + 3, 6 + (object_cur - object_top));
404         }
405
406         char ch = inkey();
407         if (visual_mode_command(
408                 ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &flavor_k_ptr->x_attr, &flavor_k_ptr->x_char, need_redraw)) {
409             if (direct_k_idx >= 0) {
410                 switch (ch) {
411                 case '\n':
412                 case '\r':
413                 case ESCAPE:
414                     flag = true;
415                     break;
416                 }
417             }
418             continue;
419         }
420
421         switch (ch) {
422         case ESCAPE: {
423             flag = true;
424             break;
425         }
426
427         case 'R':
428         case 'r': {
429             if (!visual_list && !visual_only && (grp_cnt > 0)) {
430                 desc_obj_fake(player_ptr, object_idx[object_cur]);
431                 redraw = true;
432             }
433
434             break;
435         }
436
437         default: {
438             browser_cursor(ch, &column, &grp_cur, grp_cnt, &object_cur, object_cnt);
439             break;
440         }
441         }
442     }
443
444     C_KILL(object_idx, max_k_idx, KIND_OBJECT_IDX);
445 }