ScummVM API documentation
direction_util.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef ULTIMA8_MISC_DIRECTIONUTIL_H
23#define ULTIMA8_MISC_DIRECTIONUTIL_H
24
25#include "ultima/ultima8/misc/direction.h"
26#include "ultima/ultima8/ultima8.h"
27#include "math/utils.h"
28
29namespace Ultima {
30namespace Ultima8 {
31
32/*
33 * Tables to map a Direction to x/y deltas
34 */
35
36
37inline int Direction_XFactor(Direction dir) {
38 static const int _x_fact[] = { 0, +1, +1, +1, 0, -1, -1, -1 };
39 static const int _x_fact16[] = { 0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, -1, -2, -1, -1, 0 };
40
41 assert((int)dir >= 0 && (int)dir < 16);
42
43 if (GAME_IS_U8)
44 return _x_fact[(int)dir / 2];
45 else
46 return _x_fact16[(int)dir];
47}
48
49inline int Direction_YFactor(Direction dir) {
50 static const int _y_fact[] = { -1, -1, 0, +1, +1, +1, 0, -1 };
51 static const int _y_fact16[] = { -1, -2, -1, -1, 0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, 0 };
52
53 assert((int)dir >= 0 && (int)dir < 16);
54
55 if (GAME_IS_U8)
56 return _y_fact[(int)dir / 2];
57 else
58 return _y_fact16[(int)dir];
59}
60
62inline int32 Direction_ToCentidegrees(Direction dir) {
63 return static_cast<int>(dir) * 2250;
64}
65
67inline Direction Direction_FromCentidegrees(int32 cds) {
68 return static_cast<Direction>(((cds + 1125) / 2250) % 16);
69}
70
71
80inline Direction Direction_Get(int deltay, int deltax, DirectionMode dirmode) {
81 if (deltax == 0)
82 return deltay > 0 ? dir_northwest : dir_southeast;
83
84 if (dirmode == dirmode_8dirs) {
85 int dydx = (1024 * deltay) / deltax; // Figure 1024*tan.
86 if (dydx >= 0)
87 if (deltax > 0) // Top-right
88 return dydx <= 424 ? dir_northeast : dydx <= 2472 ? dir_north
89 : dir_northwest;
90 else // Bottom-left.
91 return dydx <= 424 ? dir_southwest : dydx <= 2472 ? dir_south
92 : dir_southeast;
93 else if (deltax > 0) // Bottom-right.
94 return dydx >= -424 ? dir_northeast : dydx >= -2472 ? dir_east
95 : dir_southeast;
96 else // Top-left
97 return dydx >= -424 ? dir_southwest : dydx >= -2472 ? dir_west
98 : dir_northwest;
99 } else {
100 double angle = Math::rad2deg(atan2(deltay, deltax));
101 if (angle < -168.75) return dir_southwest;
102 else if (angle < -146.25) return dir_ssw;
103 else if (angle < -123.75) return dir_south;
104 else if (angle < -101.25) return dir_sse;
105 else if (angle < -78.75) return dir_southeast;
106 else if (angle < -56.25) return dir_ese;
107 else if (angle < -33.75) return dir_east;
108 else if (angle < -11.25) return dir_ene;
109 else if (angle < 11.25) return dir_northeast;
110 else if (angle < 33.75) return dir_nne;
111 else if (angle < 56.25) return dir_north;
112 else if (angle < 78.75) return dir_nnw;
113 else if (angle < 101.25) return dir_northwest;
114 else if (angle < 123.75) return dir_wnw;
115 else if (angle < 146.25) return dir_west;
116 else if (angle < 168.75) return dir_wsw;
117 return dir_southwest;
118 }
119}
120
121// Note that for WorldDir, Y goes down, so a positive Y points south.
122inline Direction Direction_GetWorldDir(int deltay, int deltax, DirectionMode dirmode) {
123 if (deltax == 0) {
124 if (deltay == 0) return dir_northeast; // for better compatibility with U8
125 return deltay > 0 ? dir_south : dir_north;
126 }
127
128 if (dirmode == dirmode_8dirs) {
129 int dydx = (1024 * deltay) / deltax;
130
131 if (dydx >= 0)
132 if (deltax > 0) // south-east
133 return dydx <= 424 ? dir_east : dydx <= 2472 ? dir_southeast : dir_south;
134 else // north-west
135 return dydx <= 424 ? dir_west : dydx <= 2472 ? dir_northwest : dir_north;
136 else if (deltax > 0) // north-east
137 return dydx >= -424 ? dir_east : dydx >= -2472 ? dir_northeast : dir_north;
138 else // south-west
139 return dydx >= -424 ? dir_west : dydx >= -2472 ? dir_southwest : dir_south;
140 } else {
141 double angle = Math::rad2deg(atan2(deltay, deltax));
142 if (angle < -168.75) return dir_west;
143 else if (angle < -146.25) return dir_wnw;
144 else if (angle < -123.75) return dir_northwest;
145 else if (angle < -101.25) return dir_nnw;
146 else if (angle < -78.75) return dir_north;
147 else if (angle < -56.25) return dir_nne;
148 else if (angle < -33.75) return dir_northeast;
149 else if (angle < -11.25) return dir_ene;
150 else if (angle < 11.25) return dir_east;
151 else if (angle < 33.75) return dir_ese;
152 else if (angle < 56.25) return dir_southeast;
153 else if (angle < 78.75) return dir_sse;
154 else if (angle < 101.25) return dir_south;
155 else if (angle < 123.75) return dir_ssw;
156 else if (angle < 146.25) return dir_southwest;
157 else if (angle < 168.75) return dir_wsw;
158 return dir_west;
159 }
160}
161
162
163
164inline Direction Direction_GetWorldDirInRange(int deltay, int deltax, DirectionMode dirmode, Direction mindir, Direction maxdir) {
165 int ndirs = (dirmode == dirmode_8dirs ? 8 : 16);
166 Direction dir = Direction_GetWorldDir(deltay, deltax, dirmode);
167
168 if ((dir < mindir) || (dir > maxdir)) {
169 int32 dmin1 = dir - mindir;
170 int32 dmin2 = mindir - dir;
171 if (dmin1 < 0) {
172 dmin1 = dmin1 + ndirs;
173 }
174 if (dmin2 < 0) {
175 dmin2 = dmin2 + ndirs;
176 }
177 int32 dist_to_min = MIN(dmin1, dmin2);
178
179 int dmax1 = dir - maxdir;
180 int dmax2 = maxdir - dir;
181 if (dmax1 < 0) {
182 dmax1 = dmax1 + ndirs;
183 }
184 if (dmax2 < 0) {
185 dmax2 = dmax2 + ndirs;
186 }
187 int32 dist_to_max = MIN(dmax1, dmax2);
188
189 if (dist_to_min < dist_to_max) {
190 return mindir;
191 } else {
192 return maxdir;
193 }
194 }
195
196 return dir;
197}
198
199inline Direction Direction_Invert(Direction dir) {
200 assert(dir != dir_current);
201 switch (dir) {
202 case dir_north: return dir_south;
203 case dir_nne: return dir_ssw;
204 case dir_northeast: return dir_southwest;
205 case dir_ene: return dir_wsw;
206 case dir_east: return dir_west;
207 case dir_ese: return dir_wnw;
208 case dir_southeast: return dir_northwest;
209 case dir_sse: return dir_nnw;
210 case dir_south: return dir_north;
211 case dir_ssw: return dir_nne;
212 case dir_southwest: return dir_northeast;
213 case dir_wsw: return dir_ene;
214 case dir_west: return dir_east;
215 case dir_wnw: return dir_ese;
216 case dir_northwest: return dir_southeast;
217 case dir_nnw: return dir_sse;
218 default: return dir_north;
219 }
220}
221
223inline Direction Direction_OneLeft(Direction dir, DirectionMode mode) {
224 if (mode == dirmode_8dirs)
225 return static_cast<Direction>((static_cast<int>(dir) + 14) % 16);
226 else
227 return static_cast<Direction>((static_cast<int>(dir) + 15) % 16);
228}
229
231inline Direction Direction_OneRight(Direction dir, DirectionMode mode) {
232 if (mode == dirmode_8dirs)
233 return static_cast<Direction>((static_cast<int>(dir) + 2) % 16);
234 else
235 return static_cast<Direction>((static_cast<int>(dir) + 1) % 16);
236}
237
238inline Direction Direction_TurnByDelta(Direction dir, int delta, DirectionMode mode) {
239 if (delta > 0) {
240 for (int i = 0; i < delta; i++)
241 dir = Direction_OneRight(dir, mode);
242 } else if (delta < 0) {
243 for (int i = 0; i < -delta; i++)
244 dir = Direction_OneLeft(dir, mode);
245 }
246 return dir;
247}
248
251inline int Direction_GetShorterTurnDelta(Direction from, Direction to) {
252 if ((from - to + 16) % 16 < 8)
253 return -1;
254 return 1;
255}
256
257inline uint32 Direction_ToUsecodeDir(Direction dir) {
258 if (GAME_IS_U8) {
259 return static_cast<int32>(dir / 2);
260 } else {
261 return static_cast<int32>(dir);
262 }
263}
264
265inline Direction Direction_FromUsecodeDir(uint32 dir) {
266 if (GAME_IS_U8) {
267 return static_cast<Direction>(dir * 2);
268 } else {
269 return static_cast<Direction>(dir);
270 }
271}
272
273} // End of namespace Ultima8
274} // End of namespace Ultima
275
276#endif
T MIN(T a, T b)
Definition: util.h:63