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:
parent
a94886f8f7
commit
2caa65f6ad
14 changed files with 253 additions and 221 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 7f76e21ddfbca7dd4f23e48d98d0620f29192900
|
||||
Subproject commit 37d592703b23c0762a3fc285d2841da11bb6d525
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 49b1311349cdb002c7630e6d00d62eb9f5bcd010
|
||||
Subproject commit b99f0bac831b823a1e5a57ef3bd7c7dcaf8dee22
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
12
inc/yapb.h
12
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 {};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
102
src/support.cpp
102
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue