]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/havocbot/havocbot.qc
Add a networked entity to hold weapon state
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / havocbot / havocbot.qc
index 67b558eedf208172ba76de153edbdd85f000445f..b3bc26bbfecdae804db45248d322561ef2417a39 100644 (file)
@@ -11,8 +11,9 @@
 #include <common/constants.qh>
 #include <common/physics/player.qh>
 #include <common/state.qh>
-#include <common/items/all.qh>
+#include <common/items/_mod.qh>
 
+#include <common/triggers/teleporters.qh>
 #include <common/triggers/trigger/jumppads.qh>
 
 #include <lib/warpzone/common.qh>
@@ -97,7 +98,8 @@ void havocbot_ai(entity this)
 
                if(this.weapons)
                {
-                       Weapon w = PS(this).m_weapon;
+                       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+                       Weapon w = this.(weaponentity).m_weapon;
                        w.wr_aim(w, this);
                        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
                        {
@@ -107,7 +109,7 @@ void havocbot_ai(entity this)
                        else
                        {
                                if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))
-                                       this.lastfiredweapon = PS(this).m_weapon.m_id;
+                                       this.lastfiredweapon = this.(weaponentity).m_weapon.m_id;
                        }
                }
                else
@@ -164,9 +166,10 @@ void havocbot_ai(entity this)
                if(skill >= 5) // bots can only look for unloaded weapons past this skill
                if(this.clip_load >= 0) // only if we're not reloading a weapon already
                {
+                       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
                        FOREACH(Weapons, it != WEP_Null, LAMBDA(
                                if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.weapon_load[it.m_id] < it.reloading_ammo))
-                                       PS(this).m_switchweapon = it;
+                                       this.(weaponentity).m_switchweapon = it;
                        ));
                }
        }
@@ -520,7 +523,7 @@ void havocbot_movetogoal(entity this)
                                threshold = maxspeed * 0.2;
                                if(vdist(velxy, <, threshold))
                                {
-                                       LOG_TRACE("Warning: ", this.netname, " got stuck on a jumppad (velocity in xy is ", vtos(velxy), "), trying to get out of it now\n");
+                                       LOG_TRACE("Warning: ", this.netname, " got stuck on a jumppad (velocity in xy is ", vtos(velxy), "), trying to get out of it now");
                                        this.aistatus |= AI_STATUS_OUT_JUMPPAD;
                                }
                                return;
@@ -597,7 +600,8 @@ void havocbot_movetogoal(entity this)
                                        return;
                                }
 
-                               PS(this).m_switchweapon = WEP_DEVASTATOR;
+                               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+                               this.(weaponentity).m_switchweapon = WEP_DEVASTATOR;
                                this.v_angle_x = 90;
                                PHYS_INPUT_BUTTON_ATCK(this) = true;
                                this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay);
@@ -771,7 +775,7 @@ void havocbot_movetogoal(entity 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\n");
+                                                       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;
                                                }
