OSDN Git Service

[Refactor] format 関数の戻り値を std::string にする
[hengbandforosx/hengbandosx.git] / src / target / target-describer.cpp
1 #include "target/target-describer.h"
2 #include "action/travel-execution.h"
3 #include "core/stuff-handler.h"
4 #include "dungeon/quest.h"
5 #include "flavor/flavor-describer.h"
6 #include "floor/cave.h"
7 #include "floor/floor-object.h"
8 #include "floor/floor-town.h"
9 #include "floor/geometry.h"
10 #include "floor/object-scanner.h"
11 #include "game-option/input-options.h"
12 #include "grid/feature.h"
13 #include "grid/grid.h"
14 #include "info-reader/fixed-map-parser.h"
15 #include "io/cursor.h"
16 #include "io/input-key-acceptor.h"
17 #include "locale/english.h"
18 #include "lore/lore-util.h"
19 #include "monster-race/monster-race.h"
20 #include "monster-race/race-flags1.h"
21 #include "monster/monster-describer.h"
22 #include "monster/monster-description-types.h"
23 #include "monster/monster-flag-types.h"
24 #include "object/item-tester-hooker.h"
25 #include "object/object-mark-types.h"
26 #include "player-base/player-race.h"
27 #include "player/player-status-table.h"
28 #include "system/building-type-definition.h"
29 #include "system/dungeon-info.h"
30 #include "system/floor-type-definition.h"
31 #include "system/grid-type-definition.h"
32 #include "system/item-entity.h"
33 #include "system/monster-entity.h"
34 #include "system/monster-race-info.h"
35 #include "system/player-type-definition.h"
36 #include "system/system-variables.h"
37 #include "system/terrain-type-definition.h"
38 #include "target/target-types.h"
39 #include "term/screen-processor.h"
40 #include "term/term-color-types.h"
41 #include "term/z-form.h"
42 #include "timed-effect/player-hallucination.h"
43 #include "timed-effect/timed-effects.h"
44 #include "util/bit-flags-calculator.h"
45 #include "view/display-lore.h"
46 #include "view/display-messages.h"
47 #include "view/display-monster-status.h"
48 #include "window/display-sub-windows.h"
49 #include "world/world.h"
50
51 static const int16_t CONTINUOUS_DESCRIPTION = 256;
52
53 bool show_gold_on_floor = false;
54
55 // Examine grid
56 struct eg_type {
57     POSITION y;
58     POSITION x;
59     target_type mode;
60     bool boring;
61     concptr info;
62     concptr s1;
63     concptr s2;
64     concptr s3;
65     concptr x_info;
66     char query;
67     char out_val[MAX_NLEN + 80];
68     OBJECT_IDX floor_list[23];
69     ITEM_NUMBER floor_num;
70     grid_type *g_ptr;
71     MonsterEntity *m_ptr;
72     OBJECT_IDX next_o_idx;
73     FEAT_IDX feat;
74     TerrainType *f_ptr;
75     std::string name;
76 };
77
78 static eg_type *initialize_eg_type(PlayerType *player_ptr, eg_type *eg_ptr, POSITION y, POSITION x, target_type mode, concptr info)
79 {
80     eg_ptr->y = y;
81     eg_ptr->x = x;
82     eg_ptr->boring = true;
83     eg_ptr->mode = mode;
84     eg_ptr->info = info;
85     eg_ptr->s1 = "";
86     eg_ptr->s2 = "";
87     eg_ptr->s3 = "";
88     eg_ptr->x_info = "";
89     eg_ptr->query = '\001';
90     eg_ptr->floor_num = 0;
91
92     auto *floor_ptr = player_ptr->current_floor_ptr;
93     eg_ptr->g_ptr = &floor_ptr->grid_array[y][x];
94     eg_ptr->m_ptr = &floor_ptr->m_list[eg_ptr->g_ptr->m_idx];
95     eg_ptr->next_o_idx = 0;
96     return eg_ptr;
97 }
98
99 /*
100  * Evaluate number of kill needed to gain level
101  */
102 static std::string evaluate_monster_exp(PlayerType *player_ptr, MonsterEntity *m_ptr)
103 {
104     MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
105     if ((player_ptr->lev >= PY_MAX_LEVEL) || PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
106         return "**";
107     }
108
109     if (!ap_r_ptr->r_tkills || m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
110         if (!w_ptr->wizard) {
111             return "??";
112         }
113     }
114
115     int32_t exp_mon = ap_r_ptr->mexp * ap_r_ptr->level;
116     uint32_t exp_mon_frac = 0;
117     s64b_div(&exp_mon, &exp_mon_frac, 0, (player_ptr->max_plv + 2));
118
119     int32_t exp_adv = player_exp[player_ptr->lev - 1] * player_ptr->expfact;
120     uint32_t exp_adv_frac = 0;
121     s64b_div(&exp_adv, &exp_adv_frac, 0, 100);
122
123     s64b_sub(&exp_adv, &exp_adv_frac, player_ptr->exp, player_ptr->exp_frac);
124
125     s64b_add(&exp_adv, &exp_adv_frac, exp_mon, exp_mon_frac);
126     s64b_sub(&exp_adv, &exp_adv_frac, 0, 1);
127
128     s64b_div(&exp_adv, &exp_adv_frac, exp_mon, exp_mon_frac);
129
130     auto num = std::min<uint>(999, exp_adv_frac);
131     return format("%03ld", (long int)num);
132 }
133
134 static void describe_scan_result(PlayerType *player_ptr, eg_type *eg_ptr)
135 {
136     if (!easy_floor) {
137         return;
138     }
139
140     eg_ptr->floor_num = scan_floor_items(player_ptr, eg_ptr->floor_list, eg_ptr->y, eg_ptr->x, SCAN_FLOOR_ONLY_MARKED, AllMatchItemTester());
141     if (eg_ptr->floor_num > 0) {
142         eg_ptr->x_info = _("x物 ", "x,");
143     }
144 }
145
146 static void describe_target(PlayerType *player_ptr, eg_type *eg_ptr)
147 {
148     if (!player_bold(player_ptr, eg_ptr->y, eg_ptr->x)) {
149         eg_ptr->s1 = _("ターゲット:", "Target:");
150         return;
151     }
152
153 #ifdef JP
154     eg_ptr->s1 = "あなたは";
155     eg_ptr->s2 = "の上";
156     eg_ptr->s3 = "にいる";
157 #else
158     eg_ptr->s1 = "You are ";
159     eg_ptr->s2 = "on ";
160 #endif
161 }
162
163 static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, eg_type *eg_ptr)
164 {
165     if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
166         return ProcessResult::PROCESS_CONTINUE;
167     }
168
169     concptr name = _("何か奇妙な物", "something strange");
170 #ifdef JP
171     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
172 #else
173     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, name, eg_ptr->info);
174 #endif
175     prt(eg_ptr->out_val, 0, 0);
176     move_cursor_relative(eg_ptr->y, eg_ptr->x);
177     eg_ptr->query = inkey();
178     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n')) {
179         return ProcessResult::PROCESS_TRUE;
180     }
181
182     return ProcessResult::PROCESS_FALSE;
183 }
184
185 static bool describe_grid_lore(PlayerType *player_ptr, eg_type *eg_ptr)
186 {
187     screen_save();
188     screen_roff(player_ptr, eg_ptr->m_ptr->ap_r_idx, MONSTER_LORE_NORMAL);
189     term_addstr(-1, TERM_WHITE, format(_("  [r思 %s%s]", "  [r,%s%s]"), eg_ptr->x_info, eg_ptr->info));
190     eg_ptr->query = inkey();
191     screen_load();
192     return eg_ptr->query != 'r';
193 }
194
195 static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
196 {
197     bool recall = false;
198     GAME_TEXT m_name[MAX_NLEN];
199     monster_desc(player_ptr, m_name, eg_ptr->m_ptr, MD_INDEF_VISIBLE);
200     while (true) {
201         if (recall) {
202             if (describe_grid_lore(player_ptr, eg_ptr)) {
203                 return;
204             }
205
206             recall = false;
207             continue;
208         }
209
210         std::string acount = evaluate_monster_exp(player_ptr, eg_ptr->m_ptr);
211         const auto mon_desc = look_mon_desc(eg_ptr->m_ptr, 0x01);
212 #ifdef JP
213         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s(%s)%s%s [r思 %s%s]", acount.data(), eg_ptr->s1, m_name, mon_desc.data(), eg_ptr->s2, eg_ptr->s3,
214             eg_ptr->x_info, eg_ptr->info);
215 #else
216         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s%s%s(%s) [r, %s%s]", acount.data(), eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, m_name, mon_desc.data(),
217             eg_ptr->x_info, eg_ptr->info);
218 #endif
219         prt(eg_ptr->out_val, 0, 0);
220         move_cursor_relative(eg_ptr->y, eg_ptr->x);
221         eg_ptr->query = inkey();
222         if (eg_ptr->query != 'r') {
223             return;
224         }
225
226         recall = true;
227     }
228 }
229
230 static void describe_monster_person(eg_type *eg_ptr)
231 {
232     MonsterRaceInfo *ap_r_ptr = &monraces_info[eg_ptr->m_ptr->ap_r_idx];
233     eg_ptr->s1 = _("それは", "It is ");
234     if (ap_r_ptr->flags1 & RF1_FEMALE) {
235         eg_ptr->s1 = _("彼女は", "She is ");
236     } else if (ap_r_ptr->flags1 & RF1_MALE) {
237         eg_ptr->s1 = _("彼は", "He is ");
238     }
239
240 #ifdef JP
241     eg_ptr->s2 = "を";
242     eg_ptr->s3 = "持っている";
243 #else
244     eg_ptr->s2 = "carrying ";
245 #endif
246 }
247
248 static uint16_t describe_monster_item(PlayerType *player_ptr, eg_type *eg_ptr)
249 {
250     for (const auto this_o_idx : eg_ptr->m_ptr->hold_o_idx_list) {
251         GAME_TEXT o_name[MAX_NLEN];
252         ItemEntity *o_ptr;
253         o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
254         describe_flavor(player_ptr, o_name, o_ptr, 0);
255 #ifdef JP
256         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
257 #else
258         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
259 #endif
260         prt(eg_ptr->out_val, 0, 0);
261         move_cursor_relative(eg_ptr->y, eg_ptr->x);
262         eg_ptr->query = inkey();
263         if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
264             return eg_ptr->query;
265         }
266
267         if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
268             return eg_ptr->query;
269         }
270
271         eg_ptr->s2 = _("をまた", "also carrying ");
272     }
273
274     return CONTINUOUS_DESCRIPTION;
275 }
276
277 static bool within_char_util(int16_t input)
278 {
279     return (input > -127) && (input < 128);
280 }
281
282 static int16_t describe_grid(PlayerType *player_ptr, eg_type *eg_ptr)
283 {
284     if ((eg_ptr->g_ptr->m_idx == 0) || !player_ptr->current_floor_ptr->m_list[eg_ptr->g_ptr->m_idx].ml) {
285         return CONTINUOUS_DESCRIPTION;
286     }
287
288     eg_ptr->boring = false;
289     monster_race_track(player_ptr, eg_ptr->m_ptr->ap_r_idx);
290     health_track(player_ptr, eg_ptr->g_ptr->m_idx);
291     handle_stuff(player_ptr);
292     describe_grid_monster(player_ptr, eg_ptr);
293     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
294         return eg_ptr->query;
295     }
296
297     if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
298         return eg_ptr->query;
299     }
300
301     describe_monster_person(eg_ptr);
302     uint16_t monster_item_description = describe_monster_item(player_ptr, eg_ptr);
303     if (within_char_util(monster_item_description)) {
304         return (char)monster_item_description;
305     }
306
307 #ifdef JP
308     eg_ptr->s2 = "の上";
309     eg_ptr->s3 = "にいる";
310 #else
311     eg_ptr->s2 = "on ";
312 #endif
313     return CONTINUOUS_DESCRIPTION;
314 }
315
316 static int16_t describe_footing(PlayerType *player_ptr, eg_type *eg_ptr)
317 {
318     if (eg_ptr->floor_num != 1) {
319         return CONTINUOUS_DESCRIPTION;
320     }
321
322     GAME_TEXT o_name[MAX_NLEN];
323     ItemEntity *o_ptr;
324     o_ptr = &player_ptr->current_floor_ptr->o_list[eg_ptr->floor_list[0]];
325     describe_flavor(player_ptr, o_name, o_ptr, 0);
326 #ifdef JP
327     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
328 #else
329     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
330 #endif
331     prt(eg_ptr->out_val, 0, 0);
332     move_cursor_relative(eg_ptr->y, eg_ptr->x);
333     eg_ptr->query = inkey();
334     return eg_ptr->query;
335 }
336
337 static int16_t describe_footing_items(eg_type *eg_ptr)
338 {
339     if (!eg_ptr->boring) {
340         return CONTINUOUS_DESCRIPTION;
341     }
342
343 #ifdef JP
344     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s ['x'で一覧, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
345 #else
346     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [x,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
347 #endif
348     prt(eg_ptr->out_val, 0, 0);
349     move_cursor_relative(eg_ptr->y, eg_ptr->x);
350     eg_ptr->query = inkey();
351     if (eg_ptr->query != 'x' && eg_ptr->query != ' ') {
352         return eg_ptr->query;
353     }
354
355     return CONTINUOUS_DESCRIPTION;
356 }
357
358 static char describe_footing_many_items(PlayerType *player_ptr, eg_type *eg_ptr, int *min_width)
359 {
360     while (true) {
361         screen_save();
362         show_gold_on_floor = true;
363         (void)show_floor_items(player_ptr, 0, eg_ptr->y, eg_ptr->x, min_width, AllMatchItemTester());
364         show_gold_on_floor = false;
365 #ifdef JP
366         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s [Enterで次へ, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
367 #else
368         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [Enter,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
369 #endif
370         prt(eg_ptr->out_val, 0, 0);
371         eg_ptr->query = inkey();
372         screen_load();
373         if (eg_ptr->query != '\n' && eg_ptr->query != '\r') {
374             return eg_ptr->query;
375         }
376
377         if (eg_ptr->g_ptr->o_idx_list.size() < 2) {
378             continue;
379         }
380
381         eg_ptr->g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
382
383         // ターゲットしている床の座標を渡す必要があるので、window_stuff経由ではなく直接呼び出す
384         fix_floor_item_list(player_ptr, eg_ptr->y, eg_ptr->x);
385     }
386 }
387
388 static int16_t loop_describing_grid(PlayerType *player_ptr, eg_type *eg_ptr)
389 {
390     if (eg_ptr->floor_num == 0) {
391         return CONTINUOUS_DESCRIPTION;
392     }
393
394     int min_width = 0;
395     while (true) {
396         int16_t footing_description = describe_footing(player_ptr, eg_ptr);
397         if (within_char_util(footing_description)) {
398             return (char)footing_description;
399         }
400
401         int16_t footing_descriptions = describe_footing_items(eg_ptr);
402         if (within_char_util(footing_descriptions)) {
403             return (char)footing_descriptions;
404         }
405
406         return describe_footing_many_items(player_ptr, eg_ptr, &min_width);
407     }
408 }
409
410 static int16_t describe_footing_sight(PlayerType *player_ptr, eg_type *eg_ptr, ItemEntity *o_ptr)
411 {
412     if (o_ptr->marked.has_not(OmType::FOUND)) {
413         return CONTINUOUS_DESCRIPTION;
414     }
415
416     GAME_TEXT o_name[MAX_NLEN];
417     eg_ptr->boring = false;
418     describe_flavor(player_ptr, o_name, o_ptr, 0);
419 #ifdef JP
420     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
421 #else
422     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
423 #endif
424     prt(eg_ptr->out_val, 0, 0);
425     move_cursor_relative(eg_ptr->y, eg_ptr->x);
426     eg_ptr->query = inkey();
427     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
428         return eg_ptr->query;
429     }
430
431     if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
432         return eg_ptr->query;
433     }
434
435     eg_ptr->s1 = _("それは", "It is ");
436     if (o_ptr->number != 1) {
437         eg_ptr->s1 = _("それらは", "They are ");
438     }
439
440 #ifdef JP
441     eg_ptr->s2 = "の上";
442     eg_ptr->s3 = "に見える";
443 #else
444     eg_ptr->s2 = "on ";
445 #endif
446     return CONTINUOUS_DESCRIPTION;
447 }
448
449 static int16_t sweep_footing_items(PlayerType *player_ptr, eg_type *eg_ptr)
450 {
451     for (const auto this_o_idx : eg_ptr->g_ptr->o_idx_list) {
452         ItemEntity *o_ptr;
453         o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
454         int16_t ret = describe_footing_sight(player_ptr, eg_ptr, o_ptr);
455         if (within_char_util(ret)) {
456             return (char)ret;
457         }
458     }
459
460     return CONTINUOUS_DESCRIPTION;
461 }
462
463 static std::string decide_target_floor(PlayerType *player_ptr, eg_type *eg_ptr)
464 {
465     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
466         QuestId old_quest = player_ptr->current_floor_ptr->quest_number;
467         const auto &quest_list = QuestList::get_instance();
468         const QuestId number = i2enum<QuestId>(eg_ptr->g_ptr->special);
469         const auto *q_ptr = &quest_list[number];
470         std::string_view msg(_("クエスト「%s」(%d階相当)", "the entrance to the quest '%s'(level %d)"));
471         for (int j = 0; j < 10; j++) {
472             quest_text[j][0] = '\0';
473         }
474
475         quest_text_line = 0;
476         player_ptr->current_floor_ptr->quest_number = number;
477         init_flags = INIT_NAME_ONLY;
478         parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
479         player_ptr->current_floor_ptr->quest_number = old_quest;
480         return format(msg.data(), q_ptr->name, q_ptr->level);
481     }
482
483     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::BLDG) && !player_ptr->current_floor_ptr->inside_arena) {
484         return building[eg_ptr->f_ptr->subtype].name;
485     }
486
487     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
488         return format(_("%s(%d階相当)", "%s(level %d)"), dungeons_info[eg_ptr->g_ptr->special].text.data(), dungeons_info[eg_ptr->g_ptr->special].mindepth);
489     }
490
491     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN)) {
492         return town_info[eg_ptr->g_ptr->special].name;
493     }
494
495     if (player_ptr->wild_mode && (eg_ptr->feat == feat_floor)) {
496         return _("道", "road");
497     }
498
499     return eg_ptr->f_ptr->name.data();
500 }
501
502 static void describe_grid_monster_all(eg_type *eg_ptr)
503 {
504     if (!w_ptr->wizard) {
505 #ifdef JP
506         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, eg_ptr->name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
507 #else
508         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name.data(), eg_ptr->info);
509 #endif
510         return;
511     }
512
513     std::string f_idx_str;
514     if (eg_ptr->g_ptr->mimic) {
515         f_idx_str = format("%d/%d", eg_ptr->g_ptr->feat, eg_ptr->g_ptr->mimic);
516     } else {
517         f_idx_str = std::to_string(eg_ptr->g_ptr->feat);
518     }
519
520 #ifdef JP
521     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s] %x %s %d %d %d (%d,%d) %d", eg_ptr->s1, eg_ptr->name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info,
522         (uint)eg_ptr->g_ptr->info, f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y,
523         (int)eg_ptr->x, travel.cost[eg_ptr->y][eg_ptr->x]);
524 #else
525     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s] %x %s %d %d %d (%d,%d)", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name.data(), eg_ptr->info, eg_ptr->g_ptr->info,
526         f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y, (int)eg_ptr->x);
527 #endif
528 }
529
530 /*!
531  * @brief xまたはlで指定したグリッドにあるアイテムやモンスターの説明を記述する
532  * @param player_ptr プレイヤーへの参照ポインタ
533  * @param y 指定グリッドのY座標
534  * @param x 指定グリッドのX座標
535  * @param mode x (KILL)かl (LOOK)
536  * @param info 記述用文字列
537  * @return 入力キー
538  * @todo xとlで処理を分ける?
539  */
540 char examine_grid(PlayerType *player_ptr, const POSITION y, const POSITION x, target_type mode, concptr info)
541 {
542     eg_type tmp_eg;
543     eg_type *eg_ptr = initialize_eg_type(player_ptr, &tmp_eg, y, x, mode, info);
544     describe_scan_result(player_ptr, eg_ptr);
545     describe_target(player_ptr, eg_ptr);
546     ProcessResult next_target = describe_hallucinated_target(player_ptr, eg_ptr);
547     switch (next_target) {
548     case ProcessResult::PROCESS_FALSE:
549         return 0;
550     case ProcessResult::PROCESS_TRUE:
551         return eg_ptr->query;
552     default:
553         break;
554     }
555
556     int16_t description_grid = describe_grid(player_ptr, eg_ptr);
557     if (within_char_util(description_grid)) {
558         return (char)description_grid;
559     }
560
561     int16_t loop_description = loop_describing_grid(player_ptr, eg_ptr);
562     if (within_char_util(loop_description)) {
563         return (char)loop_description;
564     }
565
566     int16_t footing_items_description = sweep_footing_items(player_ptr, eg_ptr);
567     if (within_char_util(footing_items_description)) {
568         return (char)footing_items_description;
569     }
570
571     eg_ptr->feat = eg_ptr->g_ptr->get_feat_mimic();
572     if (!eg_ptr->g_ptr->is_mark() && !player_can_see_bold(player_ptr, y, x)) {
573         eg_ptr->feat = feat_none;
574     }
575
576     eg_ptr->f_ptr = &terrains_info[eg_ptr->feat];
577     if (!eg_ptr->boring && eg_ptr->f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
578         return (eg_ptr->query != '\r') && (eg_ptr->query != '\n') ? eg_ptr->query : 0;
579     }
580
581     /*
582      * グローバル変数への代入をここで行っているので動かしたくない
583      * 安全を確保できたら構造体から外すことも検討する
584      */
585     eg_ptr->name = decide_target_floor(player_ptr, eg_ptr);
586     if (*eg_ptr->s2 && (eg_ptr->f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY }) || eg_ptr->f_ptr->flags.has_none_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::TREE }) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN))) {
587         eg_ptr->s2 = _("の中", "in ");
588     }
589
590     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::STORE) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER) || (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::BLDG) && !player_ptr->current_floor_ptr->inside_arena) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
591         eg_ptr->s2 = _("の入口", "");
592     }
593 #ifdef JP
594 #else
595     else if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::FLOOR) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::SHALLOW) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
596         eg_ptr->s3 = "";
597     } else {
598         eg_ptr->s3 = (is_a_vowel(eg_ptr->name[0])) ? "an " : "a ";
599     }
600 #endif
601
602     describe_grid_monster_all(eg_ptr);
603     prt(eg_ptr->out_val, 0, 0);
604     move_cursor_relative(y, x);
605     eg_ptr->query = inkey();
606     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n')) {
607         return eg_ptr->query;
608     }
609
610     return 0;
611 }