X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fbot%2Fnavigation.qc;h=636c0d58a0871945da808c91d61a971e4e3fd9bf;hp=8f72014a2eb9f6992993dea2dd6eab3417c09a13;hb=b8e3716086cc9249b2f93f86f082e1acbc922383;hpb=0d17ea4a6fc382131b4f06e971f8abe9d2ae97a2 diff --git a/qcsrc/server/bot/navigation.qc b/qcsrc/server/bot/navigation.qc index 8f72014a2..636c0d58a 100644 --- a/qcsrc/server/bot/navigation.qc +++ b/qcsrc/server/bot/navigation.qc @@ -133,36 +133,42 @@ float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float // hit something if (trace_fraction < 1) { - // check if we can walk over this obstacle + // check if we can walk over this obstacle, possibly by jumpstepping tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e); if (trace_fraction < 1 || trace_startsolid) { - if(autocvar_bot_debug_tracewalk) - debugnodestatus(trace_endpos, DEBUG_NODE_WARNING); - - // check for doors - traceline( org, move, movemode, e); - if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door") + tracebox(org + jumpstepheightvec, m1, m2, move + jumpstepheightvec, movemode, e); + if (trace_fraction < 1 || trace_startsolid) { - local vector nextmove; - move = trace_endpos; - while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door") + if(autocvar_bot_debug_tracewalk) + debugnodestatus(trace_endpos, DEBUG_NODE_WARNING); + + // check for doors + traceline( org, move, movemode, e); + if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door") { - nextmove = move + (dir * stepdist); - traceline( move, nextmove, movemode, e); - move = nextmove; + local vector nextmove; + move = trace_endpos; + while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door") + { + nextmove = move + (dir * stepdist); + traceline( move, nextmove, movemode, e); + move = nextmove; + } } - } - else - { - if(autocvar_bot_debug_tracewalk) - debugnodestatus(trace_endpos, DEBUG_NODE_FAIL); + else + { + if(autocvar_bot_debug_tracewalk) + debugnodestatus(trace_endpos, DEBUG_NODE_FAIL); - //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n"); - //te_explosion(trace_endpos); - //print(ftos(e.dphitcontentsmask), "\n"); - return FALSE; // failed + //print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n"); + //te_explosion(trace_endpos); + //print(ftos(e.dphitcontentsmask), "\n"); + return FALSE; // failed + } } + else + move = trace_endpos; } else move = trace_endpos; @@ -641,16 +647,22 @@ void navigation_markroutes_inverted(entity fixed_source_waypoint) void navigation_routerating(entity e, float f, float rangebias) { entity nwp; + vector o; if (!e) return; + if(e.blacklisted) + return; + + o = (e.absmin + e.absmax) * 0.5; + //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n"); // Evaluate path using jetpack if(g_jetpack) if(self.items & IT_JETPACK) if(autocvar_bot_ai_navigation_jetpack) - if(vlen(self.origin - e.origin) > autocvar_bot_ai_navigation_jetpack_mindistance) + if(vlen(self.origin - o) > autocvar_bot_ai_navigation_jetpack_mindistance) { vector pointa, pointb; @@ -661,7 +673,7 @@ void navigation_routerating(entity e, float f, float rangebias) pointa = trace_endpos - '0 0 1'; // Point B - traceline(e.origin, e.origin + '0 0 65535', MOVE_NORMAL, e); + traceline(o, o + '0 0 65535', MOVE_NORMAL, e); pointb = trace_endpos - '0 0 1'; // Can I see these two points from the sky? @@ -745,14 +757,48 @@ void navigation_routerating(entity e, float f, float rangebias) } else { + float search; + + search = TRUE; + + if(e.flags & FL_ITEM) + { + if not(e.flags & FL_WEAPON) + if(e.nearestwaypoint) + search = FALSE; + } + else if (e.flags & FL_WEAPON) + { + if(e.classname != "droppedweapon") + if(e.nearestwaypoint) + search = FALSE; + } + + if(search) if (time > e.nearestwaypointtimeout) { nwp = navigation_findnearestwaypoint(e, TRUE); if(nwp) e.nearestwaypoint = nwp; else + { dprint("FAILED to find a nearest waypoint to '", e.classname, "' #", etos(e), "\n"); + if(e.flags & FL_ITEM) + e.blacklisted = TRUE; + else if (e.flags & FL_WEAPON) + { + if(e.classname != "droppedweapon") + e.blacklisted = TRUE; + } + + if(e.blacklisted) + { + dprint("The entity '", e.classname, "' is going to be excluded from path finding during this match\n"); + return; + } + } + // TODO: Cleaner solution, probably handling this timeout from ctf.qc if(e.classname=="item_flag_team") e.nearestwaypointtimeout = time + 2; @@ -768,7 +814,7 @@ void navigation_routerating(entity e, float f, float rangebias) { //te_wizspike(nwp.wpnearestpoint); // dprint(e.classname, " ", ftos(f), "/(1+", ftos((nwp.wpcost + vlen(e.origin - nwp.wpnearestpoint))), "/", ftos(rangebias), ") = "); - f = f * rangebias / (rangebias + (nwp.wpcost + vlen(e.origin - nwp.wpnearestpoint))); + f = f * rangebias / (rangebias + (nwp.wpcost + vlen(o - nwp.wpnearestpoint))); //dprint("considering ", e.classname, " (with rating ", ftos(f), ")\n"); //dprint(ftos(f)); if (navigation_bestrating < f) @@ -801,7 +847,7 @@ float navigation_routetogoal(entity e, vector startposition) return TRUE; // if it can reach the goal there is nothing more to do - if (tracewalk(self, startposition, PL_MIN, PL_MAX, e.origin, bot_navigation_movemode)) + if (tracewalk(self, startposition, PL_MIN, PL_MAX, (e.absmin + e.absmax) * 0.5, bot_navigation_movemode)) return TRUE; // see if there are waypoints describing a path to the item @@ -851,8 +897,34 @@ void navigation_poptouchedgoals() } } + // If for some reason the bot is closer to the next goal, pop the current one + if(self.goalstack01) + if(vlen(self.goalcurrent.origin - self.origin) > vlen(self.goalstack01.origin - self.origin)) + if(checkpvs(self.origin + self.view_ofs, self.goalstack01)) + if(tracewalk(self, self.origin, self.mins, self.maxs, (self.goalstack01.absmin + self.goalstack01.absmax) * 0.5, bot_navigation_movemode)) + { + /// dprint("path optimized for ", self.netname, ", removed a goal from the queue\n"); + navigation_poproute(); + // TODO this may also be a nice idea to do "early" (e.g. by + // manipulating the vlen() comparisons) to shorten paths in + // general - this would make bots walk more "on rails" than + // "zigzagging" which they currently do with sufficiently + // random-like waypoints, and thus can make a nice bot + // personality property + } + + // HACK: remove players/bots as goals, they can lead a bot to unexpected places (cliffs, lava, etc) + // TODO: rate waypoints near the targetted player at that moment, instead of the player itself + if(self.goalcurrent.classname=="player") + navigation_poproute(); + + // aid for detecting jump pads better (distance based check fails sometimes) + if(self.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT && self.jumppadcount > 0 ) + navigation_poproute(); + // Loose goal touching check when running if(self.aistatus & AI_STATUS_RUNNING) + if(self.speed >= autocvar_sv_maxspeed) // if -really- running if(self.goalcurrent.classname=="waypoint") { if(vlen(self.origin - self.goalcurrent.origin)<150) @@ -927,7 +999,7 @@ void navigation_goalrating_end() void botframe_updatedangerousobjects(float maxupdate) { local entity head, bot_dodgelist; - local vector m1, m2, v; + local vector m1, m2, v, o; local float c, d, danger; c = 0; bot_dodgelist = findchainfloat(bot_dodge, TRUE); @@ -944,10 +1016,11 @@ void botframe_updatedangerousobjects(float maxupdate) v_x = bound(m1_x, v_x, m2_x); v_y = bound(m1_y, v_y, m2_y); v_z = bound(m1_z, v_z, m2_z); - d = head.bot_dodgerating - vlen(head.origin - v); + o = (head.absmin + head.absmax) * 0.5; + d = head.bot_dodgerating - vlen(o - v); if (d > 0) { - traceline(head.origin, v, TRUE, world); + traceline(o, v, TRUE, world); if (trace_fraction == 1) danger = danger + d; } @@ -963,12 +1036,14 @@ void botframe_updatedangerousobjects(float maxupdate) void navigation_unstuck() { + float search_radius = 1000; + if not(autocvar_bot_wander_enable) return; if not(bot_waypoint_queue_owner) { - dprint(self.netname, " taking over the waypoints queue\n"); + // dprint(self.netname, " sutck, taking over the waypoints queue\n"); bot_waypoint_queue_owner = self; bot_waypoint_queue_bestgoal = world; bot_waypoint_queue_bestgoalrating = 0; @@ -996,13 +1071,14 @@ void navigation_unstuck() { if (bot_waypoint_queue_bestgoal) { + dprint(self.netname, " stuck, reachable waypoint found, heading to it\n"); navigation_routetogoal(bot_waypoint_queue_bestgoal, self.origin); self.bot_strategytime = time + autocvar_bot_ai_strategyinterval; self.aistatus &~= AI_STATUS_STUCK; } else { - dprint(self.netname, " got BADLY stuck, giving up.\n"); + dprint(self.netname, " stuck, cannot walk to any waypoint at all\n"); } bot_waypoint_queue_owner = world; @@ -1014,17 +1090,17 @@ void navigation_unstuck() return; // build a new queue - dprint(self.netname, " building a new wayoints queue\n"); + dprint(self.netname, " stuck, scanning reachable waypoints within ", ftos(search_radius)," qu\n"); entity head, first; first = world; - head = findradius(self.origin, 1000); + head = findradius(self.origin, search_radius); while(head) { if(head.classname=="waypoint") - if(!(head.wpflags & WAYPOINTFLAG_GENERATED)) + // if(!(head.wpflags & WAYPOINTFLAG_GENERATED)) { if(bot_waypoint_queue_goal) bot_waypoint_queue_goal.bot_waypoint_queue_nextgoal = head; @@ -1042,7 +1118,8 @@ void navigation_unstuck() bot_waypoint_queue_goal = first; else { - dprint(self.netname, " got BADLY stuck, giving up.\n"); + dprint(self.netname, " stuck, cannot walk to any waypoint at all\n"); + bot_waypoint_queue_owner = world; } } } @@ -1100,7 +1177,7 @@ void debugnodestatus(vector position, float status) void debuggoalstack() { local entity goal; - local vector org; + local vector org, go; if(self.goalcounter==0)goal=self.goalcurrent; else if(self.goalcounter==1)goal=self.goalstack01; @@ -1148,8 +1225,9 @@ void debuggoalstack() org = self.lastposition; - te_lightning2(world, org, goal.origin); - self.lastposition = goal.origin; + go = ( goal.absmin + goal.absmax ) * 0.5; + te_lightning2(world, org, go); + self.lastposition = go; self.goalcounter++; }