+++ /dev/null
-#include "../server/movelib.qc"
+++ /dev/null
-#include "../server/movelib.qh"
#include "mapvoting.qc"
#include "miscfunctions.qc"
#include "modeleffects.qc"
-#include "movelib.qc"
#include "particles.qc"
#include "player_skeleton.qc"
#include "rubble.qc"
#include "../common/minigames/minigames.qc"
#include "../common/minigames/cl_minigames.qc"
+#include "../server/bot/lib/all.inc"
+
#include "../common/buffs/all.qc"
#include "../common/items/all.qc"
#include "../common/monsters/all.qc"
#ifdef IMPLEMENTATION
#ifdef SVQC
+#include "../../../server/bot/lib/movelib/movelib.qh"
float autocvar_g_monster_zombie_health;
float autocvar_g_monster_zombie_damageforcescale = 0.55;
float autocvar_g_monster_zombie_attack_melee_damage;
#include "../../server/defs.qh"
#include "../deathtypes.qh"
#include "../../server/mutators/mutators_include.qh"
- #include "../../server/steerlib.qh"
#include "../turrets/sv_turrets.qh"
#include "../turrets/util.qh"
#include "../vehicles/all.qh"
#endif // SVQC
#ifdef CSQC
-#include "../../../client/movelib.qh"
+#include "../../../server/bot/lib/movelib/movelib.qh"
void walker_draw(entity this)
{
#undef particleeffectnum
#undef setmodel
+entity(.entity fld, entity match) findchainentity = #403;
+
#pragma noref 0
#define ReadFloat() ReadCoord()
#include "navigation.qh"
-#include "../common/triggers/trigger/jumppads.qh"
+#include "../../../common/triggers/trigger/jumppads.qh"
void bot_debug(string input)
{
#include "api.qh"
+#include "lib/all.inc"
+
#include "default/all.inc"
--- /dev/null
+#ifndef BOT_LIB_ALL_H
+#define BOT_LIB_ALL_H
+
+#include "movelib/all.inc"
+#ifdef SVQC
+#include "pathlib/all.inc"
+#endif
+#include "steerlib/all.inc"
+
+#endif
--- /dev/null
+#include "movelib.qc"
--- /dev/null
+#include "movelib.qh"
+
+#ifdef SVQC
+.vector moveto;
+
+/**
+ Simulate drag
+ self.velocity = movelib_dragvec(self.velocity,0.02,0.5);
+**/
+vector movelib_dragvec(float drag, float exp_)
+{SELFPARAM();
+ float lspeed,ldrag;
+
+ lspeed = vlen(self.velocity);
+ ldrag = lspeed * drag;
+ ldrag = ldrag * (drag * exp_);
+ ldrag = 1 - (ldrag / lspeed);
+
+ return self.velocity * ldrag;
+}
+
+/**
+ Simulate drag
+ self.velocity *= movelib_dragflt(somespeed,0.01,0.7);
+**/
+float movelib_dragflt(float fspeed,float drag,float exp_)
+{
+ float ldrag;
+
+ ldrag = fspeed * drag;
+ ldrag = ldrag * ldrag * exp_;
+ ldrag = 1 - (ldrag / fspeed);
+
+ return ldrag;
+}
+
+/**
+ Do a inertia simulation based on velocity.
+ Basicaly, this allows you to simulate loss of steering with higher speed.
+ self.velocity = movelib_inertmove_byspeed(self.velocity,newvel,1000,0.1,0.9);
+**/
+vector movelib_inertmove_byspeed(vector vel_new, float vel_max,float newmin,float oldmax)
+{SELFPARAM();
+ float influense;
+
+ influense = vlen(self.velocity) * (1 / vel_max);
+
+ influense = bound(newmin,influense,oldmax);
+
+ return (vel_new * (1 - influense)) + (self.velocity * influense);
+}
+
+vector movelib_inertmove(vector new_vel,float new_bias)
+{SELFPARAM();
+ return new_vel * new_bias + self.velocity * (1-new_bias);
+}
+
+void movelib_move(vector force,float max_velocity,float drag,float theMass,float breakforce)
+{SELFPARAM();
+ float deltatime;
+ float acceleration;
+ 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);
+
+ if (theMass)
+ acceleration = vlen(force) / theMass;
+ else
+ acceleration = vlen(force);
+
+ if (self.flags & FL_ONGROUND)
+ {
+ if (breakforce)
+ {
+ breakvec = (normalize(self.velocity) * (breakforce / theMass) * deltatime);
+ self.velocity = self.velocity - breakvec;
+ }
+
+ self.velocity = self.velocity + force * (acceleration * 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' * autocvar_sv_gravity * deltatime;
+ }
+ else
+ self.velocity = self.velocity + '0 0 -1' * autocvar_sv_gravity * deltatime;
+
+ mspeed = vlen(self.velocity);
+
+ if (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_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 = (autocvar_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;
+
+}
+*/
+
+void movelib_beak_simple(float force)
+{SELFPARAM();
+ float mspeed;
+ vector mdir;
+ float vz;
+
+ mspeed = max(0,vlen(self.velocity) - force);
+ mdir = normalize(self.velocity);
+ vz = self.velocity.z;
+ self.velocity = mdir * mspeed;
+ self.velocity_z = vz;
+}
+
+/**
+Pitches and rolls the entity to match the gound.
+Yed need to set v_up and v_forward (generally by calling makevectors) before calling this.
+**/
+#endif
+
+void movelib_groundalign4point(float spring_length, float spring_up, float blendrate, float _max)
+{SELFPARAM();
+ vector a, b, c, d, e, r, push_angle, ahead, side;
+
+ push_angle.y = 0;
+ r = (self.absmax + self.absmin) * 0.5 + (v_up * spring_up);
+ e = v_up * spring_length;
+
+ // Put springs slightly inside bbox
+ ahead = v_forward * (self.maxs.x * 0.8);
+ side = v_right * (self.maxs.y * 0.8);
+
+ a = r + ahead + side;
+ b = r + ahead - side;
+ c = r - ahead + side;
+ d = r - ahead - side;
+
+ 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) * _max;
+ push_angle.x += (b.z - d.z) * _max;
+
+ push_angle.z = (b.z - a.z) * _max;
+ push_angle.z += (d.z - c.z) * _max;
+
+ //self.angles_x += push_angle_x * 0.95;
+ //self.angles_z += push_angle_z * 0.95;
+
+ self.angles_x = ((1-blendrate) * self.angles.x) + (push_angle.x * blendrate);
+ self.angles_z = ((1-blendrate) * self.angles.z) + (push_angle.z * blendrate);
+
+ //a = self.origin;
+ setorigin(self,r);
+}
+
--- /dev/null
+#ifndef MOVELIB_H
+#define MOVELIB_H
+
+#ifdef SVQC
+.vector moveto;
+
+/**
+ Simulate drag
+ self.velocity = movelib_dragvec(self.velocity,0.02,0.5);
+**/
+vector movelib_dragvec(float drag, float exp_);
+
+/**
+ Simulate drag
+ self.velocity *= movelib_dragflt(somespeed,0.01,0.7);
+**/
+float movelib_dragflt(float fspeed,float drag,float exp_);
+
+/**
+ Do a inertia simulation based on velocity.
+ Basicaly, this allows you to simulate loss of steering with higher speed.
+ self.velocity = movelib_inertmove_byspeed(self.velocity,newvel,1000,0.1,0.9);
+**/
+vector movelib_inertmove_byspeed(vector vel_new, float vel_max,float newmin,float oldmax);
+
+vector movelib_inertmove(vector new_vel,float new_bias);
+
+.float movelib_lastupdate;
+void movelib_move(vector force,float max_velocity,float drag,float theMass,float breakforce);
+
+/*
+void movelib_move_simple(vector newdir,float velo,float blendrate)
+{
+ self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo;
+}
+*/
+#define movelib_move_simple(newdir,velo,blendrate) \
+ self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo
+
+#define movelib_move_simple_gravity(newdir,velo,blendrate) \
+ if(self.flags & FL_ONGROUND) movelib_move_simple(newdir,velo,blendrate)
+
+void movelib_beak_simple(float force);
+
+/**
+Pitches and rolls the entity to match the gound.
+Yed need to set v_up and v_forward (generally by calling makevectors) before calling this.
+**/
+#endif
+
+void movelib_groundalign4point(float spring_length, float spring_up, float blendrate, float _max);
+
+#endif
--- /dev/null
+#include "costs.qc"
+#include "expandnode.qc"
+#include "main.qc"
+#include "movenode.qc"
+#include "path_waypoint.qc"
+#include "utility.qc"
--- /dev/null
+#include "pathlib.qh"
+
+float pathlib_g_static(entity parent,vector to, float static_cost)
+{
+ return parent.pathlib_node_g + static_cost;
+}
+
+float pathlib_g_static_water(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 parent.pathlib_node_g + vlen(parent.origin - to);
+}
+
+float pathlib_g_euclidean_water(entity parent,vector to, float static_cost)
+{
+ if(inwater(to))
+ return parent.pathlib_node_g + vlen(parent.origin - to) * pathlib_movecost_waterfactor;
+ else
+ return parent.pathlib_node_g + vlen(parent.origin - to);
+}
+
+
+/**
+ Manhattan Menas we expect to move up,down left or right
+ No diagonal moves espected. (like moving bewteen city blocks)
+**/
+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 += fabs(a.y - b.y);
+ h *= pathlib_gridsize;
+
+ return h;
+}
+
+/**
+ This heuristic consider both stright and disagonal moves
+ to have teh same cost.
+**/
+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;
+}
+
+/**
+ This heuristic only considers the stright line distance.
+ Will usualy mean a lower H then G meaning A* Will speand more
+ and run slower.
+**/
+float pathlib_h_euclidean(vector a,vector b)
+{
+ return vlen(a - b);
+}
+
+/**
+ This heuristic consider both stright and disagonal moves,
+ But has a separate cost for diagonal moves.
+**/
+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;
+}
+
+/**
+ This heuristic consider both stright and disagonal moves,
+ But has a separate cost for diagonal moves.
+**/
+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 = min(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;
+
+ d1 = normalize(preprev - point);
+ d2 = normalize(prev - point);
+ m = vlen(d1-d2);
+
+ return h * m;
+}
+
+
+float pathlib_h_diagonal3(vector a,vector b)
+{
+ float h_diag,h_str,h,x,y,z;
+
+ x = fabs(a.x - b.x);
+ y = fabs(a.y - b.y);
+ z = fabs(a.z - b.z);
+
+ h_diag = min(x,y,z);
+ h_str = x + y + z;
+
+ h = pathlib_movecost_diag * h_diag;
+ h += pathlib_movecost * (h_str - 2 * h_diag);
+
+ return h;
+}
--- /dev/null
+#include "pathlib.qh"
+
+MODEL(SQUARE, "models/pathlib/square.md3");
+MODEL(SQUARE_GOOD, "models/pathlib/goodsquare.md3");
+MODEL(SQUARE_BAD, "models/pathlib/badsquare.md3");
+MODEL(EDGE, "models/pathlib/edge.md3");
+
+#ifdef TURRET_DEBUG
+void mark_error(vector where,float lifetime);
+void mark_info(vector where,float lifetime);
+entity mark_misc(vector where,float lifetime);
+#endif
+
+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()
+{SELFPARAM();
+ pathlib_showpath(self);
+ self.nextthink = time + 1;
+}
+
+void __showpath2_think()
+{SELFPARAM();
+ #ifdef TURRET_DEBUG
+ mark_info(self.origin,1);
+ #endif
+ 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;
+}
+
+
+void pathlib_showsquare2(entity node ,vector ncolor,float align)
+{
+
+ node.alpha = 0.25;
+ node.scale = pathlib_gridsize / 512.001;
+ node.solid = SOLID_NOT;
+
+ setmodel(node, MDL_SQUARE);
+ setorigin(node,node.origin);
+ node.colormod = ncolor;
+
+ if(align)
+ {
+ traceline(node.origin + '0 0 32', node.origin - '0 0 128', MOVE_WORLDONLY, node);
+ node.angles = vectoangles(trace_plane_normal);
+ node.angles_x -= 90;
+ }
+}
+
+void SUB_Remove();
+
+void pathlib_showsquare(vector where,float goodsquare,float _lifetime)
+{
+ entity s;
+
+ if(!_lifetime)
+ _lifetime = time + 30;
+ else
+ _lifetime += time;
+
+ s = spawn();
+ s.alpha = 0.25;
+ s.think = SUB_Remove;
+ s.nextthink = _lifetime;
+ s.scale = pathlib_gridsize / 512.001;
+ s.solid = SOLID_NOT;
+
+ setmodel(s, goodsquare ? MDL_SQUARE_GOOD : MDL_SQUARE_BAD);
+
+ traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,s);
+
+ s.angles = vectoangles(trace_plane_normal);
+ s.angles_x -= 90;
+ setorigin(s,where);
+}
+
+void pathlib_showedge(vector where,float _lifetime,float rot)
+{
+ entity e;
+
+ if(!_lifetime)
+ _lifetime = time + 30;
+ else
+ _lifetime += time;
+
+ e = spawn();
+ e.alpha = 0.25;
+ e.think = SUB_Remove;
+ e.nextthink = _lifetime;
+ e.scale = pathlib_gridsize / 512;
+ e.solid = SOLID_NOT;
+ setorigin(e,where);
+ setmodel(e, MDL_EDGE);
+ //traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,e);
+ //e.angles = vectoangles(trace_plane_normal);
+ e.angles_y = rot;
+ //e.angles_x += 90;
+
+}
--- /dev/null
+#include "pathlib.qh"
+#include "utility.qh"
+
+vector plib_points2[8];
+vector plib_points[8];
+float plib_fvals[8];
+
+float pathlib_expandnode_starf(entity node, vector start, vector goal)
+{
+ vector where,f,r,t;
+ float fc,c;
+ entity nap;
+
+ where = node.origin;
+
+ f = PLIB_FORWARD * pathlib_gridsize;
+ r = PLIB_RIGHT * pathlib_gridsize;
+
+ // Forward
+ plib_points[0] = where + f;
+
+ // Back
+ plib_points[1] = where - f;
+
+ // Right
+ plib_points[2] = where + r;
+
+ // Left
+ plib_points[3] = where - r;
+
+ // Forward-right
+ plib_points[4] = where + f + r;
+
+ // Forward-left
+ plib_points[5] = where + f - r;
+
+ // Back-right
+ plib_points[6] = where - f + r;
+
+ // Back-left
+ plib_points[7] = where - f - r;
+
+ for(int i=0;i < 8; ++i)
+ {
+ t = plib_points[i];
+ fc = pathlib_heuristic(t,goal) + pathlib_cost(node, t, pathlib_gridsize);
+ plib_fvals[i] = fc;
+
+ }
+
+ fc = plib_fvals[0];
+ plib_points2[0] = plib_points[0];
+ vector bp;
+ bp = plib_points[0];
+ int fc2 = 0;
+ for(int i = 0; i < 8; ++i)
+ {
+ c = 0;
+ nap = pathlib_nodeatpoint(plib_points[i]);
+ if(nap)
+ if(nap.owner == openlist)
+ c = 1;
+ else
+ c = 1;
+
+ if(c)
+ if(plib_fvals[i] < fc)
+ {
+ bp = plib_points[i];
+ fc = plib_fvals[i];
+ plib_points2[fc2] = plib_points[i];
+ ++fc2;
+ }
+
+ /*
+ nap = pathlib_nodeatpoint(plib_points[i]);
+ if(nap)
+ if not nap.owner == closedlist)
+ {
+ }
+ */
+ }
+
+ pathlib_makenode(node, start, bp, goal, pathlib_gridsize);
+
+ for(int i = 0; i < 3; ++i)
+ {
+ pathlib_makenode(node, start, plib_points2[i], goal, pathlib_gridsize);
+ }
+
+ return pathlib_open_cnt;
+}
+
+float pathlib_expandnode_star(entity node, vector start, vector goal)
+{
+ vector point, where, f, r;
+
+ where = node.origin;
+
+ f = PLIB_FORWARD * pathlib_gridsize;
+ r = PLIB_RIGHT * pathlib_gridsize;
+
+ if (node.pathlib_node_edgeflags == pathlib_node_edgeflag_unknown)
+ node.pathlib_node_edgeflags = tile_check_plus2(node.origin);
+
+ if(node.pathlib_node_edgeflags == pathlib_node_edgeflag_none)
+ {
+ LOG_TRACE("Node at ", vtos(node.origin), " not expanable");
+ return pathlib_open_cnt;
+ }
+
+ // Forward
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forward)
+ {
+ point = where + f;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+ }
+
+ // Back
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_back)
+ {
+ point = where - f;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+ }
+
+ // Right
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_right)
+ {
+ point = where + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+ }
+
+ // Left
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_left)
+ {
+ point = where - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ }
+
+ // Forward-right
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forwardright)
+ {
+ point = where + f + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
+ }
+
+ // Forward-left
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forwardleft)
+ {
+ point = where + f - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
+
+ }
+
+ // Back-right
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_backright)
+ {
+ point = where - f + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
+ }
+
+ // Back-left
+ if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_backleft)
+ {
+ point = where - f - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
+ }
+
+ return pathlib_open_cnt;
+}
+
+float pathlib_expandnode_octagon(entity node, vector start, vector goal)
+{
+ vector point,where,f,r;
+
+ where = node.origin;
+
+ f = PLIB_FORWARD * pathlib_gridsize;
+ r = PLIB_RIGHT * pathlib_gridsize;
+
+ // Forward
+ point = where + f;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ // Back
+ point = where - f;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ // Right
+ point = where + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ // Left
+ point = where - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ f = PLIB_FORWARD * pathlib_gridsize * 0.5;
+ r = PLIB_RIGHT * pathlib_gridsize * 0.5;
+
+ // Forward-right
+ point = where + f + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+
+ // Forward-left
+ point = where + f - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+
+ // Back-right
+ point = where - f + r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ // Back-left
+ point = where - f - r;
+ pathlib_makenode(node, start, point, goal, pathlib_movecost);
+
+ 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;
+}
--- /dev/null
+#include "pathlib.qh"
+#include "utility.qh"
+
+void pathlib_deletepath(entity start)
+{
+ entity e;
+
+ e = findchainentity(owner, start);
+ while(e)
+ {
+ e.think = SUB_Remove;
+ e.nextthink = time;
+ e = e.chain;
+ }
+}
+
+//#define PATHLIB_NODEEXPIRE 0.05
+const float PATHLIB_NODEEXPIRE = 20;
+
+void dumpnode(entity n)
+{
+ n.is_path_node = false;
+ n.think = SUB_Remove;
+ n.nextthink = time;
+}
+
+entity pathlib_mknode(vector where,entity parent)
+{
+ entity node;
+
+ node = pathlib_nodeatpoint(where);
+ if(node)
+ {
+ #ifdef TURRET_DEBUG
+ mark_error(where, 60);
+ #endif
+ return node;
+ }
+
+ node = spawn();
+
+ node.think = SUB_Remove;
+ node.nextthink = time + PATHLIB_NODEEXPIRE;
+ node.is_path_node = true;
+ node.owner = openlist;
+ node.path_prev = parent;
+
+
+ setsize(node, '0 0 0', '0 0 0');
+
+ setorigin(node, where);
+ node.medium = pointcontents(where);
+ pathlib_showsquare(where, 1 ,15);
+
+ ++pathlib_made_cnt;
+ ++pathlib_open_cnt;
+
+ return node;
+}
+
+float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
+{
+ entity node;
+ float h,g,f,doedge = 0;
+ vector where;
+
+ ++pathlib_searched_cnt;
+
+ if(inwater(parent.origin))
+ {
+ LOG_TRACE("FromWater\n");
+ pathlib_expandnode = pathlib_expandnode_box;
+ pathlib_movenode = pathlib_swimnode;
+ }
+ else
+ {
+ if(inwater(to))
+ {
+ LOG_TRACE("ToWater\n");
+ pathlib_expandnode = pathlib_expandnode_box;
+ pathlib_movenode = pathlib_walknode;
+ }
+ else
+ {
+ LOG_TRACE("LandToLoand\n");
+ //if(edge_check(parent.origin))
+ // return 0;
+
+ pathlib_expandnode = pathlib_expandnode_star;
+ pathlib_movenode = pathlib_walknode;
+ doedge = 1;
+ }
+ }
+
+ node = pathlib_nodeatpoint(to);
+ if(node)
+ {
+ LOG_TRACE("NodeAtPoint\n");
+ ++pathlib_merge_cnt;
+
+ if(node.owner == openlist)
+ {
+ h = pathlib_heuristic(node.origin,goal);
+ g = pathlib_cost(parent,node.origin,cost);
+ f = g + h;
+
+ 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 (!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;
+ }
+
+ where = pathlib_movenode(parent.origin, to, 0);
+
+ if (!pathlib_movenode_goodnode)
+ {
+ //pathlib_showsquare(where, 0 ,30);
+ //pathlib_showsquare(parent.origin, 1 ,30);
+ LOG_TRACE("pathlib_movenode_goodnode = 0\n");
+ return 0;
+ }
+
+ //pathlib_showsquare(where, 1 ,30);
+
+ if(pathlib_nodeatpoint(where))
+ {
+ LOG_TRACE("NAP WHERE :",vtos(where),"\n");
+ LOG_TRACE("not NAP TO:",vtos(to),"\n");
+ LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)),"\n\n");
+ return 0;
+ }
+
+
+ if(doedge)
+ if (!tile_check(where))
+ {
+ LOG_TRACE("tile_check fail\n");
+ pathlib_showsquare(where, 0 ,30);
+ return 0;
+ }
+
+
+ h = pathlib_heuristic(where,goal);
+ g = pathlib_cost(parent,where,cost);
+ f = g + h;
+
+ /*
+ node = findradius(where,pathlib_gridsize * 0.5);
+ while(node)
+ {
+ if(node.is_path_node == true)
+ {
+ ++pathlib_merge_cnt;
+ if(node.owner == openlist)
+ {
+ if(node.pathlib_node_g > g)
+ {
+ //pathlib_movenode(where,node.origin,0);
+ //if(pathlib_movenode_goodnode)
+ //{
+ //mark_error(node.origin + '0 0 128',30);
+ node.pathlib_node_h = h;
+ node.pathlib_node_g = g;
+ node.pathlib_node_f = f;
+ node.path_prev = parent;
+ //}
+ }
+
+ if (!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 (!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)
+ {
+ LOG_TRACE("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)
+ {
+ vector goalmove;
+
+ goalmove = pathlib_walknode(node.origin,goal,1);
+ if(pathlib_movenode_goodnode)
+ {
+ goal_node = node;
+ pathlib_foundgoal = true;
+ }
+ }
+}
+
+void pathlib_cleanup()
+{
+ best_open_node = world;
+
+ //return;
+
+ entity node;
+
+ node = findfloat(world,is_path_node, true);
+ while(node)
+ {
+ /*
+ node.owner = openlist;
+ node.pathlib_node_g = 0;
+ node.pathlib_node_h = 0;
+ node.pathlib_node_f = 0;
+ node.path_prev = world;
+ */
+
+ dumpnode(node);
+ node = findfloat(node,is_path_node, true);
+ }
+
+ if(openlist)
+ remove(openlist);
+
+ if(closedlist)
+ remove(closedlist);
+
+ openlist = world;
+ closedlist = world;
+
+}
+
+float Cosine_Interpolate(float a, float b, float x)
+{
+ float ft,f;
+
+ ft = x * 3.1415927;
+ f = (1 - cos(ft)) * 0.5;
+
+ return a*(1-f) + b*f;
+}
+
+float buildpath_nodefilter_directional(vector n,vector c,vector p)
+{
+ vector d1,d2;
+
+ d2 = normalize(p - c);
+ d1 = normalize(c - n);
+
+ if(vlen(d1-d2) < 0.25)
+ {
+ //mark_error(c,30);
+ return 1;
+ }
+ //mark_info(c,30);
+ return 0;
+}
+
+float buildpath_nodefilter_moveskip(vector n,vector c,vector p)
+{
+ pathlib_walknode(p,n,1);
+ if(pathlib_movenode_goodnode)
+ return 1;
+
+ return 0;
+}
+
+float buildpath_nodefilter_none(vector n,vector c,vector p)
+{
+ return 0;
+}
+
+entity path_build(entity next, vector where, entity prev, entity start)
+{
+ entity path;
+
+ if(prev && next)
+ if(buildpath_nodefilter)
+ if(buildpath_nodefilter(next.origin,where,prev.origin))
+ return next;
+
+
+ path = spawn();
+ path.owner = start;
+ path.path_next = next;
+
+ setorigin(path,where);
+
+ if(!next)
+ path.classname = "path_end";
+ else
+ {
+ if(!prev)
+ path.classname = "path_start";
+ else
+ path.classname = "path_node";
+ }
+
+ return path;
+}
+
+entity pathlib_astar(vector from,vector to)
+{SELFPARAM();
+ entity path, start, end, open, n, ln;
+ float ptime, ftime, ctime;
+
+ ptime = gettime(GETTIME_REALTIME);
+ pathlib_starttime = ptime;
+
+ pathlib_cleanup();
+
+ // Select water<->land capable node make/link
+ pathlib_makenode = pathlib_makenode_adaptive;
+
+ // Select XYZ cost estimate
+ //pathlib_heuristic = pathlib_h_diagonal3;
+ pathlib_heuristic = pathlib_h_diagonal;
+
+ // Select distance + waterfactor cost
+ pathlib_cost = pathlib_g_euclidean_water;
+
+ // Select star expander
+ pathlib_expandnode = pathlib_expandnode_star;
+
+ // Select walk simulation movement test
+ pathlib_movenode = pathlib_walknode;
+
+ // Filter final nodes by direction
+ buildpath_nodefilter = buildpath_nodefilter_directional;
+
+ // Filter tiles with cross pattern
+ tile_check = tile_check_cross;
+
+ // If the start is in water we need diffrent settings
+ if(inwater(from))
+ {
+ // Select volumetric node expaner
+ pathlib_expandnode = pathlib_expandnode_box;
+
+ // Water movement test
+ pathlib_movenode = pathlib_swimnode;
+ }
+
+ if (!openlist)
+ openlist = spawn();
+
+ if (!closedlist)
+ closedlist = spawn();
+
+ pathlib_closed_cnt = 0;
+ pathlib_open_cnt = 0;
+ pathlib_made_cnt = 0;
+ pathlib_merge_cnt = 0;
+ pathlib_searched_cnt = 0;
+ pathlib_bestopen_seached = 0;
+ pathlib_bestcash_hits = 0;
+ pathlib_bestcash_saved = 0;
+
+ pathlib_gridsize = 128;
+ pathlib_movecost = pathlib_gridsize;
+ pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
+ pathlib_movecost_waterfactor = 25000000;
+ pathlib_foundgoal = 0;
+
+ movenode_boxmax = self.maxs * 1.1;
+ movenode_boxmin = self.mins * 1.1;
+
+ movenode_stepsize = pathlib_gridsize * 0.25;
+
+ tile_check_size = pathlib_gridsize * 0.5;
+ tile_check_up = '0 0 2' * pathlib_gridsize;
+ tile_check_up = '0 0 128';
+ tile_check_down = '0 0 3' * pathlib_gridsize;
+ tile_check_down = '0 0 256';
+
+ //movenode_stepup = '0 0 128';
+ movenode_stepup = '0 0 36';
+ movenode_maxdrop = '0 0 512';
+ //movenode_maxdrop = '0 0 512';
+ movenode_boxup = '0 0 72';
+
+ from.x = fsnap(from.x, pathlib_gridsize);
+ from.y = fsnap(from.y, pathlib_gridsize);
+ //from_z += 32;
+
+ to.x = fsnap(to.x, pathlib_gridsize);
+ to.y = fsnap(to.y, pathlib_gridsize);
+ //to_z += 32;
+
+ LOG_TRACE("AStar init\n");
+ path = pathlib_mknode(from, world);
+ pathlib_close_node(path, to);
+ if(pathlib_foundgoal)
+ {
+ LOG_TRACE("AStar: Goal found on first node!\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)
+ {
+ LOG_TRACE("AStar path 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);
+
+ while(pathlib_open_cnt)
+ {
+ if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
+ {
+ LOG_TRACE("Path took to long to compute!\n");
+ LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
+ LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
+ LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
+ LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\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(n,from,to);
+
+ if(pathlib_foundgoal)
+ {
+ LOG_TRACE("Target found. Rebuilding and filtering path...\n");
+ ftime = gettime(GETTIME_REALTIME);
+ ptime = ftime - ptime;
+
+ start = path_build(world,path.origin,world,world);
+ end = path_build(world,goal_node.origin,world,start);
+ ln = end;
+
+ open = goal_node;
+ for(open = goal_node; open.path_prev != path; open = open.path_prev)
+ {
+ n = path_build(ln,open.origin,open.path_prev,start);
+ ln.path_prev = n;
+ ln = n;
+ }
+ start.path_next = n;
+ n.path_prev = start;
+ ftime = gettime(GETTIME_REALTIME) - ftime;
+
+ ctime = gettime(GETTIME_REALTIME);
+ pathlib_cleanup();
+ ctime = gettime(GETTIME_REALTIME) - ctime;
+
+
+#ifdef DEBUGPATHING
+ pathlib_showpath2(start);
+
+ LOG_TRACE("Time used - pathfinding: ", ftos(ptime),"\n");
+ LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime),"\n");
+ LOG_TRACE("Time used - cleanup: ", ftos(ctime),"\n");
+ LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
+ LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
+ LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
+ LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
+ LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
+ LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
+ LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
+ LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
+ LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
+ LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
+ LOG_TRACE("AStar done.\n");
+#endif
+ return start;
+ }
+ }
+
+ LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.\n");
+
+ pathlib_cleanup();
+
+ return world;
+}
--- /dev/null
+#ifndef PATHLIB_MAIN_H
+#define PATHLIB_MAIN_H
+float buildpath_nodefilter_none(vector n,vector c,vector p);
+entity path_build(entity next, vector where, entity prev, entity start);
+#endif
--- /dev/null
+#include "pathlib.qh"
+#include "utility.qh"
+
+vector pathlib_wateroutnode(vector start,vector end, float doedge)
+{SELFPARAM();
+ 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 (!(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;
+ }
+
+ if(pointcontents(surface + '0 0 1') != CONTENT_EMPTY)
+ return end;
+
+ tracebox(start + '0 0 64', movenode_boxmin,movenode_boxmax, end + '0 0 64', MOVE_WORLDONLY, self);
+ if(trace_fraction == 1)
+ pathlib_movenode_goodnode = 1;
+
+ if(fabs(surface.z - end.z) > 32)
+ pathlib_movenode_goodnode = 0;
+
+ return end;
+}
+
+vector pathlib_swimnode(vector start,vector end, float doedge)
+{SELFPARAM();
+ 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, doedge);
+
+ tracebox(start, movenode_boxmin,movenode_boxmax, end, MOVE_WORLDONLY, self);
+ if(trace_fraction == 1)
+ pathlib_movenode_goodnode = 1;
+
+ return end;
+}
+
+vector pathlib_flynode(vector start,vector end, float doedge)
+{SELFPARAM();
+ pathlib_movenode_goodnode = 0;
+
+ end.x = fsnap(end.x, pathlib_gridsize);
+ end.y = fsnap(end.y, pathlib_gridsize);
+
+ tracebox(start, movenode_boxmin,movenode_boxmax, end, MOVE_WORLDONLY, self);
+ if(trace_fraction == 1)
+ pathlib_movenode_goodnode = 1;
+
+ return end;
+}
+
+void a_think()
+{SELFPARAM();
+ te_lightning1(self,self.origin, self.pos1);
+ if(self.cnt < time)
+ remove(self);
+ else
+ self.nextthink = time + 0.2;
+}
+
+vector pathlib_walknode(vector start,vector end,float doedge)
+{SELFPARAM();
+ vector direction,point,last_point,s,e;
+ float steps, distance, i;
+
+ LOG_TRACE("Walking node from ", vtos(start), " to ", vtos(end), "\n");
+
+ pathlib_movenode_goodnode = 0;
+
+ end.x = fsnap(end.x,pathlib_gridsize);
+ end.y = fsnap(end.y,pathlib_gridsize);
+ start.x = fsnap(start.x,pathlib_gridsize);
+ start.y = fsnap(start.y,pathlib_gridsize);
+
+ // Find the floor
+ traceline(start + movenode_stepup, start - movenode_maxdrop, MOVE_WORLDONLY, self);
+ if(trace_fraction == 1.0)
+ {
+ entity a;
+ a = spawn();
+ a.think = a_think;
+ a.nextthink = time;
+ setorigin(a,start + movenode_stepup);
+ a.pos1 = trace_endpos;
+ //start - movenode_maxdrop
+ a.cnt = time + 10;
+
+ LOG_TRACE("I cant walk on air!\n");
+ return trace_endpos;
+ }
+
+ start = trace_endpos;
+
+ // Find the direcion, without Z
+ s = start; e = end;
+ //e_z = 0; s_z = 0;
+ direction = normalize(e - s);
+
+ distance = vlen(start - end);
+ steps = rint(distance / movenode_stepsize);
+
+ last_point = start;
+ for(i = 1; i < steps; ++i)
+ {
+ point = last_point + (direction * movenode_stepsize);
+ traceline(point + movenode_stepup,point - movenode_maxdrop,MOVE_WORLDONLY,self);
+ if(trace_fraction == 1.0)
+ return trace_endpos;
+
+ last_point = trace_endpos;
+ }
+
+ point = last_point + (direction * movenode_stepsize);
+ point.x = fsnap(point.x,pathlib_gridsize);
+ point.y = fsnap(point.y,pathlib_gridsize);
+
+ //dprint("end_x: ",ftos(end_x), " end_y: ",ftos(end_y),"\n");
+ //dprint("point_x:",ftos(point_x)," point_y:",ftos(point_y),"\n\n");
+
+ traceline(point + movenode_stepup, point - movenode_maxdrop,MOVE_WORLDONLY,self);
+ if(trace_fraction == 1.0)
+ return trace_endpos;
+
+ last_point = trace_endpos;
+
+ tracebox(start + movenode_boxup, movenode_boxmin,movenode_boxmax, last_point + movenode_boxup, MOVE_WORLDONLY, self);
+ if(trace_fraction != 1.0)
+ return trace_endpos;
+
+ pathlib_movenode_goodnode = 1;
+ return last_point;
+}
--- /dev/null
+#include "pathlib.qh"
+#include "main.qh"
+
+var float pathlib_wpp_open(entity wp, entity child, float cost);
+
+void pathlib_wpp_close(entity wp)
+{
+ --pathlib_open_cnt;
+ ++pathlib_closed_cnt;
+
+ wp.pathlib_list = closedlist;
+
+ if(wp == best_open_node)
+ best_open_node = world;
+
+ if(wp == goal_node)
+ pathlib_foundgoal = true;
+}
+
+float pathlib_wpp_opencb(entity wp, entity child, float cost)
+{
+
+ if(child.pathlib_list == closedlist)
+ return false;
+
+ // FIXME! wp.wp##mincost is NOT distance. Make it distance or add a field for distance to be used here (for better speed)
+ cost = vlen(child.origin - wp.origin);
+
+ child.path_prev = wp;
+ child.pathlib_list = openlist;
+ child.pathlib_node_g = wp.pathlib_node_g + cost;
+ child.pathlib_node_h = pathlib_heuristic(child.origin, goal_node.origin);
+ child.pathlib_node_c = pathlib_wpp_waypointcallback(child, wp);
+ child.pathlib_node_f = child.pathlib_node_g + child.pathlib_node_h + child.pathlib_node_c;
+
+
+ if(child == goal_node)
+ pathlib_foundgoal = true;
+
+ ++pathlib_open_cnt;
+
+ if(best_open_node.pathlib_node_f > child.pathlib_node_f)
+ best_open_node = child;
+
+ return true;
+}
+
+float pathlib_wpp_openncb(entity wp, entity child, float cost)
+{
+
+ if(child.pathlib_list == closedlist)
+ return false;
+
+ // FIXME! wp.wp##mincost is NOT distance. Make it distance or add a field for distance to be used here (for better speed)
+ cost = vlen(child.origin - wp.origin);
+
+ child.path_prev = wp;
+ child.pathlib_list = openlist;
+ child.pathlib_node_g = wp.pathlib_node_g + cost;
+ child.pathlib_node_h = pathlib_heuristic(child.origin, goal_node.origin);
+ child.pathlib_node_f = child.pathlib_node_g + child.pathlib_node_h;
+
+ if(child == goal_node)
+ pathlib_foundgoal = true;
+
+ ++pathlib_open_cnt;
+
+ if(best_open_node.pathlib_node_f > child.pathlib_node_f)
+ best_open_node = child;
+
+ return true;
+}
+
+float pathlib_wpp_expand(entity wp)
+{
+ if(wp.wp00) pathlib_wpp_open(wp,wp.wp00,wp.wp00mincost); else return 0;
+ if(wp.wp01) pathlib_wpp_open(wp,wp.wp01,wp.wp01mincost); else return 1;
+ if(wp.wp02) pathlib_wpp_open(wp,wp.wp02,wp.wp02mincost); else return 2;
+ if(wp.wp03) pathlib_wpp_open(wp,wp.wp03,wp.wp03mincost); else return 3;
+ if(wp.wp04) pathlib_wpp_open(wp,wp.wp04,wp.wp04mincost); else return 4;
+ if(wp.wp05) pathlib_wpp_open(wp,wp.wp05,wp.wp05mincost); else return 5;
+ if(wp.wp06) pathlib_wpp_open(wp,wp.wp06,wp.wp06mincost); else return 6;
+ if(wp.wp07) pathlib_wpp_open(wp,wp.wp07,wp.wp07mincost); else return 7;
+ if(wp.wp08) pathlib_wpp_open(wp,wp.wp08,wp.wp08mincost); else return 8;
+ if(wp.wp09) pathlib_wpp_open(wp,wp.wp09,wp.wp09mincost); else return 9;
+ if(wp.wp10) pathlib_wpp_open(wp,wp.wp10,wp.wp10mincost); else return 10;
+ if(wp.wp11) pathlib_wpp_open(wp,wp.wp11,wp.wp11mincost); else return 11;
+ if(wp.wp12) pathlib_wpp_open(wp,wp.wp12,wp.wp12mincost); else return 12;
+ if(wp.wp13) pathlib_wpp_open(wp,wp.wp13,wp.wp13mincost); else return 13;
+ if(wp.wp14) pathlib_wpp_open(wp,wp.wp14,wp.wp14mincost); else return 14;
+ if(wp.wp15) pathlib_wpp_open(wp,wp.wp15,wp.wp15mincost); else return 15;
+ if(wp.wp16) pathlib_wpp_open(wp,wp.wp16,wp.wp16mincost); else return 16;
+ if(wp.wp17) pathlib_wpp_open(wp,wp.wp17,wp.wp17mincost); else return 17;
+ if(wp.wp18) pathlib_wpp_open(wp,wp.wp18,wp.wp18mincost); else return 18;
+ if(wp.wp19) pathlib_wpp_open(wp,wp.wp19,wp.wp19mincost); else return 19;
+ if(wp.wp20) pathlib_wpp_open(wp,wp.wp20,wp.wp20mincost); else return 20;
+ if(wp.wp21) pathlib_wpp_open(wp,wp.wp21,wp.wp21mincost); else return 21;
+ if(wp.wp22) pathlib_wpp_open(wp,wp.wp22,wp.wp22mincost); else return 22;
+ if(wp.wp23) pathlib_wpp_open(wp,wp.wp23,wp.wp23mincost); else return 23;
+ if(wp.wp24) pathlib_wpp_open(wp,wp.wp24,wp.wp24mincost); else return 24;
+ if(wp.wp25) pathlib_wpp_open(wp,wp.wp25,wp.wp25mincost); else return 25;
+ if(wp.wp26) pathlib_wpp_open(wp,wp.wp26,wp.wp26mincost); else return 26;
+ if(wp.wp27) pathlib_wpp_open(wp,wp.wp27,wp.wp27mincost); else return 27;
+ if(wp.wp28) pathlib_wpp_open(wp,wp.wp28,wp.wp28mincost); else return 28;
+ if(wp.wp29) pathlib_wpp_open(wp,wp.wp29,wp.wp29mincost); else return 29;
+ if(wp.wp30) pathlib_wpp_open(wp,wp.wp30,wp.wp30mincost); else return 30;
+ if(wp.wp31) pathlib_wpp_open(wp,wp.wp31,wp.wp31mincost); else return 31;
+
+ return 32;
+}
+
+entity pathlib_wpp_bestopen()
+{
+ entity n, best;
+
+ if(best_open_node)
+ return best_open_node;
+
+ n = findchainentity(pathlib_list, openlist);
+ best = n;
+ while(n)
+ {
+ if(n.pathlib_node_f < best.pathlib_node_f)
+ best = n;
+
+ n = n.chain;
+ }
+
+ return best;
+
+}
+
+entity pathlib_waypointpath(entity wp_from, entity wp_to, float callback)
+{
+ entity n;
+ float ptime;
+
+ ptime = gettime(GETTIME_REALTIME);
+ pathlib_starttime = ptime;
+ pathlib_movecost = 300;
+ pathlib_movecost_diag = vlen('1 1 0' * pathlib_movecost);
+
+ if (!pathlib_wpp_waypointcallback)
+ callback = false;
+
+ if (callback)
+ pathlib_wpp_open = pathlib_wpp_opencb;
+ else
+ pathlib_wpp_open = pathlib_wpp_openncb;
+
+ pathlib_heuristic = pathlib_h_none;
+
+ if (!openlist)
+ openlist = spawn();
+
+ if (!closedlist)
+ closedlist = spawn();
+
+ pathlib_closed_cnt = 0;
+ pathlib_open_cnt = 0;
+ pathlib_searched_cnt = 0;
+ pathlib_foundgoal = false;
+
+ LOG_TRACE("pathlib_waypointpath init\n");
+
+ // Initialize waypoint grid
+ // FIXME! presisted chain for better preformance
+ for(n = findchain(classname, "waypoint"); n; n = n.chain)
+ {
+ n.pathlib_list = world;
+ n.pathlib_node_g = 0;
+ n.pathlib_node_f = 0;
+ n.pathlib_node_h = 0;
+
+ //setmodel(n, "models/runematch/rune.mdl");
+ //n.effects = EF_LOWPRECISION;
+ //n.colormod = '0 0 0';
+ //n.scale = 1;
+
+ }
+
+ goal_node = wp_to;
+ start_node = wp_from;
+
+ start_node.pathlib_list = closedlist;
+ LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(start_node))," links\n");
+ if(pathlib_open_cnt <= 0)
+ {
+ LOG_TRACE("pathlib_waypointpath: Start waypoint not linked! aborting.\n");
+ return world;
+ }
+
+ return world;
+}
+
+entity pathlib_waypointpath_step()
+{
+ entity n;
+
+ n = pathlib_wpp_bestopen();
+ if(!n)
+ {
+ LOG_TRACE("Cannot find best open node, abort.\n");
+ return world;
+ }
+ pathlib_wpp_close(n);
+ LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(n))," links\n");
+
+ if(pathlib_foundgoal)
+ {
+ entity start, end, open, ln;
+
+ LOG_TRACE("Target found. Rebuilding and filtering path...\n");
+
+ buildpath_nodefilter = buildpath_nodefilter_none;
+ start = path_build(world, start_node.origin, world, world);
+ end = path_build(world, goal_node.origin, world, start);
+ ln = end;
+
+ for(open = goal_node; open.path_prev != start_node; open = open.path_prev)
+ {
+ n = path_build(ln,open.origin,open.path_prev,start);
+ ln.path_prev = n;
+ ln = n;
+ }
+ start.path_next = n;
+ n.path_prev = start;
+
+ return start;
+ }
+
+ return world;
+}
+void plas_think()
+{SELFPARAM();
+ pathlib_waypointpath_step();
+ if(pathlib_foundgoal)
+ return;
+ self.nextthink = time + 0.1;
+}
+
+void pathlib_waypointpath_autostep()
+{
+ entity n;
+ n = spawn();
+ n.think = plas_think;
+ n.nextthink = time + 0.1;
+}
--- /dev/null
+#ifndef PATHLIB_H
+#define PATHLIB_H
+
+.entity pathlib_list;
+.entity path_next;
+.entity path_prev;
+
+#define inwater(point) (pointcontents(point) == CONTENT_WATER)
+#define medium spawnshieldtime
+
+const vector PLIB_FORWARD = '0 1 0';
+//#define PLIB_BACK '0 -1 0'
+const vector PLIB_RIGHT = '1 0 0';
+//#define PLIB_LEFT '-1 0 0'
+
+#define DEBUGPATHING
+#ifdef DEBUGPATHING
+void pathlib_showpath(entity start);
+void pathlib_showpath2(entity path);
+#endif
+
+entity openlist;
+entity closedlist;
+
+entity goal_node;
+entity start_node;
+
+.float is_path_node;
+.float pathlib_node_g;
+.float pathlib_node_h;
+.float pathlib_node_f;
+.float pathlib_node_c;
+
+const float pathlib_node_edgeflag_unknown = 0;
+const float pathlib_node_edgeflag_left = 2;
+const float pathlib_node_edgeflag_right = 4;
+const float pathlib_node_edgeflag_forward = 8;
+const float pathlib_node_edgeflag_back = 16;
+const float pathlib_node_edgeflag_backleft = 32;
+const float pathlib_node_edgeflag_backright = 64;
+const float pathlib_node_edgeflag_forwardleft = 128;
+const float pathlib_node_edgeflag_forwardright = 256;
+const float pathlib_node_edgeflag_none = 512;
+.float pathlib_node_edgeflags;
+
+float pathlib_open_cnt;
+float pathlib_closed_cnt;
+float pathlib_made_cnt;
+float pathlib_merge_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_foundgoal;
+
+float pathlib_starttime;
+const float pathlib_maxtime = 60;
+
+entity best_open_node;
+
+vector tile_check_up;
+vector tile_check_down;
+float tile_check_size;
+float tile_check_cross(vector where);
+float tile_check_plus(vector where);
+float tile_check_star(vector where);
+var float tile_check(vector where);
+
+float movenode_stepsize;
+vector movenode_stepup;
+vector movenode_maxdrop;
+vector movenode_boxup;
+vector movenode_boxmax;
+vector movenode_boxmin;
+float pathlib_movenode_goodnode;
+
+vector pathlib_wateroutnode(vector start, vector end, float doedge);
+vector pathlib_swimnode(vector start, vector end, float doedge);
+vector pathlib_flynode(vector start, vector end, float doedge);
+vector pathlib_walknode(vector start, vector end, float doedge);
+var vector pathlib_movenode(vector start, vector end, float doedge);
+
+float pathlib_expandnode_star(entity node, vector start, vector goal);
+float pathlib_expandnode_box(entity node, vector start, vector goal);
+float pathlib_expandnode_octagon(entity node, vector start, vector goal);
+var float pathlib_expandnode(entity node, vector start, vector goal);
+
+float pathlib_g_static(entity parent, vector to, float static_cost);
+float pathlib_g_static_water(entity parent, vector to, float static_cost);
+float pathlib_g_euclidean(entity parent, vector to, float static_cost);
+float pathlib_g_euclidean_water(entity parent, vector to, float static_cost);
+var float pathlib_cost(entity parent, vector to, float static_cost);
+
+float pathlib_h_manhattan(vector a, vector b);
+float pathlib_h_diagonal(vector a, vector b);
+float pathlib_h_euclidean(vector a,vector b);
+float pathlib_h_diagonal2(vector a, vector b);
+float pathlib_h_diagonal3(vector a, vector b);
+float pathlib_h_diagonal2sdp(vector preprev, vector prev, vector point, vector end);
+float pathlib_h_none(vector preprev, vector prev) { return 0; }
+var float pathlib_heuristic(vector from, vector to);
+
+var float pathlib_makenode(entity parent,vector start, vector to, vector goal,float cost);
+var float buildpath_nodefilter(vector n,vector c,vector p);
+
+var float pathlib_wpp_waypointcallback(entity wp, entity wp_prev);
+
+#ifdef DEBUGPATHING
+ #include "debug.qc"
+#endif
+
+#endif
--- /dev/null
+#include "utility.qh"
+
+#include "pathlib.qh"
+
+float location_isok(vector point, float water_isok, float air_isok)
+{
+ float pc,pc2;
+
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
+ return 0;
+
+ pc = pointcontents(point);
+ pc2 = pointcontents(point - '0 0 1');
+
+ switch(pc)
+ {
+ case CONTENT_SOLID:
+ break;
+
+ case CONTENT_SLIME:
+ break;
+
+ case CONTENT_LAVA:
+ break;
+
+ case CONTENT_SKY:
+ break;
+
+ case CONTENT_EMPTY:
+ if (pc2 == CONTENT_SOLID)
+ return 1;
+
+ if (pc2 == CONTENT_EMPTY)
+ if(air_isok)
+ return 1;
+
+ if (pc2 == CONTENT_WATER)
+ if(water_isok)
+ return 1;
+
+ break;
+
+ case CONTENT_WATER:
+ if (water_isok)
+ return 1;
+
+ break;
+ }
+
+ return 0;
+}
+
+entity pathlib_nodeatpoint(vector where)
+{
+ entity node;
+
+ ++pathlib_searched_cnt;
+
+ where.x = fsnap(where.x,pathlib_gridsize);
+ where.y = fsnap(where.y,pathlib_gridsize);
+
+ node = findradius(where,pathlib_gridsize * 0.5);
+ while(node)
+ {
+ if(node.is_path_node == true)
+ return node;
+
+ node = node.chain;
+ }
+
+ return world;
+}
+
+float tile_check_cross(vector where)
+{SELFPARAM();
+ vector p,f,r;
+
+ f = PLIB_FORWARD * tile_check_size;
+ r = PLIB_RIGHT * tile_check_size;
+
+
+ // forward-right
+ p = where + f + r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (!location_isok(trace_endpos, 1, 0))
+ return 0;
+
+ // Forward-left
+ p = where + f - r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (!location_isok(trace_endpos, 1, 0))
+ return 0;
+
+ // Back-right
+ p = where - f + r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (!location_isok(trace_endpos, 1 ,0))
+ return 0;
+
+ //Back-left
+ p = where - f - r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (!location_isok(trace_endpos, 1, 0))
+ return 0;
+
+ return 1;
+}
+
+float tile_check_plus(vector where)
+{SELFPARAM();
+ vector p,f,r;
+
+ f = PLIB_FORWARD * tile_check_size;
+ r = PLIB_RIGHT * tile_check_size;
+
+ // forward
+ p = where + f;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (!location_isok(trace_endpos,1,0))
+ return 0;
+
+
+ //left
+ p = where - r;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (!location_isok(trace_endpos,1,0))
+ return 0;
+
+ // Right
+ p = where + r;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (!location_isok(trace_endpos,1,0))
+ return 0;
+
+ //Back
+ p = where - f;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (!location_isok(trace_endpos,1,0))
+ return 0;
+
+ return 1;
+}
+
+float tile_check_plus2(vector where)
+{SELFPARAM();
+ vector p,f,r;
+ float i = 0, e = 0;
+
+ f = PLIB_FORWARD * pathlib_gridsize;
+ r = PLIB_RIGHT * pathlib_gridsize;
+
+//#define pathlib_node_edgeflag_left 2
+//#define pathlib_node_edgeflag_right 4
+//#define pathlib_node_edgeflag_forward 8
+//#define pathlib_node_edgeflag_back 16
+
+ // forward
+ p = where + f;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (location_isok(trace_endpos,1,0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_forward;
+ }
+
+
+ //left
+ p = where - r;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (location_isok(trace_endpos,1,0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_left;
+ }
+
+
+ // Right
+ p = where + r;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (location_isok(trace_endpos,1,0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_right;
+ }
+
+ //Back
+ p = where - f;
+ traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
+ if (location_isok(trace_endpos,1,0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_back;
+ }
+
+ // forward-right
+ p = where + f + r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (location_isok(trace_endpos, 1, 0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_forwardright;
+ }
+
+ // Forward-left
+ p = where + f - r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (location_isok(trace_endpos, 1, 0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_forwardleft;
+ }
+
+ // Back-right
+ p = where - f + r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (location_isok(trace_endpos, 1 ,0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_backright;
+ }
+
+ //Back-left
+ p = where - f - r;
+ traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
+ if (location_isok(trace_endpos, 1, 0))
+ {
+ ++i;
+ e |= pathlib_node_edgeflag_backleft;
+ }
+
+
+ if(i == 0)
+ e = pathlib_node_edgeflag_none;
+
+ return e;
+}
+
+float tile_check_star(vector where)
+{
+ if(tile_check_plus(where))
+ return tile_check_cross(where);
+
+ return 0;
+}
+
--- /dev/null
+#ifndef PATHLIB_UTILITY
+#define PATHLIB_UTILITY
+float fsnap(float val,float fsize);
+entity pathlib_nodeatpoint(vector where);
+float tile_check_plus2(vector where);
+#endif
--- /dev/null
+#include "steerlib.qc"
--- /dev/null
+/**
+ Uniform pull towards a point
+**/
+vector steerlib_pull(vector point)
+{SELFPARAM();
+ return normalize(point - self.origin);
+}
+
+/**
+ Uniform push from a point
+**/
+#define steerlib_push(point) normalize(self.origin - point)
+/*
+vector steerlib_push(vector point)
+{
+ return normalize(self.origin - point);
+}
+*/
+/**
+ Pull toward a point, The further away, the stronger the pull.
+**/
+vector steerlib_arrive(vector point,float maximal_distance)
+{SELFPARAM();
+ float distance;
+ vector direction;
+
+ distance = bound(0.001,vlen(self.origin - point),maximal_distance);
+ direction = normalize(point - self.origin);
+ return direction * (distance / maximal_distance);
+}
+
+/**
+ Pull toward a point increasing the pull the closer we get
+**/
+vector steerlib_attract(vector point, float maximal_distance)
+{SELFPARAM();
+ float distance;
+ vector direction;
+
+ distance = bound(0.001,vlen(self.origin - point),maximal_distance);
+ direction = normalize(point - self.origin);
+
+ return direction * (1-(distance / maximal_distance));
+}
+
+vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)
+{SELFPARAM();
+ float distance;
+ vector direction;
+ float influense;
+
+ distance = bound(0.00001,vlen(self.origin - point),max_distance);
+ direction = normalize(point - self.origin);
+
+ influense = 1 - (distance / max_distance);
+ influense = min_influense + (influense * (max_influense - min_influense));
+
+ return direction * influense;
+}
+
+/*
+vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
+{
+ //float distance;
+ vector current_direction;
+ vector target_direction;
+ float i_target,i_current;
+
+ if(!distance)
+ distance = vlen(self.origin - point);
+
+ distance = bound(0.001,distance,maximal_distance);
+
+ target_direction = normalize(point - self.origin);
+ current_direction = normalize(self.velocity);
+
+ i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
+ i_current = 1 - i_target;
+
+ // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
+
+ string s;
+ s = ftos(i_target);
+ bprint("IT: ",s,"\n");
+ s = ftos(i_current);
+ bprint("IC : ",s,"\n");
+
+ return normalize((target_direction * i_target) + (current_direction * i_current));
+}
+*/
+/**
+ Move away from a point.
+**/
+vector steerlib_repell(vector point,float maximal_distance)
+{SELFPARAM();
+ float distance;
+ vector direction;
+
+ distance = bound(0.001,vlen(self.origin - point),maximal_distance);
+ direction = normalize(self.origin - point);
+
+ return direction * (1-(distance / maximal_distance));
+}
+
+/**
+ Try to keep at ideal_distance away from point
+**/
+vector steerlib_standoff(vector point,float ideal_distance)
+{SELFPARAM();
+ float distance;
+ vector direction;
+
+ distance = vlen(self.origin - point);
+
+
+ if(distance < ideal_distance)
+ {
+ direction = normalize(self.origin - point);
+ return direction * (distance / ideal_distance);
+ }
+
+ direction = normalize(point - self.origin);
+ return direction * (ideal_distance / distance);
+
+}
+
+/**
+ A random heading in a forward halfcicrle
+
+ use like:
+ self.target = steerlib_wander(256,32,self.target)
+
+ where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
+**/
+vector steerlib_wander(float range,float tresh,vector oldpoint)
+{SELFPARAM();
+ vector wander_point;
+ wander_point = v_forward - oldpoint;
+
+ if (vlen(wander_point) > tresh)
+ return oldpoint;
+
+ range = bound(0,range,1);
+
+ wander_point = self.origin + v_forward * 128;
+ wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
+
+ return normalize(wander_point - self.origin);
+}
+
+/**
+ Dodge a point. dont work to well.
+**/
+vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)
+{SELFPARAM();
+ float distance;
+
+ distance = max(vlen(self.origin - point),min_distance);
+ if (min_distance < distance)
+ return '0 0 0';
+
+ return dodge_dir * (min_distance/distance);
+}
+
+/**
+ flocking by .flock_id
+ Group will move towards the unified direction while keeping close to eachother.
+**/
+.float flock_id;
+vector steerlib_flock(float _radius, float standoff,float separation_force,float flock_force)
+{SELFPARAM();
+ entity flock_member;
+ vector push = '0 0 0', pull = '0 0 0';
+ float ccount = 0;
+
+ flock_member = findradius(self.origin, _radius);
+ while(flock_member)
+ {
+ if(flock_member != self)
+ if(flock_member.flock_id == self.flock_id)
+ {
+ ++ccount;
+ push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);
+ pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity, _radius) * flock_force);
+ }
+ flock_member = flock_member.chain;
+ }
+ return push + (pull* (1 / ccount));
+}
+
+/**
+ flocking by .flock_id
+ Group will move towards the unified direction while keeping close to eachother.
+ xy only version (for ground movers).
+**/
+vector steerlib_flock2d(float _radius, float standoff,float separation_force,float flock_force)
+{SELFPARAM();
+ entity flock_member;
+ vector push = '0 0 0', pull = '0 0 0';
+ float ccount = 0;
+
+ flock_member = findradius(self.origin,_radius);
+ while(flock_member)
+ {
+ if(flock_member != self)
+ if(flock_member.flock_id == self.flock_id)
+ {
+ ++ccount;
+ push = push + (steerlib_repell(flock_member.origin, standoff) * separation_force);
+ pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity, _radius) * flock_force);
+ }
+ flock_member = flock_member.chain;
+ }
+
+ push.z = 0;
+ pull.z = 0;
+
+ return push + (pull * (1 / ccount));
+}
+
+/**
+ All members want to be in the center, and keep away from eachother.
+ The furtehr form the center the more they want to be there.
+
+ This results in a aligned movement (?!) much like flocking.
+**/
+vector steerlib_swarm(float _radius, float standoff,float separation_force,float swarm_force)
+{SELFPARAM();
+ entity swarm_member;
+ vector force = '0 0 0', center = '0 0 0';
+ float ccount = 0;
+
+ swarm_member = findradius(self.origin,_radius);
+
+ while(swarm_member)
+ {
+ if(swarm_member.flock_id == self.flock_id)
+ {
+ ++ccount;
+ center = center + swarm_member.origin;
+ force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);
+ }
+ swarm_member = swarm_member.chain;
+ }
+
+ center = center * (1 / ccount);
+ force = force + (steerlib_arrive(center,_radius) * swarm_force);
+
+ return force;
+}
+
+/**
+ Steer towards the direction least obstructed.
+ Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
+ You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
+**/
+vector steerlib_traceavoid(float pitch,float length)
+{SELFPARAM();
+ vector vup_left,vup_right,vdown_left,vdown_right;
+ float fup_left,fup_right,fdown_left,fdown_right;
+ vector upwish,downwish,leftwish,rightwish;
+ vector v_left,v_down;
+
+
+ v_left = v_right * -1;
+ v_down = v_up * -1;
+
+ vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
+ traceline(self.origin, self.origin + vup_left,MOVE_NOMONSTERS,self);
+ fup_left = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+
+ vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
+ traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);
+ fup_right = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+
+ vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
+ traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);
+ fdown_left = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+
+ vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
+ traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);
+ fdown_right = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+ upwish = v_up * (fup_left + fup_right);
+ downwish = v_down * (fdown_left + fdown_right);
+ leftwish = v_left * (fup_left + fdown_left);
+ rightwish = v_right * (fup_right + fdown_right);
+
+ return (upwish+leftwish+downwish+rightwish) * 0.25;
+
+}
+
+/**
+ Steer towards the direction least obstructed.
+ Run tracelines in a forward trident, bias each direction negative if something is found there.
+**/
+vector steerlib_traceavoid_flat(float pitch, float length, vector vofs)
+{SELFPARAM();
+ vector vt_left, vt_right,vt_front;
+ float f_left, f_right,f_front;
+ vector leftwish, rightwish,frontwish, v_left;
+
+ v_left = v_right * -1;
+
+
+ vt_front = v_forward * length;
+ traceline(self.origin + vofs, self.origin + vofs + vt_front,MOVE_NOMONSTERS,self);
+ f_front = trace_fraction;
+
+ vt_left = (v_forward + (v_left * pitch)) * length;
+ traceline(self.origin + vofs, self.origin + vofs + vt_left,MOVE_NOMONSTERS,self);
+ f_left = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+
+ vt_right = (v_forward + (v_right * pitch)) * length;
+ traceline(self.origin + vofs, self.origin + vofs + vt_right ,MOVE_NOMONSTERS,self);
+ f_right = trace_fraction;
+
+ //te_lightning1(world,self.origin, trace_endpos);
+
+ leftwish = v_left * f_left;
+ rightwish = v_right * f_right;
+ frontwish = v_forward * f_front;
+
+ return normalize(leftwish + rightwish + frontwish);
+}
+
+float beamsweep_badpoint(vector point,float waterok)
+{
+ float pc,pc2;
+
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
+ return 1;
+
+ pc = pointcontents(point);
+ pc2 = pointcontents(point - '0 0 1');
+
+ switch(pc)
+ {
+ case CONTENT_SOLID: break;
+ case CONTENT_SLIME: break;
+ case CONTENT_LAVA: break;
+
+ case CONTENT_SKY:
+ return 1;
+
+ case CONTENT_EMPTY:
+ if (pc2 == CONTENT_SOLID)
+ return 0;
+
+ if (pc2 == CONTENT_WATER)
+ if(waterok)
+ return 0;
+
+ break;
+
+ case CONTENT_WATER:
+ if(waterok)
+ return 0;
+
+ break;
+ }
+
+ return 1;
+}
+
+//#define BEAMSTEER_VISUAL
+float beamsweep(vector from, vector dir,float length, float step,float step_up, float step_down)
+{SELFPARAM();
+ float i;
+ vector a,b,u,d;
+
+ u = '0 0 1' * step_up;
+ d = '0 0 1' * step_down;
+
+ traceline(from + u, from - d,MOVE_NORMAL,self);
+ if(trace_fraction == 1.0)
+ return 0;
+
+ if(beamsweep_badpoint(trace_endpos,0))
+ return 0;
+
+ a = trace_endpos;
+ for(i = 0; i < length; i += step)
+ {
+
+ b = a + dir * step;
+ tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,self);
+ if(trace_fraction != 1.0)
+ return i / length;
+
+ traceline(b + u, b - d,MOVE_NORMAL,self);
+ if(trace_fraction == 1.0)
+ return i / length;
+
+ if(beamsweep_badpoint(trace_endpos,0))
+ return i / length;
+#ifdef BEAMSTEER_VISUAL
+ te_lightning1(world,a+u,b+u);
+ te_lightning1(world,b+u,b-d);
+#endif
+ a = trace_endpos;
+ }
+
+ return 1;
+}
+
+vector steerlib_beamsteer(vector dir, float length, float step, float step_up, float step_down)
+{SELFPARAM();
+ float bm_forward, bm_right, bm_left,p;
+ vector vr,vl;
+
+ dir.z *= 0.15;
+ vr = vectoangles(dir);
+ //vr_x *= -1;
+
+ tracebox(self.origin + '0 0 1' * step_up, self.mins, self.maxs, ('0 0 1' * step_up) + self.origin + (dir * length), MOVE_NOMONSTERS, self);
+ if(trace_fraction == 1.0)
+ {
+ //te_lightning1(self,self.origin,self.origin + (dir * length));
+ return dir;
+ }
+
+
+
+
+ makevectors(vr);
+ bm_forward = beamsweep(self.origin, v_forward, length, step, step_up, step_down);
+
+ vr = normalize(v_forward + v_right * 0.125);
+ vl = normalize(v_forward - v_right * 0.125);
+
+ bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
+ bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
+
+
+ p = bm_left + bm_right;
+ if(p == 2)
+ {
+ //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
+ //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
+
+ return v_forward;
+ }
+
+ p = 2 - p;
+
+ vr = normalize(v_forward + v_right * p);
+ vl = normalize(v_forward - v_right * p);
+ bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
+ bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
+
+
+ if(bm_left + bm_right < 0.15)
+ {
+ vr = normalize((v_forward*-1) + v_right * 0.75);
+ vl = normalize((v_forward*-1) - v_right * 0.75);
+
+ bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
+ bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
+ }
+
+ //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
+ //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
+
+ bm_forward *= bm_forward;
+ bm_right *= bm_right;
+ bm_left *= bm_left;
+
+ vr = vr * bm_right;
+ vl = vl * bm_left;
+
+ return normalize(vr + vl);
+
+}
+
+
+//////////////////////////////////////////////
+// Testting //
+// Everything below this point is a mess :D //
+//////////////////////////////////////////////
+//#define TLIBS_TETSLIBS
+#ifdef TLIBS_TETSLIBS
+void flocker_die()
+{SELFPARAM();
+ Send_Effect(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
+
+ self.owner.cnt += 1;
+ self.owner = world;
+
+ self.nextthink = time;
+ self.think = SUB_Remove;
+}
+
+
+void flocker_think()
+{SELFPARAM();
+ vector dodgemove,swarmmove;
+ vector reprellmove,wandermove,newmove;
+
+ self.angles_x = self.angles.x * -1;
+ makevectors(self.angles);
+ self.angles_x = self.angles.x * -1;
+
+ dodgemove = steerlib_traceavoid(0.35,1000);
+ swarmmove = steerlib_flock(500,75,700,500);
+ reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
+
+ if(vlen(dodgemove) == 0)
+ {
+ self.pos1 = steerlib_wander(0.5,0.1,self.pos1);
+ wandermove = self.pos1 * 50;
+ }
+ else
+ self.pos1 = normalize(self.velocity);
+
+ dodgemove = dodgemove * vlen(self.velocity) * 5;
+
+ newmove = swarmmove + reprellmove + wandermove + dodgemove;
+ self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
+ //self.velocity = movelib_inertmove(dodgemove,0.65);
+
+ self.velocity = movelib_dragvec(0.01,0.6);
+
+ self.angles = vectoangles(self.velocity);
+
+ if(self.health <= 0)
+ flocker_die();
+ else
+ self.nextthink = time + 0.1;
+}
+
+MODEL(FLOCKER, "models/turrets/rocket.md3");
+
+void spawn_flocker()
+{SELFPARAM();
+ entity flocker;
+
+ flocker = spawn ();
+
+ setorigin(flocker, self.origin + '0 0 32');
+ setmodel (flocker, MDL_FLOCKER);
+ setsize (flocker, '-3 -3 -3', '3 3 3');
+
+ flocker.flock_id = self.flock_id;
+ flocker.classname = "flocker";
+ flocker.owner = self;
+ flocker.think = flocker_think;
+ flocker.nextthink = time + random() * 5;
+ PROJECTILE_MAKETRIGGER(flocker);
+ flocker.movetype = MOVETYPE_BOUNCEMISSILE;
+ flocker.effects = EF_LOWPRECISION;
+ flocker.velocity = randomvec() * 300;
+ flocker.angles = vectoangles(flocker.velocity);
+ flocker.health = 10;
+ flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
+
+ self.cnt = self.cnt -1;
+
+}
+
+void flockerspawn_think()
+{SELFPARAM();
+
+
+ if(self.cnt > 0)
+ spawn_flocker();
+
+ self.nextthink = time + self.delay;
+
+}
+
+void flocker_hunter_think()
+{SELFPARAM();
+ vector dodgemove,attractmove,newmove;
+ entity e,ee;
+ float d,bd;
+
+ self.angles_x = self.angles.x * -1;
+ makevectors(self.angles);
+ self.angles_x = self.angles.x * -1;
+
+ if(self.enemy)
+ if(vlen(self.enemy.origin - self.origin) < 64)
+ {
+ ee = self.enemy;
+ ee.health = -1;
+ self.enemy = world;
+
+ }
+
+ if(!self.enemy)
+ {
+ e = findchainfloat(flock_id,self.flock_id);
+ while(e)
+ {
+ d = vlen(self.origin - e.origin);
+
+ if(e != self.owner)
+ if(e != ee)
+ if(d > bd)
+ {
+ self.enemy = e;
+ bd = d;
+ }
+ e = e.chain;
+ }
+ }
+
+ if(self.enemy)
+ attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
+ else
+ attractmove = normalize(self.velocity) * 200;
+
+ dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
+
+ newmove = dodgemove + attractmove;
+ self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
+ self.velocity = movelib_dragvec(0.01,0.5);
+
+
+ self.angles = vectoangles(self.velocity);
+ self.nextthink = time + 0.1;
+}
+
+
+float globflockcnt;
+spawnfunc(flockerspawn)
+{SELFPARAM();
+ ++globflockcnt;
+
+ if(!self.cnt) self.cnt = 20;
+ if(!self.delay) self.delay = 0.25;
+ if(!self.flock_id) self.flock_id = globflockcnt;
+
+ self.think = flockerspawn_think;
+ self.nextthink = time + 0.25;
+
+ self.enemy = spawn();
+
+ setmodel(self.enemy, MDL_FLOCKER);
+ setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
+
+ self.enemy.classname = "FLock Hunter";
+ self.enemy.scale = 3;
+ self.enemy.effects = EF_LOWPRECISION;
+ self.enemy.movetype = MOVETYPE_BOUNCEMISSILE;
+ PROJECTILE_MAKETRIGGER(self.enemy);
+ self.enemy.think = flocker_hunter_think;
+ self.enemy.nextthink = time + 10;
+ self.enemy.flock_id = self.flock_id;
+ self.enemy.owner = self;
+}
+#endif
+
+
+
--- /dev/null
+#ifndef STEERLIB_H
+#define STEERLIB_H
+
+.vector steerto;
+
+vector steerlib_arrive(vector point,float maximal_distance);
+vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense);
+vector steerlib_pull(vector point);
+
+#endif
+++ /dev/null
-#include "movelib.qh"
-
-#ifdef SVQC
-.vector moveto;
-
-/**
- Simulate drag
- self.velocity = movelib_dragvec(self.velocity,0.02,0.5);
-**/
-vector movelib_dragvec(float drag, float exp_)
-{SELFPARAM();
- float lspeed,ldrag;
-
- lspeed = vlen(self.velocity);
- ldrag = lspeed * drag;
- ldrag = ldrag * (drag * exp_);
- ldrag = 1 - (ldrag / lspeed);
-
- return self.velocity * ldrag;
-}
-
-/**
- Simulate drag
- self.velocity *= movelib_dragflt(somespeed,0.01,0.7);
-**/
-float movelib_dragflt(float fspeed,float drag,float exp_)
-{
- float ldrag;
-
- ldrag = fspeed * drag;
- ldrag = ldrag * ldrag * exp_;
- ldrag = 1 - (ldrag / fspeed);
-
- return ldrag;
-}
-
-/**
- Do a inertia simulation based on velocity.
- Basicaly, this allows you to simulate loss of steering with higher speed.
- self.velocity = movelib_inertmove_byspeed(self.velocity,newvel,1000,0.1,0.9);
-**/
-vector movelib_inertmove_byspeed(vector vel_new, float vel_max,float newmin,float oldmax)
-{SELFPARAM();
- float influense;
-
- influense = vlen(self.velocity) * (1 / vel_max);
-
- influense = bound(newmin,influense,oldmax);
-
- return (vel_new * (1 - influense)) + (self.velocity * influense);
-}
-
-vector movelib_inertmove(vector new_vel,float new_bias)
-{SELFPARAM();
- return new_vel * new_bias + self.velocity * (1-new_bias);
-}
-
-void movelib_move(vector force,float max_velocity,float drag,float theMass,float breakforce)
-{SELFPARAM();
- float deltatime;
- float acceleration;
- 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);
-
- if (theMass)
- acceleration = vlen(force) / theMass;
- else
- acceleration = vlen(force);
-
- if (self.flags & FL_ONGROUND)
- {
- if (breakforce)
- {
- breakvec = (normalize(self.velocity) * (breakforce / theMass) * deltatime);
- self.velocity = self.velocity - breakvec;
- }
-
- self.velocity = self.velocity + force * (acceleration * 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' * autocvar_sv_gravity * deltatime;
- }
- else
- self.velocity = self.velocity + '0 0 -1' * autocvar_sv_gravity * deltatime;
-
- mspeed = vlen(self.velocity);
-
- if (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_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 = (autocvar_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;
-
-}
-*/
-
-void movelib_beak_simple(float force)
-{SELFPARAM();
- float mspeed;
- vector mdir;
- float vz;
-
- mspeed = max(0,vlen(self.velocity) - force);
- mdir = normalize(self.velocity);
- vz = self.velocity.z;
- self.velocity = mdir * mspeed;
- self.velocity_z = vz;
-}
-
-/**
-Pitches and rolls the entity to match the gound.
-Yed need to set v_up and v_forward (generally by calling makevectors) before calling this.
-**/
-#endif
-
-void movelib_groundalign4point(float spring_length, float spring_up, float blendrate, float _max)
-{SELFPARAM();
- vector a, b, c, d, e, r, push_angle, ahead, side;
-
- push_angle.y = 0;
- r = (self.absmax + self.absmin) * 0.5 + (v_up * spring_up);
- e = v_up * spring_length;
-
- // Put springs slightly inside bbox
- ahead = v_forward * (self.maxs.x * 0.8);
- side = v_right * (self.maxs.y * 0.8);
-
- a = r + ahead + side;
- b = r + ahead - side;
- c = r - ahead + side;
- d = r - ahead - side;
-
- 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) * _max;
- push_angle.x += (b.z - d.z) * _max;
-
- push_angle.z = (b.z - a.z) * _max;
- push_angle.z += (d.z - c.z) * _max;
-
- //self.angles_x += push_angle_x * 0.95;
- //self.angles_z += push_angle_z * 0.95;
-
- self.angles_x = ((1-blendrate) * self.angles.x) + (push_angle.x * blendrate);
- self.angles_z = ((1-blendrate) * self.angles.z) + (push_angle.z * blendrate);
-
- //a = self.origin;
- setorigin(self,r);
-}
-
+++ /dev/null
-#ifndef MOVELIB_H
-#define MOVELIB_H
-
-#ifdef SVQC
-.vector moveto;
-
-/**
- Simulate drag
- self.velocity = movelib_dragvec(self.velocity,0.02,0.5);
-**/
-vector movelib_dragvec(float drag, float exp_);
-
-/**
- Simulate drag
- self.velocity *= movelib_dragflt(somespeed,0.01,0.7);
-**/
-float movelib_dragflt(float fspeed,float drag,float exp_);
-
-/**
- Do a inertia simulation based on velocity.
- Basicaly, this allows you to simulate loss of steering with higher speed.
- self.velocity = movelib_inertmove_byspeed(self.velocity,newvel,1000,0.1,0.9);
-**/
-vector movelib_inertmove_byspeed(vector vel_new, float vel_max,float newmin,float oldmax);
-
-vector movelib_inertmove(vector new_vel,float new_bias);
-
-.float movelib_lastupdate;
-void movelib_move(vector force,float max_velocity,float drag,float theMass,float breakforce);
-
-/*
-void movelib_move_simple(vector newdir,float velo,float blendrate)
-{
- self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo;
-}
-*/
-#define movelib_move_simple(newdir,velo,blendrate) \
- self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo
-
-#define movelib_move_simple_gravity(newdir,velo,blendrate) \
- if(self.flags & FL_ONGROUND) movelib_move_simple(newdir,velo,blendrate)
-
-void movelib_beak_simple(float force);
-
-/**
-Pitches and rolls the entity to match the gound.
-Yed need to set v_up and v_forward (generally by calling makevectors) before calling this.
-**/
-#endif
-
-void movelib_groundalign4point(float spring_length, float spring_up, float blendrate, float _max);
-
-#endif
#include "../playerdemo.qh"
#include "../round_handler.qh"
#include "../item_key.qh"
- #include "../pathlib/pathlib.qh"
#include "../../common/vehicles/all.qh"
#endif
+++ /dev/null
-#include "pathlib.qh"
-
-float pathlib_g_static(entity parent,vector to, float static_cost)
-{
- return parent.pathlib_node_g + static_cost;
-}
-
-float pathlib_g_static_water(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 parent.pathlib_node_g + vlen(parent.origin - to);
-}
-
-float pathlib_g_euclidean_water(entity parent,vector to, float static_cost)
-{
- if(inwater(to))
- return parent.pathlib_node_g + vlen(parent.origin - to) * pathlib_movecost_waterfactor;
- else
- return parent.pathlib_node_g + vlen(parent.origin - to);
-}
-
-
-/**
- Manhattan Menas we expect to move up,down left or right
- No diagonal moves espected. (like moving bewteen city blocks)
-**/
-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 += fabs(a.y - b.y);
- h *= pathlib_gridsize;
-
- return h;
-}
-
-/**
- This heuristic consider both stright and disagonal moves
- to have teh same cost.
-**/
-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;
-}
-
-/**
- This heuristic only considers the stright line distance.
- Will usualy mean a lower H then G meaning A* Will speand more
- and run slower.
-**/
-float pathlib_h_euclidean(vector a,vector b)
-{
- return vlen(a - b);
-}
-
-/**
- This heuristic consider both stright and disagonal moves,
- But has a separate cost for diagonal moves.
-**/
-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;
-}
-
-/**
- This heuristic consider both stright and disagonal moves,
- But has a separate cost for diagonal moves.
-**/
-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;
-
- d1 = normalize(preprev - point);
- d2 = normalize(prev - point);
- m = vlen(d1-d2);
-
- return h * m;
-}
-
-
-float pathlib_h_diagonal3(vector a,vector b)
-{
- float h_diag,h_str,h,x,y,z;
-
- 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);
-
- return h;
-}
+++ /dev/null
-#include "pathlib.qh"
-
-MODEL(SQUARE, "models/pathlib/square.md3");
-MODEL(SQUARE_GOOD, "models/pathlib/goodsquare.md3");
-MODEL(SQUARE_BAD, "models/pathlib/badsquare.md3");
-MODEL(EDGE, "models/pathlib/edge.md3");
-
-#ifdef TURRET_DEBUG
-void mark_error(vector where,float lifetime);
-void mark_info(vector where,float lifetime);
-entity mark_misc(vector where,float lifetime);
-#endif
-
-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()
-{SELFPARAM();
- pathlib_showpath(self);
- self.nextthink = time + 1;
-}
-
-void __showpath2_think()
-{SELFPARAM();
- #ifdef TURRET_DEBUG
- mark_info(self.origin,1);
- #endif
- 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;
-}
-
-
-void pathlib_showsquare2(entity node ,vector ncolor,float align)
-{
-
- node.alpha = 0.25;
- node.scale = pathlib_gridsize / 512.001;
- node.solid = SOLID_NOT;
-
- setmodel(node, MDL_SQUARE);
- setorigin(node,node.origin);
- node.colormod = ncolor;
-
- if(align)
- {
- traceline(node.origin + '0 0 32', node.origin - '0 0 128', MOVE_WORLDONLY, node);
- node.angles = vectoangles(trace_plane_normal);
- node.angles_x -= 90;
- }
-}
-
-void SUB_Remove();
-
-void pathlib_showsquare(vector where,float goodsquare,float _lifetime)
-{
- entity s;
-
- if(!_lifetime)
- _lifetime = time + 30;
- else
- _lifetime += time;
-
- s = spawn();
- s.alpha = 0.25;
- s.think = SUB_Remove;
- s.nextthink = _lifetime;
- s.scale = pathlib_gridsize / 512.001;
- s.solid = SOLID_NOT;
-
- setmodel(s, goodsquare ? MDL_SQUARE_GOOD : MDL_SQUARE_BAD);
-
- traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,s);
-
- s.angles = vectoangles(trace_plane_normal);
- s.angles_x -= 90;
- setorigin(s,where);
-}
-
-void pathlib_showedge(vector where,float _lifetime,float rot)
-{
- entity e;
-
- if(!_lifetime)
- _lifetime = time + 30;
- else
- _lifetime += time;
-
- e = spawn();
- e.alpha = 0.25;
- e.think = SUB_Remove;
- e.nextthink = _lifetime;
- e.scale = pathlib_gridsize / 512;
- e.solid = SOLID_NOT;
- setorigin(e,where);
- setmodel(e, MDL_EDGE);
- //traceline(where + '0 0 32',where - '0 0 128',MOVE_WORLDONLY,e);
- //e.angles = vectoangles(trace_plane_normal);
- e.angles_y = rot;
- //e.angles_x += 90;
-
-}
+++ /dev/null
-#include "pathlib.qh"
-#include "utility.qh"
-
-vector plib_points2[8];
-vector plib_points[8];
-float plib_fvals[8];
-
-float pathlib_expandnode_starf(entity node, vector start, vector goal)
-{
- vector where,f,r,t;
- float fc,c;
- entity nap;
-
- where = node.origin;
-
- f = PLIB_FORWARD * pathlib_gridsize;
- r = PLIB_RIGHT * pathlib_gridsize;
-
- // Forward
- plib_points[0] = where + f;
-
- // Back
- plib_points[1] = where - f;
-
- // Right
- plib_points[2] = where + r;
-
- // Left
- plib_points[3] = where - r;
-
- // Forward-right
- plib_points[4] = where + f + r;
-
- // Forward-left
- plib_points[5] = where + f - r;
-
- // Back-right
- plib_points[6] = where - f + r;
-
- // Back-left
- plib_points[7] = where - f - r;
-
- for(int i=0;i < 8; ++i)
- {
- t = plib_points[i];
- fc = pathlib_heuristic(t,goal) + pathlib_cost(node, t, pathlib_gridsize);
- plib_fvals[i] = fc;
-
- }
-
- fc = plib_fvals[0];
- plib_points2[0] = plib_points[0];
- vector bp;
- bp = plib_points[0];
- int fc2 = 0;
- for(int i = 0; i < 8; ++i)
- {
- c = 0;
- nap = pathlib_nodeatpoint(plib_points[i]);
- if(nap)
- if(nap.owner == openlist)
- c = 1;
- else
- c = 1;
-
- if(c)
- if(plib_fvals[i] < fc)
- {
- bp = plib_points[i];
- fc = plib_fvals[i];
- plib_points2[fc2] = plib_points[i];
- ++fc2;
- }
-
- /*
- nap = pathlib_nodeatpoint(plib_points[i]);
- if(nap)
- if not nap.owner == closedlist)
- {
- }
- */
- }
-
- pathlib_makenode(node, start, bp, goal, pathlib_gridsize);
-
- for(int i = 0; i < 3; ++i)
- {
- pathlib_makenode(node, start, plib_points2[i], goal, pathlib_gridsize);
- }
-
- return pathlib_open_cnt;
-}
-
-float pathlib_expandnode_star(entity node, vector start, vector goal)
-{
- vector point, where, f, r;
-
- where = node.origin;
-
- f = PLIB_FORWARD * pathlib_gridsize;
- r = PLIB_RIGHT * pathlib_gridsize;
-
- if (node.pathlib_node_edgeflags == pathlib_node_edgeflag_unknown)
- node.pathlib_node_edgeflags = tile_check_plus2(node.origin);
-
- if(node.pathlib_node_edgeflags == pathlib_node_edgeflag_none)
- {
- LOG_TRACE("Node at ", vtos(node.origin), " not expanable");
- return pathlib_open_cnt;
- }
-
- // Forward
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forward)
- {
- point = where + f;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
- }
-
- // Back
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_back)
- {
- point = where - f;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
- }
-
- // Right
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_right)
- {
- point = where + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
- }
-
- // Left
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_left)
- {
- point = where - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- }
-
- // Forward-right
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forwardright)
- {
- point = where + f + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
- }
-
- // Forward-left
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_forwardleft)
- {
- point = where + f - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
-
- }
-
- // Back-right
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_backright)
- {
- point = where - f + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
- }
-
- // Back-left
- if (node.pathlib_node_edgeflags & pathlib_node_edgeflag_backleft)
- {
- point = where - f - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost_diag);
- }
-
- return pathlib_open_cnt;
-}
-
-float pathlib_expandnode_octagon(entity node, vector start, vector goal)
-{
- vector point,where,f,r;
-
- where = node.origin;
-
- f = PLIB_FORWARD * pathlib_gridsize;
- r = PLIB_RIGHT * pathlib_gridsize;
-
- // Forward
- point = where + f;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- // Back
- point = where - f;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- // Right
- point = where + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- // Left
- point = where - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- f = PLIB_FORWARD * pathlib_gridsize * 0.5;
- r = PLIB_RIGHT * pathlib_gridsize * 0.5;
-
- // Forward-right
- point = where + f + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
-
- // Forward-left
- point = where + f - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
-
- // Back-right
- point = where - f + r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- // Back-left
- point = where - f - r;
- pathlib_makenode(node, start, point, goal, pathlib_movecost);
-
- 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;
-}
+++ /dev/null
-#include "../_all.qh"
-
-#include "pathlib.qh"
-#include "utility.qh"
-#include "../command/common.qh"
-
-void pathlib_deletepath(entity start)
-{
- entity e;
-
- e = findchainentity(owner, start);
- while(e)
- {
- e.think = SUB_Remove;
- e.nextthink = time;
- e = e.chain;
- }
-}
-
-//#define PATHLIB_NODEEXPIRE 0.05
-const float PATHLIB_NODEEXPIRE = 20;
-
-void dumpnode(entity n)
-{
- n.is_path_node = false;
- n.think = SUB_Remove;
- n.nextthink = time;
-}
-
-entity pathlib_mknode(vector where,entity parent)
-{
- entity node;
-
- node = pathlib_nodeatpoint(where);
- if(node)
- {
- #ifdef TURRET_DEBUG
- mark_error(where, 60);
- #endif
- return node;
- }
-
- node = spawn();
-
- node.think = SUB_Remove;
- node.nextthink = time + PATHLIB_NODEEXPIRE;
- node.is_path_node = true;
- node.owner = openlist;
- node.path_prev = parent;
-
-
- setsize(node, '0 0 0', '0 0 0');
-
- setorigin(node, where);
- node.medium = pointcontents(where);
- pathlib_showsquare(where, 1 ,15);
-
- ++pathlib_made_cnt;
- ++pathlib_open_cnt;
-
- return node;
-}
-
-float pathlib_makenode_adaptive(entity parent,vector start, vector to, vector goal,float cost)
-{
- entity node;
- float h,g,f,doedge = 0;
- vector where;
-
- ++pathlib_searched_cnt;
-
- if(inwater(parent.origin))
- {
- LOG_TRACE("FromWater\n");
- pathlib_expandnode = pathlib_expandnode_box;
- pathlib_movenode = pathlib_swimnode;
- }
- else
- {
- if(inwater(to))
- {
- LOG_TRACE("ToWater\n");
- pathlib_expandnode = pathlib_expandnode_box;
- pathlib_movenode = pathlib_walknode;
- }
- else
- {
- LOG_TRACE("LandToLoand\n");
- //if(edge_check(parent.origin))
- // return 0;
-
- pathlib_expandnode = pathlib_expandnode_star;
- pathlib_movenode = pathlib_walknode;
- doedge = 1;
- }
- }
-
- node = pathlib_nodeatpoint(to);
- if(node)
- {
- LOG_TRACE("NodeAtPoint\n");
- ++pathlib_merge_cnt;
-
- if(node.owner == openlist)
- {
- h = pathlib_heuristic(node.origin,goal);
- g = pathlib_cost(parent,node.origin,cost);
- f = g + h;
-
- 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 (!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;
- }
-
- where = pathlib_movenode(parent.origin, to, 0);
-
- if (!pathlib_movenode_goodnode)
- {
- //pathlib_showsquare(where, 0 ,30);
- //pathlib_showsquare(parent.origin, 1 ,30);
- LOG_TRACE("pathlib_movenode_goodnode = 0\n");
- return 0;
- }
-
- //pathlib_showsquare(where, 1 ,30);
-
- if(pathlib_nodeatpoint(where))
- {
- LOG_TRACE("NAP WHERE :",vtos(where),"\n");
- LOG_TRACE("not NAP TO:",vtos(to),"\n");
- LOG_TRACE("NAP-NNAP:",ftos(vlen(to-where)),"\n\n");
- return 0;
- }
-
-
- if(doedge)
- if (!tile_check(where))
- {
- LOG_TRACE("tile_check fail\n");
- pathlib_showsquare(where, 0 ,30);
- return 0;
- }
-
-
- h = pathlib_heuristic(where,goal);
- g = pathlib_cost(parent,where,cost);
- f = g + h;
-
- /*
- node = findradius(where,pathlib_gridsize * 0.5);
- while(node)
- {
- if(node.is_path_node == true)
- {
- ++pathlib_merge_cnt;
- if(node.owner == openlist)
- {
- if(node.pathlib_node_g > g)
- {
- //pathlib_movenode(where,node.origin,0);
- //if(pathlib_movenode_goodnode)
- //{
- //mark_error(node.origin + '0 0 128',30);
- node.pathlib_node_h = h;
- node.pathlib_node_g = g;
- node.pathlib_node_f = f;
- node.path_prev = parent;
- //}
- }
-
- if (!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 (!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)
- {
- LOG_TRACE("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)
- {
- vector goalmove;
-
- goalmove = pathlib_walknode(node.origin,goal,1);
- if(pathlib_movenode_goodnode)
- {
- goal_node = node;
- pathlib_foundgoal = true;
- }
- }
-}
-
-void pathlib_cleanup()
-{
- best_open_node = world;
-
- //return;
-
- entity node;
-
- node = findfloat(world,is_path_node, true);
- while(node)
- {
- /*
- node.owner = openlist;
- node.pathlib_node_g = 0;
- node.pathlib_node_h = 0;
- node.pathlib_node_f = 0;
- node.path_prev = world;
- */
-
- dumpnode(node);
- node = findfloat(node,is_path_node, true);
- }
-
- if(openlist)
- remove(openlist);
-
- if(closedlist)
- remove(closedlist);
-
- openlist = world;
- closedlist = world;
-
-}
-
-float Cosine_Interpolate(float a, float b, float x)
-{
- float ft,f;
-
- ft = x * 3.1415927;
- f = (1 - cos(ft)) * 0.5;
-
- return a*(1-f) + b*f;
-}
-
-float buildpath_nodefilter_directional(vector n,vector c,vector p)
-{
- vector d1,d2;
-
- d2 = normalize(p - c);
- d1 = normalize(c - n);
-
- if(vlen(d1-d2) < 0.25)
- {
- //mark_error(c,30);
- return 1;
- }
- //mark_info(c,30);
- return 0;
-}
-
-float buildpath_nodefilter_moveskip(vector n,vector c,vector p)
-{
- pathlib_walknode(p,n,1);
- if(pathlib_movenode_goodnode)
- return 1;
-
- return 0;
-}
-
-float buildpath_nodefilter_none(vector n,vector c,vector p)
-{
- return 0;
-}
-
-entity path_build(entity next, vector where, entity prev, entity start)
-{
- entity path;
-
- if(prev && next)
- if(buildpath_nodefilter)
- if(buildpath_nodefilter(next.origin,where,prev.origin))
- return next;
-
-
- path = spawn();
- path.owner = start;
- path.path_next = next;
-
- setorigin(path,where);
-
- if(!next)
- path.classname = "path_end";
- else
- {
- if(!prev)
- path.classname = "path_start";
- else
- path.classname = "path_node";
- }
-
- return path;
-}
-
-entity pathlib_astar(vector from,vector to)
-{SELFPARAM();
- entity path, start, end, open, n, ln;
- float ptime, ftime, ctime;
-
- ptime = gettime(GETTIME_REALTIME);
- pathlib_starttime = ptime;
-
- pathlib_cleanup();
-
- // Select water<->land capable node make/link
- pathlib_makenode = pathlib_makenode_adaptive;
-
- // Select XYZ cost estimate
- //pathlib_heuristic = pathlib_h_diagonal3;
- pathlib_heuristic = pathlib_h_diagonal;
-
- // Select distance + waterfactor cost
- pathlib_cost = pathlib_g_euclidean_water;
-
- // Select star expander
- pathlib_expandnode = pathlib_expandnode_star;
-
- // Select walk simulation movement test
- pathlib_movenode = pathlib_walknode;
-
- // Filter final nodes by direction
- buildpath_nodefilter = buildpath_nodefilter_directional;
-
- // Filter tiles with cross pattern
- tile_check = tile_check_cross;
-
- // If the start is in water we need diffrent settings
- if(inwater(from))
- {
- // Select volumetric node expaner
- pathlib_expandnode = pathlib_expandnode_box;
-
- // Water movement test
- pathlib_movenode = pathlib_swimnode;
- }
-
- if (!openlist)
- openlist = spawn();
-
- if (!closedlist)
- closedlist = spawn();
-
- pathlib_closed_cnt = 0;
- pathlib_open_cnt = 0;
- pathlib_made_cnt = 0;
- pathlib_merge_cnt = 0;
- pathlib_searched_cnt = 0;
- pathlib_bestopen_seached = 0;
- pathlib_bestcash_hits = 0;
- pathlib_bestcash_saved = 0;
-
- pathlib_gridsize = 128;
- pathlib_movecost = pathlib_gridsize;
- pathlib_movecost_diag = vlen(('1 1 0' * pathlib_gridsize));
- pathlib_movecost_waterfactor = 25000000;
- pathlib_foundgoal = 0;
-
- movenode_boxmax = self.maxs * 1.1;
- movenode_boxmin = self.mins * 1.1;
-
- movenode_stepsize = pathlib_gridsize * 0.25;
-
- tile_check_size = pathlib_gridsize * 0.5;
- tile_check_up = '0 0 2' * pathlib_gridsize;
- tile_check_up = '0 0 128';
- tile_check_down = '0 0 3' * pathlib_gridsize;
- tile_check_down = '0 0 256';
-
- //movenode_stepup = '0 0 128';
- movenode_stepup = '0 0 36';
- movenode_maxdrop = '0 0 512';
- //movenode_maxdrop = '0 0 512';
- movenode_boxup = '0 0 72';
-
- from.x = fsnap(from.x, pathlib_gridsize);
- from.y = fsnap(from.y, pathlib_gridsize);
- //from_z += 32;
-
- to.x = fsnap(to.x, pathlib_gridsize);
- to.y = fsnap(to.y, pathlib_gridsize);
- //to_z += 32;
-
- LOG_TRACE("AStar init\n");
- path = pathlib_mknode(from, world);
- pathlib_close_node(path, to);
- if(pathlib_foundgoal)
- {
- LOG_TRACE("AStar: Goal found on first node!\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)
- {
- LOG_TRACE("AStar path 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);
-
- while(pathlib_open_cnt)
- {
- if((gettime(GETTIME_REALTIME) - pathlib_starttime) > pathlib_maxtime)
- {
- LOG_TRACE("Path took to long to compute!\n");
- LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
- LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
- LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
- LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\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(n,from,to);
-
- if(pathlib_foundgoal)
- {
- LOG_TRACE("Target found. Rebuilding and filtering path...\n");
- ftime = gettime(GETTIME_REALTIME);
- ptime = ftime - ptime;
-
- start = path_build(world,path.origin,world,world);
- end = path_build(world,goal_node.origin,world,start);
- ln = end;
-
- open = goal_node;
- for(open = goal_node; open.path_prev != path; open = open.path_prev)
- {
- n = path_build(ln,open.origin,open.path_prev,start);
- ln.path_prev = n;
- ln = n;
- }
- start.path_next = n;
- n.path_prev = start;
- ftime = gettime(GETTIME_REALTIME) - ftime;
-
- ctime = gettime(GETTIME_REALTIME);
- pathlib_cleanup();
- ctime = gettime(GETTIME_REALTIME) - ctime;
-
-
-#ifdef DEBUGPATHING
- pathlib_showpath2(start);
-
- LOG_TRACE("Time used - pathfinding: ", ftos(ptime),"\n");
- LOG_TRACE("Time used - rebuild & filter: ", ftos(ftime),"\n");
- LOG_TRACE("Time used - cleanup: ", ftos(ctime),"\n");
- LOG_TRACE("Time used - total: ", ftos(ptime + ftime + ctime),"\n");
- LOG_TRACE("Time used - # frames: ", ftos(ceil((ptime + ftime + ctime) / sys_frametime)),"\n\n");
- LOG_TRACE("Nodes - created: ", ftos(pathlib_made_cnt),"\n");
- LOG_TRACE("Nodes - open: ", ftos(pathlib_open_cnt),"\n");
- LOG_TRACE("Nodes - merged: ", ftos(pathlib_merge_cnt),"\n");
- LOG_TRACE("Nodes - closed: ", ftos(pathlib_closed_cnt),"\n");
- LOG_TRACE("Nodes - searched: ", ftos(pathlib_searched_cnt),"\n");
- LOG_TRACE("Nodes bestopen searched: ", ftos(pathlib_bestopen_seached),"\n");
- LOG_TRACE("Nodes bestcash - hits: ", ftos(pathlib_bestcash_hits),"\n");
- LOG_TRACE("Nodes bestcash - save: ", ftos(pathlib_bestcash_saved),"\n");
- LOG_TRACE("AStar done.\n");
-#endif
- return start;
- }
- }
-
- LOG_TRACE("A* Faild to find a path! Try a smaller gridsize.\n");
-
- pathlib_cleanup();
-
- return world;
-}
+++ /dev/null
-#ifndef PATHLIB_MAIN_H
-#define PATHLIB_MAIN_H
-float buildpath_nodefilter_none(vector n,vector c,vector p);
-entity path_build(entity next, vector where, entity prev, entity start);
-#endif
+++ /dev/null
-#include "../_all.qh"
-
-#include "pathlib.qh"
-#include "utility.qh"
-
-vector pathlib_wateroutnode(vector start,vector end, float doedge)
-{SELFPARAM();
- 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 (!(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;
- }
-
- if(pointcontents(surface + '0 0 1') != CONTENT_EMPTY)
- return end;
-
- tracebox(start + '0 0 64', movenode_boxmin,movenode_boxmax, end + '0 0 64', MOVE_WORLDONLY, self);
- if(trace_fraction == 1)
- pathlib_movenode_goodnode = 1;
-
- if(fabs(surface.z - end.z) > 32)
- pathlib_movenode_goodnode = 0;
-
- return end;
-}
-
-vector pathlib_swimnode(vector start,vector end, float doedge)
-{SELFPARAM();
- 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, doedge);
-
- tracebox(start, movenode_boxmin,movenode_boxmax, end, MOVE_WORLDONLY, self);
- if(trace_fraction == 1)
- pathlib_movenode_goodnode = 1;
-
- return end;
-}
-
-vector pathlib_flynode(vector start,vector end, float doedge)
-{SELFPARAM();
- pathlib_movenode_goodnode = 0;
-
- end.x = fsnap(end.x, pathlib_gridsize);
- end.y = fsnap(end.y, pathlib_gridsize);
-
- tracebox(start, movenode_boxmin,movenode_boxmax, end, MOVE_WORLDONLY, self);
- if(trace_fraction == 1)
- pathlib_movenode_goodnode = 1;
-
- return end;
-}
-
-void a_think()
-{SELFPARAM();
- te_lightning1(self,self.origin, self.pos1);
- if(self.cnt < time)
- remove(self);
- else
- self.nextthink = time + 0.2;
-}
-
-vector pathlib_walknode(vector start,vector end,float doedge)
-{SELFPARAM();
- vector direction,point,last_point,s,e;
- float steps, distance, i;
-
- LOG_TRACE("Walking node from ", vtos(start), " to ", vtos(end), "\n");
-
- pathlib_movenode_goodnode = 0;
-
- end.x = fsnap(end.x,pathlib_gridsize);
- end.y = fsnap(end.y,pathlib_gridsize);
- start.x = fsnap(start.x,pathlib_gridsize);
- start.y = fsnap(start.y,pathlib_gridsize);
-
- // Find the floor
- traceline(start + movenode_stepup, start - movenode_maxdrop, MOVE_WORLDONLY, self);
- if(trace_fraction == 1.0)
- {
- entity a;
- a = spawn();
- a.think = a_think;
- a.nextthink = time;
- setorigin(a,start + movenode_stepup);
- a.pos1 = trace_endpos;
- //start - movenode_maxdrop
- a.cnt = time + 10;
-
- LOG_TRACE("I cant walk on air!\n");
- return trace_endpos;
- }
-
- start = trace_endpos;
-
- // Find the direcion, without Z
- s = start; e = end;
- //e_z = 0; s_z = 0;
- direction = normalize(e - s);
-
- distance = vlen(start - end);
- steps = rint(distance / movenode_stepsize);
-
- last_point = start;
- for(i = 1; i < steps; ++i)
- {
- point = last_point + (direction * movenode_stepsize);
- traceline(point + movenode_stepup,point - movenode_maxdrop,MOVE_WORLDONLY,self);
- if(trace_fraction == 1.0)
- return trace_endpos;
-
- last_point = trace_endpos;
- }
-
- point = last_point + (direction * movenode_stepsize);
- point.x = fsnap(point.x,pathlib_gridsize);
- point.y = fsnap(point.y,pathlib_gridsize);
-
- //dprint("end_x: ",ftos(end_x), " end_y: ",ftos(end_y),"\n");
- //dprint("point_x:",ftos(point_x)," point_y:",ftos(point_y),"\n\n");
-
- traceline(point + movenode_stepup, point - movenode_maxdrop,MOVE_WORLDONLY,self);
- if(trace_fraction == 1.0)
- return trace_endpos;
-
- last_point = trace_endpos;
-
- tracebox(start + movenode_boxup, movenode_boxmin,movenode_boxmax, last_point + movenode_boxup, MOVE_WORLDONLY, self);
- if(trace_fraction != 1.0)
- return trace_endpos;
-
- pathlib_movenode_goodnode = 1;
- return last_point;
-}
+++ /dev/null
-#include "pathlib.qh"
-#include "main.qh"
-
-var float pathlib_wpp_open(entity wp, entity child, float cost);
-
-void pathlib_wpp_close(entity wp)
-{
- --pathlib_open_cnt;
- ++pathlib_closed_cnt;
-
- wp.pathlib_list = closedlist;
-
- if(wp == best_open_node)
- best_open_node = world;
-
- if(wp == goal_node)
- pathlib_foundgoal = true;
-}
-
-float pathlib_wpp_opencb(entity wp, entity child, float cost)
-{
-
- if(child.pathlib_list == closedlist)
- return false;
-
- // FIXME! wp.wp##mincost is NOT distance. Make it distance or add a field for distance to be used here (for better speed)
- cost = vlen(child.origin - wp.origin);
-
- child.path_prev = wp;
- child.pathlib_list = openlist;
- child.pathlib_node_g = wp.pathlib_node_g + cost;
- child.pathlib_node_h = pathlib_heuristic(child.origin, goal_node.origin);
- child.pathlib_node_c = pathlib_wpp_waypointcallback(child, wp);
- child.pathlib_node_f = child.pathlib_node_g + child.pathlib_node_h + child.pathlib_node_c;
-
-
- if(child == goal_node)
- pathlib_foundgoal = true;
-
- ++pathlib_open_cnt;
-
- if(best_open_node.pathlib_node_f > child.pathlib_node_f)
- best_open_node = child;
-
- return true;
-}
-
-float pathlib_wpp_openncb(entity wp, entity child, float cost)
-{
-
- if(child.pathlib_list == closedlist)
- return false;
-
- // FIXME! wp.wp##mincost is NOT distance. Make it distance or add a field for distance to be used here (for better speed)
- cost = vlen(child.origin - wp.origin);
-
- child.path_prev = wp;
- child.pathlib_list = openlist;
- child.pathlib_node_g = wp.pathlib_node_g + cost;
- child.pathlib_node_h = pathlib_heuristic(child.origin, goal_node.origin);
- child.pathlib_node_f = child.pathlib_node_g + child.pathlib_node_h;
-
- if(child == goal_node)
- pathlib_foundgoal = true;
-
- ++pathlib_open_cnt;
-
- if(best_open_node.pathlib_node_f > child.pathlib_node_f)
- best_open_node = child;
-
- return true;
-}
-
-float pathlib_wpp_expand(entity wp)
-{
- if(wp.wp00) pathlib_wpp_open(wp,wp.wp00,wp.wp00mincost); else return 0;
- if(wp.wp01) pathlib_wpp_open(wp,wp.wp01,wp.wp01mincost); else return 1;
- if(wp.wp02) pathlib_wpp_open(wp,wp.wp02,wp.wp02mincost); else return 2;
- if(wp.wp03) pathlib_wpp_open(wp,wp.wp03,wp.wp03mincost); else return 3;
- if(wp.wp04) pathlib_wpp_open(wp,wp.wp04,wp.wp04mincost); else return 4;
- if(wp.wp05) pathlib_wpp_open(wp,wp.wp05,wp.wp05mincost); else return 5;
- if(wp.wp06) pathlib_wpp_open(wp,wp.wp06,wp.wp06mincost); else return 6;
- if(wp.wp07) pathlib_wpp_open(wp,wp.wp07,wp.wp07mincost); else return 7;
- if(wp.wp08) pathlib_wpp_open(wp,wp.wp08,wp.wp08mincost); else return 8;
- if(wp.wp09) pathlib_wpp_open(wp,wp.wp09,wp.wp09mincost); else return 9;
- if(wp.wp10) pathlib_wpp_open(wp,wp.wp10,wp.wp10mincost); else return 10;
- if(wp.wp11) pathlib_wpp_open(wp,wp.wp11,wp.wp11mincost); else return 11;
- if(wp.wp12) pathlib_wpp_open(wp,wp.wp12,wp.wp12mincost); else return 12;
- if(wp.wp13) pathlib_wpp_open(wp,wp.wp13,wp.wp13mincost); else return 13;
- if(wp.wp14) pathlib_wpp_open(wp,wp.wp14,wp.wp14mincost); else return 14;
- if(wp.wp15) pathlib_wpp_open(wp,wp.wp15,wp.wp15mincost); else return 15;
- if(wp.wp16) pathlib_wpp_open(wp,wp.wp16,wp.wp16mincost); else return 16;
- if(wp.wp17) pathlib_wpp_open(wp,wp.wp17,wp.wp17mincost); else return 17;
- if(wp.wp18) pathlib_wpp_open(wp,wp.wp18,wp.wp18mincost); else return 18;
- if(wp.wp19) pathlib_wpp_open(wp,wp.wp19,wp.wp19mincost); else return 19;
- if(wp.wp20) pathlib_wpp_open(wp,wp.wp20,wp.wp20mincost); else return 20;
- if(wp.wp21) pathlib_wpp_open(wp,wp.wp21,wp.wp21mincost); else return 21;
- if(wp.wp22) pathlib_wpp_open(wp,wp.wp22,wp.wp22mincost); else return 22;
- if(wp.wp23) pathlib_wpp_open(wp,wp.wp23,wp.wp23mincost); else return 23;
- if(wp.wp24) pathlib_wpp_open(wp,wp.wp24,wp.wp24mincost); else return 24;
- if(wp.wp25) pathlib_wpp_open(wp,wp.wp25,wp.wp25mincost); else return 25;
- if(wp.wp26) pathlib_wpp_open(wp,wp.wp26,wp.wp26mincost); else return 26;
- if(wp.wp27) pathlib_wpp_open(wp,wp.wp27,wp.wp27mincost); else return 27;
- if(wp.wp28) pathlib_wpp_open(wp,wp.wp28,wp.wp28mincost); else return 28;
- if(wp.wp29) pathlib_wpp_open(wp,wp.wp29,wp.wp29mincost); else return 29;
- if(wp.wp30) pathlib_wpp_open(wp,wp.wp30,wp.wp30mincost); else return 30;
- if(wp.wp31) pathlib_wpp_open(wp,wp.wp31,wp.wp31mincost); else return 31;
-
- return 32;
-}
-
-entity pathlib_wpp_bestopen()
-{
- entity n, best;
-
- if(best_open_node)
- return best_open_node;
-
- n = findchainentity(pathlib_list, openlist);
- best = n;
- while(n)
- {
- if(n.pathlib_node_f < best.pathlib_node_f)
- best = n;
-
- n = n.chain;
- }
-
- return best;
-
-}
-
-entity pathlib_waypointpath(entity wp_from, entity wp_to, float callback)
-{
- entity n;
- float ptime;
-
- ptime = gettime(GETTIME_REALTIME);
- pathlib_starttime = ptime;
- pathlib_movecost = 300;
- pathlib_movecost_diag = vlen('1 1 0' * pathlib_movecost);
-
- if (!pathlib_wpp_waypointcallback)
- callback = false;
-
- if (callback)
- pathlib_wpp_open = pathlib_wpp_opencb;
- else
- pathlib_wpp_open = pathlib_wpp_openncb;
-
- pathlib_heuristic = pathlib_h_none;
-
- if (!openlist)
- openlist = spawn();
-
- if (!closedlist)
- closedlist = spawn();
-
- pathlib_closed_cnt = 0;
- pathlib_open_cnt = 0;
- pathlib_searched_cnt = 0;
- pathlib_foundgoal = false;
-
- LOG_TRACE("pathlib_waypointpath init\n");
-
- // Initialize waypoint grid
- // FIXME! presisted chain for better preformance
- for(n = findchain(classname, "waypoint"); n; n = n.chain)
- {
- n.pathlib_list = world;
- n.pathlib_node_g = 0;
- n.pathlib_node_f = 0;
- n.pathlib_node_h = 0;
-
- //setmodel(n, "models/runematch/rune.mdl");
- //n.effects = EF_LOWPRECISION;
- //n.colormod = '0 0 0';
- //n.scale = 1;
-
- }
-
- goal_node = wp_to;
- start_node = wp_from;
-
- start_node.pathlib_list = closedlist;
- LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(start_node))," links\n");
- if(pathlib_open_cnt <= 0)
- {
- LOG_TRACE("pathlib_waypointpath: Start waypoint not linked! aborting.\n");
- return world;
- }
-
- return world;
-}
-
-entity pathlib_waypointpath_step()
-{
- entity n;
-
- n = pathlib_wpp_bestopen();
- if(!n)
- {
- LOG_TRACE("Cannot find best open node, abort.\n");
- return world;
- }
- pathlib_wpp_close(n);
- LOG_TRACE("Expanding ",ftos(pathlib_wpp_expand(n))," links\n");
-
- if(pathlib_foundgoal)
- {
- entity start, end, open, ln;
-
- LOG_TRACE("Target found. Rebuilding and filtering path...\n");
-
- buildpath_nodefilter = buildpath_nodefilter_none;
- start = path_build(world, start_node.origin, world, world);
- end = path_build(world, goal_node.origin, world, start);
- ln = end;
-
- for(open = goal_node; open.path_prev != start_node; open = open.path_prev)
- {
- n = path_build(ln,open.origin,open.path_prev,start);
- ln.path_prev = n;
- ln = n;
- }
- start.path_next = n;
- n.path_prev = start;
-
- return start;
- }
-
- return world;
-}
-void plas_think()
-{SELFPARAM();
- pathlib_waypointpath_step();
- if(pathlib_foundgoal)
- return;
- self.nextthink = time + 0.1;
-}
-
-void pathlib_waypointpath_autostep()
-{
- entity n;
- n = spawn();
- n.think = plas_think;
- n.nextthink = time + 0.1;
-}
+++ /dev/null
-#ifndef PATHLIB_H
-#define PATHLIB_H
-
-.entity pathlib_list;
-.entity path_next;
-.entity path_prev;
-
-#define inwater(point) (pointcontents(point) == CONTENT_WATER)
-#define medium spawnshieldtime
-
-const vector PLIB_FORWARD = '0 1 0';
-//#define PLIB_BACK '0 -1 0'
-const vector PLIB_RIGHT = '1 0 0';
-//#define PLIB_LEFT '-1 0 0'
-
-#define DEBUGPATHING
-#ifdef DEBUGPATHING
-void pathlib_showpath(entity start);
-void pathlib_showpath2(entity path);
-#endif
-
-entity openlist;
-entity closedlist;
-
-entity goal_node;
-entity start_node;
-
-.float is_path_node;
-.float pathlib_node_g;
-.float pathlib_node_h;
-.float pathlib_node_f;
-.float pathlib_node_c;
-
-const float pathlib_node_edgeflag_unknown = 0;
-const float pathlib_node_edgeflag_left = 2;
-const float pathlib_node_edgeflag_right = 4;
-const float pathlib_node_edgeflag_forward = 8;
-const float pathlib_node_edgeflag_back = 16;
-const float pathlib_node_edgeflag_backleft = 32;
-const float pathlib_node_edgeflag_backright = 64;
-const float pathlib_node_edgeflag_forwardleft = 128;
-const float pathlib_node_edgeflag_forwardright = 256;
-const float pathlib_node_edgeflag_none = 512;
-.float pathlib_node_edgeflags;
-
-float pathlib_open_cnt;
-float pathlib_closed_cnt;
-float pathlib_made_cnt;
-float pathlib_merge_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_foundgoal;
-
-float pathlib_starttime;
-const float pathlib_maxtime = 60;
-
-entity best_open_node;
-
-vector tile_check_up;
-vector tile_check_down;
-float tile_check_size;
-float tile_check_cross(vector where);
-float tile_check_plus(vector where);
-float tile_check_star(vector where);
-var float tile_check(vector where);
-
-float movenode_stepsize;
-vector movenode_stepup;
-vector movenode_maxdrop;
-vector movenode_boxup;
-vector movenode_boxmax;
-vector movenode_boxmin;
-float pathlib_movenode_goodnode;
-
-vector pathlib_wateroutnode(vector start, vector end, float doedge);
-vector pathlib_swimnode(vector start, vector end, float doedge);
-vector pathlib_flynode(vector start, vector end, float doedge);
-vector pathlib_walknode(vector start, vector end, float doedge);
-var vector pathlib_movenode(vector start, vector end, float doedge);
-
-float pathlib_expandnode_star(entity node, vector start, vector goal);
-float pathlib_expandnode_box(entity node, vector start, vector goal);
-float pathlib_expandnode_octagon(entity node, vector start, vector goal);
-var float pathlib_expandnode(entity node, vector start, vector goal);
-
-float pathlib_g_static(entity parent, vector to, float static_cost);
-float pathlib_g_static_water(entity parent, vector to, float static_cost);
-float pathlib_g_euclidean(entity parent, vector to, float static_cost);
-float pathlib_g_euclidean_water(entity parent, vector to, float static_cost);
-var float pathlib_cost(entity parent, vector to, float static_cost);
-
-float pathlib_h_manhattan(vector a, vector b);
-float pathlib_h_diagonal(vector a, vector b);
-float pathlib_h_euclidean(vector a,vector b);
-float pathlib_h_diagonal2(vector a, vector b);
-float pathlib_h_diagonal3(vector a, vector b);
-float pathlib_h_diagonal2sdp(vector preprev, vector prev, vector point, vector end);
-float pathlib_h_none(vector preprev, vector prev) { return 0; }
-var float pathlib_heuristic(vector from, vector to);
-
-var float pathlib_makenode(entity parent,vector start, vector to, vector goal,float cost);
-var float buildpath_nodefilter(vector n,vector c,vector p);
-
-var float pathlib_wpp_waypointcallback(entity wp, entity wp_prev);
-
-#ifdef DEBUGPATHING
- #include "debug.qc"
-#endif
-
-#endif
+++ /dev/null
-#include "utility.qh"
-
-#include "pathlib.qh"
-
-float location_isok(vector point, float water_isok, float air_isok)
-{
- float pc,pc2;
-
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
- return 0;
-
- pc = pointcontents(point);
- pc2 = pointcontents(point - '0 0 1');
-
- switch(pc)
- {
- case CONTENT_SOLID:
- break;
-
- case CONTENT_SLIME:
- break;
-
- case CONTENT_LAVA:
- break;
-
- case CONTENT_SKY:
- break;
-
- case CONTENT_EMPTY:
- if (pc2 == CONTENT_SOLID)
- return 1;
-
- if (pc2 == CONTENT_EMPTY)
- if(air_isok)
- return 1;
-
- if (pc2 == CONTENT_WATER)
- if(water_isok)
- return 1;
-
- break;
-
- case CONTENT_WATER:
- if (water_isok)
- return 1;
-
- break;
- }
-
- return 0;
-}
-
-entity pathlib_nodeatpoint(vector where)
-{
- entity node;
-
- ++pathlib_searched_cnt;
-
- where.x = fsnap(where.x,pathlib_gridsize);
- where.y = fsnap(where.y,pathlib_gridsize);
-
- node = findradius(where,pathlib_gridsize * 0.5);
- while(node)
- {
- if(node.is_path_node == true)
- return node;
-
- node = node.chain;
- }
-
- return world;
-}
-
-float tile_check_cross(vector where)
-{SELFPARAM();
- vector p,f,r;
-
- f = PLIB_FORWARD * tile_check_size;
- r = PLIB_RIGHT * tile_check_size;
-
-
- // forward-right
- p = where + f + r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (!location_isok(trace_endpos, 1, 0))
- return 0;
-
- // Forward-left
- p = where + f - r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (!location_isok(trace_endpos, 1, 0))
- return 0;
-
- // Back-right
- p = where - f + r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (!location_isok(trace_endpos, 1 ,0))
- return 0;
-
- //Back-left
- p = where - f - r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (!location_isok(trace_endpos, 1, 0))
- return 0;
-
- return 1;
-}
-
-float tile_check_plus(vector where)
-{SELFPARAM();
- vector p,f,r;
-
- f = PLIB_FORWARD * tile_check_size;
- r = PLIB_RIGHT * tile_check_size;
-
- // forward
- p = where + f;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (!location_isok(trace_endpos,1,0))
- return 0;
-
-
- //left
- p = where - r;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (!location_isok(trace_endpos,1,0))
- return 0;
-
- // Right
- p = where + r;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (!location_isok(trace_endpos,1,0))
- return 0;
-
- //Back
- p = where - f;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (!location_isok(trace_endpos,1,0))
- return 0;
-
- return 1;
-}
-
-float tile_check_plus2(vector where)
-{SELFPARAM();
- vector p,f,r;
- float i = 0, e = 0;
-
- f = PLIB_FORWARD * pathlib_gridsize;
- r = PLIB_RIGHT * pathlib_gridsize;
-
-//#define pathlib_node_edgeflag_left 2
-//#define pathlib_node_edgeflag_right 4
-//#define pathlib_node_edgeflag_forward 8
-//#define pathlib_node_edgeflag_back 16
-
- // forward
- p = where + f;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (location_isok(trace_endpos,1,0))
- {
- ++i;
- e |= pathlib_node_edgeflag_forward;
- }
-
-
- //left
- p = where - r;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (location_isok(trace_endpos,1,0))
- {
- ++i;
- e |= pathlib_node_edgeflag_left;
- }
-
-
- // Right
- p = where + r;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (location_isok(trace_endpos,1,0))
- {
- ++i;
- e |= pathlib_node_edgeflag_right;
- }
-
- //Back
- p = where - f;
- traceline(p+tile_check_up,p-tile_check_down,MOVE_WORLDONLY,self);
- if (location_isok(trace_endpos,1,0))
- {
- ++i;
- e |= pathlib_node_edgeflag_back;
- }
-
- // forward-right
- p = where + f + r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (location_isok(trace_endpos, 1, 0))
- {
- ++i;
- e |= pathlib_node_edgeflag_forwardright;
- }
-
- // Forward-left
- p = where + f - r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (location_isok(trace_endpos, 1, 0))
- {
- ++i;
- e |= pathlib_node_edgeflag_forwardleft;
- }
-
- // Back-right
- p = where - f + r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (location_isok(trace_endpos, 1 ,0))
- {
- ++i;
- e |= pathlib_node_edgeflag_backright;
- }
-
- //Back-left
- p = where - f - r;
- traceline(p + tile_check_up, p - tile_check_down, MOVE_WORLDONLY, self);
- if (location_isok(trace_endpos, 1, 0))
- {
- ++i;
- e |= pathlib_node_edgeflag_backleft;
- }
-
-
- if(i == 0)
- e = pathlib_node_edgeflag_none;
-
- return e;
-}
-
-float tile_check_star(vector where)
-{
- if(tile_check_plus(where))
- return tile_check_cross(where);
-
- return 0;
-}
-
+++ /dev/null
-#ifndef PATHLIB_UTILITY
-#define PATHLIB_UTILITY
-float fsnap(float val,float fsize);
-entity pathlib_nodeatpoint(vector where);
-float tile_check_plus2(vector where);
-#endif
#include "../lib/_all.inc"
+#include "bot/lib/steerlib/steerlib.qh"
+
#include "anticheat.qc"
#include "antilag.qc"
#include "campaign.qc"
#include "item_key.qc"
#include "mapvoting.qc"
#include "miscfunctions.qc"
-#include "movelib.qc"
#include "playerdemo.qc"
#include "portals.qc"
#include "race.qc"
#include "scores.qc"
#include "scores_rules.qc"
#include "spawnpoints.qc"
-#include "steerlib.qc"
#include "sv_main.qc"
#include "teamplay.qc"
+
+#include "bot/lib/all.inc"
+
#include "t_halflife.qc"
#include "t_items.qc"
#include "t_quake3.qc"
#include "mutators/mutators_include.qc"
#include "mutators/mutators.qc"
-#include "pathlib/costs.qc"
-#include "pathlib/expandnode.qc"
-#include "pathlib/main.qc"
-#include "pathlib/movenode.qc"
-#include "pathlib/path_waypoint.qc"
-#include "pathlib/utility.qc"
-
#include "weapons/accuracy.qc"
#include "weapons/common.qc"
#include "weapons/csqcprojectile.qc" // TODO
+++ /dev/null
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
-#endif
-
-/**
- Uniform pull towards a point
-**/
-vector steerlib_pull(vector point)
-{SELFPARAM();
- return normalize(point - self.origin);
-}
-
-/**
- Uniform push from a point
-**/
-#define steerlib_push(point) normalize(self.origin - point)
-/*
-vector steerlib_push(vector point)
-{
- return normalize(self.origin - point);
-}
-*/
-/**
- Pull toward a point, The further away, the stronger the pull.
-**/
-vector steerlib_arrive(vector point,float maximal_distance)
-{SELFPARAM();
- float distance;
- vector direction;
-
- distance = bound(0.001,vlen(self.origin - point),maximal_distance);
- direction = normalize(point - self.origin);
- return direction * (distance / maximal_distance);
-}
-
-/**
- Pull toward a point increasing the pull the closer we get
-**/
-vector steerlib_attract(vector point, float maximal_distance)
-{SELFPARAM();
- float distance;
- vector direction;
-
- distance = bound(0.001,vlen(self.origin - point),maximal_distance);
- direction = normalize(point - self.origin);
-
- return direction * (1-(distance / maximal_distance));
-}
-
-vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense)
-{SELFPARAM();
- float distance;
- vector direction;
- float influense;
-
- distance = bound(0.00001,vlen(self.origin - point),max_distance);
- direction = normalize(point - self.origin);
-
- influense = 1 - (distance / max_distance);
- influense = min_influense + (influense * (max_influense - min_influense));
-
- return direction * influense;
-}
-
-/*
-vector steerlib_attract2(vector point, float maximal_distance,float min_influense,float max_influense,float distance)
-{
- //float distance;
- vector current_direction;
- vector target_direction;
- float i_target,i_current;
-
- if(!distance)
- distance = vlen(self.origin - point);
-
- distance = bound(0.001,distance,maximal_distance);
-
- target_direction = normalize(point - self.origin);
- current_direction = normalize(self.velocity);
-
- i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
- i_current = 1 - i_target;
-
- // i_target = bound(min_influense,(1-(distance / maximal_distance)),max_influense);
-
- string s;
- s = ftos(i_target);
- bprint("IT: ",s,"\n");
- s = ftos(i_current);
- bprint("IC : ",s,"\n");
-
- return normalize((target_direction * i_target) + (current_direction * i_current));
-}
-*/
-/**
- Move away from a point.
-**/
-vector steerlib_repell(vector point,float maximal_distance)
-{SELFPARAM();
- float distance;
- vector direction;
-
- distance = bound(0.001,vlen(self.origin - point),maximal_distance);
- direction = normalize(self.origin - point);
-
- return direction * (1-(distance / maximal_distance));
-}
-
-/**
- Try to keep at ideal_distance away from point
-**/
-vector steerlib_standoff(vector point,float ideal_distance)
-{SELFPARAM();
- float distance;
- vector direction;
-
- distance = vlen(self.origin - point);
-
-
- if(distance < ideal_distance)
- {
- direction = normalize(self.origin - point);
- return direction * (distance / ideal_distance);
- }
-
- direction = normalize(point - self.origin);
- return direction * (ideal_distance / distance);
-
-}
-
-/**
- A random heading in a forward halfcicrle
-
- use like:
- self.target = steerlib_wander(256,32,self.target)
-
- where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
-**/
-vector steerlib_wander(float range,float tresh,vector oldpoint)
-{SELFPARAM();
- vector wander_point;
- wander_point = v_forward - oldpoint;
-
- if (vlen(wander_point) > tresh)
- return oldpoint;
-
- range = bound(0,range,1);
-
- wander_point = self.origin + v_forward * 128;
- wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
-
- return normalize(wander_point - self.origin);
-}
-
-/**
- Dodge a point. dont work to well.
-**/
-vector steerlib_dodge(vector point,vector dodge_dir,float min_distance)
-{SELFPARAM();
- float distance;
-
- distance = max(vlen(self.origin - point),min_distance);
- if (min_distance < distance)
- return '0 0 0';
-
- return dodge_dir * (min_distance/distance);
-}
-
-/**
- flocking by .flock_id
- Group will move towards the unified direction while keeping close to eachother.
-**/
-.float flock_id;
-vector steerlib_flock(float _radius, float standoff,float separation_force,float flock_force)
-{SELFPARAM();
- entity flock_member;
- vector push = '0 0 0', pull = '0 0 0';
- float ccount = 0;
-
- flock_member = findradius(self.origin, _radius);
- while(flock_member)
- {
- if(flock_member != self)
- if(flock_member.flock_id == self.flock_id)
- {
- ++ccount;
- push = push + (steerlib_repell(flock_member.origin,standoff) * separation_force);
- pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity, _radius) * flock_force);
- }
- flock_member = flock_member.chain;
- }
- return push + (pull* (1 / ccount));
-}
-
-/**
- flocking by .flock_id
- Group will move towards the unified direction while keeping close to eachother.
- xy only version (for ground movers).
-**/
-vector steerlib_flock2d(float _radius, float standoff,float separation_force,float flock_force)
-{SELFPARAM();
- entity flock_member;
- vector push = '0 0 0', pull = '0 0 0';
- float ccount = 0;
-
- flock_member = findradius(self.origin,_radius);
- while(flock_member)
- {
- if(flock_member != self)
- if(flock_member.flock_id == self.flock_id)
- {
- ++ccount;
- push = push + (steerlib_repell(flock_member.origin, standoff) * separation_force);
- pull = pull + (steerlib_arrive(flock_member.origin + flock_member.velocity, _radius) * flock_force);
- }
- flock_member = flock_member.chain;
- }
-
- push.z = 0;
- pull.z = 0;
-
- return push + (pull * (1 / ccount));
-}
-
-/**
- All members want to be in the center, and keep away from eachother.
- The furtehr form the center the more they want to be there.
-
- This results in a aligned movement (?!) much like flocking.
-**/
-vector steerlib_swarm(float _radius, float standoff,float separation_force,float swarm_force)
-{SELFPARAM();
- entity swarm_member;
- vector force = '0 0 0', center = '0 0 0';
- float ccount = 0;
-
- swarm_member = findradius(self.origin,_radius);
-
- while(swarm_member)
- {
- if(swarm_member.flock_id == self.flock_id)
- {
- ++ccount;
- center = center + swarm_member.origin;
- force = force + (steerlib_repell(swarm_member.origin,standoff) * separation_force);
- }
- swarm_member = swarm_member.chain;
- }
-
- center = center * (1 / ccount);
- force = force + (steerlib_arrive(center,_radius) * swarm_force);
-
- return force;
-}
-
-/**
- Steer towards the direction least obstructed.
- Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
- You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
-**/
-vector steerlib_traceavoid(float pitch,float length)
-{SELFPARAM();
- vector vup_left,vup_right,vdown_left,vdown_right;
- float fup_left,fup_right,fdown_left,fdown_right;
- vector upwish,downwish,leftwish,rightwish;
- vector v_left,v_down;
-
-
- v_left = v_right * -1;
- v_down = v_up * -1;
-
- vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
- traceline(self.origin, self.origin + vup_left,MOVE_NOMONSTERS,self);
- fup_left = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
-
- vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
- traceline(self.origin,self.origin + vup_right ,MOVE_NOMONSTERS,self);
- fup_right = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
-
- vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
- traceline(self.origin,self.origin + vdown_left,MOVE_NOMONSTERS,self);
- fdown_left = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
-
- vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
- traceline(self.origin,self.origin + vdown_right,MOVE_NOMONSTERS,self);
- fdown_right = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
- upwish = v_up * (fup_left + fup_right);
- downwish = v_down * (fdown_left + fdown_right);
- leftwish = v_left * (fup_left + fdown_left);
- rightwish = v_right * (fup_right + fdown_right);
-
- return (upwish+leftwish+downwish+rightwish) * 0.25;
-
-}
-
-/**
- Steer towards the direction least obstructed.
- Run tracelines in a forward trident, bias each direction negative if something is found there.
-**/
-vector steerlib_traceavoid_flat(float pitch, float length, vector vofs)
-{SELFPARAM();
- vector vt_left, vt_right,vt_front;
- float f_left, f_right,f_front;
- vector leftwish, rightwish,frontwish, v_left;
-
- v_left = v_right * -1;
-
-
- vt_front = v_forward * length;
- traceline(self.origin + vofs, self.origin + vofs + vt_front,MOVE_NOMONSTERS,self);
- f_front = trace_fraction;
-
- vt_left = (v_forward + (v_left * pitch)) * length;
- traceline(self.origin + vofs, self.origin + vofs + vt_left,MOVE_NOMONSTERS,self);
- f_left = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
-
- vt_right = (v_forward + (v_right * pitch)) * length;
- traceline(self.origin + vofs, self.origin + vofs + vt_right ,MOVE_NOMONSTERS,self);
- f_right = trace_fraction;
-
- //te_lightning1(world,self.origin, trace_endpos);
-
- leftwish = v_left * f_left;
- rightwish = v_right * f_right;
- frontwish = v_forward * f_front;
-
- return normalize(leftwish + rightwish + frontwish);
-}
-
-float beamsweep_badpoint(vector point,float waterok)
-{
- float pc,pc2;
-
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
- return 1;
-
- pc = pointcontents(point);
- pc2 = pointcontents(point - '0 0 1');
-
- switch(pc)
- {
- case CONTENT_SOLID: break;
- case CONTENT_SLIME: break;
- case CONTENT_LAVA: break;
-
- case CONTENT_SKY:
- return 1;
-
- case CONTENT_EMPTY:
- if (pc2 == CONTENT_SOLID)
- return 0;
-
- if (pc2 == CONTENT_WATER)
- if(waterok)
- return 0;
-
- break;
-
- case CONTENT_WATER:
- if(waterok)
- return 0;
-
- break;
- }
-
- return 1;
-}
-
-//#define BEAMSTEER_VISUAL
-float beamsweep(vector from, vector dir,float length, float step,float step_up, float step_down)
-{SELFPARAM();
- float i;
- vector a,b,u,d;
-
- u = '0 0 1' * step_up;
- d = '0 0 1' * step_down;
-
- traceline(from + u, from - d,MOVE_NORMAL,self);
- if(trace_fraction == 1.0)
- return 0;
-
- if(beamsweep_badpoint(trace_endpos,0))
- return 0;
-
- a = trace_endpos;
- for(i = 0; i < length; i += step)
- {
-
- b = a + dir * step;
- tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,self);
- if(trace_fraction != 1.0)
- return i / length;
-
- traceline(b + u, b - d,MOVE_NORMAL,self);
- if(trace_fraction == 1.0)
- return i / length;
-
- if(beamsweep_badpoint(trace_endpos,0))
- return i / length;
-#ifdef BEAMSTEER_VISUAL
- te_lightning1(world,a+u,b+u);
- te_lightning1(world,b+u,b-d);
-#endif
- a = trace_endpos;
- }
-
- return 1;
-}
-
-vector steerlib_beamsteer(vector dir, float length, float step, float step_up, float step_down)
-{SELFPARAM();
- float bm_forward, bm_right, bm_left,p;
- vector vr,vl;
-
- dir.z *= 0.15;
- vr = vectoangles(dir);
- //vr_x *= -1;
-
- tracebox(self.origin + '0 0 1' * step_up, self.mins, self.maxs, ('0 0 1' * step_up) + self.origin + (dir * length), MOVE_NOMONSTERS, self);
- if(trace_fraction == 1.0)
- {
- //te_lightning1(self,self.origin,self.origin + (dir * length));
- return dir;
- }
-
-
-
-
- makevectors(vr);
- bm_forward = beamsweep(self.origin, v_forward, length, step, step_up, step_down);
-
- vr = normalize(v_forward + v_right * 0.125);
- vl = normalize(v_forward - v_right * 0.125);
-
- bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
- bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
-
-
- p = bm_left + bm_right;
- if(p == 2)
- {
- //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
- //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
-
- return v_forward;
- }
-
- p = 2 - p;
-
- vr = normalize(v_forward + v_right * p);
- vl = normalize(v_forward - v_right * p);
- bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
- bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
-
-
- if(bm_left + bm_right < 0.15)
- {
- vr = normalize((v_forward*-1) + v_right * 0.75);
- vl = normalize((v_forward*-1) - v_right * 0.75);
-
- bm_right = beamsweep(self.origin, vr, length, step, step_up, step_down);
- bm_left = beamsweep(self.origin, vl, length, step, step_up, step_down);
- }
-
- //te_lightning1(self,self.origin + '0 0 32',self.origin + '0 0 32' + vr * length);
- //te_lightning1(self.tur_head,self.origin + '0 0 32',self.origin + '0 0 32' + vl * length);
-
- bm_forward *= bm_forward;
- bm_right *= bm_right;
- bm_left *= bm_left;
-
- vr = vr * bm_right;
- vl = vl * bm_left;
-
- return normalize(vr + vl);
-
-}
-
-
-//////////////////////////////////////////////
-// Testting //
-// Everything below this point is a mess :D //
-//////////////////////////////////////////////
-//#define TLIBS_TETSLIBS
-#ifdef TLIBS_TETSLIBS
-void flocker_die()
-{SELFPARAM();
- Send_Effect(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
-
- self.owner.cnt += 1;
- self.owner = world;
-
- self.nextthink = time;
- self.think = SUB_Remove;
-}
-
-
-void flocker_think()
-{SELFPARAM();
- vector dodgemove,swarmmove;
- vector reprellmove,wandermove,newmove;
-
- self.angles_x = self.angles.x * -1;
- makevectors(self.angles);
- self.angles_x = self.angles.x * -1;
-
- dodgemove = steerlib_traceavoid(0.35,1000);
- swarmmove = steerlib_flock(500,75,700,500);
- reprellmove = steerlib_repell(self.owner.enemy.origin+self.enemy.velocity,2000) * 700;
-
- if(vlen(dodgemove) == 0)
- {
- self.pos1 = steerlib_wander(0.5,0.1,self.pos1);
- wandermove = self.pos1 * 50;
- }
- else
- self.pos1 = normalize(self.velocity);
-
- dodgemove = dodgemove * vlen(self.velocity) * 5;
-
- newmove = swarmmove + reprellmove + wandermove + dodgemove;
- self.velocity = movelib_inertmove_byspeed(newmove,300,0.2,0.9);
- //self.velocity = movelib_inertmove(dodgemove,0.65);
-
- self.velocity = movelib_dragvec(0.01,0.6);
-
- self.angles = vectoangles(self.velocity);
-
- if(self.health <= 0)
- flocker_die();
- else
- self.nextthink = time + 0.1;
-}
-
-MODEL(FLOCKER, "models/turrets/rocket.md3");
-
-void spawn_flocker()
-{SELFPARAM();
- entity flocker;
-
- flocker = spawn ();
-
- setorigin(flocker, self.origin + '0 0 32');
- setmodel (flocker, MDL_FLOCKER);
- setsize (flocker, '-3 -3 -3', '3 3 3');
-
- flocker.flock_id = self.flock_id;
- flocker.classname = "flocker";
- flocker.owner = self;
- flocker.think = flocker_think;
- flocker.nextthink = time + random() * 5;
- PROJECTILE_MAKETRIGGER(flocker);
- flocker.movetype = MOVETYPE_BOUNCEMISSILE;
- flocker.effects = EF_LOWPRECISION;
- flocker.velocity = randomvec() * 300;
- flocker.angles = vectoangles(flocker.velocity);
- flocker.health = 10;
- flocker.pos1 = normalize(flocker.velocity + randomvec() * 0.1);
-
- self.cnt = self.cnt -1;
-
-}
-
-void flockerspawn_think()
-{SELFPARAM();
-
-
- if(self.cnt > 0)
- spawn_flocker();
-
- self.nextthink = time + self.delay;
-
-}
-
-void flocker_hunter_think()
-{SELFPARAM();
- vector dodgemove,attractmove,newmove;
- entity e,ee;
- float d,bd;
-
- self.angles_x = self.angles.x * -1;
- makevectors(self.angles);
- self.angles_x = self.angles.x * -1;
-
- if(self.enemy)
- if(vlen(self.enemy.origin - self.origin) < 64)
- {
- ee = self.enemy;
- ee.health = -1;
- self.enemy = world;
-
- }
-
- if(!self.enemy)
- {
- e = findchainfloat(flock_id,self.flock_id);
- while(e)
- {
- d = vlen(self.origin - e.origin);
-
- if(e != self.owner)
- if(e != ee)
- if(d > bd)
- {
- self.enemy = e;
- bd = d;
- }
- e = e.chain;
- }
- }
-
- if(self.enemy)
- attractmove = steerlib_attract(self.enemy.origin+self.enemy.velocity * 0.1,5000) * 1250;
- else
- attractmove = normalize(self.velocity) * 200;
-
- dodgemove = steerlib_traceavoid(0.35,1500) * vlen(self.velocity);
-
- newmove = dodgemove + attractmove;
- self.velocity = movelib_inertmove_byspeed(newmove,1250,0.3,0.7);
- self.velocity = movelib_dragvec(0.01,0.5);
-
-
- self.angles = vectoangles(self.velocity);
- self.nextthink = time + 0.1;
-}
-
-
-float globflockcnt;
-spawnfunc(flockerspawn)
-{SELFPARAM();
- ++globflockcnt;
-
- if(!self.cnt) self.cnt = 20;
- if(!self.delay) self.delay = 0.25;
- if(!self.flock_id) self.flock_id = globflockcnt;
-
- self.think = flockerspawn_think;
- self.nextthink = time + 0.25;
-
- self.enemy = spawn();
-
- setmodel(self.enemy, MDL_FLOCKER);
- setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
-
- self.enemy.classname = "FLock Hunter";
- self.enemy.scale = 3;
- self.enemy.effects = EF_LOWPRECISION;
- self.enemy.movetype = MOVETYPE_BOUNCEMISSILE;
- PROJECTILE_MAKETRIGGER(self.enemy);
- self.enemy.think = flocker_hunter_think;
- self.enemy.nextthink = time + 10;
- self.enemy.flock_id = self.flock_id;
- self.enemy.owner = self;
-}
-#endif
-
-
-
+++ /dev/null
-#ifndef STEERLIB_H
-#define STEERLIB_H
-
-.vector steerto;
-
-vector steerlib_arrive(vector point,float maximal_distance);
-vector steerlib_attract2(vector point, float min_influense,float max_distance,float max_influense);
-vector steerlib_pull(vector point);
-
-#endif