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"
51 static const int16_t CONTINUOUS_DESCRIPTION = 256;
53 bool show_gold_on_floor = false;
67 char out_val[MAX_NLEN + 80];
68 OBJECT_IDX floor_list[23];
69 ITEM_NUMBER floor_num;
72 OBJECT_IDX next_o_idx;
78 static eg_type *initialize_eg_type(PlayerType *player_ptr, eg_type *eg_ptr, POSITION y, POSITION x, target_type mode, concptr info)
82 eg_ptr->boring = true;
89 eg_ptr->query = '\001';
90 eg_ptr->floor_num = 0;
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;
100 * Evaluate number of kill needed to gain level
102 static std::string evaluate_monster_exp(PlayerType *player_ptr, MonsterEntity *m_ptr)
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)) {
109 if (!ap_r_ptr->r_tkills || m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
110 if (!w_ptr->wizard) {
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));
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);
123 s64b_sub(&exp_adv, &exp_adv_frac, player_ptr->exp, player_ptr->exp_frac);
125 s64b_add(&exp_adv, &exp_adv_frac, exp_mon, exp_mon_frac);
126 s64b_sub(&exp_adv, &exp_adv_frac, 0, 1);
128 s64b_div(&exp_adv, &exp_adv_frac, exp_mon, exp_mon_frac);
130 auto num = std::min<uint>(999, exp_adv_frac);
131 return format("%03ld", (long int)num);
134 static void describe_scan_result(PlayerType *player_ptr, eg_type *eg_ptr)
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,");
146 static void describe_target(PlayerType *player_ptr, eg_type *eg_ptr)
148 if (!player_bold(player_ptr, eg_ptr->y, eg_ptr->x)) {
149 eg_ptr->s1 = _("ターゲット:", "Target:");
158 eg_ptr->s1 = "You are ";
163 static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, eg_type *eg_ptr)
165 if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
166 return ProcessResult::PROCESS_CONTINUE;
169 concptr name = _("何か奇妙な物", "something strange");
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);
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);
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;
182 return ProcessResult::PROCESS_FALSE;
185 static bool describe_grid_lore(PlayerType *player_ptr, eg_type *eg_ptr)
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();
192 return eg_ptr->query != 'r';
195 static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
198 GAME_TEXT m_name[MAX_NLEN];
199 monster_desc(player_ptr, m_name, eg_ptr->m_ptr, MD_INDEF_VISIBLE);
202 if (describe_grid_lore(player_ptr, eg_ptr)) {
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);
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);
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);
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') {
230 static void describe_monster_person(eg_type *eg_ptr)
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 ");
242 eg_ptr->s3 = "持っている";
244 eg_ptr->s2 = "carrying ";
248 static uint16_t describe_monster_item(PlayerType *player_ptr, eg_type *eg_ptr)
250 for (const auto this_o_idx : eg_ptr->m_ptr->hold_o_idx_list) {
251 GAME_TEXT o_name[MAX_NLEN];
253 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
254 describe_flavor(player_ptr, o_name, o_ptr, 0);
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);
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);
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;
267 if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
268 return eg_ptr->query;
271 eg_ptr->s2 = _("をまた", "also carrying ");
274 return CONTINUOUS_DESCRIPTION;
277 static bool within_char_util(int16_t input)
279 return (input > -127) && (input < 128);
282 static int16_t describe_grid(PlayerType *player_ptr, eg_type *eg_ptr)
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;
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;
297 if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
298 return eg_ptr->query;
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;
313 return CONTINUOUS_DESCRIPTION;
316 static int16_t describe_footing(PlayerType *player_ptr, eg_type *eg_ptr)
318 if (eg_ptr->floor_num != 1) {
319 return CONTINUOUS_DESCRIPTION;
322 GAME_TEXT o_name[MAX_NLEN];
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);
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);
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);
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;
337 static int16_t describe_footing_items(eg_type *eg_ptr)
339 if (!eg_ptr->boring) {
340 return CONTINUOUS_DESCRIPTION;
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);
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);
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;
355 return CONTINUOUS_DESCRIPTION;
358 static char describe_footing_many_items(PlayerType *player_ptr, eg_type *eg_ptr, int *min_width)
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;
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);
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);
370 prt(eg_ptr->out_val, 0, 0);
371 eg_ptr->query = inkey();
373 if (eg_ptr->query != '\n' && eg_ptr->query != '\r') {
374 return eg_ptr->query;
377 if (eg_ptr->g_ptr->o_idx_list.size() < 2) {
381 eg_ptr->g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
383 // ターゲットしている床の座標を渡す必要があるので、window_stuff経由ではなく直接呼び出す
384 fix_floor_item_list(player_ptr, eg_ptr->y, eg_ptr->x);
388 static int16_t loop_describing_grid(PlayerType *player_ptr, eg_type *eg_ptr)
390 if (eg_ptr->floor_num == 0) {
391 return CONTINUOUS_DESCRIPTION;
396 int16_t footing_description = describe_footing(player_ptr, eg_ptr);
397 if (within_char_util(footing_description)) {
398 return (char)footing_description;
401 int16_t footing_descriptions = describe_footing_items(eg_ptr);
402 if (within_char_util(footing_descriptions)) {
403 return (char)footing_descriptions;
406 return describe_footing_many_items(player_ptr, eg_ptr, &min_width);
410 static int16_t describe_footing_sight(PlayerType *player_ptr, eg_type *eg_ptr, ItemEntity *o_ptr)
412 if (o_ptr->marked.has_not(OmType::FOUND)) {
413 return CONTINUOUS_DESCRIPTION;
416 GAME_TEXT o_name[MAX_NLEN];
417 eg_ptr->boring = false;
418 describe_flavor(player_ptr, o_name, o_ptr, 0);
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);
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);
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;
431 if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
432 return eg_ptr->query;
435 eg_ptr->s1 = _("それは", "It is ");
436 if (o_ptr->number != 1) {
437 eg_ptr->s1 = _("それらは", "They are ");
446 return CONTINUOUS_DESCRIPTION;
449 static int16_t sweep_footing_items(PlayerType *player_ptr, eg_type *eg_ptr)
451 for (const auto this_o_idx : eg_ptr->g_ptr->o_idx_list) {
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)) {
460 return CONTINUOUS_DESCRIPTION;
463 static std::string decide_target_floor(PlayerType *player_ptr, eg_type *eg_ptr)
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';
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);
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;
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);
491 if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN)) {
492 return town_info[eg_ptr->g_ptr->special].name;
495 if (player_ptr->wild_mode && (eg_ptr->feat == feat_floor)) {
496 return _("道", "road");
499 return eg_ptr->f_ptr->name.data();
502 static void describe_grid_monster_all(eg_type *eg_ptr)
504 if (!w_ptr->wizard) {
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);
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);
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);
517 f_idx_str = std::to_string(eg_ptr->g_ptr->feat);
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]);
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);
531 * @brief xまたはlで指定したグリッドにあるアイテムやモンスターの説明を記述する
532 * @param player_ptr プレイヤーへの参照ポインタ
533 * @param y 指定グリッドのY座標
534 * @param x 指定グリッドのX座標
535 * @param mode x (KILL)かl (LOOK)
540 char examine_grid(PlayerType *player_ptr, const POSITION y, const POSITION x, target_type mode, concptr info)
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:
550 case ProcessResult::PROCESS_TRUE:
551 return eg_ptr->query;
556 int16_t description_grid = describe_grid(player_ptr, eg_ptr);
557 if (within_char_util(description_grid)) {
558 return (char)description_grid;
561 int16_t loop_description = loop_describing_grid(player_ptr, eg_ptr);
562 if (within_char_util(loop_description)) {
563 return (char)loop_description;
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;
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;
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;
582 * グローバル変数への代入をここで行っているので動かしたくない
583 * 安全を確保できたら構造体から外すことも検討する
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 ");
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 = _("の入口", "");
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)) {
598 eg_ptr->s3 = (is_a_vowel(eg_ptr->name[0])) ? "an " : "a ";
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;