]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/havocbot/havocbot.qc
Merge branch 'master' into Mario/overkill
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / havocbot / havocbot.qc
index d23c29675a70fa7bc5d2944922f143ee6a7c9a28..761300005321530823d3c8f1ddf60bc6f6bcded4 100644 (file)
@@ -9,10 +9,14 @@
 #include "../waypoints.qh"
 
 #include <common/constants.qh>
+#include <common/impulses/all.qh>
+#include <common/net_linked.qh>
 #include <common/physics/player.qh>
 #include <common/state.qh>
 #include <common/items/_mod.qh>
+#include <common/wepent.qh>
 
+#include <common/triggers/teleporters.qh>
 #include <common/triggers/trigger/jumppads.qh>
 
 #include <lib/warpzone/common.qh>
@@ -42,7 +46,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))
                {
@@ -83,10 +87,16 @@ void havocbot_ai(entity this)
                return;
 
        havocbot_chooseenemy(this);
-       if (this.bot_chooseweapontime < time )
+
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
-               this.bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval;
-               havocbot_chooseweapon(this);
+               .entity weaponentity = weaponentities[slot];
+               if(this.(weaponentity).m_weapon != WEP_Null || slot == 0)
+               if(this.(weaponentity).bot_chooseweapontime < time)
+               {
+                       this.(weaponentity).bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval;
+                       havocbot_chooseweapon(this, weaponentity);
+               }
        }
        havocbot_aim(this);
        lag_update(this);
@@ -97,8 +107,6 @@ void havocbot_ai(entity this)
 
                if(this.weapons)
                {
-                       Weapon w = PS(this).m_weapon;
-                       w.wr_aim(w, this);
                        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
                        {
                                PHYS_INPUT_BUTTON_ATCK(this) = false;
@@ -106,8 +114,16 @@ 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;
+                               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                               {
+                                       .entity weaponentity = weaponentities[slot];
+                                       Weapon w = this.(weaponentity).m_weapon;
+                                       if(w == WEP_Null && slot != 0)
+                                               continue;
+                                       w.wr_aim(w, this, weaponentity);
+                                       if(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) // TODO: what if we didn't fire this weapon, but the previous?
+                                               this.(weaponentity).lastfiredweapon = this.(weaponentity).m_weapon.m_id;
+                               }
                        }
                }
                else
@@ -128,7 +144,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);
@@ -154,20 +170,31 @@ void havocbot_ai(entity this)
        // if the bot is not attacking, consider reloading weapons
        if (!(this.aistatus & AI_STATUS_ATTACKING))
        {
-               // we are currently holding a weapon that's not fully loaded, reload it
-               if(skill >= 2) // bots can only reload the held weapon on purpose past this skill
-               if(this.clip_load < this.clip_size)
-                       this.impulse = 20; // "press" the reload button, not sure if this is done right
-
-               // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next
-               // the code above executes next frame, starting the reloading then
-               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
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
-                       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;
-                       ));
+                       .entity weaponentity = weaponentities[slot];
+
+                       if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
+                               continue;
+
+                       // we are currently holding a weapon that's not fully loaded, reload it
+                       if(skill >= 2) // bots can only reload the held weapon on purpose past this skill
+                       if(this.(weaponentity).clip_load < this.(weaponentity).clip_size)
+                               this.impulse = IMP_weapon_reload.impulse; // not sure if this is done right
+
+                       // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next
+                       // the code above executes next frame, starting the reloading then
+                       if(skill >= 5) // bots can only look for unloaded weapons past this skill
+                       if(this.(weaponentity).clip_load >= 0) // only if we're not reloading a weapon already
+                       {
+                               FOREACH(Weapons, it != WEP_Null, LAMBDA(
+                                       if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
+                                       {
+                                               this.(weaponentity).m_switchweapon = it;
+                                               break;
+                                       }
+                               ));
+                       }
                }
        }
 }
@@ -319,7 +346,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);
@@ -341,7 +368,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
@@ -471,7 +499,7 @@ void havocbot_movetogoal(entity this)
 
                // Flying
                PHYS_INPUT_BUTTON_HOOK(this) = true;
-               if(this.navigation_jetpack_point.z - STAT(PL_MAX, NULL).z + STAT(PL_MIN, NULL).z < this.origin.z)
+               if(this.navigation_jetpack_point.z - STAT(PL_MAX, this).z + STAT(PL_MIN, this).z < this.origin.z)
                {
                        this.movement_x = dir * v_forward * maxspeed;
                        this.movement_y = dir * v_right * maxspeed;
@@ -483,6 +511,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)
@@ -495,7 +524,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;
                                });
 
@@ -505,6 +534,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;
                                }
                        }
