if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
{
if(walkfromwp && !ent.navigation_dynamicgoal)
- {
waypoint_clearlinks(ent); // initialize wpXXmincost fields
- navigation_item_addlink(it, ent);
- }
return it;
}
});
org.z = ent.origin.z + ent.mins.z - PL_MIN_CONST.z; // player height
}
- if(!autocvar_g_waypointeditor && walkfromwp && !ent.navigation_dynamicgoal)
- {
- waypoint_clearlinks(ent); // initialize wpXXmincost fields
- IL_EACH(g_waypoints, it != ent,
- {
- if (walkfromwp && (it.wpflags & WPFLAGMASK_NORELINK))
- continue;
-
- set_tracewalk_dest(ent, it.origin, false);
- if (vdist(tracewalk_dest - it.origin, <, 1050)
- && tracewalk(ent, it.origin, PL_MIN_CONST, PL_MAX_CONST,
- tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
- {
- navigation_item_addlink(it, ent);
- }
- });
- }
-
// box check failed, try walk
IL_EACH(g_waypoints, it != ent,
{
if(e == NULL)
return false;
- if(nearest_wp && nearest_wp.enemy)
+ if(nearest_wp && nearest_wp.enemy && !(nearest_wp.enemy.wpflags & WPFLAGMASK_NORELINK))
{
// often path can be optimized by not adding the nearest waypoint
if (this.goalentity.navigation_dynamicgoal || autocvar_g_waypointeditor)
}
}
}
- else if(navigation_item_islinked(nearest_wp.enemy, this.goalentity))
- e = nearest_wp.enemy;
+ else
+ {
+ // NOTE unlike waypoints, items hold incoming links
+ navigation_item_initlinks_ifneeded(this.goalentity);
+ int link_num = navigation_item_getlinknum(this.goalentity, nearest_wp.enemy);
+ if (link_num >= 0)
+ {
+ if (navigation_item_iswalkablelink(this.goalentity, link_num))
+ e = nearest_wp.enemy;
+ }
+ else // untested link
+ {
+ entity wp = nearest_wp.enemy;
+ entity goal = this.goalentity;
+ bool walkable = false;
+ if (checkpvs(wp.origin, goal))
+ {
+ set_tracewalk_dest(goal, wp.origin, false);
+ if (vdist(tracewalk_dest - wp.origin, <, 1050)
+ && tracewalk(goal, wp.origin, PL_MIN_CONST, PL_MAX_CONST,
+ tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
+ {
+ walkable = true;
+ e = nearest_wp.enemy;
+ }
+ }
+ navigation_item_add_link(wp, goal, walkable);
+ }
+ }
}
for (;;)
/*
// item it is linked from waypoint it.wpXX (INCOMING link)
// links are sorted by their cost (wpXXmincost)
+// one of these links is added in game every time a bot heads to an item
+// even links that are not walkable are added (marked with a high cost)
+// so that bots next time know if they can walk it or not saving a tracewalk call
.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
*/
-#define navigation_item_islinked(from_wp, to_item) waypoint_islinked(to_item, from_wp)
-#define navigation_item_addlink(from_wp, to_item) \
- waypoint_addlink_customcost(to_item, from_wp, waypoint_getlinkcost(from_wp, to_item))
+#define navigation_item_initlinks_ifneeded(e) MACRO_BEGIN if (!e.wp00) waypoint_clearlinks(e); MACRO_END // initialize wpXXmincost fields
+#define navigation_item_getlinknum(to_item, from_wp) waypoint_getlinknum(to_item, from_wp)
+#define navigation_item_iswalkablelink(to_item, from_wp) (waypoint_get_assigned_link_cost(to_item, from_wp) < 999)
+
+#define navigation_item_add_link(from_wp, to_item, walkable) \
+ waypoint_addlink_customcost(to_item, from_wp, (walkable ? waypoint_getlinkcost(from_wp, to_item) : 999))
#define TELEPORT_USED(pl, tele_wp) \
boxesoverlap(tele_wp.absmin, tele_wp.absmax, pl.lastteleport_origin + STAT(PL_MIN, pl), pl.lastteleport_origin + STAT(PL_MAX, pl))
LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired");
}
+float waypoint_get_assigned_link_cost(entity w, float i)
+{
+ switch(i)
+ {
+ case 0: return w.wp00mincost;
+ case 1: return w.wp01mincost;
+ case 2: return w.wp02mincost;
+ case 3: return w.wp03mincost;
+ case 4: return w.wp04mincost;
+ case 5: return w.wp05mincost;
+ case 6: return w.wp06mincost;
+ case 7: return w.wp07mincost;
+ case 8: return w.wp08mincost;
+ case 9: return w.wp09mincost;
+ case 10: return w.wp10mincost;
+ case 11: return w.wp11mincost;
+ case 12: return w.wp12mincost;
+ case 13: return w.wp13mincost;
+ case 14: return w.wp14mincost;
+ case 15: return w.wp15mincost;
+ case 16: return w.wp16mincost;
+ case 17: return w.wp17mincost;
+ case 18: return w.wp18mincost;
+ case 19: return w.wp19mincost;
+ case 20: return w.wp20mincost;
+ case 21: return w.wp21mincost;
+ case 22: return w.wp22mincost;
+ case 23: return w.wp23mincost;
+ case 24: return w.wp24mincost;
+ case 25: return w.wp25mincost;
+ case 26: return w.wp26mincost;
+ case 27: return w.wp27mincost;
+ case 28: return w.wp28mincost;
+ case 29: return w.wp29mincost;
+ case 30: return w.wp30mincost;
+ case 31: return w.wp31mincost;
+ default: return -1;
+ }
+}
+
entity waypoint_get_link(entity w, float i)
{
switch(i)
void waypoint_clearlinks(entity wp);
void waypoint_schedulerelink(entity wp);
+float waypoint_get_assigned_link_cost(entity w, float i);
+
float waypoint_getlinkcost(entity from, entity to);
float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent);
float waypoint_getlinearcost(float dist);