]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/bot_fix
authorterencehill <piuntn@gmail.com>
Thu, 29 Dec 2016 01:59:28 +0000 (02:59 +0100)
committerterencehill <piuntn@gmail.com>
Thu, 29 Dec 2016 01:59:28 +0000 (02:59 +0100)
defaultXonotic.cfg
qcsrc/common/items/item/armor.qh
qcsrc/common/t_items.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/bot.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/navigation.qc

index bf35a4189ef44d0fb966bdf8ae93a94c33db6122..bbdbdcb74a4873406ac60d3c4ac72fc158aba72e 100644 (file)
@@ -382,7 +382,7 @@ set bot_ai_friends_aware_pickup_radius "500"        "Bots will not pickup items if a te
 set bot_ai_ignoregoal_timeout 3        "Ignore goals making bots to get stuck in front of a wall for N seconds"
 set bot_ai_bunnyhop_skilloffset 7      "Bots with skill equal or greater than this value will perform the  \"bunnyhop\" technique"
 set bot_ai_bunnyhop_startdistance 200 "Run to goals located further than this distance"
-set bot_ai_bunnyhop_stopdistance 200 "Stop jumping after reaching this distance to the goal"
+set bot_ai_bunnyhop_stopdistance 300 "Stop jumping after reaching this distance to the goal"
 set bot_ai_bunnyhop_firstjumpdelay 0.2 "Start running to the goal only if it was seen for more than N seconds"
 set bot_god 0 "god mode for bots"
 set bot_ai_navigation_jetpack 0 "Enable bots to navigate maps using the jetpack"
