[nexuiz-commits] r6245 - trunk/data/qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Mar 22 10:09:56 EDT 2009


Author: tzork
Date: 2009-03-22 10:09:56 -0400 (Sun, 22 Mar 2009)
New Revision: 6245

Added:
   trunk/data/qcsrc/server/verbstack.qc
Modified:
   trunk/data/qcsrc/server/movelib.qc
   trunk/data/qcsrc/server/pathlib.qc
Log:
pathlib changed to use with AStar.
add verbstack for stack based ai.


Modified: trunk/data/qcsrc/server/movelib.qc
===================================================================
--- trunk/data/qcsrc/server/movelib.qc	2009-03-21 22:12:11 UTC (rev 6244)
+++ trunk/data/qcsrc/server/movelib.qc	2009-03-22 14:09:56 UTC (rev 6245)
@@ -31,7 +31,7 @@
 
 /**
     Do a inertia simulation based on velocity.
-    Basicaly, this allows you to simulate objects loss steering with speed.
+    Basicaly, this allows you to simulate loss of steering with higher speed.
     self.velocity = movelib_inertia_fromspeed(self.velocity,newvel,1000,0.1,0.9);
 **/
 vector movelib_inertmove_byspeed(vector vel_new, float vel_max,float newmin,float oldmax)
@@ -55,14 +55,15 @@
 {
     float deltatime;
     float acceleration;
-    //float mspeed;
+    float mspeed;
+    vector breakvec;
 
     deltatime = time - self.movelib_lastupdate;
     if (deltatime > 0.15) deltatime = 0;
     self.movelib_lastupdate = time;
     if(!deltatime) return;
 
-    //mspeed = vlen(self.velocity);
+    mspeed = vlen(self.velocity);
 
     if(mass)
         acceleration = vlen(force) / mass;
@@ -72,61 +73,144 @@
     if(self.flags & FL_ONGROUND)
     {
         if(breakforce)
-        {
-            breakforce = 1 - ((breakforce / mass) * deltatime);
-            self.velocity = self.velocity * breakforce;
-        }
+        {
+            breakvec = (normalize(self.velocity) * (breakforce / mass) * deltatime);
+            self.velocity = self.velocity - breakvec;
+        }
 
         self.velocity = self.velocity + force * (acceleration * deltatime);
-    }
+    }
 
-    self.velocity = self.velocity + '0 0 -1' * sv_gravity * deltatime;
+    if(drag)
+        self.velocity = movelib_dragvec(drag, 1);
+
+    if(self.waterlevel > 1)
+    {
+        self.velocity = self.velocity + force * (acceleration * deltatime);
+        self.velocity = self.velocity + '0 0 0.05' * sv_gravity * deltatime;
+    }
+    else
+        self.velocity = self.velocity + '0 0 -1' * sv_gravity * deltatime;
+
+    mspeed = vlen(self.velocity);
 
-    if(drag)
-        self.velocity = movelib_dragvec(drag, 1);
-
     if(max_velocity)
-    if(vlen(self.velocity) > max_velocity)
-        self.velocity = normalize(self.velocity) * max_velocity;
-}
+        if(mspeed > max_velocity)
+            self.velocity = normalize(self.velocity) * (mspeed - 50);//* max_velocity;
+}
+
+/*
+.float mass;
+.float side_friction;
+.float ground_friction;
+.float air_friction;
+.float water_friction;
+.float buoyancy;
+float movelib_deltatime;
+
+void movelib_startupdate()
+{
+    movelib_deltatime = time - self.movelib_lastupdate;
+
+    if (movelib_deltatime > 0.5)
+        movelib_deltatime = 0;
+
+    self.movelib_lastupdate = time;
+}
 
-void movelib_move_simple(vector newdir,float velo,float turnrate)
-{
-    vector olddir;
+void movelib_update(vector dir,float force)
+{
+    vector acceleration;
+    float old_speed;
+    float ffriction,v_z;
+
+    vector breakvec;
+    vector old_dir;
+    vector ggravity;
+    vector old;
+
+    if(!movelib_deltatime)
+        return;
+    v_z = self.velocity_z;
+    old_speed    = vlen(self.velocity);
+    old_dir      = normalize(self.velocity);
+
+    //ggravity      =  (sv_gravity / self.mass) * '0 0 100';
+    acceleration =  (force / self.mass) * dir;
+    //acceleration -= old_dir * (old_speed / self.mass);
+    acceleration -= ggravity;
+
+    if(self.waterlevel > 1)
+    {
+        ffriction = self.water_friction;
+        acceleration += self.buoyancy * '0 0 1';
+    }
+    else
+        if(self.flags & FL_ONGROUND)
+            ffriction = self.ground_friction;
+        else
+            ffriction = self.air_friction;
+
+    acceleration *= ffriction;
+    //self.velocity = self.velocity * (ffriction * movelib_deltatime);
+    self.velocity += acceleration * movelib_deltatime;
+    self.velocity_z = v_z;
+
+}
+*/
 
-    olddir = normalize(self.velocity);
-
-    self.velocity = normalize(olddir + newdir * turnrate) * velo;
-}
-
-/*
-vector movelib_accelerate(float force)
+void movelib_move_simple(vector newdir,float velo,float blendrate)
 {
-    vector vel;
-    vel = self.velocity;
-    vel = normalize(vel) * (vlen(vel) + force);
-    self.velocity = self.velocity  + vel;
+    self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo;
 }
-
-
-vector movelib_decelerate(float force,float mass)
-{
-    vector vel;
-    float decel;
-
-    if(mass)
-        decel = force / mass;
-    else
-        decel = force;
-
-    vel = self.velocity;
-    vel = normalize(vel) * max((vlen(vel) - decel),0);
-    self.velocity = self.velocity - vel;
-
-    if(vlen(self.velocity) < 5) self.velocity = '0 0 0';
-}
-*/
-vector movelib_velocity_transfer(entity source,entity destination)
-{
-    return '0 0 0';
-}
+void movelib_beak_simple(float force)
+{
+    float mspeed;
+    vector mdir;
+
+    mspeed = max(0,vlen(self.velocity) - force);
+    mdir   = normalize(self.velocity);
+    self.velocity = mdir * mspeed;
+}
+
+
+void movelib_groundalign4point(float spring_length,float spring_up)
+{
+    vector a,b,c,d,e,r,push_angle;
+    push_angle_y = 0;
+    r = (self.absmax + self.absmin) * 0.5 + (v_up * spring_up);
+    e = v_up * spring_length;
+
+    a = r + (v_forward * self.maxs_x) + (v_right * self.maxs_y);
+    b = r + (v_forward * self.maxs_x) - (v_right * self.maxs_y);
+    c = r - (v_forward * self.maxs_x) + (v_right * self.maxs_y);
+    d = r - (v_forward * self.maxs_x) - (v_right * self.maxs_y);
+
+    traceline(a, a - e,MOVE_NORMAL,self);
+    a_z =  (1 - trace_fraction);
+    r = trace_endpos;
+    traceline(b, b - e,MOVE_NORMAL,self);
+    b_z =  (1 - trace_fraction);
+    r += trace_endpos;
+    traceline(c, c - e,MOVE_NORMAL,self);
+    c_z =  (1 - trace_fraction);
+    r += trace_endpos;
+    traceline(d, d - e,MOVE_NORMAL,self);
+    d_z =  (1 - trace_fraction);
+    r += trace_endpos;
+    a_x = r_z;
+    r = self.origin;
+    r_z = r_z;
+
+    push_angle_x = (a_z - c_z) * 45;
+    push_angle_x += (b_z - d_z) * 45;
+
+    push_angle_z = (b_z - a_z) * 45;
+    push_angle_z += (d_z - c_z) * 45;
+
+    self.angles_x += push_angle_x * 0.95;
+    self.angles_z += push_angle_z * 0.95;
+
+    setorigin(self,r);
+}
+

