OSDN Git Service

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