index b222ca62894465b23364409bb9d369fe478d53c3..4b6b9fdf6c4c8554599bdcc9e3e14830ea699fd3 100644 (file)
@@ -68,7 +68,7 @@ REGISTER_ITEM(ArmorBig, Armor) {
     this.m_color                =   '0 1 0';
     this.m_waypoint             =   _("Big armor");
 #ifdef SVQC
-    this.m_botvalue             =   20000; // FIXME: higher than BOT_PICKUP_RATING_HIGH?
+    this.m_botvalue             =   BOT_PICKUP_RATING_HIGH;
     this.m_itemid               =   IT_ARMOR;
     this.m_respawntime          =   GET(g_pickup_respawntime_long);
     this.m_respawntimejitter    =   GET(g_pickup_respawntimejitter_long);
index cacbfdcea855fe4bd33cf839e8011b65d5f5f0a6..9d89679e3be9f88817ea8abd9883774c36eca22a 100644 (file)
@@ -924,17 +924,20 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup
 float weapon_pickupevalfunc(entity player, entity item)
 {
        float c;
+       int rating = item.bot_pickupbasevalue;
 
        // See if I have it already
-       if(item.weapons & ~player.weapons)
+       if(player.weapons & item.weapons)
        {
                // If I can pick it up
                if(!item.spawnshieldtime)
                        c = 0;
                else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
                {
+                       if (rating > 0)
+                               rating = BOT_PICKUP_RATING_LOW * 0.5 * (1 + rating / BOT_PICKUP_RATING_HIGH);
                        // Skilled bots will grab more
-                       c = bound(0, skill / 10, 1) * 0.5;
+                       c = 1 + bound(0, skill / 10, 1) * 0.5;
                }
                else
                        c = 0;
@@ -942,58 +945,74 @@ float weapon_pickupevalfunc(entity player, entity item)
        else
                c = 1;
 
+       if (c <= 0)
+               return 0;
+
        // If custom weapon priorities for bots is enabled rate most wanted weapons higher
-       if( bot_custom_weapon && c )
-       {
-               // Find the highest position on any range
-               int position = -1;
-               for (int j = 0; j < WEP_LAST ; ++j){
-                       if(
-                                       bot_weapons_far[j] == item.weapon ||
-                                       bot_weapons_mid[j] == item.weapon ||
-                                       bot_weapons_close[j] == item.weapon
-                         )
+       if(bot_custom_weapon)
+       {
+               int best_ratio = 0;
+               int missing = 0;
+
+               // evaluate weapon usefulness in all ranges
+               for(int list = 0; list < 3; list++)
+               {
+                       int position = -1;
+                       int wep_count = 0;
+                       int wpn = item.weapon;
+                       for (int j = 0; j < WEP_LAST; ++j)
                        {
-                               position = j;
-                               break;
+                               int list_wpn = 0;
+                               if (list == 0) list_wpn = bot_weapons_far[j];
+                               else if (list == 1) list_wpn = bot_weapons_mid[j];
+                               else list_wpn = bot_weapons_close[j];
+
+                               if (weaponsInMap & Weapons_from(list_wpn).m_wepset) // only if available
+                               {
+                                       if (list_wpn > 0)
+                                               wep_count++;
+                                       if (position == -1 && list_wpn == wpn)
+                                               position = wep_count;
+                               }
+                       }
+                       if (position == -1)
+                       {
+                               missing++;
+                               position = wep_count; // if missing assume last
+                       }
+                       if (wep_count)
+                       {
+                               if (!best_ratio || position / wep_count < best_ratio)
+                                       best_ratio = position / wep_count;
                        }
                }
 
-               // Rate it
-               if (position >= 0 )
-               {
-                       position = WEP_LAST - position;
-                       // item.bot_pickupbasevalue is overwritten here
-                       return (BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ))) * c;
-               }
+               if (missing < 3 && best_ratio)
+                       c = c - best_ratio * 0.3;
        }
 
-       return item.bot_pickupbasevalue * c;
+       return rating * c;
 }
 
 float commodity_pickupevalfunc(entity player, entity item)
 {
-       float c;
-       float need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
-       c = 0;
+       bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
+       float c = 0;
 
        // Detect needed ammo
        FOREACH(Weapons, it != WEP_Null, {
                if(!(player.weapons & (it.m_wepset)))
                        continue;
 
-               if(it.items & ITEM_Shells.m_itemid)
-                       need_shells = true;
-               else if(it.items & ITEM_Bullets.m_itemid)
-                       need_nails = true;
-               else if(it.items & ITEM_Rockets.m_itemid)
-                       need_rockets = true;
-               else if(it.items & ITEM_Cells.m_itemid)
-                       need_cells = true;
-               else if(it.items & ITEM_Plasma.m_itemid)
-                       need_plasma = true;
-               else if(it.items & ITEM_JetpackFuel.m_itemid)
-                       need_fuel = true;
+               switch(it.ammo_field)
+               {
+                       case ammo_shells:  need_shells  = true; break;
+                       case ammo_nails:   need_nails   = true; break;
+                       case ammo_rockets: need_rockets = true; break;
+                       case ammo_cells:   need_cells   = true; break;
+                       case ammo_plasma:  need_plasma  = true; break;
+                       case ammo_fuel:    need_fuel    = true; break;
+               }
        });
 
        // TODO: figure out if the player even has the weapon this ammo is for?
index ed9070f9cdd60821538da821afdceab6a2405cab..fb6f1e046d9da192218b8d78da18474b87de4b67 100644 (file)
@@ -64,6 +64,8 @@ void bot_think(entity this)
                this.flags |= FL_GODMODE;
 
        this.bot_nextthink = this.bot_nextthink + autocvar_bot_ai_thinkinterval * pow(0.5, this.bot_aiskill);
+       if(this.bot_nextthink < time)
+               this.bot_nextthink = time + autocvar_bot_ai_thinkinterval * pow(0.5, this.bot_aiskill);
        //if (this.bot_painintensity > 0)
        //      this.bot_painintensity = this.bot_painintensity - (skill + 1) * 40 * frametime;
 
index 05c6a5ed9a0643b4a1d8232c70a13d96262009b9..f615c040360f7f2bbbc85f296137c60c1c8c2765 100644 (file)
@@ -3,18 +3,18 @@
  * Globals and Fields
  */
 
-const int AI_STATUS_ROAMING                                            = BIT(0);       // Bot is just crawling the map. No enemies at sight
-const int AI_STATUS_ATTACKING                                  = BIT(1);       // There are enemies at sight
-const int AI_STATUS_RUNNING                                            = BIT(2);       // Bot is bunny hopping
-const int AI_STATUS_DANGER_AHEAD                               = BIT(3);       // There is lava/slime/trigger_hurt ahead
-const int AI_STATUS_OUT_JUMPPAD                                        = BIT(4);       // Trying to get out of a "vertical" jump pad
-const int AI_STATUS_OUT_WATER                                  = BIT(5);       // Trying to get out of water
-const int AI_STATUS_WAYPOINT_PERSONAL_LINKING  = BIT(6);       // Waiting for the personal waypoint to be linked
-const int AI_STATUS_WAYPOINT_PERSONAL_GOING            = BIT(7);       // Going to a personal waypoint
-const int AI_STATUS_WAYPOINT_PERSONAL_REACHED  = BIT(8);       // Personal waypoint reached
-const int AI_STATUS_JETPACK_FLYING                             = BIT(9);
-const int AI_STATUS_JETPACK_LANDING                            = BIT(10);
-const int AI_STATUS_STUCK                                              = BIT(11);  // Cannot reach any goal
+const int AI_STATUS_ROAMING                    = BIT(0); // Bot is just crawling the map. No enemies at sight
+const int AI_STATUS_ATTACKING                  = BIT(1); // There are enemies at sight
+const int AI_STATUS_RUNNING                    = BIT(2); // Bot is bunny hopping
+const int AI_STATUS_DANGER_AHEAD               = BIT(3); // There is lava/slime/trigger_hurt ahead
+const int AI_STATUS_OUT_JUMPPAD                = BIT(4); // Trying to get out of a "vertical" jump pad
+const int AI_STATUS_OUT_WATER                  = BIT(5); // Trying to get out of water
+const int AI_STATUS_WAYPOINT_PERSONAL_LINKING  = BIT(6); // Waiting for the personal waypoint to be linked
+const int AI_STATUS_WAYPOINT_PERSONAL_GOING    = BIT(7); // Going to a personal waypoint
+const int AI_STATUS_WAYPOINT_PERSONAL_REACHED  = BIT(8); // Personal waypoint reached
+const int AI_STATUS_JETPACK_FLYING             = BIT(9);
+const int AI_STATUS_JETPACK_LANDING            = BIT(10);
+const int AI_STATUS_STUCK                      = BIT(11); // Cannot reach any goal
 
 .float isbot; // true if this client is actually a bot
 .int aistatus;
index c26d768b038ae55501eb01c011dbb8c07ba74527..d211397d3bb057d108e97852fe212ce6d9d7f6d3 100644 (file)
@@ -29,13 +29,6 @@ void havocbot_ai(entity this)
        if(bot_execute_commands(this))
                return;
 
-       while(this.goalcurrent && wasfreed(this.goalcurrent))
-       {
-               navigation_poproute(this);
-               if(!this.goalcurrent)
-                       this.bot_strategytime = 0;
-       }
-
        if (bot_strategytoken == this)
        if (!bot_strategytoken_taken)
        {
@@ -350,7 +343,8 @@ void havocbot_bunnyhop(entity this, vector dir)
                                        if(checkdistance)
                                        {
                                                this.aistatus &= ~AI_STATUS_RUNNING;
-                                               if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance)
+                                               // increase stop distance in case the goal is on a slope or a lower platform 
+                                               if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance + (this.origin.z - gco.z))
                                                        PHYS_INPUT_BUTTON_JUMP(this) = true;
                                        }
                                        else
@@ -492,6 +486,7 @@ void havocbot_movetogoal(entity this)
        if(this.jumppadcount)
        {
                // If got stuck on the jump pad try to reach the farthest visible waypoint
+               // but with some randomness so it can try out different paths
                if(this.aistatus & AI_STATUS_OUT_JUMPPAD)
                {
                        if(fabs(this.velocity.z)<50)
@@ -504,7 +499,7 @@ void havocbot_movetogoal(entity this)
                                        if(trace_fraction < 1)
                                                continue;
 
-                                       if(!newgoal || vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin))
+                                       if(!newgoal || ((random() < 0.8) && vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin)))
                                                newgoal = it;
                                });
 
