1 #define PLF_GROUNDSNAP 1
\r
2 #define PLF_NOOPTIMIZE 2
\r
3 #define PLF_SUBPATH3D 4
\r
5 //#define PATHLIB_RDFIELDS
\r
6 #ifdef PATHLIB_RDFIELDS
\r
7 #define path_flags lip
\r
9 #define path_subpathing_size autoswitch
\r
10 #define path_subpathing_bboxexpand welcomemessage_time
\r
12 #define path_next swampslug
\r
13 #define path_prev lasertarget
\r
18 .float path_subpathing_size;
\r
19 .float path_subpathing_bboxexpand;
\r
23 #define pathlib_garbagetime 120
\r
24 #define pathib_maxdivide 256
\r
26 .float(vector start,vector end) path_validate;
\r
28 float pathlib_stdproc_path_validate(vector start,vector end)
\r
30 tracebox(start, self.mins, self.maxs, end, MOVE_NORMAL, self);
\r
32 if(vlen(trace_endpos - end) < 32)
\r
38 vector pathlib_groundsnap(vector where,entity path)
\r
42 lsize = vlen(self.mins - self.maxs) * 0.25;
\r
44 traceline(where + ('0 0 1' * lsize) ,where - '0 0 10000',MOVE_NORMAL,self);
\r
46 return trace_endpos + ('0 0 1' * lsize);
\r
50 entity pathlib_createpoint(entity parent,entity next,entity first,vector where)
\r
55 point.classname = "path_node";
\r
58 point.owner = first;
\r
61 point.classname = "path_master";
\r
62 point.owner = point;
\r
66 point.path_prev = parent;
\r
70 point.path_next = next;
\r
71 //point.path_nodelength = vlen(point.origin - next.origin)
\r
74 point.classname = "path_end";
\r
76 if(point.owner.path_flags & PLF_GROUNDSNAP)
\r
77 where = pathlib_groundsnap(where,parent);
\r
80 setorigin(point,where);
\r
86 vector pathlib_findsubpath(entity start,vector vcrash,entity end,float maxsize)
\r
92 float pathlength_best;
\r
97 pathlength_best = 1000000;
\r
99 step = vlen(self.maxs - self.mins) * start.owner.path_subpathing_bboxexpand;
\r
101 if(start.owner.path_flags & PLF_SUBPATH3D)
\r
103 zmin = maxsize * -1;
\r
112 for(z = zmin; z < zmax; z += step)
\r
113 for(y = -maxsize; y < maxsize; y += step)
\r
114 for(x = -maxsize; x < maxsize; x += step)
\r
117 point_z = vcrash_z + z;
\r
118 point_x = vcrash_x + x;
\r
119 point_y = vcrash_y + y;
\r
122 if(start.owner.path_flags & PLF_GROUNDSNAP)
\r
123 point = pathlib_groundsnap(point,start);
\r
125 if(self.path_validate(start.origin,point))
\r
127 dist = vlen(start.origin - point);
\r
130 pathlength = dist + vlen(point - end.origin);
\r
131 if(pathlength < pathlength_best)
\r
134 pathlength_best = pathlength;
\r
141 if(pathlength_best != 1000000)
\r
147 float pathlib_path(entity start,entity end)
\r
150 vector subpath_point;
\r
154 if(start.cnt > pathib_maxdivide)
\r
157 if(self.path_validate(start.origin,end.origin))
\r
160 vcrash = trace_endpos;
\r
162 subpath_point = pathlib_findsubpath(start,vcrash,end,start.owner.path_subpathing_size);
\r
164 if(subpath_point == vcrash)
\r
167 subpoint = pathlib_createpoint(start,end,start.owner,subpath_point);
\r
169 subpoint.cnt = start.cnt +1;
\r
170 start.path_next = subpoint;
\r
171 end.path_prev = subpoint;
\r
173 if(self.path_validate(start.origin,end.origin))
\r
176 return pathlib_path(subpoint,end);
\r
179 void pathlib_path_optimize(entity start,entity end)
\r
181 entity point,point_tmp;
\r
184 point = start.path_next;
\r
186 while(point != end)
\r
191 dprint("pathlib_path_optimize runaway!\n");
\r
196 point = point.path_next;
\r
197 if(self.path_validate(point_tmp.path_prev.origin,point_tmp.path_next.origin))
\r
200 point_tmp.path_next.path_prev = point_tmp.path_prev;
\r
201 point_tmp.path_prev.path_next = point_tmp.path_next;
\r
207 void pathlib_deletepath(entity start)
\r
211 e = findentity(start, owner, start);
\r
215 e = findentity(start, owner, start);
\r
219 void pathlib_showpath(entity start)
\r
225 te_lightning1(e,e.origin,e.path_next.origin);
\r
231 Run a A*-like pathing from 'from' to 'to'
\r
233 entity pathlib_makepath(vector from, vector to,float pathflags,float subpathing_size, float subpathing_bboxexpand)
\r
235 entity e_start,e_end;
\r
237 if(!self.path_validate)
\r
238 self.path_validate = pathlib_stdproc_path_validate;
\r
241 if(subpathing_size < 10)
\r
242 subpathing_size = 500;
\r
244 if(subpathing_bboxexpand < 1)
\r
245 subpathing_bboxexpand = 1;
\r
247 e_start = pathlib_createpoint(world,world,world,from);
\r
248 e_start.path_flags = pathflags;
\r
250 e_start.path_subpathing_size = subpathing_size;
\r
251 e_start.path_subpathing_bboxexpand = subpathing_bboxexpand;
\r
253 e_start.owner = e_start;
\r
255 e_end = pathlib_createpoint(e_start,world,e_start,to);
\r
256 e_start.path_next = e_end;
\r
259 if(!pathlib_path(e_start,e_end))
\r
261 pathlib_deletepath(e_start);
\r
266 pathlib_path_optimize(e_start,e_end);
\r
274 void pathlib_test_think()
\r
276 pathlib_showpath(self.enemy);
\r
278 self.nextthink = time + 0.5;
\r
280 void pathlib_test_dinit()
\r
285 if(self.target == "")
\r
287 bprint("^1 ==== ERROR: pathlib_test with no target. ====\n");
\r
292 end = find(world,targetname,self.target);
\r
295 bprint("^1 ==== ERROR: pathlib_test with no valid target. ====\n");
\r
300 setsize(self,'-50 -50 0','50 50 50');
\r
301 path = pathlib_makepath(self.origin,end.origin, PLF_GROUNDSNAP,500,1.25);
\r
305 bprint("^1 ==== ERROR: pathlib_test pathing fail ====\n");
\r
311 self.think = pathlib_test_think;
\r
312 self.nextthink = time + 0.5;
\r
315 void spawnfunc_pathlib_test()
\r
317 self.think = pathlib_test_dinit;
\r
318 self.nextthink = time + 2;
\r