OSDN Git Service

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