]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/havocbot/havocbot.qc
Part 2 of edc2958143 "Make sure bots don't move to removed goals such as a key when...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / havocbot / havocbot.qc
index cbb6a68b6d8504108c1842c2c41f0e4a69c9000b..b23c15bcafdeccbfb0b4874f0d8cfe77f18c5aaa 100644 (file)
@@ -9,6 +9,7 @@
 #include "../waypoints.qh"
 
 #include <common/constants.qh>
+#include <common/net_linked.qh>
 #include <common/physics/player.qh>
 #include <common/state.qh>
 #include <common/items/_mod.qh>
@@ -28,6 +29,13 @@ 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)
        {
@@ -43,7 +51,7 @@ void havocbot_ai(entity this)
 
                // TODO: tracewalk() should take care of this job (better path finding under water)
                // if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
-               if(IS_DEAD(this))
+               if(!(IS_DEAD(this)))
                if(!this.goalcurrent)
                if(this.waterlevel == WATERLEVEL_SWIMMING || (this.aistatus & AI_STATUS_OUT_WATER))
                {
@@ -129,7 +137,7 @@ void havocbot_ai(entity this)
                //heading = this.velocity;
                //dprint(this.goalstack01.classname,etos(this.goalstack01),"\n");
                if(
-                       this.goalstack01 != this && this.goalstack01 != NULL && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
+                       this.goalstack01 != this && this.goalstack01 && !wasfreed(this.goalstack01) && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
                        !(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
                )
                        next = ((this.goalstack01.absmin + this.goalstack01.absmax) * 0.5) - (this.origin + this.view_ofs);
@@ -320,7 +328,7 @@ void havocbot_bunnyhop(entity this, vector dir)
                                        if(this.goalcurrent.classname=="waypoint")
                                        if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
                                        if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
-                                       if(this.goalstack01!=NULL)
+                                       if(this.goalstack01 && !wasfreed(this.goalstack01))
                                        {
                                                gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
                                                deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
@@ -897,24 +905,75 @@ void havocbot_chooseenemy(entity this)
        if (time < this.havocbot_chooseenemy_finished)
                return;
        this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
+       vector eye = this.origin + this.view_ofs;
+       entity best = NULL;
+       float bestrating = 100000000;
+
+       // Backup hit flags
+       int hf = this.dphitcontentsmask;
 
        // Search for enemies, if no enemy can be seen directly try to look through transparent objects
 
-       int myhit = this.dphitcontentsmask;
        this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
 
-       entity best = havocbot_gettarget(this, false); // first try primary targets
-       if(!best)
-               best = havocbot_gettarget(this, true); // now try secondary targets
-       if(!best && this.weapons)
+       bool scan_transparent = false;
+       bool scan_secondary_targets = false;
+       bool have_secondary_targets = false;
+       while(true)
        {
+               scan_secondary_targets = false;
+LABEL(scan_targets)
+               IL_EACH(g_bot_targets, it.bot_attack,
+               {
+                       if(!scan_secondary_targets)
+                       {
+                               if(it.classname == "misc_breakablemodel")
+                               {
+                                       have_secondary_targets = true;
+                                       continue;
+                               }
+                       }
+                       else if(it.classname != "misc_breakablemodel")
+                               continue;
+
+                       vector v = (it.absmin + it.absmax) * 0.5;
+                       float rating = vlen2(v - eye);
+                       if (vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
+                       if (bestrating > rating)
+                       if (bot_shouldattack(this, it))
+                       {
+                               traceline(eye, v, true, this);
+                               if (trace_ent == it || trace_fraction >= 1)
+                               {
+                                       best = it;
+                                       bestrating = rating;
+                               }
+                       }
+               });
+
+               if(!best && have_secondary_targets && !scan_secondary_targets)
+               {
+                       scan_secondary_targets = true;
+                       // restart the loop
+                       bestrating = 100000000;
+                       goto scan_targets;
+               }
+
+               // I want to do a second scan if no enemy was found or I don't have weapons
+               // TODO: Perform the scan when using the rifle (requires changes on the rifle code)
+               if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id
+                       break;
+               if(scan_transparent)
+                       break;
+
+               // Set flags to see through transparent objects
                this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
-               best = havocbot_gettarget(this, false);
-               if(!best)
-                       best = havocbot_gettarget(this, true);
+
+               scan_transparent = true;
        }
 
-       this.dphitcontentsmask = myhit;
+       // Restore hit flags
+       this.dphitcontentsmask = hf;
 
        this.enemy = best;
        this.havocbot_stickenemy = true;