// 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
+ CS(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(
+ FOREACH(Weapons, it != WEP_Null, {
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;
}
- ));
+ });
}
}
}
void havocbot_keyboard_movement(entity this, vector destorg)
{
vector keyboard;
- float blend, maxspeed;
- float sk;
-
- sk = skill + this.bot_moveskill;
-
- maxspeed = autocvar_sv_maxspeed;
- if (time < this.havocbot_keyboardtime)
- return;
-
- this.havocbot_keyboardtime =
- max(
- this.havocbot_keyboardtime
- + 0.05/max(1, sk+this.havocbot_keyboardskill)
- + random()*0.025/max(0.00025, skill+this.havocbot_keyboardskill)
- , time);
- keyboard = this.movement * (1.0 / maxspeed);
-
- float trigger, trigger1;
- blend = bound(0,sk*0.1,1);
- trigger = autocvar_bot_ai_keyboard_threshold;
- trigger1 = 0 - trigger;
-
- // categorize forward movement
- // at skill < 1.5 only forward
- // at skill < 2.5 only individual directions
- // at skill < 4.5 only individual directions, and forward diagonals
- // at skill >= 4.5, all cases allowed
- if (keyboard.x > trigger)
- {
- keyboard.x = 1;
- if (sk < 2.5)
- keyboard.y = 0;
- }
- else if (keyboard.x < trigger1 && sk > 1.5)
+ if (time > this.havocbot_keyboardtime)
{
- keyboard.x = -1;
+ float sk = skill + this.bot_moveskill;
+ this.havocbot_keyboardtime =
+ max(
+ this.havocbot_keyboardtime
+ + 0.05 / max(1, sk + this.havocbot_keyboardskill)
+ + random() * 0.025 / max(0.00025, skill + this.havocbot_keyboardskill)
+ , time);
+ keyboard = CS(this).movement / autocvar_sv_maxspeed;
+
+ float trigger = autocvar_bot_ai_keyboard_threshold;
+ float trigger1 = -trigger;
+
+ // categorize forward movement
+ // at skill < 1.5 only forward
+ // at skill < 2.5 only individual directions
+ // at skill < 4.5 only individual directions, and forward diagonals
+ // at skill >= 4.5, all cases allowed
+ if (keyboard.x > trigger)
+ {
+ keyboard.x = 1;
+ if (sk < 2.5)
+ keyboard.y = 0;
+ }
+ else if (keyboard.x < trigger1 && sk > 1.5)
+ {
+ keyboard.x = -1;
+ if (sk < 4.5)
+ keyboard.y = 0;
+ }
+ else
+ {
+ keyboard.x = 0;
+ if (sk < 1.5)
+ keyboard.y = 0;
+ }
if (sk < 4.5)
- keyboard.y = 0;
- }
- else
- {
- keyboard.x = 0;
- if (sk < 1.5)
- keyboard.y = 0;
- }
- if (sk < 4.5)
- keyboard.z = 0;
+ keyboard.z = 0;
- if (keyboard.y > trigger)
- keyboard.y = 1;
- else if (keyboard.y < trigger1)
- keyboard.y = -1;
- else
- keyboard.y = 0;
+ if (keyboard.y > trigger)
+ keyboard.y = 1;
+ else if (keyboard.y < trigger1)
+ keyboard.y = -1;
+ else
+ keyboard.y = 0;
- if (keyboard.z > trigger)
- keyboard.z = 1;
- else if (keyboard.z < trigger1)
- keyboard.z = -1;
- else
- keyboard.z = 0;
+ if (keyboard.z > trigger)
+ keyboard.z = 1;
+ else if (keyboard.z < trigger1)
+ keyboard.z = -1;
+ else
+ keyboard.z = 0;
- this.havocbot_keyboard = keyboard * maxspeed;
- if (this.havocbot_ducktime>time) PHYS_INPUT_BUTTON_CROUCH(this) = true;
+ this.havocbot_keyboard = keyboard * autocvar_sv_maxspeed;
+ if (this.havocbot_ducktime > time)
+ PHYS_INPUT_BUTTON_CROUCH(this) = true;
+ }
keyboard = this.havocbot_keyboard;
- blend = bound(0,vlen(destorg-this.origin)/autocvar_bot_ai_keyboard_distance,1); // When getting close move with 360 degree
- //dprint("movement ", vtos(this.movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
- this.movement = this.movement + (keyboard - this.movement) * blend;
+ float blend = bound(0, vlen(destorg - this.origin) / autocvar_bot_ai_keyboard_distance, 1); // When getting close move with 360 degree
+ //dprint("movement ", vtos(CS(this).movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
+ CS(this).movement = CS(this).movement + (keyboard - CS(this).movement) * blend;
}
void havocbot_bunnyhop(entity this, vector dir)
if(checkdistance)
{
this.aistatus &= ~AI_STATUS_RUNNING;
- // increase stop distance in case the goal is on a slope or a lower platform
+ // 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;
}
while (deviation.y > 180) deviation.y = deviation.y - 360;
if(fabs(deviation.y)>10)
- this.movement_x = 0;
+ CS(this).movement_x = 0;
if(deviation.y>10)
- this.movement_y = maxspeed * -1;
+ CS(this).movement_y = maxspeed * -1;
else if(deviation.y<10)
- this.movement_y = maxspeed;
+ CS(this).movement_y = maxspeed;
}
}
vector dodge;
//if (this.goalentity)
// te_lightning2(this, this.origin, (this.goalentity.absmin + this.goalentity.absmax) * 0.5);
- this.movement = '0 0 0';
+ CS(this).movement = '0 0 0';
maxspeed = autocvar_sv_maxspeed;
// Jetpack navigation
// Brake
if(fabs(this.velocity.x)>maxspeed*0.3)
{
- this.movement_x = dir * v_forward * -maxspeed;
+ CS(this).movement_x = dir * v_forward * -maxspeed;
return;
}
// Switch to normal mode
PHYS_INPUT_BUTTON_HOOK(this) = true;
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;
+ CS(this).movement_x = dir * v_forward * maxspeed;
+ CS(this).movement_y = dir * v_right * maxspeed;
}
return;
}
tracebox(this.origin, this.mins, this.maxs, this.origin + (dir * maxspeed * 3), MOVE_NOMONSTERS, this);
if(trace_fraction==1)
{
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
+ CS(this).movement_x = dir * v_forward * maxspeed;
+ CS(this).movement_y = dir * v_right * maxspeed;
if (skill < 10)
havocbot_keyboard_movement(this, this.origin + dir * 100);
}
return;
}
- else if(this.health>WEP_CVAR(devastator, damage)*0.5)
+ else if(this.health > WEP_CVAR(devastator, damage) * 0.5 * ((this.strength_finished < time) ? autocvar_g_balance_powerup_strength_selfdamage : 1))
{
if(this.velocity.z < 0)
{
if(client_hasweapon(this, WEP_DEVASTATOR, weaponentity, true, false))
{
- this.movement_x = maxspeed;
+ CS(this).movement_x = maxspeed;
if(this.rocketjumptime)
{
{
// If there is no goal try to move forward
if(this.goalcurrent==NULL)
- this.movement_x = maxspeed;
+ CS(this).movement_x = maxspeed;
}
}
else
PHYS_INPUT_BUTTON_JUMP(this) = false;
makevectors(this.v_angle.y * '0 1 0');
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- this.movement_z = dir * v_up * maxspeed;
+ CS(this).movement_x = dir * v_forward * maxspeed;
+ CS(this).movement_y = dir * v_right * maxspeed;
+ CS(this).movement_z = dir * v_up * maxspeed;
}
// if there is nowhere to go, exit
evadeobstacle = '0 0 0';
evadelava = '0 0 0';
+ this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
makevectors(this.v_angle.y * '0 1 0');
if (this.waterlevel)
{
}
// if bot for some reason doesn't get close to the current goal find another one
- float curr_dist = vlen(this.origin - this.goalcurrent.origin);
- if(!IS_PLAYER(this.goalcurrent))
+ if(!IS_PLAYER(this.goalcurrent) && !(this.goalcurrent.bot_pickup_respawning && this.goalcurrent_distance < 50))
{
+ float curr_dist = vlen(this.origin - this.goalcurrent.origin);
if(this.goalcurrent != this.goalcurrent_prev)
{
this.goalcurrent_prev = this.goalcurrent;
// Check for water/slime/lava and dangerous edges
// (only when the bot is on the ground or jumping intentionally)
- this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
vector dst_ahead = this.origin + this.view_ofs + offset;
vector dst_down = dst_ahead - '0 0 3000';
//dir = this.bot_dodgevector;
//if (this.bot_dodgevector_jumpbutton)
// PHYS_INPUT_BUTTON_JUMP(this) = true;
- this.movement_x = dir * v_forward * maxspeed;
- this.movement_y = dir * v_right * maxspeed;
- this.movement_z = dir * v_up * maxspeed;
+ CS(this).movement_x = dir * v_forward * maxspeed;
+ CS(this).movement_y = dir * v_right * maxspeed;
+ CS(this).movement_z = dir * v_up * maxspeed;
// Emulate keyboard interface
if (skill < 10)
// if this weapon is scheduled for reloading, don't switch to it during combat
if (this.(weaponentity).weapon_load[new_weapon] < 0)
{
- FOREACH(Weapons, it != WEP_Null, LAMBDA(
+ FOREACH(Weapons, it != WEP_Null, {
if(it.wr_checkammo1(it, this, weaponentity) + it.wr_checkammo2(it, this, weaponentity))
return true; // other weapon available
- ));
+ });
}
return false;
{
// If no weapon was chosen get the first available weapon
if(this.(weaponentity).m_weapon==WEP_Null)
- FOREACH(Weapons, it != WEP_Null, LAMBDA(
+ FOREACH(Weapons, it != WEP_Null, {
if(client_hasweapon(this, it, weaponentity, true, false))
{
this.(weaponentity).m_switchweapon = it;
return;
}
- ));
+ });
return;
}
void havocbot_aim(entity this)
{
- vector myvel, enemyvel;
-// if(this.flags & FL_INWATER)
-// return;
if (time < this.nextaim)
return;
this.nextaim = time + 0.1;
- myvel = this.velocity;
+ vector myvel = this.velocity;
if (!this.waterlevel)
myvel.z = 0;
- if (this.enemy)
+ if(MUTATOR_CALLHOOK(HavocBot_Aim, this)) { /* do nothing */ }
+ else if (this.enemy)
{
- enemyvel = this.enemy.velocity;
+ vector enemyvel = this.enemy.velocity;
if (!this.enemy.waterlevel)
enemyvel.z = 0;
- lag_additem(this, time + this.ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
+ lag_additem(this, time + CS(this).ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
}
else
- lag_additem(this, time + this.ping, 0, 0, NULL, this.origin, myvel, ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5, '0 0 0');
+ lag_additem(this, time + CS(this).ping, 0, 0, NULL, this.origin, myvel, ( this.goalcurrent.absmin + this.goalcurrent.absmax ) * 0.5, '0 0 0');
}
bool havocbot_moveto_refresh_route(entity this)
navigation_goalrating_start(this);
navigation_routerating(this, wp, 10000, 10000);
navigation_goalrating_end(this);
- return this.navigation_hasgoals;
+ return (this.goalentity != NULL);
}
float havocbot_moveto(entity this, vector pos)