From d5e587d2d3ef0a040ecf82fa0e29b829df38eaa3 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Sun, 28 Aug 2011 19:31:58 +0200 Subject: [PATCH] more autowaypoint stuff --- qcsrc/server/bot/navigation.qc | 59 +++++++------ qcsrc/server/bot/waypoints.qc | 152 +++++++++++++++++++++++++-------- 2 files changed, 148 insertions(+), 63 deletions(-) diff --git a/qcsrc/server/bot/navigation.qc b/qcsrc/server/bot/navigation.qc index 968e760b8..71016d503 100644 --- a/qcsrc/server/bot/navigation.qc +++ b/qcsrc/server/bot/navigation.qc @@ -326,11 +326,35 @@ void navigation_poproute() self.goalstack31 = world; }; +float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist) +{ + float dist; + dist = vlen(v - org); + if (bestdist > dist) + { + traceline(v, org, TRUE, ent); + if (trace_fraction == 1) + { + if (walkfromwp) + { + if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode)) + return TRUE; + } + else + { + if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode)) + return TRUE; + } + } + } + return FALSE; +} + // find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon -entity navigation_findnearestwaypoint(entity ent, float walkfromwp) +entity navigation_findnearestwaypoint_withdist(entity ent, float walkfromwp, float bestdist) { local entity waylist, w, best; - local float dist, bestdist; + local float dist; local vector v, org, pm1, pm2; pm1 = ent.origin + ent.mins; pm2 = ent.origin + ent.maxs; @@ -356,7 +380,6 @@ entity navigation_findnearestwaypoint(entity ent, float walkfromwp) te_plasmaburn(org); best = world; - bestdist = 1050; // box check failed, try walk w = waylist; @@ -376,36 +399,20 @@ entity navigation_findnearestwaypoint(entity ent, float walkfromwp) } else v = w.origin; - dist = vlen(v - org); - if (bestdist > dist) + if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist)) { - traceline(v, org, TRUE, ent); - if (trace_fraction == 1) - { - if (walkfromwp) - { - //print("^1can I reach ", vtos(org), " from ", vtos(v), "?\n"); - if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode)) - { - bestdist = dist; - best = w; - } - } - else - { - if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode)) - { - bestdist = dist; - best = w; - } - } - } + bestdist = dist; + best = w; } } w = w.chain; } return best; } +entity navigation_findnearestwaypoint(entity ent, float walkfromwp) +{ + return navigation_findnearestwaypoint_withdist(ent, walkfromwp, 1050); +} // finds the waypoints near the bot initiating a navigation query float navigation_markroutes_nearestwaypoints(entity waylist, float maxdist) diff --git a/qcsrc/server/bot/waypoints.qc b/qcsrc/server/bot/waypoints.qc index eb08b38c5..5a0bb1e7c 100644 --- a/qcsrc/server/bot/waypoints.qc +++ b/qcsrc/server/bot/waypoints.qc @@ -877,62 +877,136 @@ void botframe_showwaypointlinks() } }; -// automatically create missing waypoints -.float lastwaypointtime0; -.float lastwaypointtime1; -void botframe_autowaypoints_fix(entity p, float walkfromwp, .float last) +float botframe_autowaypoints_fixdown(vector v) +{ + tracebox(v, PL_MIN, PL_MAX, v + '0 0 -64', MOVE_NOMONSTERS, world); + if(trace_fraction >= 1) + return 0; + return 1; +} + +// return value: +// 1 = WP created +// 0 = no action needed +// -1 = temp fail, try from world too +// -2 = permanent fail, do not retry +float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .entity fld) { - float t; - entity wp; + // make it possible to go from p to wp, if we can + // if wp is world, nearest is chosen + + entity w; + vector porg; + float t, tmin, tmax; vector o; - float tmin, tmax; vector save; - - wp = navigation_findnearestwaypoint(p, walkfromwp); + + if(!botframe_autowaypoints_fixdown(p.origin)) + return -2; + porg = trace_endpos; + if(wp) - return; + { + // if nearest WP from here is linked to wp, everything is fine + w = navigation_findnearestwaypoint(p, walkfromwp); + if(w != wp) + { + if(navigation_waypoint_will_link(w.origin, wp.origin, p, walkfromwp, 1050)) + { + print("update chain from ", etos(p.fld), " to new nearest WP ", etos(w), "\n"); + p.fld = w; + return 0; + } + } + if(navigation_waypoint_will_link(p.origin, wp.origin, p, walkfromwp, 1050)) + { + p.fld = wp; + return 0; + } + } + else + { + w = navigation_findnearestwaypoint(p, walkfromwp); + if(w) + { + p.fld = w; + return 0; + } + } tmin = 0; tmax = 1; for(;;) { + if(tmax - tmin < 0.001) + { + // did not get a good candidate + return -1; + } + t = (tmin + tmax) * 0.5; o = antilag_takebackorigin(p, time - t); - save = p.origin; - setorigin(p, o); - wp = navigation_findnearestwaypoint(p, walkfromwp); - setorigin(p, save); + if(!botframe_autowaypoints_fixdown(o)) + return -1; + o = trace_endpos; + if(wp) { - if(walkfromwp) - { - if(tracewalk(p, o, PL_MIN, PL_MAX, p.origin, bot_navigation_movemode)) - break; - } - else + if(!navigation_waypoint_will_link(wp.origin, o, p, walkfromwp, 1050)) { - if(tracewalk(p, p.origin, PL_MIN, PL_MAX, o, bot_navigation_movemode)) - break; + // we cannot walk from wp.origin to o + // get closer to tmax + tmin = t; + continue; } - // if we get here: o has a nearest waypoint, but can't reach us - // i.e. move towards current location - tmax = t; } else { - // if we get here: o has no nearest waypoint - // i.e. move closer to to the past - tmin = t; - } - if(tmax - tmin < 0.01) - { - print("Cannot link waypoints - didn't find a good new WP position\n"); - return; + save = p.origin; + setorigin(p, o); + w = navigation_findnearestwaypoint(p, walkfromwp); + setorigin(p, save); + if(!w) + { + // we cannot walk from any WP to o + // get closer to tmax + tmin = t; + continue; + } } + + // if we get here, o is valid regarding waypoints + // check if o is connected right to the player + // we break if it succeeds, as that means o is a good waypoint location + if(navigation_waypoint_will_link(o, porg, p, walkfromwp, 1050)) + break; + + // o is no good, we need to get closer to the player + tmax = t; } - waypoint_schedulerelink(waypoint_spawn(o, o, 0)); - p.last = max(1, time - t); + print("spawning a waypoint for connecting to ", etos(wp), "\n"); + waypoint_schedulerelink(p.fld = waypoint_spawn(o, o, 0)); + print("new waypoint is ", etos(p.fld), "\n"); + return 1; +} + +// automatically create missing waypoints +.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1; +void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld) +{ + float r; + r = botframe_autowaypoints_fix_from(p, walkfromwp, p.fld, fld); + if(r != -1) + return; + r = botframe_autowaypoints_fix_from(p, walkfromwp, world, fld); + if(r != -1) + return; + + print("emergency: got no good nearby WP to build a link from, starting a new chain\n"); + if(!botframe_autowaypoints_fixdown(p.origin)) + return; // shouldn't happen, caught above + waypoint_schedulerelink(p.fld = waypoint_spawn(trace_endpos, trace_endpos, 0)); } void botframe_autowaypoints() { @@ -940,7 +1014,11 @@ void botframe_autowaypoints() entity wp0, wp1; FOR_EACH_REALPLAYER(p) { - botframe_autowaypoints_fix(p, FALSE, lastwaypointtime0); - botframe_autowaypoints_fix(p, TRUE, lastwaypointtime1); + if(p.deadflag) + continue; + if(!(p.flags & FL_ONGROUND)) + continue; + botframe_autowaypoints_fix(p, FALSE, botframe_autowaypoints_lastwp0); + botframe_autowaypoints_fix(p, TRUE, botframe_autowaypoints_lastwp1); } } -- 2.39.2