@@ -514,6 +509,8 @@ void havocbot_movetogoal(entity this)
                                        this.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout;
                                        navigation_clearroute(this);
                                        navigation_routetogoal(this, newgoal, this.origin);
+                                       if(autocvar_bot_debug_goalstack)
+                                               debuggoalstack(this);
                                        this.aistatus &= ~AI_STATUS_OUT_JUMPPAD;
                                }
                        }
@@ -642,8 +639,7 @@ void havocbot_movetogoal(entity this)
        if (this.goalcurrent == NULL)
                return;
 
-       if (this.goalcurrent)
-               navigation_poptouchedgoals(this);
+       navigation_poptouchedgoals(this);
 
        // if ran out of goals try to use an alternative goal or get a new strategy asap
        if(this.goalcurrent == NULL)
@@ -718,10 +714,8 @@ void havocbot_movetogoal(entity this)
                        }
 
                        // avoiding dangers and obstacles
-                       vector dst_ahead, dst_down;
-                       makevectors(this.v_angle.y * '0 1 0');
-                       dst_ahead = this.origin + this.view_ofs + (this.velocity * 0.4) + (v_forward * 32 * 3);
-                       dst_down = dst_ahead - '0 0 1500';
+                       vector dst_ahead = this.origin + this.view_ofs + this.velocity * 0.5;
+                       vector dst_down = dst_ahead - '0 0 3000';
 
                        // Look ahead
                        traceline(this.origin + this.view_ofs, dst_ahead, true, NULL);
