]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/wepent_experimental
authorMario <mario@smbclan.net>
Sat, 31 Dec 2016 01:00:59 +0000 (11:00 +1000)
committerMario <mario@smbclan.net>
Sat, 31 Dec 2016 01:00:59 +0000 (11:00 +1000)
18 files changed:
.gitlab-ci.yml
defaultXonotic.cfg
mutators.cfg
qcsrc/common/items/item/armor.qh
qcsrc/common/mutators/mutator/buffs/all.inc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qh
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/t_items.qc
qcsrc/common/turrets/cl_turrets.qc
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/bot.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/teamplay.qc
qcsrc/server/weapons/throwing.qc

index 63130f8ba1710060163ecbc49c99ef9788b7709f..39414d108ae8b1b3d395537006c571182d4fd6cf 100644 (file)
@@ -30,7 +30,7 @@ test_sv_game:
     - wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
     - wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
     - make
-    - EXPECT=b58f9c7587f1a14e5c52176d4e62a9fb
+    - EXPECT=37be9dc5489925451eb497390fdf58b9
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index fa093b04721433b92a930f0288c6a1ed4864c391..ac3b51613967c33f4c98dbd64d0869c6530bf89e 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 f36a5a77494e9508a79bc8d083574b408c2f1262..d487327bc690c3becc73ee20dbcaab171aa21dad 100644 (file)
@@ -288,7 +288,7 @@ set g_new_toys_use_pickupsound 1 "play the 'new toys, new toys!' roflsound when
 //  buffs
 // =======
 set cl_buffs_autoreplace 1 "automatically drop current buff when picking up another"
-set g_buffs 0 "enable buffs (requires buff items or powerups)"
+set g_buffs -1 "enable buffs (requires buff items or powerups)"
 set g_buffs_effects 1 "show particle effects from carried buffs"
 set g_buffs_waypoint_distance 1024 "maximum distance at which buff waypoint can be seen from item"
 set g_buffs_randomize 1 "randomize buff type when player drops buff"
@@ -296,7 +296,7 @@ set g_buffs_random_lifetime 30 "re-spawn the buff again if it hasn't been touche
 set g_buffs_random_location 0 "randomize buff location on start and when reset"
 set g_buffs_random_location_attempts 10 "number of random locations a single buff will attempt to respawn at before giving up"
 set g_buffs_spawn_count 0 "how many buffs to spawn on the map if none exist already"
-set g_buffs_replace_powerups 1 "replace powerups on the map with random buffs"
+set g_buffs_replace_powerups 0 "replace powerups on the map with random buffs"
 set g_buffs_cooldown_activate 5 "cooldown period when buff is first activated"
 set g_buffs_cooldown_respawn 3 "cooldown period when buff is reloading"
 set g_buffs_ammo 1 "ammo buff: infinite ammunition"
@@ -361,6 +361,8 @@ set g_buffs_luck 1 "luck buff: randomly increased damage"
 set g_buffs_luck_time 60 "luck buff carry time"
 set g_buffs_luck_chance 0.15 "chance for 'critical' hit (multiplied damage) with luck buff"
 set g_buffs_luck_damagemultiplier 3 "luck damage multiplier"
+set g_buffs_flight 0 "flight buff: crouch jump to reverse your gravity!"
+set g_buffs_flight_time 60 "flight buff carry time"
 
 
 // ==============
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 f6c25f76103353e9bd865123f944ec7d61303070..915f95329dbda327f6d3f752221892346a4bb114 100644 (file)
@@ -116,3 +116,11 @@ REGISTER_BUFF(LUCK) {
     this.m_color = '1 0.23 0.44';
 }
 BUFF_SPAWNFUNCS(luck, BUFF_LUCK)
