OSDN Git Service

[Refactor] #40571 Separated set_target_grid() from target_set()
[hengbandforosx/hengbandosx.git] / src / target / target-setter.c
1 #include "target/target-setter.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/floor.h"
7 #include "game-option/cheat-options.h"
8 #include "game-option/game-play-options.h"
9 #include "game-option/input-options.h"
10 #include "grid/grid.h"
11 #include "io/cursor.h"
12 #include "io/input-key-requester.h"
13 #include "io/screen-util.h"
14 #include "main/sound-of-music.h"
15 #include "system/floor-type-definition.h"
16 #include "target/target-checker.h"
17 #include "target/target-describer.h"
18 #include "target/target-preparation.h"
19 #include "target/target-types.h"
20 #include "term/screen-processor.h"
21 #include "util/int-char-converter.h"
22 #include "window/main-window-util.h"
23
24 // Target Setter.
25 typedef struct ts_type {
26     target_type mode;
27     POSITION y;
28     POSITION x;
29     POSITION y2;
30     POSITION x2;
31     bool done;
32     bool flag;
33     char query;
34     char info[80];
35     grid_type *g_ptr;
36     TERM_LEN wid, hgt;
37     int m;
38     int distance;
39     int target_num;
40 } ts_type;
41
42 static ts_type *initialize_target_set_type(player_type *creature_ptr, ts_type *ts_ptr, target_type mode)
43 {
44     ts_ptr->mode = mode;
45     ts_ptr->y = creature_ptr->y;
46     ts_ptr->x = creature_ptr->x;
47     ts_ptr->done = FALSE;
48     ts_ptr->flag = TRUE;
49     get_screen_size(&ts_ptr->wid, &ts_ptr->hgt);
50     ts_ptr->m = 0;
51     return ts_ptr;
52 }
53
54 /*!
55  * @brief フォーカスを当てるべきマップ描画の基準座標を指定する
56  * @param creature_ptr プレーヤーへの参照ポインタ
57  * @param y 変更先のフロアY座標
58  * @param x 変更先のフロアX座標
59  * @details
60  * Handle a request to change the current panel
61  * Return TRUE if the panel was changed.
62  * Also used in do_cmd_locate
63  * @return 実際に再描画が必要だった場合TRUEを返す
64  */
65 static bool change_panel_xy(player_type *creature_ptr, POSITION y, POSITION x)
66 {
67     POSITION dy = 0, dx = 0;
68     TERM_LEN wid, hgt;
69     get_screen_size(&wid, &hgt);
70     if (y < panel_row_min)
71         dy = -1;
72
73     if (y > panel_row_max)
74         dy = 1;
75
76     if (x < panel_col_min)
77         dx = -1;
78
79     if (x > panel_col_max)
80         dx = 1;
81
82     if (!dy && !dx)
83         return FALSE;
84
85     return change_panel(creature_ptr, dy, dx);
86 }
87
88 /*
89  * Help "select" a location (see below)
90  */
91 static POSITION_IDX target_pick(POSITION y1, POSITION x1, POSITION dy, POSITION dx)
92 {
93     POSITION_IDX b_i = -1, b_v = 9999;
94     for (POSITION_IDX i = 0; i < tmp_pos.n; i++) {
95         POSITION x2 = tmp_pos.x[i];
96         POSITION y2 = tmp_pos.y[i];
97         POSITION x3 = (x2 - x1);
98         POSITION y3 = (y2 - y1);
99         if (dx && (x3 * dx <= 0))
100             continue;
101
102         if (dy && (y3 * dy <= 0))
103             continue;
104
105         POSITION x4 = ABS(x3);
106         POSITION y4 = ABS(y3);
107         if (dy && !dx && (x4 > y4))
108             continue;
109
110         if (dx && !dy && (y4 > x4))
111             continue;
112
113         POSITION_IDX v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));
114         if ((b_i >= 0) && (v >= b_v))
115             continue;
116
117         b_i = i;
118         b_v = v;
119     }
120
121     return b_i;
122 }
123
124 static void describe_projectablity(player_type *creature_ptr, ts_type *ts_ptr)
125 {
126     ts_ptr->y = tmp_pos.y[ts_ptr->m];
127     ts_ptr->x = tmp_pos.x[ts_ptr->m];
128     change_panel_xy(creature_ptr, ts_ptr->y, ts_ptr->x);
129     if ((ts_ptr->mode & TARGET_LOOK) == 0)
130         print_path(creature_ptr, ts_ptr->y, ts_ptr->x);
131
132     ts_ptr->g_ptr = &creature_ptr->current_floor_ptr->grid_array[ts_ptr->y][ts_ptr->x];
133     if (target_able(creature_ptr, ts_ptr->g_ptr->m_idx))
134         strcpy(ts_ptr->info, _("q止 t決 p自 o現 +次 -前", "q,t,p,o,+,-,<dir>"));
135     else
136         strcpy(ts_ptr->info, _("q止 p自 o現 +次 -前", "q,p,o,+,-,<dir>"));
137
138     if (!cheat_sight)
139         return;
140
141     char cheatinfo[30];
142     sprintf(cheatinfo, " LOS:%d, PROJECTABLE:%d", los(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x),
143         projectable(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x));
144     strcat(ts_ptr->info, cheatinfo);
145 }
146
147 static void menu_target(ts_type *ts_ptr)
148 {
149     if (!use_menu)
150         return;
151
152     if (ts_ptr->query == '\r')
153         ts_ptr->query = 't';
154 }
155
156 static void switch_target_input(player_type *creature_ptr, ts_type *ts_ptr)
157 {
158     ts_ptr->distance = 0;
159     switch (ts_ptr->query) {
160     case ESCAPE:
161     case 'q':
162         ts_ptr->done = TRUE;
163         return;
164     case 't':
165     case '.':
166     case '5':
167     case '0':
168         if (!target_able(creature_ptr, ts_ptr->g_ptr->m_idx)) {
169             bell();
170             return;
171         }
172
173         health_track(creature_ptr, ts_ptr->g_ptr->m_idx);
174         target_who = ts_ptr->g_ptr->m_idx;
175         target_row = ts_ptr->y;
176         target_col = ts_ptr->x;
177         ts_ptr->done = TRUE;
178         return;
179     case ' ':
180     case '*':
181     case '+':
182         if (++ts_ptr->m != tmp_pos.n)
183             return;
184
185         ts_ptr->m = 0;
186         if (!expand_list)
187             ts_ptr->done = TRUE;
188
189         return;
190     case '-':
191         if (ts_ptr->m-- != 0)
192             return;
193
194         ts_ptr->m = tmp_pos.n - 1;
195         if (!expand_list)
196             ts_ptr->done = TRUE;
197
198         return;
199     case 'p': {
200         verify_panel(creature_ptr);
201         creature_ptr->update |= PU_MONSTERS;
202         creature_ptr->redraw |= PR_MAP;
203         creature_ptr->window |= PW_OVERHEAD;
204         handle_stuff(creature_ptr);
205         target_set_prepare(creature_ptr, ts_ptr->mode);
206         ts_ptr->y = creature_ptr->y;
207         ts_ptr->x = creature_ptr->x;
208     }
209         /* Fall through */
210     case 'o':
211         ts_ptr->flag = FALSE;
212         return;
213     case 'm':
214         return;
215     default:
216         if (ts_ptr->query != rogue_like_commands ? 'x' : 'l') {
217             ts_ptr->distance = get_keymap_dir(ts_ptr->query);
218             if (ts_ptr->distance == 0)
219                 bell();
220
221             return;
222         }
223
224         if (++ts_ptr->m != tmp_pos.n)
225             return;
226
227         ts_ptr->m = 0;
228         if (!expand_list)
229             ts_ptr->done = TRUE;
230
231         return;
232     }
233 }
234
235 static bool check_panel_changed(player_type *creature_ptr, ts_type *ts_ptr)
236 {
237     if (!change_panel(creature_ptr, ddy[ts_ptr->distance], ddx[ts_ptr->distance]))
238         return FALSE;
239
240     int v = tmp_pos.y[ts_ptr->m];
241     int u = tmp_pos.x[ts_ptr->m];
242     target_set_prepare(creature_ptr, ts_ptr->mode);
243     ts_ptr->flag = TRUE;
244     ts_ptr->target_num = target_pick(v, u, ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
245     if (ts_ptr->target_num >= 0)
246         ts_ptr->m = ts_ptr->target_num;
247
248     return TRUE;
249 }
250
251 static void sweep_targets(player_type *creature_ptr, ts_type *ts_ptr)
252 {
253     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
254     while (ts_ptr->flag && (ts_ptr->target_num < 0)) {
255         if (check_panel_changed(creature_ptr, ts_ptr))
256             continue;
257
258         POSITION dx = ddx[ts_ptr->distance];
259         POSITION dy = ddy[ts_ptr->distance];
260         panel_row_min = ts_ptr->y2;
261         panel_col_min = ts_ptr->x2;
262         panel_bounds_center();
263         creature_ptr->update |= PU_MONSTERS;
264         creature_ptr->redraw |= PR_MAP;
265         creature_ptr->window |= PW_OVERHEAD;
266         handle_stuff(creature_ptr);
267         target_set_prepare(creature_ptr, ts_ptr->mode);
268         ts_ptr->flag = FALSE;
269         ts_ptr->x += dx;
270         ts_ptr->y += dy;
271         if (((ts_ptr->x < panel_col_min + ts_ptr->wid / 2) && (dx > 0)) || ((ts_ptr->x > panel_col_min + ts_ptr->wid / 2) && (dx < 0)))
272             dx = 0;
273
274         if (((ts_ptr->y < panel_row_min + ts_ptr->hgt / 2) && (dy > 0)) || ((ts_ptr->y > panel_row_min + ts_ptr->hgt / 2) && (dy < 0)))
275             dy = 0;
276
277         if ((ts_ptr->y >= panel_row_min + ts_ptr->hgt) || (ts_ptr->y < panel_row_min) || (ts_ptr->x >= panel_col_min + ts_ptr->wid)
278             || (ts_ptr->x < panel_col_min)) {
279             if (change_panel(creature_ptr, dy, dx))
280                 target_set_prepare(creature_ptr, ts_ptr->mode);
281         }
282
283         if (ts_ptr->x >= floor_ptr->width - 1)
284             ts_ptr->x = floor_ptr->width - 2;
285         else if (ts_ptr->x <= 0)
286             ts_ptr->x = 1;
287
288         if (ts_ptr->y >= floor_ptr->height - 1)
289             ts_ptr->y = floor_ptr->height - 2;
290         else if (ts_ptr->y <= 0)
291             ts_ptr->y = 1;
292     }
293 }
294
295 static bool set_target_grid(player_type *creature_ptr, ts_type *ts_ptr)
296 {
297     if (!ts_ptr->flag || (tmp_pos.n == 0))
298         return FALSE;
299
300     describe_projectablity(creature_ptr, ts_ptr);
301     while (TRUE) {
302         ts_ptr->query = examine_grid(creature_ptr, ts_ptr->y, ts_ptr->x, ts_ptr->mode, ts_ptr->info);
303         if (ts_ptr->query)
304             break;
305     }
306
307     menu_target(ts_ptr);
308     switch_target_input(creature_ptr, ts_ptr);
309     if (ts_ptr->distance == 0)
310         return TRUE;
311
312     ts_ptr->y2 = panel_row_min;
313     ts_ptr->x2 = panel_col_min;
314     ts_ptr->target_num = target_pick(tmp_pos.y[ts_ptr->m], tmp_pos.x[ts_ptr->m], ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
315     sweep_targets(creature_ptr, ts_ptr);
316     ts_ptr->m = ts_ptr->target_num;
317     return TRUE;
318 }
319
320 /*
321  * Handle "target" and "look".
322  */
323 bool target_set(player_type *creature_ptr, target_type mode)
324 {
325     ts_type tmp_ts;
326     ts_type *ts_ptr = initialize_target_set_type(creature_ptr, &tmp_ts, mode);
327     target_who = 0;
328     target_set_prepare(creature_ptr, mode);
329     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
330     while (!ts_ptr->done) {
331         if (set_target_grid(creature_ptr, ts_ptr))
332             continue;
333
334         bool move_fast = FALSE;
335         if (!(mode & TARGET_LOOK))
336             print_path(creature_ptr, ts_ptr->y, ts_ptr->x);
337
338         ts_ptr->g_ptr = &floor_ptr->grid_array[ts_ptr->y][ts_ptr->x];
339         strcpy(ts_ptr->info, _("q止 t決 p自 m近 +次 -前", "q,t,p,m,+,-,<dir>"));
340         if (cheat_sight) {
341             char cheatinfo[100];
342             sprintf(cheatinfo, " LOS:%d, PROJECTABLE:%d, SPECIAL:%d", los(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x),
343                 projectable(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x), ts_ptr->g_ptr->special);
344             strcat(ts_ptr->info, cheatinfo);
345         }
346
347         /* Describe and Prompt (enable "TARGET_LOOK") */
348         while ((ts_ptr->query = examine_grid(creature_ptr, ts_ptr->y, ts_ptr->x, mode | TARGET_LOOK, ts_ptr->info)) == 0)
349             ;
350
351         int d = 0;
352         if (use_menu && (ts_ptr->query == '\r'))
353             ts_ptr->query = 't';
354
355         switch (ts_ptr->query) {
356         case ESCAPE:
357         case 'q':
358             ts_ptr->done = TRUE;
359             break;
360         case 't':
361         case '.':
362         case '5':
363         case '0':
364             target_who = -1;
365             target_row = ts_ptr->y;
366             target_col = ts_ptr->x;
367             ts_ptr->done = TRUE;
368             break;
369         case 'p':
370             verify_panel(creature_ptr);
371             creature_ptr->update |= (PU_MONSTERS);
372             creature_ptr->redraw |= (PR_MAP);
373             creature_ptr->window |= (PW_OVERHEAD);
374             handle_stuff(creature_ptr);
375             target_set_prepare(creature_ptr, mode);
376             ts_ptr->y = creature_ptr->y;
377             ts_ptr->x = creature_ptr->x;
378         case 'o':
379             break;
380         case ' ':
381         case '*':
382         case '+':
383         case '-':
384         case 'm': {
385             ts_ptr->flag = TRUE;
386             ts_ptr->m = 0;
387             int bd = 999;
388             for (int i = 0; i < tmp_pos.n; i++) {
389                 int t = distance(ts_ptr->y, ts_ptr->x, tmp_pos.y[i], tmp_pos.x[i]);
390                 if (t < bd) {
391                     ts_ptr->m = i;
392                     bd = t;
393                 }
394             }
395
396             if (bd == 999)
397                 ts_ptr->flag = FALSE;
398
399             break;
400         }
401         default: {
402             d = get_keymap_dir(ts_ptr->query);
403             if (isupper(ts_ptr->query))
404                 move_fast = TRUE;
405
406             if (!d)
407                 bell();
408             break;
409         }
410         }
411
412         if (d) {
413             POSITION dx = ddx[d];
414             POSITION dy = ddy[d];
415             if (move_fast) {
416                 int mag = MIN(ts_ptr->wid / 2, ts_ptr->hgt / 2);
417                 ts_ptr->x += dx * mag;
418                 ts_ptr->y += dy * mag;
419             } else {
420                 ts_ptr->x += dx;
421                 ts_ptr->y += dy;
422             }
423
424             if (((ts_ptr->x < panel_col_min + ts_ptr->wid / 2) && (dx > 0)) || ((ts_ptr->x > panel_col_min + ts_ptr->wid / 2) && (dx < 0)))
425                 dx = 0;
426
427             if (((ts_ptr->y < panel_row_min + ts_ptr->hgt / 2) && (dy > 0)) || ((ts_ptr->y > panel_row_min + ts_ptr->hgt / 2) && (dy < 0)))
428                 dy = 0;
429
430             if ((ts_ptr->y >= panel_row_min + ts_ptr->hgt) || (ts_ptr->y < panel_row_min) || (ts_ptr->x >= panel_col_min + ts_ptr->wid)
431                 || (ts_ptr->x < panel_col_min)) {
432                 if (change_panel(creature_ptr, dy, dx))
433                     target_set_prepare(creature_ptr, mode);
434             }
435
436             if (ts_ptr->x >= floor_ptr->width - 1)
437                 ts_ptr->x = floor_ptr->width - 2;
438             else if (ts_ptr->x <= 0)
439                 ts_ptr->x = 1;
440
441             if (ts_ptr->y >= floor_ptr->height - 1)
442                 ts_ptr->y = floor_ptr->height - 2;
443             else if (ts_ptr->y <= 0)
444                 ts_ptr->y = 1;
445         }
446     }
447
448     tmp_pos.n = 0;
449     prt("", 0, 0);
450     verify_panel(creature_ptr);
451     creature_ptr->update |= (PU_MONSTERS);
452     creature_ptr->redraw |= (PR_MAP);
453     creature_ptr->window |= (PW_OVERHEAD);
454     handle_stuff(creature_ptr);
455     return target_who != 0;
456 }