Merge pull request #40 from jeefo/develop

This commit is contained in:
jeefo 2016-12-09 22:13:36 +03:00 committed by GitHub
commit 66484293d5
9 changed files with 103 additions and 80 deletions

View file

@ -1313,7 +1313,7 @@ public:
int GetIndex (edict_t *ent); int GetIndex (edict_t *ent);
Bot *GetBot (int index); Bot *GetBot (int index);
Bot *GetBot (edict_t *ent); Bot *GetBot (edict_t *ent);
Bot *FindOneValidAliveBot (void); Bot *GetAliveBot (void);
Bot *GetHighestFragsBot (int team); Bot *GetHighestFragsBot (int team);
int GetHumansNum (void); int GetHumansNum (void);

View file

@ -30,7 +30,6 @@
#endif #endif
#ifdef ENABLE_SSE_INTRINSICS #ifdef ENABLE_SSE_INTRINSICS
#include <xmmintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
#endif #endif
@ -150,22 +149,23 @@ namespace Math
const float MATH_R2D = 180.0f / MATH_PI; const float MATH_R2D = 180.0f / MATH_PI;
#ifdef ENABLE_SSE_INTRINSICS #ifdef ENABLE_SSE_INTRINSICS
// //
// Function: mm_abs // Function: sse_abs
// //
// mm version if 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); return _mm_andnot_ps (_mm_castsi128_ps (_mm_set1_epi32 (0x80000000)), val);
}; };
// //
// Function: mm_sine // Function: sse_sine
// //
// mm version if 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 pi2 = _mm_set1_ps (MATH_PI * 2);
__m128 val = _mm_cmpnlt_ps (inp, _mm_set1_ps (MATH_PI)); __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_cmpngt_ps (inp, _mm_set1_ps (-MATH_PI));
val = _mm_and_ps (val, pi2); val = _mm_and_ps (val, pi2);
inp = _mm_add_ps (inp, val); 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)); val = _mm_add_ps (val, _mm_set1_ps (4.0f / MATH_PI));
__m128 res = _mm_mul_ps (val, inp); __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_sub_ps (val, res);
val = _mm_mul_ps (val, _mm_set1_ps (0.225f)); val = _mm_mul_ps (val, _mm_set1_ps (0.225f));
res = _mm_add_ps (val, res); res = _mm_add_ps (val, res);
@ -196,7 +196,7 @@ namespace Math
static inline float A_sqrtf (float value) static inline float A_sqrtf (float value)
{ {
#ifdef ENABLE_SSE_INTRINSICS #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 #else
return sqrtf (value); return sqrtf (value);
#endif #endif
@ -210,7 +210,7 @@ namespace Math
static inline float A_sinf (float value) static inline float A_sinf (float value)
{ {
#ifdef ENABLE_SSE_INTRINSICS #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 #else
return sinf (value); return sinf (value);
#endif #endif
@ -224,7 +224,7 @@ namespace Math
static inline float A_cosf (float value) static inline float A_cosf (float value)
{ {
#ifdef ENABLE_SSE_INTRINSICS #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 #else
return cosf (value); return cosf (value);
#endif #endif
@ -238,7 +238,7 @@ namespace Math
static inline void A_sincosf (float rad, float *sine, float *cosine) static inline void A_sincosf (float rad, float *sine, float *cosine)
{ {
#ifdef ENABLE_SSE_INTRINSICS #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)); __m128 m_cos = _mm_shuffle_ps (m_sincos, m_sincos, _MM_SHUFFLE (0, 0, 0, 1));
*sine = _mm_cvtss_f32 (m_sincos); *sine = _mm_cvtss_f32 (m_sincos);

View file

@ -3025,7 +3025,7 @@ void Bot::RunTask_Normal (void)
} }
// bots rushing with knife, when have no enemy (thanks for idea to nicebot project) // 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) if (Random.Int (0, 100) < 40)
pev->button |= IN_ATTACK; pev->button |= IN_ATTACK;
@ -3137,14 +3137,17 @@ void Bot::RunTask_Normal (void)
m_hostages[i] = nullptr; // clear array of hostage pointers 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); 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_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 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; m_campButtons |= IN_DUCK;
else else
m_campButtons &= ~IN_DUCK; 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_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 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) auto path = waypoints.GetPath (index);
m_campButtons |= IN_DUCK;
else // decide to duck or not to duck
m_campButtons &= ~IN_DUCK; if (path->vis.crouch <= path->vis.stand)
m_campButtons |= IN_DUCK;
else
m_campButtons &= ~IN_DUCK;
ChatterMessage (Chatter_DefendingBombSite); // play info about that 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 // do pathfinding if it's not the current waypoint
if (destIndex != m_currentWaypointIndex) 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 else
{ {
@ -5867,14 +5873,6 @@ bool Bot::OutOfBombTimer (void)
void Bot::ReactOnSound (void) void Bot::ReactOnSound (void)
{ {
int hearEnemyIndex = -1; 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 <float *> (&pasOrg));
float minDistance = 99999.0f; float minDistance = 99999.0f;
// loop through all enemy clients to check for hearable stuff // loop through all enemy clients to check for hearable stuff
@ -5890,9 +5888,6 @@ void Bot::ReactOnSound (void)
if (distance > client.hearingDistance) if (distance > client.hearingDistance)
continue; continue;
if (!ENGINE_CHECK_VISIBILITY (client.ent, pas))
continue;
if (distance < minDistance) if (distance < minDistance)
{ {
hearEnemyIndex = i; hearEnemyIndex = i;

View file

@ -238,14 +238,6 @@ bool Bot::LookupEnemy (void)
// ignore shielded enemies, while we have real one // ignore shielded enemies, while we have real one
edict_t *shieldEnemy = nullptr; 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 <float *> (&potentialVisibility));
// search the world for players... // search the world for players...
for (int i = 0; i < engine.MaxClients (); i++) for (int i = 0; i < engine.MaxClients (); i++)
{ {
@ -256,10 +248,6 @@ bool Bot::LookupEnemy (void)
player = client.ent; 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 // do some blind by smoke grenade
if (m_blindRecognizeTime < engine.Time () && IsBehindSmokeClouds (player)) if (m_blindRecognizeTime < engine.Time () && IsBehindSmokeClouds (player))
{ {
@ -970,7 +958,7 @@ bool Bot::IsWeaponBadInDistance (int weaponIndex, float distance)
int wid = g_weaponSelect[weaponIndex].id; int wid = g_weaponSelect[weaponIndex].id;
if (wid == WEAPON_KNIFE) if (wid == WEAPON_KNIFE)
return false; return false;
// check is ammo available for secondary weapon // check is ammo available for secondary weapon
if (m_ammoInClip[g_weaponSelect[GetBestSecondaryWeaponCarried ()].id] >= 1) if (m_ammoInClip[g_weaponSelect[GetBestSecondaryWeaponCarried ()].id] >= 1)

View file

@ -969,7 +969,7 @@ void Engine::ProcessMessageCapture (void *ptr)
if (yb_communication_type.GetInt () == 2) if (yb_communication_type.GetInt () == 2)
{ {
Bot *notify = bots.FindOneValidAliveBot (); Bot *notify = bots.GetAliveBot ();
if (notify != nullptr && notify->m_notKilled) if (notify != nullptr && notify->m_notKilled)
notify->HandleChatterMessage (strVal); notify->HandleChatterMessage (strVal);
@ -988,7 +988,7 @@ void Engine::ProcessMessageCapture (void *ptr)
if (yb_communication_type.GetInt () == 2) if (yb_communication_type.GetInt () == 2)
{ {
Bot *notify = bots.FindOneValidAliveBot (); Bot *notify = bots.GetAliveBot ();
if (notify != nullptr && notify->m_notKilled) if (notify != nullptr && notify->m_notKilled)
notify->HandleChatterMessage (strVal); notify->HandleChatterMessage (strVal);
@ -1069,6 +1069,7 @@ void Engine::ProcessMessageCapture (void *ptr)
m_msgBlock.state++; // and finally update network message state 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) 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); engine.PushVariableToStack (name, initval, type, regMissing, regVal, this);

View file

@ -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 // 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. // 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 (index);
Bot *bot = bots.GetBot (i);
// check if its a bot // 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 (index);
bot->EnableChatterIcon (false);
bots.Free (i);
}
} }
bots.AdjustQuota (false, ent);
if (g_gameFlags & GAME_METAMOD) if (g_gameFlags & GAME_METAMOD)
RETURN_META (MRES_IGNORED); RETURN_META (MRES_IGNORED);

View file

@ -10,7 +10,7 @@
#include <core.h> #include <core.h>
ConVar yb_autovacate ("yb_autovacate", "1"); 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 ("yb_quota", "0", VT_NORMAL);
ConVar yb_quota_mode ("yb_quota_mode", "normal"); ConVar yb_quota_mode ("yb_quota_mode", "normal");
@ -275,7 +275,7 @@ Bot *BotManager::GetBot (edict_t *ent)
return GetBot (GetIndex (ent)); return GetBot (GetIndex (ent));
} }
Bot *BotManager::FindOneValidAliveBot (void) Bot *BotManager::GetAliveBot (void)
{ {
// this function finds one bot, alive bot :) // 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); 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 // 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; return;
if (isPlayerConnection) if (isPlayerConnecting)
{ {
if (yb_autovacate_smart_kick.GetBool ()) if (yb_autovacate_smart_kick.GetBool ())
AddPlayerToCheckTeamQueue (ent); AddPlayerToCheckTeamQueue (ent);
@ -368,9 +368,11 @@ void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent)
{ {
RemoveRandom (); RemoveRandom ();
m_balanceCount--; m_balanceCount--;
m_quotaMaintainTime = engine.Time () + 2.0f;
} }
} }
else if (m_balanceCount <= 0) else if (m_balanceCount < 0)
{ {
AddRandom (); AddRandom ();
m_balanceCount++; m_balanceCount++;
@ -379,6 +381,9 @@ void BotManager::AdjustQuota (bool isPlayerConnection, edict_t *ent)
void BotManager::AddPlayerToCheckTeamQueue (edict_t *ent) void BotManager::AddPlayerToCheckTeamQueue (edict_t *ent)
{ {
if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || IsValidBot (ent))
return;
// entity must be unique // entity must be unique
bool hasFound = false; bool hasFound = false;
@ -397,7 +402,7 @@ void BotManager::AddPlayerToCheckTeamQueue (edict_t *ent)
void BotManager::VerifyPlayersHasJoinedTeam (int &desiredCount) void BotManager::VerifyPlayersHasJoinedTeam (int &desiredCount)
{ {
if (m_trackedPlayers.IsEmpty ()) if (!engine.IsDedicatedServer () || !yb_autovacate.GetBool () || m_trackedPlayers.IsEmpty ())
return; return;
for (int i = 0; i < engine.MaxClients (); i++) for (int i = 0; i < engine.MaxClients (); i++)
@ -472,21 +477,23 @@ void BotManager::MaintainBotQuota (void)
} }
int numBots = GetBotsNum (); int numBots = GetBotsNum ();
int numHumans = yb_autovacate_smart_kick.GetBool () ? GetHumansNum () : GetHumansJoinedTeam (); int numHumans = GetHumansNum ();
int desiredCount = yb_quota.GetInt (); int desiredCount = yb_quota.GetInt ();
if (yb_join_after_player.GetBool () && !numHumans) if (yb_join_after_player.GetBool () && !numHumans)
desiredCount = 0; desiredCount = 0;
int numHumansOnTeam = yb_autovacate_smart_kick.GetBool () ? GetHumansJoinedTeam () : numHumans;
// quota mode // quota mode
char mode = yb_quota_mode.GetString ()[0]; char mode = yb_quota_mode.GetString ()[0];
if (mode == 'f' || mode == 'F') // fill 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 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) if (yb_autovacate_smart_kick.GetBool () && numBots > 1 && desiredCount > 1)
VerifyPlayersHasJoinedTeam (desiredCount); VerifyPlayersHasJoinedTeam (desiredCount);
@ -1033,9 +1040,7 @@ Bot::~Bot (void)
{ {
// this is bot destructor // this is bot destructor
EnableChatterIcon (false);
ReleaseUsedName (); ReleaseUsedName ();
DeleteSearchNodes (); DeleteSearchNodes ();
ResetTasks (); ResetTasks ();
} }
@ -1082,7 +1087,7 @@ int BotManager::GetHumansJoinedTeam (void)
{ {
const Client &client = g_clients[i]; 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++; count++;
} }
return count; return count;
@ -1290,7 +1295,7 @@ void Bot::NewRound (void)
m_defendHostage = false; m_defendHostage = false;
m_headedTime = 0.0f; 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_spawnTime = engine.Time ();
m_lastChatTime = engine.Time (); m_lastChatTime = engine.Time ();
@ -1331,11 +1336,16 @@ void Bot::Kick (bool keepQuota)
{ {
// this function kick off one bot from the server. // 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 // clear fakeclient bit immediately
pev->flags &= ~FL_FAKECLIENT; pev->flags &= ~FL_FAKECLIENT;
engine.IssueCmd ("kick \"%s\"", STRING (pev->netname)); engine.IssueCmd ("kick \"%s\"", username);
engine.CenterPrintf ("Bot '%s' kicked", STRING (pev->netname)); engine.CenterPrintf ("Bot '%s' kicked", username);
// keep quota number up to date // keep quota number up to date
if (!keepQuota) if (!keepQuota)

View file

@ -626,7 +626,7 @@ void Bot::CheckTerrain (float movedDistance, const Vector &dirNormal)
if (IsOnFloor () || IsInWater ()) if (IsOnFloor () || IsInWater ())
{ {
pev->button |= IN_JUMP; pev->button |= IN_JUMP;
m_jumpStateTimer = Random.Float (1.0f, 2.0f); m_jumpStateTimer = Random.Float (2.0f, 3.0f);
} }
break; break;
@ -1150,7 +1150,6 @@ bool Bot::DoWaypointNav (void)
m_lastEnemy = ent; m_lastEnemy = ent;
m_enemy = ent; m_enemy = ent;
m_lastEnemyOrigin = ent->v.origin; m_lastEnemyOrigin = ent->v.origin;
} }
else if (IsValidPlayer (ent) && IsAlive (ent) && m_team == engine.GetTeam (ent)) else if (IsValidPlayer (ent) && IsAlive (ent) && m_team == engine.GetTeam (ent))
{ {
@ -1193,7 +1192,7 @@ bool Bot::DoWaypointNav (void)
if (waypointDistance < desiredDistance) if (waypointDistance < desiredDistance)
{ {
// Did we reach a destination Waypoint? // did we reach a destination waypoint?
if (GetTask ()->data == m_currentWaypointIndex) if (GetTask ()->data == m_currentWaypointIndex)
{ {
// add goal values // add goal values
@ -1247,7 +1246,7 @@ bool Bot::DoWaypointNav (void)
{ {
float distance = (bombOrigin - waypoints.GetPath (taskTarget)->origin).GetLength (); 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)) if (Random.Int (0, 100) < 50 && !waypoints.IsGoalVisited (taskTarget))
RadioMessage (Radio_SectorClear); RadioMessage (Radio_SectorClear);
@ -2427,8 +2426,10 @@ bool Bot::HeadTowardWaypoint (void)
GetBestNextWaypoint (); GetBestNextWaypoint ();
m_minSpeed = pev->maxspeed; m_minSpeed = pev->maxspeed;
TaskID taskID = GetTaskId ();
// only if we in normal task and bomb is not planted // 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; m_campButtons = 0;
@ -2467,6 +2468,24 @@ bool Bot::HeadTowardWaypoint (void)
else if (Random.Int (1, 100) > m_difficulty * 25) else if (Random.Int (1, 100) > m_difficulty * 25)
m_minSpeed = GetWalkSpeed (); 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) 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; int occupyId = GetShootingConeDeviation (bot->GetEntity (), &pev->origin) >= 0.7f ? bot->m_prevWptIndex[0] : m_currentWaypointIndex;
if (index == occupyId)
return true;
// length check // length check
float length = (waypoints.GetPath (occupyId)->origin - waypoints.GetPath (index)->origin).GetLengthSquared (); 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; return true;
} }
} }

View file

@ -722,6 +722,10 @@ void SoundAttachToClients (edict_t *ent, const char *sample, float volume)
return; return;
const Vector &origin = engine.GetAbsOrigin (ent); const Vector &origin = engine.GetAbsOrigin (ent);
if (origin.IsZero ())
return;
int index = engine.IndexOfEntity (ent) - 1; int index = engine.IndexOfEntity (ent) - 1;
if (index < 0 || index >= engine.MaxClients ()) if (index < 0 || index >= engine.MaxClients ())