#include "havocbot.qh"
+#include <server/defs.qh>
+#include <server/miscfunctions.qh>
#include "../cvars.qh"
#include "../aim.qh"
this.aistatus |= AI_STATUS_ROAMING;
this.aistatus &= ~AI_STATUS_ATTACKING;
- vector v, now, next;
+ vector v = '0 0 0', now, next;
float aimdistance,skillblend,distanceblend,blend;
- if(this.goalcurrent.wpisbox && boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin, this.origin))
- v = this.goalcurrent.origin;
- else
- SET_DESTCOORDS(this.goalcurrent, this.origin, v);
+ SET_DESTCOORDS(this.goalcurrent, this.origin, v);
+ if(this.goalcurrent.wpisbox)
+ {
+ // avoid a glitch when bot is teleported but teleport waypoint isn't removed yet
+ if(this.goalstack02 && this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT
+ && this.lastteleporttime > 0 && time - this.lastteleporttime < 0.15)
+ v = (this.goalstack02.absmin + this.goalstack02.absmax) * 0.5;
+ // aim to teleport origin if bot is inside teleport waypoint but hasn't touched the real teleport yet
+ else if(boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin, this.origin))
+ v = this.goalcurrent.origin;
+ }
next = now = v - (this.origin + this.view_ofs);
aimdistance = vlen(now);
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;
}
- ));
+ });
}
}
}
float bunnyhopdistance;
vector deviation;
float maxspeed;
- vector gco, gno;
+ vector gco = '0 0 0', gno;
// Don't jump when attacking
if(this.aistatus & AI_STATUS_ATTACKING)
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;
}
bool havocbot_checkgoaldistance(entity this, vector gco)
{
float curr_dist = vlen(this.origin - gco);
- if(curr_dist > this.goalcurrent_distance)
+ float curr_dist_2d = vlen(vec2(this.origin - gco));
+ if(curr_dist > this.goalcurrent_distance && curr_dist_2d > this.goalcurrent_distance_2d)
{
if(!this.goalcurrent_distance_time)
this.goalcurrent_distance_time = time;
else
{
// reduce it a little bit so it works even with very small approaches to the goal
- this.goalcurrent_distance = max(20, curr_dist - 15);
+ this.goalcurrent_distance = max(20, curr_dist - 10);
+ this.goalcurrent_distance_2d = max(20, curr_dist_2d - 10);
this.goalcurrent_distance_time = 0;
}
return false;
void havocbot_movetogoal(entity this)
{
- vector destorg;
+ vector destorg = '0 0 0';
vector diff;
vector dir;
vector flatdir;
this.goalentity.bot_pickup_respawning = false;
else if(time < this.goalentity.scheduledrespawntime - 10) // item already taken (by someone else)
{
- this.goalentity.bot_pickup_respawning = false;
- navigation_clearroute(this);
- this.bot_strategytime = 0;
- return;
+ if(checkpvs(this.origin, this.goalentity))
+ {
+ this.goalentity.bot_pickup_respawning = false;
+ navigation_clearroute(this);
+ this.bot_strategytime = 0;
+ return;
+ }
}
else if(this.goalentity == this.goalcurrent)
locked_goal = true; // wait for item to respawn
}
- else if(!this.goalentity.solid)
+ else if(!this.goalentity.solid && !boxesoverlap(this.goalentity.absmin, this.goalentity.absmax, this.absmin, this.absmax))
{
- navigation_clearroute(this);
- this.bot_strategytime = 0;
- return;
+ if(checkpvs(this.origin, this.goalentity))
+ {
+ navigation_clearroute(this);
+ this.bot_strategytime = 0;
+ return;
+ }
}
}
if(!locked_goal)
- navigation_poptouchedgoals(this);
+ {
+ if(navigation_poptouchedgoals(this) && this.bot_strategytime < time + 1)
+ this.bot_strategytime = 0;
+ }
// if ran out of goals try to use an alternative goal or get a new strategy asap
if(this.goalcurrent == NULL)
// in case bot ends up inside the teleport waypoint without touching
// the teleport itself, head to the teleport origin
- if(this.goalcurrent.wpisbox && boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.absmin, this.absmax))
+ if(this.goalcurrent.wpisbox && boxesoverlap(this.goalcurrent.absmin, this.goalcurrent.absmax, this.origin + eZ * this.mins.z, this.origin + eZ * this.maxs.z))
{
bunnyhop_forbidden = true;
destorg = this.goalcurrent.origin;
// 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;
}
debuggoalstack(this);
// Heading
- vector dir;
+ vector dir = '0 0 0';
SET_DESTCOORDS(this.goalcurrent, this.origin, dir);
dir = dir - (this.origin + this.view_ofs);
dir.z = 0;