]> 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 d23c29675a70fa7bc5d2944922f143ee6a7c9a28..b23c15bcafdeccbfb0b4874f0d8cfe77f18c5aaa 100644 (file)
@@ -9,10 +9,12 @@
 #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>
 
+#include <common/triggers/teleporters.qh>
 #include <common/triggers/trigger/jumppads.qh>
 
 #include <lib/warpzone/common.qh>
@@ -27,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)
        {
@@ -42,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))
                {
@@ -128,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);
@@ -319,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);
@@ -836,11 +845,28 @@ void havocbot_movetogoal(entity this)
        if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-this.bot_dodgeskill)*0.1,1)) this.havocbot_ducktime=time+0.3/bound(0.1,skill+this.bot_dodgeskill,10);
 }
 
+entity havocbot_gettarget(entity this, bool secondary)
+{
+       entity best = NULL;
+       vector eye = CENTER_OR_VIEWOFS(this);
+       IL_EACH(g_bot_targets, boolean((secondary) ? it.classname == "misc_breakablemodel" : it.classname != "misc_breakablemodel"),
+       {
+               vector v = CENTER_OR_VIEWOFS(it);
+               if(vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
+               if(!best || vlen2(CENTER_OR_VIEWOFS(best) - eye) > vlen2(v - eye))
+               if(bot_shouldattack(this, it))
+               {
+                       traceline(eye, v, true, this);
+                       if (trace_ent == it || trace_fraction >= 1)
+                               best = it;
+               }
+       });
+
+       return best;
+}
+
 void havocbot_chooseenemy(entity this)
 {
-       entity head, best, head2;
-       float rating, bestrating, hf;
-       vector eye, v;
        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
        {
                this.enemy = NULL;
@@ -879,13 +905,12 @@ void havocbot_chooseenemy(entity this)
        if (time < this.havocbot_chooseenemy_finished)
                return;
        this.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
-       eye = this.origin + this.view_ofs;
-       best = NULL;
-       bestrating = 100000000;
-       head = head2 = findchainfloat(bot_attack, true);
+       vector eye = this.origin + this.view_ofs;
+       entity best = NULL;
+       float bestrating = 100000000;
 
        // Backup hit flags
-       hf = this.dphitcontentsmask;
+       int hf = this.dphitcontentsmask;
 
        // Search for enemies, if no enemy can be seen directly try to look through transparent objects
 
@@ -898,42 +923,38 @@ void havocbot_chooseenemy(entity this)
        {
                scan_secondary_targets = false;
 LABEL(scan_targets)
-               for( ; head; head = head.chain)
+               IL_EACH(g_bot_targets, it.bot_attack,
                {
                        if(!scan_secondary_targets)
                        {
-                               if(head.classname == "misc_breakablemodel")
+                               if(it.classname == "misc_breakablemodel")
                                {
                                        have_secondary_targets = true;
                                        continue;
                                }
                        }
-                       else
-                       {
-                               if(head.classname != "misc_breakablemodel")
-                                       continue;
-                       }
+                       else if(it.classname != "misc_breakablemodel")
+                               continue;
 
-                       v = (head.absmin + head.absmax) * 0.5;
-                       rating = vlen(v - eye);
-                       if (rating<autocvar_bot_ai_enemydetectionradius)
+                       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, head))
+                       if (bot_shouldattack(this, it))
                        {
                                traceline(eye, v, true, this);
-                               if (trace_ent == head || trace_fraction >= 1)
+                               if (trace_ent == it || trace_fraction >= 1)
                                {
-                                       best = head;
+                                       best = it;
                                        bestrating = rating;
                                }
                        }
-               }
+               });
 
                if(!best && have_secondary_targets && !scan_secondary_targets)
                {
                        scan_secondary_targets = true;
                        // restart the loop
-                       head = head2;
                        bestrating = 100000000;
                        goto scan_targets;
                }
@@ -948,7 +969,6 @@ LABEL(scan_targets)
                // Set flags to see through transparent objects
                this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
 
-               head = head2;
                scan_transparent = true;
        }
 
@@ -1214,7 +1234,7 @@ float havocbot_moveto(entity this, vector pos)
        this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
 
        // if pos is inside a teleport, then let's mark it as teleport waypoint
-       FOREACH_ENTITY_CLASS("trigger_teleport", WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
+       IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(pos, pos, it, NULL),
        {
                wp.wpflags |= WAYPOINTFLAG_TELEPORT;
                this.lastteleporttime = 0;