1 #include "target/grid-selector.h"
2 #include "core/player-redraw-types.h"
3 #include "core/player-update-types.h"
4 #include "core/stuff-handler.h"
5 #include "core/window-redrawer.h"
6 #include "floor/cave.h"
7 #include "floor/geometry.h"
8 #include "game-option/game-play-options.h"
9 #include "game-option/input-options.h"
10 #include "game-option/keymap-directory-getter.h"
11 #include "grid/feature-flag-types.h"
12 #include "grid/feature.h"
13 #include "io/cursor.h"
14 #include "io/input-key-acceptor.h"
15 #include "io/screen-util.h"
16 #include "system/floor-type-definition.h"
17 #include "system/grid-type-definition.h"
18 #include "target/target-checker.h"
19 #include "term/screen-processor.h"
20 #include "util/int-char-converter.h"
21 #include "util/sort.h"
22 #include "view/display-messages.h"
23 #include "window/main-window-util.h"
25 #include <unordered_map>
29 * XAngband: determine if a given location is "interesting"
30 * based on target_set_accept function.
32 static bool tgt_pt_accept(player_type *creature_ptr, POSITION y, POSITION x)
34 floor_type *floor_ptr = creature_ptr->current_floor_ptr;
35 if (!(in_bounds(floor_ptr, y, x)))
38 if ((y == creature_ptr->y) && (x == creature_ptr->x))
41 if (creature_ptr->image)
45 g_ptr = &floor_ptr->grid_array[y][x];
46 if (!g_ptr->is_mark())
49 if (g_ptr->cave_has_flag(FF::LESS) || g_ptr->cave_has_flag(FF::MORE) || g_ptr->cave_has_flag(FF::QUEST_ENTER)
50 || g_ptr->cave_has_flag(FF::QUEST_EXIT))
53 if (g_ptr->cave_has_flag(FF::STORE) || g_ptr->cave_has_flag(FF::BLDG))
60 * XAngband: Prepare the "temp" array for "tget_pt"
61 * based on target_set_prepare funciton.
63 static void tgt_pt_prepare(player_type *creature_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs)
68 floor_type *floor_ptr = creature_ptr->current_floor_ptr;
69 for (POSITION y = 1; y < floor_ptr->height; y++) {
70 for (POSITION x = 1; x < floor_ptr->width; x++) {
71 if (!tgt_pt_accept(creature_ptr, y, x))
79 ang_sort(creature_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_distance, ang_sort_swap_position);
83 * @brief グリッドのシンボルが指定した記号かどうかを調べる
84 * @param g_ptr グリッド情報への参照ポインタ
85 * @param ch 指定するシンボル文字
86 * @return シンボルが指定した記号ならTRUE、そうでなければFALSE
88 static bool cave_is_symbol_grid(grid_type *g_ptr, char ch)
90 return f_info[g_ptr->feat].x_char[0] == ch;
94 * @brief 指定したシンボルのマスかどうかを判定するための条件式コールバック
96 std::unordered_map<int, std::function<bool(grid_type *)>> tgt_pt_symbol_call_back = {
97 { '<', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STAIRS) && g_ptr->cave_has_flag(FF::LESS); } },
98 { '>', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STAIRS) && g_ptr->cave_has_flag(FF::MORE); } },
99 { '+', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::BLDG); } },
100 { '0', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '0'); } },
101 { '!', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '1'); } },
102 { '"', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '2'); } },
103 { '#', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '3'); } },
104 { '$', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '4'); } },
105 { '%', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '5'); } },
106 { '&', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '6'); } },
107 { '\'', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '7'); } },
108 { '(', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '8'); } },
109 { ')', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(FF::STORE) && cave_is_symbol_grid(g_ptr, '9'); } },
113 * @brief 位置ターゲット指定情報構造体
115 * ang_sort() を利用する関係上、y/x 座標それぞれについて配列を作る。
118 TERM_LEN wid; //!< 画面サイズ(幅)
119 TERM_LEN hgt; //!< 画面サイズ(高さ)
120 POSITION y; //!< 現在の指定位置(Y)
121 POSITION x; //!< 現在の指定位置(X)
122 std::vector<POSITION> ys; //!< "interesting" な座標たちを記録する配列(Y)
123 std::vector<POSITION> xs; //!< "interesting" な座標たちを記録する配列(X)
124 size_t n; //<! シンボル配列の何番目か
126 char prev_ch; //<! 前回入力キー
127 std::function<bool(grid_type *)> callback; //<! 条件判定コールバック
131 * @brief 指定した記号のシンボルのグリッドにカーソルを移動する
132 * @param creature_ptr プレイヤー情報への参照ポインタ
133 * @param info 位置ターゲット指定情報構造体(参照渡し)
135 void tgt_pt_move_to_symbol(player_type *creature_ptr, tgt_pt_info &info)
137 if (!expand_list || info.ys.empty())
141 int cx = (panel_col_min + panel_col_max) / 2;
142 int cy = (panel_row_min + panel_row_max) / 2;
143 if (info.ch != info.prev_ch)
145 info.prev_ch = info.ch;
148 for (; info.n < size(info.ys); ++info.n) {
149 const POSITION y_cur = info.ys[info.n];
150 const POSITION x_cur = info.xs[info.n];
151 grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[y_cur][x_cur];
152 if (info.callback(g_ptr))
156 if (info.n == size(info.ys)) {
158 info.y = creature_ptr->y;
159 info.x = creature_ptr->x;
160 verify_panel(creature_ptr);
161 creature_ptr->update |= PU_MONSTERS;
162 creature_ptr->redraw |= PR_MAP;
163 creature_ptr->window_flags |= PW_OVERHEAD;
164 handle_stuff(creature_ptr);
166 info.y = info.ys[info.n];
167 info.x = info.xs[info.n];
168 dy = 2 * (info.y - cy) / info.hgt;
169 dx = 2 * (info.x - cx) / info.wid;
171 change_panel(creature_ptr, dy, dx);
176 * @brief 位置を指定するプロンプト
177 * @param creature_ptr プレイヤー情報への参照ポインタ
178 * @param x_ptr x座標への参照ポインタ
179 * @param y_ptr y座標への参照ポインタ
180 * @return 指定したらTRUE、キャンセルしたらFALSE
182 bool tgt_pt(player_type *creature_ptr, POSITION *x_ptr, POSITION *y_ptr)
185 get_screen_size(&info.wid, &info.hgt);
187 info.y = creature_ptr->y;
188 info.x = creature_ptr->x;
190 tgt_pt_prepare(creature_ptr, info.ys, info.xs);
192 msg_print(_("場所を選んでスペースキーを押して下さい。", "Select a point and press space."));
197 bool success = false;
198 while ((info.ch != ESCAPE) && !success) {
199 bool move_fast = false;
200 move_cursor_relative(info.y, info.x);
208 if (player_bold(creature_ptr, info.y, info.x))
225 info.callback = tgt_pt_symbol_call_back[info.ch];
226 tgt_pt_move_to_symbol(creature_ptr, info);
230 if (rogue_like_commands) {
231 if (info.ch >= '0' && info.ch <= '9') {
234 info.callback = tgt_pt_symbol_call_back[info.ch];
235 tgt_pt_move_to_symbol(creature_ptr, info);
239 if (info.ch == '5' || info.ch == '0') {
240 if (player_bold(creature_ptr, info.y, info.x))
248 int d = get_keymap_dir(info.ch);
249 if (isupper(info.ch))
258 int mag = MIN(info.wid / 2, info.hgt / 2);
266 if (((info.x < panel_col_min + info.wid / 2) && (dx > 0)) || ((info.x > panel_col_min + info.wid / 2) && (dx < 0)))
269 if (((info.y < panel_row_min + info.hgt / 2) && (dy > 0)) || ((info.y > panel_row_min + info.hgt / 2) && (dy < 0)))
272 if ((info.y >= panel_row_min + info.hgt) || (info.y < panel_row_min) || (info.x >= panel_col_min + info.wid) || (info.x < panel_col_min))
273 change_panel(creature_ptr, dy, dx);
275 if (info.x >= creature_ptr->current_floor_ptr->width - 1)
276 info.x = creature_ptr->current_floor_ptr->width - 2;
277 else if (info.x <= 0)
280 if (info.y >= creature_ptr->current_floor_ptr->height - 1)
281 info.y = creature_ptr->current_floor_ptr->height - 2;
282 else if (info.y <= 0)
291 verify_panel(creature_ptr);
292 creature_ptr->update |= PU_MONSTERS;
293 creature_ptr->redraw |= PR_MAP;
294 creature_ptr->window_flags |= PW_OVERHEAD;
295 handle_stuff(creature_ptr);