]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/navigation.qc
Merge branch 'master' into terencehill/bot_ai
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / navigation.qc
index c79ed40a4304cac996f80b84b2917d94ec44ee0e..4665be482a69287c8eb0d3d46b4b292e226f7717 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
 
 .float speed;
 
@@ -246,6 +246,7 @@ vector resurface_limited(vector org, float lim, vector m1)
 // rough simulation of walking from one point to another to test if a path
 // can be traveled, used for waypoint linking and havocbot
 // if end_height is > 0 destination is any point in the vertical segment [end, end + end_height * eZ]
+// INFO: the command sv_cmd trace walk is useful to test this function in game
 bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
 {
        if(autocvar_bot_debug_tracewalk)
@@ -264,8 +265,7 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float e
        int nav_action;
 
        // Analyze starting point
-       traceline(start, start, MOVE_NORMAL, e);
-       if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
+       if (IN_LAVA(start))
                ignorehazards = true;
 
        tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
@@ -731,6 +731,7 @@ void navigation_clearroute(entity this)
        this.goalcurrent_distance_z = FLOAT_MAX;
        this.goalcurrent_distance_time = 0;
        this.goalentity_lock_timeout = 0;
+       this.goalentity_shouldbefrozen = false;
        this.goalentity = NULL;
        this.goalcurrent = NULL;
        this.goalstack01 = NULL;
@@ -1233,12 +1234,13 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                {
                        entity theEnemy = e;
                        entity best_wp = NULL;
-                       float best_dist = 10000;
-                       IL_EACH(g_waypoints, vdist(it.origin - theEnemy.origin, <, 500)
+                       float best_dist = FLOAT_MAX;
+                       IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT)
+                               && vdist(it.origin - theEnemy.origin, <, 500)
                                && vdist(it.origin - this.origin, >, 100)
-                               && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+                               && vdist(it.origin - this.origin, <, 10000),
                        {
-                               float dist = vlen(it.origin - theEnemy.origin);
+                               float dist = vlen2(it.origin - theEnemy.origin);
                                if (dist < best_dist)
                                {
                                        best_wp = it;
@@ -1256,7 +1258,6 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
        //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
 
        // Evaluate path using jetpack
-       if(g_jetpack)
        if(this.items & IT_JETPACK)
        if(autocvar_bot_ai_navigation_jetpack)
        if(vdist(this.origin - goal_org, >, autocvar_bot_ai_navigation_jetpack_mindistance))
@@ -1315,10 +1316,10 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                        t += xydistance / autocvar_g_jetpack_maxspeed_side;
                        fuel = t * autocvar_g_jetpack_fuel * 0.8;
 
-                       LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
+                       LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), ", have ", ftos(GetResourceAmount(this, RESOURCE_FUEL)));
 
                        // enough fuel ?
-                       if(this.ammo_fuel>fuel)
+                       if(GetResourceAmount(this, RESOURCE_FUEL) > fuel || (this.items & IT_UNLIMITED_WEAPON_AMMO))
                        {
                                // Estimate cost
                                // (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
@@ -1387,7 +1388,6 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                nwp = e.nearestwaypoint;
        }
 
-       LOG_DEBUG("-- checking ", e.classname, " (with cost ", ftos(nwp.wpcost), ")");
        if (nwp && nwp.wpcost < 10000000)
        {
                //te_wizspike(nwp.wpnearestpoint);
@@ -1397,12 +1397,12 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                else
                        nwptoitem_cost = waypoint_gettravelcost(nwp.wpnearestpoint, goal_org, nwp, e);
                float cost = nwp.wpcost + nwptoitem_cost;
-               LOG_DEBUG(e.classname, " ", ftos(f), "/(1+", ftos(cost), "/", ftos(rangebias), ") = ");
+               LOG_DEBUG("checking ^5", e.classname, "^7 with base rating ^xf04", ftos(f), "^7 and rangebias ^xf40", ftos(rangebias));
                f = f * rangebias / (rangebias + cost);
-               LOG_DEBUG("considering ", e.classname, " (with rating ", ftos(f), ")");
+               LOG_DEBUG("         ^5", e.classname, "^7 with cost ^6", ftos(cost), "^7 and final rating ^2", ftos(f));
                if (navigation_bestrating < f)
                {
-                       LOG_DEBUG("ground path: added goal ", e.classname, " (with rating ", ftos(f), ")");
+                       LOG_DEBUG(" ground path: ^3added goal ^5", e.classname);
                        navigation_bestrating = f;
                        navigation_bestgoal = e;
                }
@@ -1509,12 +1509,12 @@ bool navigation_routetogoal(entity this, entity e, vector startposition)
 }
 
 // shorten path by removing intermediate goals
-void navigation_shortenpath(entity this)
+bool navigation_shortenpath(entity this)
 {
        if (!this.goalstack01 || wasfreed(this.goalstack01))
-               return;
+               return false;
        if (this.bot_tracewalk_time > time)
-               return;
+               return false;
        this.bot_tracewalk_time = max(time, this.bot_tracewalk_time) + 0.25;
 
        bool cut_allowed = false;
@@ -1553,8 +1553,9 @@ void navigation_shortenpath(entity this)
                                        navigation_poproute(this);
                                }
                                while (this.goalcurrent != next);
+                               return true;
                        }
-                       return;
+                       return false;
                }
        }
 
@@ -1575,8 +1576,10 @@ void navigation_shortenpath(entity this)
                {
                        LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
                        navigation_poproute(this);
+                       return true;
                }
        }
+       return false;
 }
 
 // removes any currently touching waypoints from the goal stack
@@ -1600,6 +1603,16 @@ int navigation_poptouchedgoals(entity this)
                                this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
                                this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
                        }
+                       if(this.jumppadcount)
+                       {
+                               // remove jumppad waypoint after a random delay to prevent bots getting
+                               // stuck on certain jumppads that require an extra initial horizontal speed
+                               float max_delay = 0.1;
+                               if (vdist(vec2(this.velocity), >, 2 * autocvar_sv_maxspeed))
+                                       max_delay = 0.05;
+                               if (time - this.lastteleporttime < random() * max_delay)
+                                       return removed_goals;
+                       }
                        navigation_poproute(this);
                        this.lastteleporttime = 0;
                        ++removed_goals;
@@ -1770,6 +1783,7 @@ void navigation_goalrating_end(entity this)
                        this.aistatus |= AI_STATUS_STUCK;
                }
        }
+       this.goalentity_shouldbefrozen = boolean(STAT(FROZEN, this.goalentity));
 }
 
 void botframe_updatedangerousobjects(float maxupdate)
@@ -1839,7 +1853,7 @@ void navigation_unstuck(entity this)
                float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
                LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d));
                set_tracewalk_dest(bot_waypoint_queue_goal, this.origin, false);
-               if (tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
+               if (tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
                        tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
                {
                        if( d > bot_waypoint_queue_bestgoalrating)