From 2caa65f6ada55237fa655b13f0527c9d555aa6da Mon Sep 17 00:00:00 2001 From: jeefo Date: Sat, 9 Mar 2024 01:06:11 +0300 Subject: [PATCH] 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 --- .editorconfig | 2 +- ext/crlib | 2 +- ext/linkage | 2 +- inc/constant.h | 33 +++++++++++++++- inc/manager.h | 8 ++-- inc/support.h | 8 ++-- inc/yapb.h | 12 ++++-- src/botlib.cpp | 54 +++++++++++-------------- src/chatlib.cpp | 30 ++++---------- src/combat.cpp | 68 ++++++++++++++++++-------------- src/config.cpp | 58 ++++++++++++++------------- src/manager.cpp | 45 ++++++++++----------- src/support.cpp | 102 +++++++++++++++++++++++++----------------------- src/tasks.cpp | 50 +++++++++++++----------- 14 files changed, 253 insertions(+), 221 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9f12464..8de856c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,4 +7,4 @@ indent_size = 3 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file +insert_final_newline = true diff --git a/ext/crlib b/ext/crlib index 7f76e21..37d5927 160000 --- a/ext/crlib +++ b/ext/crlib @@ -1 +1 @@ -Subproject commit 7f76e21ddfbca7dd4f23e48d98d0620f29192900 +Subproject commit 37d592703b23c0762a3fc285d2841da11bb6d525 diff --git a/ext/linkage b/ext/linkage index 49b1311..b99f0ba 160000 --- a/ext/linkage +++ b/ext/linkage @@ -1 +1 @@ -Subproject commit 49b1311349cdb002c7630e6d00d62eb9f5bcd010 +Subproject commit b99f0bac831b823a1e5a57ef3bd7c7dcaf8dee22 diff --git a/inc/constant.h b/inc/constant.h index 6aa3133..5ef483e 100644 --- a/inc/constant.h +++ b/inc/constant.h @@ -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 (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; diff --git a/inc/manager.h b/inc/manager.h index daca54f..36518ee 100644 --- a/inc/manager.h +++ b/inc/manager.h @@ -24,9 +24,9 @@ public: using UniqueBot = UniquePtr ; 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 { private: - ThreadPool m_botWorker; + ThreadPool m_botWorker {}; public: explicit BotThreadWorker () = default; diff --git a/inc/support.h b/inc/support.h index 3826fc5..3d77a86 100644 --- a/inc/support.h +++ b/inc/support.h @@ -18,7 +18,7 @@ private: StringArray m_sentences {}; SmallArray m_clients {}; - HashMap m_weaponAlias {}; + HashMap 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)); } }; diff --git a/inc/yapb.h b/inc/yapb.h index 725cd3f..f991889 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -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 {}; diff --git a/src/botlib.cpp b/src/botlib.cpp index b4eef5e..233a078 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -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 (";"); - 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 (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 teammates; + static Array 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 (pev->button), static_cast (pev->impulse), msecVal); + engfuncs.pfnRunPlayerMove (pev->pContainingEntity, + getRpmAngles (), m_moveSpeed, m_strafeSpeed, + 0.0f, static_cast (pev->button), static_cast (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 () { diff --git a/src/chatlib.cpp b/src/chatlib.cpp index 726f8ed..c3498ac 100644 --- a/src/chatlib.cpp +++ b/src/chatlib.cpp @@ -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) { diff --git a/src/combat.cpp b/src/combat.cpp index 8d6ae64..29a0d46 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -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 users; + static Array 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 { diff --git a/src/config.cpp b/src/config.cpp index 96c7d7b..7c1377f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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 () { diff --git a/src/manager.cpp b/src/manager.cpp index b6f5f52..5d7c8c6 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -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; diff --git a/src/support.cpp b/src/support.cpp index 9866532..cd52f01 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -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; } diff --git a/src/tasks.cpp b/src/tasks.cpp index 1faa3ee..86544b0 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -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;