ScummVM API documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
29 namespace Ultima {
30 namespace Ultima8 {
31 
32 /*
33  * Tables to map a Direction to x/y deltas
34  */
35 
36 
37 inline 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 
49 inline 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 
62 inline int32 Direction_ToCentidegrees(Direction dir) {
63  return static_cast<int>(dir) * 2250;
64 }
65 
67 inline Direction Direction_FromCentidegrees(int32 cds) {
68  return static_cast<Direction>(((cds + 1125) / 2250) % 16);
69 }
70 
71 
80 inline 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.
122 inline 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 
164 inline 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 
199 inline 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 
223 inline 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 
231 inline 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 
238 inline 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 
251 inline int Direction_GetShorterTurnDelta(Direction from, Direction to) {
252  if ((from - to + 16) % 16 < 8)
253  return -1;
254  return 1;
255 }
256 
257 inline 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 
265 inline 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
Definition: detection.h:27
T MIN(T a, T b)
Definition: util.h:61