Version 20 update
- Changes from this version:
================= BUILD IS NATIVE ONLY:
Path builder:
- Added Botz_DirectPlatformBelow path, it's a direct link that activates when it becomes walkable.
- Added Botz_NavigRemoverSmart, removes clustered/excess PathNodes and InventorSpot within its radius.
- Added Botz_Telewatcher, dynamically disables routes through disabled teleporters within its radius.
- Fixed bug preventing 45ยบ routes from being pathed upwards.
- Botz_NavigDoorSpecial paths can optimally remove links between other nodes blocked by a gate.
- Botz_NavigDoorSpecial works normally in case of one-way incoming paths.
- Botz_NavigDoorSpecial supports triggered doors.
- Various bugfixes on direct link node placement.
- Water reachspecs have added weight (as with unreal editor built paths)
New pathfinder:
Maps the entire path network and sets on each node the path's weight (that leads to said node).
Then objectives are evaluated based on said networks mapping, this allows botz and game profiles to
evaluate multiple goals by mapping the network once.
It is possible to even determine which of many objectives can be reachable sooner.
- Used for all (except inventory finding) pathfinding now.
- Ported to c++, can call an event to customize cost in the route network.
- Can be used to remap the network from a different starting point without having to recalculate the cost.
- It's possible to modify the requirements for allowed reachspecs during mapping.
- Fixed route caching bug causing bots to get stuck on walls.
Botz_LiftCenter path better handled by both Botz and other pawns.
Botz are less likely to get stuck at items.
Botz's weapons no longer freeze when they go out of ammo.
Shock rifle profile and combo code greatly improved.
Game profiles:
- Attacking code revamped, BotzTargetAdder.SuggestAttack is always called, then bot decides whether to get items or not.
** This lets SuggestAttack modify the bot's inventory picking priorities.
- MonsterHunt profile (MH proto only): prioritization of objectives according to orders:
-- Attack: MonsterWaypoints/MonsterEnd, Monsters, Triggers
-- Freelence: MonsterWaypoints/MonsterEnd, Triggers, Monsters
-- Defend: Triggers, Monsters, MonsterWaypoints/MonsterEnd
*** If bots try going through locked doors/gates, order 'defense'.
EDIT: Added this PNG file to visual tutorials, remember to check the DirectLink tutorial on how to connect these nodes to ANY other node.
=============================
The route mapper has it's downsides, as it only currently maps the entire path network and that can be slower on maps with way too many navigation points.
The upside is that it allows the coder to evaluate multiple 'endpoints' without performing pathfinding for each one.
Other advantages are that one can specify the Start Anchor meaning that pathfinding in air situations (or for hypothetical paths taken by other creatures) is possible.
If this goes well, it'll be implemented into XC_Engine in a not so distant future.
Anatomy of the route mapper:
Every NavigationPoint's
VisitedWeight will indicate the 'distance/cost' of the shortest route between StartAnchor and said point.
If VisitedWeight is equal or above 10000000 then that means said node is unreachable from StartAnchor.
Code: Select all
//Modifiers:
// 0x0001: no R_WALK routes
// 0x0002: no R_FLY routes
// 0x0004: no R_SWIM routes
// 0x0008: no R_JUMP routes
// 0x0010: no R_DOOR routes
// 0x0020: no R_SPECIAL routes
// 0x0040: no R_PLAYERONLY routes
// 0x0080: soft-reset (VisitedWeight, prevOrdered) instead of hard-reset (+ cost, nextOrdered)
// When calling MapRoutes a 'hard-reset' will occur and all paths will be ready to be mapped
// PostHardResetEvent allows the user to modify NavigationPoint's cost inbetween a hard-reset and the mapping
// If you intend to change the StartAnchor after already having mapped the network,
// perform a soft-reset to avoid calculating path 'Cost' again
native final function MapRoutes( NavigationPoint StartAnchor, optional int MinWidth, optional int MinHeight, optional int Modifiers, optional name PostHardResetEvent);
This is an example function for locating StartAnchor near the bot, StartAnchor is a global variable here.
Code: Select all
//Only overrides anchor if found one
function bool LocateStartAnchor( optional bool bUnreachableAllowed)
{
local float BestWeight, Weight;
local NavigationPoint N, NewAnchor;
BestWeight = -1;
ForEach NavigationActors ( class'NavigationPoint', N, 2000)
{
Weight = 2 + int(FastTrace(N.Location)) - VSize(Location - N.Location) * 0.001;
if ( (Weight > BestWeight) && (bUnreachableAllowed || PointReachable(N.Location)) )
{
NewAnchor = N;
BestWeight = Weight;
}
}
if ( NewAnchor != None )
{
StartAnchor = NewAnchor;
return true;
}
}
When a hard-reset occurs, every NavigationPoint's Cost is set to either:
= ExtraCost variable if bSpecialCost=False
= SpecialCost event if bSpecialCost=True
This event (if specified on MapRoutes) will allow the modification of Path's costs between the hard-reset and the route mapping.
Here the Botz increase cost of paths where he's been previously killed.
Code: Select all
// Increase cost of navigation points post MapRouts hard-reset
event CostBads()
{
local Botz_BaddingSpot B;
For ( B=MyBads ; B!=none ; B=B.NextSpot )
B.ApplyBadding();
if ( PlayerReplicationInfo.Team < 4 )
For ( B=MasterEntity.TeamBads[PlayerReplicationInfo.Team] ; B!=none ; B=B.NextSpot )
B.ApplyBadding();
}
This is an example function on how to build the route cache from a desired EndPoint, obviously we should check that this EndPoint.VisitedWeight is lesser than 10000000 to verify it's reachable.
This allows us to determine the next path to follow AFTER we've mapped the route.
There 10k arbitrary limit is there to prevent crashes.
This code skips elements in the route that are touching or too close to the bot.
Code: Select all
function NavigationPoint BuildRouteCache( NavigationPoint EndPoint)
{
local int i;
EndPoint.RouteCache = none; //Build the chain
while ( EndPoint.prevOrdered != None )
{
EndPoint.prevOrdered.RouteCache = EndPoint;
EndPoint = EndPoint.prevOrdered;
if ( ++i == 10000 ) return None;
}
i = 0;
while ( (EndPoint != None) && InRadiusEntity(EndPoint) ) //Skip nearby nodes, treat them as visited
EndPoint = NavigationPoint(EndPoint.RouteCache);
while ( (EndPoint != None) && (i<16) )
{
RouteCache[i++] = EndPoint;
EndPoint = NavigationPoint(EndPoint.RouteCache);
}
return RouteCache[0];
}