]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/havocbot/havocbot.qc
Merge branch 'master' into mirceakitsune/sandbox
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / havocbot / havocbot.qc
index 1d9054952d24bbdde4d63981bc5a86689f3a44f4..3aefc45a75323b45782bea68f59dacc6b986e490 100644 (file)
@@ -4,6 +4,7 @@
 #include "role_keyhunt.qc"
 #include "role_freezetag.qc"
 #include "role_keepaway.qc"
+#include "role_assault.qc"
 #include "roles.qc"
 
 void havocbot_ai()
@@ -34,8 +35,8 @@ void havocbot_ai()
                if(self.waterlevel==WATERLEVEL_SWIMMING || self.aistatus & AI_STATUS_OUT_WATER)
                {
                        // Look for the closest waypoint out of water
-                       local entity newgoal, head;
-                       local float bestdistance, distance;
+                       entity newgoal, head;
+                       float bestdistance, distance;
 
                        newgoal = world;
                        bestdistance = 10000;
@@ -118,8 +119,8 @@ void havocbot_ai()
                self.aistatus |= AI_STATUS_ROAMING;
                self.aistatus &~= AI_STATUS_ATTACKING;
 
-               local vector now,v,next;//,heading;
-               local float aimdistance,skillblend,distanceblend,blend;
+               vector now,v,next;//,heading;
+               float aimdistance,skillblend,distanceblend,blend;
                next = now = ( (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5) - (self.origin + self.view_ofs);
                aimdistance = vlen(now);
                //heading = self.velocity;
@@ -167,17 +168,17 @@ void havocbot_ai()
                        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                        {
                                e = get_weaponinfo(i);
-                               if ((e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo"))))
+                               if ((self.weapons & W_WeaponBit(i)) && (e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo"))))
                                        self.switchweapon = i;
                        }
                }
        }
-};
+}
 
 void havocbot_keyboard_movement(vector destorg)
 {
-       local vector keyboard;
-       local float blend, maxspeed;
+       vector keyboard;
+       float blend, maxspeed;
        float sk;
 
        sk = skill + self.bot_moveskill;
@@ -195,7 +196,7 @@ void havocbot_keyboard_movement(vector destorg)
                , time);
        keyboard = self.movement * (1.0 / maxspeed);
 
-       local float trigger, trigger1;
+       float trigger, trigger1;
        blend = bound(0,sk*0.1,1);
        trigger = autocvar_bot_ai_keyboard_threshold;
        trigger1 = 0 - trigger;
@@ -247,27 +248,24 @@ void havocbot_keyboard_movement(vector destorg)
        blend = bound(0,vlen(destorg-self.origin)/autocvar_bot_ai_keyboard_distance,1); // When getting close move with 360 degree
        //dprint("movement ", vtos(self.movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
        self.movement = self.movement + (keyboard - self.movement) * blend;
-};
+}
 
 void havocbot_bunnyhop(vector dir)
 {
-       local float bunnyhopdistance;
-       local vector deviation;
-       local float maxspeed;
+       float bunnyhopdistance;
+       vector deviation;
+       float maxspeed;
        vector gco, gno;
 
        if(autocvar_g_midair)
                return;
 
-       // Don't jump when using some weapons
-       /*
+       // Don't jump when attacking
        if(self.aistatus & AI_STATUS_ATTACKING)
-       if(self.weapon == WEP_RIFLE)
                return;
 
        if(self.goalcurrent.classname == "player")
                return;
-       */
 
        maxspeed = autocvar_sv_maxspeed;
 
@@ -308,7 +306,7 @@ void havocbot_bunnyhop(vector dir)
                                // for a period of time
                                if(time - self.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
                                {
-                                       local float checkdistance;
+                                       float checkdistance;
                                        checkdistance = TRUE;
 
                                        // don't run if it is too close
@@ -369,6 +367,7 @@ void havocbot_bunnyhop(vector dir)
                self.bot_timelastseengoal = 0;
        }
 
+#if 0
        // Release jump button
        if(!cvar("sv_pogostick"))
        if(self.flags & FL_ONGROUND == 0)
@@ -394,23 +393,24 @@ void havocbot_bunnyhop(vector dir)
 
                }
        }
