diff --git a/include/core.h b/include/core.h index 966a79d..c2f21ed 100644 --- a/include/core.h +++ b/include/core.h @@ -1313,7 +1313,7 @@ public: int GetIndex (edict_t *ent); Bot *GetBot (int index); Bot *GetBot (edict_t *ent); - Bot *FindOneValidAliveBot (void); + Bot *GetAliveBot (void); Bot *GetHighestFragsBot (int team); int GetHumansNum (void); diff --git a/include/corelib.h b/include/corelib.h index 2a9cb3c..6650dc9 100644 --- a/include/corelib.h +++ b/include/corelib.h @@ -30,7 +30,6 @@ #endif #ifdef ENABLE_SSE_INTRINSICS -#include #include #endif @@ -150,22 +149,23 @@ namespace Math const float MATH_R2D = 180.0f / MATH_PI; #ifdef ENABLE_SSE_INTRINSICS + // - // Function: mm_abs + // Function: sse_abs // // mm version if abs // - static inline __m128 mm_abs (__m128 val) + static inline __m128 sse_abs (__m128 val) { return _mm_andnot_ps (_mm_castsi128_ps (_mm_set1_epi32 (0x80000000)), val); }; // - // Function: mm_sine + // Function: sse_sine // // mm version if sine // - static inline __m128 mm_sine (__m128 inp) + static inline __m128 sse_sine (__m128 inp) { __m128 pi2 = _mm_set1_ps (MATH_PI * 2); __m128 val = _mm_cmpnlt_ps (inp, _mm_set1_ps (MATH_PI)); @@ -175,12 +175,12 @@ namespace Math val = _mm_cmpngt_ps (inp, _mm_set1_ps (-MATH_PI)); val = _mm_and_ps (val, pi2); inp = _mm_add_ps (inp, val); - val = _mm_mul_ps (mm_abs (inp), _mm_set1_ps (-4.0f / (MATH_PI * MATH_PI))); + val = _mm_mul_ps (sse_abs (inp), _mm_set1_ps (-4.0f / (MATH_PI * MATH_PI))); val = _mm_add_ps (val, _mm_set1_ps (4.0f / MATH_PI)); __m128 res = _mm_mul_ps (val, inp); - val = _mm_mul_ps (mm_abs (res), res); + val = _mm_mul_ps (sse_abs (res), res); val = _mm_sub_ps (val, res); val = _mm_mul_ps (val, _mm_set1_ps (0.225f)); res = _mm_add_ps (val, res); @@ -196,7 +196,7 @@ namespace Math static inline float A_sqrtf (float value) { #ifdef ENABLE_SSE_INTRINSICS - return _mm_cvtss_f32 (_mm_sqrt_ss (_mm_load_ss (&value))); + return _mm_cvtss_f32 (_mm_sqrt_ss (_mm_set1_ps (value))); #else return sqrtf (value); #endif @@ -210,7 +210,7 @@ namespace Math static inline float A_sinf (float value) { #ifdef ENABLE_SSE_INTRINSICS - return _mm_cvtss_f32 (mm_sine (_mm_set1_ps (value))); + return _mm_cvtss_f32 (sse_sine (_mm_set1_ps (value))); #else return sinf (value); #endif @@ -224,7 +224,7 @@ namespace Math static inline float A_cosf (float value) { #ifdef ENABLE_SSE_INTRINSICS - return _mm_cvtss_f32 (mm_sine (_mm_set1_ps (value + MATH_PI / 2.0f))); + return _mm_cvtss_f32 (sse_sine (_mm_set1_ps (value + MATH_PI / 2.0f))); #else return cosf (value); #endif @@ -238,7 +238,7 @@ namespace Math static inline void A_sincosf (float rad, float *sine, float *cosine) { #ifdef ENABLE_SSE_INTRINSICS - __m128 m_sincos = mm_sine (_mm_set_ps (0.0f, 0.0f, rad + MATH_PI / 2.f, rad)); + __m128 m_sincos = sse_sine (_mm_set_ps (0.0f, 0.0f, rad + MATH_PI / 2.f, rad)); __m128 m_cos = _mm_shuffle_ps (m_sincos, m_sincos, _MM_SHUFFLE (0, 0, 0, 1)); *sine = _mm_cvtss_f32 (m_sincos); diff --git a/source/basecode.cpp b/source/basecode.cpp index 9faae37..2e0d1f1 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -3025,7 +3025,7 @@ void Bot::RunTask_Normal (void) } // bots rushing with knife, when have no enemy (thanks for idea to nicebot project) - if (m_currentWeapon == WEAPON_KNIFE && (engine.IsNullEntity (m_lastEnemy) || !IsAlive (m_lastEnemy)) && engine.IsNullEntity (m_enemy) && m_knifeAttackTime < engine.Time () && !HasShield () && GetNearbyFriendsNearPosition (pev->origin, 96) == 0) + if (m_currentWeapon == WEAPON_KNIFE && (engine.IsNullEntity (m_lastEnemy) || !IsAlive (m_lastEnemy)) && engine.IsNullEntity (m_enemy) && m_knifeAttackTime < engine.Time () && !HasShield () && GetNearbyFriendsNearPosition (pev->origin, 96.0f) == 0) { if (Random.Int (0, 100) < 40) pev->button |= IN_ATTACK; @@ -3137,14 +3137,17 @@ void Bot::RunTask_Normal (void) m_hostages[i] = nullptr; // clear array of hostage pointers } } - else if (m_team == TERRORIST && Random.Int (0, 100) < 80) + else if (m_team == TERRORIST && Random.Int (0, 100) < 75) { int index = FindDefendWaypoint (m_currentPath->origin); PushTask (TASK_CAMP, TASKPRI_CAMP, -1, engine.Time () + Random.Float (60.0f, 120.0f), true); // push camp task on to stack PushTask (TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, index, engine.Time () + Random.Float (5.0f, 10.0f), true); // push move command - if (waypoints.GetPath (index)->vis.crouch <= waypoints.GetPath (index)->vis.stand) + auto path = waypoints.GetPath (index); + + // decide to duck or not to duck + if (path->vis.crouch <= path->vis.stand) m_campButtons |= IN_DUCK; else m_campButtons &= ~IN_DUCK; @@ -3183,10 +3186,13 @@ void Bot::RunTask_Normal (void) PushTask (TASK_CAMP, TASKPRI_CAMP, -1, engine.Time () + campTime, true); // push camp task on to stack PushTask (TASK_MOVETOPOSITION, TASKPRI_MOVETOPOSITION, index, engine.Time () + Random.Float (5.0f, 11.0f), true); // push move command - if (waypoints.GetPath (index)->vis.crouch <= waypoints.GetPath (index)->vis.stand) - m_campButtons |= IN_DUCK; - else - m_campButtons &= ~IN_DUCK; + auto path = waypoints.GetPath (index); + + // decide to duck or not to duck + if (path->vis.crouch <= path->vis.stand) + m_campButtons |= IN_DUCK; + else + m_campButtons &= ~IN_DUCK; ChatterMessage (Chatter_DefendingBombSite); // play info about that } @@ -3211,7 +3217,7 @@ void Bot::RunTask_Normal (void) // do pathfinding if it's not the current waypoint if (destIndex != m_currentWaypointIndex) - FindPath (m_currentWaypointIndex, destIndex, ((g_bombPlanted && m_team == CT) || yb_debug_goal.GetInt () != -1) ? SEARCH_PATH_FASTEST : m_pathType); + FindPath (m_currentWaypointIndex, destIndex, m_pathType); } else { @@ -5867,14 +5873,6 @@ bool Bot::OutOfBombTimer (void) void Bot::ReactOnSound (void) { int hearEnemyIndex = -1; - - Vector pasOrg = EyePosition (); - - if (pev->flags & FL_DUCKING) - pasOrg = pasOrg + (VEC_HULL_MIN - VEC_DUCK_HULL_MIN); - - uint8 *pas = ENGINE_SET_PAS (reinterpret_cast (&pasOrg)); - float minDistance = 99999.0f; // loop through all enemy clients to check for hearable stuff @@ -5890,9 +5888,6 @@ void Bot::ReactOnSound (void) if (distance > client.hearingDistance) continue; - if (!ENGINE_CHECK_VISIBILITY (client.ent, pas)) - continue; - if (distance < minDistance) { hearEnemyIndex = i; diff --git a/source/combat.cpp b/source/combat.cpp index bcab996..97d13e1 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -238,14 +238,6 @@ bool Bot::LookupEnemy (void) // ignore shielded enemies, while we have real one edict_t *shieldEnemy = nullptr; - // setup potentially visible set for this bot - Vector potentialVisibility = EyePosition (); - - if (pev->flags & FL_DUCKING) - potentialVisibility = potentialVisibility + (VEC_HULL_MIN - VEC_DUCK_HULL_MIN); - - uint8 *pvs = ENGINE_SET_PVS (reinterpret_cast (&potentialVisibility)); - // search the world for players... for (int i = 0; i < engine.MaxClients (); i++) { @@ -256,10 +248,6 @@ bool Bot::LookupEnemy (void) player = client.ent; - // let the engine check if this player is potentially visible - if (!ENGINE_CHECK_VISIBILITY (player, pvs)) - continue; - // do some blind by smoke grenade if (m_blindRecognizeTime < engine.Time () && IsBehindSmokeClouds (player)) { @@ -970,7 +958,7 @@ bool Bot::IsWeaponBadInDistance (int weaponIndex, float distance) int wid = g_weaponSelect[weaponIndex].id; if (wid == WEAPON_KNIFE) - return false; + return false; // check is ammo available for secondary weapon if (m_ammoInClip[g_weaponSelect[GetBestSecondaryWeaponCarried ()].id] >= 1) diff --git a/source/engine.cpp b/source/engine.cpp index 89389c7..203abc5 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -969,7 +969,7 @@ void Engine::ProcessMessageCapture (void *ptr) if (yb_communication_type.GetInt () == 2) { - Bot *notify = bots.FindOneValidAliveBot (); + Bot *notify = bots.GetAliveBot (); if (notify != nullptr && notify->m_notKilled) notify->HandleChatterMessage (strVal); @@ -988,7 +988,7 @@ void Engine::ProcessMessageCapture (void *ptr) if (yb_communication_type.GetInt () == 2) { - Bot *notify = bots.FindOneValidAliveBot (); + Bot *notify = bots.GetAliveBot (); if (notify != nullptr && notify->m_notKilled) notify->HandleChatterMessage (strVal); @@ -1069,6 +1069,7 @@ void Engine::ProcessMessageCapture (void *ptr) m_msgBlock.state++; // and finally update network message state } +// console var registrator ConVar::ConVar (const char *name, const char *initval, VarType type, bool regMissing, const char *regVal) : m_eptr (nullptr) { engine.PushVariableToStack (name, initval, type, regMissing, regVal, this); diff --git a/source/interface.cpp b/source/interface.cpp index b191f81..308e6e9 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -1119,24 +1119,21 @@ void ClientDisconnect (edict_t *ent) // to reset his entity pointer for safety. There are still a few server frames to go once a // listen server client disconnects, and we don't want to send him any sort of message then. - bots.AdjustQuota (false, ent); + int index = engine.IndexOfEntity (ent) - 1; - int i = engine.IndexOfEntity (ent) - 1; + InternalAssert (index >= 0 && index < MAX_ENGINE_PLAYERS); - InternalAssert (i >= 0 && i < MAX_ENGINE_PLAYERS); - - Bot *bot = bots.GetBot (i); + Bot *bot = bots.GetBot (index); // check if its a bot - if (bot != nullptr) + if (bot != nullptr && bot->pev == &ent->v) { - if (bot->pev == &ent->v) - { - bot->EnableChatterIcon (false); - bots.Free (i); - } + bot->EnableChatterIcon (false); + bots.Free (index); } + bots.AdjustQuota (false, ent); + if (g_gameFlags & GAME_METAMOD) RETURN_META (MRES_IGNORED); diff --git a/source/manager.cpp b/source/manager.cpp index 7ea451e..a8be448 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -10,7 +10,7 @@ #include ConVar yb_autovacate ("yb_autovacate", "1"); -ConVar yb_autovacate_smart_kick ("yb_autovacate_smart_kick", "0"); +ConVar yb_autovacate_smart_kick ("yb_autovacate_smart_kick", "1"); ConVar yb_quota ("yb_quota", "0", VT_NORMAL); ConVar yb_quota_mode ("yb_quota_mode", "normal"); @@ -275,7 +275,7 @@ Bot *BotManager::GetBot (edict_t *ent) return GetBot (GetIndex (ent)); } -Bot *BotManager::FindOneValidAliveBot (void) +Bot *BotManager::GetAliveBot (void) { // this function finds one bot, alive bot :) @@ -353,14 +353,14 @@ void BotManager::AddBot (const String &name, const String &difficulty, const Str m_creationTab.Push (bot); } -void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent) +void BotManager::AdjustQuota (bool isPlayerConnecting, edict_t *ent) { // this function increases or decreases bot quota amount depending on auto vacate variables - if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || GetBot (ent)) + if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || IsValidBot (ent)) return; - if (isPlayerConnection) + if (isPlayerConnecting) { if (yb_autovacate_smart_kick.GetBool ()) AddPlayerToCheckTeamQueue (ent); @@ -368,9 +368,11 @@ void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent) { RemoveRandom (); m_balanceCount--; + + m_quotaMaintainTime = engine.Time () + 2.0f; } } - else if (m_balanceCount <= 0) + else if (m_balanceCount < 0) { AddRandom (); m_balanceCount++; @@ -379,6 +381,9 @@ void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent) void BotManager::AddPlayerToCheckTeamQueue (edict_t *ent) { + if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || IsValidBot (ent)) + return; + // entity must be unique bool hasFound = false; @@ -397,7 +402,7 @@ void BotManager::AddPlayerToCheckTeamQueue (edict_t *ent) void BotManager::VerifyPlayersHasJoinedTeam (int &desiredCount) { - if (m_trackedPlayers.IsEmpty ()) + if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || m_trackedPlayers.IsEmpty ()) return; for (int i = 0; i < engine.MaxClients (); i++) @@ -472,21 +477,23 @@ void BotManager::MaintainBotQuota (void) } int numBots = GetBotsNum (); - int numHumans = yb_autovacate_smart_kick.GetBool () ? GetHumansNum () : GetHumansJoinedTeam (); + int numHumans = GetHumansNum (); int desiredCount = yb_quota.GetInt (); if (yb_join_after_player.GetBool () && !numHumans) desiredCount = 0; + int numHumansOnTeam = yb_autovacate_smart_kick.GetBool () ? GetHumansJoinedTeam () : numHumans; + // quota mode char mode = yb_quota_mode.GetString ()[0]; if (mode == 'f' || mode == 'F') // fill - desiredCount = A_max (0, desiredCount - numHumans); + desiredCount = A_max (0, desiredCount - numHumansOnTeam); else if (mode == 'm' || mode == 'M') // match - desiredCount = A_max (0, yb_quota.GetInt () * numHumans); + desiredCount = A_max (0, yb_quota.GetInt () * numHumansOnTeam); - desiredCount = A_min (desiredCount, engine.MaxClients () - (numHumans + (yb_autovacate.GetBool () ? 1 : 0))); + desiredCount = A_min (desiredCount, engine.MaxClients () - (numHumansOnTeam + (yb_autovacate.GetBool () ? 1 : 0))); if (yb_autovacate_smart_kick.GetBool () && numBots > 1 && desiredCount > 1) VerifyPlayersHasJoinedTeam (desiredCount); @@ -1033,9 +1040,7 @@ Bot::~Bot (void) { // this is bot destructor - EnableChatterIcon (false); ReleaseUsedName (); - DeleteSearchNodes (); ResetTasks (); } @@ -1082,7 +1087,7 @@ int BotManager::GetHumansJoinedTeam (void) { const Client &client = g_clients[i]; - if ((client.flags & (CF_USED | CF_ALIVE)) && m_bots[i] == nullptr && client.team != SPECTATOR && !(client.ent->v.flags & FL_FAKECLIENT) && client.ent->v.movetype != MOVETYPE_FLY) + if ((client.flags & (CF_USED | CF_ALIVE)) && m_bots[i] == nullptr && client.team != SPECTATOR && !(client.ent->v.flags & FL_FAKECLIENT)) count++; } return count; @@ -1290,7 +1295,7 @@ void Bot::NewRound (void) m_defendHostage = false; m_headedTime = 0.0f; - m_timeLogoSpray = engine.Time () + Random.Float (0.5f, 2.0f); + m_timeLogoSpray = engine.Time () + Random.Float (5.0f, 30.0f); m_spawnTime = engine.Time (); m_lastChatTime = engine.Time (); @@ -1331,11 +1336,16 @@ void Bot::Kick (bool keepQuota) { // this function kick off one bot from the server. + auto username = STRING (pev->netname); + + if (!(pev->flags & FL_FAKECLIENT) || IsNullString (username)) + return; + // clear fakeclient bit immediately pev->flags &= ~FL_FAKECLIENT; - engine.IssueCmd ("kick \"%s\"", STRING (pev->netname)); - engine.CenterPrintf ("Bot '%s' kicked", STRING (pev->netname)); + engine.IssueCmd ("kick \"%s\"", username); + engine.CenterPrintf ("Bot '%s' kicked", username); // keep quota number up to date if (!keepQuota) diff --git a/source/navigate.cpp b/source/navigate.cpp index 64688da..d701081 100644 --- a/source/navigate.cpp +++ b/source/navigate.cpp @@ -626,7 +626,7 @@ void Bot::CheckTerrain (float movedDistance, const Vector &dirNormal) if (IsOnFloor () || IsInWater ()) { pev->button |= IN_JUMP; - m_jumpStateTimer = Random.Float (1.0f, 2.0f); + m_jumpStateTimer = Random.Float (2.0f, 3.0f); } break; @@ -1150,7 +1150,6 @@ bool Bot::DoWaypointNav (void) m_lastEnemy = ent; m_enemy = ent; m_lastEnemyOrigin = ent->v.origin; - } else if (IsValidPlayer (ent) && IsAlive (ent) && m_team == engine.GetTeam (ent)) { @@ -1193,7 +1192,7 @@ bool Bot::DoWaypointNav (void) if (waypointDistance < desiredDistance) { - // Did we reach a destination Waypoint? + // did we reach a destination waypoint? if (GetTask ()->data == m_currentWaypointIndex) { // add goal values @@ -1247,7 +1246,7 @@ bool Bot::DoWaypointNav (void) { float distance = (bombOrigin - waypoints.GetPath (taskTarget)->origin).GetLength (); - if (distance > 512.0) + if (distance > 512.0f) { if (Random.Int (0, 100) < 50 && !waypoints.IsGoalVisited (taskTarget)) RadioMessage (Radio_SectorClear); @@ -2427,8 +2426,10 @@ bool Bot::HeadTowardWaypoint (void) GetBestNextWaypoint (); m_minSpeed = pev->maxspeed; + TaskID taskID = GetTaskId (); + // only if we in normal task and bomb is not planted - if (GetTaskId () == TASK_NORMAL && g_timeRoundMid + 5.0f < engine.Time () && m_timeCamping + 5.0f < engine.Time () && !g_bombPlanted && m_personality != PERSONALITY_RUSHER && !m_hasC4 && !m_isVIP && m_loosedBombWptIndex == -1 && !HasHostage ()) + if (taskID == TASK_NORMAL && g_timeRoundMid + 5.0f < engine.Time () && m_timeCamping + 5.0f < engine.Time () && !g_bombPlanted && m_personality != PERSONALITY_RUSHER && !m_hasC4 && !m_isVIP && m_loosedBombWptIndex == -1 && !HasHostage ()) { m_campButtons = 0; @@ -2467,6 +2468,24 @@ bool Bot::HeadTowardWaypoint (void) else if (Random.Int (1, 100) > m_difficulty * 25) m_minSpeed = GetWalkSpeed (); } + + // force terrorist bot to plant bomb + if (taskID == TASK_NORMAL && m_inBombZone && !m_hasProgressBar && m_hasC4) + { + int newGoal = FindGoal (); + + m_prevGoalIndex = newGoal; + m_chosenGoalIndex = newGoal; + + // remember index + GetTask ()->data = newGoal; + + // do path finding if it's not the current waypoint + if (newGoal != m_currentWaypointIndex) + FindPath (m_currentWaypointIndex, newGoal, m_pathType); + + return false; + } } } @@ -3373,12 +3392,21 @@ bool Bot::IsPointOccupied (int index) if (bot->m_notKilled && m_currentWaypointIndex != -1 && bot->m_prevWptIndex[0] != -1) { + int targetId = bot->GetTask ()->data; + + if (index == targetId) + return true; + + // check bot's current waypoint int occupyId = GetShootingConeDeviation (bot->GetEntity (), &pev->origin) >= 0.7f ? bot->m_prevWptIndex[0] : m_currentWaypointIndex; + if (index == occupyId) + return true; + // length check float length = (waypoints.GetPath (occupyId)->origin - waypoints.GetPath (index)->origin).GetLengthSquared (); - if (occupyId == index || bot->GetTask ()->data == index || length < GET_SQUARE (64.0f)) + if (length < GET_SQUARE (128.0f)) return true; } } diff --git a/source/support.cpp b/source/support.cpp index 8c7d93c..7583b2a 100644 --- a/source/support.cpp +++ b/source/support.cpp @@ -722,6 +722,10 @@ void SoundAttachToClients (edict_t *ent, const char *sample, float volume) return; const Vector &origin = engine.GetAbsOrigin (ent); + + if (origin.IsZero ()) + return; + int index = engine.IndexOfEntity (ent) - 1; if (index < 0 || index >= engine.MaxClients ())