OSDN Git Service

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