OSDN Git Service

Merge remote-tracking branch 'remotes/hengband-osx/For2.2.2-Refactoring-English-Edit...
[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         const char queried_command = rogue_like_commands ? 'x' : 'l';
218         if (ts_ptr->query != queried_command) {
219             ts_ptr->distance = get_keymap_dir(ts_ptr->query);
220             if (ts_ptr->distance == 0)
221                 bell();
222
223             return;
224         }
225
226         if (++ts_ptr->m != tmp_pos.n)
227             return;
228
229         ts_ptr->m = 0;
230         if (!expand_list)
231             ts_ptr->done = TRUE;
232
233         return;
234     }
235     }
236 }
237
238 static bool check_panel_changed(player_type *creature_ptr, ts_type *ts_ptr)
239 {
240     if (!change_panel(creature_ptr, ddy[ts_ptr->distance], ddx[ts_ptr->distance]))
241         return FALSE;
242
243     int v = tmp_pos.y[ts_ptr->m];
244     int u = tmp_pos.x[ts_ptr->m];
245     target_set_prepare(creature_ptr, ts_ptr->mode);
246     ts_ptr->flag = TRUE;
247     ts_ptr->target_num = target_pick(v, u, ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
248     if (ts_ptr->target_num >= 0)
249         ts_ptr->m = ts_ptr->target_num;
250
251     return TRUE;
252 }
253
254 static void sweep_targets(player_type *creature_ptr, ts_type *ts_ptr)
255 {
256     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
257     while (ts_ptr->flag && (ts_ptr->target_num < 0)) {
258         if (check_panel_changed(creature_ptr, ts_ptr))
259             continue;
260
261         POSITION dx = ddx[ts_ptr->distance];
262         POSITION dy = ddy[ts_ptr->distance];
263         panel_row_min = ts_ptr->y2;
264         panel_col_min = ts_ptr->x2;
265         panel_bounds_center();
266         creature_ptr->update |= PU_MONSTERS;
267         creature_ptr->redraw |= PR_MAP;
268         creature_ptr->window |= PW_OVERHEAD;
269         handle_stuff(creature_ptr);
270         target_set_prepare(creature_ptr, ts_ptr->mode);
271         ts_ptr->flag = FALSE;
272         ts_ptr->x += dx;
273         ts_ptr->y += dy;
274         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)))
275             dx = 0;
276
277         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)))
278             dy = 0;
279
280         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)
281             || (ts_ptr->x < panel_col_min)) {
282             if (change_panel(creature_ptr, dy, dx))
283                 target_set_prepare(creature_ptr, ts_ptr->mode);
284         }
285
286         if (ts_ptr->x >= floor_ptr->width - 1)
287             ts_ptr->x = floor_ptr->width - 2;
288         else if (ts_ptr->x <= 0)
289             ts_ptr->x = 1;
290
291         if (ts_ptr->y >= floor_ptr->height - 1)
292             ts_ptr->y = floor_ptr->height - 2;
293         else if (ts_ptr->y <= 0)
294             ts_ptr->y = 1;
295     }
296 }
297
298 static bool set_target_grid(player_type *creature_ptr, ts_type *ts_ptr)
299 {
300     if (!ts_ptr->flag || (tmp_pos.n == 0))
301         return FALSE;
302
303     describe_projectablity(creature_ptr, ts_ptr);
304     while (TRUE) {
305         ts_ptr->query = examine_grid(creature_ptr, ts_ptr->y, ts_ptr->x, ts_ptr->mode, ts_ptr->info);
306         if (ts_ptr->query)
307             break;
308     }
309
310     menu_target(ts_ptr);
311     switch_target_input(creature_ptr, ts_ptr);
312     if (ts_ptr->distance == 0)
313         return TRUE;
314
315     ts_ptr->y2 = panel_row_min;
316     ts_ptr->x2 = panel_col_min;
317     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]);
318     sweep_targets(creature_ptr, ts_ptr);
319     ts_ptr->m = ts_ptr->target_num;
320     return TRUE;
321 }
322
323 static void describe_grid_wizard(player_type *creature_ptr, ts_type *ts_ptr)
324 {
325     if (!cheat_sight)
326         return;
327
328     char cheatinfo[100];
329     sprintf(cheatinfo, " LOS:%d, PROJECTABLE:%d, SPECIAL:%d", los(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x),
330         projectable(creature_ptr, creature_ptr->y, creature_ptr->x, ts_ptr->y, ts_ptr->x), ts_ptr->g_ptr->special);
331     strcat(ts_ptr->info, cheatinfo);
332 }
333
334 static void switch_next_grid_command(player_type *creature_ptr, ts_type *ts_ptr)
335 {
336     switch (ts_ptr->query) {
337     case ESCAPE:
338     case 'q':
339         ts_ptr->done = TRUE;
340         break;
341     case 't':
342     case '.':
343     case '5':
344     case '0':
345         target_who = -1;
346         target_row = ts_ptr->y;
347         target_col = ts_ptr->x;
348         ts_ptr->done = TRUE;
349         break;
350     case 'p':
351         verify_panel(creature_ptr);
352         creature_ptr->update |= PU_MONSTERS;
353         creature_ptr->redraw |= PR_MAP;
354         creature_ptr->window |= PW_OVERHEAD;
355         handle_stuff(creature_ptr);
356         target_set_prepare(creature_ptr, ts_ptr->mode);
357         ts_ptr->y = creature_ptr->y;
358         ts_ptr->x = creature_ptr->x;
359     case 'o':
360         // todo ↑元からbreakしていないがFall Throughを付けてよいか不明なので保留
361         break;
362     case ' ':
363     case '*':
364     case '+':
365     case '-':
366     case 'm': {
367         ts_ptr->flag = TRUE;
368         ts_ptr->m = 0;
369         int bd = 999;
370         for (int i = 0; i < tmp_pos.n; i++) {
371             int t = distance(ts_ptr->y, ts_ptr->x, tmp_pos.y[i], tmp_pos.x[i]);
372             if (t < bd) {
373                 ts_ptr->m = i;
374                 bd = t;
375             }
376         }
377
378         if (bd == 999)
379             ts_ptr->flag = FALSE;
380
381         break;
382     }
383     default:
384         ts_ptr->distance = get_keymap_dir(ts_ptr->query);
385         if (isupper(ts_ptr->query))
386             ts_ptr->move_fast = TRUE;
387
388         if (!ts_ptr->distance)
389             bell();
390
391         break;
392     }
393 }
394
395 static void decide_change_panel(player_type *creature_ptr, ts_type *ts_ptr)
396 {
397     if (ts_ptr->distance == 0)
398         return;
399
400     POSITION dx = ddx[ts_ptr->distance];
401     POSITION dy = ddy[ts_ptr->distance];
402     if (ts_ptr->move_fast) {
403         int mag = MIN(ts_ptr->wid / 2, ts_ptr->hgt / 2);
404         ts_ptr->x += dx * mag;
405         ts_ptr->y += dy * mag;
406     } else {
407         ts_ptr->x += dx;
408         ts_ptr->y += dy;
409     }
410
411     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)))
412         dx = 0;
413
414     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)))
415         dy = 0;
416
417     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)
418         || (ts_ptr->x < panel_col_min)) {
419         if (change_panel(creature_ptr, dy, dx))
420             target_set_prepare(creature_ptr, ts_ptr->mode);
421     }
422
423     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
424     if (ts_ptr->x >= floor_ptr->width - 1)
425         ts_ptr->x = floor_ptr->width - 2;
426     else if (ts_ptr->x <= 0)
427         ts_ptr->x = 1;
428
429     if (ts_ptr->y >= floor_ptr->height - 1)
430         ts_ptr->y = floor_ptr->height - 2;
431     else if (ts_ptr->y <= 0)
432         ts_ptr->y = 1;
433 }
434
435 static void sweep_target_grids(player_type *creature_ptr, ts_type *ts_ptr)
436 {
437     while (!ts_ptr->done) {
438         if (set_target_grid(creature_ptr, ts_ptr))
439             continue;
440
441         ts_ptr->move_fast = FALSE;
442         if ((ts_ptr->mode & TARGET_LOOK) == 0)
443             print_path(creature_ptr, ts_ptr->y, ts_ptr->x);
444
445         ts_ptr->g_ptr = &creature_ptr->current_floor_ptr->grid_array[ts_ptr->y][ts_ptr->x];
446         strcpy(ts_ptr->info, _("q止 t決 p自 m近 +次 -前", "q,t,p,m,+,-,<dir>"));
447         describe_grid_wizard(creature_ptr, ts_ptr);
448
449         /* Describe and Prompt (enable "TARGET_LOOK") */
450         while ((ts_ptr->query = examine_grid(creature_ptr, ts_ptr->y, ts_ptr->x, ts_ptr->mode | TARGET_LOOK, ts_ptr->info)) == 0)
451             ;
452
453         ts_ptr->distance = 0;
454         if (use_menu && (ts_ptr->query == '\r'))
455             ts_ptr->query = 't';
456
457         switch_next_grid_command(creature_ptr, ts_ptr);
458         decide_change_panel(creature_ptr, ts_ptr);
459     }
460 }
461
462 /*
463  * Handle "target" and "look".
464  */
465 bool target_set(player_type *creature_ptr, target_type mode)
466 {
467     ts_type tmp_ts;
468     ts_type *ts_ptr = initialize_target_set_type(creature_ptr, &tmp_ts, mode);
469     target_who = 0;
470     target_set_prepare(creature_ptr, mode);
471     sweep_target_grids(creature_ptr, ts_ptr);
472     tmp_pos.n = 0;
473     prt("", 0, 0);
474     verify_panel(creature_ptr);
475     creature_ptr->update |= (PU_MONSTERS);
476     creature_ptr->redraw |= (PR_MAP);
477     creature_ptr->window |= (PW_OVERHEAD);
478     handle_stuff(creature_ptr);
479     return target_who != 0;
480 }