5 #include "../command/common.qh"
7 void pathlib_deletepath(entity start)
11 e = findchainentity(owner, start);
14 setthink(e, SUB_Remove);
20 //#define PATHLIB_NODEEXPIRE 0.05
21 const float PATHLIB_NODEEXPIRE = 20;
23 void dumpnode(entity n)
25 n.is_path_node = false;
26 setthink(n, SUB_Remove);
31 void pathlib_showpath(entity start);
32 void pathlib_showpath2(entity path);
33 void pathlib_showsquare(vector where,float goodsquare,float _lifetime);
37 entity pathlib_mknode(vector where,entity parent)
41 node = pathlib_nodeatpoint(where);
45 mark_error(where, 60);
52 setthink(node, SUB_Remove);
53 node.nextthink = time + PATHLIB_NODEEXPIRE;
54 node.is_path_node = true;
55 node.owner = openlist;
56 node.path_prev = parent;
59 setsize(node, '0 0 0', '0 0 0');
61 setorigin(node, where);
62 node.medium = pointcontents(where);
64 pathlib_showsquare(where, 1 ,15);
72 float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
75 float h,g,f,doedge = 0;
78 ++pathlib_searched_cnt;
80 if(inwater(parent.origin))
82 LOG_TRACE("FromWater\n");
83 pathlib_expandnode = pathlib_expandnode_box;
84 pathlib_movenode = pathlib_swimnode;
90 LOG_TRACE("ToWater\n");
91 pathlib_expandnode = pathlib_expandnode_box;
92 pathlib_movenode = pathlib_walknode;
96 LOG_TRACE("LandToLoand\n");
97 //if(edge_check(parent.origin))
100 pathlib_expandnode = pathlib_expandnode_star;
101 pathlib_movenode = pathlib_walknode;
106 node = pathlib_nodeatpoint(to);
109 LOG_TRACE("NodeAtPoint\n");
112 if(node.owner == openlist)
114 h = pathlib_heuristic(node.origin,goal);
115 g = pathlib_cost(parent,node.origin,cost);
118 if(node.pathlib_node_g > g)
120 node.pathlib_node_h = h;
121 node.pathlib_node_g = g;
122 node.pathlib_node_f = f;
124 node.path_prev = parent;
128 best_open_node = node;
129 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
130 best_open_node = node;
136 where = pathlib_movenode(parent, parent.origin, to, 0);
138 if (!pathlib_movenode_goodnode)
140 //pathlib_showsquare(where, 0 ,30);
141 //pathlib_showsquare(parent.origin, 1 ,30);
142 LOG_TRACE("pathlib_movenode_goodnode = 0\n");
146 //pathlib_showsquare(where, 1 ,30);
148 if(pathlib_nodeatpoint(where))
150 LOG_TRACE("NAP WHERE :",vtos(where),"\n");
151 LOG_TRACE("not NAP TO:",vtos(to),"\n");
152 LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)),"\n\n");
158 if (!tile_check(parent, where))
160 LOG_TRACE("tile_check fail\n");
162 pathlib_showsquare(where, 0 ,30);
168 h = pathlib_heuristic(where,goal);
169 g = pathlib_cost(parent,where,cost);
173 node = findradius(where,pathlib_gridsize * 0.5);
176 if(node.is_path_node == true)
179 if(node.owner == openlist)
181 if(node.pathlib_node_g > g)
183 //pathlib_movenode(node, where,node.origin,0);
184 //if(pathlib_movenode_goodnode)
186 //mark_error(node.origin + '0 0 128',30);
187 node.pathlib_node_h = h;
188 node.pathlib_node_g = g;
189 node.pathlib_node_f = f;
190 node.path_prev = parent;
195 best_open_node = node;
196 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
197 best_open_node = node;
206 node = pathlib_mknode(where, parent);
207 node.pathlib_node_h = h;
208 node.pathlib_node_g = g;
209 node.pathlib_node_f = f;
212 best_open_node = node;
213 else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
214 best_open_node = node;
219 entity pathlib_getbestopen()
226 ++pathlib_bestcash_hits;
227 pathlib_bestcash_saved += pathlib_open_cnt;
229 return best_open_node;
232 node = findchainentity(owner,openlist);
239 ++pathlib_bestopen_seached;
240 if(node.pathlib_node_f < bestnode.pathlib_node_f)
249 void pathlib_close_node(entity node,vector goal)
252 if(node.owner == closedlist)
254 LOG_TRACE("Pathlib: Tried to close a closed node!\n");
258 if(node == best_open_node)
259 best_open_node = NULL;
261 ++pathlib_closed_cnt;
264 node.owner = closedlist;
266 if(vdist(node.origin - goal, <=, pathlib_gridsize))
270 goalmove = pathlib_walknode(node, node.origin, goal, 1);
271 if(pathlib_movenode_goodnode)
274 pathlib_foundgoal = true;
279 void pathlib_cleanup()
281 best_open_node = NULL;
287 node = findfloat(NULL,is_path_node, true);
291 node.owner = openlist;
292 node.pathlib_node_g = 0;
293 node.pathlib_node_h = 0;
294 node.pathlib_node_f = 0;
295 node.path_prev = NULL;
299 node = findfloat(node,is_path_node, true);
313 float Cosine_Interpolate(float a, float b, float x)
318 f = (1 - cos(ft)) * 0.5;
320 return a*(1-f) + b*f;
323 float buildpath_nodefilter_directional(vector n,vector c,vector p)
327 d2 = normalize(p - c);
328 d1 = normalize(c - n);
330 if(vdist(d1 - d2, <, 0.25))
339 float buildpath_nodefilter_moveskip(entity this, vector n,vector c,vector p)
341 pathlib_walknode(this, p, n, 1);
342 if(pathlib_movenode_goodnode)
348 float buildpath_nodefilter_none(vector n,vector c,vector p)
353 entity path_build(entity next, vector where, entity prev, entity start)
358 if(buildpath_nodefilter)
359 if(buildpath_nodefilter(next.origin,where,prev.origin))
365 path.path_next = next;
367 setorigin(path, where);
370 path.classname = "path_end";
374 path.classname = "path_start";
376 path.classname = "path_node";
382 entity pathlib_astar(entity this, vector from,vector to)
384 entity path, start, end, open, n, ln;
385 float ptime, ftime, ctime;
387 ptime = gettime(GETTIME_REALTIME);
388 pathlib_starttime = ptime;
392 // Select water<->land capable node make/link
393 pathlib_makenode = pathlib_makenode_adaptive;
395 // Select XYZ cost estimate
396 //pathlib_heuristic = pathlib_h_diagonal3;
397 pathlib_heuristic = pathlib_h_diagonal;
399 // Select distance + waterfactor cost
400 pathlib_cost = pathlib_g_euclidean_water;
402 // Select star expander
403 pathlib_expandnode = pathlib_expandnode_star;
405 // Select walk simulation movement test
406 pathlib_movenode = pathlib_walknode;
408 // Filter final nodes by direction
409 buildpath_nodefilter = buildpath_nodefilter_directional;
411 // Filter tiles with cross pattern
412 tile_check = tile_check_cross;
414 // If the start is in water we need diffrent settings
417 // Select volumetric node expaner
418 pathlib_expandnode = pathlib_expandnode_box;
420 // Water movement test
421 pathlib_movenode = pathlib_swimnode;
428 closedlist = spawn();
430 pathlib_closed_cnt = 0;
431 pathlib_open_cnt = 0;
432 pathlib_made_cnt = 0;
433 pathlib_merge_cnt = 0;
434 pathlib_searched_cnt = 0;
435 pathlib_bestopen_seached = 0;
436 pathlib_bestcash_hits = 0;
437 pathlib_bestcash_saved = 0;
439 pathlib_gridsize = 128;
440 pathlib_movecost = pathlib_gridsize;
441 pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
442 pathlib_movecost_waterfactor = 25000000;
443 pathlib_foundgoal = 0;
445 movenode_boxmax = this.maxs * 1.1;
446 movenode_boxmin = this.mins * 1.1;
448 movenode_stepsize = pathlib_gridsize * 0.25;
450 tile_check_size = pathlib_gridsize * 0.5;
451 tile_check_up = '0 0 2' * pathlib_gridsize;
452 tile_check_up = '0 0 128';
453 tile_check_down = '0 0 3' * pathlib_gridsize;
454 tile_check_down = '0 0 256';
456 //movenode_stepup = '0 0 128';
457 movenode_stepup = '0 0 36';
458 movenode_maxdrop = '0 0 512';
459 //movenode_maxdrop = '0 0 512';
460 movenode_boxup = '0 0 72';
462 from.x = fsnap(from.x, pathlib_gridsize);
463 from.y = fsnap(from.y, pathlib_gridsize);
466 to.x = fsnap(to.x, pathlib_gridsize);
467 to.y = fsnap(to.y, pathlib_gridsize);
470 LOG_TRACE("AStar init\n");
471 path = pathlib_mknode(from, NULL);
472 pathlib_close_node(path, to);
473 if(pathlib_foundgoal)
475 LOG_TRACE("AStar: Goal found on first node!\n");
477 open = new(path_end);
479 setorigin(open, path.origin);
486 if(pathlib_expandnode(path, from, to) <= 0)
488 LOG_TRACE("AStar path fail.\n");
494 best_open_node = pathlib_getbestopen();
496 pathlib_close_node(best_open_node, to);
497 if(inwater(n.origin))
498 pathlib_expandnode_box(n, from, to);
500 pathlib_expandnode_star(n, from, to);
502 while(pathlib_open_cnt)
504 if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
506 LOG_TRACE("Path took to long to compute!\n");
507 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
508 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
509 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
510 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
516 best_open_node = pathlib_getbestopen();
518 pathlib_close_node(best_open_node,to);
520 if(inwater(n.origin))
521 pathlib_expandnode_box(n,from,to);
523 pathlib_expandnode(n,from,to);
525 if(pathlib_foundgoal)
527 LOG_TRACE("Target found. Rebuilding and filtering path...\n");
528 ftime = gettime(GETTIME_REALTIME);
529 ptime = ftime - ptime;
531 start = path_build(NULL,path.origin,NULL,NULL);
532 end = path_build(NULL,goal_node.origin,NULL,start);
536 for(open = goal_node; open.path_prev != path; open = open.path_prev)
538 n = path_build(ln,open.origin,open.path_prev,start);
544 ftime = gettime(GETTIME_REALTIME) - ftime;
546 ctime = gettime(GETTIME_REALTIME);
548 ctime = gettime(GETTIME_REALTIME) - ctime;
552 pathlib_showpath2(start);
554 LOG_TRACE("Time used - pathfinding: ", ftos(ptime),"\n");
555 LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime),"\n");
556 LOG_TRACE("Time used - cleanup: ", ftos(ctime),"\n");
557 LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
558 LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
559 LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
560 LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
561 LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
562 LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
563 LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
564 LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
565 LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
566 LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
567 LOG_TRACE("AStar done.\n");
573 LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.\n");