#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/wepent.qh>
#include <common/triggers/teleporters.qh>
#include <common/triggers/trigger/jumppads.qh>
if(bot_execute_commands(this))
return;
+ if(this.goalcurrent)
+ if(wasfreed(this.goalcurrent))
+ navigation_poproute(this);
+
if (bot_strategytoken == this)
if (!bot_strategytoken_taken)
{
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);
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;
}
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
// 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 = 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.(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;
+ ));
+ }
}
}
}
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
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;
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
{
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;
}
// Set flags to see through transparent objects
this.dphitcontentsmask |= DPCONTENTS_OPAQUE;
- head = head2;
scan_transparent = true;
}
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.
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))
+ if(it.wr_checkammo1(it, this, weaponentity) + it.wr_checkammo2(it, this, weaponentity))
other_weapon_available = true;
));
if(other_weapon_available)
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;
}
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;
}
));
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;
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;
}
}
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;
}
}
// 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;
}
}