OSDN Git Service

Merge pull request #855 from shimitei/feature/add_version_res
[hengbandforosx/hengbandosx.git] / src / target / grid-selector.cpp
1 #include <vector>
2 #include <unordered_map>
3
4 #include "core/player-redraw-types.h"
5 #include "core/player-update-types.h"
6 #include "core/stuff-handler.h"
7 #include "core/window-redrawer.h"
8 #include "floor/cave.h"
9 #include "game-option/game-play-options.h"
10 #include "game-option/input-options.h"
11 #include "game-option/keymap-directory-getter.h"
12 #include "grid/feature.h"
13 #include "grid/feature-flag-types.h"
14 #include "grid/grid.h"
15 #include "io/cursor.h"
16 #include "io/input-key-acceptor.h"
17 #include "io/screen-util.h"
18 #include "system/floor-type-definition.h"
19 #include "target/grid-selector.h"
20 #include "target/target-checker.h"
21 #include "term/screen-processor.h"
22 #include "util/int-char-converter.h"
23 #include "util/sort.h"
24 #include "view/display-messages.h"
25 #include "window/main-window-util.h"
26
27 /*
28  * XAngband: determine if a given location is "interesting"
29  * based on target_set_accept function.
30  */
31 static bool tgt_pt_accept(player_type *creature_ptr, POSITION y, POSITION x)
32 {
33     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
34     if (!(in_bounds(floor_ptr, y, x)))
35         return FALSE;
36
37     if ((y == creature_ptr->y) && (x == creature_ptr->x))
38         return TRUE;
39
40     if (creature_ptr->image)
41         return FALSE;
42
43     grid_type *g_ptr;
44     g_ptr = &floor_ptr->grid_array[y][x];
45     if (!(g_ptr->info & (CAVE_MARK)))
46         return FALSE;
47
48     if (cave_has_flag_grid(g_ptr, FF_LESS) || cave_has_flag_grid(g_ptr, FF_MORE) || cave_has_flag_grid(g_ptr, FF_QUEST_ENTER)
49         || cave_has_flag_grid(g_ptr, FF_QUEST_EXIT))
50         return TRUE;
51
52     if (cave_has_flag_grid(g_ptr, FF_STORE) || cave_has_flag_grid(g_ptr, FF_BLDG))
53         return TRUE;
54
55     return FALSE;
56 }
57
58 /*
59  * XAngband: Prepare the "temp" array for "tget_pt"
60  * based on target_set_prepare funciton.
61  */
62 static void tgt_pt_prepare(player_type *creature_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs)
63 {
64     if (!expand_list)
65         return;
66
67     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
68     for (POSITION y = 1; y < floor_ptr->height; y++) {
69         for (POSITION x = 1; x < floor_ptr->width; x++) {
70             if (!tgt_pt_accept(creature_ptr, y, x))
71                 continue;
72
73             ys.emplace_back(y);
74             xs.emplace_back(x);
75         }
76     }
77
78     ang_sort(creature_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_distance, ang_sort_swap_position);
79 }
80
81 /*!
82  * @brief グリッドのシンボルが指定した記号かどうかを調べる
83  * @param g_ptr グリッド情報への参照ポインタ
84  * @param ch 指定するシンボル文字
85  * @return シンボルが指定した記号ならTRUE、そうでなければFALSE
86  */
87 static bool cave_is_symbol_grid(grid_type* g_ptr, char ch) { return f_info[g_ptr->feat].x_char[0] == ch; }
88
89 /*!
90  * @brief 指定したシンボルのマスかどうかを判定するための条件式コールバック
91  */
92 std::unordered_map<int, std::function<bool(grid_type*)>> tgt_pt_symbol_call_back = {
93     { '<', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STAIRS) && cave_has_flag_grid(g_ptr, FF_LESS); } },
94     { '>', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STAIRS) && cave_has_flag_grid(g_ptr, FF_MORE); } },
95     { '+', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_BLDG); } },
96     { '0', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '0'); } },
97     { '!', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '1'); } },
98     { '"', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '2'); } },
99     { '#', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '3'); } },
100     { '$', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '4'); } },
101     { '%', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '5'); } },
102     { '&', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '6'); } },
103     { '\'', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '7'); } },
104     { '(', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '8'); } },
105     { ')', [](grid_type *g_ptr) { return cave_has_flag_grid(g_ptr, FF_STORE) && cave_is_symbol_grid(g_ptr, '9'); } },
106 };
107
108 /*!
109  * @brief 位置ターゲット指定情報構造体
110  * @details
111  * ang_sort() を利用する関係上、y/x 座標それぞれについて配列を作る。
112  */
113 struct tgt_pt_info {
114     TERM_LEN wid; //!< 画面サイズ(幅)
115     TERM_LEN hgt; //!< 画面サイズ(高さ)
116     POSITION y; //!< 現在の指定位置(Y)
117     POSITION x; //!< 現在の指定位置(X)
118     std::vector<POSITION> ys; //!< "interesting" な座標たちを記録する配列(Y)
119     std::vector<POSITION> xs; //!< "interesting" な座標たちを記録する配列(X)
120     size_t n; //<! シンボル配列の何番目か
121     char ch; //<! 入力キー
122     char prev_ch; //<! 前回入力キー
123     std::function<bool(grid_type *)> callback; //<! 条件判定コールバック
124 };
125
126 /*!
127  * @brief 指定した記号のシンボルのグリッドにカーソルを移動する
128  * @param creature_ptr プレイヤー情報への参照ポインタ
129  * @param info 位置ターゲット指定情報構造体(参照渡し)
130  * @return なし
131  */
132 void tgt_pt_move_to_symbol(player_type *creature_ptr, tgt_pt_info& info)
133 {
134     if (!expand_list || info.ys.empty())
135         return;
136
137     int dx, dy;
138     int cx = (panel_col_min + panel_col_max) / 2;
139     int cy = (panel_row_min + panel_row_max) / 2;
140     if (info.ch != info.prev_ch)
141         info.n = 0;
142     info.prev_ch = info.ch;
143     info.n++;
144
145     for (; info.n < size(info.ys); ++info.n) {
146         const POSITION y_cur = info.ys[info.n];
147         const POSITION x_cur = info.xs[info.n];
148         grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[y_cur][x_cur];
149         if (info.callback(g_ptr))
150             break;
151     }
152
153     if (info.n == size(info.ys)) {
154         info.n = 0;
155         info.y = creature_ptr->y;
156         info.x = creature_ptr->x;
157         verify_panel(creature_ptr);
158         creature_ptr->update |= PU_MONSTERS;
159         creature_ptr->redraw |= PR_MAP;
160         creature_ptr->window_flags |= PW_OVERHEAD;
161         handle_stuff(creature_ptr);
162     } else {
163         info.y = info.ys[info.n];
164         info.x = info.xs[info.n];
165         dy = 2 * (info.y - cy) / info.hgt;
166         dx = 2 * (info.x - cx) / info.wid;
167         if (dy || dx)
168             change_panel(creature_ptr, dy, dx);
169     }
170 }
171
172 /*!
173  * @brief 位置を指定するプロンプト
174  * @param creature_ptr プレイヤー情報への参照ポインタ
175  * @param x_ptr x座標への参照ポインタ
176  * @param y_ptr y座標への参照ポインタ
177  * @return 指定したらTRUE、キャンセルしたらFALSE
178  */
179 bool tgt_pt(player_type *creature_ptr, POSITION *x_ptr, POSITION *y_ptr)
180 {
181     tgt_pt_info info;
182     get_screen_size(&info.wid, &info.hgt);
183
184     info.y = creature_ptr->y;
185     info.x = creature_ptr->x;
186     if (expand_list)
187         tgt_pt_prepare(creature_ptr, info.ys, info.xs);
188
189     msg_print(_("場所を選んでスペースキーを押して下さい。", "Select a point and press space."));
190     msg_flag = FALSE;
191
192     info.ch = 0;
193     info.n = 0;
194     bool success = FALSE;
195     while ((info.ch != ESCAPE) && !success) {
196         bool move_fast = FALSE;
197         move_cursor_relative(info.y, info.x);
198         info.ch = inkey();
199         switch (info.ch) {
200         case ESCAPE:
201             break;
202         case ' ':
203         case 't':
204         case '.':
205             if (player_bold(creature_ptr, info.y, info.x))
206                 info.ch = 0;
207             else
208                 success = TRUE;
209             break;
210         case '>':
211         case '<':
212         case '+':
213         case '!':
214         case '"':
215         case '#':
216         case '$':
217         case '%':
218         case '&':
219         case '\'':
220         case '(':
221         case ')': {
222             info.callback = tgt_pt_symbol_call_back[info.ch];
223             tgt_pt_move_to_symbol(creature_ptr, info);
224             break;
225         }
226         default: {
227             if (rogue_like_commands) {
228                 if (info.ch >= '0' && info.ch <= '9') {
229                     if (info.ch != '0')
230                         info.ch -= 16;
231                     info.callback = tgt_pt_symbol_call_back[info.ch];
232                     tgt_pt_move_to_symbol(creature_ptr, info);
233                     break;
234                 }
235             } else {
236                 if (info.ch == '5' || info.ch == '0') {
237                     if (player_bold(creature_ptr, info.y, info.x))
238                         info.ch = 0;
239                     else
240                         success = TRUE;
241                     break;
242                 }
243             }
244
245             int d = get_keymap_dir(info.ch);
246             if (isupper(info.ch))
247                 move_fast = TRUE;
248
249             if (d == 0)
250                 break;
251
252             int dx = ddx[d];
253             int dy = ddy[d];
254             if (move_fast) {
255                 int mag = MIN(info.wid / 2, info.hgt / 2);
256                 info.x += dx * mag;
257                 info.y += dy * mag;
258             } else {
259                 info.x += dx;
260                 info.y += dy;
261             }
262
263             if (((info.x < panel_col_min + info.wid / 2) && (dx > 0)) || ((info.x > panel_col_min + info.wid / 2) && (dx < 0)))
264                 dx = 0;
265
266             if (((info.y < panel_row_min + info.hgt / 2) && (dy > 0)) || ((info.y > panel_row_min + info.hgt / 2) && (dy < 0)))
267                 dy = 0;
268
269             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))
270                 change_panel(creature_ptr, dy, dx);
271
272             if (info.x >= creature_ptr->current_floor_ptr->width - 1)
273                 info.x = creature_ptr->current_floor_ptr->width - 2;
274             else if (info.x <= 0)
275                 info.x = 1;
276
277             if (info.y >= creature_ptr->current_floor_ptr->height - 1)
278                 info.y = creature_ptr->current_floor_ptr->height - 2;
279             else if (info.y <= 0)
280                 info.y = 1;
281
282             break;
283         }
284         }
285     }
286
287     prt("", 0, 0);
288     verify_panel(creature_ptr);
289     creature_ptr->update |= PU_MONSTERS;
290     creature_ptr->redraw |= PR_MAP;
291     creature_ptr->window_flags |= PW_OVERHEAD;
292     handle_stuff(creature_ptr);
293     *x_ptr = info.x;
294     *y_ptr = info.y;
295     return success;
296 }