1 //#define PATHLIB_RDFIELDS
\r
2 #ifdef PATHLIB_RDFIELDS
\r
3 #define path_next swampslug
\r
4 #define path_prev lasertarget
\r
10 #define medium spawnshieldtime
\r
12 //#define DEBUGPATHING
\r
18 .float pathlib_node_g;
\r
19 .float pathlib_node_h;
\r
20 .float pathlib_node_f;
\r
22 float pathlib_open_cnt;
\r
23 float pathlib_closed_cnt;
\r
24 float pathlib_made_cnt;
\r
25 float pathlib_merge_cnt;
\r
26 float pathlib_recycle_cnt;
\r
27 float pathlib_searched_cnt;
\r
33 float pathlib_bestopen_seached;
\r
34 float pathlib_bestcash_hits;
\r
35 float pathlib_bestcash_saved;
\r
37 float pathlib_gridsize;
\r
39 float pathlib_movecost;
\r
40 float pathlib_movecost_diag;
\r
41 float pathlib_movecost_waterfactor;
\r
43 float pathlib_edge_check_size;
\r
45 float pathlib_foundgoal;
\r
48 entity best_open_node;
\r
49 .float is_path_node;
\r
53 float edge_show(vector point,float fsize);
\r
54 void mark_error(vector where,float lifetime);
\r
55 void mark_info(vector where,float lifetime);
\r
56 entity mark_misc(vector where,float lifetime);
\r
58 void pathlib_showpath(entity start)
\r
64 te_lightning1(e,e.origin,e.path_next.origin);
\r
69 void path_dbg_think()
\r
71 pathlib_showpath(self);
\r
72 self.nextthink = time + 1;
\r
75 void __showpath2_think()
\r
77 mark_info(self.origin,1);
\r
80 self.path_next.think = __showpath2_think;
\r
81 self.path_next.nextthink = time + 0.15;
\r
85 self.owner.think = __showpath2_think;
\r
86 self.owner.nextthink = time + 0.15;
\r
90 void pathlib_showpath2(entity path)
\r
92 path.think = __showpath2_think;
\r
93 path.nextthink = time;
\r
98 void pathlib_deletepath(entity start)
\r
102 e = findchainentity(owner, start);
\r
105 e.think = SUB_Remove;
\r
106 e.nextthink = time;
\r
111 float fsnap(float val,float fsize)
\r
113 return rint(val / fsize) * fsize;
\r
116 vector vsnap(vector point,float fsize)
\r
120 vret_x = rint(point_x / fsize) * fsize;
\r
121 vret_y = rint(point_y / fsize) * fsize;
\r
122 vret_z = ceil(point_z / fsize) * fsize;
\r
127 float walknode_stepsize;
\r
128 vector walknode_stepup;
\r
129 vector walknode_maxdrop;
\r
130 vector walknode_boxup;
\r
131 vector walknode_boxmax;
\r
132 vector walknode_boxmin;
\r
133 float pathlib_movenode_goodnode;
\r
135 float floor_ok(vector point)
\r
139 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
142 pc = pointcontents(point);
\r
146 case CONTENT_SOLID:
\r
147 case CONTENT_SLIME:
\r
151 case CONTENT_EMPTY:
\r
152 if not (pointcontents(point - '0 0 1') == CONTENT_SOLID)
\r
155 case CONTENT_WATER:
\r
158 if(pointcontents(point - '0 0 1') == CONTENT_SOLID)
\r
164 #define inwater(point) (pointcontents(point) == CONTENT_WATER)
\r
166 float inwater(vector point)
\r
168 if(pointcontents(point) == CONTENT_WATER)
\r
174 #define _pcheck(p) traceline(p+z_up,p-z_down,MOVE_WORLDONLY,self); if not(floor_ok(trace_endpos)) return 1
\r
175 float edge_check(vector point,float fsize)
\r
177 vector z_up,z_down;
\r
179 z_up = '0 0 1' * fsize;
\r
180 z_down = '0 0 1' * fsize;
\r
182 _pcheck(point + ('1 1 0' * fsize));
\r
183 _pcheck(point + ('1 -1 0' * fsize));
\r
184 _pcheck(point + ('1 0 0' * fsize));
\r
186 _pcheck(point + ('0 1 0' * fsize));
\r
187 _pcheck(point + ('0 -1 0' * fsize));
\r
189 _pcheck(point + ('-1 0 0' * fsize));
\r
190 _pcheck(point + ('-1 1 0' * fsize));
\r
191 _pcheck(point + ('-1 -1 0' * fsize));
\r
196 #ifdef DEBUGPATHING
\r
197 #define _pshow(p) mark_error(p,10)
\r
198 float edge_show(vector point,float fsize)
\r
201 _pshow(point + ('1 1 0' * fsize));
\r
202 _pshow(point + ('1 -1 0' * fsize));
\r
203 _pshow(point + ('1 0 0' * fsize));
\r
205 _pshow(point + ('0 1 0' * fsize));
\r
206 _pshow(point + ('0 -1 0' * fsize));
\r
208 _pshow(point + ('-1 0 0' * fsize));
\r
209 _pshow(point + ('-1 1 0' * fsize));
\r
210 _pshow(point + ('-1 -1 0' * fsize));
\r
216 var vector pathlib_movenode(vector start,vector end,float doedge);
\r
217 vector pathlib_wateroutnode(vector start,vector end)
\r
221 pathlib_movenode_goodnode = 0;
\r
223 end_x = fsnap(end_x, pathlib_gridsize);
\r
224 end_y = fsnap(end_y, pathlib_gridsize);
\r
226 traceline(end + ('0 0 0.25' * pathlib_gridsize),end - ('0 0 1' * pathlib_gridsize),MOVE_WORLDONLY,self);
\r
227 end = trace_endpos;
\r
229 if not(pointcontents(end - '0 0 1') == CONTENT_SOLID)
\r
232 for(surface = start ; surface_z < (end_z + 32); ++surface_z)
\r
234 if(pointcontents(surface) == CONTENT_EMPTY)
\r
238 if(pointcontents(surface + '0 0 1') != CONTENT_EMPTY)
\r
241 tracebox(start + '0 0 64', walknode_boxmin,walknode_boxmax, end + '0 0 64', MOVE_WORLDONLY, self);
\r
242 if(trace_fraction == 1)
\r
243 pathlib_movenode_goodnode = 1;
\r
245 if(fabs(surface_z - end_z) > 32)
\r
246 pathlib_movenode_goodnode = 0;
\r
251 vector pathlib_swimnode(vector start,vector end)
\r
253 pathlib_movenode_goodnode = 0;
\r
255 if(pointcontents(start) != CONTENT_WATER)
\r
258 end_x = fsnap(end_x, pathlib_gridsize);
\r
259 end_y = fsnap(end_y, pathlib_gridsize);
\r
261 if(pointcontents(end) == CONTENT_EMPTY)
\r
262 return pathlib_wateroutnode( start, end);
\r
264 tracebox(start, walknode_boxmin,walknode_boxmax, end, MOVE_WORLDONLY, self);
\r
265 if(trace_fraction == 1)
\r
266 pathlib_movenode_goodnode = 1;
\r
271 vector pathlib_flynode(vector start,vector end)
\r
273 pathlib_movenode_goodnode = 0;
\r
275 end_x = fsnap(end_x, pathlib_gridsize);
\r
276 end_y = fsnap(end_y, pathlib_gridsize);
\r
278 tracebox(start, walknode_boxmin,walknode_boxmax, end, MOVE_WORLDONLY, self);
\r
279 if(trace_fraction == 1)
\r
280 pathlib_movenode_goodnode = 1;
\r
285 vector pathlib_walknode(vector start,vector end,float doedge)
\r
287 vector direction,point,last_point,s,e;
\r
288 float steps, distance, i,laststep;
\r
290 pathlib_movenode_goodnode = 0;
\r
296 direction = normalize(s - e);
\r
298 distance = vlen(start - end);
\r
299 laststep = distance / walknode_stepsize;
\r
300 steps = floor(laststep);
\r
301 laststep = laststep - steps;
\r
304 s = point + walknode_stepup;
\r
305 e = point - walknode_maxdrop;
\r
307 traceline(s, e,MOVE_WORLDONLY,self);
\r
308 if(trace_fraction == 1.0)
\r
309 return trace_endpos;
\r
311 if (floor_ok(trace_endpos) == 0)
\r
312 return trace_endpos;
\r
314 last_point = trace_endpos;
\r
316 for(i = 0; i < steps; ++i)
\r
318 point = last_point + direction * walknode_stepsize;
\r
320 s = point + walknode_stepup;
\r
321 e = point - walknode_maxdrop;
\r
322 traceline(s, e,MOVE_WORLDONLY,self);
\r
323 if(trace_fraction == 1.0)
\r
324 return trace_endpos;
\r
326 point = trace_endpos;
\r
327 if not(floor_ok(trace_endpos))
\r
328 return trace_endpos;
\r
330 tracebox(last_point + walknode_boxup, walknode_boxmin,walknode_boxmax, point + walknode_boxup, MOVE_WORLDONLY, self);
\r
331 if(trace_fraction != 1.0)
\r
332 return trace_endpos;
\r
335 if(edge_check(point,pathlib_edge_check_size))
\r
336 return trace_endpos;
\r
338 last_point = point;
\r
341 point = last_point + direction * walknode_stepsize * laststep;
\r
343 point_x = fsnap(point_x, pathlib_gridsize);
\r
344 point_y = fsnap(point_y, pathlib_gridsize);
\r
346 s = point + walknode_stepup;
\r
347 e = point - walknode_maxdrop;
\r
348 traceline(s, e,MOVE_WORLDONLY,self);
\r
350 if(trace_fraction == 1.0)
\r
351 return trace_endpos;
\r
353 point = trace_endpos;
\r
355 if not(floor_ok(trace_endpos))
\r
356 return trace_endpos;
\r
358 tracebox(last_point + walknode_boxup, walknode_boxmin,walknode_boxmax, point + walknode_boxup, MOVE_WORLDONLY, self);
\r
359 if(trace_fraction != 1.0)
\r
360 return trace_endpos;
\r
362 pathlib_movenode_goodnode = 1;
\r
366 var float pathlib_cost(entity parent,vector to, float static_cost);
\r
367 float pathlib_g_static(entity parent,vector to, float static_cost)
\r
370 return parent.pathlib_node_g + static_cost * pathlib_movecost_waterfactor;
\r
372 return parent.pathlib_node_g + static_cost;
\r
375 float pathlib_g_static_water(entity parent,vector to, float static_cost)
\r
378 return parent.pathlib_node_g + static_cost * pathlib_movecost_waterfactor;
\r
380 return parent.pathlib_node_g + static_cost;
\r
383 float pathlib_g_euclidean(entity parent,vector to, float static_cost)
\r
385 return parent.pathlib_node_g + vlen(parent.origin - to);
\r
387 float pathlib_g_euclidean_water(entity parent,vector to, float static_cost)
\r
390 return parent.pathlib_node_g + vlen(parent.origin - to) * pathlib_movecost_waterfactor;
\r
392 return parent.pathlib_node_g + vlen(parent.origin - to);
\r
395 var float(vector from,vector to) pathlib_heuristic;
\r
398 Manhattan Menas we expect to move up,down left or right
\r
399 No diagonal moves espected. (like moving bewteen city blocks)
\r
401 float pathlib_h_manhattan(vector a,vector b)
\r
403 //h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
\r
406 h = fabs(a_x - b_x);
\r
407 h += fabs(a_y - b_y);
\r
408 h *= pathlib_gridsize;
\r
414 This heuristic consider both stright and disagonal moves
\r
415 to have teh same cost.
\r
417 float pathlib_h_diagonal(vector a,vector b)
\r
419 //h(n) = D * max(abs(n.x-goal.x), abs(n.y-goal.y))
\r
422 x = fabs(a_x - b_x);
\r
423 y = fabs(a_y - b_y);
\r
424 h = pathlib_movecost * max(x,y);
\r
430 This heuristic only considers the stright line distance.
\r
431 Will usualy mean a lower H then G meaning A* Will speand more
\r
434 float pathlib_h_euclidean(vector a,vector b)
\r
436 return vlen(a - b);
\r
440 This heuristic consider both stright and disagonal moves,
\r
441 But has a separate cost for diagonal moves.
\r
443 float pathlib_h_diagonal2(vector a,vector b)
\r
445 float h_diag,h_str,h,x,y;
\r
448 h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
\r
449 h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
\r
450 h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
\r
453 x = fabs(a_x - b_x);
\r
454 y = fabs(a_y - b_y);
\r
459 h = pathlib_movecost_diag * h_diag;
\r
460 h += pathlib_movecost * (h_str - 2 * h_diag);
\r
466 This heuristic consider both stright and disagonal moves,
\r
467 But has a separate cost for diagonal moves.
\r
471 float pathlib_h_diagonal2sdp(vector preprev,vector prev,vector point,vector end)
\r
473 float h_diag,h_str,h,x,y,z;
\r
475 //h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
\r
476 //h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
\r
477 //h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
\r
479 x = fabs(point_x - end_x);
\r
480 y = fabs(point_y - end_y);
\r
481 z = fabs(point_z - end_z);
\r
483 h_diag = min3(x,y,z);
\r
486 h = pathlib_movecost_diag * h_diag;
\r
487 h += pathlib_movecost * (h_str - 2 * h_diag);
\r
492 d1 = normalize(preprev - point);
\r
493 d2 = normalize(prev - point);
\r
495 //bprint("pathlib_h_diagonal2sdp-M = ",ftos(m),"\n");
\r
501 float pathlib_h_diagonal3(vector a,vector b)
\r
503 float h_diag,h_str,h,x,y,z;
\r
505 //h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
\r
506 //h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
\r
507 //h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
\r
509 x = fabs(a_x - b_x);
\r
510 y = fabs(a_y - b_y);
\r
511 z = fabs(a_z - b_z);
\r
513 h_diag = min3(x,y,z);
\r
516 h = pathlib_movecost_diag * h_diag;
\r
517 h += pathlib_movecost * (h_str - 2 * h_diag);
\r
522 //#define PATHLIB_USE_NODESCRAP
\r
523 #define PATHLIB_NODEEXPIRE 0.05
\r
524 float pathlib_scraplist_cnt;
\r
528 #ifdef PATHLIB_USE_NODESCRAP
\r
529 if(pathlib_scraplist_cnt)
\r
531 n = findentity(world,owner,scraplist);
\r
534 --pathlib_scraplist_cnt;
\r
535 ++pathlib_recycle_cnt;
\r
539 pathlib_scraplist_cnt = 0;
\r
542 ++pathlib_made_cnt;
\r
544 #ifdef PATHLIB_NODEEXPIRE
\r
545 n.think = SUB_Remove;
\r
546 n.nextthink = time + PATHLIB_NODEEXPIRE;
\r
550 void dumpnode(entity n)
\r
552 #ifdef PATHLIB_USE_NODESCRAP
\r
553 ++pathlib_scraplist_cnt;
\r
555 n.path_next = world;
\r
556 n.path_prev = world;
\r
557 n.is_path_node = FALSE;
\r
558 n.owner = scraplist;
\r
560 //n.is_path_node = FALSE;
\r
561 n.think = SUB_Remove;
\r
562 n.nextthink = time;
\r
566 entity pathlib_mknode(vector where,entity parent)
\r
571 node.is_path_node = TRUE;
\r
572 node.owner = openlist;
\r
573 node.path_prev = parent;
\r
575 setorigin(node, where);
\r
577 ++pathlib_open_cnt;
\r
579 node.medium = pointcontents(where);
\r
584 var float pathlib_expandnode(entity node, vector start, vector goal);
\r
585 float pathlib_expandnode_star(entity node, vector start, vector goal);
\r
586 float pathlib_expandnode_box(entity node, vector start, vector goal);
\r
588 var float pathlib_makenode(entity parent,vector start, vector to, vector goal,float cost);
\r
589 float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
\r
592 float h,g,f,doedge;
\r
595 ++pathlib_searched_cnt;
\r
597 if(inwater(parent.origin))
\r
599 pathlib_expandnode = pathlib_expandnode_box;
\r
600 pathlib_movenode = pathlib_swimnode;
\r
606 pathlib_expandnode = pathlib_expandnode_box;
\r
607 pathlib_movenode = pathlib_swimnode;
\r
612 pathlib_expandnode = pathlib_expandnode_star;
\r
613 pathlib_movenode = pathlib_walknode;
\r
618 where = pathlib_movenode(parent.origin,to,0);
\r
619 if not(pathlib_movenode_goodnode)
\r
623 if(edge_check(where,pathlib_edge_check_size))
\r
626 if(parent.path_prev)
\r
627 pathlib_h_diagonal2sdp(parent.path_prev.origin,parent.origin,where,goal);
\r
629 h = pathlib_heuristic(where,goal);
\r
630 g = pathlib_cost(parent,where,cost);
\r
633 node = findradius(where,pathlib_gridsize * 0.75);
\r
636 if(node.is_path_node == TRUE)
\r
638 ++pathlib_merge_cnt;
\r
639 if(node.owner == openlist)
\r
641 if(node.pathlib_node_g > g)
\r
643 node.pathlib_node_h = h;
\r
644 node.pathlib_node_g = g;
\r
645 node.pathlib_node_f = f;
\r
646 node.path_prev = parent;
\r
649 if not (best_open_node)
\r
650 best_open_node = node;
\r
651 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
\r
652 best_open_node = node;
\r
660 node = pathlib_mknode(where,parent);
\r
661 node.pathlib_node_h = h;
\r
662 node.pathlib_node_g = g;
\r
663 node.pathlib_node_f = f;
\r
665 if not (best_open_node)
\r
666 best_open_node = node;
\r
667 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
\r
668 best_open_node = node;
\r
673 entity pathlib_getbestopen()
\r
680 ++pathlib_bestcash_hits;
\r
681 pathlib_bestcash_saved += pathlib_open_cnt;
\r
683 return best_open_node;
\r
686 node = findchainentity(owner,openlist);
\r
693 ++pathlib_bestopen_seached;
\r
694 if(node.pathlib_node_f < bestnode.pathlib_node_f)
\r
703 void pathlib_close_node(entity node,vector goal)
\r
706 if(node.owner == closedlist)
\r
708 dprint("Pathlib: Tried to close a closed node!\n");
\r
712 if(node == best_open_node)
\r
713 best_open_node = world;
\r
715 ++pathlib_closed_cnt;
\r
716 --pathlib_open_cnt;
\r
718 node.owner = closedlist;
\r
720 if(vlen(node.origin - goal) <= pathlib_gridsize)
\r
724 goalmove = pathlib_walknode(node.origin,goal,1);
\r
725 if(pathlib_movenode_goodnode)
\r
728 pathlib_foundgoal = TRUE;
\r
733 float pathlib_expandnode_star(entity node, vector start, vector goal)
\r
739 where = node.origin;
\r
741 v_forward = '1 0 0';
\r
745 point = where + v_forward * pathlib_gridsize;
\r
746 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
\r
749 point = where - v_forward * pathlib_gridsize;
\r
750 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
\r
753 point = where + v_right * pathlib_gridsize;
\r
754 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
\r
757 point = where - v_right * pathlib_gridsize;
\r
758 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
\r
761 point = where + v_forward * pathlib_gridsize + v_right * pathlib_gridsize;
\r
762 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
\r
765 point = where + v_forward * pathlib_gridsize - v_right * pathlib_gridsize;
\r
766 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
\r
769 point = where - v_forward * pathlib_gridsize + v_right * pathlib_gridsize;
\r
770 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
\r
773 point = where - v_forward * pathlib_gridsize - v_right * pathlib_gridsize;
\r
774 nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
\r
776 return pathlib_open_cnt;
\r
779 float pathlib_expandnode_box(entity node, vector start, vector goal)
\r
783 for(v_z = node.origin_z - pathlib_gridsize; v_z <= node.origin_z + pathlib_gridsize; v_z += pathlib_gridsize)
\r
784 for(v_y = node.origin_y - pathlib_gridsize; v_y <= node.origin_y + pathlib_gridsize; v_y += pathlib_gridsize)
\r
785 for(v_x = node.origin_x - pathlib_gridsize; v_x <= node.origin_x + pathlib_gridsize; v_x += pathlib_gridsize)
\r
787 if(vlen(v - node.origin))
\r
788 pathlib_makenode(node,start,v,goal,pathlib_movecost);
\r
791 return pathlib_open_cnt;
\r
794 void pathlib_cleanup()
\r
798 node = findfloat(world,is_path_node, TRUE);
\r
802 node = findfloat(node,is_path_node, TRUE);
\r
809 remove(closedlist);
\r
811 best_open_node = world;
\r
813 closedlist = world;
\r
816 var float buildpath_nodefilter(vector n,vector c,vector p);
\r
817 float buildpath_nodefilter_directional(vector n,vector c,vector p)
\r
821 d2 = normalize(p - c);
\r
822 d1 = normalize(c - n);
\r
824 if(vlen(d1-d2) < 0.25)
\r
830 float buildpath_nodefilter_moveskip(vector n,vector c,vector p)
\r
832 pathlib_walknode(p,n,1);
\r
833 if(pathlib_movenode_goodnode)
\r
839 entity path_build(entity next, vector where, entity prev, entity start)
\r
844 if(buildpath_nodefilter)
\r
845 if(buildpath_nodefilter(next.origin,where,prev.origin))
\r
850 path.owner = start;
\r
851 path.path_next = next;
\r
853 setorigin(path,where);
\r
856 path.classname = "path_end";
\r
860 path.classname = "path_start";
\r
862 path.classname = "path_node";
\r
868 entity pathlib_astar(vector from,vector to)
\r
870 entity path, start, end, open, n, ln;
\r
871 float ptime, ftime, ctime;
\r
873 ptime = gettime(GETTIME_REALTIME);
\r
877 // Select water<->land capable node make/link
\r
878 pathlib_makenode = pathlib_makenode_adaptive;
\r
879 // Select XYZ cost estimate
\r
880 pathlib_heuristic = pathlib_h_diagonal3;
\r
881 // Select distance + waterfactor cost
\r
882 pathlib_cost = pathlib_g_euclidean_water;
\r
883 // Select star expander
\r
884 pathlib_expandnode = pathlib_expandnode_star;
\r
885 // Select walk simulation movement test
\r
886 pathlib_movenode = pathlib_walknode;
\r
887 // Filter final nodes by direction
\r
888 buildpath_nodefilter = buildpath_nodefilter_directional;
\r
890 // If the start is in water we need diffrent settings
\r
893 // Select volumetric node expaner
\r
894 pathlib_expandnode = pathlib_expandnode_box;
\r
896 // Water movement test
\r
897 pathlib_movenode = pathlib_swimnode;
\r
901 openlist = spawn();
\r
904 closedlist = spawn();
\r
907 scraplist = spawn();
\r
909 pathlib_closed_cnt = 0;
\r
910 pathlib_open_cnt = 0;
\r
911 pathlib_made_cnt = 0;
\r
912 pathlib_merge_cnt = 0;
\r
913 pathlib_searched_cnt = 0;
\r
914 pathlib_bestopen_seached = 0;
\r
915 pathlib_bestcash_hits = 0;
\r
916 pathlib_bestcash_saved = 0;
\r
917 pathlib_recycle_cnt = 0;
\r
919 pathlib_gridsize = 128;
\r
920 pathlib_movecost = pathlib_gridsize;
\r
921 pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
\r
922 pathlib_movecost_waterfactor = 1.1;
\r
923 pathlib_foundgoal = 0;
\r
925 walknode_boxmax = self.maxs * 1.5;
\r
926 walknode_boxmin = self.mins * 1.5;
\r
928 pathlib_edge_check_size = (vlen(walknode_boxmin - walknode_boxmax) * 0.5);
\r
930 walknode_boxup = '0 0 2' * self.maxs_z;
\r
931 walknode_stepsize = 32;
\r
932 walknode_stepup = '0 0 1' * walknode_stepsize;
\r
933 walknode_maxdrop = '0 0 3' * walknode_stepsize;
\r
935 from_x = fsnap(from_x,pathlib_gridsize);
\r
936 from_y = fsnap(from_y,pathlib_gridsize);
\r
938 to_x = fsnap(to_x,pathlib_gridsize);
\r
939 to_y = fsnap(to_y,pathlib_gridsize);
\r
941 dprint("AStar init. ", ftos(pathlib_scraplist_cnt), " nodes on scrap\n");
\r
942 path = pathlib_mknode(from,world);
\r
943 pathlib_close_node(path,to);
\r
944 if(pathlib_foundgoal)
\r
946 dprint("AStar: Goal found on first node!\n");
\r
950 open.classname = "path_end";
\r
951 setorigin(open,path.origin);
\r
958 if(pathlib_expandnode(path,from,to) <= 0)
\r
960 dprint("AStar path fail.\n");
\r
966 best_open_node = pathlib_getbestopen();
\r
967 n = best_open_node;
\r
968 pathlib_close_node(best_open_node,to);
\r
969 if(inwater(n.origin))
\r
970 pathlib_expandnode_box(n,from,to);
\r
972 pathlib_expandnode_star(n,from,to);
\r
974 while(pathlib_open_cnt)
\r
976 best_open_node = pathlib_getbestopen();
\r
977 n = best_open_node;
\r
978 pathlib_close_node(best_open_node,to);
\r
980 if(inwater(n.origin))
\r
981 pathlib_expandnode_box(n,from,to);
\r
983 pathlib_expandnode(n,from,to);
\r
985 if(pathlib_foundgoal)
\r
987 dprint("Target found. Rebuilding and filtering path...\n");
\r
988 ftime = gettime(GETTIME_REALTIME);
\r
989 ptime = ftime - ptime;
\r
991 start = path_build(world,path.origin,world,world);
\r
992 end = path_build(world,goal_node.origin,world,start);
\r
996 for(open = goal_node; open.path_prev != path; open = open.path_prev)
\r
998 n = path_build(ln,open.origin,open.path_prev,start);
\r
1002 start.path_next = n;
\r
1003 n.path_prev = start;
\r
1004 ftime = gettime(GETTIME_REALTIME) - ftime;
\r
1006 ctime = gettime(GETTIME_REALTIME);
\r
1007 pathlib_cleanup();
\r
1008 ctime = gettime(GETTIME_REALTIME) - ctime;
\r
1011 #ifdef DEBUGPATHING
\r
1012 pathlib_showpath2(start);
\r
1014 dprint("Time used - pathfinding: ", ftos(ptime),"\n");
\r
1015 dprint("Time used - rebuild & filter: ", ftos(ftime),"\n");
\r
1016 dprint("Time used - cleanup: ", ftos(ctime),"\n");
\r
1017 dprint("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
\r
1018 dprint("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
\r
1019 dprint("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
\r
1020 dprint("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
\r
1021 dprint("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
\r
1022 dprint("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
\r
1023 dprint("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
\r
1025 if(pathlib_recycle_cnt)
\r
1026 dprint("Nodes - make/reuse: ", ftos(pathlib_made_cnt / pathlib_recycle_cnt),"\n");
\r
1027 if(pathlib_recycle_cnt)
\r
1028 dprint("Nodes - reused: ", ftos(pathlib_recycle_cnt),"\n");
\r
1030 dprint("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
\r
1031 dprint("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
\r
1032 dprint("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
\r
1033 dprint("AStar done. ", ftos(pathlib_scraplist_cnt), " nodes on scrap\n\n");
\r
1039 dprint("A* Faild to find a path! Try a smaller gridsize.\n");
\r
1041 pathlib_cleanup();
\r