1 #include "target/grid-selector.h"
2 #include "core/stuff-handler.h"
3 #include "core/window-redrawer.h"
4 #include "floor/cave.h"
5 #include "floor/geometry.h"
6 #include "game-option/game-play-options.h"
7 #include "game-option/input-options.h"
8 #include "game-option/keymap-directory-getter.h"
9 #include "grid/feature-flag-types.h"
10 #include "io/cursor.h"
11 #include "io/input-key-acceptor.h"
12 #include "io/screen-util.h"
13 #include "system/floor-type-definition.h"
14 #include "system/grid-type-definition.h"
15 #include "system/redrawing-flags-updater.h"
16 #include "target/target-checker.h"
17 #include "term/screen-processor.h"
18 #include "timed-effect/player-hallucination.h"
19 #include "timed-effect/timed-effects.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(PlayerType *player_ptr, POSITION y, POSITION x)
34 auto *floor_ptr = player_ptr->current_floor_ptr;
35 if (!(in_bounds(floor_ptr, y, x))) {
39 if ((y == player_ptr->y) && (x == player_ptr->x)) {
43 if (player_ptr->effects()->hallucination()->is_hallucinated()) {
47 auto &grid = floor_ptr->grid_array[y][x];
48 if (!grid.is_mark()) {
52 using Tc = TerrainCharacteristics;
53 auto is_acceptable = grid.cave_has_flag(Tc::LESS);
54 is_acceptable |= grid.cave_has_flag(Tc::MORE);
55 is_acceptable |= grid.cave_has_flag(Tc::QUEST_ENTER);
56 is_acceptable |= grid.cave_has_flag(Tc::QUEST_EXIT);
57 is_acceptable |= grid.cave_has_flag(Tc::STORE);
58 is_acceptable |= grid.cave_has_flag(Tc::BLDG);
63 * XAngband: Prepare the "temp" array for "tget_pt"
64 * based on target_set_prepare funciton.
66 static void tgt_pt_prepare(PlayerType *player_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs)
72 auto *floor_ptr = player_ptr->current_floor_ptr;
73 for (POSITION y = 1; y < floor_ptr->height; y++) {
74 for (POSITION x = 1; x < floor_ptr->width; x++) {
75 if (!tgt_pt_accept(player_ptr, y, x)) {
84 ang_sort(player_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_distance, ang_sort_swap_position);
88 * @brief 指定したシンボルのマスかどうかを判定するための条件式コールバック
90 std::unordered_map<int, std::function<bool(Grid *)>> tgt_pt_symbol_call_back = {
91 { '<', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::LESS); } },
92 { '>', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::MORE); } },
93 { '+', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::BLDG); } },
94 { '0', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('0'); } },
95 { '!', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('1'); } },
96 { '"', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('2'); } },
97 { '#', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('3'); } },
98 { '$', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('4'); } },
99 { '%', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('5'); } },
100 { '&', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('6'); } },
101 { '\'', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('7'); } },
102 { '(', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('8'); } },
103 { ')', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('9'); } },
107 * @brief 位置ターゲット指定情報構造体
109 * ang_sort() を利用する関係上、y/x 座標それぞれについて配列を作る。
114 std::tie(this->width, this->height) = get_screen_size();
117 int width; //!< 画面サイズ(幅)
118 int height; //!< 画面サイズ(高さ)
119 POSITION y = 0; //!< 現在の指定位置(Y)
120 POSITION x = 0; //!< 現在の指定位置(X)
121 std::vector<POSITION> ys{}; //!< "interesting" な座標たちを記録する配列(Y)
122 std::vector<POSITION> xs{}; //!< "interesting" な座標たちを記録する配列(X)
123 size_t n = 0; //<! シンボル配列の何番目か
124 char ch = '\0'; //<! 入力キー
125 char prev_ch = '\0'; //<! 前回入力キー
126 std::function<bool(Grid *)> callback{}; //<! 条件判定コールバック
128 void move_to_symbol(PlayerType *player_ptr);
132 * @brief 指定した記号のシンボルのグリッドにカーソルを移動する
133 * @param player_ptr プレイヤー情報への参照ポインタ
134 * @details 自分 (@)の位置に戻ってくるような処理に見える.
137 void tgt_pt_info::move_to_symbol(PlayerType *player_ptr)
139 if (!expand_list || this->ys.empty()) {
144 int cx = (panel_col_min + panel_col_max) / 2;
145 int cy = (panel_row_min + panel_row_max) / 2;
146 if (this->ch != this->prev_ch) {
149 this->prev_ch = this->ch;
152 for (; this->n < size(this->ys); ++this->n) {
153 const POSITION y_cur = this->ys[this->n];
154 const POSITION x_cur = this->xs[this->n];
155 auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y_cur][x_cur];
156 if (this->callback(g_ptr)) {
161 if (this->n == size(this->ys)) {
163 this->y = player_ptr->y;
164 this->x = player_ptr->x;
165 verify_panel(player_ptr);
166 auto &rfu = RedrawingFlagsUpdater::get_instance();
167 rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
168 rfu.set_flag(MainWindowRedrawingFlag::MAP);
169 rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
170 handle_stuff(player_ptr);
172 this->y = this->ys[this->n];
173 this->x = this->xs[this->n];
174 dy = 2 * (this->y - cy) / this->height;
175 dx = 2 * (this->x - cx) / this->width;
177 change_panel(player_ptr, dy, dx);
183 * @brief 位置を指定するプロンプト
184 * @param player_ptr プレイヤー情報への参照ポインタ
185 * @param x_ptr x座標への参照ポインタ
186 * @param y_ptr y座標への参照ポインタ
187 * @return 指定したらTRUE、キャンセルしたらFALSE
189 bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
192 info.y = player_ptr->y;
193 info.x = player_ptr->x;
195 tgt_pt_prepare(player_ptr, info.ys, info.xs);
198 msg_print(_("場所を選んでスペースキーを押して下さい。", "Select a point and press space."));
203 bool success = false;
204 while ((info.ch != ESCAPE) && !success) {
205 bool move_fast = false;
206 move_cursor_relative(info.y, info.x);
214 if (player_ptr->is_located_at({ info.y, info.x })) {
232 info.callback = tgt_pt_symbol_call_back[info.ch];
233 info.move_to_symbol(player_ptr);
237 if (rogue_like_commands) {
238 if (info.ch >= '0' && info.ch <= '9') {
239 if (info.ch != '0') {
242 info.callback = tgt_pt_symbol_call_back[info.ch];
243 info.move_to_symbol(player_ptr);
247 if (info.ch == '5' || info.ch == '0') {
248 if (player_ptr->is_located_at({ info.y, info.x })) {
257 int d = get_keymap_dir(info.ch);
258 if (isupper(info.ch)) {
269 int mag = std::min(info.width / 2, info.height / 2);
277 if (((info.x < panel_col_min + info.width / 2) && (dx > 0)) || ((info.x > panel_col_min + info.width / 2) && (dx < 0))) {
281 if (((info.y < panel_row_min + info.height / 2) && (dy > 0)) || ((info.y > panel_row_min + info.height / 2) && (dy < 0))) {
285 if ((info.y >= panel_row_min + info.height) || (info.y < panel_row_min) || (info.x >= panel_col_min + info.width) || (info.x < panel_col_min)) {
286 change_panel(player_ptr, dy, dx);
289 if (info.x >= player_ptr->current_floor_ptr->width - 1) {
290 info.x = player_ptr->current_floor_ptr->width - 2;
291 } else if (info.x <= 0) {
295 if (info.y >= player_ptr->current_floor_ptr->height - 1) {
296 info.y = player_ptr->current_floor_ptr->height - 2;
297 } else if (info.y <= 0) {
307 verify_panel(player_ptr);
308 auto &rfu = RedrawingFlagsUpdater::get_instance();
309 rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
310 rfu.set_flag(MainWindowRedrawingFlag::MAP);
311 rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
312 handle_stuff(player_ptr);