OSDN Git Service

55e544d5e06b76ae9198d0e7aa4c873142db8aa8
[hengband/hengband.git] / src / target / projection-path-calculator.c
1 #include "target/projection-path-calculator.h"
2 #include "effect/effect-characteristics.h"
3 #include "floor/cave.h"
4 #include "grid/feature-flag-types.h"
5 #include "grid/grid.h"
6 #include "system/floor-type-definition.h"
7
8 typedef struct projection_path_type {
9     u16b *gp;
10     POSITION range;
11     BIT_FLAGS flag;
12     POSITION y1;
13     POSITION x1;
14     POSITION y2;
15     POSITION x2;
16     POSITION y;
17     POSITION x;
18     POSITION ay;
19     POSITION ax;
20     POSITION sy;
21     POSITION sx;
22     int frac;
23     int m;
24     int half;
25     int full;
26     int n;
27     int k;
28 } projection_path_type;
29
30 /*
31  * @brief Convert a "location" (Y, X) into a "grid" (G)
32  * @param y Y\8dÀ\95W
33  * @param x X\8dÀ\95W
34  * return \8co\98H\8dÀ\95W
35  */
36 static u16b location_to_grid(POSITION y, POSITION x) { return 256 * y + x; }
37
38 static projection_path_type *initialize_projection_path_type(
39     projection_path_type *pp_ptr, u16b *gp, POSITION range, BIT_FLAGS flag, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
40 {
41     pp_ptr->gp = gp;
42     pp_ptr->range = range;
43     pp_ptr->flag = flag;
44     pp_ptr->y1 = y1;
45     pp_ptr->x1 = x1;
46     pp_ptr->y2 = y2;
47     pp_ptr->x2 = x2;
48     return pp_ptr;
49 }
50
51 static void set_asxy(projection_path_type *pp_ptr)
52 {
53     if (pp_ptr->y2 < pp_ptr->y1) {
54         pp_ptr->ay = pp_ptr->y1 - pp_ptr->y2;
55         pp_ptr->sy = -1;
56     } else {
57         pp_ptr->ay = pp_ptr->y2 - pp_ptr->y1;
58         pp_ptr->sy = 1;
59     }
60
61     if (pp_ptr->x2 < pp_ptr->x1) {
62         pp_ptr->ax = pp_ptr->x1 - pp_ptr->x2;
63         pp_ptr->sx = -1;
64     } else {
65         pp_ptr->ax = pp_ptr->x2 - pp_ptr->x1;
66         pp_ptr->sx = 1;
67     }
68 }
69
70 static bool calc_vertical_projection(player_type *player_ptr, projection_path_type *pp_ptr)
71 {
72     if (pp_ptr->ay > pp_ptr->ax)
73         return FALSE;
74
75     pp_ptr->m = pp_ptr->ax * pp_ptr->ax * 2;
76     pp_ptr->y = pp_ptr->y1 + pp_ptr->sy;
77     pp_ptr->x = pp_ptr->x1;
78     pp_ptr->frac = pp_ptr->m;
79     if (pp_ptr->frac > pp_ptr->half) {
80         pp_ptr->x += pp_ptr->sx;
81         pp_ptr->frac -= pp_ptr->full;
82         pp_ptr->k++;
83     }
84
85     floor_type *floor_ptr = player_ptr->current_floor_ptr;
86     while (TRUE) {
87         pp_ptr->gp[pp_ptr->n++] = location_to_grid(pp_ptr->y, pp_ptr->x);
88         if ((pp_ptr->n + (pp_ptr->k >> 1)) >= pp_ptr->range)
89             break;
90
91         if (!(pp_ptr->flag & PROJECT_THRU)) {
92             if ((pp_ptr->x == pp_ptr->x2) && (pp_ptr->y == pp_ptr->y2))
93                 break;
94         }
95
96         if (pp_ptr->flag & PROJECT_DISI) {
97             if ((pp_ptr->n > 0) && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x))
98                 break;
99         } else if (pp_ptr->flag & PROJECT_LOS) {
100             if ((pp_ptr->n > 0) && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x))
101                 break;
102         } else if (!(pp_ptr->flag & PROJECT_PATH)) {
103             if ((pp_ptr->n > 0) && !cave_have_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, FF_PROJECT))
104                 break;
105         }
106
107         if (pp_ptr->flag & PROJECT_STOP) {
108             if ((pp_ptr->n > 0) && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0))
109                 break;
110         }
111
112         if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x))
113             break;
114
115         if (pp_ptr->m) {
116             pp_ptr->frac += pp_ptr->m;
117             if (pp_ptr->frac > pp_ptr->half) {
118                 pp_ptr->x += pp_ptr->sx;
119                 pp_ptr->frac -= pp_ptr->full;
120                 pp_ptr->k++;
121             }
122         }
123
124         pp_ptr->y += pp_ptr->sy;
125     }
126
127     return TRUE;
128 }
129
130 /*!
131  * @brief \8en\93_\82©\82ç\8fI\93_\82Ö\82Ì\92¼\90ü\8co\98H\82ð\95Ô\82· /
132  * Determine the path taken by a projection.
133  * @param player_ptr \83v\83\8c\81[\83\84\81[\82Ö\82Ì\8eQ\8fÆ\83|\83C\83\93\83^
134  * @param gp \8co\98H\8dÀ\95W\83\8a\83X\83g\82ð\95Ô\82·\8eQ\8fÆ\83|\83C\83\93\83^
135  * @param range \8b\97\97£
136  * @param y1 \8en\93_Y\8dÀ\95W
137  * @param x1 \8en\93_X\8dÀ\95W
138  * @param y2 \8fI\93_Y\8dÀ\95W
139  * @param x2 \8fI\93_X\8dÀ\95W
140  * @param flag \83t\83\89\83OID
141  * @return \83\8a\83X\83g\82Ì\92·\82³
142  */
143 int projection_path(player_type *player_ptr, u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flag)
144 {
145     if ((x1 == x2) && (y1 == y2))
146         return 0;
147
148     projection_path_type tmp_projection_path;
149     projection_path_type *pp_ptr = initialize_projection_path_type(&tmp_projection_path, gp, range, flag, y1, x1, y2, x2);
150     set_asxy(pp_ptr);
151     pp_ptr->half = pp_ptr->ay * pp_ptr->ax;
152     pp_ptr->full = pp_ptr->half << 1;
153     pp_ptr->n = 0;
154     pp_ptr->k = 0;
155
156     if (calc_vertical_projection(player_ptr, pp_ptr))
157         return pp_ptr->n;
158
159     /* Horizontal */
160     if (pp_ptr->ax > pp_ptr->ay) {
161         pp_ptr->m = pp_ptr->ay * pp_ptr->ay * 2;
162         pp_ptr->y = y1;
163         pp_ptr->x = x1 + pp_ptr->sx;
164         pp_ptr->frac = pp_ptr->m;
165         if (pp_ptr->frac > pp_ptr->half) {
166             pp_ptr->y += pp_ptr->sy;
167             pp_ptr->frac -= pp_ptr->full;
168             pp_ptr->k++;
169         }
170
171         floor_type *floor_ptr = player_ptr->current_floor_ptr;
172         while (TRUE) {
173             gp[pp_ptr->n++] = location_to_grid(pp_ptr->y, pp_ptr->x);
174             if ((pp_ptr->n + (pp_ptr->k >> 1)) >= range)
175                 break;
176
177             if (!(flag & (PROJECT_THRU))) {
178                 if ((pp_ptr->x == x2) && (pp_ptr->y == y2))
179                     break;
180             }
181
182             if (flag & (PROJECT_DISI)) {
183                 if ((pp_ptr->n > 0) && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x))
184                     break;
185             } else if (flag & (PROJECT_LOS)) {
186                 if ((pp_ptr->n > 0) && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x))
187                     break;
188             } else if (!(flag & (PROJECT_PATH))) {
189                 if ((pp_ptr->n > 0) && !cave_have_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, FF_PROJECT))
190                     break;
191             }
192
193             if (flag & (PROJECT_STOP)) {
194                 if ((pp_ptr->n > 0) && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0))
195                     break;
196             }
197
198             if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x))
199                 break;
200
201             if (pp_ptr->m) {
202                 pp_ptr->frac += pp_ptr->m;
203                 if (pp_ptr->frac > pp_ptr->half) {
204                     pp_ptr->y += pp_ptr->sy;
205                     pp_ptr->frac -= pp_ptr->full;
206                     pp_ptr->k++;
207                 }
208             }
209
210             pp_ptr->x += pp_ptr->sx;
211         }
212
213         return pp_ptr->n;
214     }
215
216     pp_ptr->y = y1 + pp_ptr->sy;
217     pp_ptr->x = x1 + pp_ptr->sx;
218
219     floor_type *floor_ptr = player_ptr->current_floor_ptr;
220     while (TRUE) {
221         gp[pp_ptr->n++] = location_to_grid(pp_ptr->y, pp_ptr->x);
222         if ((pp_ptr->n + (pp_ptr->n >> 1)) >= range)
223             break;
224
225         if (!(flag & PROJECT_THRU)) {
226             if ((pp_ptr->x == x2) && (pp_ptr->y == y2))
227                 break;
228         }
229
230         if (flag & PROJECT_DISI) {
231             if ((pp_ptr->n > 0) && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x))
232                 break;
233         } else if (flag & PROJECT_LOS) {
234             if ((pp_ptr->n > 0) && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x))
235                 break;
236         } else if (!(flag & PROJECT_PATH)) {
237             if ((pp_ptr->n > 0) && !cave_have_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, FF_PROJECT))
238                 break;
239         }
240
241         if (flag & PROJECT_STOP) {
242             if ((pp_ptr->n > 0) && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0))
243                 break;
244         }
245
246         if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x))
247             break;
248
249         pp_ptr->y += pp_ptr->sy;
250         pp_ptr->x += pp_ptr->sx;
251     }
252
253     return pp_ptr->n;
254 }