// general bot AI cvars
set bot_ai_thinkinterval 0.05
set bot_ai_strategyinterval 5 "How often a new objective is chosen"
+set bot_ai_strategyinterval_movingtarget 3.5 "How often a new objective is chosen when current objective can move"
set bot_ai_enemydetectioninterval 2 "How often bots pick a new target"
set bot_ai_enemydetectionradius 10000 "How far bots can see enemies"
set bot_ai_dodgeupdateinterval 0.2 "How often scan for items to dodge. Currently not in use."
if(this.havocbot_attack_time>time)
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
navigation_goalrating_start(this);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
havocbot_goalrating_ons_offenseitems(this, 10000, this.origin, 10000);
navigation_goalrating_end(this);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_timeout_set(this);
}
}
string autocvar__campaign_name;
bool autocvar__sv_init;
float autocvar_bot_ai_strategyinterval;
+float autocvar_bot_ai_strategyinterval_movingtarget;
#define autocvar_bot_number cvar("bot_number")
int autocvar_bot_vs_human;
int autocvar_captureleadlimit_override;
.float bot_moveskill; // moving technique
.float bot_pickup;
.float(entity player, entity item) bot_pickupevalfunc;
-.float bot_strategytime;
.string cleanname;
.float havocbot_role_timeout;
.float isbot; // true if this client is actually a bot
entity navigation_findnearestwaypoint(entity ent, float walkfromwp);
void navigation_goalrating_end(entity this);
void navigation_goalrating_start(entity this);
+void navigation_goalrating_timeout_set(entity this);
+void navigation_goalrating_timeout_force(entity this);
+bool navigation_goalrating_timeout(entity this);
void navigation_markroutes(entity this, entity fixed_source_waypoint);
void navigation_markroutes_inverted(entity fixed_source_waypoint);
void navigation_routerating(entity this, entity e, float f, float rangebias);
if (this.deadflag == DEAD_DEAD)
{
PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
}
else if(this.aistatus & AI_STATUS_STUCK)
else if(havocbot_checkgoaldistance(this, gco))
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
else
return;
if(this.goalentity && wasfreed(this.goalentity))
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
return;
}
else if(this.goalentity.bot_pickup)
{
this.goalentity.bot_pickup_respawning = false;
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
return;
}
}
if(checkpvs(this.origin, this.goalentity))
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
return;
}
}
if(!locked_goal)
{
if(navigation_poptouchedgoals(this) && this.bot_strategytime < time + 1)
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
// if ran out of goals try to use an alternative goal or get a new strategy asap
if(this.goalcurrent == NULL)
{
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
return;
}
if(havocbot_checkgoaldistance(this, gco))
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
return;
}
if(unreachable)
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
}
if(IS_DEAD(this))
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
havocbot_goalrating_items(this, 10000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
- if(IS_PLAYER(this.goalentity))
- this.bot_strategytime = time + min(2, autocvar_bot_ai_strategyinterval);
+ navigation_goalrating_timeout_set(this);
}
}
void havocbot_chooserole(entity this)
{
LOG_TRACE("choosing a role...");
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
if(!MUTATOR_CALLHOOK(HavocBot_ChooseRole, this))
havocbot_chooserole_generic(this);
}
.float speed;
+void navigation_goalrating_timeout_set(entity this)
+{
+ if((IS_PLAYER(this.goalentity) || IS_MONSTER(this.goalentity)) && !STAT(FROZEN, this.goalentity))
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval_movingtarget;
+ else
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+}
+
+void navigation_goalrating_timeout_force(entity this)
+{
+ this.bot_strategytime = 0;
+}
+
+bool navigation_goalrating_timeout(entity this)
+{
+ return this.bot_strategytime < time;
+}
+
void navigation_dynamicgoal_init(entity this, bool initially_static)
{
this.navigation_dynamicgoal = true;
{
LOG_DEBUG(this.netname, " stuck, reachable waypoint found, heading to it");
navigation_routetogoal(this, bot_waypoint_queue_bestgoal, this.origin);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_timeout_set(this);
this.aistatus &= ~AI_STATUS_STUCK;
}
else
int navigation_poptouchedgoals(entity this);
void navigation_goalrating_start(entity this);
void navigation_goalrating_end(entity this);
+void navigation_goalrating_timeout_set(entity this);
+void navigation_goalrating_timeout_force(entity this);
+bool navigation_goalrating_timeout(entity this);
void navigation_unstuck(entity this);
void botframe_updatedangerousobjects(float maxupdate);
if(this.havocbot_attack_time>time)
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
navigation_goalrating_start(this);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
havocbot_goalrating_items(this, 15000, this.origin, 10000);
navigation_goalrating_end(this);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_timeout_set(this);
}
}
if(this.havocbot_attack_time>time)
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
navigation_goalrating_start(this);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 3000);
havocbot_goalrating_items(this, 15000, this.origin, 10000);
navigation_goalrating_end(this);
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
navigation_goalrating_start(this);
+
if(ctf_oneflag)
havocbot_goalrating_ctf_enemybase(this, 50000);
else
navigation_goalrating_end(this);
+ navigation_goalrating_timeout_set(this);
+
if (this.goalentity)
this.havocbot_cantfindflag = time + 10;
else if (time > this.havocbot_cantfindflag)
}
// Chase the flag carrier
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
+
havocbot_goalrating_ctf_enemyflag(this, 30000);
havocbot_goalrating_ctf_ourstolenflag(this, 40000);
havocbot_goalrating_items(this, 10000, this.origin, 10000);
+
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
+
havocbot_goalrating_ctf_ourstolenflag(this, 50000);
havocbot_goalrating_ctf_enemybase(this, 20000);
havocbot_goalrating_items(this, 5000, this.origin, 1000);
havocbot_goalrating_items(this, 1000, this.origin, 10000);
+
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
if(this.goalcurrent == mf)
{
navigation_clearroute(this);
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
havocbot_ctf_reset_role(this);
return;
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
float rt_radius;
rt_radius = 10000;
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
+
havocbot_goalrating_ctf_ourstolenflag(this, 50000);
havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
havocbot_goalrating_ctf_enemybase(this, 30000);
havocbot_goalrating_items(this, 500, this.origin, rt_radius);
+
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
vector org;
org = havocbot_middlepoint;
org.z = this.origin.z;
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
+
havocbot_goalrating_ctf_ourstolenflag(this, 50000);
havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
havocbot_goalrating_items(this, 2500, this.origin, 10000);
havocbot_goalrating_ctf_enemybase(this, 2500);
+
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
havocbot_ctf_reset_role(this);
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
vector org = mf.dropped_origin;
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
// if enemies are closer to our base, go there
havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
havocbot_goalrating_items(this, 5000, this.origin, 10000);
+
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
bot.havocbot_role = havocbot_role_ctf_carrier;
bot.havocbot_role_timeout = 0;
bot.havocbot_cantfindflag = time + 10;
- bot.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(bot);
break;
case HAVOCBOT_CTF_ROLE_DEFENSE:
s = "defense";
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_retriever;
bot.havocbot_role_timeout = time + 10;
- bot.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(bot);
break;
case HAVOCBOT_CTF_ROLE_ESCORT:
s = "escort";
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_escort;
bot.havocbot_role_timeout = time + 30;
- bot.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(bot);
break;
}
LOG_TRACE(bot.netname, " switched to ", s);
if(IS_DEAD(this))
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
IL_EACH(g_racecheckpoints, true,
});
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
if(IS_DEAD(this))
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
havocbot_goalrating_items(this, 8000, this.origin, 8000);
//havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (time > this.bot_strategytime)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
navigation_goalrating_start(this);
havocbot_goalrating_items(this, 10000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (time > this.bot_strategytime)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
navigation_goalrating_start(this);
havocbot_goalrating_items(this, 8000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
if (IS_DEAD(this))
return;
- if (time > this.bot_strategytime)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
navigation_goalrating_start(this);
havocbot_goalrating_items(this, 10000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
if (!this.ballcarried)
{
this.havocbot_role = havocbot_role_ka_collector;
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
}
if (IS_DEAD(this))
return;
- if (time > this.bot_strategytime)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-
navigation_goalrating_start(this);
havocbot_goalrating_items(this, 10000, this.origin, 10000);
havocbot_goalrating_enemyplayers(this, 1000, this.origin, 10000);
havocbot_goalrating_ball(this, 20000, this.origin);
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
if (this.ballcarried)
{
this.havocbot_role = havocbot_role_ka_carrier;
- this.bot_strategytime = 0;
+ navigation_goalrating_timeout_force(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
if(kh_Key_AllOwnedByWhichTeam() == this.team)
havocbot_goalrating_kh(this, 4, 4, 1); // play defensively
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
float key_owner_team;
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
key_owner_team = kh_Key_AllOwnedByWhichTeam();
havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
float key_owner_team;
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
key_owner_team = kh_Key_AllOwnedByWhichTeam();
havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK! EMERGENCY!
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
return;
}
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
int key_owner_team = kh_Key_AllOwnedByWhichTeam();
havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}
if(IS_DEAD(this))
return;
- if (this.bot_strategytime < time)
+ if (navigation_goalrating_timeout(this))
{
- this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
IL_EACH(g_racecheckpoints, true,
{
if(it.cnt == this.race_checkpoint)
- {
navigation_routerating(this, it, 1000000, 5000);
- }
else if(this.race_checkpoint == -1)
- {
navigation_routerating(this, it, 1000000, 5000);
- }
});
navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
}
}