Reduce var usage no kd tree

This commit is contained in:
ineedbots 2021-05-27 11:18:39 -06:00
parent 6c1b6218a6
commit 40d5b03bcf
5 changed files with 205 additions and 257 deletions

View File

@ -23,11 +23,6 @@ init()
if (!getDvarInt("bots_main")) if (!getDvarInt("bots_main"))
return; return;
if(getDvar("bots_main_lowmem") == "")
setDvar("bots_main_lowmem", false);//lower memory usage mode, more cpu
level.bots_lowmem = getDvarInt("bots_main_lowmem");
thread load_waypoints(); thread load_waypoints();
thread hook_callbacks(); thread hook_callbacks();

View File

@ -1823,7 +1823,7 @@ cleanUpAStar(team)
self waittill_any("death", "disconnect", "kill_goal"); self waittill_any("death", "disconnect", "kill_goal");
for(i = self.bot.astar.size - 1; i >= 0; i--) for(i = self.bot.astar.size - 1; i >= 0; i--)
level.waypoints[self.bot.astar[i]].bots[team]--; RemoveWaypointUsage(self.bot.astar[i], team);
} }
/* /*
@ -1851,7 +1851,7 @@ removeAStar()
remove = self.bot.astar.size-1; remove = self.bot.astar.size-1;
if(level.teamBased) if(level.teamBased)
level.waypoints[self.bot.astar[remove]].bots[self.team]--; RemoveWaypointUsage(self.bot.astar[remove], self.team);
self.bot.astar[remove] = undefined; self.bot.astar[remove] = undefined;

View File

@ -1594,47 +1594,6 @@ bots_watch_touch_obj(obj)
} }
} }
/*
Is bot near any of the given waypoints
*/
nearAnyOfWaypoints(dist, waypoints)
{
dist *= dist;
for (i = 0; i < waypoints.size; i++)
{
waypoint = waypoints[i];
if (DistanceSquared(waypoint.origin, self.origin) > dist)
continue;
return true;
}
return false;
}
/*
Returns nearest waypoint of waypoints
*/
getNearestWaypointOfWaypoints(waypoints)
{
answer = undefined;
closestDist = 2147483647;
for (i = 0; i < waypoints.size; i++)
{
waypoint = waypoints[i];
thisDist = DistanceSquared(self.origin, waypoint.origin);
if (isDefined(answer) && thisDist > closestDist)
continue;
answer = waypoint;
closestDist = thisDist;
}
return answer;
}
/* /*
Watches while the obj is being carried, calls 'goal' when complete Watches while the obj is being carried, calls 'goal' when complete
*/ */
@ -2056,16 +2015,7 @@ bot_think_camp()
if(randomInt(100) > self.pers["bots"]["behavior"]["camp"]) if(randomInt(100) > self.pers["bots"]["behavior"]["camp"])
continue; continue;
campSpots = []; campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsCamp.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsCamp[i].origin) > distSq)
continue;
campSpots[campSpots.size] = level.waypointsCamp[i];
}
campSpot = random(campSpots);
if (!isDefined(campSpot)) if (!isDefined(campSpot))
continue; continue;
@ -2404,18 +2354,9 @@ bot_use_tube_think()
loc = undefined; loc = undefined;
if (!self nearAnyOfWaypoints(128, level.waypointsTube)) if (!self nearAnyOfWaypoints(128, getWaypointsOfType("tube")))
{ {
tubeWps = []; tubeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("tube"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsTube.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsTube[i].origin) > distSq)
continue;
tubeWps[tubeWps.size] = level.waypointsTube[i];
}
tubeWp = random(tubeWps);
myEye = self GetEye(); myEye = self GetEye();
if (!isDefined(tubeWp) || self HasScriptGoal() || self.bot_lock_goal) if (!isDefined(tubeWp) || self HasScriptGoal() || self.bot_lock_goal)
@ -2453,7 +2394,7 @@ bot_use_tube_think()
} }
else else
{ {
tubeWp = self getNearestWaypointOfWaypoints(level.waypointsTube); tubeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("tube")));
loc = tubeWp.origin + AnglesToForward(tubeWp.angles) * 2048; loc = tubeWp.origin + AnglesToForward(tubeWp.angles) * 2048;
} }
@ -2534,18 +2475,9 @@ bot_use_equipment_think()
loc = undefined; loc = undefined;
if (!self nearAnyOfWaypoints(128, level.waypointsClay)) if (!self nearAnyOfWaypoints(128, getWaypointsOfType("claymore")))
{ {
clayWps = []; clayWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("claymore"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsClay.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsClay[i].origin) > distSq)
continue;
clayWps[clayWps.size] = level.waypointsClay[i];
}
clayWp = random(clayWps);
if (!isDefined(clayWp) || self HasScriptGoal() || self.bot_lock_goal) if (!isDefined(clayWp) || self HasScriptGoal() || self.bot_lock_goal)
{ {
@ -2573,7 +2505,7 @@ bot_use_equipment_think()
} }
else else
{ {
clayWp = self getNearestWaypointOfWaypoints(level.waypointsClay); clayWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("claymore")));
loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048; loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048;
} }
@ -2642,18 +2574,9 @@ bot_use_grenade_think()
loc = undefined; loc = undefined;
if (!self nearAnyOfWaypoints(128, level.waypointsGren)) if (!self nearAnyOfWaypoints(128, getWaypointsOfType("grenade")))
{ {
nadeWps = []; nadeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("grenade"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsGren.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsGren[i].origin) > distSq)
continue;
nadeWps[nadeWps.size] = level.waypointsGren[i];
}
nadeWp = random(nadeWps);
myEye = self GetEye(); myEye = self GetEye();
if (!isDefined(nadeWp) || self HasScriptGoal() || self.bot_lock_goal) if (!isDefined(nadeWp) || self HasScriptGoal() || self.bot_lock_goal)
@ -2691,7 +2614,7 @@ bot_use_grenade_think()
} }
else else
{ {
nadeWp = self getNearestWaypointOfWaypoints(level.waypointsGren); nadeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("grenade")));
loc = nadeWp.origin + AnglesToForward(nadeWp.angles) * 2048; loc = nadeWp.origin + AnglesToForward(nadeWp.angles) * 2048;
} }
@ -2895,18 +2818,9 @@ bot_jav_loc_think()
loc = undefined; loc = undefined;
if (!self nearAnyOfWaypoints(128, level.waypointsJav)) if (!self nearAnyOfWaypoints(128, getWaypointsOfType("javelin")))
{ {
javWps = []; javWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("javelin"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsJav.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsJav[i].origin) > distSq)
continue;
javWps[javWps.size] = level.waypointsJav[i];
}
javWp = random(javWps);
if (!isDefined(javWp) || self HasScriptGoal() || self.bot_lock_goal) if (!isDefined(javWp) || self HasScriptGoal() || self.bot_lock_goal)
{ {
@ -2942,7 +2856,7 @@ bot_jav_loc_think()
} }
else else
{ {
javWp = self getNearestWaypointOfWaypoints(level.waypointsJav); javWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("javelin")));
loc = javWp.jav_point; loc = javWp.jav_point;
} }
@ -4055,18 +3969,9 @@ bot_killstreak_think()
if (self inLastStand()) if (self inLastStand())
continue; continue;
if (lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && streakName != "sentry" && !self nearAnyOfWaypoints(128, level.waypointsCamp)) if (lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && streakName != "sentry" && !self nearAnyOfWaypoints(128, getWaypointsOfType("camp")))
{ {
campSpots = []; campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024)));
distSq = 1024*1024;
for (i = 0; i < level.waypointsCamp.size; i++)
{
if (DistanceSquared(self.origin, level.waypointsCamp[i].origin) > distSq)
continue;
campSpots[campSpots.size] = level.waypointsCamp[i];
}
campSpot = random(campSpots);
if (isDefined(campSpot)) if (isDefined(campSpot))
{ {

View File

@ -779,7 +779,6 @@ parseTokensIntoWaypoint(tokens)
childStr = tokens[1]; childStr = tokens[1];
childToks = strtok(childStr, " "); childToks = strtok(childStr, " ");
waypoint.childCount = childToks.size;
waypoint.children = []; waypoint.children = [];
for( j=0; j<childToks.size; j++ ) for( j=0; j<childToks.size; j++ )
waypoint.children[j] = int(childToks[j]); waypoint.children[j] = int(childToks[j]);
@ -876,6 +875,9 @@ load_waypoints()
{ {
level.waypointCount = 0; level.waypointCount = 0;
level.waypoints = []; level.waypoints = [];
level.waypointUsage = [];
level.waypointUsage["allies"] = [];
level.waypointUsage["axis"] = [];
mapname = getDvar("mapname"); mapname = getDvar("mapname");
@ -1107,11 +1109,6 @@ load_waypoints()
for(i = 0; i < level.waypointCount; i++) for(i = 0; i < level.waypointCount; i++)
{ {
level.waypoints[i].index = i;
level.waypoints[i].bots = [];
level.waypoints[i].bots["allies"] = 1;
level.waypoints[i].bots["axis"] = 1;
if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size)) if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size))
level.waypoints[i].children = []; level.waypoints[i].children = [];
@ -1121,31 +1118,108 @@ load_waypoints()
if (!isDefined(level.waypoints[i].type)) if (!isDefined(level.waypoints[i].type))
level.waypoints[i].type = "crouch"; level.waypoints[i].type = "crouch";
level.waypoints[i].childCount = level.waypoints[i].children.size; level.waypoints[i].childCount = undefined;
} }
}
if (!level.bots_lowmem) /*
Is bot near any of the given waypoints
*/
nearAnyOfWaypoints(dist, waypoints)
{
dist *= dist;
for (i = 0; i < waypoints.size; i++)
{ {
level.waypointsKDTree = WaypointsToKDTree(); waypoint = level.waypoints[waypoints[i]];
if (DistanceSquared(waypoint.origin, self.origin) > dist)
continue;
return true;
} }
level.waypointsCamp = []; return false;
level.waypointsTube = []; }
level.waypointsGren = [];
level.waypointsClay = [];
level.waypointsJav = [];
/*
Returns the waypoints that are near
*/
waypointsNear(waypoints, dist)
{
dist *= dist;
answer = [];
for (i = 0; i < waypoints.size; i++)
{
wp = level.waypoints[waypoints[i]];
if (DistanceSquared(wp.origin, self.origin) > dist)
continue;
answer[answer.size] = waypoints[i];
}
return answer;
}
/*
Returns nearest waypoint of waypoints
*/
getNearestWaypointOfWaypoints(waypoints)
{
answer = undefined;
closestDist = 2147483647;
for (i = 0; i < waypoints.size; i++)
{
waypoint = level.waypoints[waypoints[i]];
thisDist = DistanceSquared(self.origin, waypoint.origin);
if (isDefined(answer) && thisDist > closestDist)
continue;
answer = waypoints[i];
closestDist = thisDist;
}
return answer;
}
/*
Returns all waypoints of type
*/
getWaypointsOfType(type)
{
answer = [];
for(i = 0; i < level.waypointCount; i++) for(i = 0; i < level.waypointCount; i++)
if(level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) {
level.waypointsCamp[level.waypointsCamp.size] = level.waypoints[i]; wp = level.waypoints[i];
else if(level.waypoints[i].type == "tube")
level.waypointsTube[level.waypointsTube.size] = level.waypoints[i]; if (type == "camp")
else if(level.waypoints[i].type == "grenade") {
level.waypointsGren[level.waypointsGren.size] = level.waypoints[i]; if (wp.type != "crouch")
else if(level.waypoints[i].type == "claymore") continue;
level.waypointsClay[level.waypointsClay.size] = level.waypoints[i];
else if(level.waypoints[i].type == "javelin") if (wp.children.size != 1)
level.waypointsJav[level.waypointsJav.size] = level.waypoints[i]; continue;
}
else if (type != wp.type)
continue;
answer[answer.size] = i;
}
return answer;
}
/*
Returns the waypoint for index
*/
getWaypointForIndex(i)
{
if (!isDefined(i))
return undefined;
return level.waypoints[i];
} }
/* /*
@ -1872,6 +1946,23 @@ ReverseHeapAStar(item, item2)
return item.f < item2.f; return item.f < item2.f;
} }
/*
Removes the waypoint usage
*/
RemoveWaypointUsage(wp, team)
{
if (!isDefined(level.waypointUsage))
return;
if (!isDefined(level.waypointUsage[team][wp+""]))
return;
level.waypointUsage[team][wp+""]--;
if (level.waypointUsage[team][wp+""] <= 0)
level.waypointUsage[team][wp+""] = undefined;
}
/* /*
Will linearly search for the nearest waypoint to pos that has a direct line of sight. Will linearly search for the nearest waypoint to pos that has a direct line of sight.
*/ */
@ -1890,7 +1981,7 @@ GetNearestWaypointWithSight(pos)
continue; continue;
dist = curdis; dist = curdis;
candidate = level.waypoints[i]; candidate = i;
} }
return candidate; return candidate;
@ -1911,7 +2002,7 @@ GetNearestWaypoint(pos)
continue; continue;
dist = curdis; dist = curdis;
candidate = level.waypoints[i]; candidate = i;
} }
return candidate; return candidate;
@ -1920,71 +2011,48 @@ GetNearestWaypoint(pos)
/* /*
Modified Pezbot astar search. Modified Pezbot astar search.
This makes use of sets for quick look up and a heap for a priority queue instead of simple lists which require to linearly search for elements everytime. This makes use of sets for quick look up and a heap for a priority queue instead of simple lists which require to linearly search for elements everytime.
Also makes use of the KD tree to search for the nearest node to the goal. We only use the closest node from the KD tree if it has a direct line of sight, else we will have to linearly search for one that we have a line of sight on.
It is also modified to make paths with bots already on more expensive and will try a less congested path first. Thus spliting up the bots onto more paths instead of just one (the smallest). It is also modified to make paths with bots already on more expensive and will try a less congested path first. Thus spliting up the bots onto more paths instead of just one (the smallest).
*/ */
AStarSearch(start, goal, team, greedy_path) AStarSearch(start, goal, team, greedy_path)
{ {
open = NewHeap(::ReverseHeapAStar);//heap open = NewHeap(::ReverseHeapAStar);//heap
openset = [];//set for quick lookup openset = [];//set for quick lookup
closed = [];//set for quick lookup closed = [];//set for quick lookup
startwp = undefined;
if (level.bots_lowmem) startWp = getNearestWaypoint(start);
startwp = getNearestWaypoint(start); if(!isDefined(startWp))
else
startwp = level.waypointsKDTree KDTreeNearest(start);//balanced kdtree, for nns
if(!isDefined(startwp))
return []; return [];
_startwp = undefined; _startwp = undefined;
if(!bulletTracePassed(start + (0, 0, 15), startwp.origin + (0, 0, 15), false, undefined)) if(!bulletTracePassed(start + (0, 0, 15), level.waypoints[startWp].origin + (0, 0, 15), false, undefined))
_startwp = GetNearestWaypointWithSight(start); _startwp = GetNearestWaypointWithSight(start);
if(isDefined(_startwp)) if(isDefined(_startwp))
startwp = _startwp; startWp = _startwp;
startwp = startwp.index;
goalwp = undefined;
if (level.bots_lowmem) goalWp = getNearestWaypoint(goal);
goalwp = getNearestWaypoint(goal); if(!isDefined(goalWp))
else
goalwp = level.waypointsKDTree KDTreeNearest(goal);
if(!isDefined(goalwp))
return []; return [];
_goalwp = undefined;
if(!bulletTracePassed(goal + (0, 0, 15), goalwp.origin + (0, 0, 15), false, undefined)) _goalWp = undefined;
if(!bulletTracePassed(goal + (0, 0, 15), level.waypoints[goalWp].origin + (0, 0, 15), false, undefined))
_goalwp = GetNearestWaypointWithSight(goal); _goalwp = GetNearestWaypointWithSight(goal);
if(isDefined(_goalwp)) if(isDefined(_goalwp))
goalwp = _goalwp; goalWp = _goalwp;
goalwp = goalwp.index;
/*storeKey = "astarcache " + startwp + " " + goalwp;
if (StoreHas(storeKey))
{
path = [];
pathArrStr = tokenizeLine(StoreGet(storeKey), ",");
pathArrSize = pathArrStr.size;
for (i = 0; i < pathArrSize; i++)
{
path[path.size] = int(pathArrStr[i]);
}
return path;
}*/
goalorg = level.waypoints[goalWp].origin;
node = spawnStruct(); node = spawnStruct();
node.g = 0; //path dist so far node.g = 0; //path dist so far
node.h = DistanceSquared(level.waypoints[startWp].origin, goalorg); //herustic, distance to goal for path finding node.h = DistanceSquared(level.waypoints[startWp].origin, level.waypoints[goalWp].origin); //herustic, distance to goal for path finding
//node.f = node.h + node.g; // combine path dist and heru, use reverse heap to sort the priority queue by this attru node.f = node.h + node.g; // combine path dist and heru, use reverse heap to sort the priority queue by this attru
node.f = node.h; node.index = startWp;
node.index = startwp;
node.parent = undefined; //we are start, so we have no parent node.parent = undefined; //we are start, so we have no parent
//push node onto queue //push node onto queue
openset[node.index] = node; openset[node.index+""] = node;
open HeapInsert(node); open HeapInsert(node);
//while the queue is not empty //while the queue is not empty
@ -1993,94 +2061,94 @@ AStarSearch(start, goal, team, greedy_path)
//pop bestnode from queue //pop bestnode from queue
bestNode = open.data[0]; bestNode = open.data[0];
open HeapRemove(); open HeapRemove();
openset[bestNode.index] = undefined; openset[bestNode.index+""] = undefined;
wp = level.waypoints[bestNode.index];
//check if we made it to the goal //check if we made it to the goal
if(bestNode.index == goalwp) if(bestNode.index == goalWp)
{ {
path = []; path = [];
//storeStr = "";
while(isDefined(bestNode)) while(isDefined(bestNode))
{ {
if(isdefined(team)) if(isdefined(team) && isDefined(level.waypointUsage))
level.waypoints[bestNode.index].bots[team]++; {
if (!isDefined(level.waypointUsage[team][bestNode.index+""]))
level.waypointUsage[team][bestNode.index+""] = 0;
level.waypointUsage[team][bestNode.index+""]++;
}
//construct path //construct path
path[path.size] = bestNode.index; path[path.size] = bestNode.index;
//storeStr += bestNode.index;
bestNode = bestNode.parent; bestNode = bestNode.parent;
/*if (isDefined(bestNode))
storeStr += ",";*/
} }
//StoreSet(storeKey, storeStr);
return path; return path;
} }
nodeorg = level.waypoints[bestNode.index].origin;
childcount = level.waypoints[bestNode.index].childCount;
//for each child of bestnode //for each child of bestnode
for(i = 0; i < childcount; i++) for(i = wp.children.size - 1; i >= 0; i--)
{ {
child = level.waypoints[bestNode.index].children[i]; child = wp.children[i];
childorg = level.waypoints[child].origin; childWp = level.waypoints[child];
childtype = level.waypoints[child].type;
penalty = 1; penalty = 1;
if(!greedy_path && isdefined(team)) if(!greedy_path && isdefined(team) && isDefined(level.waypointUsage))
{ {
temppen = level.waypoints[child].bots[team];//consider how many bots are taking this path temppen = 1;
if (isDefined(level.waypointUsage[team][child+""]))
temppen = level.waypointUsage[team][child+""];//consider how many bots are taking this path
if(temppen > 1) if(temppen > 1)
penalty = temppen; penalty = temppen;
} }
// have certain types of nodes more expensive // have certain types of nodes more expensive
if (childtype == "climb" || childtype == "prone") if (childWp.type == "climb" || childWp.type == "prone")
penalty += 4; penalty += 4;
//calc the total path we have took //calc the total path we have took
newg = bestNode.g + DistanceSquared(nodeorg, childorg)*penalty;//bots on same team's path are more expensive newg = bestNode.g + DistanceSquared(wp.origin, childWp.origin)*penalty;//bots on same team's path are more expensive
//check if this child is in open or close with a g value less than newg //check if this child is in open or close with a g value less than newg
inopen = isDefined(openset[child]); inopen = isDefined(openset[child+""]);
if(inopen && openset[child].g <= newg) if(inopen && openset[child+""].g <= newg)
continue; continue;
inclosed = isDefined(closed[child]); inclosed = isDefined(closed[child+""]);
if(inclosed && closed[child].g <= newg) if(inclosed && closed[child+""].g <= newg)
continue; continue;
node = undefined;
if(inopen) if(inopen)
node = openset[child]; node = openset[child+""];
else if(inclosed) else if(inclosed)
node = closed[child]; node = closed[child+""];
else else
node = spawnStruct(); node = spawnStruct();
node.parent = bestNode; node.parent = bestNode;
node.g = newg; node.g = newg;
node.h = DistanceSquared(childorg, goalorg); node.h = DistanceSquared(childWp.origin, level.waypoints[goalWp].origin);
node.f = node.g + node.h; node.f = node.g + node.h;
node.index = child; node.index = child;
//check if in closed, remove it //check if in closed, remove it
if(inclosed) if(inclosed)
closed[child] = undefined; closed[child+""] = undefined;
//check if not in open, add it //check if not in open, add it
if(!inopen) if(!inopen)
{ {
open HeapInsert(node); open HeapInsert(node);
openset[child] = node; openset[child+""] = node;
} }
} }
//done with children, push onto closed //done with children, push onto closed
closed[bestNode.index] = bestNode; closed[bestNode.index+""] = bestNode;
} }
return []; return [];