-};
+#endif
+}
 
 void havocbot_movetogoal()
 {
-       local vector destorg;
-       local vector diff;
-       local vector dir;
-       local vector flatdir;
-       local vector m1;
-       local vector m2;
-       local vector evadeobstacle;
-       local vector evadelava;
-       local float s;
-       local float maxspeed;
-       local vector gco;
-       //local float dist;
-       local vector dodge;
+       vector destorg;
+       vector diff;
+       vector dir;
+       vector flatdir;
+       vector m1;
+       vector m2;
+       vector evadeobstacle;
+       vector evadelava;
+       float s;
+       float maxspeed;
+       vector gco;
+       //float dist;
+       vector dodge;
        //if (self.goalentity)
        //      te_lightning2(self, self.origin, (self.goalentity.absmin + self.goalentity.absmax) * 0.5);
        self.movement = '0 0 0';
@@ -488,18 +488,16 @@ void havocbot_movetogoal()
        // Handling of jump pads
        if(self.jumppadcount)
        {
-               // If got stuck on the jump pad try to reach the farthest visible item
+               // If got stuck on the jump pad try to reach the farthest visible waypoint
                if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
                {
                        if(fabs(self.velocity_z)<50)
                        {
-                               local entity head, newgoal;
-                               local float distance, bestdistance;
+                               entity head, newgoal;
+                               float distance, bestdistance;
 
-                               for (head = findchainfloat(bot_pickup, TRUE); head; head = head.chain)
+                               for (head = findchain(classname, "waypoint"); head; head = head.chain)
                                {
-                                       if(head.classname=="worldspawn")
-                                               continue;
 
                                        distance = vlen(head.origin - self.origin);
                                        if(distance>1000)
@@ -533,11 +531,13 @@ void havocbot_movetogoal()
                {
                        if(self.velocity_z>0)
                        {
-                               local float threshold;
+                               float threshold, sxy;
+                               vector velxy = self.velocity; velxy_z = 0;
+                               sxy = vlen(velxy);
                                threshold = maxspeed * 0.2;
-                               if(fabs(self.velocity_x) < threshold  &&  fabs(self.velocity_y) < threshold)
+                               if(sxy < threshold)
                                {
-                                       dprint("Warning: ", self.netname, " got stuck on a jumppad, trying to get out of it now\n");
+                                       dprint("Warning: ", self.netname, " got stuck on a jumppad (velocity in xy is ", ftos(sxy), "), trying to get out of it now\n");
                                        self.aistatus |= AI_STATUS_OUT_JUMPPAD;
                                }
                                return;
@@ -577,8 +577,8 @@ void havocbot_movetogoal()
                        else
                                dir = normalize(( ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5 ) - self.origin);
 
-                       local vector xyvelocity = self.velocity; xyvelocity_z = 0;
-                       local float xyspeed = xyvelocity * dir;
+                       vector xyvelocity = self.velocity; xyvelocity_z = 0;
+                       float xyspeed = xyvelocity * dir;
 
                        if(xyspeed < (maxspeed / 2))
                        {
@@ -726,7 +726,7 @@ void havocbot_movetogoal()
                        }
 
                        // avoiding dangers and obstacles
-                       local vector dst_ahead, dst_down;
+                       vector dst_ahead, dst_down;
                        makevectors(self.v_angle_y * '0 1 0');
                        dst_ahead = self.origin + self.view_ofs + (self.velocity * 0.4) + (v_forward * 32 * 3);
                        dst_down = dst_ahead + '0 0 -1500';
@@ -765,7 +765,7 @@ void havocbot_movetogoal()
                        // (only when the bot is on the ground or jumping intentionally)
                        self.aistatus &~= AI_STATUS_DANGER_AHEAD;
 
-                       if(trace_fraction == 1 && self.jumppadcount == 0)
+                       if(trace_fraction == 1 && self.jumppadcount == 0 && !self.goalcurrent.wphardwired )
                        if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE)
                        {
                                // Look downwards
@@ -788,15 +788,9 @@ void havocbot_movetogoal()
                                                if(tracebox_hits_trigger_hurt(dst_ahead, self.mins, self.maxs, trace_endpos))
                                                {
                                                        // Remove dangerous dynamic goals from stack
-                                                       if (self.goalcurrent.classname == "player" || self.goalcurrent.classname == "droppedweapon")
-                                                       {
-                                                               navigation_poproute();
-                                                               if(self.goalcurrent)
-                                                                       gco = (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5;
-                                                       }
-                                                       // try to stop
-                                                       flatdir = '0 0 0';
-                                                       evadeobstacle = normalize(self.velocity) * -1;
+                                                       dprint("bot ", self.netname, " avoided the goal ", self.goalcurrent.classname, " ", etos(self.goalcurrent), " because it led to a dangerous path; goal stack cleared\n");
+                                                       navigation_clearroute();
+                                                       return;
                                                }
                                        }
                                }
@@ -857,13 +851,13 @@ void havocbot_movetogoal()
        if ((dir * v_up) >= autocvar_sv_jumpvelocity*0.5 && (self.flags & FL_ONGROUND)) self.BUTTON_JUMP=1;
        if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill-self.bot_dodgeskill)*0.1,1)) self.BUTTON_JUMP=TRUE;
        if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-self.bot_dodgeskill)*0.1,1)) self.havocbot_ducktime=time+0.3/bound(0.1,skill+self.bot_dodgeskill,10);
