OSDN Git Service

[Refactor] #2645 strip_name() の戻り値をvoid からstd::string に変更し、引数からchar* を消した
[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 #include <numeric>
35 #include <set>
36
37 /*!
38  * @brief Check the status of "artifacts"
39  * @param player_ptr プレイヤーへの参照ポインタ
40  */
41 void do_cmd_knowledge_artifacts(PlayerType *player_ptr)
42 {
43     FILE *fff = nullptr;
44     GAME_TEXT file_name[FILE_NAME_SIZE];
45     if (!open_temporary_file(&fff, file_name)) {
46         return;
47     }
48
49     std::set<FixedArtifactId> known_list;
50
51     for (const auto &[a_idx, a_ref] : a_info) {
52         if (a_ref.name.empty()) {
53             continue;
54         }
55         if (!a_ref.is_generated) {
56             continue;
57         }
58
59         known_list.insert(known_list.end(), a_idx);
60     }
61
62     for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++) {
63         for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
64             auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
65             for (const auto this_o_idx : g_ptr->o_idx_list) {
66                 ObjectType *o_ptr;
67                 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
68                 if (!o_ptr->is_fixed_artifact()) {
69                     continue;
70                 }
71                 if (o_ptr->is_known()) {
72                     continue;
73                 }
74
75                 known_list.erase(o_ptr->fixed_artifact_idx);
76             }
77         }
78     }
79
80     for (auto i = 0; i < INVEN_TOTAL; i++) {
81         auto *o_ptr = &player_ptr->inventory_list[i];
82         if (!o_ptr->k_idx) {
83             continue;
84         }
85         if (!o_ptr->is_fixed_artifact()) {
86             continue;
87         }
88         if (o_ptr->is_known()) {
89             continue;
90         }
91
92         known_list.erase(o_ptr->fixed_artifact_idx);
93     }
94
95     std::vector<FixedArtifactId> whats(known_list.begin(), known_list.end());
96
97     uint16_t why = 3;
98     ang_sort(player_ptr, whats.data(), &why, whats.size(), ang_sort_art_comp, ang_sort_art_swap);
99     for (auto a_idx : whats) {
100         const auto &a_ref = a_info.at(a_idx);
101         GAME_TEXT base_name[MAX_NLEN];
102         strcpy(base_name, _("未知の伝説のアイテム", "Unknown Artifact"));
103         const auto z = lookup_kind(a_ref.tval, a_ref.sval);
104         if (z != 0) {
105             ObjectType forge;
106             ObjectType *q_ptr;
107             q_ptr = &forge;
108             q_ptr->prep(z);
109             q_ptr->fixed_artifact_idx = a_idx;
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     angband_fclose(fff);
118     (void)show_file(player_ptr, true, file_name, _("既知の伝説のアイテム", "Artifacts Seen"), 0, 0);
119     fd_kill(file_name);
120 }
121
122 /*
123  * Build a list of object indexes in the given group. Return the number
124  * of objects in the group.
125  *
126  * mode & 0x01 : check for non-empty group
127  * mode & 0x02 : visual operation only
128  */
129 static KIND_OBJECT_IDX collect_objects(int grp_cur, KIND_OBJECT_IDX object_idx[], BIT_FLAGS8 mode)
130 {
131     KIND_OBJECT_IDX object_cnt = 0;
132     auto group_tval = object_group_tval[grp_cur];
133     for (const auto &k_ref : k_info) {
134         if (k_ref.name.empty()) {
135             continue;
136         }
137
138         if (!(mode & 0x02)) {
139             if (!w_ptr->wizard) {
140                 if (!k_ref.flavor) {
141                     continue;
142                 }
143                 if (!k_ref.aware) {
144                     continue;
145                 }
146             }
147
148             auto k = std::reduce(std::begin(k_ref.chance), std::end(k_ref.chance), 0);
149             if (!k) {
150                 continue;
151             }
152         }
153
154         if (group_tval == ItemKindType::LIFE_BOOK) {
155             if (ItemKindType::LIFE_BOOK <= k_ref.tval && k_ref.tval <= ItemKindType::HEX_BOOK) {
156                 object_idx[object_cnt++] = k_ref.idx;
157             } else {
158                 continue;
159             }
160         } else if (k_ref.tval == group_tval) {
161             object_idx[object_cnt++] = k_ref.idx;
162         } else {
163             continue;
164         }
165
166         if (mode & 0x01) {
167             break;
168         }
169     }
170
171     object_idx[object_cnt] = -1;
172     return object_cnt;
173 }
174
175 /*
176  * Display the objects in a group.
177  */
178 static void display_object_list(int col, int row, int per_page, IDX object_idx[], int object_cur, int object_top, bool visual_only)
179 {
180     int i;
181     for (i = 0; i < per_page && (object_idx[object_top + i] >= 0); i++) {
182         TERM_COLOR a;
183         object_kind *flavor_k_ptr;
184         KIND_OBJECT_IDX k_idx = object_idx[object_top + i];
185         auto *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         std::string o_name;
196         if (!k_ptr->flavor || (!visual_only && k_ptr->aware)) {
197             o_name = strip_name(k_idx);
198         } else {
199             o_name = flavor_k_ptr->flavor_name;
200         }
201
202         c_prt(attr, o_name.data(), row + i, col);
203         if (per_page == 1) {
204             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);
205         }
206
207         if (w_ptr->wizard || visual_only) {
208             c_prt(attr, format("%d", k_idx), row + i, 70);
209         }
210
211         a = flavor_k_ptr->x_attr;
212         auto c = flavor_k_ptr->x_char;
213
214         term_queue_bigchar(use_bigtile ? 76 : 77, row + i, a, c, 0, 0);
215     }
216
217     for (; i < per_page; i++) {
218         term_erase(col, row + i, 255);
219     }
220 }
221
222 /*
223  * Describe fake object
224  */
225 static void desc_obj_fake(PlayerType *player_ptr, KIND_OBJECT_IDX k_idx)
226 {
227     ObjectType *o_ptr;
228     ObjectType ObjectType_body;
229     o_ptr = &ObjectType_body;
230     o_ptr->wipe();
231     o_ptr->prep(k_idx);
232
233     o_ptr->ident |= IDENT_KNOWN;
234     handle_stuff(player_ptr);
235
236     if (screen_object(player_ptr, o_ptr, SCROBJ_FAKE_OBJECT | SCROBJ_FORCE_DETAIL)) {
237         return;
238     }
239
240     msg_print(_("特に変わったところはないようだ。", "You see nothing special."));
241     msg_print(nullptr);
242 }
243
244 /**
245  * @brief Display known objects
246  */
247 void do_cmd_knowledge_objects(PlayerType *player_ptr, bool *need_redraw, bool visual_only, KIND_OBJECT_IDX direct_k_idx)
248 {
249     KIND_OBJECT_IDX object_old, object_top;
250     KIND_OBJECT_IDX grp_idx[100];
251     int object_cnt;
252
253     bool visual_list = false;
254     TERM_COLOR attr_top = 0;
255     byte char_left = 0;
256     byte mode;
257
258     TERM_LEN wid, hgt;
259     term_get_size(&wid, &hgt);
260
261     int browser_rows = hgt - 8;
262     std::vector<KIND_OBJECT_IDX> object_idx(k_info.size());
263
264     int len;
265     int max = 0;
266     int grp_cnt = 0;
267     if (direct_k_idx < 0) {
268         mode = visual_only ? 0x03 : 0x01;
269         for (IDX i = 0; object_group_text[i] != nullptr; i++) {
270             len = strlen(object_group_text[i]);
271             if (len > max) {
272                 max = len;
273             }
274
275             if (collect_objects(i, object_idx.data(), mode)) {
276                 grp_idx[grp_cnt++] = i;
277             }
278         }
279
280         object_old = -1;
281         object_cnt = 0;
282     } else {
283         auto *k_ptr = &k_info[direct_k_idx];
284         object_kind *flavor_k_ptr;
285
286         if (!visual_only && k_ptr->flavor) {
287             flavor_k_ptr = &k_info[k_ptr->flavor];
288         } else {
289             flavor_k_ptr = k_ptr;
290         }
291
292         object_idx[0] = direct_k_idx;
293         object_old = direct_k_idx;
294         object_cnt = 1;
295         object_idx[1] = -1;
296         (void)visual_mode_command(
297             '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);
298     }
299
300     grp_idx[grp_cnt] = -1;
301     mode = visual_only ? 0x02 : 0x00;
302     IDX old_grp_cur = -1;
303     IDX grp_cur = 0;
304     IDX grp_top = 0;
305     IDX object_cur = object_top = 0;
306     bool flag = false;
307     bool redraw = true;
308     int column = 0;
309     while (!flag) {
310         object_kind *k_ptr, *flavor_k_ptr;
311
312         if (redraw) {
313             clear_from(0);
314
315 #ifdef JP
316             prt(format("%s - アイテム", !visual_only ? "知識" : "表示"), 2, 0);
317             if (direct_k_idx < 0) {
318                 prt("グループ", 4, 0);
319             }
320             prt("名前", 4, max + 3);
321             if (w_ptr->wizard || visual_only) {
322                 prt("Idx", 4, 70);
323             }
324             prt("文字", 4, 74);
325 #else
326             prt(format("%s - objects", !visual_only ? "Knowledge" : "Visuals"), 2, 0);
327             if (direct_k_idx < 0) {
328                 prt("Group", 4, 0);
329             }
330             prt("Name", 4, max + 3);
331             if (w_ptr->wizard || visual_only) {
332                 prt("Idx", 4, 70);
333             }
334             prt("Sym", 4, 75);
335 #endif
336
337             for (IDX i = 0; i < 78; i++) {
338                 term_putch(i, 5, TERM_WHITE, '=');
339             }
340
341             if (direct_k_idx < 0) {
342                 for (IDX i = 0; i < browser_rows; i++) {
343                     term_putch(max + 1, 6 + i, TERM_WHITE, '|');
344                 }
345             }
346
347             redraw = false;
348         }
349
350         if (direct_k_idx < 0) {
351             if (grp_cur < grp_top) {
352                 grp_top = grp_cur;
353             }
354             if (grp_cur >= grp_top + browser_rows) {
355                 grp_top = grp_cur - browser_rows + 1;
356             }
357
358             std::vector<concptr> tmp_texts;
359             for (auto &text : object_group_text) {
360                 tmp_texts.push_back(text);
361             }
362
363             display_group_list(0, 6, max, browser_rows, grp_idx, tmp_texts.data(), grp_cur, grp_top);
364             if (old_grp_cur != grp_cur) {
365                 old_grp_cur = grp_cur;
366                 object_cnt = collect_objects(grp_idx[grp_cur], object_idx.data(), mode);
367             }
368
369             while (object_cur < object_top) {
370                 object_top = std::max<short>(0, object_top - browser_rows / 2);
371             }
372
373             while (object_cur >= object_top + browser_rows) {
374                 object_top = std::min<short>(object_cnt - browser_rows, object_top + browser_rows / 2);
375             }
376         }
377
378         if (!visual_list) {
379             display_object_list(max + 3, 6, browser_rows, object_idx.data(), object_cur, object_top, visual_only);
380         } else {
381             object_top = object_cur;
382             display_object_list(max + 3, 6, 1, object_idx.data(), object_cur, object_top, visual_only);
383             display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
384         }
385
386         k_ptr = &k_info[object_idx[object_cur]];
387
388         if (!visual_only && k_ptr->flavor) {
389             flavor_k_ptr = &k_info[k_ptr->flavor];
390         } else {
391             flavor_k_ptr = k_ptr;
392         }
393
394 #ifdef JP
395         prt(format("<方向>%s%s%s, ESC", (!visual_list && !visual_only) ? ", 'r'で詳細を見る" : "", visual_list ? ", ENTERで決定" : ", 'v'でシンボル変更",
396                 (attr_idx || char_idx) ? ", 'c', 'p'でペースト" : ", 'c'でコピー"),
397             hgt - 1, 0);
398 #else
399         prt(format("<dir>%s%s%s, ESC", (!visual_list && !visual_only) ? ", 'r' to recall" : "", visual_list ? ", ENTER to accept" : ", 'v' for visuals",
400                 (attr_idx || char_idx) ? ", 'c', 'p' to paste" : ", 'c' to copy"),
401             hgt - 1, 0);
402 #endif
403
404         if (!visual_only) {
405             if (object_cnt) {
406                 object_kind_track(player_ptr, object_idx[object_cur]);
407             }
408
409             if (object_old != object_idx[object_cur]) {
410                 handle_stuff(player_ptr);
411                 object_old = object_idx[object_cur];
412             }
413         }
414
415         if (visual_list) {
416             place_visual_list_cursor(max + 3, 7, flavor_k_ptr->x_attr, flavor_k_ptr->x_char, attr_top, char_left);
417         } else if (!column) {
418             term_gotoxy(0, 6 + (grp_cur - grp_top));
419         } else {
420             term_gotoxy(max + 3, 6 + (object_cur - object_top));
421         }
422
423         char ch = inkey();
424         if (visual_mode_command(
425                 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)) {
426             if (direct_k_idx >= 0) {
427                 switch (ch) {
428                 case '\n':
429                 case '\r':
430                 case ESCAPE:
431                     flag = true;
432                     break;
433                 }
434             }
435             continue;
436         }
437
438         switch (ch) {
439         case ESCAPE: {
440             flag = true;
441             break;
442         }
443
444         case 'R':
445         case 'r': {
446             if (!visual_list && !visual_only && (grp_cnt > 0)) {
447                 desc_obj_fake(player_ptr, object_idx[object_cur]);
448                 redraw = true;
449             }
450
451             break;
452         }
453
454         default: {
455             browser_cursor(ch, &column, &grp_cur, grp_cnt, &object_cur, object_cnt);
456             break;
457         }
458         }
459     }
460 }