Bump version 2.0.1

This commit is contained in:
ineedbots 2021-05-14 20:25:06 -06:00
parent 30285b8fc9
commit d23fb6cd60
11 changed files with 818 additions and 332 deletions

View File

@ -161,6 +161,22 @@ You can easily setup a local LAN dedicated server for you to join and play on. H
- bots_main_debug - a boolean value (0 or 1), enables or disables the waypoint editor
## Changelog
- v2.0.1
- Reduced bots crouching
- Increased bots sprinting
- Improved bots mantling, crouching and knifing glass when needed
- Fixed possible script runtime errors
- Improved domination
- Bots use explosives more if they have it
- Bots aim slower when ads'ing
- Fixed bots holding breath
- Fixed bots rubberbanding movement when their goal changes
- Added bots quickscoping with snipers
- Added bots reload canceling and fast swaps
- Bots use C4
- Improved revenge
- Bots can swap weapons on spawn more likely
- v2.0.0
- Initial reboot release

@ -1 +1 @@
Subproject commit bfdf1b98f54f71bdc6651834d7555ce539f7f40f
Subproject commit 55d419cdb20b2bf89a883b1b59d79df1ed8381ac

View File

@ -8,7 +8,7 @@
*/
init()
{
level.bw_VERSION = "2.0.0";
level.bw_VERSION = "2.0.1";
if(getDvar("bots_main") == "")
setDvar("bots_main", true);

View File

@ -8,7 +8,7 @@
*/
init()
{
level.bw_VERSION = "2.0.0";
level.bw_VERSION = "2.0.1";
if(getDvar("bots_main") == "")
setDvar("bots_main", true);

View File

@ -32,6 +32,8 @@ added()
self.pers["bots"]["skill"]["aim_offset_amount"] = 1; // how far a bot's incorrect aim is
self.pers["bots"]["skill"]["bone_update_interval"] = 0.05; // how often a bot changes their bone target
self.pers["bots"]["skill"]["bones"] = "j_head"; // a list of comma seperated bones the bot will aim at
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; // a factor of how much ads to reduce when adsing
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; // a factor of how much more aimspeed delay to add
self.pers["bots"]["behavior"] = [];
self.pers["bots"]["behavior"]["strafe"] = 50; // percentage of how often the bot strafes a target
@ -43,6 +45,9 @@ added()
self.pers["bots"]["behavior"]["switch"] = 1; // percentage of how often the bot will switch weapons
self.pers["bots"]["behavior"]["class"] = 1; // percentage of how often the bot will change classes
self.pers["bots"]["behavior"]["jump"] = 100; // percentage of how often the bot will jumpshot and dropshot
self.pers["bots"]["behavior"]["quickscope"] = false; // is a quickscoper
self.pers["bots"]["behavior"]["initswitch"] = 10; // percentage of how often the bot will switch weapons on spawn
}
/*
@ -131,6 +136,8 @@ resetBotVars()
self.bot.stop_move = false;
self.bot.greedy_path = false;
self.bot.climbing = false;
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self.bot.isfrozen = false;
self.bot.sprintendtime = -1;
@ -145,8 +152,11 @@ resetBotVars()
self.bot.semi_time = false;
self.bot.jump_time = undefined;
self.bot.last_fire_time = -1;
self.bot.is_cur_full_auto = false;
self.bot.cur_weap_dist_multi = 1;
self.bot.is_cur_sniper = false;
self.bot.rand = randomInt(100);
@ -213,10 +223,162 @@ spawned()
self thread aim();
self thread watchHoldBreath();
self thread onNewEnemy();
self thread doBotMovement();
self thread watchGrenadeFire();
self notify("bot_spawned");
}
/*
Watches when the bot fires a grenade
*/
watchGrenadeFire()
{
self endon("disconnect");
self endon("death");
for (;;)
{
self waittill( "grenade_fire", nade, weapname );
if ( weapname == "c4_mp" )
self thread watchC4Thrown(nade);
}
}
/*
Watches the c4
*/
watchC4Thrown(c4)
{
self endon("disconnect");
c4 endon("death");
wait 0.5;
for (;;)
{
wait 1 + randomInt(50) * 0.05;
shouldBreak = false;
for (i = 0; i < level.players.size; i++)
{
player = level.players[i];
if(player == self)
continue;
if((level.teamBased && self.team == player.team) || player.sessionstate != "playing" || !isAlive(player))
continue;
if (distanceSquared(c4.origin, player.origin) > 200*200)
continue;
if (!bulletTracePassed(c4.origin, player.origin + (0, 0, 25), false, c4))
continue;
shouldBreak = true;
}
if (shouldBreak)
break;
}
weap = self getCurrentWeapon();
if ( weap != "c4_mp" )
self notify( "alt_detonate" );
else
self thread pressFire();
}
/*
Bot moves towards the point
*/
doBotMovement()
{
self endon("disconnect");
self endon("death");
FORWARDAMOUNT = 25;
for (i = 0;;i+=0.05)
{
wait 0.05;
angles = self GetPlayerAngles();
// climb through windows
if (self isMantling())
self crouch();
startPos = self.origin + (0, 0, 50);
startPosForward = startPos + anglesToForward((0, angles[1], 0)) * FORWARDAMOUNT;
bt = bulletTrace(startPos, startPosForward, false, self);
if (bt["fraction"] >= 1)
{
// check if need to jump
bt = bulletTrace(startPosForward, startPosForward - (0, 0, 40), false, self);
if (bt["fraction"] < 1 && bt["normal"][2] > 0.9 && i > 1.5 && !self isOnLadder())
{
i = 0;
self thread jump();
}
}
// check if need to knife glass
else if (bt["surfacetype"] == "glass")
{
if (i > 1.5)
{
i = 0;
self thread knife();
}
}
else
{
// check if need to crouch
if (bulletTracePassed(startPos - (0, 0, 25), startPosForward - (0, 0, 25), false, self))
self crouch();
}
}
}
/*
Sets the factor of distance for a weapon
*/
SetWeaponDistMulti(weap)
{
if (weap == "none")
return 1;
switch(weaponClass(weap))
{
case "rifle":
return 0.9;
case "smg":
return 0.7;
case "pistol":
return 0.5;
default:
return 1;
}
}
/*
Is the weap a sniper
*/
IsWeapSniper(weap)
{
if (weap == "none")
return false;
if (maps\mp\gametypes\_missions::getWeaponClass(weap) != "weapon_sniper")
return false;
return true;
}
/*
The hold breath thread.
*/
@ -232,7 +394,7 @@ watchHoldBreath()
if(self.bot.isfrozen)
continue;
self holdbreath((self playerADS() && weaponClass(self getCurrentWEapon()) == "rifle"));
self holdbreath(self playerADS() > 0);
}
}
@ -277,21 +439,24 @@ onWeaponChange()
self endon("disconnect");
self endon("death");
weap = self GetCurrentWeapon();
self.bot.is_cur_full_auto = WeaponIsFullAuto(weap);
if (weap != "none")
self changeToWeap(weap);
first = true;
for(;;)
{
newWeapon = undefined;
if (first)
{
first = false;
newWeapon = self getCurrentWeapon();
}
else
self waittill( "weapon_change", newWeapon );
self.bot.is_cur_full_auto = WeaponIsFullAuto(newWeapon);
self.bot.cur_weap_dist_multi = SetWeaponDistMulti(newWeapon);
self.bot.is_cur_sniper = IsWeapSniper(newWeapon);
if (newWeapon == "none")
{
continue;
}
self changeToWeap(newWeapon);
}
@ -327,7 +492,18 @@ reload_watch()
{
self waittill("reload_start");
self.bot.isreloading = true;
self waittill_notify_or_timeout("reload", 7.5);
while(true)
{
ret = self waittill_any_timeout(7.5, "reload");
if (ret == "timeout")
break;
weap = self GetCurrentWeapon();
if (self GetWeaponAmmoClip(weap) >= WeaponClipSize(weap))
break;
}
self.bot.isreloading = false;
}
}
@ -376,17 +552,25 @@ stance()
self prone();
curweap = self getCurrentWeapon();
time = getTime();
chance = self.pers["bots"]["behavior"]["sprint"];
if (time - self.lastSpawnTime < 5000)
chance *= 2;
if(isDefined(self.bot.script_goal) && DistanceSquared(self.origin, self.bot.script_goal) > 256*256)
chance *= 2;
if(toStance != "stand" || self.bot.isreloading || self.bot.issprinting || self.bot.isfraggingafter || self.bot.issmokingafter)
continue;
if(randomInt(100) > self.pers["bots"]["behavior"]["sprint"])
if(randomInt(100) > chance)
continue;
if(isDefined(self.bot.target) && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap))
continue;
if(self.bot.sprintendtime != -1 && getTime() - self.bot.sprintendtime < 2000)
if(self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000)
continue;
if(!isDefined(self.bot.towards_goal) || DistanceSquared(self.origin, self.bot.towards_goal) < level.bots_minSprintDistance || getConeDot(self.bot.towards_goal, self.origin, self GetPlayerAngles()) < 0.75)
@ -582,9 +766,11 @@ updateAimOffset(obj)
targetObjUpdateTraced(obj, daDist, ent, theTime, isScriptObj)
{
distClose = self.pers["bots"]["skill"]["dist_start"];
distClose *= self.bot.cur_weap_dist_multi;
distClose *= distClose;
distMax = self.pers["bots"]["skill"]["dist_max"];
distMax *= self.bot.cur_weap_dist_multi;
distMax *= distMax;
timeMulti = 1;
@ -635,13 +821,18 @@ target()
myAngles = self GetPlayerAngles();
myFov = self.pers["bots"]["skill"]["fov"];
bestTargets = [];
bestTime = 9999999999;
bestTime = 2147483647;
rememberTime = self.pers["bots"]["skill"]["remember_time"];
initReactTime = self.pers["bots"]["skill"]["init_react_time"];
hasTarget = isDefined(self.bot.target);
adsAmount = self PlayerADS();
adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"];
// reduce fov if ads'ing
myFov *= 1 - 0.5 * self PlayerADS();
if (adsAmount > 0)
{
myFov *= 1 - adsFovFact * adsAmount;
}
if(hasTarget && !isDefined(self.bot.target.entity))
{
@ -782,7 +973,7 @@ target()
if(hasTarget && isDefined(bestTargets[self.bot.target.entity getEntityNumber()+""]))
continue;
closest = 9999999999;
closest = 2147483647;
toBeTarget = undefined;
bestKeys = getArrayKeys(bestTargets);
@ -874,6 +1065,9 @@ watchToLook()
if(!self isInRange(self.bot.target.dist, curweap))
continue;
if (self.bot.is_cur_sniper)
continue;
if(randomInt(100) > self.pers["bots"]["behavior"]["jump"])
continue;
@ -958,6 +1152,14 @@ aim()
eyePos = self getEyePos();
curweap = self getCurrentWeapon();
angles = self GetPlayerAngles();
adsAmount = self PlayerADS();
adsAimSpeedFact = self.pers["bots"]["skill"]["ads_aimspeed_multi"];
// reduce aimspeed if ads'ing
if (adsAmount > 0)
{
aimspeed *= 1 + adsAimSpeedFact * adsAmount;
}
if(isDefined(self.bot.target) && isDefined(self.bot.target.entity))
{
@ -1020,7 +1222,10 @@ aim()
else
{
if (self canAds(dist, curweap))
self thread pressADS();
{
if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"])
self thread pressAds();
}
}
self botLookAt(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed);
@ -1031,7 +1236,14 @@ aim()
{
if(isplay)
{
if (!target IsPlayerModelOK())
continue;
aimpos = target getTagOrigin( bone );
if (!isDefined(aimpos))
continue;
aimpos += offset;
aimpos += aimoffset;
aimpos += (0, 0, nadeAimOffset);
@ -1065,15 +1277,25 @@ aim()
if(!self canFire(curweap) || !self isInRange(dist, curweap))
continue;
//c4 logic here, but doesnt work anyway
canADS = self canAds(dist, curweap);
canADS = (self canAds(dist, curweap) && conedot > 0.75);
if (canADS)
self thread pressADS();
{
stopAdsOverride = false;
if (self.bot.is_cur_sniper)
{
if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000)
stopAdsOverride = true;
else
self notify("kill_goal");
}
if (!stopAdsOverride)
self thread pressAds();
}
if (trace_time > reaction_time)
{
if((!canADS || self playerads() == 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.95 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire"))
if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.99 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire"))
self botFire();
if (isplay)
@ -1104,11 +1326,23 @@ aim()
if(!self canFire(curweap) || !self isInRange(dist, curweap))
continue;
canADS = self canAds(dist, curweap);
canADS = (self canAds(dist, curweap) && conedot > 0.75);
if (canADS)
self thread pressADS();
{
stopAdsOverride = false;
if (self.bot.is_cur_sniper)
{
if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000)
stopAdsOverride = true;
else
self notify("kill_goal");
}
if((!canADS || self playerads() == 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.95 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire"))
if (!stopAdsOverride)
self thread pressAds();
}
if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.95 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire"))
self botFire();
continue;
@ -1144,6 +1378,8 @@ aim()
*/
botFire()
{
self.bot.last_fire_time = getTime();
if(self.bot.is_cur_full_auto)
{
self thread pressFire();
@ -1258,6 +1494,8 @@ walk()
if(self maps\mp\_flashgrenades::isFlashbanged())
{
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self botMoveTo(self.origin + self GetVelocity()*500);
continue;
}
@ -1274,7 +1512,7 @@ walk()
if(self.bot.target.isplay && self.bot.target.trace_time && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap))
{
if (self InLastStand() || self GetStance() == "prone")
if (self InLastStand() || self GetStance() == "prone" || (self.bot.is_cur_sniper && self PlayerADS() > 0))
continue;
if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"])
@ -1370,6 +1608,8 @@ strafe(target)
if(traceRight["fraction"] > traceLeft["fraction"])
strafe = traceRight["position"];
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self botMoveTo(strafe);
wait 2;
self notify("kill_goal");
@ -1481,39 +1721,34 @@ doWalk(goal, dist, isScriptGoal)
self thread watchOnGoal(goal, distsq);
current = self initAStar(goal);
// if a waypoint is closer than the goal
//if (current >= 0 && DistanceSquared(self.origin, level.waypoints[self.bot.astar[current]].origin) < DistanceSquared(self.origin, goal))
//{
// skip waypoints we already completed to prevent rubber banding
if (current > 0 && self.bot.astar[current] == self.bot.last_next_wp && self.bot.astar[current-1] == self.bot.last_second_next_wp)
current = self removeAStar();
if (current >= 0)
{
// check if a waypoint is closer than the goal
wpOrg = level.waypoints[self.bot.astar[current]].origin;
ppt = PlayerPhysicsTrace(self.origin + (0,0,32), wpOrg, false, self);
if (DistanceSquared(self.origin, wpOrg) < DistanceSquared(self.origin, goal) || DistanceSquared(wpOrg, ppt) > 1.0)
{
while(current >= 0)
{
// skip down the line of waypoints and go to the waypoint we have a direct path too
/*for (;;)
{
if (current <= 0)
break;
ppt = PlayerPhysicsTrace(self.origin + (0,0,32), level.waypoints[self.bot.astar[current-1]].origin, false, self);
if (DistanceSquared(level.waypoints[self.bot.astar[current-1]].origin, ppt) > 1.0)
break;
if (level.waypoints[self.bot.astar[current-1]].type == "climb" || level.waypoints[self.bot.astar[current]].type == "climb")
break;
current = self removeAStar();
}*/
self.bot.next_wp = self.bot.astar[current];
self.bot.second_next_wp = -1;
if(current != 0)
if(current > 0)
self.bot.second_next_wp = self.bot.astar[current-1];
self notify("new_static_waypoint");
self movetowards(level.waypoints[self.bot.next_wp].origin);
self.bot.last_next_wp = self.bot.next_wp;
self.bot.last_second_next_wp = self.bot.second_next_wp;
current = self removeAStar();
}
//}
}
}
self.bot.next_wp = -1;
self.bot.second_next_wp = -1;
@ -1521,6 +1756,8 @@ doWalk(goal, dist, isScriptGoal)
if(DistanceSquared(self.origin, goal) > distsq)
{
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self movetowards(goal); // any better way??
}
@ -1549,17 +1786,18 @@ movetowards(goal)
{
self botMoveTo(goal);
if(time > 3)
if(time > 3.5)
{
time = 0;
if(distanceSquared(self.origin, lastOri) < 128)
{
self thread knife();
wait 0.5;
stucks++;
randomDir = self getRandomLargestStafe(stucks);
self knife(); // knife glass
wait 0.25;
self botMoveTo(randomDir);
wait stucks;
}
@ -1568,7 +1806,7 @@ movetowards(goal)
}
else if(timeslow > 1.5)
{
self thread jump();
self thread doMantle();
}
else if(timeslow > 0.75)
{
@ -1590,6 +1828,22 @@ movetowards(goal)
self notify("completed_move_to");
}
/*
Bots do the mantle
*/
doMantle()
{
self endon("disconnect");
self endon("death");
self endon("kill_goal");
self jump();
wait 0.35;
self jump();
}
/*
Will return the pos of the largest trace from the bot.
*/

View File

@ -28,6 +28,7 @@ connected()
self endon("disconnect");
self.killerLocation = undefined;
self.lastKiller = undefined;
self thread difficulty();
self thread teamWatch();
@ -44,6 +45,7 @@ connected()
onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration)
{
self.killerLocation = undefined;
self.lastKiller = undefined;
if(!IsDefined( self ) || !isDefined(self.team))
return;
@ -70,6 +72,7 @@ onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc,
return;
self.killerLocation = eAttacker.origin;
self.lastKiller = eAttacker;
}
/*
@ -260,13 +263,10 @@ difficulty()
for(;;)
{
wait 1;
rankVar = GetDvarInt("bots_skill");
if(rankVar == 9)
continue;
if(rankVar != 9)
{
switch(self.pers["bots"]["skill"]["base"])
{
case 1:
@ -287,13 +287,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 4;
self.pers["bots"]["skill"]["bone_update_interval"] = 2;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_ankle_le,j_ankle_ri";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 0;
self.pers["bots"]["behavior"]["nade"] = 10;
self.pers["bots"]["behavior"]["sprint"] = 10;
self.pers["bots"]["behavior"]["sprint"] = 30;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 70;
self.pers["bots"]["behavior"]["crouch"] = 20;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 0;
@ -316,13 +318,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 3;
self.pers["bots"]["skill"]["bone_update_interval"] = 1.5;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_ankle_le,j_ankle_ri,j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 10;
self.pers["bots"]["behavior"]["nade"] = 15;
self.pers["bots"]["behavior"]["sprint"] = 15;
self.pers["bots"]["behavior"]["sprint"] = 45;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 60;
self.pers["bots"]["behavior"]["crouch"] = 15;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 10;
@ -345,13 +349,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 2.5;
self.pers["bots"]["skill"]["bone_update_interval"] = 1;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 20;
self.pers["bots"]["behavior"]["nade"] = 20;
self.pers["bots"]["behavior"]["sprint"] = 20;
self.pers["bots"]["behavior"]["sprint"] = 50;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 50;
self.pers["bots"]["behavior"]["crouch"] = 10;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 25;
@ -374,13 +380,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 2;
self.pers["bots"]["skill"]["bone_update_interval"] = 0.75;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head,j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 30;
self.pers["bots"]["behavior"]["nade"] = 25;
self.pers["bots"]["behavior"]["sprint"] = 30;
self.pers["bots"]["behavior"]["sprint"] = 55;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 40;
self.pers["bots"]["behavior"]["crouch"] = 10;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 35;
@ -403,13 +411,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 1.5;
self.pers["bots"]["skill"]["bone_update_interval"] = 0.5;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 40;
self.pers["bots"]["behavior"]["nade"] = 35;
self.pers["bots"]["behavior"]["sprint"] = 40;
self.pers["bots"]["behavior"]["sprint"] = 60;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 30;
self.pers["bots"]["behavior"]["crouch"] = 10;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 50;
@ -432,13 +442,15 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 1;
self.pers["bots"]["skill"]["bone_update_interval"] = 0.25;
self.pers["bots"]["skill"]["bones"] = "j_spineupper,j_head,j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 50;
self.pers["bots"]["behavior"]["nade"] = 45;
self.pers["bots"]["behavior"]["sprint"] = 50;
self.pers["bots"]["behavior"]["sprint"] = 65;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 20;
self.pers["bots"]["behavior"]["crouch"] = 10;
self.pers["bots"]["behavior"]["switch"] = 2;
self.pers["bots"]["behavior"]["class"] = 2;
self.pers["bots"]["behavior"]["jump"] = 75;
@ -461,10 +473,12 @@ difficulty()
self.pers["bots"]["skill"]["aim_offset_amount"] = 0;
self.pers["bots"]["skill"]["bone_update_interval"] = 0.05;
self.pers["bots"]["skill"]["bones"] = "j_head";
self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5;
self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5;
self.pers["bots"]["behavior"]["strafe"] = 65;
self.pers["bots"]["behavior"]["nade"] = 65;
self.pers["bots"]["behavior"]["sprint"] = 65;
self.pers["bots"]["behavior"]["sprint"] = 70;
self.pers["bots"]["behavior"]["camp"] = 5;
self.pers["bots"]["behavior"]["follow"] = 5;
self.pers["bots"]["behavior"]["crouch"] = 5;
@ -474,6 +488,9 @@ difficulty()
break;
}
}
wait 5;
}
}
/*
@ -545,6 +562,11 @@ set_class(rankxp)
rank = self maps\mp\gametypes\_rank::getRankForXp( rankxp ) + 1;
if (RandomFloatRange(0, 1) < ((rank / level.maxRank) + 0.1))
{
self.pers["bots"]["behavior"]["quickscope"] = true;
}
for(i=0; i < 5; i++)
{
primary = get_random_weapon(primaryGroups, rank);
@ -651,7 +673,6 @@ get_random_perk(perkslot, rank, att1, att2)
{
case "specialty_parabolic":
case "specialty_holdbreath":
case "specialty_weapon_c4":
case "specialty_explosivedamage":
case "specialty_twoprimaries":
continue;
@ -917,6 +938,7 @@ start_bot_threads()
self thread bot_killstreak_think();
self thread bot_weapon_think();
self thread doReloadCancel();
// script targeting
if (getDvarInt("bots_play_target_other"))
@ -944,6 +966,7 @@ start_bot_threads()
self thread bot_use_tube_think();
self thread bot_use_grenade_think();
self thread bot_use_equipment_think();
self thread bot_watch_think_mw2();
}
// obj
@ -970,6 +993,9 @@ bot_inc_bots(obj, unreach)
level endon("game_ended");
self endon("bot_inc_bots");
if (!isDefined(obj))
return;
if (!isDefined(obj.bots))
obj.bots = 0;
@ -1035,7 +1061,7 @@ nearAnyOfWaypoints(dist, waypoints)
getNearestWaypointOfWaypoints(waypoints)
{
answer = undefined;
closestDist = 999999999999;
closestDist = 2147483647;
for (i = 0; i < waypoints.size; i++)
{
waypoint = waypoints[i];
@ -1311,6 +1337,23 @@ fire_current_weapon()
}
}
/*
Fires the bots c4
*/
fire_c4()
{
self endon("death");
self endon("disconnect");
self endon("weapon_change");
self endon("stop_firing_weapon");
for (;;)
{
self thread BotPressAds(0.05);
wait 0.1;
}
}
/*
Changes to the weap
*/
@ -1767,6 +1810,8 @@ bot_use_equipment_think()
nade = undefined;
if (self GetAmmoCount("claymore_mp"))
nade = "claymore_mp";
if (self GetAmmoCount("c4_mp"))
nade = "c4_mp";
if (!isDefined(nade))
continue;
@ -1844,7 +1889,10 @@ bot_use_equipment_think()
if (self changeToWeapon(nade))
{
if (nade != "c4_mp")
self thread fire_current_weapon();
else
self thread fire_c4();
self waittill_any_timeout(5, "grenade_fire", "weapon_change");
self notify("stop_firing_weapon");
}
@ -2087,9 +2135,19 @@ bot_revenge_think()
if(self.pers["bots"]["skill"]["base"] <= 1)
return;
if (isDefined(self.lastKiller) && isAlive(self.lastKiller))
{
if(bulletTracePassed(self getEyePos(), self.lastKiller getTagOrigin( "j_spineupper" ), false, self.lastKiller))
{
self setAttacker(self.lastKiller);
}
}
if(!isDefined(self.killerLocation))
return;
loc = self.killerLocation;
for(;;)
{
wait( RandomIntRange( 1, 5 ) );
@ -2100,13 +2158,80 @@ bot_revenge_think()
if ( randomint( 100 ) < 75 )
return;
self SetScriptGoal( self.killerLocation, 64 );
self SetScriptGoal( loc, 64 );
if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal")
self ClearScriptGoal();
}
}
/*
Reload cancels
*/
doReloadCancel()
{
self endon("disconnect");
self endon("death");
for (;;)
{
ret = self waittill_any_return("reload", "weapon_change");
if(self BotIsFrozen())
continue;
if(self isDefusing() || self isPlanting())
continue;
if (self InLastStand())
continue;
curWeap = self GetCurrentWeapon();
if (!maps\mp\gametypes\_weapons::isSideArm( curWeap ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap ))
continue;
if (ret == "reload")
{
// check single reloads
if (self GetWeaponAmmoClip(curWeap) < WeaponClipSize(curWeap))
continue;
}
// check difficulty
if (self.pers["bots"]["skill"]["base"] <= 3)
continue;
// check if got another weapon
weaponslist = self GetWeaponsListPrimaries();
weap = "";
while(weaponslist.size)
{
weapon = weaponslist[randomInt(weaponslist.size)];
weaponslist = array_remove(weaponslist, weapon);
if (!maps\mp\gametypes\_weapons::isSideArm( weapon ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon ))
continue;
if(curWeap == weapon || weapon == "none" || weapon == "")
continue;
weap = weapon;
break;
}
if(weap == "")
continue;
// do the cancel
wait 0.1;
self BotChangeToWeapon(weap);
wait 0.25;
self BotChangeToWeapon(curWeap);
wait 2;
}
}
/*
Bot logic for switching weapons.
*/
@ -2116,6 +2241,8 @@ bot_weapon_think()
self endon("disconnect");
level endon("game_ended");
first = true;
for(;;)
{
self waittill_any_timeout(randomIntRange(2, 4), "bot_force_check_switch");
@ -2141,7 +2268,16 @@ bot_weapon_think()
}
}
if(curWeap != "none" && self getAmmoCount(curWeap) && curWeap != "c4_mp")
if (first)
{
first = false;
if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"])
continue;
}
else
{
if(curWeap != "none" && self getAmmoCount(curWeap))
{
if(randomInt(100) > self.pers["bots"]["behavior"]["switch"])
continue;
@ -2149,6 +2285,7 @@ bot_weapon_think()
if(hasTarget)
continue;
}
}
weaponslist = self getweaponslist();
weap = "";
@ -2166,7 +2303,7 @@ bot_weapon_think()
if (maps\mp\gametypes\_weapons::isGrenade( weapon ))
continue;
if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "")//c4 no work
if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "")
continue;
weap = weapon;
@ -2180,6 +2317,52 @@ bot_weapon_think()
}
}
/*
Bots play mw2
*/
bot_watch_think_mw2()
{
self endon("disconnect");
self endon("death");
level endon("game_ended");
for (;;)
{
wait randomIntRange(1, 4);
if(self BotIsFrozen())
continue;
if(self isDefusing() || self isPlanting())
continue;
if (self InLastStand())
continue;
if (self HasThreat())
continue;
tube = self getValidTube();
if (!isDefined(tube))
{
if (self GetAmmoCount("rpg_mp"))
tube = "rpg_mp";
else
continue;
}
if (self GetCurrentWeapon() == tube)
continue;
chance = self.pers["bots"]["behavior"]["nade"];
if (randomInt(100) > chance)
continue;
self ChangeToWeapon(tube);
}
}
/*
Bot logic for killstreaks.
*/
@ -2285,8 +2468,12 @@ bot_killstreak_think()
if (isAirstrikePos && !isDefined( level.airstrikeInProgress ))
{
self BotFreezeControls(true);
self notify( "confirm_location", targetPos );
wait 1;
self BotFreezeControls(false);
}
self thread changeToWeapon(curWeap);
@ -2466,6 +2653,9 @@ bot_equipment_kill_think()
{
item = grenades[i];
if (!isDefined(item))
continue;
if ( !IsDefined( item.name ) )
{
continue;
@ -2706,6 +2896,8 @@ bot_dom_cap_think()
otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam );
if (game["teamScores"][myteam] >= game["teamScores"][otherTeam])
{
if ( myFlagCount < otherFlagCount )
{
if ( randomint( 100 ) < 15 )
@ -2721,6 +2913,7 @@ bot_dom_cap_think()
if ( randomint( 100 ) < 95 )
continue;
}
}
flag = undefined;
flags = [];

View File

@ -1525,7 +1525,7 @@ KDTree()
*/
KDTreeInsert(data)//as long as what you insert has a .origin attru, it will work.
{
self.root = self _KDTreeInsert(self.root, data, 0, -9999999999, -9999999999, -9999999999, 9999999999, 9999999999, 9999999999);
self.root = self _KDTreeInsert(self.root, data, 0, -2147483647, -2147483647, -2147483647, 2147483647, 2147483647, 2147483647);
}
/*
@ -1804,7 +1804,7 @@ ReverseHeapAStar(item, item2)
GetNearestWaypointWithSight(pos)
{
candidate = undefined;
dist = 9999999999;
dist = 2147483647;
for(i = 0; i < level.waypointCount; i++)
{

View File

@ -27,6 +27,9 @@ watchPlayers()
{
wait 1;
if (!getDvarInt("bots_main_menu"))
return;
for (i = level.players.size - 1; i >= 0; i--)
{
player = level.players[i];

View File

@ -368,7 +368,7 @@ watchSaveWaypointsCommand()
{
self iPrintlnBold("Auto link enabled");
level.autoLink = true;
level.wpToLink = self.nearest;
level.wpToLink = self.closest;
}
}
@ -446,6 +446,12 @@ DeleteAllWaypoints()
{
level.waypoints = [];
level.waypointCount = 0;
level.waypointsKDTree = WaypointsToKDTree();
level.waypointsCamp = [];
level.waypointsTube = [];
level.waypointsGren = [];
level.waypointsClay = [];
self iprintln("DelAllWps");
}
@ -617,9 +623,7 @@ destroyOnDeath(hud)
{
hud endon("death");
self waittill_either("death","disconnect");
hud notify("death");
hud destroy();
hud = undefined;
}
textScroll(string)

View File

@ -30,6 +30,22 @@ Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your s
- Pressing the menu button again closes menus.
## Changelog
- v2.0.1
- Reduced bots crouching
- Increased bots sprinting
- Improved bots mantling, crouching and knifing glass when needed
- Fixed possible script runtime errors
- Improved domination
- Bots use explosives more if they have it
- Bots aim slower when ads'ing
- Fixed bots holding breath
- Fixed bots rubberbanding movement when their goal changes
- Added bots quickscoping with snipers
- Added bots reload canceling and fast swaps
- Bots use C4
- Improved revenge
- Bots can swap weapons on spawn more likely
- v2.0.0
- Initial reboot release