-};
+}
 
 void havocbot_chooseenemy()
 {
-       local entity head, best, head2;
-       local float rating, bestrating, i, f;
-       local vector eye, v;
+       entity head, best, head2;
+       float rating, bestrating, i, hf;
+       vector eye, v;
        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(self))
        {
                self.enemy = world;
@@ -890,7 +884,7 @@ void havocbot_chooseenemy()
                        if (self.health > 30)
                        {
                                // remain tracking him for a shot while (case he went after a small corner or pilar
-                               self.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval;
+                               self.havocbot_chooseenemy_finished = time + 0.5;
                                return;
                        }
                        // enemy isn't visible, or is far away, or we're injured severely
@@ -907,7 +901,13 @@ void havocbot_chooseenemy()
        bestrating = 100000000;
        head = head2 = findchainfloat(bot_attack, TRUE);
 
+       // Backup hit flags
+       hf = self.dphitcontentsmask;
+
        // Search for enemies, if no enemy can be seen directly try to look through transparent objects
+
+       self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
        for(;;)
        {
                while (head)
@@ -936,20 +936,18 @@ void havocbot_chooseenemy()
                        break;
 
                // Set flags to see through transparent objects
-               f = self.dphitcontentsmask;
-               self.dphitcontentsmask = DPCONTENTS_OPAQUE;
+               self.dphitcontentsmask |= DPCONTENTS_OPAQUE;
 
                head = head2;
                ++i;
        }
 
-       // Restore hit flags if needed
-       if(i)
-               self.dphitcontentsmask = f;
+       // Restore hit flags
+       self.dphitcontentsmask = hf;
 
        self.enemy = best;
        self.havocbot_stickenemy = TRUE;
-};
+}
 
 float havocbot_chooseweapon_checkreload(float new_weapon)
 {
@@ -962,7 +960,7 @@ float havocbot_chooseweapon_checkreload(float new_weapon)
        // if this weapon is scheduled for reloading, don't switch to it during combat
        if (self.weapon_load[new_weapon] < 0)
        {
-               local float i, other_weapon_available;
+               float i, other_weapon_available;
                for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                {
                        // if we are out of ammo for all other weapons, it's an emergency to switch to anything else
@@ -978,7 +976,7 @@ float havocbot_chooseweapon_checkreload(float new_weapon)
 
 void havocbot_chooseweapon()
 {
-       local float i;
+       float i;
 
        // ;)
        if(g_weaponarena == WEPBIT_TUBA)
@@ -1008,11 +1006,11 @@ void havocbot_chooseweapon()
        if(i < 1)
                return;
 
-       local float w;
-       local float distance; distance=bound(10,vlen(self.origin-self.enemy.origin)-200,10000);
+       float w;
+       float distance; distance=bound(10,vlen(self.origin-self.enemy.origin)-200,10000);
 
        // Should it do a weapon combo?
-       local float af, ct, combo_time, combo;
+       float af, ct, combo_time, combo;
 
        af = ATTACK_FINISHED(self);
        ct = autocvar_bot_ai_weapon_combo_threshold;
@@ -1076,11 +1074,11 @@ void havocbot_chooseweapon()
                        }
                }
        }
-};
+}
 
 void havocbot_aim()
 {
-       local vector selfvel, enemyvel;
+       vector selfvel, enemyvel;
 //     if(self.flags & FL_INWATER)
 //             return;
        if (time < self.nextaim)
@@ -1098,7 +1096,7 @@ void havocbot_aim()
        }
        else
                lag_additem(time + self.ping, 0, 0, world, self.origin, selfvel, ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5, '0 0 0');
-};
+}
 
 float havocbot_moveto_refresh_route()
 {
@@ -1113,7 +1111,7 @@ float havocbot_moveto_refresh_route()
 
 float havocbot_moveto(vector pos)
 {
-       local entity wp;
+       entity wp;
 
        if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
        {
@@ -1155,7 +1153,7 @@ float havocbot_moveto(vector pos)
                        debuggoalstack();
 
                // Heading
-               local vector dir = ( ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5 ) - (self.origin + self.view_ofs);
+               vector dir = ( ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5 ) - (self.origin + self.view_ofs);
                dir_z = 0;
                bot_aimdir(dir, -1);
 
@@ -1247,9 +1245,9 @@ vector havocbot_dodge()
        // LordHavoc: disabled because this is too expensive
        return '0 0 0';
 #if 0
-       local entity head;
-       local vector dodge, v, n;
-       local float danger, bestdanger, vl, d;
+       entity head;
+       vector dodge, v, n;
+       float danger, bestdanger, vl, d;
        dodge = '0 0 0';
        bestdanger = -20;
        // check for dangerous objects near bot or approaching bot
@@ -1292,4 +1290,4 @@ vector havocbot_dodge()
        }
        return dodge;
 #endif
-};
+}