1 #define PLF_GROUNDSNAP 1
\r
2 #define PLF_NOOPTIMIZE 2
\r
3 #define PLF_SUBPATH3D 4
\r
5 #define path_flags lip
\r
8 // #define pathgroup version
\r
9 #define path_subpathing_size autoswitch
\r
10 #define path_subpathing_bboxexpand welcomemessage_time
\r
15 #define path_next swampslug
\r
16 #define path_prev lasertarget
\r
18 #define pathlib_garbagetime 120
\r
20 .float(vector start,vector end) path_validate;
\r
22 float pathlib_stdproc_path_validate(vector start,vector end)
\r
24 tracebox(start, self.mins, self.maxs, end, MOVE_NORMAL, self);
\r
26 if(vlen(trace_endpos - end) < 32)
\r
32 vector pathlib_groundsnap(vector where,entity path)
\r
36 lsize = vlen(self.mins - self.maxs) * 0.25;
\r
38 traceline(where + ('0 0 1' * lsize) ,where - '0 0 10000',MOVE_NORMAL,self);
\r
40 return trace_endpos + ('0 0 1' * lsize);
\r
44 entity pathlib_createpoint(entity parent,entity next,entity first,vector where)
\r
49 point.classname = "path_node";
\r
51 //point.think = SUB_Remove;
\r
52 //point.nectthink = time + pathlib_garbagetime;
\r
55 point.owner = first;
\r
58 point.classname = "path_master";
\r
59 point.owner = point;
\r
63 point.path_prev = parent;
\r
66 point.path_next = next;
\r
68 point.classname = "path_end";
\r
70 if(point.owner.path_flags & PLF_GROUNDSNAP)
\r
71 where = pathlib_groundsnap(where,parent);
\r
74 setorigin(point,where);
\r
80 #define pathib_maxdivide 128
\r
81 vector pathlib_findsubpath(entity start,vector vcrash,entity end,float maxsize)
\r
87 float pathlength_best;
\r
92 pathlength_best = 1000000;
\r
94 step = vlen(self.maxs - self.mins) * start.owner.path_subpathing_bboxexpand;
\r
96 if(start.owner.path_flags & PLF_SUBPATH3D)
\r
98 zmin = maxsize * -1;
\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
112 point_z = vcrash_z + z;
\r
113 point_x = vcrash_x + x;
\r
114 point_y = vcrash_y + y;
\r
117 if(start.owner.path_flags & PLF_GROUNDSNAP)
\r
118 point = pathlib_groundsnap(point,start);
\r
120 if(self.path_validate(start.origin,point))
\r
122 dist = vlen(start.origin - point);
\r
125 pathlength = dist + vlen(point - end.origin);
\r
126 if(pathlength < pathlength_best)
\r
129 pathlength_best = pathlength;
\r
136 if(pathlength_best != 1000000)
\r
142 float pathlib_path(entity start,entity end)
\r
145 vector subpath_point;
\r
149 if(start.cnt > pathib_maxdivide)
\r
152 if(self.path_validate(start.origin,end.origin))
\r
155 vcrash = trace_endpos;
\r
157 subpath_point = pathlib_findsubpath(start,vcrash,end,start.owner.path_subpathing_size);
\r
159 if(subpath_point == vcrash)
\r
162 subpoint = pathlib_createpoint(start,end,start.owner,subpath_point);
\r
164 subpoint.cnt = start.cnt +1;
\r
165 start.path_next = subpoint;
\r
166 end.path_prev = subpoint;
\r
168 if(self.path_validate(start.origin,end.origin))
\r
171 return pathlib_path(subpoint,end);
\r
174 void pathlib_path_optimize(entity start,entity end)
\r
176 entity point,point_tmp;
\r
179 point = start.path_next;
\r
181 while(point != end)
\r
186 dprint("pathlib_path_optimize runaway!\n");
\r
191 point = point.path_next;
\r
192 if(self.path_validate(point_tmp.path_prev.origin,point_tmp.path_next.origin))
\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
202 void pathlib_deletepath(entity start)
\r
206 e = findentity(start, owner, start);
\r
210 e = findentity(start, owner, start);
\r
214 void pathlib_showpath(entity start)
\r
220 te_lightning1(e,e.origin,e.path_next.origin);
\r
225 entity pathlib_makepath(vector from, vector to,float pathflags,float subpathing_size, float subpathing_bboxexpand)
\r
227 entity e_start,e_end;
\r
229 if(!self.path_validate)
\r
230 self.path_validate = pathlib_stdproc_path_validate;
\r
233 if(subpathing_size < 10)
\r
234 subpathing_size = 500;
\r
236 if(subpathing_bboxexpand < 1)
\r
237 subpathing_bboxexpand = 1;
\r
239 e_start = pathlib_createpoint(world,world,world,from);
\r
240 e_start.path_flags = pathflags;
\r
242 e_start.path_subpathing_size = subpathing_size;
\r
243 e_start.path_subpathing_bboxexpand = subpathing_bboxexpand;
\r
245 e_start.owner = e_start;
\r
247 e_end = pathlib_createpoint(e_start,world,e_start,to);
\r
248 e_start.path_next = e_end;
\r
251 if(!pathlib_path(e_start,e_end))
\r
253 pathlib_deletepath(e_start);
\r
258 pathlib_path_optimize(e_start,e_end);
\r
264 void pathlib_test_think()
\r
266 pathlib_showpath(self.enemy);
\r
268 self.nextthink = time + 0.5;
\r
270 void pathlib_test_dinit()
\r
275 if(self.target == "")
\r
277 bprint("^1 ==== ERROR: pathlib_test with no target. ====\n");
\r
282 end = find(world,targetname,self.target);
\r
285 bprint("^1 ==== ERROR: pathlib_test with no valid target. ====\n");
\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
295 bprint("^1 ==== ERROR: pathlib_test pathing fail ====\n");
\r
301 self.think = pathlib_test_think;
\r
302 self.nextthink = time + 0.5;
\r
305 void spawnfunc_pathlib_test()
\r
307 self.think = pathlib_test_dinit;
\r
308 self.nextthink = time + 2;
\r