+
+REGISTER_BUFF(FLIGHT) {
+    this.m_prettyName = _("Flight");
+    this.m_name = "flight";
+    this.m_skin = 11;
+    this.m_color = '0.23 0.44 1';
+}
+BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
index a5d3490a459186e0ff8fa71d9e57905dad91354d..3bf73bf101364748169fef6c39303a0cda392ba2 100644 (file)
@@ -6,11 +6,14 @@
 .float buff_time = _STAT(BUFF_TIME);
 void buffs_DelayedInit(entity this);
 
-REGISTER_MUTATOR(buffs, cvar("g_buffs"))
+AUTOCVAR(g_buffs, int, -1, _("Enable buffs, -1: enabled but no auto location or replacing powerups, 1: enabled and can replace them"));
+
+REGISTER_MUTATOR(buffs, autocvar_g_buffs)
 {
        MUTATOR_ONADD
        {
-               InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
+               if(autocvar_g_buffs > 0)
+                       InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
        }
 }
 
@@ -592,6 +595,10 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
 
        if(player.buffs & BUFF_JUMP.m_itemid)
                M_ARGV(1, float) = autocvar_g_buffs_jump_height;
+
+       if(player.buffs & BUFF_FLIGHT.m_itemid)
+       if(!IS_JUMP_HELD(player) && PHYS_INPUT_BUTTON_CROUCH(player))
+               player.gravity *= -1;
 }
 
 MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
