]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/gamec/urrebot_nn_use.c
Reinstated navigation "optimization" for profiling tests.
[divverent/nexuiz.git] / data / qcsrc / server / gamec / urrebot_nn_use.c
1 /* --- ClampPointToSpace ---\r
2 This function lets the bot know where to go to reach the next navnode.\r
3 \r
4 This is a highly optimized version, it used to also be direction based, so it\r
5 was far more accurate. However, this accuracy was so slow, that it was a\r
6 show-stopper. Now it merely takes the shortest path to the navnode. Due to this,\r
7 navigation gets more and more inaccurate as the navnodes get larger.\r
8 A regular indoor map doesn't require navnodes of the kind of size that would\r
9 suffer from this. I hope to reinstate direction based some time in the future,\r
10 if I get it fast enough.*/\r
11 \r
12 vector(vector point, entity current_space, entity goal_space) ClampPointToSpace =\r
13 {\r
14         local float North, South, West, East, Up, Down;\r
15         local float f, f2;\r
16         local vector ret_point, tvec;\r
17         local entity e;\r
18 \r
19         if (!goal_space)\r
20                 goal_space = current_space;\r
21 \r
22         North = min(current_space.origin_y + current_space.maxs_y, goal_space.origin_y + goal_space.maxs_y);\r
23         South = max(current_space.origin_y + current_space.mins_y, goal_space.origin_y + goal_space.mins_y);\r
24         East = min(current_space.origin_x + current_space.maxs_x, goal_space.origin_x + goal_space.maxs_x);\r
25         West = max(current_space.origin_x + current_space.mins_x, goal_space.origin_x + goal_space.mins_x);\r
26         Up = min(current_space.origin_z + current_space.maxs_z, goal_space.origin_z + goal_space.maxs_z);\r
27         Down = max(current_space.origin_z + current_space.mins_z, goal_space.origin_z + goal_space.mins_z);\r
28 \r
29         f = (East + West) * 0.5;\r
30         f2 = East - self.maxs_x;\r
31         East = max(f, f2);\r
32         f2 = West - self.mins_x;\r
33         West = min(f, f2);\r
34         f = (North + South) * 0.5;\r
35         f2 = North - self.maxs_y;\r
36         North = max(f, f2);\r
37         f2 = South - self.mins_y;\r
38         South = min(f, f2);\r
39         f = (Up + Down) * 0.5;\r
40         f2 = Up - self.maxs_z;\r
41         Up = max(f, f2);\r
42         f2 = Down - self.mins_z;\r
43         Down = min(f, f2);\r
44 \r
45         ret_point_x = bound(West, point_x, East);\r
46         ret_point_y = bound(South, point_y, North);\r
47         ret_point_z = bound(Down, point_z, Up);\r
48 \r
49         e = goal_space.plane_chain;\r
50         while (e)\r
51         {\r
52                 tvec = self.maxs;\r
53                 if (e.mangle_x < 0)\r
54                         tvec_x = self.mins_x;\r
55                 if (e.mangle_y < 0)\r
56                         tvec_y = self.mins_y;\r
57                 if (e.mangle_z < 0)\r
58                         tvec_z = self.mins_z;\r
59                 tvec += ret_point;\r
60                 f = tvec*e.mangle - goal_space.origin*e.mangle-e.delay;\r
61                 if (f > 0)\r
62                         ret_point = ret_point - f*e.mangle;\r
63                 e = e.list;\r
64         }\r
65 \r
66         return ret_point;\r
67 };\r
68 \r
69 entity (entity navn, entity from, entity to) MatchOptPoint =\r
70 {\r
71         local float fr, go;\r
72         local entity t;\r
73 \r
74         if (!from)\r
75                 from = navn;\r
76         if (!to)\r
77                 to = navn;\r
78         t = navn.optp_chain;\r
79         while (t)\r
80         {\r
81                 fr = go = FALSE;\r
82                 if (t.link0 == from)\r
83                         fr = TRUE;\r
84                 else if (t.link1 == from)\r
85                         fr = TRUE;\r
86                 else if (t.link2 == from)\r
87                         fr = TRUE;\r
88                 else if (t.link3 == from)\r
89                         fr = TRUE;\r
90                 else if (t.link4 == from)\r
91                         fr = TRUE;\r
92                 else if (t.link5 == from)\r
93                         fr = TRUE;\r
94                 else if (t.link6 == from)\r
95                         fr = TRUE;\r
96                 else if (t.link7 == from)\r
97                         fr = TRUE;\r
98                 else if (t.link8 == from)\r
99                         fr = TRUE;\r
100                 else if (t.link9 == from)\r
101                         fr = TRUE;\r
102                 if (t.link10 == to)\r
103                         go = TRUE;\r
104                 else if (t.link11 == to)\r
105                         go = TRUE;\r
106                 else if (t.link12 == to)\r
107                         go = TRUE;\r
108                 else if (t.link13 == to)\r
109                         go = TRUE;\r
110                 else if (t.link14 == to)\r
111                         go = TRUE;\r
112                 else if (t.link15 == to)\r
113                         go = TRUE;\r
114                 else if (t.link16 == to)\r
115                         go = TRUE;\r
116                 else if (t.link17 == to)\r
117                         go = TRUE;\r
118                 else if (t.link18 == to)\r
119                         go = TRUE;\r
120                 else if (t.link19 == to)\r
121                         go = TRUE;\r
122                 if (fr && go)\r
123                         return t;\r
124                 t = t.list;\r
125         }\r
126         return world;\r
127 };\r
128 \r
129 /* --- PopRoute ---\r
130 Traverses the bots goal-list to get a new goal to travel towards*/\r
131 \r
132 void() PopRoute =\r
133 {\r
134         self.goallist = self.goalcurrent;\r
135         self.goalcurrent = self.link0;\r
136         self.link0 = self.link1;\r
137         self.link1 = self.link2;\r
138         self.link2 = self.link3;\r
139         self.link3 = self.link4;\r
140         self.link4 = self.link5;\r
141         self.link5 = self.link6;\r
142         self.link6 = self.link7;\r
143         self.link7 = self.link8;\r
144         self.link8 = self.link9;\r
145         self.link9 = self.link10;\r
146         self.link10 = self.link11;\r
147         self.link11 = self.link12;\r
148         self.link12 = self.link13;\r
149         self.link13 = self.link14;\r
150         self.link14 = self.link15;\r
151         self.link15 = self.link16;\r
152         self.link16 = self.link17;\r
153         self.link17 = self.link18;\r
154         self.link18 = self.link19;\r
155         self.link19 = world;\r
156         if (cvar("urrebots_debug"))\r
157         {\r
158                 bprint(self.goalcurrent.classname);\r
159                 bprint("\n");\r
160         }\r
161 };\r
162 \r
163 /* --- PushRoute ---\r
164 Adds navnodes to the bots goal-list*/\r
165 \r
166 void(entity e) PushRoute =\r
167 {\r
168         self.link19 = self.link18;\r
169         self.link18 = self.link17;\r
170         self.link17 = self.link16;\r
171         self.link16 = self.link15;\r
172         self.link15 = self.link14;\r
173         self.link14 = self.link13;\r
174         self.link13 = self.link12;\r
175         self.link12 = self.link11;\r
176         self.link11 = self.link10;\r
177         self.link10 = self.link9;\r
178         self.link9 = self.link8;\r
179         self.link8 = self.link7;\r
180         self.link7 = self.link6;\r
181         self.link6 = self.link5;\r
182         self.link5 = self.link4;\r
183         self.link4 = self.link3;\r
184         self.link3 = self.link2;\r
185         self.link2 = self.link1;\r
186         self.link1 = self.link0;\r
187         self.link0 = self.goalcurrent;\r
188         self.goalcurrent = e;\r
189 };\r
190 \r
191 /* --- ClearRoute ---\r
192 Removes all goals from the bots goal-list*/\r
193 \r
194 void() ClearRoute =\r
195 {\r
196         self.movepoint = nullvector;\r
197         self.goalcurrent = world;\r
198         self.link0 = world;\r
199         self.link1 = world;\r
200         self.link2 = world;\r
201         self.link3 = world;\r
202         self.link4 = world;\r
203         self.link5 = world;\r
204         self.link6 = world;\r
205         self.link7 = world;\r
206         self.link8 = world;\r
207         self.link9 = world;\r
208         self.link10 = world;\r
209         self.link11 = world;\r
210         self.link12 = world;\r
211         self.link13 = world;\r
212         self.link14 = world;\r
213         self.link15 = world;\r
214         self.link16 = world;\r
215         self.link17 = world;\r
216         self.link18 = world;\r
217         self.link19 = world;\r
218 };\r
219 \r
220 /* --- FindCurrentNavNode ---\r
221 Returns the current navnode at an origin with a size*/\r
222 // FIXME: you can do better\r
223 entity(vector org, vector minss, vector maxss) FindCurrentNavNode =\r
224 {\r
225         local float f, f2, bad;\r
226         local vector tvec;\r
227         local entity e, plane, best;\r
228 \r
229         e = navnode_chain;\r
230         while (e)\r
231         {\r
232                 bad = FALSE;\r
233                 if (boxesoverlap(org, org, e.origin + e.mins, e.origin + e.maxs))\r
234                 {\r
235                         plane = e.plane_chain;\r
236                         while (plane)\r
237                         {\r
238                                 f = org*plane.mangle - e.origin*plane.mangle-plane.delay;\r
239                                 if (f > 0)\r
240                                         bad = TRUE;\r
241                                 plane = plane.list;\r
242                         }\r
243                         if (!bad)\r
244                                 return e;\r
245                 }\r
246                 e = e.list;\r
247         }\r
248         e = navnode_chain;\r
249         while (e)\r
250         {\r
251                 bad = FALSE;\r
252                 if (boxesoverlap(org + minss, org + maxss, e.origin + e.mins, e.origin + e.maxs))\r
253                 {\r
254                         plane = e.plane_chain;\r
255                         while (plane)\r
256                         {\r
257                                 tvec = maxss;\r
258                                 if (plane.mangle_x < 0)\r
259                                         tvec_x = minss_x;\r
260                                 if (plane.mangle_y < 0)\r
261                                         tvec_y = minss_y;\r
262                                 if (plane.mangle_z < 0)\r
263                                         tvec_z = minss_z;\r
264                                 tvec += org;\r
265                                 f = tvec*plane.mangle - e.origin*plane.mangle-plane.delay;\r
266                                 if (f > 0)\r
267                                         bad = TRUE;\r
268                                 plane = plane.list;\r
269                         }\r
270                         if (!bad)\r
271                                 return e;\r
272                 }\r
273                 e = e.list;\r
274         }\r
275         f2 = 10000000;\r
276         e = navnode_chain;\r
277         while (e)\r
278         {\r
279                 traceline(org, e.origin, TRUE, world);\r
280                 if (trace_fraction == 1)\r
281                 {\r
282                         f = vlen(org - e.origin);\r
283                         if (f < f2)\r
284                         {\r
285                                 best = e;\r
286                                 f2 = f;\r
287                         }\r
288                 }\r
289                 e = e.list;\r
290         }\r
291         return best;\r
292 };\r
293 \r
294 /* --- ToPointInSpace ---\r
295 Returns a direction towards a point, inside a navnode\r
296 It prefers staying inside a navnode over going towards the point\r
297 This function exists to allow the bot to drop off a platform and run\r
298 under it, and to avoid getting stuck in corners*/\r
299 \r
300 vector(entity space, vector point) ToPointInSpace =\r
301 {\r
302         local float f;\r
303         vector tvec, ret_dir, intonavn, towardspoint;\r
304         local entity e;\r
305 \r
306         if (self.origin_x + self.mins_x <= space.origin_x + space.mins_x)\r
307                 intonavn = '1 0 0';\r
308         else if (self.origin_x + self.maxs_x >= space.origin_x + space.maxs_x)\r
309                 intonavn = '-1 0 0';\r
310         if (self.origin_y + self.mins_y <= space.origin_y + space.mins_y)\r
311                 intonavn += '0 1 0';\r
312         else if (self.origin_y + self.maxs_y >= space.origin_y + space.maxs_y)\r
313                 intonavn += '0 -1 0';\r
314         if (self.origin_z + self.mins_z <= space.origin_z + space.mins_z)\r
315                 intonavn += '0 0 1';\r
316         else if (self.origin_z + self.maxs_z >= space.origin_z + space.maxs_z)\r
317                 intonavn += '0 0 -1';\r
318 \r
319         e = space.plane_chain;\r
320         while (e)\r
321         {\r
322                 tvec = self.maxs;\r
323                 if (e.mangle_x < 0)\r
324                         tvec_x = self.mins_x;\r
325                 if (e.mangle_y < 0)\r
326                         tvec_y = self.mins_y;\r
327                 if (e.mangle_z < 0)\r
328                         tvec_z = self.mins_z;\r
329                 tvec += self.origin;\r
330                 f = tvec*e.mangle - space.origin*e.mangle-e.delay;\r
331                 if (f > 0)\r
332                         intonavn = intonavn - e.mangle;\r
333                 e = e.list;\r
334         }\r
335         intonavn = normalize(intonavn);\r
336 \r
337         towardspoint = normalize(point - self.origin);\r
338         if (!intonavn)\r
339                 ret_dir = towardspoint;\r
340         else\r
341         {\r
342                 if ((intonavn_x < 0 && towardspoint_x < 0) || (intonavn_x > 0 && towardspoint_x > 0))\r
343                         ret_dir_x = towardspoint_x;\r
344                 else\r
345                         ret_dir_x = intonavn_x;\r
346                 if ((intonavn_y < 0 && towardspoint_y < 0) || (intonavn_y > 0 && towardspoint_y > 0))\r
347                         ret_dir_y = towardspoint_y;\r
348                 else\r
349                         ret_dir_y = intonavn_y;\r
350                 if ((intonavn_z < 0 && towardspoint_z < 0) || (intonavn_z > 0 && towardspoint_z > 0))\r
351                         ret_dir_z = towardspoint_z;\r
352                 else\r
353                         ret_dir_z = intonavn_z;\r
354         }\r
355         return ret_dir;\r
356 };