Modified: trunk/data/qcsrc/server/pathlib.qc
===================================================================
--- trunk/data/qcsrc/server/pathlib.qc	2009-03-21 22:12:11 UTC (rev 6244)
+++ trunk/data/qcsrc/server/pathlib.qc	2009-03-22 14:09:56 UTC (rev 6245)
@@ -1,480 +1,1001 @@
-#define PFL_GROUNDSNAP 1
-#define PFL_NOOPTIMIZE 2
-#define PFL_SUBPATH3D  4
-
-#define PT_QUICKSTAR 1
-#define PT_QUICKBOX  2
-#define PT_ASTAR     4  // FIXME NOT IMPLEMENTED
-
-//#define PATHLIB_RDFIELDS
-#ifdef PATHLIB_RDFIELDS
-    #define path_flags lip
-
-    #define path_subpathing_size autoswitch
-    #define path_subpathing_bboxexpand welcomemessage_time
-
-    #define path_next swampslug
-    #define path_prev lasertarget
-#else
-    .entity path_next;
-    .entity path_prev;
-
-    .float path_subpathing_size;
-    .float path_subpathing_bboxexpand;
-    .float path_flags;
-#endif
-
-#define pathlib_garbagetime 120
-#define pathib_maxdivide 512
-
-.float(vector start,vector end) path_validate;
-
-float pathlib_stdproc_path_validate(vector start,vector end)
-{
-    tracebox(start, self.mins, self.maxs, end, MOVE_WORLDONLY, self);
-
-    if(vlen(trace_endpos - end) < 32)
-        return 1;
-
-    return 0;
-}
-
-vector pathlib_groundsnap(vector where)
-{
-    float lsize;
-
-    lsize = vlen(self.mins - self.maxs) * 0.25;
-
-    traceline(where + ('0 0 1' * lsize) ,where - '0 0 10240',MOVE_WORLDONLY,self);
-
-    return trace_endpos + ('0 0 1' * lsize);
-
-}
-
-entity pathlib_createpoint(entity parent,entity next,entity first,vector where)
-{
-    entity point;
-
-    point = spawn();
-    point.classname = "path_node";
-
-    if(first)
-        point.owner = first;
-    else
-    {
-        point.classname = "path_master";
-        point.owner = point;
-    }
-
-    if(parent)
-        point.path_prev = parent;
-
-    if(next)
-    {
-        point.path_next = next;
-    }
-    else
-        point.classname = "path_end";
-
-    if (point.owner.path_flags & PFL_GROUNDSNAP)
-        where = pathlib_groundsnap(where);
-
-    setorigin(point,where);
-
-
-    return point;
-}
-
-/*
-float pathlib_scoresubpath(vector start,vector point,vector end,float minstep)
-{
-    float dist_stp,dist_pte,dist_total;
-
-    dist_stp = vlen(start - point);
-    if(dist_stp < minstep)
-        return 100000000;
-
-    dist_pte = vlen(point - end);
-    dist_total = dist_stp + dist_pte;
-    return -1;
-}
-*/
-
-vector pathlib_subpath_quickbox(entity start,vector vcrash,entity end,float maxsize)
-{
-
-    float step;
-    float pathscore;
-    float pathscore_best;
-    float dist;
-    vector bestpoint,point;
-    float zmin,zmax;
-    vector box;
-
-    pathscore_best = 0;
-
-    step = vlen(self.maxs - self.mins) * start.owner.path_subpathing_bboxexpand;
-
-    if(start.owner.path_flags & PFL_SUBPATH3D)
-    {
-        zmin = maxsize * -1;
-        zmax = maxsize;
-    }
-    else
-    {
-        zmin = 0;
-        zmax = 1;
-    }
-
-    for(box_z = zmin; box_z < zmax; box_z += step)
-    for(box_y = -maxsize; box_y < maxsize; box_y += step)
-    for(box_x = -maxsize; box_x < maxsize; box_x += step)
-    {
-
-        point = vcrash + box;
-
-        if(start.owner.path_flags & PFL_GROUNDSNAP)
-            point = pathlib_groundsnap(point);
-
-        if(self.path_validate(start.origin,point))
-        {
-            dist = vlen(start.origin - point);
-            if(dist > step)
-            {
-                pathscore = 1 / (dist + vlen(point - end.origin));
-                if(pathscore > pathscore_best)
-                {
-                    bestpoint = point;
-                    pathscore_best = pathscore;
-                }
-            }
-        }
-
-    }
-
-    if(pathscore_best != 0)
-        return bestpoint;
-
-    return start.origin;
-}
-
-vector pathlib_subpath_quickstar(entity start,entity end,float gridsize)
-{
-    vector point, best_point;
-    float  score, best_score;
-    vector dir_end;
-
-    dir_end   = normalize(end.origin - start.origin);
-    dir_end_x = dir_end_x * -1;
-
-    makevectors(dir_end);
-
-    best_score = 0;
-    score      = 0;
-
-    best_point = start.origin;
-
-    // Forward
-    point = start.origin + v_forward * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    // Forward-right
-    point = start.origin + (v_forward + v_right * 0.5) * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-
-    // Forward-left
-    point = start.origin + (v_forward - v_right * 0.5) * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-
-    // Right
-    point = start.origin + v_right * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    // Left
-    point = start.origin - v_right * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    // Back
-    point = start.origin - v_forward * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    // Back-right
-
-    point = start.origin - (v_forward + v_right * 0.5) * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    // Back-left
-    point = start.origin - (v_forward - v_right * 0.5) * gridsize;
-    point  = pathlib_groundsnap(point);
-    if(self.path_validate(start.origin,point)) score = 1 / vlen(point - end.origin);
-    if(score < best_score) { best_point = point; best_score = score; }
-    //te_lightning1(world,start.origin,point);
-
-    return(best_point);
-}
-
-float pathlib_path(entity start,entity end,float pathing_method)
-{
-    vector vcrash;
-    vector subpath_point;
-    entity subpoint;
-
-    // Fail.
-    if(start.cnt > pathib_maxdivide)
-    {
-        bprint("To many segments!\n");
-        return 0;
-    }
-
-    if(self.path_validate(start.origin,end.origin))
-        return 1;
-
-    vcrash = trace_endpos;
-
-    switch(pathing_method)
-    {
-        case PT_QUICKSTAR:
-            subpath_point = pathlib_subpath_quickstar(start,end,start.owner.path_subpathing_size);
-            break;
-        case PT_QUICKBOX:
-            subpath_point = pathlib_subpath_quickbox(start,vcrash,end,start.owner.path_subpathing_size);
-            break;
-        case PT_ASTAR:
-            dprint("Pathlib error: A* pathing not implemented!\n");
-            return 0;
-        default:
-            subpath_point = pathlib_subpath_quickstar(start,end,start.owner.path_subpathing_size);
-            dprint("Pathlib warning: unknown pathing method, using quickstar!\n");
-            break;
-    }
-
-    if(subpath_point == start.origin)
-        return 0; // Fail.
-
-    subpoint = pathlib_createpoint(start,end,start.owner,subpath_point);
-
-    subpoint.cnt = start.cnt +1;
-    start.path_next = subpoint;
-    end.path_prev = subpoint;
-
-    if(self.path_validate(start.origin,end.origin))
-        return 1;
-
-    return pathlib_path(subpoint,end,pathing_method);
-}
-
-void pathlib_path_optimize(entity start,entity end)
-{
-    entity point,point_tmp;
-    float c;
-
-    point = start.path_next;
-
-    while(point != end)
-    {
-        ++c;
-        if(c > 5000)
-        {
-            dprint("pathlib_path_optimize runaway!\n");
-            return;
-        }
-
-        point_tmp = point;
-        point = point.path_next;
-        if(self.path_validate(point_tmp.path_prev.origin,point_tmp.path_next.origin))
-        {
-
-            point_tmp.path_next.path_prev = point_tmp.path_prev;
-            point_tmp.path_prev.path_next = point_tmp.path_next;
-            remove(point_tmp);
-        }
-    }
-}
-
-void pathlib_deletepath(entity start)
-{
-    entity e;
-
-    e = findchainentity(owner, start);
-    while(e)
-    {
-        e.think = SUB_Remove;
-        e.nextthink = time;
-        e = e.chain;
-    }
-}
-
-//#define DEBUGPATHING
-#ifdef DEBUGPATHING
-void pathlib_showpath(entity start)
-{
-    entity e;
-    e = start;
-    while(e.path_next)
-    {
-        te_lightning1(e,e.origin,e.path_next.origin);
-        e = e.path_next;
-    }
-}
-
-void path_dbg_think()
-{
-    pathlib_showpath(self);
-    self.nextthink = time + 1;
-}
-#endif
-/**
-    Pathing from 'from' to 'to'
-**/
-entity pathlib_makepath(vector from, vector to,float pathflags,float subpathing_size, float subpathing_bboxexpand,float pathing_method)
-{
-    entity e_start,e_end;
-
-    if(!self.path_validate)
-        self.path_validate = pathlib_stdproc_path_validate;
-
-
-    if(subpathing_size < 10)
-        subpathing_size = 500;
-
-    if(subpathing_bboxexpand < 1)
-        subpathing_bboxexpand = 1;
-
-    if(pathflags & PFL_GROUNDSNAP)
-    {
-        from = pathlib_groundsnap(from);
-        to = pathlib_groundsnap(to);
-    }
-
-    e_start = pathlib_createpoint(world,world,world,from);
-    e_start.path_flags = pathflags;
-
-    e_start.path_subpathing_size = subpathing_size;
-    e_start.path_subpathing_bboxexpand = subpathing_bboxexpand;
-
-    e_start.owner = e_start;
-
-    e_end = pathlib_createpoint(e_start,world,e_start,to);
-    e_start.path_next = e_end;
-    e_start.cnt = 0;
-
-    if(!pathlib_path(e_start,e_end,pathing_method))
-    {
-        bprint("Fail, Fail, Fail!\n");
-        pathlib_deletepath(e_start);
-        remove(e_start);
-
-        return world;
-    }
-
-    pathlib_path_optimize(e_start,e_end);
-
-#ifdef DEBUGPATHING
-    e_start.think = path_dbg_think;
-    e_start.nextthink = time + 1;
-#endif
-
-    return e_start;
-
-}
-
-/*
-.entity goalcurrent, goalstack01, goalstack02, goalstack03;
-.entity goalstack04, goalstack05, goalstack06, goalstack07;
-.entity goalstack08, goalstack09, goalstack10, goalstack11;
-.entity goalstack12, goalstack13, goalstack14, goalstack15;
-.entity goalstack16, goalstack17, goalstack18, goalstack19;
-.entity goalstack20, goalstack21, goalstack22, goalstack23;
-.entity goalstack24, goalstack25, goalstack26, goalstack27;
-.entity goalstack28, goalstack29, goalstack30, goalstack31;
-*/
-
-#define node_left  goalstack01
-#define node_right goalstack02
-#define node_front goalstack03
-#define node_back  goalstack04
-
-#define node_open    goalstack05
-#define node_closed  goalstack06
-#define node_blocked goalstack07
-
-
-
-float pointinbox(vector point,vector box,float ssize)
-{
-    return 0;
-}
-#ifdef DEBUGPATHING
-
-/* TESTING */
-void pathlib_test_think()
-{
-    pathlib_showpath(self.enemy);
-
-    self.nextthink = time + 0.5;
-}
-void pathlib_test_dinit()
-{
-    entity path;
-    entity end;
-
-    if(self.target == "")
-    {
-        bprint("^1 ==== ERROR: pathlib_test with no target. ====\n");
-        remove(self);
-        return;
-    }
-
-    end = find(world,targetname,self.target);
-    if(!end)
-    {
-        bprint("^1 ==== ERROR: pathlib_test with no valid target. ====\n");
-        remove(self);
-        return;
-    }
-
-    setsize(self,'-50 -50 0','50 50 50');
-    path = pathlib_makepath(self.origin,end.origin, PFL_GROUNDSNAP,500,1.25,PT_QUICKSTAR);
-
-    if(!path)
-    {
-        bprint("^1 ==== ERROR: pathlib_test pathing fail ====\n");
-        remove(self);
-        return;
-    }
-
-    self.enemy = path;
-    self.think = pathlib_test_think;
-    self.nextthink = time + 0.5;
-
-}
-void spawnfunc_pathlib_test()
-{
-    self.think = pathlib_test_dinit;
-    self.nextthink = time + 2;
-}
-
-#endif
+//#define PATHLIB_RDFIELDS
+#ifdef PATHLIB_RDFIELDS
+    #define path_next swampslug
+    #define path_prev lasertarget
+#else
+    .entity path_next;
+    .entity path_prev;
+#endif
+
+entity openlist;
+entity closedlist;
+entity scraplist;
+
+.float pathlib_node_g;
+.float pathlib_node_h;
+.float pathlib_node_f;
+
+float pathlib_open_cnt;
+float pathlib_closed_cnt;
+float pathlib_made_cnt;
+float pathlib_merge_cnt;
+float pathlib_recycle_cnt;
+float pathlib_searched_cnt;
+
+float pathlib_bestopen_seached;
+float pathlib_bestcash_hits;
+float pathlib_bestcash_saved;
+
+float pathlib_gridsize;
+
+float pathlib_movecost;
+float pathlib_movecost_diag;
+float pathlib_movecost_waterfactor;
+
+float pathlib_edge_check_size;
+
+float pathlib_foundgoal;
+entity goal_node;
+
+entity best_open_node;
+.float is_path_node;
+
+float edge_show(vector point,float fsize);
+
+//#define DEBUGPATHING
+#ifdef DEBUGPATHING
+void mark_error(vector where,float lifetime);
+void mark_info(vector where,float lifetime);
+entity mark_misc(vector where,float lifetime);
+
+
+
+void pathlib_showpath(entity start)
+{
+    entity e;
+    e = start;
+    while(e.path_next)
+    {
+        te_lightning1(e,e.origin,e.path_next.origin);
+        e = e.path_next;
+    }
+}
+
+void path_dbg_think()
+{
+    pathlib_showpath(self);
+    self.nextthink = time + 1;
+}
+
+void __showpath2_think()
+{
+    mark_info(self.origin,1);
+    if(self.path_next)
+    {
+        self.path_next.think     = __showpath2_think;
+        self.path_next.nextthink = time + 0.15;
+    }
+    else
+    {
+        self.owner.think     = __showpath2_think;
+        self.owner.nextthink = time + 0.15;
+    }
+}
+
+void pathlib_showpath2(entity path)
+{
+    path.think     = __showpath2_think;
+    path.nextthink = time;
+}
+
+#endif
+
+/*
+float pathlib_stdproc_path_validate(vector start,vector end)
+{
+    tracebox(start, self.mins * 2, self.maxs * 2, end, MOVE_WORLDONLY, self);
+
+    if(vlen(trace_endpos - end) < 5)
+        return 1;
+
+    return 0;
+}
+*/
+
+
+void pathlib_deletepath(entity start)
+{
+    entity e;
+
+    e = findchainentity(owner, start);
+    while(e)
+    {
+        e.think = SUB_Remove;
+        e.nextthink = time;
+        e = e.chain;
+    }
+}
+
+float fsnap(float val,float fsize)
+{
+    return rint(val / fsize) * fsize;
+}
+
+vector vsnap(vector point,float fsize)
+{
+    vector vret;
+
+    vret_x = rint(point_x / fsize) * fsize;
+    vret_y = rint(point_y / fsize) * fsize;
+    vret_z = ceil(point_z / fsize) * fsize;
+
+    return vret;
+}
+
+
+#define floor_failmask (DPCONTENTS_SLIME | DPCONTENTS_LAVA)
+// | DPCONTENTS_MONSTERCLIP | DPCONTENTS_DONOTENTER
+float walknode_stepsize;
+vector walknode_stepup;
+vector walknode_maxdrop;
+vector walknode_boxup;
+vector walknode_boxmax;
+vector walknode_boxmin;
+float pathlib_movenode_goodnode;
+
+float floor_ok(vector point)
+{
+    float pc;
+
+    if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
+        return 0;
+
+    pc = pointcontents(point);
+
+    switch(pc)
+    {
+        case CONTENT_SOLID:
+        case CONTENT_SLIME:
+        case CONTENT_LAVA:
+        case CONTENT_SKY:
+            return 0;
+        case CONTENT_EMPTY:
+            if not (pointcontents(point - '0 0 1') == CONTENT_SOLID)
+                return 0;
+            break;
+        case CONTENT_WATER:
+            return 1;
+    }
+    if(pointcontents(point - '0 0 1') == CONTENT_SOLID)
+        return 1;
+
+    return 0;
+}
+
+float inwater(vector point)
+{
+    if(pointcontents(point) == CONTENT_WATER)
+        return 1;
+
+    return 0;
+}
+
+//#define _pcheck(p) traceline(p+z_up,p-z_down,MOVE_WORLDONLY,self); if(trace_fraction == 1.0) return 1
+#define _pcheck(p) traceline(p+z_up,p-z_down,MOVE_WORLDONLY,self); if not(floor_ok(trace_endpos)) return 1
+float edge_check(vector point,float fsize)
+{
+    vector z_up,z_down;
+
+    z_up   = '0 0 1' * fsize;
+    z_down = '0 0 1' * fsize;
+
+    _pcheck(point + ('1 1 0'  * fsize));
+    _pcheck(point + ('1 -1 0'  * fsize));
+    _pcheck(point + ('1 0 0' * fsize));
+
+    _pcheck(point + ('0 1 0'  * fsize));
+    _pcheck(point + ('0 -1 0' * fsize));
+
+    _pcheck(point + ('-1 0 0'  * fsize));
+    _pcheck(point + ('-1 1 0'  * fsize));
+    _pcheck(point + ('-1 -1 0' * fsize));
+
+    return 0;
+}
+
+/*
+#define _pshow(p) mark_error(p,10)
+float edge_show(vector point,float fsize)
+{
+
+    _pshow(point + ('1 1 0'  * fsize));
+    _pshow(point + ('1 -1 0' * fsize));
+    _pshow(point + ('1 0 0'  * fsize));
+
+    _pshow(point + ('0 1 0'  * fsize));
+    _pshow(point + ('0 -1 0' * fsize));
+
+    _pshow(point + ('-1 0 0'  * fsize));
+    _pshow(point + ('-1 1 0'  * fsize));
+    _pshow(point + ('-1 -1 0' * fsize));
+
+    return 0;
+}
+*/
+
+var vector pathlib_movenode(vector start,vector end,float doedge);
+vector pathlib_wateroutnode(vector start,vector end)
+{
+    vector surface;
+
+    pathlib_movenode_goodnode = 0;
+
+    end_x = fsnap(end_x, pathlib_gridsize);
+    end_y = fsnap(end_y, pathlib_gridsize);
+
+    traceline(end + ('0 0 0.25' * pathlib_gridsize),end - ('0 0 1' * pathlib_gridsize),MOVE_WORLDONLY,self);
+    end = trace_endpos;
+
+    if not(pointcontents(end - '0 0 1') == CONTENT_SOLID)
+        return end;
+
+    for(surface = start ; surface_z < (end_z + 32); ++surface_z)
+    {
+        if(pointcontents(surface) == CONTENT_EMPTY)
+            break;
+    }
+    //mark_error(surface,10);
+
+    if(pointcontents(surface + '0 0 1') != CONTENT_EMPTY)
+        return end;
+
+    tracebox(start + '0 0 64', walknode_boxmin,walknode_boxmax, end + '0 0 64', MOVE_WORLDONLY, self);
+    if(trace_fraction == 1)
+    {
+        pathlib_movenode_goodnode = 1;
+        //mark_error(end + '0 0 64',30);
+    }
+
+    if(fabs(surface_z - end_z) > 32)
+        pathlib_movenode_goodnode = 0;
+
+    return end;
+}
+
+vector pathlib_swimnode(vector start,vector end)
+{
+    pathlib_movenode_goodnode = 0;
+
+    if(pointcontents(start) != CONTENT_WATER)
+        return end;
+
+    end_x = fsnap(end_x, pathlib_gridsize);
+    end_y = fsnap(end_y, pathlib_gridsize);
+
+    if(pointcontents(end) == CONTENT_EMPTY)
+        return pathlib_wateroutnode( start, end);
+
+    tracebox(start, walknode_boxmin,walknode_boxmax, end, MOVE_WORLDONLY, self);
+    if(trace_fraction == 1)
+        pathlib_movenode_goodnode = 1;
+
+    return end;
+}
+
+vector pathlib_flynode(vector start,vector end)
+{
+    pathlib_movenode_goodnode = 0;
+
+    /*
+    if(pointcontents(start) == CONTENT_EMPTY)
+        return end;
+
+    if(pointcontents(end) == CONTENT_EMPTY)
+        return end;
+    */
+    end_x = fsnap(end_x, pathlib_gridsize);
+    end_y = fsnap(end_y, pathlib_gridsize);
+
+    tracebox(start, walknode_boxmin,walknode_boxmax, end, MOVE_WORLDONLY, self);
+    if(trace_fraction == 1)
+        pathlib_movenode_goodnode = 1;
+
+    return end;
+}
+
+vector pathlib_walknode(vector start,vector end,float doedge)
+{
+    vector direction,point,last_point,s,e;
+    float steps, distance, i,laststep;
+
+    pathlib_movenode_goodnode = 0;
+
+    s   = start;
+    e   = end;
+    e_z = 0;
+    s_z = 0;
+    direction  = normalize(s - e);
+
+    distance    = vlen(start - end);
+    laststep    = distance / walknode_stepsize;
+    steps       = floor(laststep);
+    laststep    = laststep - steps;
+
+    point = start;
+    s     = point + walknode_stepup;
+    e     = point - walknode_maxdrop;
+
+    traceline(s, e,MOVE_WORLDONLY,self);
+    if(trace_fraction == 1.0)
+        return trace_endpos;
+
+    if (floor_ok(trace_endpos) == 0)
+        return trace_endpos;
+
+    last_point = trace_endpos;
+
+    for(i = 0; i < steps; ++i)
+    {
+        point = last_point + direction * walknode_stepsize;
+
+        s = point + walknode_stepup;
+        e = point - walknode_maxdrop;
+        traceline(s, e,MOVE_WORLDONLY,self);
+        if(trace_fraction == 1.0)
+            return trace_endpos;
+
+        point = trace_endpos;
+        if not(floor_ok(trace_endpos))
+            return trace_endpos;
+
+        tracebox(last_point + walknode_boxup, walknode_boxmin,walknode_boxmax, point + walknode_boxup, MOVE_WORLDONLY, self);
+        if(trace_fraction != 1.0)
+            return trace_endpos;
+
+        if(doedge)
+        if(edge_check(point,pathlib_edge_check_size))
+            return trace_endpos;
+
+        last_point = point;
+    }
+
+    point = last_point + direction * walknode_stepsize * laststep;
+
+    point_x = fsnap(point_x, pathlib_gridsize);
+    point_y = fsnap(point_y, pathlib_gridsize);
+
+    s = point + walknode_stepup;
+    e = point - walknode_maxdrop;
+    traceline(s, e,MOVE_WORLDONLY,self);
+
+    if(trace_fraction == 1.0)
+        return trace_endpos;
+
+    point = trace_endpos;
+
+    if not(floor_ok(trace_endpos))
+        return trace_endpos;
+
+    tracebox(last_point + walknode_boxup, walknode_boxmin,walknode_boxmax, point + walknode_boxup, MOVE_WORLDONLY, self);
+    if(trace_fraction != 1.0)
+        return trace_endpos;
+
+    pathlib_movenode_goodnode = 1;
+    return point;
+}
+
+var float pathlib_cost(entity parent,vector to, float static_cost);
+float pathlib_g_static(entity parent,vector to, float static_cost)
+{
+    if(inwater(to))
+        return parent.pathlib_node_g + static_cost * pathlib_movecost_waterfactor;
+    else
+        return parent.pathlib_node_g + static_cost;
+}
+
+float pathlib_g_euclidean(entity parent,vector to, float static_cost)
+{
+    return vlen(parent.origin - to);
+}
+
+var float(vector from,vector to) pathlib_heuristic;
+float pathlib_h_manhattan(vector a,vector b)
+{
+    //h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
+
+    float h;
+    h = fabs(a_x - b_x);
+    h = h + fabs(a_y - b_y);
+    h = pathlib_gridsize * h;
+
+    return h;
+}
+
+float pathlib_h_diagonal(vector a,vector b)
+{
+    //h(n) = D * max(abs(n.x-goal.x), abs(n.y-goal.y))
+    float h,x,y;
+
+    x = fabs(a_x - b_x);
+    y = fabs(a_y - b_y);
+    h = pathlib_movecost * max(x,y);
+
+    return h;
+}
+
+float pathlib_h_euclidean(vector a,vector b)
+{
+    return vlen(a - b);
+}
+
+float pathlib_h_diagonal2(vector a,vector b)
+{
+    float h_diag,h_str,h,x,y;
+
+    /*
+    h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
+    h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
+    h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
+    */
+
+    x = fabs(a_x - b_x);
+    y = fabs(a_y - b_y);
+
+    h_diag = min(x,y);
+    h_str = x + y;
+
+    h =  pathlib_movecost_diag * h_diag;
+    h += pathlib_movecost * (h_str - 2 * h_diag);
+
+    return h;
+}
+
+float pathlib_h_diagonal2tbs(vector start,vector point,vector end)
+{
+    float h_diag,h_str,h,x,y;
+
+    /*
+    h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
+    h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
+    h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
+    */
+
+    float dx1,dx2,dy1,dy2,fcross;
+    dx1 = point_x - end_x;
+    dy1 = point_y - end_y;
+    dx2 = start_x - end_x;
+    dy2 = start_y - end_y;
+    fcross = fabs(dx1*dy2 - dx2*dy1);
+
+    x = fabs(point_x - end_x);
+    y = fabs(point_y - end_y);
+
+    h_diag = min(x,y);
+    h_str = x + y;
+
+    h =  pathlib_movecost_diag * h_diag;
+    h += pathlib_movecost * (h_str - 2 * h_diag);
+
+    return h + (fcross * 0.001);
+}
+
+float pathlib_h_diagonal2sdp(vector preprev,vector prev,vector point,vector end)
+{
+    float h_diag,h_str,h,x,y,z;
+
+    //h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
+    //h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
+    //h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
+
+    x = fabs(point_x - end_x);
+    y = fabs(point_y - end_y);
+    z = fabs(point_z - end_z);
+
+    h_diag = min3(x,y,z);
+    h_str = x + y + z;
+
+    h =  pathlib_movecost_diag * h_diag;
+    h += pathlib_movecost * (h_str - 2 * h_diag);
+
+    float m;
+    vector d1,d2;
+
+    m = 0.999;
+    d1 = normalize(preprev - prev);
+    d2 = normalize(prev - point);
+    if(vlen(d1-d2) > 0.6)
+        m = 1;
+
+
+    return h * m;
+}
+
+
+float pathlib_h_diagonal3(vector a,vector b)
+{
+    float h_diag,h_str,h,x,y,z;
+
+    //h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
+    //h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
+    //h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
+
+    x = fabs(a_x - b_x);
+    y = fabs(a_y - b_y);
+    z = fabs(a_z - b_z);
+
+    h_diag = min3(x,y,z);
+    h_str = x + y + z;
+
+    h =  pathlib_movecost_diag * h_diag;
+    h += pathlib_movecost * (h_str - 2 * h_diag);
+
+    //if(inwater(a))
+    //h =
+
+    return h;
+}
+
+//#define PATHLIB_USE_NODESCRAP
+float pathlib_scraplist_cnt;
+entity newnode()
+{
+    entity n;
+#ifdef PATHLIB_USE_NODESCRAP
+    if(pathlib_scraplist_cnt)
+    {
+        n = findentity(world,owner,scraplist);
+        if(n)
+        {
+            --pathlib_scraplist_cnt;
+            ++pathlib_recycle_cnt;
+            return n;
+        }
+        else
+            pathlib_scraplist_cnt = 0;
+    }
+#endif
+    ++pathlib_made_cnt;
+    n = spawn();
+    return n;
+}
+
+void dumpnode(entity n)
+{
+#ifdef PATHLIB_USE_NODESCRAP
+    ++pathlib_scraplist_cnt;
+    n.owner = scraplist;
+#else
+    remove(n);
+#endif
+}
+
+entity pathlib_mknode(vector where,entity parent)
+{
+    entity node;
+
+    node              = newnode();
+    node.is_path_node = TRUE;
+    node.owner        = openlist;
+    node.path_prev    = parent;
+
+    setorigin(node, where);
+
+    ++pathlib_open_cnt;
+
+    //if(inwater(where))
+    //{
+        //node.waterlevel = 1;
+        //mark_info(where,5);
+    //}
+    //mark_info(where,30);
+    return node;
+}
+var float pathlib_expandnode(entity node, vector start, vector goal);
+float pathlib_expandnode_star(entity node, vector start, vector goal);
+float pathlib_expandnode_box(entity node, vector start, vector goal);
+
+float pathlib_makenode(entity parent,vector start, vector to, vector goal,float cost)
+{
+    entity node;
+    float h,g,f,doedge;
+    vector where;
+
+    ++pathlib_searched_cnt;
+
+    if(inwater(parent.origin))
+    {
+        if(inwater(to))
+        {
+            //bprint("Switch to water tracing\n");
+            pathlib_expandnode = pathlib_expandnode_box;
+            pathlib_movenode   = pathlib_swimnode;
+        }
+        else
+        {
+
+            //bprint("Switch to get out of water tracing\n");
+            pathlib_expandnode = pathlib_expandnode_box;
+            pathlib_movenode   = pathlib_swimnode;
+        }
+    }
+    else
+    {
+        if(inwater(to))
+        {
+            //bprint("Switch to get into water tracing\n");
+            pathlib_expandnode = pathlib_expandnode_box;
+            pathlib_movenode   = pathlib_swimnode;
+        }
+        else
+        {
+
+            //bprint("Switch to land tracing\n");
+            pathlib_expandnode = pathlib_expandnode_star;
+            pathlib_movenode   = pathlib_walknode;
+            doedge = 1;
+        }
+    }
+
+    where = pathlib_movenode(parent.origin,to,0);
+    if not(pathlib_movenode_goodnode)
+    {
+        //mark_error(where,15);
+        return 0;
+    }
+
+    if(doedge)
+    if(edge_check(where,pathlib_edge_check_size))
+        return 0;
+
+    h = pathlib_heuristic(where,goal);
+
+    /*
+    if(parent.path_prev)
+        h = pathlib_h_diagonal2sdp(parent.path_prev.origin,parent.origin,where,goal);
+    else
+        h = pathlib_heuristic(where,goal);
+    */
+
+
+    //h = 0;
+    g = pathlib_cost(parent,where,cost);
+    f = g + h;
+
+    node = findradius(where,pathlib_gridsize * 0.75);
+    while(node)
+    {
+        if(node.is_path_node == TRUE)
+        {
+            ++pathlib_merge_cnt;
+            if(node.owner == openlist)
+            {
+                if(node.pathlib_node_g > g)
+                {
+                    node.pathlib_node_h = h;
+                    node.pathlib_node_g = g;
+                    node.pathlib_node_f = f;
+                    node.path_prev = parent;
+                }
+
+                if not (best_open_node)
+                    best_open_node = node;
+                else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
+                    best_open_node = node;
+            }
+
+            return 1;
+        }
+        node = node.chain;
+    }
+
+    node = pathlib_mknode(where,parent);
+
+    node.pathlib_node_h = h;
+    node.pathlib_node_g = g;
+    node.pathlib_node_f = f;
+
+    if not (best_open_node)
+        best_open_node = node;
+    else if(best_open_node.pathlib_node_f > node.pathlib_node_f)
+        best_open_node = node;
+
+    return 1;
+}
+
+entity pathlib_getbestopen()
+{
+    entity node;
+    entity bestnode;
+
+    if(best_open_node)
+    {
+        ++pathlib_bestcash_hits;
+        pathlib_bestcash_saved += pathlib_open_cnt;
+
+        return best_open_node;
+    }
+
+    node = findchainentity(owner,openlist);
+    if(!node)
+        return world;
+
+    bestnode = node;
+    while(node)
+    {
+        ++pathlib_bestopen_seached;
+        if(node.pathlib_node_f < bestnode.pathlib_node_f)
+            bestnode = node;
+
+        node = node.chain;
+    }
+
+    return bestnode;
+}
+
+void pathlib_close_node(entity node,vector goal)
+{
+
+    if(node.owner == closedlist)
+    {
+        dprint("Pathlib: Tried to close a closed node!\n");
+        return;
+    }
+
+    if(node == best_open_node)
+        best_open_node = world;
+
+    ++pathlib_closed_cnt;
+    --pathlib_open_cnt;
+
+    node.owner = closedlist;
+
+    if(vlen(node.origin - goal) <= pathlib_gridsize)
+    {
+        //if(vlen(node.origin - goal) < 128)
+        vector goalmove;
+        goalmove = pathlib_walknode(node.origin,goal,1);
+        if(pathlib_movenode_goodnode)
+            {
+                goal_node         = node;
+                pathlib_foundgoal = TRUE;
+            }
+    }
+}
+
+float pathlib_expandnode_star(entity node, vector start, vector goal)
+{
+    vector point;
+    vector where;
+    float nodecnt;
+
+    where = node.origin;
+
+    v_forward = '1 0 0';
+    v_right   = '0 1 0';
+
+    // Forward
+    point = where + v_forward * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
+
+    // Back
+    point = where - v_forward * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
+
+    // Right
+    point = where + v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
+
+    // Left
+    point = where - v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost);
+
+    // Forward-right
+    point = where + v_forward * pathlib_gridsize + v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
+
+    // Forward-left
+    point = where + v_forward * pathlib_gridsize - v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
+
+    // Back-right
+    point = where - v_forward * pathlib_gridsize + v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
+
+    // Back-left
+    point = where - v_forward * pathlib_gridsize - v_right * pathlib_gridsize;
+    nodecnt += pathlib_makenode(node,start,point,goal,pathlib_movecost_diag);
+
+    return pathlib_open_cnt;
+}
+
+float pathlib_expandnode_box(entity node, vector start, vector goal)
+{
+    vector v;
+
+    for(v_z = node.origin_z - pathlib_gridsize; v_z <= node.origin_z + pathlib_gridsize; v_z += pathlib_gridsize)
+    for(v_y = node.origin_y - pathlib_gridsize; v_y <= node.origin_y + pathlib_gridsize; v_y += pathlib_gridsize)
+    for(v_x = node.origin_x - pathlib_gridsize; v_x <= node.origin_x + pathlib_gridsize; v_x += pathlib_gridsize)
+    {
+        if(vlen(v - node.origin))
+            pathlib_makenode(node,start,v,goal,pathlib_movecost);
+    }
+
+    return pathlib_open_cnt;
+}
+
+void pathlib_cleanup()
+{
+    entity node;
+
+    if(best_open_node != world)
+        remove(best_open_node);
+
+    best_open_node = world;
+
+    node = findfloat(world,is_path_node, TRUE);
+    while(node)
+    {
+        node.path_next = world;
+        node.path_prev = world;
+        node.is_path_node = FALSE;
+        dumpnode(node);
+        //remove(node);
+        node = findfloat(world,is_path_node, TRUE);
+    }
+
+    if(openlist)
+        remove(openlist);
+
+    if(closedlist)
+        remove(closedlist);
+}
+
+entity pathlib_astar(vector from,vector to)
+{
+    entity path;
+    entity open,n;
+
+    pathlib_cleanup();
+
+    pathlib_heuristic  = pathlib_h_diagonal3;
+    pathlib_cost       = pathlib_g_static;
+    pathlib_expandnode = pathlib_expandnode_star;
+    pathlib_movenode   = pathlib_walknode;
+
+    if not(openlist)
+        openlist       = spawn();
+
+    if not(closedlist)
+        closedlist     = spawn();
+
+    if not(scraplist)
+        scraplist      = spawn();
+
+    pathlib_closed_cnt     = 0;
+    pathlib_open_cnt       = 0;
+    pathlib_made_cnt       = 0;
+    pathlib_merge_cnt      = 0;
+    pathlib_searched_cnt   = 0;
+    pathlib_bestcash_hits  = 0;
+    pathlib_bestcash_saved = 0;
+    pathlib_recycle_cnt    = 0;
+
+    pathlib_gridsize       = 192;
+    pathlib_movecost       = pathlib_gridsize;
+    pathlib_movecost_diag  = vlen(('1 1 0' * pathlib_gridsize));
+    pathlib_movecost_waterfactor = 1.1;
+    pathlib_foundgoal      = 0;
+
+    walknode_boxmax   = self.maxs * 1.5;
+    walknode_boxmin   = self.mins * 1.5;
+
+    pathlib_edge_check_size = (vlen(walknode_boxmin - walknode_boxmax) * 0.25);
+
+    walknode_boxup    = '0 0 2' * self.maxs_z;
+    walknode_stepsize = 32;
+    walknode_stepup   = '0 0 1' * walknode_stepsize;
+    walknode_maxdrop  = '0 0 3' * walknode_stepsize;
+
+    dprint("AStar init. ", ftos(pathlib_scraplist_cnt), " nodes on scrap\n");
+    path = pathlib_mknode(from,world);
+    pathlib_close_node(path,to);
+    if(pathlib_foundgoal)
+    {
+        dprint("A* Goal fond in first square!\n");
+
+        open           = spawn();
+        open.owner     = open;
+        open.classname = "path_end";
+        setorigin(open,path.origin);
+        pathlib_cleanup();
+
+        return open;
+    }
+
+    if(pathlib_expandnode(path,from,to) <= 0)
+    {
+        dprint("A* pathing fail\n");
+        pathlib_cleanup();
+        return world;
+    }
+
+    best_open_node = pathlib_getbestopen();
+    n = best_open_node;
+    pathlib_close_node(best_open_node,to);
+    if(inwater(n.origin))
+        pathlib_expandnode_box(n,from,to);
+    else
+        pathlib_expandnode_star(n,from,to);
+
+    //pathlib_expandnode(n,from,to);
+
+    while(pathlib_open_cnt)
+    {
+        best_open_node = pathlib_getbestopen();
+        n = best_open_node;
+        pathlib_close_node(best_open_node,to);
+
+        if(inwater(n.origin))
+            pathlib_expandnode_box(n,from,to);
+        else
+            pathlib_expandnode(n,from,to);
+
+        if(pathlib_foundgoal)
+        {
+            dprint("Path found, re-tracing...\n");
+
+            open              = goal_node;
+            open.is_path_node = FALSE;
+            open.classname    = "path_end";
+            open.owner        = path;
+            open.path_next    = world;
+
+
+            while(open.path_prev != path)
+            {
+                n                 = open;
+                open              = open.path_prev;
+                open.owner        = path;
+                open.path_next    = n;
+
+                open.is_path_node = FALSE;
+                open.classname    = "path_node";
+            }
+
+            open.path_prev    = path;
+            path.path_next    = open;
+            path.classname    = "path_master";
+            path.is_path_node = FALSE;
+            path.owner        = path;
+
+            pathlib_cleanup();
+
+#ifdef DEBUGPATHING
+            bprint("Chain done..\n");
+            pathlib_showpath2(path);
+
+
+            bprint("           Nodes reused: ", ftos(pathlib_recycle_cnt),"\n");
+            bprint("          Nodes created: ", ftos(pathlib_made_cnt),"\n");
+            bprint("       Nodes make/reuse: ", ftos(pathlib_made_cnt / pathlib_recycle_cnt),"\n");
+            bprint("             Nodes open: ", ftos(pathlib_open_cnt),"\n");
+            bprint("           Nodes merged: ", ftos(pathlib_merge_cnt),"\n");
+            bprint("           Nodes closed: ", ftos(pathlib_closed_cnt),"\n");
+            bprint("         Nodes searched: ", ftos(pathlib_searched_cnt),"\n");
+            bprint("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
+            bprint("    Nodes bestcash hits: ", ftos(pathlib_bestcash_hits),"\n");
+            bprint("    Nodes bestcash save: ", ftos(pathlib_bestcash_saved),"\n");
+            bprint("AStar done. ", ftos(pathlib_scraplist_cnt), " nodes on scrap\n\n");
+
+#endif
+            return path;
+        }
+    }
+
+    dprint("A* Faild to find a path! Try a smaller gridsize.\n");
+
+    pathlib_cleanup();
+
+    return world;
+}
+

Added: trunk/data/qcsrc/server/verbstack.qc
===================================================================
--- trunk/data/qcsrc/server/verbstack.qc	                        (rev 0)
+++ trunk/data/qcsrc/server/verbstack.qc	2009-03-22 14:09:56 UTC (rev 6245)
@@ -0,0 +1,111 @@
+entity verb;
+.entity verbs_idle;
+.entity verbs_attack;
+.entity verbs_move;
+
+.float(float eval) verb_call;
+.entity  verbstack;
+.float verb_static_value;
+
+#define VS_CALL_NO        0
+#define VS_CALL_YES_DOING -1
+#define VS_CALL_YES_DONE  -2
+#define VS_CALL_REMOVE    -3
+
+entity verbstack_push(entity stack, float(float eval) vrb_call, float val_static, float vrb_life)
+{
+    entity vrb;
+
+    vrb                   = spawn();
+    vrb.owner             = self;
+    vrb.verbstack         = stack;
+    vrb.verb_call         = vrb_call;
+    vrb.verb_static_value = val_static;
+
+    if(vrb_life)
+    {
+        vrb.think     = SUB_Remove;
+        vrb.nextthink = time + vrb_life;
+    }
+
+    return vrb;
+}
+
+float verbstack_pop(entity stack)
+{
+    entity vrb;
+    entity bestverb,oldself;
+    float value,bestvalue;
+
+    oldself = self;
+
+    vrb = findchainentity(verbstack,stack);
+    while(vrb)
+    {
+        verb = vrb;
+        self = vrb.owner;
+        value = vrb.verb_call(TRUE);
+        if(value < 0)
+        {
+            if(value == VS_CALL_REMOVE)
+                remove(vrb);
+        }
+        else
+        {
+            if(value > bestvalue)
+            {
+                bestverb = vrb;
+                bestvalue = value;
+            }
+        }
+        vrb = vrb.chain;
+    }
+
+    if(bestverb)
+    {
+        verb = bestverb;
+        self = verb.owner;
+        value = bestverb.verb_call(FALSE);
+            if(value == VS_CALL_REMOVE)
+                remove(bestverb);
+    }
+
+    self = oldself;
+
+    return value;
+}
+
+entity verbstack_pull(entity stack)
+{
+    entity vrb;
+    entity bestverb,oldself;
+    float value,bestvalue;
+
+    oldself = self;
+
+    vrb = findchainentity(verbstack,stack);
+    while(vrb)
+    {
+        self = vrb.owner;
+        verb = vrb;
+        value = vrb.verb_call(TRUE);
+        if(value > 0)
+        {
+            if(value == VS_CALL_REMOVE)
+                remove(vrb);
+        }
+        else
+        {
+            if(value > bestvalue)
+            {
+                bestverb = vrb;
+                bestvalue = value;
+            }
+        }
+        vrb =vrb.chain;
+    }
+
+    self = oldself;
+
+    return bestverb;
+}



More information about the nexuiz-commits mailing list