From: terencehill Date: Sat, 20 Aug 2022 16:28:52 +0000 (+0200) Subject: Bot AI: improve bots aim by requiring they aim at the target (with some tolerance... X-Git-Tag: xonotic-v0.8.6~322^2~12 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=ee2f4178f1709cbf38b2e865c6c96a7d177bbebf;p=xonotic%2Fxonotic-data.pk3dir.git Bot AI: improve bots aim by requiring they aim at the target (with some tolerance) before starting to shoot (bot_ai_aimskill_firetolerance is now enabled by default). It fixes bots often missing the first shot right when they get a new target if they were aiming in a different direction 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 --- diff --git a/qcsrc/common/mutators/mutator/overkill/okhmg.qc b/qcsrc/common/mutators/mutator/overkill/okhmg.qc index 6bfafed67..d5a2ba2e3 100644 --- a/qcsrc/common/mutators/mutator/overkill/okhmg.qc +++ b/qcsrc/common/mutators/mutator/overkill/okhmg.qc @@ -55,7 +55,7 @@ void W_OverkillHeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity 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)) diff --git a/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc b/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc index 597d17e2e..20db8d961 100644 --- a/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc +++ b/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc @@ -49,7 +49,7 @@ void W_OverkillMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weap 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)) diff --git a/qcsrc/common/mutators/mutator/overkill/oknex.qc b/qcsrc/common/mutators/mutator/overkill/oknex.qc index aefc72346..4e001a65c 100644 --- a/qcsrc/common/mutators/mutator/overkill/oknex.qc +++ b/qcsrc/common/mutators/mutator/overkill/oknex.qc @@ -117,7 +117,7 @@ void W_OverkillNex_Attack(Weapon thiswep, entity actor, .entity weaponentity, fl 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 { diff --git a/qcsrc/common/mutators/mutator/overkill/okrpc.qc b/qcsrc/common/mutators/mutator/overkill/okrpc.qc index ea700a9ca..4610a0b1d 100644 --- a/qcsrc/common/mutators/mutator/overkill/okrpc.qc +++ b/qcsrc/common/mutators/mutator/overkill/okrpc.qc @@ -130,7 +130,7 @@ void W_OverkillRocketPropelledChainsaw_Attack(Weapon thiswep, entity actor, .ent 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)) diff --git a/qcsrc/common/mutators/mutator/overkill/okshotgun.qc b/qcsrc/common/mutators/mutator/overkill/okshotgun.qc index 627c14f20..6b4b3aa8e 100644 --- a/qcsrc/common/mutators/mutator/overkill/okshotgun.qc +++ b/qcsrc/common/mutators/mutator/overkill/okshotgun.qc @@ -5,11 +5,11 @@ METHOD(OverkillShotgun, wr_aim, void(entity thiswep, entity actor, .entity weapo { 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); } } diff --git a/qcsrc/common/weapons/weapon/arc.qc b/qcsrc/common/weapons/weapon/arc.qc index 981130cae..aa1a637c9 100644 --- a/qcsrc/common/weapons/weapon/arc.qc +++ b/qcsrc/common/weapons/weapon/arc.qc @@ -611,7 +611,7 @@ METHOD(Arc, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) WEP_CVAR(arc, beam_botaimspeed), 0, WEP_CVAR(arc, beam_botaimlifetime), - false + false, true ); } else @@ -622,7 +622,7 @@ METHOD(Arc, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) 1000000, 0, 0.001, - false + false, true ); } } diff --git a/qcsrc/common/weapons/weapon/blaster.qc b/qcsrc/common/weapons/weapon/blaster.qc index e0fd2282b..6902f4853 100644 --- a/qcsrc/common/weapons/weapon/blaster.qc +++ b/qcsrc/common/weapons/weapon/blaster.qc @@ -112,12 +112,12 @@ METHOD(Blaster, wr_aim, void(entity thiswep, entity actor, .entity weaponentity) 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)) diff --git a/qcsrc/common/weapons/weapon/crylink.qc b/qcsrc/common/weapons/weapon/crylink.qc index 5458a2496..86dd8fc92 100644 --- a/qcsrc/common/weapons/weapon/crylink.qc +++ b/qcsrc/common/weapons/weapon/crylink.qc @@ -522,9 +522,9 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity) 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)) { diff --git a/qcsrc/common/weapons/weapon/devastator.qc b/qcsrc/common/weapons/weapon/devastator.qc index 089002714..cff2398a6 100644 --- a/qcsrc/common/weapons/weapon/devastator.qc +++ b/qcsrc/common/weapons/weapon/devastator.qc @@ -380,7 +380,9 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponenti // 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! { diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc index 3a70920e0..e122077b3 100644 --- a/qcsrc/common/weapons/weapon/electro.qc +++ b/qcsrc/common/weapons/weapon/electro.qc @@ -509,9 +509,9 @@ METHOD(Electro, wr_aim, void(entity thiswep, entity actor, .entity weaponentity) 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) { @@ -521,7 +521,7 @@ METHOD(Electro, wr_aim, void(entity thiswep, entity actor, .entity weaponentity) } 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; diff --git a/qcsrc/common/weapons/weapon/fireball.qc b/qcsrc/common/weapons/weapon/fireball.qc index b4a3da78a..391aa7294 100644 --- a/qcsrc/common/weapons/weapon/fireball.qc +++ b/qcsrc/common/weapons/weapon/fireball.qc @@ -342,7 +342,7 @@ METHOD(Fireball, wr_aim, void(entity thiswep, entity actor, .entity weaponentity 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; @@ -350,7 +350,7 @@ METHOD(Fireball, wr_aim, void(entity thiswep, entity actor, .entity weaponentity } 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; diff --git a/qcsrc/common/weapons/weapon/hagar.qc b/qcsrc/common/weapons/weapon/hagar.qc index bfda2124d..82f75f363 100644 --- a/qcsrc/common/weapons/weapon/hagar.qc +++ b/qcsrc/common/weapons/weapon/hagar.qc @@ -387,9 +387,9 @@ void W_Hagar_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int 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)) { diff --git a/qcsrc/common/weapons/weapon/hlac.qc b/qcsrc/common/weapons/weapon/hlac.qc index d89cdb128..e4db316af 100644 --- a/qcsrc/common/weapons/weapon/hlac.qc +++ b/qcsrc/common/weapons/weapon/hlac.qc @@ -153,7 +153,7 @@ void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int 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)) { diff --git a/qcsrc/common/weapons/weapon/machinegun.qc b/qcsrc/common/weapons/weapon/machinegun.qc index 684ae22bc..15a4d6a3c 100644 --- a/qcsrc/common/weapons/weapon/machinegun.qc +++ b/qcsrc/common/weapons/weapon/machinegun.qc @@ -138,9 +138,9 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentit 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)) { diff --git a/qcsrc/common/weapons/weapon/minelayer.qc b/qcsrc/common/weapons/weapon/minelayer.qc index 8a8d4839c..9ab5533f1 100644 --- a/qcsrc/common/weapons/weapon/minelayer.qc +++ b/qcsrc/common/weapons/weapon/minelayer.qc @@ -346,7 +346,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentit 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 diff --git a/qcsrc/common/weapons/weapon/mortar.qc b/qcsrc/common/weapons/weapon/mortar.qc index 6f37469f0..a1264748f 100644 --- a/qcsrc/common/weapons/weapon/mortar.qc +++ b/qcsrc/common/weapons/weapon/mortar.qc @@ -256,7 +256,7 @@ METHOD(Mortar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) 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; @@ -264,7 +264,7 @@ METHOD(Mortar, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) } 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; diff --git a/qcsrc/common/weapons/weapon/porto.qc b/qcsrc/common/weapons/weapon/porto.qc index b161d1054..7ee416215 100644 --- a/qcsrc/common/weapons/weapon/porto.qc +++ b/qcsrc/common/weapons/weapon/porto.qc @@ -338,7 +338,7 @@ METHOD(PortoLaunch, wr_aim, void(entity thiswep, entity actor, .entity weaponent 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)) diff --git a/qcsrc/common/weapons/weapon/rifle.qc b/qcsrc/common/weapons/weapon/rifle.qc index 3efa61102..803930cc0 100644 --- a/qcsrc/common/weapons/weapon/rifle.qc +++ b/qcsrc/common/weapons/weapon/rifle.qc @@ -94,7 +94,7 @@ METHOD(Rifle, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) 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; @@ -102,7 +102,7 @@ METHOD(Rifle, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) } 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; diff --git a/qcsrc/common/weapons/weapon/seeker.qc b/qcsrc/common/weapons/weapon/seeker.qc index cdf7d6a2e..5dd62fa51 100644 --- a/qcsrc/common/weapons/weapon/seeker.qc +++ b/qcsrc/common/weapons/weapon/seeker.qc @@ -533,12 +533,12 @@ METHOD(Seeker, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)) 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)) { diff --git a/qcsrc/common/weapons/weapon/shockwave.qc b/qcsrc/common/weapons/weapon/shockwave.qc index 2429a3017..7863de55e 100644 --- a/qcsrc/common/weapons/weapon/shockwave.qc +++ b/qcsrc/common/weapons/weapon/shockwave.qc @@ -587,9 +587,9 @@ void W_Shockwave_Attack(Weapon thiswep, entity actor, .entity weaponentity) 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)) { diff --git a/qcsrc/common/weapons/weapon/shotgun.qc b/qcsrc/common/weapons/weapon/shotgun.qc index bc1ce8947..4b4a11e8e 100644 --- a/qcsrc/common/weapons/weapon/shotgun.qc +++ b/qcsrc/common/weapons/weapon/shotgun.qc @@ -196,9 +196,9 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity 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)) diff --git a/qcsrc/common/weapons/weapon/vaporizer.qc b/qcsrc/common/weapons/weapon/vaporizer.qc index 09d8ef36b..25aa1b665 100644 --- a/qcsrc/common/weapons/weapon/vaporizer.qc +++ b/qcsrc/common/weapons/weapon/vaporizer.qc @@ -245,9 +245,9 @@ void W_RocketMinsta_Attack(entity actor, .entity weaponentity, int mode) 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)) { diff --git a/qcsrc/common/weapons/weapon/vortex.qc b/qcsrc/common/weapons/weapon/vortex.qc index 5ba28f9c7..f92af9fae 100644 --- a/qcsrc/common/weapons/weapon/vortex.qc +++ b/qcsrc/common/weapons/weapon/vortex.qc @@ -169,7 +169,7 @@ void W_Vortex_Charge(entity actor, .entity weaponentity, float dt) 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 { diff --git a/qcsrc/server/bot/api.qh b/qcsrc/server/bot/api.qh index 65ab46bad..db1cb939b 100644 --- a/qcsrc/server/bot/api.qh +++ b/qcsrc/server/bot/api.qh @@ -64,7 +64,7 @@ float skill; .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); diff --git a/qcsrc/server/bot/default/aim.qc b/qcsrc/server/bot/default/aim.qc index a58ec6134..024db9237 100644 --- a/qcsrc/server/bot/default/aim.qc +++ b/qcsrc/server/bot/default/aim.qc @@ -352,9 +352,9 @@ vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, flo 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; @@ -376,10 +376,18 @@ bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeed 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)) @@ -388,11 +396,11 @@ bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeed 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) diff --git a/qcsrc/server/bot/default/aim.qh b/qcsrc/server/bot/default/aim.qh index 2a3145176..b03e77a9b 100644 --- a/qcsrc/server/bot/default/aim.qh +++ b/qcsrc/server/bot/default/aim.qh @@ -92,7 +92,7 @@ void bot_lagfunc(entity this, float t, float f1, float f2, entity e1, vector v1, 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); diff --git a/qcsrc/server/bot/null/bot_null.qc b/qcsrc/server/bot/null/bot_null.qc index a27e00c42..f820848ad 100644 --- a/qcsrc/server/bot/null/bot_null.qc +++ b/qcsrc/server/bot/null/bot_null.qc @@ -1,7 +1,7 @@ #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) { } diff --git a/xonotic-server.cfg b/xonotic-server.cfg index 859314980..f4ef72241 100644 --- a/xonotic-server.cfg +++ b/xonotic-server.cfg @@ -138,7 +138,7 @@ set bot_ai_dangerdetectioninterval 0.25 "How often scan for waypoints with dange 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"