@@ -758,12 +752,12 @@ void havocbot_movetogoal(entity this)
                        this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
 
                        if(trace_fraction == 1 && this.jumppadcount == 0 && !this.goalcurrent.wphardwired )
-                       if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || PHYS_INPUT_BUTTON_JUMP(this))
+                       if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || (this.aistatus & AI_STATUS_ROAMING) || PHYS_INPUT_BUTTON_JUMP(this))
                        {
                                // Look downwards
                                traceline(dst_ahead , dst_down, true, NULL);
-                       //      te_lightning2(NULL, this.origin, dst_ahead);    // Draw "ahead" look
-                       //      te_lightning2(NULL, dst_ahead, dst_down);               // Draw "downwards" look
+                               //te_lightning2(NULL, this.origin + this.view_ofs, dst_ahead); // Draw "ahead" look
+                               //te_lightning2(NULL, dst_ahead, dst_down); // Draw "downwards" look
                                if(trace_endpos.z < this.origin.z + this.mins.z)
                                {
                                        s = pointcontents(trace_endpos + '0 0 1');
@@ -772,17 +766,20 @@ void havocbot_movetogoal(entity this)
                                                evadelava = normalize(this.velocity) * -1;
                                        else if (s == CONTENT_SKY)
                                                evadeobstacle = normalize(this.velocity) * -1;
-                                       else if (!boxesoverlap(dst_ahead - this.view_ofs + this.mins, dst_ahead - this.view_ofs + this.maxs,
-                                                               this.goalcurrent.absmin, this.goalcurrent.absmax))
+                                       else
                                        {
-                                               // if ain't a safe goal with "holes" (like the jumpad on soylent)
-                                               // and there is a trigger_hurt below
-                                               if(tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
+                                               tracebox(dst_ahead, this.mins, this.maxs, dst_down, true, this);
+                                               if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
                                                {
-                                                       // Remove dangerous dynamic goals from stack
-                                                       LOG_TRACE("bot ", this.netname, " avoided the goal ", this.goalcurrent.classname, " ", etos(this.goalcurrent), " because it led to a dangerous path; goal stack cleared");
-                                                       navigation_clearroute(this);
-                                                       return;
+                                                       if (gco.z > this.origin.z + jumpstepheightvec.z)
+                                                       { 
+                                                               // the goal is probably on an upper platform, assume bot can't get there
+                                                               LOG_TRACE("bot ", this.netname, " avoided the goal ", this.goalcurrent.classname, " ", etos(this.goalcurrent), " because it led to a dangerous path; goal stack cleared");
+                                                               navigation_clearroute(this);
+                                                               this.bot_strategytime = 0;
+                                                       }
+                                                       else
+                                                               evadelava = normalize(this.velocity) * -1;
                                                }
                                        }
                                }
index 2a2f7753daf2cd22008bd4f776816bc5568fc14e..4c8982e9457a22d9614a6d4aed2d2bec00ab46fa 100644 (file)
@@ -876,10 +876,15 @@ void navigation_poptouchedgoals(entity this)
        m1 = org + this.mins;
        m2 = org + this.maxs;
 
+       while(this.goalcurrent && wasfreed(this.goalcurrent))
+               navigation_poproute(this);
+
        if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
        {
+               // make sure jumppad is really hit, don't rely on distance based checks
+               // as they may report a touch even if it didn't really happen
                if(this.lastteleporttime>0)
-               if(time-this.lastteleporttime<(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL)?2:0.15)
+               if(time - this.lastteleporttime < ((this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL) ? 2 : 0.15))
                {
                        if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
                        if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)
@@ -913,14 +918,11 @@ void navigation_poptouchedgoals(entity this)
        if(IS_PLAYER(this.goalcurrent))
                navigation_poproute(this);
 
-       // aid for detecting jump pads better (distance based check fails sometimes)
-       if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT && this.jumppadcount > 0 )
-               navigation_poproute(this);
-
        // Loose goal touching check when running
        if(this.aistatus & AI_STATUS_RUNNING)
        if(this.speed >= autocvar_sv_maxspeed) // if -really- running
        if(this.goalcurrent.classname=="waypoint")
+       if(!(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT))
        {
                if(vdist(this.origin - this.goalcurrent.origin, <, 150))
                {
@@ -942,6 +944,9 @@ void navigation_poptouchedgoals(entity this)
 
        while (this.goalcurrent && boxesoverlap(m1, m2, this.goalcurrent.absmin, this.goalcurrent.absmax))
        {
+               if((this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT))
+                       break;
+
                // Detect personal waypoints
                if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
                if(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && this.goalcurrent.owner==this)