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_util.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-17  |  14.0 KB  |  494 lines

  1. //
  2. // C++ Implementation: bot_util
  3. //
  4. // Description: Basic util functions, mostly bot related
  5. //
  6. //
  7. // Author:  <rickhelmus@gmail.com>
  8. //
  9. // 
  10. //
  11. //
  12.  
  13. #include "bot.h"
  14.  
  15. // Function code by PMB - Begin
  16.  
  17.  
  18. // Random functions begin
  19. // copied from
  20. // http://forums.bots-united.com/showthread.php?t=244&page=1&pp=10&highlight=random
  21. // So credits to PMB and the person(s) who actually made it :]
  22.  
  23. // maximum value returned by our number generator (2^31 - 1 = 0x7FFFFFFF)
  24. #define LRAND_MAX 2147483647L
  25. long lseed; // our random number generator's seed
  26.  
  27. long lrand (void)
  28. {
  29.      // this function is the equivalent of the rand() standard C library function,
  30.      // except that whereas rand() works only with short integers
  31.      // (i.e. not above 32767), this function is able to generate 32-bit random
  32.      // numbers. Isn't that nice ?
  33.      // credits go to Ray Gardner for his fast implementation of minimal random
  34.      // number generators
  35.      // http://c.snippets.org/snip_lister.php?fname=rg_rand.c
  36.      
  37.      // compose the two 16-bit parts of the long integer and assemble them
  38.      static unsigned long lrand_lo, lrand_hi;
  39.      lrand_lo = 16807 * (long) (lseed & 0xFFFF); // low part
  40.      lrand_hi = 16807 * (long) ((unsigned long) lseed >> 16);
  41.      // high part
  42.      lrand_lo += (lrand_hi & 0x7FFF) << 16;
  43.      // assemble both in lrand_lo
  44.      // is the resulting number greater than LRAND_MAX (half the capacity) ?
  45.      if (lrand_lo > LRAND_MAX)
  46.      {
  47.           lrand_lo &= LRAND_MAX; // then get rid of the disturbing bit
  48.           lrand_lo++; // and increase it a bit (to avoid overflow problems, I suppose)
  49.      }
  50.      
  51.      lrand_lo += lrand_hi >> 15;
  52.      // now do twisted maths to generate the next seed
  53.      // is the resulting number greater than LRAND_MAX (half the capacity) ?
  54.      if (lrand_lo > LRAND_MAX)
  55.      {
  56.           lrand_lo &= LRAND_MAX; // then get rid of the disturbing bit
  57.           lrand_lo++; // and increase it a bit (to avoid overflow problems, I suppose)
  58.      }
  59.      // now we've got our (pseudo-)random number.
  60.      lseed = (long) lrand_lo; // put it in the seed for next time
  61.      return (lseed); // and return it. Yeah, simple as that.
  62. }
  63.  
  64. void lsrand (unsigned long initial_seed)
  65. {
  66.      // this function initializes the random seed based on the initial seed value
  67.      // passed in the initial_seed parameter. Since random seeds are
  68.      // usually initialized with the time of day, and time is a value that
  69.      // changes slowly, we bump the seed twice to have it in a more
  70.      // random state for future calls of the random number generator.
  71.      
  72.      // fill in the initial seed of the random number generator
  73.      lseed = (long) initial_seed; 
  74.      lseed = lrand (); // bump it once
  75.      lseed = lrand (); // bump it twice
  76.      return; // that's all folks
  77. }
  78.  
  79. long RandomLong (long from, long to)
  80. {
  81.      // this function returns a random integer number between (and including)
  82.      // the starting and ending values passed by parameters from and to.
  83.      if (to <= from) 
  84.           return (from);
  85.           
  86.      return (from + lrand () / (LRAND_MAX / (to - from + 1)));
  87. }
  88.  
  89. float RandomFloat (float from, float to)
  90. {
  91.      // this function returns a random floating-point number between (and including)
  92.      // the starting and ending values passed by parameters from and to.
  93.      
  94.      if (to <= from)
  95.           return (from);
  96.           
  97.      return (from + (float) lrand () / (LRAND_MAX / (to - from)));
  98. }
  99.  
  100. // End random functions
  101.  
  102. void AnglesToVectors(vec angles, vec &forward, vec &right, vec &up)
  103. {
  104.      static float degrees_to_radians = 2 * PI / 360;
  105.      float angle;
  106.      float sin_pitch;
  107.      float sin_yaw;
  108.      float sin_roll;
  109.      float cos_pitch;
  110.      float cos_yaw;
  111.      float cos_roll;
  112.          
  113.      // For some reason this has to be done :)
  114.      // Me = math n00b
  115.      angles.x = -angles.x;
  116.      angles.y -= 90;
  117.      
  118.      // compute the sin and cosine of the pitch component
  119.      angle = angles.x * degrees_to_radians;
  120.      sin_pitch = sinf (angle);
  121.      cos_pitch = cosf (angle);
  122.      
  123.      // compute the sin and cosine of the yaw component
  124.      angle = angles.y * degrees_to_radians;
  125.      sin_yaw = sinf (angle);
  126.      cos_yaw = cosf (angle);
  127.      
  128.      // compute the sin and cosine of the roll component
  129.      angle = angles.z * degrees_to_radians;
  130.      sin_roll = sinf (angle);
  131.      cos_roll = cosf (angle);
  132.      
  133.      // build the FORWARD vector
  134.      forward.x = cos_pitch * cos_yaw;
  135.      forward.y = cos_pitch * sin_yaw;
  136.      forward.z = -sin_pitch;
  137.      
  138.      // build the RIGHT vector
  139.      right.x = -(-(sin_roll * sin_pitch * cos_yaw) - (cos_roll * -sin_yaw));
  140.      right.y = -(-(sin_roll * sin_pitch * sin_yaw) - (cos_roll * cos_yaw));
  141.      right.z = -(sin_roll * cos_pitch);
  142.      
  143.      // build the UPWARDS vector
  144.      up.x = ((cos_roll * sin_pitch * cos_yaw) - (sin_roll * -sin_yaw));
  145.      up.y = ((cos_roll * sin_pitch * sin_yaw) - (sin_roll * cos_yaw));
  146.      up.z = cos_roll * cos_pitch;
  147.      
  148.      return;
  149. }
  150.  
  151. // Function code by PMB - End
  152.  
  153. float WrapXAngle(float angle)
  154. {
  155.      if (angle > 90) angle = 90;
  156.      else if (angle < -90) angle = -90;
  157.  
  158.      return angle;
  159. }
  160.  
  161. float WrapYZAngle(float angle)
  162. {
  163.      while (angle >= 360.0f) angle -= 360.0f;
  164.      while (angle < 0.0f) angle += 360.0f;
  165.  
  166.      return angle;
  167. }
  168.  
  169. // Sees how far it can come from 'from' to 'to' and puts the end vector in 'end'
  170. // (1337 description :-)
  171. // UNDONE: Optimize this as much as possible
  172. void TraceLine(vec from, vec to, dynent *pTracer, bool CheckPlayers, traceresult_s *tr,
  173.                bool SkipTags)
  174. {
  175.      tr->end = from;
  176.      tr->collided = false;
  177.      
  178.      static float flNearestDist, flDist;
  179.      static vec v;
  180.      static bool solid;
  181.     
  182.      flNearestDist = 9999.0f;
  183.      
  184.      if(OUTBORD((int)from.x, (int)from.y)) return;
  185.     
  186.      // Check if the 'line' collides with entities like mapmodels
  187.      loopv(ents)
  188.      {
  189.           entity &e = ents[i];
  190.           if(e.type!=MAPMODEL) continue; // Only check map models for now
  191.                
  192.           mapmodelinfo &mmi = getmminfo(e.attr2);
  193.           if(!&mmi || !mmi.h) continue;
  194.     
  195.           float lo = (float)(S(e.x, e.y)->floor+mmi.zoff+e.attr3);
  196.           float hi = lo+mmi.h;
  197.           float z = (fabs(from.z-lo) < fabs(from.z-hi)) ? lo : hi;           
  198.           makevec(&v, e.x, e.y, z);          
  199.           flDist = GetDistance(from, v); 
  200.                
  201.           if ((flDist < flNearestDist) && (intersect(&e, from, to, &tr->end)))
  202.           {
  203.                flNearestDist = GetDistance(from, tr->end);
  204.                tr->collided = true;
  205.           }
  206.      }
  207.  
  208.      if (CheckPlayers)
  209.      {
  210.           // Check if the 'line' collides with players
  211.           loopv(players)
  212.           {
  213.                dynent *d = players[i];
  214.                if(!d || (d==pTracer) || (d->state != CS_ALIVE)) continue; // Only check valid players
  215.                     
  216.                flDist = GetDistance(from, d->o); 
  217.                
  218.                if ((flDist < flNearestDist) && (intersect(d, from, to, &tr->end)))
  219.                {
  220.                     flNearestDist = flDist;
  221.                     tr->collided = true;
  222.                }
  223.           }
  224.  
  225.           // Check if the 'line' collides with the local player(player1)
  226.           dynent *d = player1; // Shortcut
  227.           if (d && (d!=pTracer) && !BotManager.m_pBotToView && (d->state == CS_ALIVE))
  228.           {
  229.                flDist = GetDistance(from, d->o); 
  230.                
  231.                if ((flDist < flNearestDist) && (intersect(d, from, to, &tr->end)))
  232.                {
  233.                     flNearestDist = flDist;
  234.                     tr->collided = true;
  235.                }
  236.           }          
  237.      }
  238.     
  239.     
  240.      float dx = to.x-from.x;
  241.      float dy = to.y-from.y; 
  242.      int steps = (int)(sqrt(dx*dx+dy*dy)/0.9);
  243.      if(!steps) // If from and to are on the same cube...
  244.      {
  245.           if (GetDistance(from, to) < flNearestDist)         
  246.           {
  247.                tr->end = to;
  248.                sqr *s = S(int(from.x), int(from.y));
  249.                float flr = GetCubeFloor(int(from.x), int(from.y));
  250.                solid = ((!SkipTags || !s->tag) && SOLID(s));
  251.                if (solid || (to.z < flr) || (to.z > s->ceil))
  252.                {
  253.                     tr->collided = true;
  254.                     tr->end.z = (fabs(to.z-s->ceil) < fabs(to.z-flr)) ? s->ceil : flr;
  255.                }
  256.           }
  257.           return;
  258.      }
  259.      
  260.      float x = from.x;
  261.      float y = from.y;
  262.      int i = 0;
  263.      vec endcube = from;
  264.      
  265.      // Now check if the 'line' is hit by a cube
  266.      while(i<steps)
  267.      {
  268.           if(OUTBORD((int)x, (int)y)) break;
  269.           if (GetDistance(from, endcube) >= flNearestDist) break;
  270.           sqr *s = S(int(x), int(y));
  271.           solid = ((!SkipTags || !s->tag) && SOLID(s));
  272.           if(solid) break;
  273.           float floor = s->floor;
  274.           if(s->type==FHF) floor -= s->vdelta/4.0f;
  275.           float ceil = s->ceil;
  276.           if(s->type==CHF) ceil += s->vdelta/4.0f;
  277.           float rz = from.z-((from.z-to.z)*(i/(float)steps));
  278.           if(rz<floor || rz>ceil) break;
  279.         
  280.           endcube.x = x;
  281.           endcube.y = y;
  282.           endcube.z = rz;
  283.           x += dx/(float)steps;
  284.           y += dy/(float)steps;
  285.           i++;
  286.      }
  287.     
  288.      if ((i>=steps) && !tr->collided)
  289.      {
  290.           tr->end = to;
  291.      }
  292.      else
  293.      {
  294.           tr->collided = true;
  295.           if (GetDistance(from, endcube) < flNearestDist)
  296.                tr->end = endcube;
  297.      }
  298.  
  299.      return;
  300. }
  301.  
  302. float GetDistance(vec v1, vec v2)
  303. {
  304.      if ((v1.x == 0) && (v2.x == 0) && (v1.y == 0) && (v2.y == 0) && (v1.z == 0) &&
  305.          (v2.z == 0))
  306.           return 0.0f;
  307.           
  308.      return v1.dist(v2);
  309. }
  310.  
  311. // As GetDistance(), but doesn take height in account.
  312. float Get2DDistance(vec v1, vec v2)
  313. {
  314.      if ((v1.x == 0) && (v2.x == 0) && (v1.y == 0) && (v2.y == 0))
  315.           return 0.0f;
  316.      
  317.      v1.z = v2.z = 0.0f;
  318.      return v1.dist(v2);
  319. }
  320.  
  321. bool IsVisible(vec v1, vec v2, dynent *tracer, bool SkipTags)
  322. {
  323.      traceresult_s tr;
  324.      TraceLine(v1, v2, tracer, (tracer!=NULL), &tr, SkipTags);
  325.      return !tr.collided;
  326. }
  327.  
  328. // Prediction:
  329. // - pos: Current position
  330. // - vel: Current velocity
  331. // - Time: In seconds, predict how far it is in Time seconds
  332. vec PredictPos(vec pos, vec vel, float Time)
  333. {
  334.      float flVelLength = vel.magnitude();
  335.     
  336.      if (flVelLength <= 1.0)
  337.           return pos; // don't bother with low velocities...
  338.  
  339.      vec v_end = vel;
  340.      v_end.mul(Time);
  341.      v_end.add(pos);
  342.      return v_end;
  343. }
  344.  
  345. // returns true if the given file is valid
  346. bool IsValidFile(const char *szFileName)
  347. {
  348.      FILE *fp = fopen(szFileName, "r");
  349.  
  350.      if (fp)
  351.      {
  352.           fclose(fp);
  353.           return true;
  354.      }
  355.  
  356.      return false;
  357. }
  358.  
  359. bool FileIsOlder(const char *szFileName1, const char *szFileName2)
  360. {
  361. /*     int file1, file2;
  362.      struct stat stat1, stat2;
  363.  
  364.      file1 = open(szFileName1, O_RDONLY);
  365.      file2 = open(szFileName2, O_RDONLY);
  366.  
  367.      fstat(file1, &stat1);
  368.      fstat(file2, &stat2);
  369.  
  370.      close(file1);
  371.      close(file2);
  372.  
  373.      return(stat1.st_mtime < stat2.st_mtime);*/ return false; // FIXME
  374. }
  375.  
  376. vec Normalize(vec v)
  377. {
  378.      float flLen = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
  379.      static vec v_norm = g_vecZero;
  380.      if (flLen == 0) 
  381.      {
  382.           v_norm.x=0;v_norm.y=0;v_norm.z=1;
  383.      }
  384.      else
  385.      {
  386.           flLen = 1 / flLen;
  387.           v_norm.x = v.x * flLen; v_norm.y = v.y * flLen; v_norm.z = v.z * flLen;
  388.      }
  389.      return v_norm;
  390. }
  391.  
  392. float GetYawDiff(float curyaw, vec v1, vec v2)
  393. {
  394.      float yaw = -(float)atan2(v2.x - v1.x, v2.y - v1.y)/PI*180+180;    
  395.      return yaw-curyaw;
  396. }
  397.  
  398. vec CrossProduct(const vec &a, const vec &b)
  399. {
  400.      vec cross(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
  401.      return cross;
  402. }
  403.  
  404. int GetDirection(const vec &angles, const vec &v1, const vec &v2)
  405. {
  406.      vec tmp, forward, right, up, cross;
  407.      float flDot;
  408.  
  409.      AnglesToVectors(angles, forward, right, up);
  410.  
  411.      tmp = v2;
  412.      tmp.sub(v1);
  413.      tmp.z = 0.0f; // Make 2D
  414.      tmp = Normalize(tmp);
  415.      forward.z = 0; // Make 2D
  416.           
  417.      flDot = tmp.dot(forward);
  418.      cross = CrossProduct(tmp, forward);
  419.      
  420.      int Dir = DIR_NONE;
  421.                
  422.      if (cross.z > 0.1f) Dir |= LEFT;
  423.      else if (cross.z < -0.1f) Dir |= RIGHT;
  424.      if (flDot < -0.1f) Dir |= BACKWARD;
  425.      else if (flDot > 0.1f) Dir |= FORWARD;
  426.      
  427.      if (v1.z > v2.z) Dir |= DOWN;
  428.      if (v1.z < v2.z) Dir |= UP;
  429.      
  430.      return Dir;
  431. }
  432.  
  433. float GetCubeFloor(int x, int y)
  434. {
  435.      sqr *s = S(x, y);
  436.      float floor = s->floor;
  437.      if (s->type == FHF)
  438.           floor -= (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
  439.      return floor;
  440. }
  441.  
  442. float GetCubeHeight(int x, int y)
  443. {
  444.      sqr *s = S(x, y);
  445.      float ceil = s->ceil;
  446.      if(s->type == CHF)
  447.           ceil += (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
  448.      return ceil;
  449. }
  450.  
  451. char *SkillNrToSkillName(short skillnr)
  452. {
  453.      if (skillnr == 0) return "best";
  454.      else if (skillnr == 1) return "good";
  455.      else if (skillnr == 2) return "medium";
  456.      else if (skillnr == 3) return "worse";
  457.      else if (skillnr == 4) return "bad";
  458.      
  459.      return NULL;
  460. }
  461.  
  462. bool IsInGame(dynent *d)
  463. {
  464.      if (!d) return false;
  465.      
  466.      if (d->type==ENT_BOT)
  467.      {
  468.           loopv(bots)
  469.           {
  470.                if (bots[i] == d)
  471.                     return true;
  472.           }
  473.      }
  474.      else
  475.      {
  476.           if (d == player1)
  477.                return true;
  478.           else
  479.           {
  480.                loopv(players)
  481.                {
  482. #ifdef VANILLA_CUBE               
  483.                     if (!players[i] || (players[i]->state == CS_DEDHOST)) continue;
  484. #elif defined(AC_CUBE)
  485.                     if (!players[i]) continue;
  486. #endif                    
  487.                     if (players[i] == d)
  488.                          return true;
  489.                }
  490.           }
  491.      }
  492.      return false;
  493. }
  494.