]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Added a better handling of stuck bots. Walkability is checked for every potential...
authormand1nga <mand1nga@xonotic.org>
Wed, 20 Apr 2011 07:34:23 +0000 (04:34 -0300)
committermand1nga <mand1nga@xonotic.org>
Wed, 20 Apr 2011 07:34:23 +0000 (04:34 -0300)
qcsrc/server/bot/bot.qc
qcsrc/server/bot/bot.qh
qcsrc/server/bot/navigation.qc
qcsrc/server/bot/navigation.qh

index 581e3f0c758050dae69b33c9c983a98a4ba735c4..5c70af58c7c2ded0bbb76abeb7dd896b9da7d511 100644 (file)
@@ -99,6 +99,10 @@ void bot_think()
                }
        }
 
+       //
+       if(self.aistatus & AI_STATUS_STUCK)
+               navigation_unstuck();
+
        // now call the current bot AI (havocbot for example)
        self.bot_ai();
 };
@@ -374,6 +378,8 @@ void bot_clientdisconnect()
        self.playermodel_freeme = string_null;
        self.playerskin_freeme = string_null;
        remove(self.bot_cmd_current);
+       if(navigation_wander_owner==self)
+               navigation_wander_owner = world;
 }
 
 void bot_clientconnect()
index 9e6d447e6a8d22ef3b9e857e32f00efe67b282d1..b4556bb76b95cfdbc561c440f6e18029f7222d3c 100644 (file)
@@ -13,6 +13,7 @@ float AI_STATUS_WAYPOINT_PERSONAL_GOING               = 128;  // Going to a personal waypoint
 float AI_STATUS_WAYPOINT_PERSONAL_REACHED      = 256;  // Personal waypoint reached
 float AI_STATUS_JETPACK_FLYING                 = 512;
 float AI_STATUS_JETPACK_LANDING                        = 1024;
+float AI_STATUS_STUCK                  = 2048; // bot cannot reach any useful goal
 
 .float isbot; // true if this client is actually a bot
 .float aistatus;
index e460bdc57e1ad84d2661be3753e5e267e9d75042..e39c5408d1fed2ebf54080bc94c6a56f3a32fe9c 100644 (file)
@@ -890,6 +890,9 @@ void navigation_poptouchedgoals()
 // begin a goal selection session (queries spawnfunc_waypoint network)
 void navigation_goalrating_start()
 {
+       if(self.aistatus & AI_STATUS_STUCK)
+               return;
+
        self.navigation_jetpack_goal = world;
        navigation_bestrating = -1;
        self.navigation_hasgoals = FALSE;
@@ -901,31 +904,21 @@ void navigation_goalrating_start()
 // ends a goal selection session (updates goal stack to the best goal)
 void navigation_goalrating_end()
 {
+       if(self.aistatus & AI_STATUS_STUCK)
+               return;
+
        navigation_routetogoal(navigation_bestgoal, self.origin);
 //     dprint("best goal ", self.goalcurrent.classname , "\n");
 
-       // Hack: if it can't walk to any goal just move blindly to the first visible waypoint
+       // If the bot got stuck then try to reach the farthest waypoint
        if not (self.navigation_hasgoals)
        if (autocvar_bot_wander_enable)
        {
-               if not(autocvar_g_campaign)
-                       dprint(self.netname, " can't walk to any goal, going to a near waypoint\n");
-
-               entity head;
-
-               RandomSelection_Init();
-               head = findradius(self.origin,1000);
-               while(head)
+               if not(self.aistatus & AI_STATUS_STUCK)
                {
-                       if(head.classname=="waypoint")
-                       if(!(head.wpflags & WAYPOINTFLAG_GENERATED))
-                       if(vlen(self.origin-head.origin)>100)
-                       if(checkpvs(self.view_ofs,head))
-                               RandomSelection_Add(head, 0, string_null, 1 + (vlen(self.origin-head.origin)<500), 0);
-                       head = head.chain;
+                       dprint(self.netname, " cannot walk to any goal\n");
+                       self.aistatus |= AI_STATUS_STUCK;
                }
-               if(RandomSelection_chosen_ent)
-                       navigation_routetogoal(RandomSelection_chosen_ent, self.origin);
 
                self.navigation_hasgoals = FALSE; // Reset this value
        }
@@ -968,6 +961,90 @@ void botframe_updatedangerousobjects(float maxupdate)
        }
 };
 
