From: TimePath Date: Wed, 7 Oct 2015 23:56:13 +0000 (+1100) Subject: Bots: move supporting code into bot directory X-Git-Tag: xonotic-v0.8.2~1849^2 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=dd3c7bd110ff27b62d6c8ee82cd25f51fc4b5a49;p=xonotic%2Fxonotic-data.pk3dir.git Bots: move supporting code into bot directory --- diff --git a/qcsrc/client/movelib.qc b/qcsrc/client/movelib.qc deleted file mode 100644 index 074f146dc..000000000 --- a/qcsrc/client/movelib.qc +++ /dev/null @@ -1 +0,0 @@ -#include "../server/movelib.qc" diff --git a/qcsrc/client/movelib.qh b/qcsrc/client/movelib.qh deleted file mode 100644 index a0634f6de..000000000 --- a/qcsrc/client/movelib.qh +++ /dev/null @@ -1 +0,0 @@ -#include "../server/movelib.qh" diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index ec5c31844..4a10ef196 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -19,7 +19,6 @@ #include "mapvoting.qc" #include "miscfunctions.qc" #include "modeleffects.qc" -#include "movelib.qc" #include "particles.qc" #include "player_skeleton.qc" #include "rubble.qc" @@ -51,6 +50,8 @@ #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" diff --git a/qcsrc/common/monsters/monster/zombie.qc b/qcsrc/common/monsters/monster/zombie.qc index 8425a123a..05f466621 100644 --- a/qcsrc/common/monsters/monster/zombie.qc +++ b/qcsrc/common/monsters/monster/zombie.qc @@ -27,6 +27,7 @@ REGISTER_MONSTER(ZOMBIE, NEW(Zombie)) { #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; diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index 8b05f781d..75837cf1a 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -14,7 +14,6 @@ #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" diff --git a/qcsrc/common/turrets/turret/walker.qc b/qcsrc/common/turrets/turret/walker.qc index e629ada79..4a5ed2fc8 100644 --- a/qcsrc/common/turrets/turret/walker.qc +++ b/qcsrc/common/turrets/turret/walker.qc @@ -631,7 +631,7 @@ spawnfunc(turret_walker) { if(!turret_initialize(TUR_WALKER)) remove(self); } #endif // SVQC #ifdef CSQC -#include "../../../client/movelib.qh" +#include "../../../server/bot/lib/movelib/movelib.qh" void walker_draw(entity this) { diff --git a/qcsrc/dpdefs/csprogsdefs.qh b/qcsrc/dpdefs/csprogsdefs.qh index 6ad27242a..0daa5dce3 100644 --- a/qcsrc/dpdefs/csprogsdefs.qh +++ b/qcsrc/dpdefs/csprogsdefs.qh @@ -23,6 +23,8 @@ #undef particleeffectnum #undef setmodel +entity(.entity fld, entity match) findchainentity = #403; + #pragma noref 0 #define ReadFloat() ReadCoord() diff --git a/qcsrc/server/bot/default/navigation.qc b/qcsrc/server/bot/default/navigation.qc index fb196fcc3..8898b7163 100644 --- a/qcsrc/server/bot/default/navigation.qc +++ b/qcsrc/server/bot/default/navigation.qc @@ -1,6 +1,6 @@ #include "navigation.qh" -#include "../common/triggers/trigger/jumppads.qh" +#include "../../../common/triggers/trigger/jumppads.qh" void bot_debug(string input) { diff --git a/qcsrc/server/bot/impl.qc b/qcsrc/server/bot/impl.qc index 9f36c4f67..c0b6c8716 100644 --- a/qcsrc/server/bot/impl.qc +++ b/qcsrc/server/bot/impl.qc @@ -1,3 +1,5 @@ #include "api.qh" +#include "lib/all.inc" + #include "default/all.inc" diff --git a/qcsrc/server/bot/lib/all.inc b/qcsrc/server/bot/lib/all.inc new file mode 100644 index 000000000..9a92a9616 --- /dev/null +++ b/qcsrc/server/bot/lib/all.inc @@ -0,0 +1,10 @@ +#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 diff --git a/qcsrc/server/bot/lib/movelib/all.inc b/qcsrc/server/bot/lib/movelib/all.inc new file mode 100644 index 000000000..c12ce90ef --- /dev/null +++ b/qcsrc/server/bot/lib/movelib/all.inc @@ -0,0 +1 @@ +#include "movelib.qc" diff --git a/qcsrc/server/bot/lib/movelib/movelib.qc b/qcsrc/server/bot/lib/movelib/movelib.qc new file mode 100644 index 000000000..acacba093 --- /dev/null +++ b/qcsrc/server/bot/lib/movelib/movelib.qc @@ -0,0 +1,237 @@ +#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); +} + diff --git a/qcsrc/server/bot/lib/movelib/movelib.qh b/qcsrc/server/bot/lib/movelib/movelib.qh new file mode 100644 index 000000000..8a4bfd488 --- /dev/null +++ b/qcsrc/server/bot/lib/movelib/movelib.qh @@ -0,0 +1,53 @@ +#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 diff --git a/qcsrc/server/bot/lib/pathlib/all.inc b/qcsrc/server/bot/lib/pathlib/all.inc new file mode 100644 index 000000000..8622734d0 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/all.inc @@ -0,0 +1,6 @@ +#include "costs.qc" +#include "expandnode.qc" +#include "main.qc" +#include "movenode.qc" +#include "path_waypoint.qc" +#include "utility.qc" diff --git a/qcsrc/server/bot/lib/pathlib/costs.qc b/qcsrc/server/bot/lib/pathlib/costs.qc new file mode 100644 index 000000000..eb885a4f5 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/costs.qc @@ -0,0 +1,146 @@ +#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; +} diff --git a/qcsrc/server/bot/lib/pathlib/debug.qc b/qcsrc/server/bot/lib/pathlib/debug.qc new file mode 100644 index 000000000..37e167aae --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/debug.qc @@ -0,0 +1,123 @@ +#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; + +} diff --git a/qcsrc/server/bot/lib/pathlib/expandnode.qc b/qcsrc/server/bot/lib/pathlib/expandnode.qc new file mode 100644 index 000000000..1f095a785 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/expandnode.qc @@ -0,0 +1,235 @@ +#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; +} diff --git a/qcsrc/server/bot/lib/pathlib/main.qc b/qcsrc/server/bot/lib/pathlib/main.qc new file mode 100644 index 000000000..39e23bd0b --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/main.qc @@ -0,0 +1,566 @@ +#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; +} diff --git a/qcsrc/server/bot/lib/pathlib/main.qh b/qcsrc/server/bot/lib/pathlib/main.qh new file mode 100644 index 000000000..177c432cf --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/main.qh @@ -0,0 +1,5 @@ +#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 diff --git a/qcsrc/server/bot/lib/pathlib/movenode.qc b/qcsrc/server/bot/lib/pathlib/movenode.qc new file mode 100644 index 000000000..5326a746d --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/movenode.qc @@ -0,0 +1,152 @@ +#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; +} diff --git a/qcsrc/server/bot/lib/pathlib/path_waypoint.qc b/qcsrc/server/bot/lib/pathlib/path_waypoint.qc new file mode 100644 index 000000000..615840d51 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/path_waypoint.qc @@ -0,0 +1,248 @@ +#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; +} diff --git a/qcsrc/server/bot/lib/pathlib/pathlib.qh b/qcsrc/server/bot/lib/pathlib/pathlib.qh new file mode 100644 index 000000000..dbf785266 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/pathlib.qh @@ -0,0 +1,116 @@ +#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 diff --git a/qcsrc/server/bot/lib/pathlib/utility.qc b/qcsrc/server/bot/lib/pathlib/utility.qc new file mode 100644 index 000000000..9028f85e4 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/utility.qc @@ -0,0 +1,245 @@ +#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; +} + diff --git a/qcsrc/server/bot/lib/pathlib/utility.qh b/qcsrc/server/bot/lib/pathlib/utility.qh new file mode 100644 index 000000000..bf72549a0 --- /dev/null +++ b/qcsrc/server/bot/lib/pathlib/utility.qh @@ -0,0 +1,6 @@ +#ifndef PATHLIB_UTILITY +#define PATHLIB_UTILITY +float fsnap(float val,float fsize); +entity pathlib_nodeatpoint(vector where); +float tile_check_plus2(vector where); +#endif diff --git a/qcsrc/server/bot/lib/steerlib/all.inc b/qcsrc/server/bot/lib/steerlib/all.inc new file mode 100644 index 000000000..9e802b586 --- /dev/null +++ b/qcsrc/server/bot/lib/steerlib/all.inc @@ -0,0 +1 @@ +#include "steerlib.qc" diff --git a/qcsrc/server/bot/lib/steerlib/steerlib.qc b/qcsrc/server/bot/lib/steerlib/steerlib.qc new file mode 100644 index 000000000..23b847373 --- /dev/null +++ b/qcsrc/server/bot/lib/steerlib/steerlib.qc @@ -0,0 +1,665 @@ +/** + 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 + + + diff --git a/qcsrc/server/bot/lib/steerlib/steerlib.qh b/qcsrc/server/bot/lib/steerlib/steerlib.qh new file mode 100644 index 000000000..fcd35ba78 --- /dev/null +++ b/qcsrc/server/bot/lib/steerlib/steerlib.qh @@ -0,0 +1,10 @@ +#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 diff --git a/qcsrc/server/movelib.qc b/qcsrc/server/movelib.qc deleted file mode 100644 index acacba093..000000000 --- a/qcsrc/server/movelib.qc +++ /dev/null @@ -1,237 +0,0 @@ -#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); -} - diff --git a/qcsrc/server/movelib.qh b/qcsrc/server/movelib.qh deleted file mode 100644 index 8a4bfd488..000000000 --- a/qcsrc/server/movelib.qh +++ /dev/null @@ -1,53 +0,0 @@ -#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 diff --git a/qcsrc/server/mutators/mutators_include.qc b/qcsrc/server/mutators/mutators_include.qc index 8564d34c5..67bb246b0 100644 --- a/qcsrc/server/mutators/mutators_include.qc +++ b/qcsrc/server/mutators/mutators_include.qc @@ -70,7 +70,6 @@ #include "../playerdemo.qh" #include "../round_handler.qh" #include "../item_key.qh" - #include "../pathlib/pathlib.qh" #include "../../common/vehicles/all.qh" #endif diff --git a/qcsrc/server/pathlib/costs.qc b/qcsrc/server/pathlib/costs.qc deleted file mode 100644 index 3e452f66e..000000000 --- a/qcsrc/server/pathlib/costs.qc +++ /dev/null @@ -1,146 +0,0 @@ -#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; -} diff --git a/qcsrc/server/pathlib/debug.qc b/qcsrc/server/pathlib/debug.qc deleted file mode 100644 index 37e167aae..000000000 --- a/qcsrc/server/pathlib/debug.qc +++ /dev/null @@ -1,123 +0,0 @@ -#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; - -} diff --git a/qcsrc/server/pathlib/expandnode.qc b/qcsrc/server/pathlib/expandnode.qc deleted file mode 100644 index 1f095a785..000000000 --- a/qcsrc/server/pathlib/expandnode.qc +++ /dev/null @@ -1,235 +0,0 @@ -#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; -} diff --git a/qcsrc/server/pathlib/main.qc b/qcsrc/server/pathlib/main.qc deleted file mode 100644 index f097e8a0f..000000000 --- a/qcsrc/server/pathlib/main.qc +++ /dev/null @@ -1,569 +0,0 @@ -#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; -} diff --git a/qcsrc/server/pathlib/main.qh b/qcsrc/server/pathlib/main.qh deleted file mode 100644 index 177c432cf..000000000 --- a/qcsrc/server/pathlib/main.qh +++ /dev/null @@ -1,5 +0,0 @@ -#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 diff --git a/qcsrc/server/pathlib/movenode.qc b/qcsrc/server/pathlib/movenode.qc deleted file mode 100644 index 6645d7126..000000000 --- a/qcsrc/server/pathlib/movenode.qc +++ /dev/null @@ -1,154 +0,0 @@ -#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; -} diff --git a/qcsrc/server/pathlib/path_waypoint.qc b/qcsrc/server/pathlib/path_waypoint.qc deleted file mode 100644 index 615840d51..000000000 --- a/qcsrc/server/pathlib/path_waypoint.qc +++ /dev/null @@ -1,248 +0,0 @@ -#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; -} diff --git a/qcsrc/server/pathlib/pathlib.qh b/qcsrc/server/pathlib/pathlib.qh deleted file mode 100644 index dbf785266..000000000 --- a/qcsrc/server/pathlib/pathlib.qh +++ /dev/null @@ -1,116 +0,0 @@ -#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 diff --git a/qcsrc/server/pathlib/utility.qc b/qcsrc/server/pathlib/utility.qc deleted file mode 100644 index 9028f85e4..000000000 --- a/qcsrc/server/pathlib/utility.qc +++ /dev/null @@ -1,245 +0,0 @@ -#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; -} - diff --git a/qcsrc/server/pathlib/utility.qh b/qcsrc/server/pathlib/utility.qh deleted file mode 100644 index bf72549a0..000000000 --- a/qcsrc/server/pathlib/utility.qh +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PATHLIB_UTILITY -#define PATHLIB_UTILITY -float fsnap(float val,float fsize); -entity pathlib_nodeatpoint(vector where); -float tile_check_plus2(vector where); -#endif diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index 75c00833f..ad1e855e5 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -7,6 +7,8 @@ #include "../lib/_all.inc" +#include "bot/lib/steerlib/steerlib.qh" + #include "anticheat.qc" #include "antilag.qc" #include "campaign.qc" @@ -29,7 +31,6 @@ #include "item_key.qc" #include "mapvoting.qc" #include "miscfunctions.qc" -#include "movelib.qc" #include "playerdemo.qc" #include "portals.qc" #include "race.qc" @@ -37,9 +38,11 @@ #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" @@ -50,13 +53,6 @@ #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 diff --git a/qcsrc/server/steerlib.qc b/qcsrc/server/steerlib.qc deleted file mode 100644 index fbf84da32..000000000 --- a/qcsrc/server/steerlib.qc +++ /dev/null @@ -1,672 +0,0 @@ -#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 - - - diff --git a/qcsrc/server/steerlib.qh b/qcsrc/server/steerlib.qh deleted file mode 100644 index fcd35ba78..000000000 --- a/qcsrc/server/steerlib.qh +++ /dev/null @@ -1,10 +0,0 @@ -#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