fix: bots not throwing grenades since last commit

combat: various fixes to combat movements
combat: tweaked grenade throwing code
refactor: convert some arrays initializations  to initializer lists
build: switch docker image to clang 18.1
This commit is contained in:
jeefo 2024-03-09 01:06:11 +03:00
commit 2caa65f6ad
No known key found for this signature in database
GPG key ID: 927BCA0779BEA8ED
14 changed files with 253 additions and 221 deletions

View file

@ -7,4 +7,4 @@ indent_size = 3
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
insert_final_newline = true

@ -1 +1 @@
Subproject commit 7f76e21ddfbca7dd4f23e48d98d0620f29192900
Subproject commit 37d592703b23c0762a3fc285d2841da11bb6d525

@ -1 +1 @@
Subproject commit 49b1311349cdb002c7630e6d00d62eb9f5bcd010
Subproject commit b99f0bac831b823a1e5a57ef3bd7c7dcaf8dee22

View file

@ -431,6 +431,7 @@ constexpr auto kSprayDistance = 260.0f;
constexpr auto kDoubleSprayDistance = kSprayDistance * 2;
constexpr auto kMaxChatterRepeatInterval = 99.0f;
constexpr auto kViewFrameUpdate = 1.0f / 30.0f;
constexpr auto kGrenadeDamageRadius = 385.0f;
constexpr auto kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
constexpr auto kMaxWeapons = 32;
@ -443,8 +444,36 @@ constexpr auto kGrenadeInventoryEmpty = -1;
constexpr auto kConfigExtension = "cfg";
// weapon masks
constexpr auto kPrimaryWeaponMask = (cr::bit (Weapon::XM1014) | cr::bit (Weapon::M3) | cr::bit (Weapon::MAC10) | cr::bit (Weapon::UMP45) | cr::bit (Weapon::MP5) | cr::bit (Weapon::TMP) | cr::bit (Weapon::P90) | cr::bit (Weapon::AUG) | cr::bit (Weapon::M4A1) | cr::bit (Weapon::SG552) | cr::bit (Weapon::AK47) | cr::bit (Weapon::Scout) | cr::bit (Weapon::SG550) | cr::bit (Weapon::AWP) | cr::bit (Weapon::G3SG1) | cr::bit (Weapon::M249) | cr::bit (Weapon::Famas) | cr::bit (Weapon::Galil));
constexpr auto kSecondaryWeaponMask = (cr::bit (Weapon::P228) | cr::bit (Weapon::Elite) | cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18) | cr::bit (Weapon::Deagle) | cr::bit (Weapon::FiveSeven));
constexpr auto kPrimaryWeaponMask = (cr::bit (Weapon::XM1014) |
cr::bit (Weapon::M3) |
cr::bit (Weapon::MAC10) |
cr::bit (Weapon::UMP45) |
cr::bit (Weapon::MP5) |
cr::bit (Weapon::TMP) |
cr::bit (Weapon::P90) |
cr::bit (Weapon::AUG) |
cr::bit (Weapon::M4A1) |
cr::bit (Weapon::SG552) |
cr::bit (Weapon::AK47) |
cr::bit (Weapon::Scout) |
cr::bit (Weapon::SG550) |
cr::bit (Weapon::AWP) |
cr::bit (Weapon::G3SG1) |
cr::bit (Weapon::M249) |
cr::bit (Weapon::Famas) |
cr::bit (Weapon::Galil));
constexpr auto kSecondaryWeaponMask = (cr::bit (Weapon::P228)
| cr::bit (Weapon::Elite)
| cr::bit (Weapon::USP)
| cr::bit (Weapon::Glock18)
| cr::bit (Weapon::Deagle)
| cr::bit (Weapon::FiveSeven));
constexpr auto kSniperWeaponMask = (cr::bit (Weapon::Scout)
| cr::bit (Weapon::SG550)
| cr::bit (Weapon::AWP)
| cr::bit (Weapon::G3SG1));
// weapons < 7 are secondary
constexpr auto kPrimaryWeaponMinIndex = 7;

View file

@ -24,9 +24,9 @@ public:
using UniqueBot = UniquePtr <Bot>;
private:
float m_timeRoundStart {};
float m_timeRoundEnd {};
float m_timeRoundMid {};
float m_timeRoundStart {}; // time round has started
float m_timeRoundEnd {}; // time round ended
float m_timeRoundMid {}; // middle point timestamp of a round
float m_difficultyBalanceTime {}; // time to balance difficulties ?
float m_autoKillCheckTime {}; // time to kill all the bots ?
@ -277,7 +277,7 @@ public:
// bot async worker wrapper
class BotThreadWorker final : public Singleton <BotThreadWorker> {
private:
ThreadPool m_botWorker;
ThreadPool m_botWorker {};
public:
explicit BotThreadWorker () = default;

View file

@ -18,7 +18,7 @@ private:
StringArray m_sentences {};
SmallArray <Client> m_clients {};
HashMap <int32_t, String> m_weaponAlias {};
HashMap <int32_t, String> m_weaponAliases {};
public:
BotSupport ();
@ -121,13 +121,13 @@ public:
}
// gets the shooting cone deviation
float getShootingCone (edict_t *ent, const Vector &pos) {
float getConeDeviation (edict_t *ent, const Vector &pos) const {
return ent->v.v_angle.forward () | (pos - (ent->v.origin + ent->v.view_ofs)).normalize (); // he's facing it, he meant it
}
// check if position is inside view cone of entity
bool isInViewCone (const Vector &pos, edict_t *ent) {
return getShootingCone (ent, pos) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
bool isInViewCone (const Vector &pos, edict_t *ent) const {
return getConeDeviation (ent, pos) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
}
};

View file

@ -297,7 +297,6 @@ private:
bool m_isLeader {}; // bot is leader of his team
bool m_checkTerrain {}; // check for terrain
bool m_moveToC4 {}; // ct is moving to bomb
bool m_grenadeRequested {}; // bot requested change to grenade
bool m_needToSendWelcomeChat {}; // bot needs to greet people on server?
bool m_isCreature {}; // bot is not a player, but something else ? zombie ?
bool m_defuseNotified {}; // bot is notified about bomb defusion
@ -367,7 +366,7 @@ private:
int numEnemiesNear (const Vector &origin, const float radius);
int numFriendsNear (const Vector &origin, const float radius);
float getBombTimeleft ();
float getBombTimeleft () const;
float getEstimatedNodeReachTime ();
float isInFOV (const Vector &dest);
float getShiftSpeed ();
@ -386,8 +385,8 @@ private:
bool checkWallOnRight ();
bool updateNavigation ();
bool isEnemyThreat ();
bool isWeaponRestricted (int weaponIndex);
bool isWeaponRestrictedAMX (int weaponIndex);
bool isWeaponRestricted (int wid);
bool isWeaponRestrictedAMX (int wid);
bool isInViewCone (const Vector &origin);
bool checkBodyParts (edict_t *target);
bool seesEnemy (edict_t *player);
@ -560,6 +559,11 @@ private:
}
}
// get run player move angles
const Vector &getRpmAngles () {
return getCurrentTaskId () == Task::Attack ? pev->v_angle : m_moveAngles;
}
public:
entvars_t *pev {};

