}
else
{
- self.havocbot_role();
+ if not(self.jumppadcount)
+ self.havocbot_role();
}
// TODO: tracewalk() should take care of this job (better path finding under water)
bot_aimdir(v, -1);
}
havocbot_movetogoal();
+
+ // if the bot is not attacking, consider reloading weapons
+ if not(self.aistatus & AI_STATUS_ATTACKING)
+ {
+ float i;
+ entity e;
+
+ // 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(self.clip_load < self.clip_size)
+ self.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(self.clip_load >= 0) // only if we're not reloading a weapon already
+ {
+ 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"))))
+ self.switchweapon = i;
+ }
+ }
+ }
};
void havocbot_keyboard_movement(vector destorg)
local float trigger, trigger1;
blend = bound(0,sk*0.1,1);
- trigger = autocvar_bot_ai_keyboard_treshold;
+ trigger = autocvar_bot_ai_keyboard_threshold;
trigger1 = 0 - trigger;
// categorize forward movement
return;
// Don't jump when using some weapons
+ /*
if(self.aistatus & AI_STATUS_ATTACKING)
- if(self.weapon & WEP_CAMPINGRIFLE)
+ if(self.weapon == WEP_RIFLE)
return;
if(self.goalcurrent.classname == "player")
return;
+ */
maxspeed = autocvar_sv_maxspeed;
}
// Release jump button
+ if(!cvar("sv_pogostick"))
if(self.flags & FL_ONGROUND == 0)
{
if(self.velocity_z < 0 || vlen(self.velocity)<maxspeed)
if(self.goalcurrent==self.navigation_jetpack_goal)
if(self.ammo_fuel)
{
- #ifdef DEBUG_BOT_GOALSTACK
+ if(autocvar_bot_debug_goalstack)
+ {
debuggoalstack();
te_wizspike(self.navigation_jetpack_point);
- #endif
+ }
// Take off
if not(self.aistatus & AI_STATUS_JETPACK_FLYING)
// Handling of jump pads
if(self.jumppadcount)
{
- if(self.flags & FL_ONGROUND)
- {
- self.jumppadcount = FALSE;
- if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
- self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
- }
-
- // If got stuck on the jump pad try to reach the farther visible item
+ // If got stuck on the jump pad try to reach the farthest visible item
if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
{
if(fabs(self.velocity_z)<50)
local float threshold;
threshold = maxspeed * 0.2;
if(fabs(self.velocity_x) < threshold && fabs(self.velocity_y) < threshold)
+ {
+ dprint("Warning: ", self.netname, " got stuck on a jumppad, trying to get out of it now\n");
self.aistatus |= AI_STATUS_OUT_JUMPPAD;
+ }
return;
}
+
+ // Don't chase players while using a jump pad
+ if(self.goalcurrent.classname=="player" || self.goalstack01.classname=="player")
+ return;
}
}
+ else if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
+ self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
// If there is a trigger_hurt right below try to use the jetpack or make a rocketjump
if(skill>6)
return;
}
-#ifdef DEBUG_BOT_GOALSTACK
- debuggoalstack();
-#endif
+ if(autocvar_bot_debug_goalstack)
+ debuggoalstack();
m1 = self.goalcurrent.origin + self.goalcurrent.mins;
m2 = self.goalcurrent.origin + self.goalcurrent.maxs;
// (only when the bot is on the ground or jumping intentionally)
self.aistatus &~= AI_STATUS_DANGER_AHEAD;
- if(trace_fraction == 1)
+ if(trace_fraction == 1 && self.jumppadcount == 0)
if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE)
{
// Look downwards
// I want to do a second scan if no enemy was found or I don't have weapons
// TODO: Perform the scan when using the rifle (requires changes on the rifle code)
- if(best || self.weapons) // || self.weapon == WEP_CAMPINGRIFLE
+ if(best || self.weapons) // || self.weapon == WEP_RIFLE
break;
if(i)
break;
self.havocbot_stickenemy = TRUE;
};
+float havocbot_chooseweapon_checkreload(float 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.
+ // this also allows bots under this skill to be more stupid, and reload more often during combat :)
+ if(skill < 5)
+ return FALSE;
+
+ // 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;
+ 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
+ if (weapon_action(i, WR_CHECKAMMO1) + weapon_action(i, WR_CHECKAMMO2))
+ other_weapon_available = TRUE;
+ }
+ if(other_weapon_available)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
void havocbot_chooseweapon()
{
local float i;
if(i < 1)
return;
- // Workaround for rifle reloading (..)
- if(self.weapon == WEP_CAMPINGRIFLE)
- if(i < autocvar_g_balance_campingrifle_reloadtime + 1)
- return;
-
local float w;
- local float rocket ; rocket =-1000;
- local float nex ; nex =-1000;
- local float hagar ; hagar =-1000;
- local float grenade ; grenade =-1000;
- local float mine ; mine =-1000;
- local float electro ; electro =-1000;
- local float crylink ; crylink =-1000;
- local float uzi ; uzi =-1000;
- local float shotgun ; shotgun =-1000;
- local float campingrifle ; campingrifle =-1000;
- local float laser ; laser =-1000;
- local float minstanex ; minstanex =-1000;
- local float bestscore; bestscore = 0;
- local float bestweapon; bestweapon=self.switchweapon;
local float distance; distance=bound(10,vlen(self.origin-self.enemy.origin)-200,10000);
- local float maxdelaytime=0.5;
- local float spreadpenalty=10;
// Should it do a weapon combo?
local float af, ct, combo_time, combo;
if ( distance > bot_distance_far ) {
for(i=0; i < WEP_COUNT && bot_weapons_far[i] != -1 ; ++i){
w = bot_weapons_far[i];
- if ( client_hasweapon(self, w, TRUE, FALSE) ){
- if ( self.weapon == w && combo)
+ if ( client_hasweapon(self, w, TRUE, FALSE) )
+ {
+ if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w))
continue;
self.switchweapon = w;
return;
if ( distance > bot_distance_close) {
for(i=0; i < WEP_COUNT && bot_weapons_mid[i] != -1 ; ++i){
w = bot_weapons_mid[i];
- if ( client_hasweapon(self, w, TRUE, FALSE) ){
- if ( self.weapon == w && combo)
+ if ( client_hasweapon(self, w, TRUE, FALSE) )
+ {
+ if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w))
continue;
self.switchweapon = w;
return;
// Choose weapons for close distance
for(i=0; i < WEP_COUNT && bot_weapons_close[i] != -1 ; ++i){
w = bot_weapons_close[i];
- if ( client_hasweapon(self, w, TRUE, FALSE) ){
- if ( self.weapon == w && combo)
+ if ( client_hasweapon(self, w, TRUE, FALSE) )
+ {
+ if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w))
continue;
self.switchweapon = w;
return;
}
}
- #ifdef DEBUG_BOT_GOALSTACK
+ if(autocvar_bot_debug_goalstack)
debuggoalstack();
- #endif
// Heading
local vector dir = self.goalcurrent.origin - (self.origin + self.view_ofs);
{
// 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;
head = head.chain;
}
return dodge;
- */
+#endif
};