Example #1
0
bool Bot::LookupEnemy (void)
{
   // this function tries to find the best suitable enemy for the bot
   m_visibility = 0;

   // SyPB Pro P.1
   if (m_enemy != null && (GetTeam (GetEntity ()) == GetTeam (m_enemy) || Attack_Invisible(m_enemy)))
   {
   	   m_enemy = null;
   	   return false;
   }

   // SyPB Pro P.4
   if (GetEnemyEntity ())
   	   return true;

   // do not search for enemies while we're blinded, or shooting disabled by user
   if (m_blindTime > engine->GetTime () || sypb_noshots.GetBool ())
      return false;

   // do not check for new enemy too fast
   if (!FNullEnt (m_enemy) && m_enemyUpdateTime > engine->GetTime () && !(m_states & STATE_SUSPECTENEMY))
   {
      m_aimFlags |= AIM_ENEMY;
      return true;
   }
   edict_t *player, *newEnemy = null;

   float nearestDistance = m_viewDistance;
   int i, team = GetTeam (GetEntity ());

   // 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_t *pvs = ENGINE_SET_PVS (reinterpret_cast <float *> (&potentialVisibility));

   // clear suspected flag
   if (m_seeEnemyTime + 4.0f < engine->GetTime ())
      m_states &= ~STATE_SUSPECTENEMY;

   if (!FNullEnt (m_enemy))
   {
      player = m_enemy;

      // is player is alive
      if (IsAlive (player) && IsEnemyViewable (player))
         newEnemy = player;
   }

   // the old enemy is no longer visible or
   if (FNullEnt (newEnemy))
   {
      m_enemyUpdateTime = engine->GetTime () + 0.25f;

      // some shield stuff
      Array <edict_t *> enemies;

      // search the world for players...
      for (i = 0; i < engine->GetMaxClients (); i++)
      {
         if (!(g_clients[i].flags & CFLAG_USED) || !(g_clients[i].flags & CFLAG_ALIVE) || (g_clients[i].team == team) || (g_clients[i].ent == GetEntity ()))
            continue;

         player = g_clients[i].ent;

         // let the engine check if this player is potentially visible
         if (!ENGINE_CHECK_VISIBILITY (player, pvs))
            continue;

         // skip glowed players, in free for all mode, we can't hit them
         if (player->v.renderfx == kRenderFxGlowShell && GetGameMod() == 1)
            continue;

         // do some blind by smoke grenade
         if (IsBehindSmokeClouds (player) && m_blindRecognizeTime < engine->GetTime ())
            m_blindRecognizeTime = engine->GetTime () + engine->RandomFloat (2.0, 3.0f);

         if (player->v.button & (IN_ATTACK | IN_ATTACK2))
            m_blindRecognizeTime = engine->GetTime () - 0.1f;

         // see if bot can see the player...
         if (m_blindRecognizeTime < engine->GetTime () && IsEnemyViewable (player))
         {
            float distance = (player->v.origin - pev->origin).GetLength ();

            if (distance < nearestDistance)
            {
               enemies.Push (player);

               if (IsEnemyProtectedByShield (player))
                  continue;

               nearestDistance = distance;
               newEnemy = player;

               // aim VIP first on AS maps...
               if ((g_mapType & MAP_AS) && *(INFOKEY_VALUE (GET_INFOKEYBUFFER (player), "model")) == 'v')
                  break;
            }
         }
      }

      // if we got no enemies with no shield, and got enemies with target them
      if (enemies.GetElementNumber () != 0 && !IsValidPlayer (newEnemy))
         newEnemy = enemies[0];
   }

   if (IsValidPlayer (newEnemy))
   {
      g_botsCanPause = true;
      m_aimFlags |= AIM_ENEMY;

      if (newEnemy == m_enemy)
      {
         // if enemy is still visible and in field of view, keep it keep track of when we last saw an enemy
         m_seeEnemyTime = engine->GetTime ();

         // zero out reaction time
         m_actualReactionTime = 0.0f;
         m_lastEnemy = newEnemy;
         m_lastEnemyOrigin = newEnemy->v.origin;
         
         m_GetNewEnemyTimer =  engine->GetTime () + 0.8;

         return true;
      }
      else
      {
         if (m_seeEnemyTime + 3.0f < engine->GetTime () && (pev->weapons & (1 << WEAPON_C4) || HasHostage () || !FNullEnt (m_targetEntity)))
            RadioMessage (Radio_EnemySpotted);

         m_targetEntity = null; // stop following when we see an enemy...

         if (engine->RandomInt (0, 100) < m_skill)
            m_enemySurpriseTime = engine->GetTime () + (m_actualReactionTime / 3);
         else
            m_enemySurpriseTime = engine->GetTime () + m_actualReactionTime;

         // zero out reaction time
         m_actualReactionTime = 0.0f;
         m_enemy = newEnemy;
         m_lastEnemy = newEnemy;
         m_lastEnemyOrigin = newEnemy->v.origin;
         m_enemyReachableTimer = 0.0f;

         // keep track of when we last saw an enemy
         m_seeEnemyTime = engine->GetTime ();

         // now alarm all teammates who see this bot & don't have an actual enemy of the bots enemy should simulate human players seeing a teammate firing
         for (int j = 0; j < engine->GetMaxClients (); j++)
         {
            if (!(g_clients[j].flags & CFLAG_USED) || !(g_clients[j].flags & CFLAG_ALIVE) || g_clients[j].team != team || g_clients[j].ent == GetEntity ())
               continue;

            Bot *friendBot = g_botManager->GetBot (g_clients[j].ent);

            if (friendBot != null)
            {
               if (friendBot->m_seeEnemyTime + 2.0f < engine->GetTime () || FNullEnt (friendBot->m_lastEnemy))
               {
                  if (IsVisible (pev->origin, ENT (friendBot->pev)))
                  {
                     friendBot->m_lastEnemy = newEnemy;
                     friendBot->m_lastEnemyOrigin = m_lastEnemyOrigin;
                     friendBot->m_seeEnemyTime = engine->GetTime ();
                  }
               }
            }
         }
         m_GetNewEnemyTimer =  engine->GetTime () + 1.6;
         return true;
      }
   }
   else if (!FNullEnt (m_enemy))
   {
      newEnemy = m_enemy;
      m_lastEnemy = newEnemy;
      m_GetNewEnemyTimer =  engine->GetTime () + 0.8;

      if (!IsAlive (newEnemy))
      {
         m_enemy = null;

         // shoot at dying players if no new enemy to give some more human-like illusion
         if (m_seeEnemyTime + 0.1 > engine->GetTime ())
         {
            if (!UsesSniper ())
            {
               m_shootAtDeadTime = engine->GetTime () + 0.2f;
               m_actualReactionTime = 0.0f;
               m_states |= STATE_SUSPECTENEMY;

               return true;
            }
            return false;
         }
         else if (m_shootAtDeadTime > engine->GetTime ())
         {
            m_actualReactionTime = 0.0f;
            m_states |= STATE_SUSPECTENEMY;

            return true;
         }
         return false;
      }

      // if no enemy visible check if last one shoot able through wall
      if (sypb_thruwalls.GetBool () && engine->RandomInt (1, 100) < g_skillTab[m_skill / 20].seenShootThruProb)
      {
         if (IsShootableThruObstacle (newEnemy->v.origin))
         {
            m_seeEnemyTime = engine->GetTime () - 0.2f;

            m_states |= STATE_SUSPECTENEMY;
            m_aimFlags |= AIM_LASTENEMY;

            m_enemy = newEnemy;
            m_lastEnemy = newEnemy;
            m_lastEnemyOrigin = newEnemy->v.origin;

            return true;
         }
      }
   }

   // check if bots should reload...
   if ((m_aimFlags <= AIM_PREDICTENEMY && m_seeEnemyTime + 4.0f < engine->GetTime () &&  !(m_states & (STATE_SEEINGENEMY | STATE_HEARENEMY)) && FNullEnt (m_lastEnemy) && FNullEnt (m_enemy) && GetCurrentTask ()->taskID != TASK_DESTROYBREAKABLE && GetCurrentTask ()->taskID != TASK_PLANTBOMB && GetCurrentTask ()->taskID != TASK_DEFUSEBOMB) || g_roundEnded)
   {
      if (!m_reloadState)
         m_reloadState = RSTATE_PRIMARY;
   }

   // is the bot using a sniper rifle or a zoomable rifle?
   if ((UsesSniper () || UsesZoomableRifle ()) && m_zoomCheckTime + 1.0f < engine->GetTime ())
   {
      if (pev->fov < 90) // let the bot zoom out
         pev->button |= IN_ATTACK2;
      else
         m_zoomCheckTime = 0.0f;
   }
   return false;
}