View file

@ -1108,16 +1108,16 @@ void Bot::checkMsgQueue () {
}
}
bool Bot::isWeaponRestricted (int weaponIndex) {
bool Bot::isWeaponRestricted (int wid) {
// this function checks for weapon restrictions.
auto val = cv_restricted_weapons.str ();
if (val.empty ()) {
return isWeaponRestrictedAMX (weaponIndex); // no banned weapons
return isWeaponRestrictedAMX (wid); // no banned weapons
}
const auto &bannedWeapons = val.split <String> (";");
const auto &alias = util.weaponIdToAlias (weaponIndex);
const auto &alias = util.weaponIdToAlias (wid);
for (const auto &ban : bannedWeapons) {
// check is this weapon is banned
@ -1125,24 +1125,24 @@ bool Bot::isWeaponRestricted (int weaponIndex) {
return true;
}
}
return isWeaponRestrictedAMX (weaponIndex);
return isWeaponRestrictedAMX (wid);
}
bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
bool Bot::isWeaponRestrictedAMX (int wid) {
// this function checks restriction set by AMX Mod, this function code is courtesy of KWo.
if (!game.is (GameFlags::Metamod)) {
return false;
}
auto checkRestriction = [&weaponIndex] (StringRef cvar, const int *data) -> bool {
auto checkRestriction = [&wid] (StringRef cvar, const int *data) -> bool {
auto restrictedWeapons = game.findCvar (cvar);
if (restrictedWeapons.empty ()) {
return false;
}
// find the weapon index
int index = data[weaponIndex - 1];
const auto index = data[wid - 1];
// validate index range
if (index < 0 || index >= static_cast <int> (restrictedWeapons.length ())) {
@ -1152,7 +1152,7 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
};
// check for weapon restrictions
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
if (cr::bit (wid) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
constexpr int ids[] = { 4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11 };
// verify restrictions
@ -1827,10 +1827,7 @@ void Bot::setConditions () {
pushRadioMessage (Radio::EnemyDown);
}
else if (rg.chance (60)) {
if ((m_lastVictim->v.weapons & cr::bit (Weapon::AWP))
|| (m_lastVictim->v.weapons & cr::bit (Weapon::Scout))
|| (m_lastVictim->v.weapons & cr::bit (Weapon::G3SG1))
|| (m_lastVictim->v.weapons & cr::bit (Weapon::SG550))) {
if (m_lastVictim->v.weapons & kSniperWeaponMask) {
pushChatterMessage (Chatter::SniperKilled);
}
@ -1907,7 +1904,7 @@ void Bot::setConditions () {
// clear the last enemy pointers if time has passed or enemy far away
if (!m_lastEnemyOrigin.empty ()) {
auto distanceSq = pev->origin.distanceSq (m_lastEnemyOrigin);
const auto distanceSq = pev->origin.distanceSq (m_lastEnemyOrigin);
if (distanceSq > cr::sqrf (2048.0f) || (game.isNullEntity (m_enemy) && m_seeEnemyTime + 10.0f < game.time ())) {
m_lastEnemyOrigin = nullptr;
@ -2312,7 +2309,7 @@ bool Bot::lastEnemyShootable () {
if (!(m_aimFlags & (AimFlags::LastEnemy | AimFlags::PredictPath)) || m_lastEnemyOrigin.empty () || game.isNullEntity (m_lastEnemy)) {
return false;
}
return util.getShootingCone (ent (), m_lastEnemyOrigin) >= 0.90f && isPenetrableObstacle (m_lastEnemyOrigin);
return util.getConeDeviation (ent (), m_lastEnemyOrigin) >= 0.90f && isPenetrableObstacle (m_lastEnemyOrigin);
}
void Bot::checkRadioQueue () {
@ -2966,7 +2963,8 @@ void Bot::logicDuringFreezetime () {
pev->button |= IN_JUMP;
m_jumpTime = game.time ();
}
Array <Bot *> teammates;
static Array <Bot *> teammates;
teammates.clear ();
for (const auto &bot : bots) {
if (bot->m_isAlive && bot->m_team == m_team && seesEntity (bot->pev->origin) && bot.get () != this) {
@ -3127,10 +3125,7 @@ void Bot::logic () {
}
else if (!hasFriendNearby
&& rg.chance (40)
&& ((m_enemy->v.weapons & cr::bit (Weapon::AWP))
|| (m_enemy->v.weapons & cr::bit (Weapon::Scout))
|| (m_enemy->v.weapons & cr::bit (Weapon::G3SG1))
|| (m_enemy->v.weapons & cr::bit (Weapon::SG550)))) {
&& (m_enemy->v.weapons & kSniperWeaponMask)) {
pushChatterMessage (Chatter::SniperWarning);
}
@ -3163,7 +3158,7 @@ void Bot::logic () {
updateLookAngles (); // and turn to chosen aim direction
// the bots wants to fire at something?
if (m_shootAtDeadTime > game.time () || (m_wantsToFire && !m_isUsingGrenade && (m_shootTime <= game.time ()))) {
if (m_shootAtDeadTime > game.time () || (m_wantsToFire && !m_isUsingGrenade && m_shootTime <= game.time ())) {
fireWeapons (); // if bot didn't fire a bullet try again next frame
}
@ -3750,32 +3745,29 @@ void Bot::runMovement () {
// problems, such as bots getting stuck into each others. That's because the model's
// bounding boxes, which are the boxes the engine uses to compute and detect all the
// collisions of the model, only exist, and are only valid, while in the duration of the
// movement. That's why if you get a pfnRunPlayerMove for one boINFt that lasts a little too
// movement. That's why if you get a pfnRunPlayerMove for one bot that lasts a little too
// short in comparison with the frame's duration, the remaining time until the frame
// elapses, that bot will behave like a ghost : no movement, but bullets and players can
// pass through it. Then, when the next frame will begin, the stucking problem will arise !
m_frameInterval = game.time () - m_lastCommandTime;
const uint8_t msecVal = computeMsec ();
const auto msecVal = computeMsec ();
m_lastCommandTime = game.time ();
engfuncs.pfnRunPlayerMove (pev->pContainingEntity, m_moveAngles, m_moveSpeed, m_strafeSpeed, 0.0f, static_cast <uint16_t> (pev->button), static_cast <uint8_t> (pev->impulse), msecVal);
engfuncs.pfnRunPlayerMove (pev->pContainingEntity,
getRpmAngles (), m_moveSpeed, m_strafeSpeed,
0.0f, static_cast <uint16_t> (pev->button), static_cast <uint8_t> (pev->impulse), msecVal);
// save our own copy of old buttons, since bot ai code is not running every frame now
// save our own copy of old buttons, since bot bot code is not running every frame now
m_oldButtons = pev->button;
}
float Bot::getBombTimeleft () {
float Bot::getBombTimeleft () const {
if (!bots.isBombPlanted ()) {
return 0.0f;
}
const float timeLeft = ((bots.getTimeBombPlanted () + mp_c4timer.float_ ()) - game.time ());
if (timeLeft < 0.0f) {
return 0.0f;
}
return timeLeft;
return cr::max (bots.getTimeBombPlanted () + mp_c4timer.float_ () - game.time (), 0.0f);
}
bool Bot::isOutOfBombTimer () {

View file

@ -11,28 +11,14 @@ ConVar cv_chat ("chat", "1", "Enables or disables bots chat functionality.");
ConVar cv_chat_percent ("chat_percent", "30", "Bot chances to send random dead chat when killed.", true, 0.0f, 100.0f);
BotChatManager::BotChatManager () {
m_clanTags.emplace ("[[", "]]");
m_clanTags.emplace ("-=", "=-");
m_clanTags.emplace ("-[", "]-");
m_clanTags.emplace ("-]", "[-");
m_clanTags.emplace ("-}", "{-");
m_clanTags.emplace ("-{", "}-");
m_clanTags.emplace ("<[", "]>");
m_clanTags.emplace ("<]", "[>");
m_clanTags.emplace ("[-", "-]");
m_clanTags.emplace ("]-", "-[");
m_clanTags.emplace ("{-", "-}");
m_clanTags.emplace ("}-", "-{");
m_clanTags.emplace ("[", "]");
m_clanTags.emplace ("{", "}");
m_clanTags.emplace ("<", "[");
m_clanTags.emplace (">", "<");
m_clanTags.emplace ("-", "-");
m_clanTags.emplace ("|", "|");
m_clanTags.emplace ("=", "=");
m_clanTags.emplace ("+", "+");
m_clanTags.emplace ("(", ")");
m_clanTags.emplace (")", "(");
m_clanTags = {
{ "[[", "]]" }, { "-=", "=-" }, { "-[", "]-" }, { "-]", "[-" },
{ "-}", "{-" }, { "-{", "}-" }, { "<[", "]>" }, { "<]", "[>" },
{ "[-", "-]" }, { "]-", "-[" }, { "{-", "-}" }, { "}-", "-{" },
{ "[", "]" }, { "{", "}" }, { "<", "[" }, { ">", "<" }, { ")", "(" },
{ "-", "-" }, { "|", "|" }, { "=", "=" }, { "+", "+" }, { "(", ")" },
};
}
void BotChatManager::stripTags (String &line) {

View file

@ -656,7 +656,7 @@ bool Bot::isFriendInLineOfFire (float distance) {
const auto friendDistanceSq = client.ent->v.origin.distanceSq (pev->origin);
if (friendDistanceSq <= distanceSq
&& util.getShootingCone (ent (), client.ent->v.origin) > friendDistanceSq / (friendDistanceSq + cr::sqrf (33.0f))) {
&& util.getConeDeviation (ent (), client.ent->v.origin) > friendDistanceSq / (friendDistanceSq + cr::sqrf (33.0f))) {
return true;
}
}
@ -805,7 +805,7 @@ bool Bot::needToPauseFiring (float distance) {
}
if ((m_aimFlags & AimFlags::Enemy) && !m_enemyOrigin.empty ()) {
if (util.getShootingCone (ent (), m_enemyOrigin) > 0.92f && isEnemyBehindShield (m_enemy)) {
if (util.getConeDeviation (ent (), m_enemyOrigin) > 0.92f && isEnemyBehindShield (m_enemy)) {
return true;
}
}
@ -1148,13 +1148,13 @@ void Bot::focusEnemy () {
}
}
else {
const float dot = util.getShootingCone (ent (), m_enemyOrigin);
const float dot = util.getConeDeviation (ent (), m_enemyOrigin);
if (dot < 0.90f) {
m_wantsToFire = false;
}
else {
const float enemyDot = util.getShootingCone (m_enemy, pev->origin);
const float enemyDot = util.getConeDeviation (m_enemy, pev->origin);
// enemy faces bot?
if (enemyDot >= 0.90f) {
@ -1209,9 +1209,16 @@ void Bot::attackMovement () {
// only take cover when bomb is not planted and enemy can see the bot or the bot is VIP
if (!game.is (GameFlags::CSDM)) {
if (m_retreatTime < game.time () && (m_states & Sense::SeeingEnemy) && approach < 30 && !bots.isBombPlanted () && (isInViewCone (m_enemy->v.origin) || m_isVIP)) {
m_moveSpeed = -pev->maxspeed;
startTask (Task::SeekCover, TaskPri::SeekCover, kInvalidNodeIndex, 0.0f, true);
if (m_retreatTime < game.time () && approach < 30 && !bots.isBombPlanted ()) {
const auto enemyCone = util.getConeDeviation (m_enemy, pev->origin);
const auto seeingEnemy = (m_states & Sense::SeeingEnemy);
const auto enemyWeaponIsSniper = (m_enemy->v.weapons & kSniperWeaponMask);
// make bot seek cover
if ((enemyCone > 0.8f && seeingEnemy) || (enemyWeaponIsSniper && enemyCone > 0.95f)) {
startTask (Task::SeekCover, TaskPri::SeekCover, kInvalidNodeIndex, 0.0f, false);
m_moveSpeed = -pev->maxspeed;
}
}
else if (approach < 50) {
m_moveSpeed = 0.0f;
@ -1268,7 +1275,7 @@ void Bot::attackMovement () {
const auto pistolStrafeDistance = game.is (GameFlags::CSDM) ? kDoubleSprayDistance * 3.0f : kDoubleSprayDistance;
// fire hurts friend value here is from previous frame, but acceptable, and saves us alot of cpu cycles
if (m_fireHurtsFriend || ((usesPistol () || usesShotgun ())
if (approach < 30 || m_fireHurtsFriend || ((usesPistol () || usesShotgun ())
&& distance < pistolStrafeDistance
&& isInViewCone (m_enemyOrigin))) {
m_fightStyle = Fight::Strafe;
@ -1290,7 +1297,7 @@ void Bot::attackMovement () {
};
auto strafeUpdateTime = [] () {
return game.time () + rg.get (1.0f, 1.5f);
return game.time () + rg.get (0.8f, 1.25f);
};
// to start strafing, we have to first figure out if the target is on the left side or right side
@ -1346,7 +1353,7 @@ void Bot::attackMovement () {
}
// we're setting strafe speed regardless of move angles, so not resetting forward move here cause bots to behave strange
if (!usesKnife ()) {
if (!usesKnife () && approach >= 30) {
m_moveSpeed = 0.0f;
}
@ -1463,7 +1470,7 @@ int Bot::bestPrimaryCarried () {
int weaponIndex = 0;
int weapons = pev->weapons;
const auto &tab = conf.getRawWeapons ();
const auto tab = conf.getRawWeapons ();
// take the shield in account
if (hasShield ()) {
@ -1588,6 +1595,7 @@ void Bot::selectBestWeapon () {
// loop through all the weapons until terminator is found...
while (tab[selectIndex].id) {
// is the bot NOT carrying this weapon?
if (!(pev->weapons & cr::bit (tab[selectIndex].id))) {
++selectIndex; // skip to next weapon
@ -1627,7 +1635,7 @@ void Bot::selectBestWeapon () {
}
void Bot::selectSecondary () {
int oldWeapons = pev->weapons;
const int oldWeapons = pev->weapons;
pev->weapons &= ~kPrimaryWeaponMask;
selectBestWeapon ();
@ -1649,14 +1657,15 @@ int Bot::bestWeaponCarried () {
num = i;
}
++i;
tab++;
++tab;
}
return num;
}
void Bot::decideFollowUser () {
// this function forces bot to follow user
Array <edict_t *> users;
static Array <edict_t *> users;
users.clear ();
// search friends near us
for (const auto &client : util.getClients ()) {
@ -1975,7 +1984,6 @@ void Bot::checkGrenadesThrow () {
|| isInNarrowPlace ()
|| cv_ignore_enemies.bool_ ()
|| m_isUsingGrenade
|| m_grenadeRequested
|| m_isReloading
|| (isKnifeMode () && !bots.isBombPlanted ())
|| m_grenadeCheckTime >= game.time ()
@ -2006,7 +2014,7 @@ void Bot::checkGrenadesThrow () {
clearThrowStates (m_states);
return;
}
else {
else if (!isGrenadeMode) {
int cancelProb = m_agressionLevel > m_fearLevel ? 5 : 20;
if (grenadeToThrow == Weapon::Flashbang) {
@ -2034,23 +2042,25 @@ void Bot::checkGrenadesThrow () {
// special condition if we're have valid current enemy
if (!isGrenadeMode && ((m_states & Sense::SeeingEnemy)
&& util.isAlive (m_enemy)
&& ((m_enemy->v.button | m_enemy->v.oldbuttons) & IN_ATTACK)
&& util.isInViewCone (pev->origin, m_enemy))) {
&& util.isAlive (m_enemy)
&& ((m_enemy->v.button | m_enemy->v.oldbuttons) & IN_ATTACK)
&& util.isVisible (pev->origin, m_enemy))
&& util.isInViewCone (pev->origin, m_enemy)) {
// do not throw away grenades if anyone is attacking us
distanceSq = kInfiniteDistance;
}
// don't throw away nades if just seen the enemy
if (!isGrenadeMode && m_seeEnemyTime + kGrenadeCheckTime * 0.2f < game.time ()) {
if (!isGrenadeMode && m_seeEnemyTime + kGrenadeCheckTime * 0.2f > game.time ()) {
distanceSq = kInfiniteDistance;
}
// enemy within a good throw distance?
const auto grenadeToThrowCondition = isGrenadeMode ? 100.0f : grenadeToThrow == Weapon::Smoke ? 200.0f : 350.0f;
const auto grenadeToThrowCondition =
isGrenadeMode ? kGrenadeDamageRadius / 4.0f : grenadeToThrow == Weapon::Smoke ? 200.0f : kGrenadeDamageRadius;
if (distanceSq > cr::sqrf (grenadeToThrowCondition) && distanceSq < cr::sqrf (1200.0f)) {
if (distanceSq > cr::sqrf (grenadeToThrowCondition) && distanceSq < cr::sqrf (kGrenadeDamageRadius * 3.0f)) {
bool allowThrowing = true;
// care about different grenades
@ -2060,8 +2070,8 @@ void Bot::checkGrenadesThrow () {
allowThrowing = false;
}
else {
const float radius = cr::max (192.0f, m_lastEnemy->v.velocity.length2d ());
const Vector &pos = m_lastEnemy->v.velocity.get2d () + m_lastEnemy->v.origin;
const auto radius = cr::max (192.0f, m_lastEnemy->v.velocity.length2d ());
const auto &pos = m_lastEnemy->v.velocity.get2d () + m_lastEnemy->v.origin;
auto predicted = graph.getNearestInRadius (radius, pos, 12);
@ -2143,7 +2153,7 @@ void Bot::checkGrenadesThrow () {
case Weapon::Smoke:
if (allowThrowing && !game.isNullEntity (m_lastEnemy)) {
if (util.getShootingCone (m_lastEnemy, pev->origin) >= 0.9f) {
if (util.getConeDeviation (m_lastEnemy, pev->origin) >= 0.9f) {
allowThrowing = false;
}
}
@ -2160,16 +2170,16 @@ void Bot::checkGrenadesThrow () {
clearThrowStates (m_states);
return;
}
const float kMaxThrowTime = game.time () + kGrenadeCheckTime * 4.0f;
const float maxThrowTime = game.time () + kGrenadeCheckTime * 3.6f;
if (m_states & Sense::ThrowExplosive) {
startTask (Task::ThrowExplosive, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
startTask (Task::ThrowExplosive, TaskPri::Throw, kInvalidNodeIndex, maxThrowTime, false);
}
else if (m_states & Sense::ThrowFlashbang) {
startTask (Task::ThrowFlashbang, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
startTask (Task::ThrowFlashbang, TaskPri::Throw, kInvalidNodeIndex, maxThrowTime, false);
}
else if (m_states & Sense::ThrowSmoke) {
startTask (Task::ThrowSmoke, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
startTask (Task::ThrowSmoke, TaskPri::Throw, kInvalidNodeIndex, maxThrowTime, false);
}
}
else {

View file

@ -777,35 +777,37 @@ void BotConfig::initWeapons () {
m_weapons.clear ();
// fill array with available weapons
m_weapons.emplace (Weapon::Knife, "weapon_knife", "knife.mdl", 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, WeaponType::Melee, true);
m_weapons.emplace (Weapon::USP, "weapon_usp", "usp.mdl", 500, 1, -1, -1, 1, 1, 2, 2, 0, 12, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Glock18, "weapon_glock18", "glock18.mdl", 400, 1, -1, -1, 1, 2, 1, 1, 0, 20, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Deagle, "weapon_deagle", "deagle.mdl", 650, 1, 2, 2, 1, 3, 4, 4, 2, 7, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::P228, "weapon_p228", "p228.mdl", 600, 1, 2, 2, 1, 4, 3, 3, 0, 13, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::Elite, "weapon_elite", "elite.mdl", 800, 1, 0, 0, 1, 5, 5, 5, 0, 30, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::FiveSeven, "weapon_fiveseven", "fiveseven.mdl", 750, 1, 1, 1, 1, 6, 5, 5, 0, 20, WeaponType::Pistol, false);
m_weapons.emplace (Weapon::M3, "weapon_m3", "m3.mdl", 1700, 1, 2, -1, 2, 1, 1, 1, 0, 8, WeaponType::Shotgun, false);
m_weapons.emplace (Weapon::XM1014, "weapon_xm1014", "xm1014.mdl", 3000, 1, 2, -1, 2, 2, 2, 2, 0, 7, WeaponType::Shotgun, false);
m_weapons.emplace (Weapon::MP5, "weapon_mp5navy", "mp5.mdl", 1500, 1, 2, 1, 3, 1, 2, 2, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::TMP, "weapon_tmp", "tmp.mdl", 1250, 1, 1, 1, 3, 2, 1, 1, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::P90, "weapon_p90", "p90.mdl", 2350, 1, 2, 1, 3, 3, 4, 4, 0, 50, WeaponType::SMG, true);
m_weapons.emplace (Weapon::MAC10, "weapon_mac10", "mac10.mdl", 1400, 1, 0, 0, 3, 4, 1, 1, 0, 30, WeaponType::SMG, true);
m_weapons.emplace (Weapon::UMP45, "weapon_ump45", "ump45.mdl", 1700, 1, 2, 2, 3, 5, 3, 3, 0, 25, WeaponType::SMG, true);
m_weapons.emplace (Weapon::AK47, "weapon_ak47", "ak47.mdl", 2500, 1, 0, 0, 4, 1, 2, 2, 2, 30, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::SG552, "weapon_sg552", "sg552.mdl", 3500, 1, 0, -1, 4, 2, 4, 4, 2, 30, WeaponType::ZoomRifle, true);
m_weapons.emplace (Weapon::M4A1, "weapon_m4a1", "m4a1.mdl", 3100, 1, 1, 1, 4, 3, 3, 3, 2, 30, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::Galil, "weapon_galil", "galil.mdl", 2000, 1, 0, 0, 4, -1, 1, 1, 2, 35, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::Famas, "weapon_famas", "famas.mdl", 2250, 1, 1, 1, 4, -1, 1, 1, 2, 25, WeaponType::Rifle, true);
m_weapons.emplace (Weapon::AUG, "weapon_aug", "aug.mdl", 3500, 1, 1, 1, 4, 4, 4, 4, 2, 30, WeaponType::ZoomRifle, true);
m_weapons.emplace (Weapon::Scout, "weapon_scout", "scout.mdl", 2750, 1, 2, 0, 4, 5, 3, 2, 3, 10, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::AWP, "weapon_awp", "awp.mdl", 4750, 1, 2, 0, 4, 6, 5, 6, 3, 10, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::G3SG1, "weapon_g3sg1", "g3sg1.mdl", 5000, 1, 0, 2, 4, 7, 6, 6, 3, 20, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::SG550, "weapon_sg550", "sg550.mdl", 4200, 1, 1, 1, 4, 8, 5, 5, 3, 30, WeaponType::Sniper, false);
m_weapons.emplace (Weapon::M249, "weapon_m249", "m249.mdl", 5750, 1, 2, 1, 5, 1, 1, 1, 2, 100, WeaponType::Heavy, true);
m_weapons.emplace (Weapon::Shield, "weapon_shield", "shield.mdl", 2200, 0, 1, 1, 8, -1, 8, 8, 0, 0, WeaponType::Pistol, false);
m_weapons = {
{ Weapon::Knife, "weapon_knife", "knife.mdl", 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, WeaponType::Melee, true },
{ Weapon::USP, "weapon_usp", "usp.mdl", 500, 1, -1, -1, 1, 1, 2, 2, 0, 12, WeaponType::Pistol, false },
{ Weapon::Glock18, "weapon_glock18", "glock18.mdl", 400, 1, -1, -1, 1, 2, 1, 1, 0, 20, WeaponType::Pistol, false },
{ Weapon::Deagle, "weapon_deagle", "deagle.mdl", 650, 1, 2, 2, 1, 3, 4, 4, 2, 7, WeaponType::Pistol, false },
{ Weapon::P228, "weapon_p228", "p228.mdl", 600, 1, 2, 2, 1, 4, 3, 3, 0, 13, WeaponType::Pistol, false },
{ Weapon::Elite, "weapon_elite", "elite.mdl", 800, 1, 0, 0, 1, 5, 5, 5, 0, 30, WeaponType::Pistol, false },
{ Weapon::FiveSeven, "weapon_fiveseven", "fiveseven.mdl", 750, 1, 1, 1, 1, 6, 5, 5, 0, 20, WeaponType::Pistol, false },
{ Weapon::M3, "weapon_m3", "m3.mdl", 1700, 1, 2, -1, 2, 1, 1, 1, 0, 8, WeaponType::Shotgun, false },
{ Weapon::XM1014, "weapon_xm1014", "xm1014.mdl", 3000, 1, 2, -1, 2, 2, 2, 2, 0, 7, WeaponType::Shotgun, false },
{ Weapon::MP5, "weapon_mp5navy", "mp5.mdl", 1500, 1, 2, 1, 3, 1, 2, 2, 0, 30, WeaponType::SMG, true },
{ Weapon::TMP, "weapon_tmp", "tmp.mdl", 1250, 1, 1, 1, 3, 2, 1, 1, 0, 30, WeaponType::SMG, true },
{ Weapon::P90, "weapon_p90", "p90.mdl", 2350, 1, 2, 1, 3, 3, 4, 4, 0, 50, WeaponType::SMG, true },
{ Weapon::MAC10, "weapon_mac10", "mac10.mdl", 1400, 1, 0, 0, 3, 4, 1, 1, 0, 30, WeaponType::SMG, true },
{ Weapon::UMP45, "weapon_ump45", "ump45.mdl", 1700, 1, 2, 2, 3, 5, 3, 3, 0, 25, WeaponType::SMG, true },
{ Weapon::AK47, "weapon_ak47", "ak47.mdl", 2500, 1, 0, 0, 4, 1, 2, 2, 2, 30, WeaponType::Rifle, true },
{ Weapon::SG552, "weapon_sg552", "sg552.mdl", 3500, 1, 0, -1, 4, 2, 4, 4, 2, 30, WeaponType::ZoomRifle, true },
{ Weapon::M4A1, "weapon_m4a1", "m4a1.mdl", 3100, 1, 1, 1, 4, 3, 3, 3, 2, 30, WeaponType::Rifle, true },
{ Weapon::Galil, "weapon_galil", "galil.mdl", 2000, 1, 0, 0, 4, -1, 1, 1, 2, 35, WeaponType::Rifle, true },
{ Weapon::Famas, "weapon_famas", "famas.mdl", 2250, 1, 1, 1, 4, -1, 1, 1, 2, 25, WeaponType::Rifle, true },
{ Weapon::AUG, "weapon_aug", "aug.mdl", 3500, 1, 1, 1, 4, 4, 4, 4, 2, 30, WeaponType::ZoomRifle, true },
{ Weapon::Scout, "weapon_scout", "scout.mdl", 2750, 1, 2, 0, 4, 5, 3, 2, 3, 10, WeaponType::Sniper, false },
{ Weapon::AWP, "weapon_awp", "awp.mdl", 4750, 1, 2, 0, 4, 6, 5, 6, 3, 10, WeaponType::Sniper, false },
{ Weapon::G3SG1, "weapon_g3sg1", "g3sg1.mdl", 5000, 1, 0, 2, 4, 7, 6, 6, 3, 20, WeaponType::Sniper, false },
{ Weapon::SG550, "weapon_sg550", "sg550.mdl", 4200, 1, 1, 1, 4, 8, 5, 5, 3, 30, WeaponType::Sniper, false },
{ Weapon::M249, "weapon_m249", "m249.mdl", 5750, 1, 2, 1, 5, 1, 1, 1, 2, 100, WeaponType::Heavy, true },
{ Weapon::Shield, "weapon_shield", "shield.mdl", 2200, 0, 1, 1, 8, -1, 8, 8, 0, 0, WeaponType::Pistol, false },
// not needed actually, but cause too much refactoring for now. todo
m_weapons.emplace (0, "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WeaponType::None, false);
// not needed actually, but cause too much refactoring for now. todo
{ 0, "", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, WeaponType::None, false }
};
}
void BotConfig::adjustWeaponPrices () {

View file

@ -562,26 +562,28 @@ void BotManager::reset () {
void BotManager::initFilters () {
// table with all available actions for the bots (filtered in & out in bot::setconditions) some of them have subactions included
m_filters.emplace (&Bot::normal_, Task::Normal, 0.0f, kInvalidNodeIndex, 0.0f, true);
m_filters.emplace (&Bot::pause_, Task::Pause, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::moveToPos_, Task::MoveToPosition, 0.0f, kInvalidNodeIndex, 0.0f, true);
m_filters.emplace (&Bot::followUser_, Task::FollowUser, 0.0f, kInvalidNodeIndex, 0.0f, true);
m_filters.emplace (&Bot::pickupItem_, Task::PickupItem, 0.0f, kInvalidNodeIndex, 0.0f, true);
m_filters.emplace (&Bot::camp_, Task::Camp, 0.0f, kInvalidNodeIndex, 0.0f, true);
m_filters.emplace (&Bot::plantBomb_, Task::PlantBomb, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::defuseBomb_, Task::DefuseBomb, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::attackEnemy_, Task::Attack, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::huntEnemy_, Task::Hunt, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::seekCover_, Task::SeekCover, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::throwExplosive_, Task::ThrowExplosive, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::throwFlashbang_, Task::ThrowFlashbang, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::throwSmoke_, Task::ThrowSmoke, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::doublejump_, Task::DoubleJump, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::escapeFromBomb_, Task::EscapeFromBomb, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::shootBreakable_, Task::ShootBreakable, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::hide_, Task::Hide, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::blind_, Task::Blind, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters.emplace (&Bot::spraypaint_, Task::Spraypaint, 0.0f, kInvalidNodeIndex, 0.0f, false);
m_filters = {
{ &Bot::normal_, Task::Normal, 0.0f, kInvalidNodeIndex, 0.0f, true },
{ &Bot::pause_, Task::Pause, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::moveToPos_, Task::MoveToPosition, 0.0f, kInvalidNodeIndex, 0.0f, true },
{ &Bot::followUser_, Task::FollowUser, 0.0f, kInvalidNodeIndex, 0.0f, true },
{ &Bot::pickupItem_, Task::PickupItem, 0.0f, kInvalidNodeIndex, 0.0f, true },
{ &Bot::camp_, Task::Camp, 0.0f, kInvalidNodeIndex, 0.0f, true },
{ &Bot::plantBomb_, Task::PlantBomb, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::defuseBomb_, Task::DefuseBomb, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::attackEnemy_, Task::Attack, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::huntEnemy_, Task::Hunt, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::seekCover_, Task::SeekCover, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::throwExplosive_, Task::ThrowExplosive, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::throwFlashbang_, Task::ThrowFlashbang, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::throwSmoke_, Task::ThrowSmoke, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::doublejump_, Task::DoubleJump, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::escapeFromBomb_, Task::EscapeFromBomb, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::shootBreakable_, Task::ShootBreakable, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::hide_, Task::Hide, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::blind_, Task::Blind, 0.0f, kInvalidNodeIndex, 0.0f, false },
{ &Bot::spraypaint_, Task::Spraypaint, 0.0f, kInvalidNodeIndex, 0.0f, false }
};
}
void BotManager::resetFilters () {
@ -1246,7 +1248,7 @@ int BotManager::getAliveHumansCount () {
int count = 0;
for (const auto &client : util.getClients ()) {
if ((client.flags & ClientFlags::Alive) && bots[client.ent] == nullptr && !(client.ent->v.flags & FL_FAKECLIENT)) {
if ((client.flags & ClientFlags::Alive) && !bots[client.ent] && !(client.ent->v.flags & FL_FAKECLIENT)) {
++count;
}
}
@ -1413,7 +1415,6 @@ void Bot::newRound () {
m_loosedBombNodeIndex = kInvalidNodeIndex;
m_plantedBombNodeIndex = kInvalidNodeIndex;
m_grenadeRequested = false;
m_moveToC4 = false;
m_defuseNotified = false;
m_duckDefuse = false;

View file

@ -18,55 +18,59 @@ BotSupport::BotSupport () {
m_welcomeReceiveTime = 0.0f;
// add default messages
m_sentences.push ("hello user,communication is acquired");
m_sentences.push ("your presence is acknowledged");
m_sentences.push ("high man, your in command now");
m_sentences.push ("blast your hostile for good");
m_sentences.push ("high man, kill some idiot here");
m_sentences.push ("is there a doctor in the area");
m_sentences.push ("warning, experimental materials detected");
m_sentences.push ("high amigo, shoot some but");
m_sentences.push ("time for some bad ass explosion");
m_sentences.push ("bad ass son of a breach device activated");
m_sentences.push ("high, do not question this great service");
m_sentences.push ("engine is operative, hello and goodbye");
m_sentences.push ("high amigo, your administration has been great last day");
m_sentences.push ("attention, expect experimental armed hostile presence");
m_sentences.push ("warning, medical attention required");
m_sentences = {
"hello user,communication is acquired",
"your presence is acknowledged",
"high man, your in command now",
"blast your hostile for good",
"high man, kill some idiot here",
"is there a doctor in the area",
"warning, experimental materials detected",
"high amigo, shoot some but",
"time for some bad ass explosion",
"bad ass son of a breach device activated",
"high, do not question this great service",
"engine is operative, hello and goodbye",
"high amigo, your administration has been great last day",
"attention, expect experimental armed hostile presence",
"warning, medical attention required"
};
// register weapon aliases
m_weaponAlias[Weapon::USP] = "usp"; // HK USP .45 Tactical
m_weaponAlias[Weapon::Glock18] = "glock"; // Glock18 Select Fire
m_weaponAlias[Weapon::Deagle] = "deagle"; // Desert Eagle .50AE
m_weaponAlias[Weapon::P228] = "p228"; // SIG P228
m_weaponAlias[Weapon::Elite] = "elite"; // Dual Beretta 96G Elite
m_weaponAlias[Weapon::FiveSeven] = "fn57"; // FN Five-Seven
m_weaponAlias[Weapon::M3] = "m3"; // Benelli M3 Super90
m_weaponAlias[Weapon::XM1014] = "xm1014"; // Benelli XM1014
m_weaponAlias[Weapon::MP5] = "mp5"; // HK MP5-Navy
m_weaponAlias[Weapon::TMP] = "tmp"; // Steyr Tactical Machine Pistol
m_weaponAlias[Weapon::P90] = "p90"; // FN P90
m_weaponAlias[Weapon::MAC10] = "mac10"; // Ingram MAC-10
m_weaponAlias[Weapon::UMP45] = "ump45"; // HK UMP45
m_weaponAlias[Weapon::AK47] = "ak47"; // Automat Kalashnikov AK-47
m_weaponAlias[Weapon::Galil] = "galil"; // IMI Galil
m_weaponAlias[Weapon::Famas] = "famas"; // GIAT FAMAS
m_weaponAlias[Weapon::SG552] = "sg552"; // Sig SG-552 Commando
m_weaponAlias[Weapon::M4A1] = "m4a1"; // Colt M4A1 Carbine
m_weaponAlias[Weapon::AUG] = "aug"; // Steyr Aug
m_weaponAlias[Weapon::Scout] = "scout"; // Steyr Scout
m_weaponAlias[Weapon::AWP] = "awp"; // AI Arctic Warfare/Magnum
m_weaponAlias[Weapon::G3SG1] = "g3sg1"; // HK G3/SG-1 Sniper Rifle
m_weaponAlias[Weapon::SG550] = "sg550"; // Sig SG-550 Sniper
m_weaponAlias[Weapon::M249] = "m249"; // FN M249 Para
m_weaponAlias[Weapon::Flashbang] = "flash"; // Concussion Grenade
m_weaponAlias[Weapon::Explosive] = "hegren"; // High-Explosive Grenade
m_weaponAlias[Weapon::Smoke] = "sgren"; // Smoke Grenade
m_weaponAlias[Weapon::Armor] = "vest"; // Kevlar Vest
m_weaponAlias[Weapon::ArmorHelm] = "vesthelm"; // Kevlar Vest and Helmet
m_weaponAlias[Weapon::Defuser] = "defuser"; // Defuser Kit
m_weaponAlias[Weapon::Shield] = "shield"; // Tactical Shield
m_weaponAlias[Weapon::Knife] = "knife"; // Knife
m_weaponAliases = {
{ Weapon::USP, "usp" }, // HK USP .45 Tactical
{ Weapon::Glock18, "glock" }, // Glock18 Select Fire
{ Weapon::Deagle, "deagle" }, // Desert Eagle .50AE
{ Weapon::P228, "p228" }, // SIG P228
{ Weapon::Elite, "elite" }, // Dual Beretta 96G Elite
{ Weapon::FiveSeven, "fn57" }, // FN Five-Seven
{ Weapon::M3, "m3" }, // Benelli M3 Super90
{ Weapon::XM1014, "xm1014" }, // Benelli XM1014
{ Weapon::MP5, "mp5" }, // HK MP5-Navy
{ Weapon::TMP, "tmp" }, // Steyr Tactical Machine Pistol
{ Weapon::P90, "p90" }, // FN P90
{ Weapon::MAC10, "mac10" }, // Ingram MAC-10
{ Weapon::UMP45, "ump45" }, // HK UMP45
{ Weapon::AK47, "ak47" }, // Automat Kalashnikov AK-47
{ Weapon::Galil, "galil" }, // IMI Galil
{ Weapon::Famas, "famas" }, // GIAT FAMAS
{ Weapon::SG552, "sg552" }, // Sig SG-552 Commando
{ Weapon::M4A1, "m4a1" }, // Colt M4A1 Carbine
{ Weapon::AUG, "aug" }, // Steyr Aug
{ Weapon::Scout, "scout" }, // Steyr Scout
{ Weapon::AWP, "awp" }, // AI Arctic Warfare/Magnum
{ Weapon::G3SG1, "g3sg1" }, // HK G3/SG-1 Sniper Rifle
{ Weapon::SG550, "sg550" }, // Sig SG-550 Sniper
{ Weapon::M249, "m249" }, // FN M249 Para
{ Weapon::Flashbang, "flash" }, // Concussion Grenade
{ Weapon::Explosive, "hegren" }, // High-Explosive Grenade
{ Weapon::Smoke, "sgren" }, // Smoke Grenade
{ Weapon::Armor, "vest" }, // Kevlar Vest
{ Weapon::ArmorHelm, "vesthelm" }, // Kevlar Vest and Helmet
{ Weapon::Defuser, "defuser" }, // Defuser Kit
{ Weapon::Shield, "shield" }, // Tactical Shield
{ Weapon::Knife, "knife" } // Knife
};
m_clients.resize (kGameMaxPlayers + 1);
}
@ -573,8 +577,8 @@ StringRef BotSupport::getFakeSteamId (edict_t *ent) {
StringRef BotSupport::weaponIdToAlias (int32_t id) {
StringRef none = "none";
if (m_weaponAlias.exists (id)) {
return m_weaponAlias[id];
if (m_weaponAliases.exists (id)) {
return m_weaponAliases[id];
}
return none;
}

View file

@ -21,11 +21,28 @@ void Bot::normal_ () {
const int debugGoal = cv_debug_goal.int_ ();
// user forced a node as a goal?
if (debugGoal != kInvalidNodeIndex && getTask ()->data != debugGoal) {
clearSearchNodes ();
if (debugGoal != kInvalidNodeIndex) {
if (getTask ()->data != debugGoal) {
clearSearchNodes ();
getTask ()->data = debugGoal;
m_chosenGoalIndex = debugGoal;
getTask ()->data = debugGoal;
m_chosenGoalIndex = debugGoal;
}
// stop the bot if precisely reached debug goal
if (m_currentNodeIndex == debugGoal) {
const auto &debugOrigin = graph[debugGoal].origin;
if (debugOrigin.distanceSq (pev->origin) < cr::sqrf (22.0f) && util.isVisible (debugOrigin, ent ())) {
m_moveToGoal = false;
m_checkTerrain = false;
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;
return;
}
}
}
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project)
@ -1120,7 +1137,7 @@ void Bot::throwExplosive_ () {
ignoreCollision ();
if (!isGrenadeWar () && pev->origin.distanceSq (dest) < cr::sqrf (450.0f)) {
if (!isGrenadeWar () && pev->origin.distanceSq (dest) < cr::sqrf (kGrenadeDamageRadius)) {
// heck, I don't wanna blow up myself
m_grenadeCheckTime = game.time () + kGrenadeCheckTime * 2.0f;
@ -1147,14 +1164,11 @@ void Bot::throwExplosive_ () {
auto grenade = setCorrectGrenadeVelocity (kExplosiveModelName);
if (game.isNullEntity (grenade)) {
if (m_currentWeapon != Weapon::Explosive && !m_grenadeRequested) {
if (m_currentWeapon != Weapon::Explosive) {
if (pev->weapons & cr::bit (Weapon::Explosive)) {
m_grenadeRequested = true;
selectWeaponById (Weapon::Explosive);
}
else {
m_grenadeRequested = false;
selectBestWeapon ();
completeTask ();
@ -1163,7 +1177,6 @@ void Bot::throwExplosive_ () {
}
else if (!(m_oldButtons & IN_ATTACK)) {
pev->button |= IN_ATTACK;
m_grenadeRequested = false;
}
}
}
@ -1187,7 +1200,7 @@ void Bot::throwFlashbang_ () {
ignoreCollision ();
if (pev->origin.distanceSq (dest) < cr::sqrf (450.0f)) {
if (pev->origin.distanceSq (dest) < cr::sqrf (kGrenadeDamageRadius)) {
m_grenadeCheckTime = game.time () + kGrenadeCheckTime * 2.0f; // heck, I don't wanna blow up myself
selectBestWeapon ();
@ -1213,14 +1226,11 @@ void Bot::throwFlashbang_ () {
auto grenade = setCorrectGrenadeVelocity (kFlashbangModelName);
if (game.isNullEntity (grenade)) {
if (m_currentWeapon != Weapon::Flashbang && !m_grenadeRequested) {
if (m_currentWeapon != Weapon::Flashbang) {
if (pev->weapons & cr::bit (Weapon::Flashbang)) {
m_grenadeRequested = true;
selectWeaponById (Weapon::Flashbang);
}
else {
m_grenadeRequested = false;
selectBestWeapon ();
completeTask ();
@ -1229,7 +1239,6 @@ void Bot::throwFlashbang_ () {
}
else if (!(m_oldButtons & IN_ATTACK)) {
pev->button |= IN_ATTACK;
m_grenadeRequested = false;
}
}
}
@ -1261,18 +1270,14 @@ void Bot::throwSmoke_ () {
return;
}
if (m_currentWeapon != Weapon::Smoke && !m_grenadeRequested) {
if (m_currentWeapon != Weapon::Smoke) {
m_aimFlags |= AimFlags::Grenade;
if (pev->weapons & cr::bit (Weapon::Smoke)) {
m_grenadeRequested = true;
selectWeaponById (Weapon::Smoke);
getTask ()->time = game.time () + kGrenadeCheckTime * 2.0f;
}
else {
m_grenadeRequested = false;
selectBestWeapon ();
completeTask ();
@ -1281,7 +1286,6 @@ void Bot::throwSmoke_ () {
}
else if (!(m_oldButtons & IN_ATTACK)) {
pev->button |= IN_ATTACK;
m_grenadeRequested = false;
}
pev->button |= m_campButtons;
}
@ -1439,7 +1443,7 @@ void Bot::shootBreakable_ () {
m_lookAtSafe = m_breakableOrigin;
// is bot facing the breakable?
if (util.getShootingCone (ent (), m_breakableOrigin) >= 0.90f) {
if (util.getConeDeviation (ent (), m_breakableOrigin) >= 0.90f) {
m_moveSpeed = 0.0f;
m_strafeSpeed = 0.0f;