@@ -836,6 +840,26 @@ 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;
@@ -988,10 +1012,12 @@ void havocbot_chooseweapon(entity this)
 {
        int i;
 
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+
        // ;)
        if(g_weaponarena_weapons == WEPSET(TUBA))
        {
-               PS(this).m_switchweapon = WEP_TUBA;
+               this.(weaponentity).m_switchweapon = WEP_TUBA;
                return;
        }
 
@@ -999,11 +1025,11 @@ void havocbot_chooseweapon(entity this)
        if(this.enemy==NULL)
        {
                // If no weapon was chosen get the first available weapon
-               if(PS(this).m_weapon==WEP_Null)
+               if(this.(weaponentity).m_weapon==WEP_Null)
                FOREACH(Weapons, it != WEP_Null, LAMBDA(
                        if(client_hasweapon(this, it, true, false))
                        {
-                               PS(this).m_switchweapon = it;
+                               this.(weaponentity).m_switchweapon = it;
                                return;
                        }
                ));
@@ -1031,7 +1057,7 @@ void havocbot_chooseweapon(entity this)
        combo = false;
 
        if(autocvar_bot_ai_weapon_combo)
-       if(PS(this).m_weapon.m_id == this.lastfiredweapon)
+       if(this.(weaponentity).m_weapon.m_id == this.lastfiredweapon)
        if(af > combo_time)
        {
                combo = true;
@@ -1049,9 +1075,9 @@ void havocbot_chooseweapon(entity this)
                                w = bot_weapons_far[i];
                                if ( client_hasweapon(this, Weapons_from(w), true, false) )
                                {
-                                       if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+                                       if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
                                                continue;
-                                       PS(this).m_switchweapon = Weapons_from(w);
+                                       this.(weaponentity).m_switchweapon = Weapons_from(w);
                                        return;
                                }
                        }
@@ -1063,9 +1089,9 @@ void havocbot_chooseweapon(entity this)
                                w = bot_weapons_mid[i];
                                if ( client_hasweapon(this, Weapons_from(w), true, false) )
                                {
-                                       if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+                                       if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
                                                continue;
-                                       PS(this).m_switchweapon = Weapons_from(w);
+                                       this.(weaponentity).m_switchweapon = Weapons_from(w);
                                        return;
                                }
                        }
@@ -1076,9 +1102,9 @@ void havocbot_chooseweapon(entity this)
                        w = bot_weapons_close[i];
                        if ( client_hasweapon(this, Weapons_from(w), true, false) )
                        {
-                               if ((PS(this).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
+                               if ((this.(weaponentity).m_weapon.m_id == w && combo) || havocbot_chooseweapon_checkreload(this, w))
                                        continue;
-                               PS(this).m_switchweapon = Weapons_from(w);
+                               this.(weaponentity).m_switchweapon = Weapons_from(w);
                                return;
                        }
                }
@@ -1127,7 +1153,7 @@ float havocbot_moveto(entity this, vector pos)
                // Step 4: Move to waypoint
                if(this.havocbot_personal_waypoint==NULL)
                {
-                       LOG_TRACE("Error: ", this.netname, " trying to walk to a non existent personal waypoint\n");
+                       LOG_TRACE("Error: ", this.netname, " trying to walk to a non existent personal waypoint");
                        this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
                        return CMD_STATUS_ERROR;
                }
@@ -1138,7 +1164,7 @@ float havocbot_moveto(entity this, vector pos)
                        bot_strategytoken_taken = true;
                        if(havocbot_moveto_refresh_route(this))
                        {
-                               LOG_TRACE(this.netname, " walking to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts)\n");
+                               LOG_TRACE(this.netname, " walking to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts)");
                                this.havocbot_personal_waypoint_searchtime = time + 10;
                                this.havocbot_personal_waypoint_failcounter = 0;
                        }
@@ -1148,13 +1174,13 @@ float havocbot_moveto(entity this, vector pos)
                                this.havocbot_personal_waypoint_searchtime = time + 2;
                                if(this.havocbot_personal_waypoint_failcounter >= 30)
                                {
-                                       LOG_TRACE("Warning: can't walk to the personal waypoint located at ", vtos(this.havocbot_personal_waypoint.origin),"\n");
+                                       LOG_TRACE("Warning: can't walk to the personal waypoint located at ", vtos(this.havocbot_personal_waypoint.origin));
                                        this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
                                        delete(this.havocbot_personal_waypoint);
                                        return CMD_STATUS_ERROR;
                                }
                                else
-                                       LOG_TRACE(this.netname, " can't walk to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts), trying later\n");
+                                       LOG_TRACE(this.netname, " can't walk to its personal waypoint (after ", ftos(this.havocbot_personal_waypoint_failcounter), " failed attempts), trying later");
                        }
                }
 
@@ -1172,7 +1198,7 @@ float havocbot_moveto(entity this, vector pos)
                if(this.aistatus & AI_STATUS_WAYPOINT_PERSONAL_REACHED)
                {
                        // Step 5: Waypoint reached
-                       LOG_TRACE(this.netname, "'s personal waypoint reached\n");
+                       LOG_TRACE(this.netname, "'s personal waypoint reached");
                        delete(this.havocbot_personal_waypoint);
                        this.aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_REACHED;
                        return CMD_STATUS_FINISHED;
@@ -1187,7 +1213,7 @@ float havocbot_moveto(entity this, vector pos)
                // Wait until it is linked
                if(!this.havocbot_personal_waypoint.wplinked)
                {
-                       LOG_TRACE(this.netname, " waiting for personal waypoint to be linked\n");
+                       LOG_TRACE(this.netname, " waiting for personal waypoint to be linked");
                        return CMD_STATUS_EXECUTING;
                }
 
@@ -1196,7 +1222,7 @@ float havocbot_moveto(entity this, vector pos)
                this.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_GOING;
 
                // Step 3: Route to waypoint
-               LOG_TRACE(this.netname, " walking to its personal waypoint\n");
+               LOG_TRACE(this.netname, " walking to its personal waypoint");
 
                return CMD_STATUS_EXECUTING;
        }
@@ -1205,7 +1231,7 @@ float havocbot_moveto(entity this, vector pos)
        wp = waypoint_spawnpersonal(this, pos);
        if(wp==NULL)
        {
-               LOG_TRACE("Error: Can't spawn personal waypoint at ",vtos(pos),"\n");
+               LOG_TRACE("Error: Can't spawn personal waypoint at ",vtos(pos));
                return CMD_STATUS_ERROR;
        }
 
@@ -1214,7 +1240,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;