@@ -583,25 +614,35 @@ void havocbot_movetogoal(entity this)
                else if(this.health>WEP_CVAR(devastator, damage)*0.5)
                {
                        if(this.velocity.z < 0)
-                       if(client_hasweapon(this, WEP_DEVASTATOR, true, false))
                        {
-                               this.movement_x = maxspeed;
-
-                               if(this.rocketjumptime)
+                               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                                {
-                                       if(time > this.rocketjumptime)
+                                       .entity weaponentity = weaponentities[slot];
+
+                                       if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
+                                               continue;
+
+                                       if(client_hasweapon(this, WEP_DEVASTATOR, weaponentity, true, false))
                                        {
-                                               PHYS_INPUT_BUTTON_ATCK2(this) = true;
-                                               this.rocketjumptime = 0;
+                                               this.movement_x = maxspeed;
+
+                                               if(this.rocketjumptime)
+                                               {
+                                                       if(time > this.rocketjumptime)
+                                                       {
+                                                               PHYS_INPUT_BUTTON_ATCK2(this) = true;
+                                                               this.rocketjumptime = 0;
+                                                       }
+                                                       return;
+                                               }
+
+                                               this.(weaponentity).m_switchweapon = WEP_DEVASTATOR;
+                                               this.v_angle_x = 90;
+                                               PHYS_INPUT_BUTTON_ATCK(this) = true;
+                                               this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay);
+                                               return;
                                        }
-                                       return;
                                }
-
-                               PS(this).m_switchweapon = WEP_DEVASTATOR;
-                               this.v_angle_x = 90;
-                               PHYS_INPUT_BUTTON_ATCK(this) = true;
-                               this.rocketjumptime = time + WEP_CVAR(devastator, detonatedelay);
-                               return;
                        }
                }
                else
@@ -633,8 +674,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)
@@ -709,10 +749,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);
@@ -749,12 +787,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');
@@ -763,17 +801,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;
                                                }
                                        }
                                }
@@ -836,11 +879,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 +939,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 +957,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 +1003,6 @@ LABEL(scan_targets)
                // Set flags to see through transparent objects
                this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
 
-               head = head2;
                scan_transparent = true;
        }
 
@@ -961,7 +1015,7 @@ LABEL(scan_targets)
                this.havocbot_stickenemy = false;
 }
 
-float havocbot_chooseweapon_checkreload(entity this, int new_weapon)
+float havocbot_chooseweapon_checkreload(entity this, .entity weaponentity, int new_weapon)
 {
        // bots under this skill cannot find unloaded weapons to reload idly when not in combat,
        // so skip this for them, or they'll never get to reload their weapons at all.
@@ -970,28 +1024,25 @@ float havocbot_chooseweapon_checkreload(entity this, int new_weapon)
                return false;
 
        // if this weapon is scheduled for reloading, don't switch to it during combat
-       if (this.weapon_load[new_weapon] < 0)
+       if (this.(weaponentity).weapon_load[new_weapon] < 0)
        {
-               bool other_weapon_available = false;
                FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                       if(it.wr_checkammo1(it, this) + it.wr_checkammo2(it, this))
-                               other_weapon_available = true;
+                       if(it.wr_checkammo1(it, this, weaponentity) + it.wr_checkammo2(it, this, weaponentity))
+                               return true; // other weapon available
                ));
-               if(other_weapon_available)
-                       return true;
        }
 
        return false;
 }
 
-void havocbot_chooseweapon(entity this)
+void havocbot_chooseweapon(entity this, .entity weaponentity)
 {
        int i;
 
        // ;)
        if(g_weaponarena_weapons == WEPSET(TUBA))
        {
-               PS(this).m_switchweapon = WEP_TUBA;
+               this.(weaponentity).m_switchweapon = WEP_TUBA;
                return;
        }
 
@@ -999,11 +1050,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))
+                       if(client_hasweapon(this, it, weaponentity, true, false))
                        {
-                               PS(this).m_switchweapon = it;
+                               this.(weaponentity).m_switchweapon = it;
                                return;
                        }
                ));
@@ -1031,7 +1082,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.(weaponentity).lastfiredweapon)
        if(af > combo_time)
        {
                combo = true;
@@ -1047,11 +1098,11 @@ void havocbot_chooseweapon(entity this)
                if ( distance > bot_distance_far ) {
                        for(i=0; i < Weapons_COUNT && bot_weapons_far[i] != -1 ; ++i){
                                w = bot_weapons_far[i];
-                               if ( client_hasweapon(this, Weapons_from(w), true, false) )
+                               if ( client_hasweapon(this, Weapons_from(w), weaponentity, 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, weaponentity, w))
                                                continue;
-                                       PS(this).m_switchweapon = Weapons_from(w);
+                                       this.(weaponentity).m_switchweapon = Weapons_from(w);
                                        return;
                                }
                        }
@@ -1061,11 +1112,11 @@ void havocbot_chooseweapon(entity this)
                if ( distance > bot_distance_close) {
                        for(i=0; i < Weapons_COUNT && bot_weapons_mid[i] != -1 ; ++i){
                                w = bot_weapons_mid[i];
-                               if ( client_hasweapon(this, Weapons_from(w), true, false) )
+                               if ( client_hasweapon(this, Weapons_from(w), weaponentity, 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, weaponentity, w))
                                                continue;
-                                       PS(this).m_switchweapon = Weapons_from(w);
+                                       this.(weaponentity).m_switchweapon = Weapons_from(w);
                                        return;
                                }
                        }
@@ -1074,11 +1125,11 @@ void havocbot_chooseweapon(entity this)
                // Choose weapons for close distance
                for(i=0; i < Weapons_COUNT && bot_weapons_close[i] != -1 ; ++i){
                        w = bot_weapons_close[i];
-                       if ( client_hasweapon(this, Weapons_from(w), true, false) )
+                       if ( client_hasweapon(this, Weapons_from(w), weaponentity, 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, weaponentity, w))
                                        continue;
-                               PS(this).m_switchweapon = Weapons_from(w);
+                               this.(weaponentity).m_switchweapon = Weapons_from(w);
                                return;
                        }
                }
@@ -1214,7 +1265,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;