@@ -744,6 +751,9 @@ MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
 
 MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
 {
+       if(autocvar_g_buffs < 0)
+               return; // no auto replacing of entities in this mode
+
        entity ent = M_ARGV(0, entity);
 
        if(autocvar_g_buffs_replace_powerups)
@@ -920,6 +930,16 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                BUFF_ONREM(BUFF_INVISIBLE)
                        player.alpha = player.buff_invisible_prev_alpha;
 
+               BUFF_ONADD(BUFF_FLIGHT)
+               {
+                       player.buff_flight_oldgravity = player.gravity;
+                       if(!player.gravity)
+                               player.gravity = 1;
+               }
+
+               BUFF_ONREM(BUFF_FLIGHT)
+                       player.gravity = ((player.trigger_gravity_check) ? player.trigger_gravity_check.enemy.gravity : player.buff_flight_oldgravity);
+
                player.oldbuffs = player.buffs;
                if(player.buffs)
                {
@@ -1003,12 +1023,14 @@ REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace");
 
 MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
 {
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Buffs");
+       if(autocvar_g_buffs > 0) // only report as a mutator if they're enabled
+               M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Buffs");
 }
 
 MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
 {
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Buffs");
+       if(autocvar_g_buffs > 0)
+               M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Buffs");
 }
 
 void buffs_DelayedInit(entity this)
index 5b14c39f41c96804bbe04bfa4e10d3b59128cc96..8383a72ef5789a2cb269e9f61d422bca3c75a04f 100644 (file)
@@ -59,6 +59,8 @@ float autocvar_g_buffs_luck_damagemultiplier = 3;
 // disability
 .float buff_disability_time;
 .float buff_disability_effect_time;
+// flight
+.float buff_flight_oldgravity;
 // common buff variables
 .float buff_effect_delay;
 
index bcb317b4abe305562183dfd2456c51e994d93acf..bdedf295d8b7e31a967b0b9b1f4a51248618d589 100644 (file)
@@ -475,13 +475,13 @@ void Draw_WaypointSprite(entity this)
 
     InterpolateOrigin_Do(this);
 
+    float t = entcs_GetTeam(player_localnum) + 1;
     string spriteimage = "";
 
     // choose the sprite
     switch (this.rule)
     {
         case SPRITERULE_SPECTATOR:
-            float t = entcs_GetTeam(player_localnum) + 1;
             if (!(
                 (autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
             || (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage || STAT(ITEMSTIME) == 2))
@@ -492,7 +492,7 @@ void Draw_WaypointSprite(entity this)
         case SPRITERULE_DEFAULT:
             if (this.team)
             {
-                if (this.team == myteam + 1)
+                if (this.team == t)
                     spriteimage = this.netname;
                 else
                     spriteimage = "";
@@ -501,9 +501,9 @@ void Draw_WaypointSprite(entity this)
                 spriteimage = this.netname;
             break;
         case SPRITERULE_TEAMPLAY:
-            if (myteam == NUM_SPECTATOR)
+            if (t == NUM_SPECTATOR + 1)
                 spriteimage = this.netname3;
-            else if (this.team == myteam + 1)
+            else if (this.team == t)
                 spriteimage = this.netname2;
             else
                 spriteimage = this.netname;
@@ -613,7 +613,7 @@ void Draw_WaypointSprite(entity this)
 
     float crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
 
-    float t = waypointsprite_scale;
+    t = waypointsprite_scale;
     a *= waypointsprite_alpha;
 
     {
index 82801228e964c4a063fdcd0290b46392f329f00c..116fbfcd5a4768f4d4eb4c03f2f681cece9a1241 100644 (file)
@@ -950,17 +950,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;
@@ -968,58 +971,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 48c6a8798981269b18d83e41c1351f0b23d41640..c21e327d4470655336e6033d1823587c65f6e458 100644 (file)
@@ -67,12 +67,13 @@ void turret_draw2d(entity this)
                return;
 
        float dist = vlen(this.origin - view_origin);
+       float t = (entcs_GetTeam(player_localnum) + 1);
 
        vector o;
        string txt;
 
        if(autocvar_cl_vehicles_hud_tactical)
-       if(dist < 10240 && (myteam + 1 != this.team))
+       if(dist < 10240 && t != this.team)
        {
                // TODO: Vehicle tactical hud
                o = project_3d_to_2d(this.origin + '0 0 32');
@@ -120,7 +121,7 @@ void turret_draw2d(entity this)
        else
                txt = spritelookuptext(this, spriteimage);
 
-       if(time - floor(time) > 0.5 && (myteam + 1 == this.team))
+       if(time - floor(time) > 0.5 && t == this.team)
        {
                if(this.helpme && time < this.helpme)
                {
@@ -162,7 +163,7 @@ void turret_draw2d(entity this)
 
        float crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
 
-       float t = waypointsprite_scale;
+       t = waypointsprite_scale;
        a *= waypointsprite_alpha;
 
        {
index 65edcdec9b48759ec8f7f6f166f23233d18d75d1..ab52949741be985d26707db57a35fd6262182f58 100644 (file)
@@ -71,7 +71,7 @@ string XonoticMutatorsDialog_toString(entity me)
                s = strcat(s, ", ", _("Invincible Projectiles"));
        if(cvar_string("g_weaponarena") != "0")
                s = strcat(s, ", ", WeaponArenaString());
-       else if(cvar("g_balance_blaster_weaponstart") == 0)
+       else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
                s = strcat(s, ", ", _("No start weapons"));
        if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
                s = strcat(s, ", ", _("Low gravity"));
@@ -143,7 +143,7 @@ float checkCompatibility_weaponarena_weapon(entity me)
                return 0;
        if(cvar_string("g_weaponarena") == "0")
                return 0;
-       if(cvar_string("g_balance_blaster_weaponstart") == "0")
+       if(cvar_string("g_balance_blaster_weaponstartoverride") == "0")
                return 0;
        return 1;
 }
@@ -279,9 +279,9 @@ void XonoticMutatorsDialog_fill(entity me)
                        setDependent(e, "g_nix", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_balance_blaster_weaponstart", "0", _("No start weapons"), "-"));
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_balance_blaster_weaponstartoverride", "0", _("No start weapons"), "-"));
                        e.cvarOffValue = "-1";
-                       makeMulti(e, "g_balance_shotgun_weaponstart g_balance_machinegun_weaponstart g_balance_devastator_weaponstart g_balance_minelayer_weaponstart g_balance_electro_weaponstart g_balance_crylink_weaponstart g_balance_hagar_weaponstart g_balance_porto_weaponstart g_balance_vaporizer_weaponstart g_balance_hook_weaponstart g_balance_rifle_weaponstart g_balance_fireball_weaponstart g_balance_seeker_weaponstart g_balance_tuba_weaponstart g_balance_arc_weaponstart g_balance_vortex_weaponstart g_balance_mortar_weaponstart");
+                       makeMulti(e, "g_balance_shotgun_weaponstartoverride g_balance_machinegun_weaponstartoverride g_balance_devastator_weaponstartoverride g_balance_minelayer_weaponstartoverride g_balance_electro_weaponstartoverride g_balance_crylink_weaponstartoverride g_balance_hagar_weaponstartoverride g_balance_porto_weaponstartoverride g_balance_vaporizer_weaponstartoverride g_balance_hook_weaponstartoverride g_balance_rifle_weaponstartoverride g_balance_fireball_weaponstartoverride g_balance_seeker_weaponstartoverride g_balance_tuba_weaponstartoverride g_balance_arc_weaponstartoverride g_balance_vortex_weaponstartoverride g_balance_mortar_weaponstartoverride");
 
        me.gotoRC(me, me.rows - 1, 0);
                me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
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 9641fab9ada27951e5acfc66d28c3f553aad7bfb..9321d388c52e6b129990538fb038fa21e6b1d7c2 100644 (file)
@@ -30,13 +30,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)
        {
@@ -371,7 +364,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
@@ -513,6 +507,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)
@@ -525,7 +520,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;
                                });
 
@@ -535,6 +530,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;
                                }
                        }
@@ -673,8 +670,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)
@@ -749,10 +745,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);
@@ -789,12 +783,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');
@@ -803,17 +797,22 @@ 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 (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
                                        {
-                                               // 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))
+                                               // the traceline check isn't enough but is good as optimization,
+                                               // when not true (most of the time) this tracebox call is avoided
+                                               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 677ef578e79bd6984a43dbb72c02736b9389e463..536c8b205e8f5911da17a3588c14afbd352f3146 100644 (file)
@@ -34,7 +34,7 @@ void havocbot_goalrating_items(entity this, float ratingscale, vector org, float
                        traceline(o, o + '0 0 -1500', true, NULL);
 
                        d = pointcontents(trace_endpos + '0 0 1');
-                       if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
+                       if(d == CONTENT_WATER || d == CONTENT_SLIME || d == CONTENT_LAVA)
                                continue;
                        if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
                                continue;
@@ -145,12 +145,12 @@ void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org
                        continue;
 
                // not falling
-               if((IS_ONGROUND(it)) == 0)
+               if(!IS_ONGROUND(it))
                {
                        traceline(it.origin, it.origin + '0 0 -1500', true, NULL);
                        t = pointcontents(trace_endpos + '0 0 1');
                        if(t != CONTENT_SOLID )
-                       if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
+                       if(t == CONTENT_WATER || t == CONTENT_SLIME || t == CONTENT_LAVA)
                                continue;
                        if(tracebox_hits_trigger_hurt(it.origin, it.mins, it.maxs, trace_endpos))
                                continue;
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)
index 4632866b4886755e7657da57ca2cc95fa3039109..0918130159a737e83e63f5bd076af7320e3dc533 100644 (file)
@@ -109,7 +109,7 @@ string getwelcomemessage(entity this)
                else
                        modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
        }
-       else if(cvar("g_balance_blaster_weaponstart") == 0)
+       else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
                modifications = strcat(modifications, ", No start weapons");
        if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
                modifications = strcat(modifications, ", Low gravity");
index 4114c3c58b199cc9a950c811dcf5269b0fdea807..ba84b14c50d11ea9ebb657e8b5465c25e5d210b2 100644 (file)
@@ -20,7 +20,10 @@ void thrown_wep_think(entity this)
        {
                this.SendFlags |= ISF_LOCATION;
                this.oldorigin = this.origin;
+               this.bot_pickup = false;
        }
+       else
+               this.bot_pickup = true;
        this.owner = NULL;
        float timeleft = this.savenextthink - time;
        if(timeleft > 1)