To make work bot_ai_aimskill_firetolerance with all weapons, fire tolerance is now raised for specific attacks that don't require too much accuracy, e.g. shotgun and devastator attacks
METHOD(OverkillHeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true);
}
METHOD(OverkillHeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
METHOD(OverkillMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true);
}
METHOD(OverkillMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
METHOD(OverkillNex, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
- if(bot_aim(actor, weaponentity, 1000000, 0, 1, false))
+ if(bot_aim(actor, weaponentity, 1000000, 0, 1, false, true))
PHYS_INPUT_BUTTON_ATCK(actor) = true;
else
{
METHOD(OverkillRocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false, true);
}
METHOD(OverkillRocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if (vdist(actor.origin - actor.enemy.origin, >, WEP_CVAR_PRI(okshotgun, bot_range)))
{
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false);
}
else
{
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false);
}
}
WEP_CVAR(arc, beam_botaimspeed),
0,
WEP_CVAR(arc, beam_botaimlifetime),
- false
+ false, true
);
}
else
1000000,
0,
0.001,
- false
+ false, true
);
}
}
if(WEP_CVAR(blaster, secondary))
{
if((random() * (WEP_CVAR_PRI(blaster, damage) + WEP_CVAR_SEC(blaster, damage))) > WEP_CVAR_PRI(blaster, damage))
- { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(blaster, speed), 0, WEP_CVAR_SEC(blaster, lifetime), false); }
+ { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(blaster, speed), 0, WEP_CVAR_SEC(blaster, lifetime), false, true); }
else
- { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
+ { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false, true); }
}
else
- { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
+ { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false, true); }
}
METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
METHOD(Crylink, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(random() < 0.10)
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(crylink, speed), 0, WEP_CVAR_PRI(crylink, middle_lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(crylink, speed), 0, WEP_CVAR_PRI(crylink, middle_lifetime), false, true);
else
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false, true);
}
METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
// 20 times faster at 90 degrees guide rate
if (actor.bot_aimtarg && WEP_CVAR(devastator, guiderate) > 0)
spd *= sqrt(WEP_CVAR(devastator, guiderate)) * (20 / 9.489); // 9.489 ~= sqrt(90)
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, spd, 0, WEP_CVAR(devastator, lifetime), false);
+ // no need to fire with high accuracy on large distances if rockets can be guided
+ bool shot_accurate = (WEP_CVAR(devastator, guiderate) < 50);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, spd, 0, WEP_CVAR(devastator, lifetime), false, shot_accurate);
float pred_time = bound(0.02, 0.02 + (8 - skill) * 0.01, 0.1);
if(skill >= 2) // skill 0 and 1 bots won't detonate rockets!
{
float shoot;
if(WEP_CVAR_PRI(electro, speed))
- shoot = bot_aim(actor, weaponentity, WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false);
+ shoot = bot_aim(actor, weaponentity, WEP_CVAR_PRI(electro, speed), 0, WEP_CVAR_PRI(electro, lifetime), false, true);
else
- shoot = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ shoot = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true);
if(shoot)
{
}
else
{
- if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(electro, speed), WEP_CVAR_SEC(electro, speed_up), WEP_CVAR_SEC(electro, lifetime), true, true))
{
PHYS_INPUT_BUTTON_ATCK2(actor) = true;
if(random() < 0.03) actor.bot_secondary_electromooth = 0;
PHYS_INPUT_BUTTON_ATCK2(actor) = false;
if(actor.bot_primary_fireballmooth == 0)
{
- if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(fireball, speed), 0, WEP_CVAR_PRI(fireball, lifetime), false))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(fireball, speed), 0, WEP_CVAR_PRI(fireball, lifetime), false, false))
{
PHYS_INPUT_BUTTON_ATCK(actor) = true;
if(random() < 0.02) actor.bot_primary_fireballmooth = 0;
}
else
{
- if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(fireball, speed), WEP_CVAR_SEC(fireball, speed_up), WEP_CVAR_SEC(fireball, lifetime), true))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(fireball, speed), WEP_CVAR_SEC(fireball, speed_up), WEP_CVAR_SEC(fireball, lifetime), true, false))
{
PHYS_INPUT_BUTTON_ATCK2(actor) = true;
if(random() < 0.01) actor.bot_primary_fireballmooth = 1;
METHOD(Hagar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(random()>0.15)
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false, true);
else // not using secondary_speed since these are only 15% and should cause some ricochets without re-aiming
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false, true);
}
METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
METHOD(HLAC, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false, true);
}
METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
METHOD(MachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true);
else
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true);
}
METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
if(minecount >= WEP_CVAR(minelayer, limit))
PHYS_INPUT_BUTTON_ATCK(actor) = false;
else
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(minelayer, speed), 0, WEP_CVAR(minelayer, lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(minelayer, speed), 0, WEP_CVAR(minelayer, lifetime), false, false);
if(skill >= 2) // skill 0 and 1 bots won't detonate mines!
{
// decide whether to detonate mines
PHYS_INPUT_BUTTON_ATCK2(actor) = false;
if(actor.bot_secondary_grenademooth == 0) // WEAPONTODO: merge this into using WEP_CVAR_BOTH
{
- if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(mortar, speed), WEP_CVAR_PRI(mortar, speed_up), WEP_CVAR_PRI(mortar, lifetime), true))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(mortar, speed), WEP_CVAR_PRI(mortar, speed_up), WEP_CVAR_PRI(mortar, lifetime), true, true))
{
PHYS_INPUT_BUTTON_ATCK(actor) = true;
if(random() < 0.01) actor.bot_secondary_grenademooth = 1;
}
else
{
- if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(mortar, speed), WEP_CVAR_SEC(mortar, speed_up), WEP_CVAR_SEC(mortar, lifetime), true))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_SEC(mortar, speed), WEP_CVAR_SEC(mortar, speed_up), WEP_CVAR_SEC(mortar, lifetime), true, true))
{
PHYS_INPUT_BUTTON_ATCK2(actor) = true;
if(random() < 0.02) actor.bot_secondary_grenademooth = 0;
PHYS_INPUT_BUTTON_ATCK(actor) = false;
PHYS_INPUT_BUTTON_ATCK2(actor) = false;
if(!WEP_CVAR(porto, secondary))
- if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(porto, speed), 0, WEP_CVAR_PRI(porto, lifetime), false))
+ if(bot_aim(actor, weaponentity, WEP_CVAR_PRI(porto, speed), 0, WEP_CVAR_PRI(porto, lifetime), false, true))
PHYS_INPUT_BUTTON_ATCK(actor) = true;
}
METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
actor.bot_secondary_riflemooth = 0;
if(actor.bot_secondary_riflemooth == 0)
{
- if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false))
+ if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true))
{
PHYS_INPUT_BUTTON_ATCK(actor) = true;
if(random() < 0.01) actor.bot_secondary_riflemooth = 1;
}
else
{
- if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false))
+ if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true))
{
PHYS_INPUT_BUTTON_ATCK2(actor) = true;
if(random() < 0.03) actor.bot_secondary_riflemooth = 0;
if(WEP_CVAR(seeker, type) == 1)
{
if(W_Seeker_Tagged_Info(actor, weaponentity, actor.enemy) != NULL)
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, missile_speed_max), 0, WEP_CVAR(seeker, missile_lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, missile_speed_max), 0, WEP_CVAR(seeker, missile_lifetime), false, false);
else
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false, false);
}
else
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false, true);
}
METHOD(Seeker, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(vdist(actor.origin - actor.enemy.origin, <=, WEP_CVAR(shockwave, melee_range)))
- { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); }
+ { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false); }
else
- { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false); }
+ { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false); }
}
METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(vdist(actor.origin - actor.enemy.origin, <=, WEP_CVAR_SEC(shotgun, melee_range)))
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false);
else
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, false);
}
METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
METHOD(Vaporizer, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if((actor.items & IT_UNLIMITED_AMMO) || GetResource(actor, thiswep.ammo_type) > 0)
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 1, false);
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 1, false, true);
else
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false, true); // WEAPONTODO: replace with proper vaporizer cvars
}
METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
METHOD(Vortex, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
- if(bot_aim(actor, weaponentity, 1000000, 0, 1, false))
+ if(bot_aim(actor, weaponentity, 1000000, 0, 1, false, true))
PHYS_INPUT_BUTTON_ATCK(actor) = true;
else
{
.int wpflags;
.entity wphw00, wphw01, wphw02, wphw03, wphw04, wphw05, wphw06, wphw07;
-bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity);
+bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate);
void bot_aim_reset(entity this);
void bot_clientconnect(entity this);
void bot_clientdisconnect(entity this);
return targorigin + targvelocity * (shotdelay + vlen(targorigin - shotorg) / shotspeed);
}
-bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity)
+bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity, bool shot_accurate)
{
- float r, hf, distanceratio;
+ float hf, distanceratio;
vector v;
hf = this.dphitcontentsmask;
this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
shotorg = this.origin + this.view_ofs;
shotdir = v_forward;
v = bot_shotlead(this.bot_aimtargorigin, this.bot_aimtargvelocity, shotspeed, this.bot_aimlatency);
+
distanceratio = sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/autocvar_bot_ai_aimskill_firetolerance_distdegrees;
distanceratio = bound(0,distanceratio,1);
- r = (autocvar_bot_ai_aimskill_firetolerance_maxdegrees-autocvar_bot_ai_aimskill_firetolerance_mindegrees)
- * (1-distanceratio) + autocvar_bot_ai_aimskill_firetolerance_mindegrees;
+ float mindegrees = autocvar_bot_ai_aimskill_firetolerance_mindegrees;
+ float diffdegrees = autocvar_bot_ai_aimskill_firetolerance_maxdegrees - mindegrees;
+ if (!shot_accurate) // this shot doesn't require too much accuracy
+ mindegrees += diffdegrees * 0.25;
+ else // less skilled bots shoot even if they aren't aiming accurately
+ mindegrees += (random() > 0.3) ? 0 : diffdegrees * 0.25 * (1 - bound(0, skill / 10, 1));
+ diffdegrees = autocvar_bot_ai_aimskill_firetolerance_maxdegrees - mindegrees;
+ float maxfiredeviation = diffdegrees * (1 - distanceratio) + mindegrees;
+
if (applygravity && this.bot_aimtarg)
{
if (!findtrajectorywithleading(shotorg, '0 0 0', '0 0 0', this.bot_aimtarg, shotspeed, shotspeedupward, maxshottime, 0, this))
return false;
}
- bot_aimdir(this, findtrajectory_velocity - shotspeedupward * '0 0 1', r);
+ bot_aimdir(this, findtrajectory_velocity - shotspeedupward * '0 0 1', maxfiredeviation);
}
else
{
- bot_aimdir(this, v - shotorg, r);
+ bot_aimdir(this, v - shotorg, maxfiredeviation);
//dprint("AIM: ");dprint(vtos(this.bot_aimtargorigin));dprint(" + ");dprint(vtos(this.bot_aimtargvelocity));dprint(" * ");dprint(ftos(this.bot_aimlatency + vlen(this.bot_aimtargorigin - shotorg) / shotspeed));dprint(" = ");dprint(vtos(v));dprint(" : aimdir = ");dprint(vtos(normalize(v - shotorg)));dprint(" : ");dprint(vtos(shotdir));dprint("\n");
//traceline(shotorg, shotorg + shotdir * 10000, false, this);
//if (trace_ent.takedamage)
float bot_shouldattack(entity this, entity targ);
void bot_aimdir(entity this, vector v, float maxfiredeviation);
-bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity);
+bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, bool applygravity, bool shot_accurate);
void bot_aim_reset(entity this);
float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore);
#include "bot_null.qh"
#if 0
-bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity) { return false; }
+bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate) { return false; }
void bot_clientconnect(entity this) { }
void bot_clientdisconnect(entity this) { }
void bot_cmdhelp(string scmd) { }
set bot_ai_dangerdetectionupdates 64 "How many waypoints will be considered for danger detection"
set bot_ai_aimskill_blendrate 2 "How much correction will be applied to the aiming angle"
set bot_ai_aimskill_fixedrate 15 "Distance based scale from which correction will be applied to the aiming angle"
-set bot_ai_aimskill_firetolerance 0 "enable fire tolerance"
+set bot_ai_aimskill_firetolerance 1 "enable fire tolerance"
set bot_ai_aimskill_firetolerance_distdegrees 100 "Rate at which the aiming angle is updated, scales by skill"
set bot_ai_aimskill_firetolerance_mindegrees 2 "Minimum angle tolerance. Used on large distances"
set bot_ai_aimskill_firetolerance_maxdegrees 60 "Maximum firing angle. Used on close range"