home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / bot / bot.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-17  |  11.5 KB  |  423 lines

  1. //
  2. // C++ Implementation: bot
  3. //
  4. // Description: 
  5. //
  6. // Contains code of the base bot class
  7. //
  8. // Author:  Rick <rickhelmus@gmail.com>
  9. //
  10. //
  11. //
  12.  
  13. #include "bot.h"
  14.  
  15. vector<botent *> bots;
  16.  
  17. extern int triggertime;
  18. extern itemstat itemstats[];
  19. extern ENetHost *clienthost;
  20.  
  21. const vec g_vecZero(0, 0, 0);
  22.  
  23. //Bot class begin
  24.  
  25. CBot::~CBot()
  26. {
  27.      // Delete all waypoints
  28.      loopi(MAX_MAP_GRIDS)
  29.      {
  30.           loopj(MAX_MAP_GRIDS)
  31.           {
  32.                while (m_WaypointList[i][j].Empty() == false)
  33.                     delete m_WaypointList[i][j].Pop();
  34.           }
  35.      }
  36. }
  37.  
  38. void CBot::Spawn()
  39. {
  40.      // Init all bot variabeles
  41.      spawnplayer(m_pMyEnt);
  42.      
  43.      m_pMyEnt->targetyaw = m_pMyEnt->targetpitch = 0.0f;
  44.      m_pMyEnt->enemy = NULL;
  45.      m_pMyEnt->maxspeed = 22.0f;
  46.      m_pMyEnt->pBot = this;     
  47.          
  48.      m_eCurrentBotState = STATE_NORMAL;
  49.      m_iShootDelay = m_iChangeWeaponDelay = 0;
  50.      m_iCheckEnvDelay = 0;
  51.      m_vPrevOrigin = g_vecZero;
  52.      m_iStuckCheckDelay = lastmillis + 250;
  53.      m_bStuck = false;
  54.      m_iStuckTime = 0;
  55.      m_iStrafeTime = m_iStrafeCheckDelay = 0;
  56.      m_iMoveDir = DIR_NONE;
  57.      
  58.      m_pPrevEnemy = NULL;
  59.      m_iCombatNavTime = 0;
  60.      m_iSPMoveTime = 0;
  61.      m_iEnemySearchDelay = 0;
  62.      m_iSawEnemyTime = 0;
  63.      m_bCombatJump = false;
  64.      m_iCombatJumpDelay = 0;
  65.      m_bShootAtFeet = (RandomLong(1, 100) <= m_pBotSkill->sShootAtFeetWithRLPercent);
  66.      m_iHuntDelay = 0;
  67.      m_vHuntLocation = m_vPrevHuntLocation = g_vecZero;
  68.      m_pHuntTarget = NULL;
  69.      m_fPrevHuntDist = 0.0f;
  70.      m_iHuntLastTurnLessTime = m_iHuntPlayerUpdateTime = m_iHuntPauseTime = 0;
  71.      m_iLookAroundDelay = m_iLookAroundTime = m_iLookAroundUpdateTime = 0;
  72.      m_fLookAroundYaw = 0.0f;
  73.      m_bLookLeft = false;
  74.         
  75.      m_iLastJumpPad = 0;
  76.      m_pTargetEnt = NULL;
  77.      while(!m_UnreachableEnts.Empty()) delete m_UnreachableEnts.Pop();
  78.      m_iCheckTeleporterDelay = m_iCheckJumppadsDelay = 0;
  79.      m_iCheckEntsDelay = 0;
  80.      m_iCheckTriggersDelay = 0;
  81.      m_iLookForWaypointTime = 0;
  82.         
  83.      m_iAimDelay = 0;
  84.      m_fYawToTurn = m_fPitchToTurn = 0.0f;
  85.      
  86.      m_vGoal = m_vWaterGoal = g_vecZero;
  87.      
  88.      ResetWaypointVars();
  89. }
  90.  
  91. void CBot::Think()
  92. {
  93.      if (intermission)
  94.           return;
  95.              
  96.      // Bot is dead?
  97.      if (m_pMyEnt->state == CS_DEAD)
  98.      {
  99.           if(lastmillis-m_pMyEnt->lastaction<1200)
  100.           {
  101.                m_pMyEnt->move = 0;
  102.                moveplayer(m_pMyEnt, 1, false);
  103.           }
  104.           else if (!m_arena && lastmillis-m_pMyEnt->lastaction>5000)
  105.                Spawn();
  106.      
  107.           SendBotInfo();
  108.           return;
  109.      }
  110.      
  111.      CheckItemPickup();
  112.  
  113.      TLinkedList<unreachable_ent_s*>::node_s *p = m_UnreachableEnts.GetFirst(), *tmp;
  114.      while(p)
  115.      {
  116.           if ((lastmillis - p->Entry->time) > 3500)
  117.           {
  118.                tmp = p;
  119.                p = p->next;
  120.                delete tmp->Entry;               
  121.                m_UnreachableEnts.DeleteNode(tmp);
  122.                continue;
  123.           }
  124.           p = p->next;
  125.      }
  126.  
  127.      if (!BotManager.IdleBots())
  128.      {
  129.           MainAI();
  130.      }
  131.      else
  132.      {
  133.           ResetMoveSpeed();
  134.      }    
  135.      
  136.      // Aim to ideal yaw and pitch
  137.      AimToIdeal();
  138.      
  139.      // Store current location, to see if the bot is stuck
  140.      m_vPrevOrigin = m_pMyEnt->o;
  141.      
  142.      // Don't check for stuck if the bot doesn't want to move
  143.      if (!m_pMyEnt->move && !m_pMyEnt->strafe)
  144.           m_iStuckCheckDelay = max(m_iStuckCheckDelay, (lastmillis+100));
  145.           
  146.      // Move the bot
  147.      moveplayer(m_pMyEnt, 1, false);
  148.      
  149.      // Update bot info on all clients
  150.      SendBotInfo();
  151. }
  152.  
  153. void CBot::AimToVec(const vec &o)
  154. {
  155.      m_pMyEnt->targetpitch = atan2(o.z-m_pMyEnt->o.z, GetDistance(o))*180/PI;
  156.      m_pMyEnt->targetyaw = -(float)atan2(o.x - m_pMyEnt->o.x, o.y -
  157.                                          m_pMyEnt->o.y)/PI*180+180;
  158. }
  159.  
  160. void CBot::AimToIdeal()
  161. {
  162.      if (m_iAimDelay > lastmillis)
  163.           return;
  164.  
  165.      float MaxXSpeed = RandomFloat(m_pBotSkill->flMinAimXSpeed,
  166.                                    m_pBotSkill->flMaxAimXSpeed);
  167.      float MaxYSpeed = RandomFloat(m_pBotSkill->flMinAimYSpeed,
  168.                                    m_pBotSkill->flMaxAimYSpeed);
  169.      float XOffset = RandomFloat(m_pBotSkill->flMinAimXOffset,
  170.                                  m_pBotSkill->flMaxAimXOffset);
  171.      float YOffset = RandomFloat(m_pBotSkill->flMinAimYOffset,
  172.                                  m_pBotSkill->flMaxAimYOffset);
  173.      float RealXOffset, RealYOffset;
  174.      float AimXSpeed = MaxXSpeed, AimYSpeed = MaxYSpeed;
  175.      float XDiff = fabs(m_pMyEnt->targetpitch - m_pMyEnt->pitch);
  176.      float YDiff = fabs(m_pMyEnt->targetyaw - m_pMyEnt->yaw);
  177.  
  178.      // How higher the diff, how higher the offsets and aim speed
  179.           
  180.      if (XOffset)
  181.      {
  182.           if (RandomLong(0, 1))
  183.                RealXOffset = XDiff * (XOffset / 100.0f);
  184.           else
  185.                RealXOffset = -(XDiff * (XOffset / 100.0f));
  186.      }
  187.      else
  188.           RealXOffset = 0.0f;
  189.  
  190.      if (YOffset)
  191.      {
  192.           if (RandomLong(0, 1))
  193.                RealYOffset = YDiff * (YOffset / 100.0f);
  194.           else
  195.                RealYOffset = -(YDiff * (YOffset / 100.0f));
  196.      }
  197.      else
  198.           RealYOffset = 0.0f;
  199.  
  200.           
  201.      if (XDiff >= 1.0f)
  202.           AimXSpeed = (AimXSpeed * (XDiff / 80.0f)) + (AimXSpeed * 0.25f);
  203.      else
  204.           AimXSpeed *= 0.01f;
  205.  
  206.      if (YDiff >= 1.0f)
  207.           AimYSpeed = (AimYSpeed * (YDiff / 70.0f)) + (AimYSpeed * 0.25f);
  208.      else
  209.           AimYSpeed *= 0.015f;
  210.  
  211.      m_fPitchToTurn = fabs((m_pMyEnt->targetpitch + RealXOffset) - m_pMyEnt->pitch);
  212.      m_fYawToTurn = fabs((m_pMyEnt->targetyaw + RealYOffset) - m_pMyEnt->yaw);
  213.      
  214.      float flIdealPitch = ChangeAngle(AimXSpeed, m_pMyEnt->targetpitch + RealXOffset, m_pMyEnt->pitch);
  215.      float flIdealYaw = ChangeAngle(AimYSpeed, m_pMyEnt->targetyaw + RealYOffset, m_pMyEnt->yaw);
  216.      
  217. //     m_pMyEnt->pitch = WrapXAngle(m_pMyEnt->targetpitch); // Uncomment for instant aiming
  218. //     m_pMyEnt->yaw = WrapYZAngle(m_pMyEnt->targetyaw);
  219.                  
  220.      m_pMyEnt->pitch = WrapXAngle(flIdealPitch);
  221.      m_pMyEnt->yaw = WrapYZAngle(flIdealYaw);     
  222. }     
  223.  
  224. // Function code by Botman
  225. float CBot::ChangeAngle(float speed, float ideal, float current)
  226. {
  227.      float current_180;  // current +/- 180 degrees
  228.      float diff;
  229.  
  230.      // find the difference in the current and ideal angle
  231.      diff = fabs(current - ideal);
  232.     
  233.      // speed that we can turn during this frame...
  234.      speed = speed * (float(BotManager.m_iFrameTime)/1000.0f);
  235.  
  236.      // check if difference is less than the max degrees per turn
  237.      if (diff < speed)
  238.           speed = diff;  // just need to turn a little bit (less than max)
  239.  
  240.      // check if the bot is already facing the idealpitch direction...
  241.      if (diff <= 1.0f)
  242.           return ideal;
  243.           
  244.      if ((current >= 180) && (ideal >= 180))
  245.      {
  246.           if (current > ideal)
  247.                current -= speed;
  248.           else
  249.                current += speed;
  250.      }
  251.      else if ((current >= 180) && (ideal < 180))
  252.      {
  253.           current_180 = current - 180;
  254.  
  255.           if (current_180 > ideal)
  256.                current += speed;
  257.           else
  258.                current -= speed;
  259.      }
  260.      else if ((current < 180) && (ideal >= 180))
  261.      {
  262.           current_180 = current + 180;
  263.           
  264.           if (current_180 > ideal)
  265.                current += speed;
  266.           else
  267.                current -= speed;
  268.      }
  269.      else  // (current < 180) && (ideal < 180)
  270.      {
  271.           if (current > ideal)
  272.                current -= speed;
  273.           else
  274.                current += speed;
  275.      }
  276.  
  277.  
  278.      return current;     
  279. }
  280.  
  281. void CBot::SendBotInfo()
  282. {
  283.      if(lastmillis-m_iLastBotUpdate<40) return;    // don't update faster than 25fps
  284.      m_iLastBotUpdate = lastmillis;
  285. }
  286.  
  287. float CBot::GetDistance(const vec &o)
  288. {
  289.      return o.dist(m_pMyEnt->o);
  290. }
  291.  
  292. float CBot::GetDistance(const vec &v1, const vec &v2)
  293. {
  294.      return v2.dist(v1);
  295. }
  296.  
  297. float CBot::GetDistance(entity *e)
  298. {
  299.      vec v(e->x, e->y, e->z);
  300.      return v.dist(m_pMyEnt->o);
  301. }
  302.  
  303. bool CBot::SelectGun(int Gun)
  304. {
  305.     if(m_pMyEnt->reloading) return false;
  306.     if (m_pMyEnt->gunselect != Gun) playsound(S_GUNCHANGE, &m_pMyEnt->o);
  307.     m_pMyEnt->gunselect = Gun;
  308.     return true;
  309. }
  310.  
  311. bool CBot::IsVisible(entity *e, bool CheckPlayers)
  312. {
  313.      vec v(e->x, e->y, e->z);
  314.      return ::IsVisible(m_pMyEnt->o, v, (CheckPlayers) ? m_pMyEnt : NULL);
  315. }
  316.  
  317. bool CBot::IsVisible(vec o, int Dir, float flDist, bool CheckPlayers, float *pEndDist)
  318. {
  319.      static vec angles, end, forward, right, up;
  320.      static traceresult_s tr;
  321.         
  322.      end = o;
  323.      angles = GetViewAngles();
  324.      angles.x = 0;
  325.           
  326.      if (Dir & UP)
  327.           angles.x = WrapXAngle(angles.x + 45.0f);
  328.      else if (Dir & DOWN)
  329.           angles.x = WrapXAngle(angles.x - 45.0f);
  330.           
  331.      if ((Dir & FORWARD) || (Dir & BACKWARD))
  332.      {
  333.           if (Dir & BACKWARD)
  334.                angles.y = WrapYZAngle(angles.y + 180.0f);
  335.           
  336.           if (Dir & LEFT)
  337.           {
  338.                if (Dir & FORWARD)
  339.                     angles.y = WrapYZAngle(angles.y - 45.0f);
  340.                else
  341.                     angles.y = WrapYZAngle(angles.y + 45.0f);
  342.           }
  343.           else if (Dir & RIGHT)
  344.           {
  345.                if (Dir & FORWARD)
  346.                     angles.y = WrapYZAngle(angles.y + 45.0f);
  347.                else
  348.                     angles.y = WrapYZAngle(angles.y - 45.0f);
  349.           }
  350.      }
  351.      else if (Dir & LEFT)
  352.           angles.y = WrapYZAngle(angles.y - 90.0f);
  353.      else if (Dir & RIGHT)
  354.           angles.y = WrapYZAngle(angles.y + 90.0f);
  355.      else if (Dir & UP)
  356.           angles.x = WrapXAngle(angles.x + 90.0f);
  357.      else if (Dir & DOWN)
  358.           angles.x = WrapXAngle(angles.x - 90.0f);
  359.                
  360.      AnglesToVectors(angles, forward, right, up);
  361.      
  362.      forward.mul(flDist);
  363.      end.add(forward);
  364.          
  365.      TraceLine(o, end, m_pMyEnt, CheckPlayers, &tr);
  366.      
  367.      if (pEndDist)
  368.           *pEndDist = GetDistance(o, tr.end);
  369.           
  370.      return !tr.collided;
  371. }
  372.  
  373. void CBot::SetMoveDir(int iMoveDir, bool add)
  374. {
  375.      if (iMoveDir & FORWARD)
  376.           m_pMyEnt->move = 1;
  377.      else if (m_iMoveDir & BACKWARD)
  378.           m_pMyEnt->move = -1;
  379.      else if (!add)
  380.           m_pMyEnt->move = 0;
  381.  
  382.      if (iMoveDir & LEFT)
  383.           m_pMyEnt->strafe = 1;
  384.      else if (m_iMoveDir & RIGHT)
  385.           m_pMyEnt->strafe = -1;
  386.      else if (!add)
  387.           m_pMyEnt->strafe = 0;
  388.           
  389.      if (iMoveDir & UP)
  390.           m_pMyEnt->jumpnext = true;
  391. }
  392.  
  393. // Used when switching to another task/state
  394. void CBot::ResetCurrentTask()
  395. {
  396.      switch (m_eCurrentBotState)
  397.      {
  398.      case STATE_ENEMY:
  399.           m_pMyEnt->enemy = NULL;
  400.           m_pTargetEnt = NULL;
  401.           m_iCombatNavTime = m_iMoveDir = 0;
  402.           m_bCombatJump = false;
  403.           m_vGoal = g_vecZero;
  404.           break;
  405.      case STATE_ENT:
  406.           m_pTargetEnt = NULL;
  407.           m_vGoal = g_vecZero;
  408.           break;
  409.      case STATE_SP:
  410.           m_iSPMoveTime = m_iMoveDir = 0;
  411.           m_pTargetEnt = NULL;
  412.           m_vGoal = g_vecZero;
  413.           break;
  414.      case STATE_NORMAL:
  415.           m_iStrafeTime = m_iMoveDir = 0;
  416.           break;
  417.      default:
  418.           break;
  419.      }
  420. }
  421.           
  422. // Bot class end
  423.