OSDN Git Service

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