summaryrefslogtreecommitdiff
path: root/src/fpsgame/waypoint.cpp
diff options
context:
space:
mode:
authorxolatile2025-08-06 22:54:55 +0200
committerxolatile2025-08-06 22:54:55 +0200
commit0a1172b75f571685c264a8b9d8ee224bbf11381f (patch)
treed041fdc68a60f0ebb48a3852bbcce6d9432f83d5 /src/fpsgame/waypoint.cpp
parentaffde05dc07a94643f1fd2751b2b441f57f73d7d (diff)
downloadxolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.xz
xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.zst
Please do not hate me, it makes sense...
Diffstat (limited to 'src/fpsgame/waypoint.cpp')
-rw-r--r--src/fpsgame/waypoint.cpp424
1 files changed, 123 insertions, 301 deletions
diff --git a/src/fpsgame/waypoint.cpp b/src/fpsgame/waypoint.cpp
index 30a1403..05afb6c 100644
--- a/src/fpsgame/waypoint.cpp
+++ b/src/fpsgame/waypoint.cpp
@@ -2,26 +2,19 @@
extern selinfo sel;
-namespace ai
-{
+namespace ai {
using namespace game;
-
vector<waypoint> waypoints;
-
- bool clipped(const vec &o)
- {
+ bool clipped(const vec &o) {
int material = lookupmaterial(o), clipmat = material&MATF_CLIP;
return clipmat == MAT_CLIP || material&MAT_DEATH;
}
-
- int getweight(const vec &o)
- {
+ int getweight(const vec &o) {
vec pos = o; pos.z += ai::JUMPMIN;
if(!insideworld(vec(pos.x, pos.y, min(pos.z, getworldsize() - 1e-3f)))) return -2;
float dist = raycube(pos, vec(0, 0, -1), 0, RAY_CLIPMAT);
int weight = 1;
- if(dist >= 0)
- {
+ if(dist >= 0) {
weight = int(dist/ai::JUMPMIN);
pos.z -= clamp(dist-8.0f, 0.0f, pos.z);
int trgmat = lookupmaterial(pos);
@@ -29,46 +22,33 @@ namespace ai
}
return weight;
}
-
- enum
- {
+ enum {
WPCACHE_STATIC = 0,
WPCACHE_DYNAMIC,
NUMWPCACHES
};
-
- struct wpcache
- {
- struct node
- {
+ struct wpcache {
+ struct node {
float split[2];
uint child[2];
-
int axis() const { return child[0]>>30; }
int childindex(int which) const { return child[which]&0x3FFFFFFF; }
bool isleaf(int which) const { return (child[1]&(1<<(30+which)))!=0; }
};
-
vector<node> nodes;
int firstwp, lastwp;
vec bbmin, bbmax;
-
wpcache() { clear(); }
-
- void clear()
- {
+ void clear() {
nodes.setsize(0);
firstwp = lastwp = -1;
bbmin = vec(1e16f, 1e16f, 1e16f);
bbmax = vec(-1e16f, -1e16f, -1e16f);
}
-
- void build(int first = 0, int last = -1)
- {
+ void build(int first = 0, int last = -1) {
if(last < 0) last = waypoints.length();
vector<int> indices;
- for(int i = first; i < last; i++)
- {
+ for(int i = first; i < last; i++) {
waypoint &w = waypoints[i];
indices.add(i);
if(firstwp < 0) firstwp = i;
@@ -77,34 +57,27 @@ namespace ai
bbmax.max(vec(w.o).add(radius));
}
if(first < last) lastwp = max(lastwp, last-1);
- if(indices.length())
- {
+ if(indices.length()) {
nodes.reserve(indices.length());
build(indices.getbuf(), indices.length(), bbmin, bbmax);
}
}
-
- void build(int *indices, int numindices, const vec &vmin, const vec &vmax)
- {
+ void build(int *indices, int numindices, const vec &vmin, const vec &vmax) {
int axis = 2;
loopk(2) if(vmax[k] - vmin[k] > vmax[axis] - vmin[axis]) axis = k;
-
vec leftmin(1e16f, 1e16f, 1e16f), leftmax(-1e16f, -1e16f, -1e16f), rightmin(1e16f, 1e16f, 1e16f), rightmax(-1e16f, -1e16f, -1e16f);
float split = 0.5f*(vmax[axis] + vmin[axis]), splitleft = -1e16f, splitright = 1e16f;
int left, right;
- for(left = 0, right = numindices; left < right;)
- {
+ for(left = 0, right = numindices; left < right;) {
waypoint &w = waypoints[indices[left]];
float radius = WAYPOINTRADIUS;
- if(max(split - (w.o[axis]-radius), 0.0f) > max((w.o[axis]+radius) - split, 0.0f))
- {
+ if(max(split - (w.o[axis]-radius), 0.0f) > max((w.o[axis]+radius) - split, 0.0f)) {
++left;
splitleft = max(splitleft, w.o[axis]+radius);
leftmin.min(vec(w.o).sub(radius));
leftmax.max(vec(w.o).add(radius));
}
- else
- {
+ else {
--right;
swap(indices[left], indices[right]);
splitright = min(splitright, w.o[axis]-radius);
@@ -112,111 +85,84 @@ namespace ai
rightmax.max(vec(w.o).add(radius));
}
}
-
- if(!left || right==numindices)
- {
+ if(!left || right==numindices) {
leftmin = rightmin = vec(1e16f, 1e16f, 1e16f);
leftmax = rightmax = vec(-1e16f, -1e16f, -1e16f);
left = right = numindices/2;
splitleft = -1e16f;
splitright = 1e16f;
- loopi(numindices)
- {
+ loopi(numindices) {
waypoint &w = waypoints[indices[i]];
float radius = WAYPOINTRADIUS;
- if(i < left)
- {
+ if(i < left) {
splitleft = max(splitleft, w.o[axis]+radius);
leftmin.min(vec(w.o).sub(radius));
leftmax.max(vec(w.o).add(radius));
}
- else
- {
+ else {
splitright = min(splitright, w.o[axis]-radius);
rightmin.min(vec(w.o).sub(radius));
rightmax.max(vec(w.o).add(radius));
}
}
}
-
int offset = nodes.length();
node &curnode = nodes.add();
curnode.split[0] = splitleft;
curnode.split[1] = splitright;
-
if(left<=1) curnode.child[0] = (axis<<30) | (left>0 ? indices[0] : 0x3FFFFFFF);
- else
- {
+ else {
curnode.child[0] = (axis<<30) | (nodes.length()-offset);
if(left) build(indices, left, leftmin, leftmax);
}
-
if(numindices-right<=1) curnode.child[1] = (1<<31) | (left<=1 ? 1<<30 : 0) | (numindices-right>0 ? indices[right] : 0x3FFFFFFF);
- else
- {
+ else {
curnode.child[1] = (left<=1 ? 1<<30 : 0) | (nodes.length()-offset);
if(numindices-right) build(&indices[right], numindices-right, rightmin, rightmax);
}
}
} wpcaches[NUMWPCACHES];
-
static int invalidatedwpcaches = 0, clearedwpcaches = (1<<NUMWPCACHES)-1, numinvalidatewpcaches = 0, lastwpcache = 0;
-
- static inline void invalidatewpcache(int wp)
- {
+ static inline void invalidatewpcache(int wp) {
if(++numinvalidatewpcaches >= 1000) { numinvalidatewpcaches = 0; invalidatedwpcaches = (1<<NUMWPCACHES)-1; }
- else
- {
+ else {
loopi(WPCACHE_DYNAMIC) if(wp >= wpcaches[i].firstwp && wp <= wpcaches[i].lastwp) { invalidatedwpcaches |= 1<<i; return; }
invalidatedwpcaches |= 1<<WPCACHE_DYNAMIC;
}
}
-
- void clearwpcache(bool full = true)
- {
+ void clearwpcache(bool full = true) {
loopi(NUMWPCACHES) if(full || invalidatedwpcaches&(1<<i)) { wpcaches[i].clear(); clearedwpcaches |= 1<<i; }
- if(full || invalidatedwpcaches == (1<<NUMWPCACHES)-1)
- {
+ if(full || invalidatedwpcaches == (1<<NUMWPCACHES)-1) {
numinvalidatewpcaches = 0;
lastwpcache = 0;
}
invalidatedwpcaches = 0;
}
ICOMMAND(clearwpcache, "", (), clearwpcache());
-
avoidset wpavoid;
-
- void buildwpcache()
- {
+ void buildwpcache() {
loopi(NUMWPCACHES) if(wpcaches[i].firstwp < 0)
wpcaches[i].build(i > 0 ? wpcaches[i-1].lastwp+1 : 1, i+1 >= NUMWPCACHES || wpcaches[i+1].firstwp < 0 ? -1 : wpcaches[i+1].firstwp);
clearedwpcaches = 0;
lastwpcache = waypoints.length();
-
wpavoid.clear();
loopv(waypoints) if(waypoints[i].weight < 0) wpavoid.avoidnear(NULL, waypoints[i].o.z + WAYPOINTRADIUS, waypoints[i].o, WAYPOINTRADIUS);
}
-
- struct wpcachestack
- {
+ struct wpcachestack {
wpcache::node *node;
float tmin, tmax;
};
-
vector<wpcache::node *> wpcachestack;
-
- int closestwaypoint(const vec &pos, float mindist, bool links, fpsent *d)
- {
+ int closestwaypoint(const vec &pos, float mindist, bool links) {
if(waypoints.empty()) return -1;
if(clearedwpcaches) buildwpcache();
-
#define CHECKCLOSEST(index) do { \
int n = (index); \
- if(n < waypoints.length()) \
- { \
+ if(n < waypoints.length()) { \
+ \
const waypoint &w = waypoints[n]; \
- if(!links || w.links[0]) \
- { \
+ if(!links || w.links[0]) { \
+ \
float dist = w.o.squaredist(pos); \
if(dist < mindist*mindist) { closest = n; mindist = sqrtf(dist); } \
} \
@@ -224,31 +170,24 @@ namespace ai
} while(0)
int closest = -1;
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= mindist)
- {
- if(dist2 < mindist)
- {
+ if(dist1 >= mindist) {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKCLOSEST(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKCLOSEST(curnode->childindex(0));
- if(dist2 < mindist)
- {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKCLOSEST(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < mindist)
- {
+ else {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKCLOSEST(curnode->childindex(1));
}
@@ -261,48 +200,38 @@ namespace ai
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKCLOSEST(i); }
return closest;
}
-
- void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results)
- {
+ void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results) {
if(waypoints.empty()) return;
if(clearedwpcaches) buildwpcache();
-
float mindist2 = mindist*mindist, maxdist2 = maxdist*maxdist;
#define CHECKWITHIN(index) do { \
int n = (index); \
- if(n < waypoints.length()) \
- { \
+ if(n < waypoints.length()) { \
+ \
const waypoint &w = waypoints[n]; \
float dist = w.o.squaredist(pos); \
if(dist > mindist2 && dist < maxdist2) results.add(n); \
} \
} while(0)
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= maxdist)
- {
- if(dist2 < maxdist)
- {
+ if(dist1 >= maxdist) {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKWITHIN(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKWITHIN(curnode->childindex(0));
- if(dist2 < maxdist)
- {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKWITHIN(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < maxdist)
- {
+ else {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKWITHIN(curnode->childindex(1));
}
@@ -314,47 +243,37 @@ namespace ai
}
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKWITHIN(i); }
}
-
- void avoidset::avoidnear(void *owner, float above, const vec &pos, float limit)
- {
+ void avoidset::avoidnear(void *owner, float above, const vec &pos, float limit) {
if(ai::waypoints.empty()) return;
if(clearedwpcaches) buildwpcache();
-
float limit2 = limit*limit;
#define CHECKNEAR(index) do { \
int n = (index); \
- if(n < ai::waypoints.length()) \
- { \
+ if(n < ai::waypoints.length()) { \
+ \
const waypoint &w = ai::waypoints[n]; \
if(w.o.squaredist(pos) < limit2) add(owner, above, n); \
} \
} while(0)
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= limit)
- {
- if(dist2 < limit)
- {
+ if(dist1 >= limit) {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKNEAR(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKNEAR(curnode->childindex(0));
- if(dist2 < limit)
- {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKNEAR(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < limit)
- {
+ else {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKNEAR(curnode->childindex(1));
}
@@ -366,27 +285,21 @@ namespace ai
}
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKNEAR(i); }
}
-
- int avoidset::remap(fpsent *d, int n, vec &pos, bool retry)
- {
- if(!obstacles.empty())
- {
+ int avoidset::remap(fpsent *d, int n, vec &pos, bool retry) {
+ if(!obstacles.empty()) {
int cur = 0;
- loopv(obstacles)
- {
+ loopv(obstacles) {
obstacle &ob = obstacles[i];
int next = cur + ob.numwaypoints;
- if(ob.owner != d)
- {
- for(; cur < next; cur++) if(waypoints[cur] == n)
- {
+ if(ob.owner != d) {
+ for(; cur < next; cur++) if(waypoints[cur] == n) {
if(ob.above < 0) return retry ? n : -1;
vec above(pos.x, pos.y, ob.above);
if(above.z-d->o.z >= ai::JUMPMAX)
return retry ? n : -1; // too much scotty
- int node = closestwaypoint(above, ai::SIGHTMIN, true, d);
- if(ai::iswaypoint(node) && node != n)
- { // try to reroute above their head?
+ int node = closestwaypoint(above, ai::SIGHTMIN, true);
+ if(ai::iswaypoint(node) && node != n) {
+ // try to reroute above their head?
if(!find(node, d))
{
pos = ai::waypoints[node].o;
@@ -394,8 +307,7 @@ namespace ai
}
else return retry ? n : -1;
}
- else
- {
+ else {
vec old = d->o;
d->o = vec(above).add(vec(0, 0, d->eyeheight));
bool col = collide(d, vec(0, 0, 1));
@@ -414,37 +326,25 @@ namespace ai
}
return n;
}
-
static inline float heapscore(waypoint *q) { return q->score(); }
-
- bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries)
- {
+ bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries) {
if(waypoints.empty() || !iswaypoint(node) || !iswaypoint(goal) || goal == node || !waypoints[node].links[0])
return false;
-
static ushort routeid = 1;
static vector<waypoint *> queue;
-
- if(!routeid)
- {
+ if(!routeid) {
loopv(waypoints) waypoints[i].route = 0;
routeid = 1;
}
-
- if(d)
- {
- if(retries <= 1 && d->ai) loopi(ai::NUMPREVNODES) if(d->ai->prevnodes[i] != node && iswaypoint(d->ai->prevnodes[i]))
- {
+ if(d) {
+ if(retries <= 1 && d->ai) loopi(ai::NUMPREVNODES) if(d->ai->prevnodes[i] != node && iswaypoint(d->ai->prevnodes[i])) {
waypoints[d->ai->prevnodes[i]].route = routeid;
waypoints[d->ai->prevnodes[i]].curscore = -1;
waypoints[d->ai->prevnodes[i]].estscore = 0;
}
- if(retries <= 0)
- {
- loopavoid(obstacles, d,
- {
- if(iswaypoint(wp) && wp != node && wp != goal && waypoints[node].find(wp) < 0 && waypoints[goal].find(wp) < 0)
- {
+ if(retries <= 0) {
+ loopavoid(obstacles, d, {
+ if(iswaypoint(wp) && wp != node && wp != goal && waypoints[node].find(wp) < 0 && waypoints[goal].find(wp) < 0) {
waypoints[wp].route = routeid;
waypoints[wp].curscore = -1;
waypoints[wp].estscore = 0;
@@ -452,34 +352,28 @@ namespace ai
});
}
}
-
waypoints[node].route = routeid;
waypoints[node].curscore = waypoints[node].estscore = 0;
waypoints[node].prev = 0;
queue.setsize(0);
queue.add(&waypoints[node]);
route.setsize(0);
-
int lowest = -1;
- while(!queue.empty())
- {
+ while(!queue.empty()) {
waypoint &m = *queue.removeheap();
float prevscore = m.curscore;
m.curscore = -1;
- loopi(MAXWAYPOINTLINKS)
- {
+ loopi(MAXWAYPOINTLINKS) {
int link = m.links[i];
if(!link) break;
- if(iswaypoint(link) && (link == node || link == goal || waypoints[link].links[0]))
- {
+ if(iswaypoint(link) && (link == node || link == goal || waypoints[link].links[0])) {
waypoint &n = waypoints[link];
int weight = max(n.weight, 1);
float curscore = prevscore + n.o.dist(m.o)*weight;
if(n.route == routeid && curscore >= n.curscore) continue;
n.curscore = curscore;
n.prev = ushort(&m - &waypoints[0]);
- if(n.route != routeid)
- {
+ if(n.route != routeid) {
n.estscore = n.o.dist(waypoints[goal].o)*weight;
if(n.estscore <= WAYPOINTRADIUS*4 && (lowest < 0 || n.estscore <= waypoints[lowest].estscore))
lowest = link;
@@ -492,92 +386,68 @@ namespace ai
}
}
foundgoal:
-
routeid++;
-
- if(lowest >= 0) // otherwise nothing got there
- {
+ if(lowest >= 0) { // otherwise nothing got there {
for(waypoint *m = &waypoints[lowest]; m > &waypoints[0]; m = &waypoints[m->prev])
route.add(m - &waypoints[0]); // just keep it stored backward
}
-
return !route.empty();
}
-
VARF(dropwaypoints, 0, 0, 1, { player1->lastnode = -1; });
-
- int addwaypoint(const vec &o, int weight = -1)
- {
+ int addwaypoint(const vec &o, int weight = -1) {
if(waypoints.length() > MAXWAYPOINTS) return -1;
int n = waypoints.length();
waypoints.add(waypoint(o, weight >= 0 ? weight : getweight(o)));
invalidatewpcache(n);
return n;
}
-
- void linkwaypoint(waypoint &a, int n)
- {
- loopi(MAXWAYPOINTLINKS)
- {
+ void linkwaypoint(waypoint &a, int n) {
+ loopi(MAXWAYPOINTLINKS) {
if(a.links[i] == n) return;
if(!a.links[i]) { a.links[i] = n; return; }
}
a.links[rnd(MAXWAYPOINTLINKS)] = n;
}
-
string loadedwaypoints = "";
-
- static inline bool shouldnavigate()
- {
+ static inline bool shouldnavigate() {
if(dropwaypoints) return true;
loopvrev(players) if(players[i]->aitype != AI_NONE) return true;
return false;
}
-
- static inline bool shoulddrop(fpsent *d)
- {
+ static inline bool shoulddrop(fpsent *d) {
return !d->ai && (dropwaypoints || !loadedwaypoints[0]);
}
-
- void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist)
- {
+ void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist) {
if(!shouldnavigate()) return;
- if(shoulddrop(d))
- {
+ if(shoulddrop(d)) {
if(waypoints.empty()) seedwaypoints();
int from = closestwaypoint(o, mindist, false), to = closestwaypoint(v, mindist, false);
if(!iswaypoint(from)) from = addwaypoint(o);
if(!iswaypoint(to)) to = addwaypoint(v);
if(d->lastnode != from && iswaypoint(d->lastnode) && iswaypoint(from))
linkwaypoint(waypoints[d->lastnode], from);
- if(iswaypoint(to))
- {
+ if(iswaypoint(to)) {
if(from != to && iswaypoint(from) && iswaypoint(to))
linkwaypoint(waypoints[from], to);
d->lastnode = to;
}
}
- else d->lastnode = closestwaypoint(v, WAYPOINTRADIUS*2, false, d);
+ else d->lastnode = closestwaypoint(v, WAYPOINTRADIUS*2, false);
}
-
- void navigate(fpsent *d)
- {
+ void navigate(fpsent *d) {
vec v(d->feetpos());
if(d->state != CS_ALIVE) { d->lastnode = -1; return; }
bool dropping = shoulddrop(d);
int mat = lookupmaterial(v);
if((mat&MATF_CLIP) == MAT_CLIP || mat&MAT_DEATH) dropping = false;
float dist = dropping ? WAYPOINTRADIUS : (d->ai ? WAYPOINTRADIUS : SIGHTMIN);
- int curnode = closestwaypoint(v, dist, false, d), prevnode = d->lastnode;
- if(!iswaypoint(curnode) && dropping)
- {
+ int curnode = closestwaypoint(v, dist, false), prevnode = d->lastnode;
+ if(!iswaypoint(curnode) && dropping) {
if(waypoints.empty()) seedwaypoints();
curnode = addwaypoint(v);
}
- if(iswaypoint(curnode))
- {
- if(dropping && d->lastnode != curnode && iswaypoint(d->lastnode))
- {
+ if(iswaypoint(curnode)) {
+ if(dropping && d->lastnode != curnode && iswaypoint(d->lastnode)) {
linkwaypoint(waypoints[d->lastnode], curnode);
if(!d->timeinair) linkwaypoint(waypoints[curnode], d->lastnode);
}
@@ -585,35 +455,26 @@ namespace ai
if(d->ai && iswaypoint(prevnode) && d->lastnode != prevnode) d->ai->addprevnode(prevnode);
}
else if(!iswaypoint(d->lastnode) || waypoints[d->lastnode].o.squaredist(v) > SIGHTMIN*SIGHTMIN)
- d->lastnode = closestwaypoint(v, SIGHTMAX, false, d);
+ d->lastnode = closestwaypoint(v, SIGHTMAX, false);
}
-
- void navigate()
- {
+ void navigate() {
if(shouldnavigate()) loopv(players) ai::navigate(players[i]);
if(invalidatedwpcaches) clearwpcache(false);
}
-
- void clearwaypoints(bool full)
- {
+ void clearwaypoints(bool full) {
waypoints.setsize(0);
clearwpcache();
- if(full)
- {
+ if(full) {
loadedwaypoints[0] = '\0';
dropwaypoints = 0;
}
}
ICOMMAND(clearwaypoints, "", (), clearwaypoints());
-
- void seedwaypoints()
- {
+ void seedwaypoints() {
if(waypoints.empty()) addwaypoint(vec(0, 0, 0));
- loopv(entities::ents)
- {
+ loopv(entities::ents) {
extentity &e = *entities::ents[i];
- switch(e.type)
- {
+ switch(e.type) {
case PLAYERSTART: case TELEPORT: case JUMPPAD:
addwaypoint(e.o);
break;
@@ -623,21 +484,17 @@ namespace ai
}
}
}
-
- void remapwaypoints()
- {
+ void remapwaypoints() {
vector<ushort> remap;
int total = 0;
loopv(waypoints) remap.add(waypoints[i].links[1] == 0xFFFF ? 0 : total++);
total = 0;
- loopvj(waypoints)
- {
+ loopvj(waypoints) {
if(waypoints[j].links[1] == 0xFFFF) continue;
waypoint &w = waypoints[total];
if(j != total) w = waypoints[j];
int k = 0;
- loopi(MAXWAYPOINTLINKS)
- {
+ loopi(MAXWAYPOINTLINKS) {
int link = w.links[i];
if(!link) break;
if((w.links[k] = remap[link])) k++;
@@ -647,22 +504,17 @@ namespace ai
}
waypoints.setsize(total);
}
-
- bool cleanwaypoints()
- {
+ bool cleanwaypoints() {
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
- if(clipped(w.o))
- {
+ if(clipped(w.o)) {
w.links[0] = 0;
w.links[1] = 0xFFFF;
cleared++;
}
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
loopv(players) if(players[i]) players[i]->lastnode = -1;
remapwaypoints();
@@ -671,37 +523,28 @@ namespace ai
}
return false;
}
-
- bool getwaypointfile(const char *mname, char *wptname)
- {
+ bool getwaypointfile(const char *mname, char *wptname) {
if(!mname || !*mname) mname = getclientmap();
if(!*mname) return false;
-
string pakname, mapname, cfgname;
getmapfilenames(mname, NULL, pakname, mapname, cfgname);
nformatstring(wptname, MAXSTRLEN, "packages/%s.wpt", mapname);
path(wptname);
return true;
}
-
- void loadwaypoints(bool force, const char *mname)
- {
+ void loadwaypoints(bool force, const char *mname) {
string wptname;
if(!getwaypointfile(mname, wptname)) return;
if(!force && (waypoints.length() || !strcmp(loadedwaypoints, wptname))) return;
-
stream *f = opengzfile(wptname, "rb");
if(!f) return;
char magic[4];
if(f->read(magic, 4) < 4 || memcmp(magic, "OWPT", 4)) { delete f; return; }
-
copystring(loadedwaypoints, wptname);
-
waypoints.setsize(0);
waypoints.add(vec(0, 0, 0));
ushort numwp = f->getlil<ushort>();
- loopi(numwp)
- {
+ loopi(numwp) {
if(f->end()) break;
vec o;
o.x = f->getlil<float>();
@@ -709,35 +552,26 @@ namespace ai
o.z = f->getlil<float>();
waypoint &w = waypoints.add(waypoint(o, getweight(o)));
int numlinks = f->getchar(), k = 0;
- loopi(numlinks)
- {
- if((w.links[k] = f->getlil<ushort>()))
- {
+ loopi(numlinks) {
+ if((w.links[k] = f->getlil<ushort>())) {
if(++k >= MAXWAYPOINTLINKS) break;
}
}
}
-
delete f;
conoutf("loaded %d waypoints from %s", numwp, wptname);
-
if(!cleanwaypoints()) clearwpcache();
}
ICOMMAND(loadwaypoints, "s", (char *mname), loadwaypoints(true, mname));
-
- void savewaypoints(bool force, const char *mname)
- {
+ void savewaypoints(bool force, const char *mname) {
if((!dropwaypoints && !force) || waypoints.empty()) return;
-
string wptname;
if(!getwaypointfile(mname, wptname)) return;
-
stream *f = opengzfile(wptname, "wb");
if(!f) return;
f->write("OWPT", 4);
f->putlil<ushort>(waypoints.length()-1);
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
f->putlil<float>(w.o.x);
f->putlil<float>(w.o.y);
@@ -747,55 +581,43 @@ namespace ai
f->putchar(numlinks);
loopj(numlinks) f->putlil<ushort>(w.links[j]);
}
-
delete f;
conoutf("saved %d waypoints to %s", waypoints.length()-1, wptname);
}
-
ICOMMAND(savewaypoints, "s", (char *mname), savewaypoints(true, mname));
-
- void delselwaypoints()
- {
+ void delselwaypoints() {
if(noedit(true)) return;
vec o = vec(sel.o).sub(0.1f), s = vec(sel.s).mul(sel.grid).add(o).add(0.1f);
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
- if(w.o.x >= o.x && w.o.x <= s.x && w.o.y >= o.y && w.o.y <= s.y && w.o.z >= o.z && w.o.z <= s.z)
- {
+ if(w.o.x >= o.x && w.o.x <= s.x && w.o.y >= o.y && w.o.y <= s.y && w.o.z >= o.z && w.o.z <= s.z) {
w.links[0] = 0;
w.links[1] = 0xFFFF;
cleared++;
}
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
remapwaypoints();
clearwpcache();
}
}
COMMAND(delselwaypoints, "");
-
- void movewaypoints(const vec &d)
- {
+ void movewaypoints(const vec &d) {
if(noedit(true)) return;
int worldsize = getworldsize();
- if(d.x < -worldsize || d.x > worldsize || d.y < -worldsize || d.y > worldsize || d.z < -worldsize || d.z > worldsize)
- {
+ if(d.x < -worldsize || d.x > worldsize || d.y < -worldsize || d.y > worldsize || d.z < -worldsize || d.z > worldsize) {
clearwaypoints();
return;
}
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
w.o.add(d);
if(!insideworld(w.o)) { w.links[0] = 0; w.links[1] = 0xFFFF; cleared++; }
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
remapwaypoints();
}