OSDN Git Service

Merge pull request #3302 from sikabane-works/release/3.0.0Alpha83
[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     const auto m_name = monster_desc(player_ptr, eg_ptr->m_ptr, MD_INDEF_VISIBLE);
199     while (true) {
200         if (recall) {
201             if (describe_grid_lore(player_ptr, eg_ptr)) {
202                 return;
203             }
204
205             recall = false;
206             continue;
207         }
208
209         std::string acount = evaluate_monster_exp(player_ptr, eg_ptr->m_ptr);
210         const auto mon_desc = look_mon_desc(eg_ptr->m_ptr, 0x01);
211 #ifdef JP
212         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.data(), mon_desc.data(), eg_ptr->s2, eg_ptr->s3,
213             eg_ptr->x_info, eg_ptr->info);
214 #else
215         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.data(), mon_desc.data(),
216             eg_ptr->x_info, eg_ptr->info);
217 #endif
218         prt(eg_ptr->out_val, 0, 0);
219         move_cursor_relative(eg_ptr->y, eg_ptr->x);
220         eg_ptr->query = inkey();
221         if (eg_ptr->query != 'r') {
222             return;
223         }
224
225         recall = true;
226     }
227 }
228
229 static void describe_monster_person(eg_type *eg_ptr)
230 {
231     MonsterRaceInfo *ap_r_ptr = &monraces_info[eg_ptr->m_ptr->ap_r_idx];
232     eg_ptr->s1 = _("それは", "It is ");
233     if (ap_r_ptr->flags1 & RF1_FEMALE) {
234         eg_ptr->s1 = _("彼女は", "She is ");
235     } else if (ap_r_ptr->flags1 & RF1_MALE) {
236         eg_ptr->s1 = _("彼は", "He is ");
237     }
238
239 #ifdef JP
240     eg_ptr->s2 = "を";
241     eg_ptr->s3 = "持っている";
242 #else
243     eg_ptr->s2 = "carrying ";
244 #endif
245 }
246
247 static uint16_t describe_monster_item(PlayerType *player_ptr, eg_type *eg_ptr)
248 {
249     for (const auto this_o_idx : eg_ptr->m_ptr->hold_o_idx_list) {
250         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
251         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
252 #ifdef JP
253         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
254 #else
255         strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
256 #endif
257         prt(eg_ptr->out_val, 0, 0);
258         move_cursor_relative(eg_ptr->y, eg_ptr->x);
259         eg_ptr->query = inkey();
260         if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
261             return eg_ptr->query;
262         }
263
264         if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
265             return eg_ptr->query;
266         }
267
268         eg_ptr->s2 = _("をまた", "also carrying ");
269     }
270
271     return CONTINUOUS_DESCRIPTION;
272 }
273
274 static bool within_char_util(int16_t input)
275 {
276     return (input > -127) && (input < 128);
277 }
278
279 static int16_t describe_grid(PlayerType *player_ptr, eg_type *eg_ptr)
280 {
281     if ((eg_ptr->g_ptr->m_idx == 0) || !player_ptr->current_floor_ptr->m_list[eg_ptr->g_ptr->m_idx].ml) {
282         return CONTINUOUS_DESCRIPTION;
283     }
284
285     eg_ptr->boring = false;
286     monster_race_track(player_ptr, eg_ptr->m_ptr->ap_r_idx);
287     health_track(player_ptr, eg_ptr->g_ptr->m_idx);
288     handle_stuff(player_ptr);
289     describe_grid_monster(player_ptr, eg_ptr);
290     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
291         return eg_ptr->query;
292     }
293
294     if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
295         return eg_ptr->query;
296     }
297
298     describe_monster_person(eg_ptr);
299     uint16_t monster_item_description = describe_monster_item(player_ptr, eg_ptr);
300     if (within_char_util(monster_item_description)) {
301         return (char)monster_item_description;
302     }
303
304 #ifdef JP
305     eg_ptr->s2 = "の上";
306     eg_ptr->s3 = "にいる";
307 #else
308     eg_ptr->s2 = "on ";
309 #endif
310     return CONTINUOUS_DESCRIPTION;
311 }
312
313 static int16_t describe_footing(PlayerType *player_ptr, eg_type *eg_ptr)
314 {
315     if (eg_ptr->floor_num != 1) {
316         return CONTINUOUS_DESCRIPTION;
317     }
318
319     auto *o_ptr = &player_ptr->current_floor_ptr->o_list[eg_ptr->floor_list[0]];
320     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
321 #ifdef JP
322     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
323 #else
324     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
325 #endif
326     prt(eg_ptr->out_val, 0, 0);
327     move_cursor_relative(eg_ptr->y, eg_ptr->x);
328     eg_ptr->query = inkey();
329     return eg_ptr->query;
330 }
331
332 static int16_t describe_footing_items(eg_type *eg_ptr)
333 {
334     if (!eg_ptr->boring) {
335         return CONTINUOUS_DESCRIPTION;
336     }
337
338 #ifdef JP
339     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);
340 #else
341     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);
342 #endif
343     prt(eg_ptr->out_val, 0, 0);
344     move_cursor_relative(eg_ptr->y, eg_ptr->x);
345     eg_ptr->query = inkey();
346     if (eg_ptr->query != 'x' && eg_ptr->query != ' ') {
347         return eg_ptr->query;
348     }
349
350     return CONTINUOUS_DESCRIPTION;
351 }
352
353 static char describe_footing_many_items(PlayerType *player_ptr, eg_type *eg_ptr, int *min_width)
354 {
355     while (true) {
356         screen_save();
357         show_gold_on_floor = true;
358         (void)show_floor_items(player_ptr, 0, eg_ptr->y, eg_ptr->x, min_width, AllMatchItemTester());
359         show_gold_on_floor = false;
360 #ifdef JP
361         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);
362 #else
363         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);
364 #endif
365         prt(eg_ptr->out_val, 0, 0);
366         eg_ptr->query = inkey();
367         screen_load();
368         if (eg_ptr->query != '\n' && eg_ptr->query != '\r') {
369             return eg_ptr->query;
370         }
371
372         if (eg_ptr->g_ptr->o_idx_list.size() < 2) {
373             continue;
374         }
375
376         eg_ptr->g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
377
378         // ターゲットしている床の座標を渡す必要があるので、window_stuff経由ではなく直接呼び出す
379         fix_floor_item_list(player_ptr, eg_ptr->y, eg_ptr->x);
380     }
381 }
382
383 static int16_t loop_describing_grid(PlayerType *player_ptr, eg_type *eg_ptr)
384 {
385     if (eg_ptr->floor_num == 0) {
386         return CONTINUOUS_DESCRIPTION;
387     }
388
389     int min_width = 0;
390     while (true) {
391         int16_t footing_description = describe_footing(player_ptr, eg_ptr);
392         if (within_char_util(footing_description)) {
393             return (char)footing_description;
394         }
395
396         int16_t footing_descriptions = describe_footing_items(eg_ptr);
397         if (within_char_util(footing_descriptions)) {
398             return (char)footing_descriptions;
399         }
400
401         return describe_footing_many_items(player_ptr, eg_ptr, &min_width);
402     }
403 }
404
405 static int16_t describe_footing_sight(PlayerType *player_ptr, eg_type *eg_ptr, ItemEntity *o_ptr)
406 {
407     if (o_ptr->marked.has_not(OmType::FOUND)) {
408         return CONTINUOUS_DESCRIPTION;
409     }
410
411     eg_ptr->boring = false;
412     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
413 #ifdef JP
414     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
415 #else
416     strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
417 #endif
418     prt(eg_ptr->out_val, 0, 0);
419     move_cursor_relative(eg_ptr->y, eg_ptr->x);
420     eg_ptr->query = inkey();
421     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
422         return eg_ptr->query;
423     }
424
425     if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
426         return eg_ptr->query;
427     }
428
429     eg_ptr->s1 = _("それは", "It is ");
430     if (o_ptr->number != 1) {
431         eg_ptr->s1 = _("それらは", "They are ");
432     }
433
434 #ifdef JP
435     eg_ptr->s2 = "の上";
436     eg_ptr->s3 = "に見える";
437 #else
438     eg_ptr->s2 = "on ";
439 #endif
440     return CONTINUOUS_DESCRIPTION;
441 }
442
443 static int16_t sweep_footing_items(PlayerType *player_ptr, eg_type *eg_ptr)
444 {
445     for (const auto this_o_idx : eg_ptr->g_ptr->o_idx_list) {
446         ItemEntity *o_ptr;
447         o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
448         int16_t ret = describe_footing_sight(player_ptr, eg_ptr, o_ptr);
449         if (within_char_util(ret)) {
450             return (char)ret;
451         }
452     }
453
454     return CONTINUOUS_DESCRIPTION;
455 }
456
457 static std::string decide_target_floor(PlayerType *player_ptr, eg_type *eg_ptr)
458 {
459     auto *floor_ptr = player_ptr->current_floor_ptr;
460     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
461         QuestId old_quest = floor_ptr->quest_number;
462         const auto &quest_list = QuestList::get_instance();
463         const QuestId number = i2enum<QuestId>(eg_ptr->g_ptr->special);
464         const auto *q_ptr = &quest_list[number];
465         std::string_view msg(_("クエスト「%s」(%d階相当)", "the entrance to the quest '%s'(level %d)"));
466         for (int j = 0; j < 10; j++) {
467             quest_text[j][0] = '\0';
468         }
469
470         quest_text_line = 0;
471         floor_ptr->quest_number = number;
472         init_flags = INIT_NAME_ONLY;
473         parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
474         floor_ptr->quest_number = old_quest;
475         return format(msg.data(), q_ptr->name.data(), q_ptr->level);
476     }
477
478     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::BLDG) && !floor_ptr->inside_arena) {
479         return buildings[eg_ptr->f_ptr->subtype].name;
480     }
481
482     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
483         const auto &dungeon = dungeons_info[eg_ptr->g_ptr->special];
484         return format(_("%s(%d階相当)", "%s(level %d)"), dungeon.text.data(), dungeon.mindepth);
485     }
486
487     if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN)) {
488         return towns_info[eg_ptr->g_ptr->special].name;
489     }
490
491     if (player_ptr->wild_mode && (eg_ptr->feat == feat_floor)) {
492         return _("道", "road");
493     }
494
495     return eg_ptr->f_ptr->name;
496 }
497
498 static void describe_grid_monster_all(eg_type *eg_ptr)
499 {
500     if (!w_ptr->wizard) {
501 #ifdef JP
502         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);
503 #else
504         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);
505 #endif
506         return;
507     }
508
509     std::string f_idx_str;
510     if (eg_ptr->g_ptr->mimic) {
511         f_idx_str = format("%d/%d", eg_ptr->g_ptr->feat, eg_ptr->g_ptr->mimic);
512     } else {
513         f_idx_str = std::to_string(eg_ptr->g_ptr->feat);
514     }
515
516 #ifdef JP
517     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,
518         (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,
519         (int)eg_ptr->x, travel.cost[eg_ptr->y][eg_ptr->x]);
520 #else
521     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,
522         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);
523 #endif
524 }
525
526 /*!
527  * @brief xまたはlで指定したグリッドにあるアイテムやモンスターの説明を記述する
528  * @param player_ptr プレイヤーへの参照ポインタ
529  * @param y 指定グリッドのY座標
530  * @param x 指定グリッドのX座標
531  * @param mode x (KILL)かl (LOOK)
532  * @param info 記述用文字列
533  * @return 入力キー
534  * @todo xとlで処理を分ける?
535  */
536 char examine_grid(PlayerType *player_ptr, const POSITION y, const POSITION x, target_type mode, concptr info)
537 {
538     eg_type tmp_eg;
539     eg_type *eg_ptr = initialize_eg_type(player_ptr, &tmp_eg, y, x, mode, info);
540     describe_scan_result(player_ptr, eg_ptr);
541     describe_target(player_ptr, eg_ptr);
542     ProcessResult next_target = describe_hallucinated_target(player_ptr, eg_ptr);
543     switch (next_target) {
544     case ProcessResult::PROCESS_FALSE:
545         return 0;
546     case ProcessResult::PROCESS_TRUE:
547         return eg_ptr->query;
548     default:
549         break;
550     }
551
552     int16_t description_grid = describe_grid(player_ptr, eg_ptr);
553     if (within_char_util(description_grid)) {
554         return (char)description_grid;
555     }
556
557     int16_t loop_description = loop_describing_grid(player_ptr, eg_ptr);
558     if (within_char_util(loop_description)) {
559         return (char)loop_description;
560     }
561
562     int16_t footing_items_description = sweep_footing_items(player_ptr, eg_ptr);
563     if (within_char_util(footing_items_description)) {
564         return (char)footing_items_description;
565     }
566
567     eg_ptr->feat = eg_ptr->g_ptr->get_feat_mimic();
568     if (!eg_ptr->g_ptr->is_mark() && !player_can_see_bold(player_ptr, y, x)) {
569         eg_ptr->feat = feat_none;
570     }
571
572     eg_ptr->f_ptr = &terrains_info[eg_ptr->feat];
573     if (!eg_ptr->boring && eg_ptr->f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
574         return (eg_ptr->query != '\r') && (eg_ptr->query != '\n') ? eg_ptr->query : 0;
575     }
576
577     /*
578      * グローバル変数への代入をここで行っているので動かしたくない
579      * 安全を確保できたら構造体から外すことも検討する
580      */
581     eg_ptr->name = decide_target_floor(player_ptr, eg_ptr);
582     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))) {
583         eg_ptr->s2 = _("の中", "in ");
584     }
585
586     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)) {
587         eg_ptr->s2 = _("の入口", "");
588     }
589 #ifdef JP
590 #else
591     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)) {
592         eg_ptr->s3 = "";
593     } else {
594         eg_ptr->s3 = (is_a_vowel(eg_ptr->name[0])) ? "an " : "a ";
595     }
596 #endif
597
598     describe_grid_monster_all(eg_ptr);
599     prt(eg_ptr->out_val, 0, 0);
600     move_cursor_relative(y, x);
601     eg_ptr->query = inkey();
602     if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n')) {
603         return eg_ptr->query;
604     }
605
606     return 0;
607 }