+void navigation_unstuck()
+{
+       if not(navigation_wander_owner)
+       {
+               dprint(self.netname, " taking over the waypoints queue\n");
+               navigation_wander_owner = self;
+               navigation_wander_bestgoal = world;
+               navigation_wander_bestgoalrating = 0;
+       }
+
+       if(navigation_wander_owner!=self)
+               return;
+
+       if (navigation_wander_goal)
+       {
+               // evaluate the next goal on the queue
+               float d = vlen(self.origin - navigation_wander_goal.origin);
+               dprint(self.netname, " evaluating ", navigation_wander_goal.classname, " with distance ", ftos(d), "\n");
+               if(tracewalk(navigation_wander_goal, self.origin, PL_MIN, PL_MAX, navigation_wander_goal.origin, bot_navigation_movemode))
+               {
+                       if( d > navigation_wander_bestgoalrating)
+                       {
+                               navigation_wander_bestgoalrating = d;
+                               navigation_wander_bestgoal = navigation_wander_goal;
+                       }
+               }
+               navigation_wander_goal = navigation_wander_goal.navigation_wander_nextgoal;
+
+               if not(navigation_wander_goal)
+               {
+                       if (navigation_wander_bestgoal)
+                       {
+                               navigation_routetogoal(navigation_wander_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");
+                       }
+
+                       navigation_wander_owner = world;
+               }
+       }
+       else
+       {
+               // build a new queue
+               dprint(self.netname, " building a new wayoints queue\n");
+
+               entity first, head, prev;
+               head = findradius(self.origin, 1000);
+
+               while(head)
+               {
+                       if(head.classname=="waypoint")
+                       if(!(head.wpflags & WAYPOINTFLAG_GENERATED))
+                       if(vlen(self.origin-head.origin)>100)
+                       {
+                               if (first==world)
+                               {
+                                       first = head;
+                                       navigation_wander_goal = head;
+                               }
+                               else
+                               {
+                                       prev = navigation_wander_goal;
+                                       navigation_wander_goal = head;
+                                       prev.navigation_wander_nextgoal = head;
+                                       navigation_wander_goal.navigation_wander_nextgoal = world;
+                               }
+                       }
+
+                       head = head.chain;
+               }
+
+               if (first)
+                       navigation_wander_goal = first;
+               else
+               {
+                       dprint(self.netname, " got BADLY stuck, giving up.\n");
+               }
+       }
+}
+
 // Support for debugging tracewalk visually
 
 void debugresetnodes()
index 06bbb85c310101f51b4cf2f799691e9a9fae9837..6355ef70056f0b8c74d9ddd0787e4782dba72f7c 100644 (file)
@@ -35,6 +35,12 @@ float DEBUG_NODE_WARNING        = 2;
 float DEBUG_NODE_FAIL           = 3;
 vector debuglastnode;
 
+entity navigation_wander_owner;        // Owner of the temporary list of goals
+entity navigation_wander_goal;         // Head of the temporary list of goals
+.entity navigation_wander_nextgoal;
+entity navigation_wander_bestgoal;
+float navigation_wander_bestgoalrating;
+
 /*
  * Functions
  */
@@ -60,6 +66,7 @@ void navigation_routerating(entity e, float f, float rangebias);
 void navigation_poptouchedgoals();
 void navigation_goalrating_start();
 void navigation_goalrating_end();
+void navigation_unstuck();
 
 void botframe_updatedangerousobjects(float maxupdate);