View File

@ -51,7 +51,6 @@ init()
level.waypoints = []; level.waypoints = [];
level.waypointCount = 0; level.waypointCount = 0;
level.bots_lowmem = false;
level waittill( "connected", player); level waittill( "connected", player);
player thread onPlayerSpawned(); player thread onPlayerSpawned();
@ -186,7 +185,7 @@ updateWaypointsStats()
if(distance(level.waypoints[i].origin, self.origin) < getDvarFloat("bots_main_debug_distance") && (bulletTracePassed(myEye, wpOrg, false, self) || getDVarint("bots_main_debug_drawThrough"))) if(distance(level.waypoints[i].origin, self.origin) < getDvarFloat("bots_main_debug_distance") && (bulletTracePassed(myEye, wpOrg, false, self) || getDVarint("bots_main_debug_drawThrough")))
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for(h = level.waypoints[i].children.size - 1; h >= 0; h--)
line(wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + (0, 0, 25), (1,0,1)); line(wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + (0, 0, 25), (1,0,1));
if(getConeDot(wpOrg, myEye, myAngles) > getDvarFloat("bots_main_debug_cone")) if(getConeDot(wpOrg, myEye, myAngles) > getDvarFloat("bots_main_debug_cone"))
@ -366,12 +365,11 @@ watchSaveWaypointsCommand()
logprint("*/waypoints["+i+"] = spawnstruct();\n/*"); logprint("*/waypoints["+i+"] = spawnstruct();\n/*");
logprint("*/waypoints["+i+"].origin = "+level.waypoints[i].origin+";\n/*"); logprint("*/waypoints["+i+"].origin = "+level.waypoints[i].origin+";\n/*");
logprint("*/waypoints["+i+"].type = \""+level.waypoints[i].type+"\";\n/*"); logprint("*/waypoints["+i+"].type = \""+level.waypoints[i].type+"\";\n/*");
logprint("*/waypoints["+i+"].childCount = "+level.waypoints[i].childCount+";\n/*"); for(c = 0; c < level.waypoints[i].children.size; c++)
for(c = 0; c < level.waypoints[i].childCount; c++)
{ {
logprint("*/waypoints["+i+"].children["+c+"] = "+level.waypoints[i].children[c]+";\n/*"); logprint("*/waypoints["+i+"].children["+c+"] = "+level.waypoints[i].children[c]+";\n/*");
} }
if(isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) if(isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade"))
logprint("*/waypoints["+i+"].angles = "+level.waypoints[i].angles+";\n/*"); logprint("*/waypoints["+i+"].angles = "+level.waypoints[i].angles+";\n/*");
if (isDefined(level.waypoints[i].jav_point) && level.waypoints[i].type == "javelin") if (isDefined(level.waypoints[i].jav_point) && level.waypoints[i].type == "javelin")
@ -392,11 +390,11 @@ watchSaveWaypointsCommand()
str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ","; str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ",";
for(h = 0; h < wp.childCount; h++) for(h = 0; h < wp.children.size; h++)
{ {
str += wp.children[h]; str += wp.children[h];
if (h < wp.childCount - 1) if (h < wp.children.size - 1)
str += " "; str += " ";
} }
str += "," + wp.type + ","; str += "," + wp.type + ",";
@ -447,8 +445,8 @@ checkForWarnings()
continue; continue;
} }
if(level.waypoints[i].childCount <= 0) if(level.waypoints[i].children.size <= 0)
self iprintln("WARNING: waypoint "+i+" childCount is "+level.waypoints[i].childCount); self iprintln("WARNING: waypoint "+i+" childCount is "+level.waypoints[i].children.size);
else else
{ {
if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size)) if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size))
@ -457,10 +455,7 @@ checkForWarnings()
} }
else else
{ {
if(level.waypoints[i].childCount != level.waypoints[i].children.size) for(h = level.waypoints[i].children.size - 1; h >= 0; h--)
self iprintln("WARNING: waypoint "+i+" childCount is not "+level.waypoints[i].children.size);
for (h = 0; h < level.waypoints[i].childCount; h++)
{ {
child = level.waypoints[i].children[h]; child = level.waypoints[i].children[h];
@ -481,7 +476,7 @@ checkForWarnings()
if (level.waypoints[i].type == "javelin" && !isDefined(level.waypoints[i].jav_point)) if (level.waypoints[i].type == "javelin" && !isDefined(level.waypoints[i].jav_point))
self iprintln("WARNING: waypoint "+i+" jav_point is undefined"); self iprintln("WARNING: waypoint "+i+" jav_point is undefined");
if(!isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) if(!isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade"))
self iprintln("WARNING: waypoint "+i+" angles is undefined"); self iprintln("WARNING: waypoint "+i+" angles is undefined");
} }
} }
@ -505,9 +500,6 @@ UnLinkWaypoint(nwp)
level.waypoints[nwp].children = array_remove(level.waypoints[nwp].children, level.wpToLink); level.waypoints[nwp].children = array_remove(level.waypoints[nwp].children, level.wpToLink);
level.waypoints[level.wpToLink].children = array_remove(level.waypoints[level.wpToLink].children, nwp); level.waypoints[level.wpToLink].children = array_remove(level.waypoints[level.wpToLink].children, nwp);
level.waypoints[nwp].childCount = level.waypoints[nwp].children.size;
level.waypoints[level.wpToLink].childCount = level.waypoints[level.wpToLink].children.size;
self iprintln("Waypoint " + nwp + " Broken to " + level.wpToLink); self iprintln("Waypoint " + nwp + " Broken to " + level.wpToLink);
level.wpToLink = -1; level.wpToLink = -1;
} }
@ -529,7 +521,7 @@ LinkWaypoint(nwp)
} }
weGood = true; weGood = true;
for (i = 0; i < level.waypoints[level.wpToLink].childCount; i++) for(i = level.waypoints[level.wpToLink].children.size - 1; i >= 0; i--)
{ {
child = level.waypoints[level.wpToLink].children[i]; child = level.waypoints[level.wpToLink].children[i];
@ -542,7 +534,7 @@ LinkWaypoint(nwp)
if(weGood) if(weGood)
{ {
for (i = 0; i < level.waypoints[nwp].childCount; i++) for(i = level.waypoints[nwp].children.size - 1; i >= 0; i--)
{ {
child = level.waypoints[nwp].children[i]; child = level.waypoints[nwp].children[i];
@ -561,10 +553,8 @@ LinkWaypoint(nwp)
return; return;
} }
level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].childcount] = nwp; level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].children.size] = nwp;
level.waypoints[level.wpToLink].childcount++; level.waypoints[nwp].children[level.waypoints[nwp].children.size] = level.wpToLink;
level.waypoints[nwp].children[level.waypoints[nwp].childcount] = level.wpToLink;
level.waypoints[nwp].childcount++;
self iprintln("Waypoint " + nwp + " Linked to " + level.wpToLink); self iprintln("Waypoint " + nwp + " Linked to " + level.wpToLink);
level.wpToLink = -1; level.wpToLink = -1;
@ -580,18 +570,16 @@ DeleteWaypoint(nwp)
level.wpToLink = -1; level.wpToLink = -1;
for (i = 0; i < level.waypoints[nwp].childCount; i++) for(i = level.waypoints[nwp].children.size - 1; i >= 0; i--)
{ {
child = level.waypoints[nwp].children[i]; child = level.waypoints[nwp].children[i];
level.waypoints[child].children = array_remove(level.waypoints[child].children, nwp); level.waypoints[child].children = array_remove(level.waypoints[child].children, nwp);
level.waypoints[child].childCount = level.waypoints[child].children.size;
} }
for(i = 0; i < level.waypointCount; i++) for(i = 0; i < level.waypointCount; i++)
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for(h = level.waypoints[i].children.size - 1; h >= 0; h--)
{ {
if(level.waypoints[i].children[h] > nwp) if(level.waypoints[i].children[h] > nwp)
level.waypoints[i].children[h]--; level.waypoints[i].children[h]--;
@ -639,7 +627,6 @@ AddWaypoint()
level.waypoints[level.waypointCount].angles = self getPlayerAngles(); level.waypoints[level.waypointCount].angles = self getPlayerAngles();
level.waypoints[level.waypointCount].children = []; level.waypoints[level.waypointCount].children = [];
level.waypoints[level.waypointCount].childCount = 0;
if (level.waypoints[level.waypointCount].type == "javelin") if (level.waypoints[level.waypointCount].type == "javelin")
{ {
@ -666,13 +653,6 @@ DeleteAllWaypoints()
{ {
level.waypoints = []; level.waypoints = [];
level.waypointCount = 0; level.waypointCount = 0;
level.waypointsKDTree = WaypointsToKDTree();
level.waypointsCamp = [];
level.waypointsTube = [];
level.waypointsGren = [];
level.waypointsClay = [];
level.waypointsJav = [];
self iprintln("DelAllWps"); self iprintln("DelAllWps");
} }
@ -682,7 +662,7 @@ buildChildCountString ( wp )
if ( wp == -1 ) if ( wp == -1 )
return ""; return "";
wpstr = level.waypoints[wp].childCount + ""; wpstr = level.waypoints[wp].children.size + "";
return wpstr; return wpstr;
} }
@ -694,7 +674,7 @@ buildChildString( wp )
wpstr = ""; wpstr = "";
for(i = 0; i < level.waypoints[wp].childCount; i++) for(i = 0; i < level.waypoints[wp].children.size; i++)
{ {
if(i != 0) if(i != 0)
wpstr = wpstr + "," + level.waypoints[wp].children[i]; wpstr = wpstr + "," + level.waypoints[wp].children[i];