]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/pathlib.qc
Updated pathlib.qc
[divverent/nexuiz.git] / data / qcsrc / server / pathlib.qc
1 #define PLF_GROUNDSNAP 1\r
2 #define PLF_NOOPTIMIZE 2\r
3 #define PLF_SUBPATH3D  4\r
4 \r
5 #define path_flags lip\r
6 \r
7 //.float pathgroup;\r
8 // #define pathgroup version\r
9 #define path_subpathing_size autoswitch\r
10 #define path_subpathing_bboxexpand welcomemessage_time\r
11 /*\r
12 .entity path_next;\r
13 .entity path_prev;\r
14 */\r
15 #define path_next swampslug\r
16 #define path_prev lasertarget\r
17 \r
18 #define pathlib_garbagetime 120\r
19 \r
20 .float(vector start,vector end) path_validate;\r
21 \r
22 float pathlib_stdproc_path_validate(vector start,vector end)\r
23 {\r
24     tracebox(start, self.mins, self.maxs, end, MOVE_NORMAL, self);\r
25 \r
26     if(vlen(trace_endpos - end) < 32)\r
27         return 1;\r
28 \r
29     return 0;\r
30 }\r
31 \r
32 vector pathlib_groundsnap(vector where,entity path)\r
33 {\r
34     float lsize;\r
35 \r
36     lsize = vlen(self.mins - self.maxs) * 0.25;\r
37 \r
38     traceline(where + ('0 0 1' * lsize) ,where - '0 0 10000',MOVE_NORMAL,self);\r
39 \r
40     return trace_endpos + ('0 0 1' * lsize);\r
41 \r
42 }\r
43 \r
44 entity pathlib_createpoint(entity parent,entity next,entity first,vector where)\r
45 {\r
46     entity point;\r
47 \r
48     point = spawn();\r
49     point.classname = "path_node";\r
50 \r
51     //point.think = SUB_Remove;\r
52     //point.nectthink = time + pathlib_garbagetime;\r
53 \r
54     if(first)\r
55         point.owner = first;\r
56     else\r
57     {\r
58         point.classname = "path_master";\r
59         point.owner = point;\r
60     }\r
61 \r
62     if(parent)\r
63         point.path_prev = parent;\r
64 \r
65     if(next)\r
66         point.path_next = next;\r
67     else\r
68         point.classname = "path_end";\r
69 \r
70     if(point.owner.path_flags & PLF_GROUNDSNAP)\r
71         where = pathlib_groundsnap(where,parent);\r
72 \r
73 \r
74     setorigin(point,where);\r
75 \r
76 \r
77     return point;\r
78 }\r
79 \r
80 #define pathib_maxdivide 128\r
81 vector pathlib_findsubpath(entity start,vector vcrash,entity end,float maxsize)\r
82 {\r
83     float x,y,z;\r
84     float step;\r
85     float dist;\r
86     float pathlength;\r
87     float pathlength_best;\r
88     vector bestpoint;\r
89     vector point;\r
90     float zmin,zmax;\r
91 \r
92     pathlength_best = 1000000;\r
93 \r
94     step = vlen(self.maxs - self.mins) * start.owner.path_subpathing_bboxexpand;\r
95 \r
96     if(start.owner.path_flags & PLF_SUBPATH3D)\r
97     {\r
98         zmin = maxsize * -1;\r
99         zmax = maxsize;\r
100     }\r
101     else\r
102     {\r
103         zmin = 0;\r
104         zmax = 1;\r
105     }\r
106 \r
107     for(z = zmin; z < zmax; z += step)\r
108     for(y = -maxsize; y < maxsize; y += step)\r
109     for(x = -maxsize; x < maxsize; x += step)\r
110     {\r
111 \r
112         point_z = vcrash_z + z;\r
113         point_x = vcrash_x + x;\r
114         point_y = vcrash_y + y;\r
115 \r
116 \r
117         if(start.owner.path_flags & PLF_GROUNDSNAP)\r
118             point = pathlib_groundsnap(point,start);\r
119 \r
120         if(self.path_validate(start.origin,point))\r
121         {\r
122             dist = vlen(start.origin - point);\r
123             if(dist > step)\r
124             {\r
125                 pathlength = dist + vlen(point - end.origin);\r
126                 if(pathlength < pathlength_best)\r
127                 {\r
128                     bestpoint = point;\r
129                     pathlength_best = pathlength;\r
130                 }\r
131             }\r
132         }\r
133 \r
134     }\r
135 \r
136     if(pathlength_best != 1000000)\r
137         return bestpoint;\r
138 \r
139     return vcrash;\r
140 }\r
141 \r
142 float pathlib_path(entity start,entity end)\r
143 {\r
144     vector vcrash;\r
145     vector subpath_point;\r
146     entity subpoint;\r
147 \r
148     // Fail.\r
149     if(start.cnt > pathib_maxdivide)\r
150         return 0;\r
151 \r
152     if(self.path_validate(start.origin,end.origin))\r
153         return 1;\r
154 \r
155     vcrash = trace_endpos;\r
156 \r
157     subpath_point = pathlib_findsubpath(start,vcrash,end,start.owner.path_subpathing_size);\r
158 \r
159     if(subpath_point == vcrash)\r
160         return 0; // Fail.\r
161 \r
162     subpoint = pathlib_createpoint(start,end,start.owner,subpath_point);\r
163 \r
164     subpoint.cnt = start.cnt +1;\r
165     start.path_next = subpoint;\r
166     end.path_prev = subpoint;\r
167 \r
168     if(self.path_validate(start.origin,end.origin))\r
169         return 1;\r
170 \r
171     return pathlib_path(subpoint,end);\r
172 }\r
173 \r
174 void pathlib_path_optimize(entity start,entity end)\r
175 {\r
176     entity point,point_tmp;\r
177     float c;\r
178 \r
179     point = start.path_next;\r
180 \r
181     while(point != end)\r
182     {\r
183         c++;\r
184         if(c > 5000)\r
185         {\r
186             dprint("pathlib_path_optimize runaway!\n");\r
187             return;\r
188         }\r
189 \r
190         point_tmp = point;\r
191         point = point.path_next;\r
192         if(self.path_validate(point_tmp.path_prev.origin,point_tmp.path_next.origin))\r
193         {\r
194 \r
195             point_tmp.path_next.path_prev = point_tmp.path_prev;\r
196             point_tmp.path_prev.path_next = point_tmp.path_next;\r
197             remove(point_tmp);\r
198         }\r
199     }\r
200 }\r
201 \r
202 void pathlib_deletepath(entity start)\r
203 {\r
204     entity e;\r
205 \r
206     e = findentity(start, owner, start);\r
207     while(e)\r
208     {\r
209         remove(e);\r
210         e = findentity(start, owner, start);\r
211     }\r
212 }\r
213 \r
214 void pathlib_showpath(entity start)\r
215 {\r
216     entity e;\r
217     e = start;\r
218     while(e.path_next)\r
219     {\r
220         te_lightning1(e,e.origin,e.path_next.origin);\r
221         e = e.path_next;\r
222     }\r
223 }\r
224 \r
225 entity pathlib_makepath(vector from, vector to,float pathflags,float subpathing_size, float subpathing_bboxexpand)\r
226 {\r
227     entity e_start,e_end;\r
228 \r
229     if(!self.path_validate)\r
230         self.path_validate = pathlib_stdproc_path_validate;\r
231 \r
232 \r
233     if(subpathing_size < 10)\r
234         subpathing_size = 500;\r
235 \r
236     if(subpathing_bboxexpand < 1)\r
237         subpathing_bboxexpand = 1;\r
238 \r
239     e_start = pathlib_createpoint(world,world,world,from);\r
240     e_start.path_flags = pathflags;\r
241 \r
242     e_start.path_subpathing_size = subpathing_size;\r
243     e_start.path_subpathing_bboxexpand = subpathing_bboxexpand;\r
244 \r
245     e_start.owner = e_start;\r
246 \r
247     e_end = pathlib_createpoint(e_start,world,e_start,to);\r
248     e_start.path_next = e_end;\r
249     e_start.cnt = 0;\r
250 \r
251     if(!pathlib_path(e_start,e_end))\r
252     {\r
253         pathlib_deletepath(e_start);\r
254         remove(e_start);\r
255         return world;\r
256     }\r
257 \r
258     pathlib_path_optimize(e_start,e_end);\r
259 \r
260     return e_start;\r
261 \r
262 }\r
263 \r
264 void pathlib_test_think()\r
265 {\r
266     pathlib_showpath(self.enemy);\r
267 \r
268     self.nextthink = time + 0.5;\r
269 }\r
270 void pathlib_test_dinit()\r
271 {\r
272     entity path;\r
273     entity end;\r
274 \r
275     if(self.target == "")\r
276     {\r
277         bprint("^1 ==== ERROR: pathlib_test with no target. ====\n");\r
278         remove(self);\r
279         return;\r
280     }\r
281 \r
282     end = find(world,targetname,self.target);\r
283     if(!end)\r
284     {\r
285         bprint("^1 ==== ERROR: pathlib_test with no valid target. ====\n");\r
286         remove(self);\r
287         return;\r
288     }\r
289 \r
290     setsize(self,'-50 -50 0','50 50 50');\r
291     path = pathlib_makepath(self.origin,end.origin, PLF_GROUNDSNAP,500,1.25);\r
292 \r
293     if(!path)\r
294     {\r
295         bprint("^1 ==== ERROR: pathlib_test pathing fail ====\n");\r
296         remove(self);\r
297         return;\r
298     }\r
299 \r
300     self.enemy = path;\r
301     self.think = pathlib_test_think;\r
302     self.nextthink = time + 0.5;\r
303 \r
304 }\r
305 void spawnfunc_pathlib_test()\r
306 {\r
307     self.think = pathlib_test_dinit;\r
308     self.nextthink = time + 2;\r
309 }\r