UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
test_routing.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "test_shared.h"
26 
27 #include "../common/common.h"
28 #include "../common/cmodel.h"
29 #include "../common/grid.h"
30 #include "../game/g_local.h"
31 #include "../game/g_edicts.h"
32 #include "../game/g_utils.h"
33 #include "../server/server.h"
34 
35 class RoutingTest: public ::testing::Test {
36 protected:
37  static void SetUpTestCase() {
38  TEST_Init();
39  Com_ParseScripts(true);
40  }
41 
42  static void TearDownTestCase() {
43  TEST_Shutdown();
44  }
45 };
46 
49 static const char* mapName = "test_routing";
50 
51 TEST_F(RoutingTest, MapLoading)
52 {
53  ASSERT_NE(-1, FS_CheckFile("maps/%s.bsp", mapName)) << "Map resource '" << mapName << ".bsp' for test is missing.";
54  char entityString[MAX_TOKEN_CHARS];
55  CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
56  CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
57 }
58 
60 {
61  vec3_t vec;
62  pos3_t pos;
63  pos_t gridPos;
64 
65  ASSERT_NE(-1, FS_CheckFile("maps/%s.bsp", mapName)) << "Map resource '" << mapName << ".bsp' for test is missing.";
66  char entityString[MAX_TOKEN_CHARS];
67  CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
68  CM_LoadMap(mapName, true, "", entityString, &mapData, &mapTiles);
69 
70  VectorSet(vec, 16, 16, 48);
71  VecToPos(vec, pos);
72  ASSERT_EQ(pos[0], 128);
73  ASSERT_EQ(pos[1], 128);
74  ASSERT_EQ(pos[2], 0);
75 
76  VectorSet(vec, 80, 16, 80);
77  VecToPos(vec, pos);
78  ASSERT_EQ(pos[0], 130);
79  ASSERT_EQ(pos[1], 128);
80  ASSERT_EQ(pos[2], 1);
81 
82  gridPos = Grid_Fall(mapData.routing, ACTOR_SIZE_NORMAL, pos);
83  ASSERT_EQ(gridPos, 1);
84 
85  {
86  const byte crouchingState = 0;
87  const int maxTUs = MAX_ROUTE_TUS;
88  int lengthStored;
89  pos3_t to;
91 
92  VectorSet(vec, 80, 80, 32);
93  VecToPos(vec, pos);
94 
95  Grid_CalcPathing(mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, nullptr);
96  Grid_MoveStore(path);
97 
98  /* move downwards */
99  {
100  int lengthUnstored;
101  VectorSet(vec, 80, 48, 32);
102  VecToPos(vec, to);
103 
104  lengthUnstored = Grid_MoveLength(path, to, crouchingState, false);
105  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
106  ASSERT_EQ(lengthUnstored, lengthStored);
107  ASSERT_EQ(lengthStored, TU_MOVE_STRAIGHT);
108  }
109  /* try to move three steps upwards - there is a brush*/
110  {
111  VectorSet(vec, 80, 176, 32);
112  VecToPos(vec, to);
113 
114  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
115  ASSERT_EQ(lengthStored, ROUTING_NOT_REACHABLE);
116  }
117  /* try move into the nodraw */
118  {
119  VectorSet(vec, 48, 16, 32);
120  VecToPos(vec, to);
121 
122  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
123  ASSERT_EQ(lengthStored, ROUTING_NOT_REACHABLE);
124  }
125  /* move into the lightclip */
126  {
127  VectorSet(vec, 48, 48, 32);
128  VecToPos(vec, to);
129 
130  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
131  ASSERT_EQ(lengthStored, TU_MOVE_DIAGONAL);
132  }
133  /* move into the passable */
134  {
135  VectorSet(vec, 144, 48, 32);
136  VecToPos(vec, to);
137 
138  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
139  ASSERT_EQ(lengthStored, TU_MOVE_DIAGONAL + TU_MOVE_STRAIGHT);
140  }
141  /* go to the other side - diagonal, followed by six straight moves */
142  {
143  VectorSet(vec, -16, 48, 32);
144  VecToPos(vec, to);
145 
146  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
147  ASSERT_EQ(lengthStored, 6 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
148  }
149  /* try to walk out of the map */
150  {
151  VectorSet(vec, 48, 272, 32);
152  VecToPos(vec, to);
153 
154  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
155  ASSERT_EQ(lengthStored, ROUTING_NOT_REACHABLE);
156  }
157  /* walk to the map border */
158  {
159  VectorSet(vec, 48, 240, 32);
160  VecToPos(vec, to);
161 
162  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
163  ASSERT_EQ(lengthStored, 4 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
164  }
165  /* walk a level upwards */
166  {
167  VectorSet(vec, 240, 80, 96);
168  VecToPos(vec, to);
169 
170  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
171  ASSERT_EQ(lengthStored, 5 * TU_MOVE_STRAIGHT);
172  }
173  /* move to the door (not a func_door) */
174  {
175  VectorSet(vec, 176, -80, 32);
176  VecToPos(vec, to);
177 
178  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
179  ASSERT_EQ(lengthStored, 4 * TU_MOVE_STRAIGHT + 2 * TU_MOVE_DIAGONAL);
180  }
181  /* move into the trigger_touch */
182  {
183  VectorSet(vec, -48, -80, 32);
184  VecToPos(vec, to);
185 
186  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
187  ASSERT_EQ(lengthStored, 5 * TU_MOVE_STRAIGHT + 3 * TU_MOVE_DIAGONAL);
188  }
189  /* try to walk into the actorclip */
190  {
191  VectorSet(vec, -48, -48, 32);
192  VecToPos(vec, to);
193 
194  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
195  ASSERT_EQ(lengthStored, ROUTING_NOT_REACHABLE);
196  }
197  }
198 }
199 
200 TEST_F(RoutingTest, MoveEntities)
201 {
202  pos3_t pos;
203  vec3_t vec;
206  const byte crouchingState = 0;
207  const int maxTUs = MAX_ROUTE_TUS;
208  forbiddenList.reset();
209 
210  SV_Map(true, mapName, nullptr);
211 
212  /* starting point */
213  VectorSet(vec, 240, -144, 32);
214  VecToPos(vec, pos);
215 
217 
218  {
219  Edict* ent = nullptr;
220  while ((ent = G_EdictsGetNextInUse(ent))) {
221  /* Dead 2x2 unit will stop walking, too. */
222  if (ent->type == ET_SOLID) {
223  for (int j = 0; j < ent->forbiddenListSize; j++) {
224  forbiddenList.add(ent->forbiddenListPos[j], (byte*) &ent->fieldSize);
225  }
226  }
227  }
228  }
229 
230  {
231  int lengthStored;
232  pos3_t to;
233 
234  Grid_CalcPathing(sv->mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, &forbiddenList);
235  Grid_MoveStore(path);
236 
237  /* walk onto the func_breakable */
238  {
239  VectorSet(vec, 112, -144, 32);
240  VecToPos(vec, to);
241 
242  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
243  ASSERT_EQ(lengthStored, 4 * TU_MOVE_STRAIGHT);
244  }
245  /* walk over the func_breakable */
246  {
247  VectorSet(vec, 80, -144, 32);
248  VecToPos(vec, to);
249 
250  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
251  ASSERT_EQ(lengthStored, 5 * TU_MOVE_STRAIGHT);
252  }
253  /* walk over the func_breakable */
254  {
255  VectorSet(vec, 16, -144, 32);
256  VecToPos(vec, to);
257 
258  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
259  ASSERT_EQ(lengthStored, 7 * TU_MOVE_STRAIGHT);
260  }
261  }
262 
263  /* starting point */
264  VectorSet(vec, 144, 144, 32);
265  VecToPos(vec, pos);
266 
267  {
268  int lengthStored;
269  pos3_t to;
270 
271  Grid_CalcPathing(sv->mapData.routing, ACTOR_SIZE_NORMAL, path, pos, maxTUs, &forbiddenList);
272  Grid_MoveStore(path);
273 
274  /* walk through the opened door */
275  {
276  VectorSet(vec, 112, 144, 32);
277  VecToPos(vec, to);
278 
279  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
280  ASSERT_EQ(lengthStored, TU_MOVE_STRAIGHT);
281  }
282 
283  /* walk around the opened door */
284  {
285  VectorSet(vec, 144, 208, 32);
286  VecToPos(vec, to);
287 
288  lengthStored = Grid_MoveLength(path, to, crouchingState, true);
289  ASSERT_EQ(lengthStored, 2 * TU_MOVE_STRAIGHT + TU_MOVE_DIAGONAL);
290  }
291  }
292 
294 }
295 
296 /* tests for the new dvec format */
298 {
299  short dv1 = 0x0724;
300  ASSERT_EQ(getDVdir(dv1), 0x07);
301  ASSERT_EQ(getDVflags(dv1), 0x02);
302  ASSERT_EQ(getDVz(dv1), 0x04);
303 
304  short dv2 = makeDV(6, 3);
305  ASSERT_EQ(dv2, 0x0603);
306 
307  dv2 = setDVz(dv2, 4);
308  ASSERT_EQ(dv2, 0x0604);
309 }
310 
311 TEST_F(RoutingTest, TUsForDir)
312 {
313  ASSERT_EQ(Grid_GetTUsForDirection(0, 0), 2);
314  ASSERT_EQ(Grid_GetTUsForDirection(2, 0), 2);
315  ASSERT_EQ(Grid_GetTUsForDirection(5, 0), 3);
316  ASSERT_EQ(Grid_GetTUsForDirection(5, false), 3);
317  ASSERT_EQ(Grid_GetTUsForDirection(0, 1), 3); /* now crouching */
318  ASSERT_EQ(Grid_GetTUsForDirection(5, 1), 4);
319  ASSERT_EQ(Grid_GetTUsForDirection(5, true), 4);
320  ASSERT_EQ(Grid_GetTUsForDirection(16, 0), 4); /* flying takes twice as much */
321  ASSERT_EQ(Grid_GetTUsForDirection(16, 1), 4); /* flying & crouching is still the same */
322 }
Edict * G_EdictsGetNextInUse(Edict *lastEnt)
Iterate through the entities that are in use.
Definition: g_edicts.cpp:166
int Grid_GetTUsForDirection(const int dir, bool crouched)
Returns the amounts of TUs that are needed to perform one step into the given direction.
Definition: grid.cpp:766
#define getDVflags(dv)
Definition: mathlib.h:250
#define VectorSet(v, x, y, z)
Definition: vector.h:59
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition: files.cpp:298
TEST_F(RoutingTest, MapLoading)
#define makeDV(dir, z)
Definition: mathlib.h:247
pos_t Grid_Fall(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos)
Calculated the new height level when something falls down from a certain position.
Definition: grid.cpp:783
void Grid_CalcPathing(const Routing &routing, const actorSizeEnum_t actorSize, pathing_t *path, const pos3_t from, int maxTUs, forbiddenList_t *fb_list)
Recalculate the pathing table for the given actor(-position)
Definition: grid.cpp:497
void SV_Map(bool day, const char *levelstring, const char *assembly, bool verbose=true)
Change the server to a new map, taking all connected clients along with it.
Definition: sv_init.cpp:113
void Com_ParseScripts(bool onlyServer)
Definition: scripts.cpp:3641
int forbiddenListSize
Definition: g_edict.h:175
static void SetUpTestCase()
#define TU_MOVE_STRAIGHT
Definition: defines.h:74
void G_CompleteRecalcRouting(void)
Definition: g_utils.cpp:464
pos_t Grid_MoveLength(const pathing_t *path, const pos3_t to, byte crouchingState, bool stored)
Return the needed TUs to walk to a given position.
Definition: grid.cpp:698
serverInstanceGame_t * sv
Definition: sv_init.cpp:36
void reset()
Definition: grid.h:51
#define setDVz(dv, z)
Definition: mathlib.h:248
void TEST_Shutdown(void)
Definition: test_shared.cpp:34
#define VecToPos(v, p)
Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the possible max negative ...
Definition: mathlib.h:100
static forbiddenList_t forbiddenList
A list of locations that cannot be moved to.
Definition: cl_actor.cpp:602
mapData_t mapData
Definition: server.h:124
#define MAX_TOKEN_CHARS
Definition: defines.h:372
Definition: grid.h:83
#define MAX_ROUTE_TUS
Definition: defines.h:83
pos_t pos3_t[3]
Definition: ufotypes.h:58
#define getDVz(dv)
Definition: mathlib.h:251
actorSizeEnum_t fieldSize
Definition: g_edict.h:141
void Grid_MoveStore(pathing_t *path)
Caches the calculated move.
Definition: grid.cpp:683
void TEST_Init(void)
Definition: test_shared.cpp:72
#define TU_MOVE_DIAGONAL
Definition: defines.h:75
entity_type_t type
Definition: g_edict.h:81
vec_t vec3_t[3]
Definition: ufotypes.h:39
void add(pos3_t pos, byte *entSize)
Definition: grid.h:44
#define Mem_AllocType(type)
Definition: mem.h:39
#define getDVdir(dv)
Definition: mathlib.h:249
static void TearDownTestCase()
A list of locations that cannot be moved to.
Definition: grid.h:35
Definition: g_edict.h:45
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
#define ROUTING_NOT_REACHABLE
Definition: defines.h:283
Routing routing
Definition: typedefs.h:341
void SV_ShutdownGameProgs(void)
Called when either the entire server is being killed, or it is changing to a different game directory...
Definition: sv_game.cpp:703
uint8_t byte
Definition: ufotypes.h:34
static mapData_t mapData
void CM_LoadMap(const char *tiles, bool day, const char *pos, const char *entityString, mapData_t *mapData, mapTiles_t *mapTiles)
Loads in the map and all submodels.
Definition: bsp.cpp:860
pos3_t * forbiddenListPos
Definition: g_edict.h:173
byte pos_t
Definition: ufotypes.h:57
static mapTiles_t mapTiles
static const char * mapName