home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 November / Chip_2002-11_cd1.bin / oddech / orbital / orbital.exe / src / ai.cpp next >
C/C++ Source or Header  |  2002-07-15  |  26KB  |  737 lines

  1. ///////////////////////////////////////////////
  2. // 
  3. //  Snipe2d ludum dare 48h compo entry
  4. //
  5. //  Jari Komppa aka Sol 
  6. //  http://iki.fi/sol
  7. // 
  8. ///////////////////////////////////////////////
  9. // License
  10. ///////////////////////////////////////////////
  11. // 
  12. //     This software is provided 'as-is', without any express or implied
  13. //     warranty.    In no event will the authors be held liable for any damages
  14. //     arising from the use of this software.
  15. // 
  16. //     Permission is granted to anyone to use this software for any purpose,
  17. //     including commercial applications, and to alter it and redistribute it
  18. //     freely, subject to the following restrictions:
  19. // 
  20. //     1. The origin of this software must not be misrepresented; you must not
  21. //        claim that you wrote the original software. If you use this software
  22. //        in a product, an acknowledgment in the product documentation would be
  23. //        appreciated but is not required.
  24. //     2. Altered source versions must be plainly marked as such, and must not be
  25. //        misrepresented as being the original software.
  26. //     3. This notice may not be removed or altered from any source distribution.
  27. // 
  28. // (eg. same as ZLIB license)
  29. //
  30. ///////////////////////////////////////////////
  31. //
  32. // Houses are taken from a satellite picture of glasgow.
  33. //
  34. // The sources are a mess, as I didn't even try to do anything
  35. // really organized here.. and hey, it's a 48h compo =)
  36. //
  37. #include "snipe2d.h"
  38.  
  39. //#define DRAW_DEBUGLINES
  40.  
  41. int route(int x1,int y1,int x2, int y2)
  42. {
  43.     if ( SDL_LockSurface(gAIMap) < 0 ) 
  44.         return 0;
  45.     
  46.     char *t = (char*)gAIMap->pixels;
  47.     
  48.     int x, y;
  49.     int xinc;
  50.     int yinc;
  51.     int len,i;
  52.     
  53.     len = abs(x2 - x1);
  54.     i = abs(y2 - y1);
  55.     if (i > len) len = i;
  56.     if (len == 0) return 0;
  57.  
  58.     xinc = ((x2 - x1) << SHIFT_AMOUNT) / len;
  59.     yinc = ((y2 - y1) << SHIFT_AMOUNT) / len;
  60.  
  61.     x = (x1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2); 
  62.     y = (y1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
  63.  
  64.     for (i = 1; i <= len; i++) 
  65.     {
  66.         if ((t[(x >> SHIFT_AMOUNT) + 
  67.                (y >> SHIFT_AMOUNT) * 
  68.                (gAIMap->pitch)] & 0xff) == 1)
  69.             return 0;
  70.         x = x + xinc;
  71.         y = y + yinc;
  72.     }
  73.  
  74.     SDL_UnlockSurface(gAIMap);
  75.     return len;
  76. }
  77.  
  78. void drawLine(SDL_Surface * aTarget, int x1,int y1,int x2, int y2, int clr) 
  79. {
  80.     if ( SDL_LockSurface(aTarget) < 0 ) 
  81.         return;
  82.  
  83.     short *t = (short*)aTarget->pixels;
  84.         
  85.     int x, y;
  86.     int xinc;
  87.     int yinc;
  88.     int len,i;
  89.     
  90.     len = abs(x2 - x1);
  91.     i = abs(y2 - y1);
  92.     if (i > len) len = i;
  93.     if (len == 0) return;
  94.  
  95.     xinc = ((x2 - x1) << SHIFT_AMOUNT) / len;
  96.     yinc = ((y2 - y1) << SHIFT_AMOUNT) / len;
  97.  
  98.     x = (x1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2); 
  99.     y = (y1 << SHIFT_AMOUNT) + ((1 << SHIFT_AMOUNT) / 2);
  100.  
  101.     for (i = 1; i <= len; i++) 
  102.     {
  103.         t[(x >> SHIFT_AMOUNT) + 
  104.           (y >> SHIFT_AMOUNT) * 
  105.           (aTarget->pitch / 2)] = clr;
  106.             
  107.         x = x + xinc;
  108.         y = y + yinc;
  109.     }
  110.  
  111.     SDL_UnlockSurface(aTarget);
  112. }
  113.  
  114.  
  115.  
  116. void precalc_ai()
  117. {
  118.     if ( SDL_LockSurface(gAIMap) < 0 ) 
  119.         return;
  120.     // Count waypoints
  121.  
  122.     gWaypointCount = 0;
  123.     gSpawnpointCount = 0;
  124.     int i,j;
  125.     for (j = 0; j < 600; j++)
  126.     {
  127.         int ofs = j * gAIMap->pitch;
  128.         for (i = 0; i < 800; i++)
  129.         {
  130.             switch (*((char*)gAIMap->pixels + ofs) & 0xff)
  131.             {
  132.             case 0: // street
  133.                 break;
  134.             case 1: // house
  135.                 break;
  136.             case 2: // bad guys spawn points
  137.                 gSpawnpointCount++;
  138.                 gBadGuySpawnCount++;
  139.                 break;
  140.             case 3: // VIP spawn points
  141.                 gSpawnpointCount++;
  142.                 gVIPSpawnCount++;
  143.                 break;
  144.             case 4: // waypoints
  145.                 gWaypointCount++;
  146.                 break;
  147.             case 5: // neutral spawn points
  148.                 gSpawnpointCount++;
  149.                 gPedestrianSpawnCount++;
  150.                 break;
  151.             }
  152.             ofs++;
  153.         }    
  154.     }
  155.     gSpawnpoint = new SPAWNPOINT[gSpawnpointCount];
  156.     gWaypoint = new WAYPOINT[gWaypointCount];
  157.     int waypoint = 0;
  158.     int spawnpoint = 0;
  159.     for (j = 0; j < 600; j++)
  160.     {
  161.         int ofs = j * gAIMap->pitch;
  162.         for (i = 0; i < 800; i++)
  163.         {
  164.             switch (*((char*)gAIMap->pixels + ofs) & 0xff)
  165.             {
  166.             case 0: // street
  167.                 break;
  168.             case 1: // house
  169.                 break;
  170.             case 2: // bad guys spawn points
  171.                 gSpawnpoint[spawnpoint].mX = i;
  172.                 gSpawnpoint[spawnpoint].mY = j;
  173.                 gSpawnpoint[spawnpoint].mType = CHAR_BADGUY;
  174.                 spawnpoint++;
  175.                 break;
  176.             case 3: // VIP spawn points
  177.                 gSpawnpoint[spawnpoint].mX = i;
  178.                 gSpawnpoint[spawnpoint].mY = j;
  179.                 gSpawnpoint[spawnpoint].mType = CHAR_VIP;
  180.                 spawnpoint++;
  181.                 break;
  182.             case 4: // waypoints
  183.                 gWaypoint[waypoint].mX = i;
  184.                 gWaypoint[waypoint].mY = j;
  185.                 waypoint++;
  186.                 break;
  187.             case 5: // neutral spawn points
  188.                 gSpawnpoint[spawnpoint].mX = i;
  189.                 gSpawnpoint[spawnpoint].mY = j;
  190.                 gSpawnpoint[spawnpoint].mType = 2;
  191.                 spawnpoint++;
  192.                 break;
  193.             }
  194.             ofs++;
  195.         }    
  196.     }
  197.  
  198.     // Find and store connections
  199.  
  200.     for (i = 0; i < gWaypointCount; i++)
  201.     {
  202.         waypoint = 0;
  203.         for (j = 0; j < gWaypointCount; j++)
  204.             if (route(gWaypoint[i].mX, gWaypoint[i].mY, gWaypoint[j].mX, gWaypoint[j].mY))
  205.                 waypoint++;
  206.         
  207.         gWaypoint[i].mConnections = waypoint;        
  208.         gWaypoint[i].mConnection = new int[waypoint];
  209.  
  210.         waypoint = 0;
  211.         for (j = 0; j < gWaypointCount; j++)
  212.             if (route(gWaypoint[i].mX, gWaypoint[i].mY, gWaypoint[j].mX, gWaypoint[j].mY))
  213.             {
  214. #ifdef DRAW_DEBUGLINES
  215.                 drawLine(gMap, gWaypoint[i].mX, gWaypoint[i].mY, gWaypoint[j].mX, gWaypoint[j].mY, 0xffff);
  216. #endif
  217.                 gWaypoint[i].mConnection[waypoint] = j;
  218.                 waypoint++;
  219.             }
  220.     }
  221.  
  222.     for (i = 0; i < gSpawnpointCount; i++)
  223.     {
  224.         int spawndist = 10000;
  225.         for (j = 0; j < gWaypointCount; j++)
  226.         {
  227.             int newdist = route(gSpawnpoint[i].mX, gSpawnpoint[i].mY, gWaypoint[j].mX, gWaypoint[j].mY);
  228.             if (newdist && newdist < spawndist)
  229.             {
  230.                 spawndist = newdist;
  231.                 gSpawnpoint[i].mClosestWaypoint = j;
  232.             }
  233.         }
  234.     }
  235. #ifdef DRAW_DEBUGLINES
  236.     for (i = 0; i < gSpawnpointCount; i++)
  237.         drawLine(gMap, gSpawnpoint[i].mX, gSpawnpoint[i].mY, gWaypoint[gSpawnpoint[i].mClosestWaypoint].mX, gWaypoint[gSpawnpoint[i].mClosestWaypoint].mY, 0xf << (gSpawnpoint[i].mType * 6));
  238. #endif
  239.  
  240.     SDL_UnlockSurface(gAIMap);
  241. }
  242.  
  243. float distance(float aX1, float aY1, float aX2, float aY2)
  244. {
  245.     return (float)sqrt((aX2 - aX1) * (aX2 - aX1) + (aY2 - aY1) * (aY2 - aY1));
  246. }
  247.  
  248. float distance(int aWaypoint, float aX, float aY)
  249. {
  250.     return distance((float)gWaypoint[aWaypoint].mX, (float)gWaypoint[aWaypoint].mY, aX, aY);
  251. }
  252.  
  253. float distance(int aWaypoint1, int aWaypoint2)
  254. {
  255.     return distance((float)gWaypoint[aWaypoint1].mX, (float)gWaypoint[aWaypoint1].mY, (float)gWaypoint[aWaypoint2].mX, (float)gWaypoint[aWaypoint2].mY);
  256. }
  257.  
  258. void validateWaypoint(CHARACTER &c, int &next)
  259. {
  260.     int valid = 0;
  261.     int candidate = next;
  262.     while (!valid)
  263.     {
  264.         valid = 1;
  265.         int i;
  266.         for (i = 0; i < 7; i++)
  267.             if (c.mLastWaypoints[i] == gWaypoint[c.mNextWaypoint].mConnection[candidate])
  268.                 valid = 0;
  269.         if (!valid)
  270.         {
  271.             candidate++;
  272.             if (candidate >= gWaypoint[c.mNextWaypoint].mConnections)
  273.                 candidate = 0;
  274.             if (candidate == next) // no valid waypoints
  275.                 return;
  276.         }
  277.     }
  278.     next = candidate;
  279. }
  280.  
  281. void handle_ai(CHARACTER &c)
  282. {
  283.     // is this AI inactive?
  284.     if (c.mType == -1) 
  285.         return;
  286.     
  287.     // Kludge: hit position sign
  288.     if (c.mType == 3 || c.mType == 4)
  289.     {
  290.         
  291.         c.mTTL--;
  292.         if (c.mTTL < 0)
  293.             c.mType = -1;
  294.         return;
  295.     }
  296.  
  297.     // Pedestrian AI
  298.     // Pedestrians just walk around, and try not to walk
  299.     // in circles.
  300.     if (c.mType == 2)
  301.     {
  302.         float dist = distance(c.mNextWaypoint, c.mX, c.mY);
  303.         // Have we arrived at waypoint?
  304.         if (dist < 4)
  305.         {
  306.             
  307. #ifdef RECYCLE_PEDESTRIANS
  308.             // Reduce time to live..
  309.             c.mTTL--;
  310.             if (c.mTTL <= 0)
  311.             {
  312.                 // Wipe and recycle..
  313.                 spa(2);
  314.                 c.mType = -1;
  315.                 return;
  316.             }
  317. #endif
  318.             // Store current waypoint in old waypoints list..
  319.             c.mLastWaypoints[c.mLastWaypoint] = c.mNextWaypoint;
  320.             c.mLastWaypoint++;
  321.             if (c.mLastWaypoint >= 7)
  322.                 c.mLastWaypoint = 0;
  323.             // Find a new waypoint
  324.          
  325.             int next = rand() % gWaypoint[c.mNextWaypoint].mConnections;
  326.             validateWaypoint(c, next);
  327.             c.mNextWaypoint = gWaypoint[c.mNextWaypoint].mConnection[next];
  328.             // Calculate vector..
  329.             dist = distance(c.mNextWaypoint, c.mX, c.mY);
  330.             c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  331.             c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;        
  332.             
  333.         }
  334.     }
  335.  
  336.     // VIP AI
  337.     // VIPs try to find their way to their exit point.
  338.     if (c.mType == CHAR_VIP)
  339.     {
  340.         if (c.mNextWaypoint == -1)
  341.         {
  342.             // Have we arrived home?
  343.             float dist = distance((float)gSpawnpoint[c.mTarget].mX, (float)gSpawnpoint[c.mTarget].mY, c.mX, c.mY);
  344.             if (dist < 4)
  345.             {
  346.                 // arrived safely.
  347.                 c.mType = -1;
  348.                 gScore += 5000;
  349.                 gVIPCount--;
  350.                 gVIPsGottenToSafety++;
  351.             }
  352.         }
  353.         else
  354.         {
  355.             float dist = distance(c.mNextWaypoint, c.mX, c.mY);
  356.             // Have we arrived at waypoint?
  357.             if (dist < 4)
  358.             {            
  359.                 // Store current waypoint in old waypoints list..
  360.                 c.mLastWaypoints[c.mLastWaypoint] = c.mNextWaypoint;
  361.                 c.mLastWaypoint++;
  362.                 if (c.mLastWaypoint >= 7)
  363.                     c.mLastWaypoint = 0;
  364.                 // Find a new waypoint
  365.                 
  366.                 // Can we get to the final destination from here?
  367.                 if (route((int)c.mX, (int)c.mY, gSpawnpoint[c.mTarget].mX, gSpawnpoint[c.mTarget].mY))
  368.                 {
  369.                     // Yep, calculate vector to home
  370.                     c.mNextWaypoint = -1;
  371.                     dist = distance((float)gSpawnpoint[c.mTarget].mX, (float)gSpawnpoint[c.mTarget].mY, c.mX, c.mY);
  372.                     c.mXi = ((gSpawnpoint[c.mTarget].mX - c.mX) / dist) * c.mSpeed;
  373.                     c.mYi = ((gSpawnpoint[c.mTarget].mY - c.mY) / dist) * c.mSpeed;
  374.                 }
  375.                 else
  376.                 {   
  377.                     // Nope, try to figure out the closest waypoint to target that's connected from here
  378.                     int next = 0;
  379.                     dist = distance(gWaypoint[c.mNextWaypoint].mConnection[0], (float)gSpawnpoint[c.mTarget].mX, (float)gSpawnpoint[c.mTarget].mY);
  380.                     int i;
  381.                     for (i = 1; i < gWaypoint[c.mNextWaypoint].mConnections; i++)
  382.                     {
  383.                         float newdist = distance(gWaypoint[c.mNextWaypoint].mConnection[i], (float)gSpawnpoint[c.mTarget].mX, (float)gSpawnpoint[c.mTarget].mY);
  384.                         if (newdist < dist)
  385.                         {
  386.                             dist = newdist;
  387.                             next = i;
  388.                         }
  389.                     }
  390.                     // Make sure we're not walking in circles:
  391.                     validateWaypoint(c, next);
  392.                     c.mNextWaypoint = gWaypoint[c.mNextWaypoint].mConnection[next];
  393.                     // Calculate vector..
  394.                     dist = distance(c.mNextWaypoint, c.mX, c.mY);
  395.                     c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  396.                     c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;        
  397.                 }
  398.             
  399.             }
  400.         }
  401.     }
  402.  
  403.     // Bad guy AI
  404.     // Bad guys try to find their way to a VIP.
  405.     if (c.mType == CHAR_BADGUY)
  406.     {
  407.         if (c.mTarget != -1 && gCharacter[c.mTarget].mType != 1)
  408.         {
  409.             // Lost target
  410.             c.mTarget = -1;
  411.         }
  412.  
  413.         if (c.mTarget == -1) // Bad guy without a target
  414.         {
  415.             if (gVIPCount == 0)
  416.             {
  417.                 // No VIPs to pester, walk around randomly
  418.                 
  419.                 if (c.mNextWaypoint == -1)
  420.                 {
  421.                     // We were walking towards a VIP last time, so
  422.                     // we'll need to find the closest waypoint and walk to that.
  423.                     c.mNextWaypoint = 0;
  424.                     int i;
  425.                     float dist = distance(0, c.mX, c.mY);
  426.                     for (i = 1; i < gWaypointCount; i++)
  427.                     {
  428.                         float newdist = distance(i, c.mX, c.mY);
  429.                         if (newdist < dist && route(gWaypoint[i].mX, gWaypoint[i].mY, (int)c.mX, (int)c.mY))
  430.                         {
  431.                             dist = newdist;
  432.                             c.mNextWaypoint = i;
  433.                         }
  434.                     }
  435.                     // Calculate vector towards the closest waypoint
  436.                     c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  437.                     c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;
  438.                 }
  439.                 else // just walk towards the next waypoint normally
  440.                 {
  441.                     float dist = distance(c.mNextWaypoint, c.mX, c.mY);
  442.                     // Have we arrived at waypoint?
  443.                     if (dist < 4)
  444.                     {
  445.                         int next = rand() % gWaypoint[c.mNextWaypoint].mConnections;
  446.                         // Bad guys have nowhere to go, so they might
  447.                         // as well walk in circles.. (hence, no validatewaypoint)
  448.                         c.mNextWaypoint = gWaypoint[c.mNextWaypoint].mConnection[next];
  449.                         // Calculate vector..
  450.                         dist = distance(c.mNextWaypoint, c.mX, c.mY);
  451.                         c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  452.                         c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;        
  453.                     }
  454.                 }
  455.             }
  456.             else // target a VIP
  457.             {
  458.                 int t = rand() % gVIPCount;
  459.                 int i = 0;
  460.                 while (t > 0 || gCharacter[i].mType != CHAR_VIP)
  461.                 {
  462.                     if (gCharacter[i].mType == CHAR_VIP)
  463.                         t--;
  464.                     i++;
  465.                 }                
  466.                 c.mTarget = i;
  467.                 // Avoid sudden death:
  468.                 if (distance(c.mX, c.mY, gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY) < 20)
  469.                 {
  470.                     c.mTarget = -1;
  471.                     if (c.mNextWaypoint == -1)
  472.                     {
  473.                         c.mXi = 0;
  474.                         c.mYi = 0;
  475.                     }
  476.                 }
  477.             }
  478.         }
  479.         
  480.         int nolineofsight = 1;
  481.  
  482.         // Do we have line of sight to the VIP?
  483.         if (route((int)c.mX, (int)c.mY, (int)gCharacter[c.mTarget].mX, (int)gCharacter[c.mTarget].mY))
  484.         {
  485.             nolineofsight = 0;
  486.             // Calculate new vector to it
  487.             float dist = distance(gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY, c.mX, c.mY);
  488.             c.mXi = ((gCharacter[c.mTarget].mX - c.mX) / dist) * c.mSpeed;
  489.             c.mYi = ((gCharacter[c.mTarget].mY - c.mY) / dist) * c.mSpeed;
  490.             c.mNextWaypoint = -1;
  491.         }
  492.  
  493.  
  494.         if (c.mNextWaypoint == -1)
  495.         {
  496.             // Caught up with the VIP?
  497.             float dist = distance((float)gCharacter[c.mTarget].mX, (float)gCharacter[c.mTarget].mY, c.mX, c.mY);
  498.             if (dist < 3)
  499.             {
  500.                 // arrived safely.
  501.                 c.mType = -1;
  502.                 gScore -= 10000; // +game over
  503.                 gVIPCount--;
  504.                 gBadGuyCount--;
  505.                 gCharacter[c.mTarget].mType = -1;
  506. #ifdef DISPLAY_GAMEOVER_SCREEN
  507.                 gameoverscreen(2);
  508.                 return;
  509. #endif
  510.             }
  511.             else
  512.             {
  513.                 if (nolineofsight)
  514.                 {
  515.                     // Lost the VIP. Find closest accessible waypoint.
  516.                     c.mNextWaypoint = 0;
  517.                     int i;
  518.                     float dist = distance(0, gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY);
  519.                     for (i = 1; i < gWaypointCount; i++)
  520.                     {
  521.                         float newdist = distance(i, gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY);
  522.                         if (newdist < dist && route(gWaypoint[i].mX, gWaypoint[i].mY, (int)c.mX, (int)c.mY))
  523.                         {
  524.                             dist = newdist;
  525.                             c.mNextWaypoint = i;
  526.                         }
  527.                     }
  528.                     // Calculate vector towards the closest waypoint
  529.                     dist = distance(c.mNextWaypoint, c.mX, c.mY);
  530.                     c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  531.                     c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;        
  532.                 }
  533.             }
  534.         }
  535.         else
  536.         {
  537.             float dist = distance(c.mNextWaypoint, c.mX, c.mY);
  538.             // Have we arrived at waypoint?
  539.             if (dist < 4)
  540.             {            
  541.                 // Find a new waypoint
  542.                 
  543.                 if (nolineofsight)
  544.                 {   
  545.                     // Can't see the VIP, try to figure out the closest waypoint to target that's connected from here
  546.                     int next = 0;
  547.                     dist = distance(gWaypoint[c.mNextWaypoint].mConnection[0], gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY);
  548.                     int i;
  549.                     for (i = 1; i < gWaypoint[c.mNextWaypoint].mConnections; i++)
  550.                     {
  551.                         float newdist = distance(gWaypoint[c.mNextWaypoint].mConnection[i], gCharacter[c.mTarget].mX, gCharacter[c.mTarget].mY);
  552.                         if (newdist < dist)
  553.                         {
  554.                             dist = newdist;
  555.                             next = i;
  556.                         }
  557.                     }
  558.                     // Note: bad guys MAY run in circles.                    
  559.                     c.mNextWaypoint = gWaypoint[c.mNextWaypoint].mConnection[next];
  560.                     // Calculate vector..
  561.                     dist = distance(c.mNextWaypoint, c.mX, c.mY);
  562.                     c.mXi = ((gWaypoint[c.mNextWaypoint].mX - c.mX) / dist) * c.mSpeed;
  563.                     c.mYi = ((gWaypoint[c.mNextWaypoint].mY - c.mY) / dist) * c.mSpeed;        
  564.                 }
  565.             
  566.             }
  567.         }
  568.     }
  569.  
  570.  
  571.     // Make 'em walk
  572.     c.mX += c.mXi;
  573.     c.mY += c.mYi;    
  574. }
  575.  
  576. int findspawnpoint(int aIndex, int aType)
  577. {
  578.     int i, j;
  579.     j = 0;
  580.     i = 0;
  581.     while (i < gSpawnpointCount)
  582.     {
  583.         if (gSpawnpoint[i].mType == aType)
  584.             j++;
  585.         if (j > aIndex) 
  586.             return i;
  587.         i++;
  588.     }
  589.     return i;
  590. }
  591.  
  592. int spawn_ai(int aType)
  593. {
  594.     
  595.     // find empty slot
  596.     int slot = 0;
  597.     while (slot < gCharacterCount && gCharacter[slot].mType != -1) slot++;
  598.     gCharacter[slot].mType = -1; // Overwrite the last slot if all slots were in use
  599.     gCharacter[slot].mLastWaypoint = 0;
  600.     int i;
  601.     for (i = 0; i < 7; i++)
  602.         gCharacter[slot].mLastWaypoints[i] = -1;
  603.  
  604.     if (aType == CHAR_BADGUY)
  605.     {
  606.         gBadGuyCount++;
  607.         // spawn a bad guy
  608.         int spawnpoint = 0;
  609.         int i = rand() % gBadGuySpawnCount;
  610.         spawnpoint = findspawnpoint(i, CHAR_BADGUY);
  611.  
  612.         gCharacter[slot].mType = CHAR_BADGUY;
  613.         gCharacter[slot].mX = (float)gSpawnpoint[spawnpoint].mX;
  614.         gCharacter[slot].mY = (float)gSpawnpoint[spawnpoint].mY;
  615.         gCharacter[slot].mTarget = -1; // find target at next handle_ai pass
  616.         gCharacter[slot].mNextWaypoint = gSpawnpoint[spawnpoint].mClosestWaypoint;
  617.     }
  618.  
  619.     if (aType == CHAR_VIP)
  620.     {
  621.         if (gVIPCount >= 3)
  622.             return 0; // 3 vips at a time, thanks
  623.         gVIPCount++;
  624.         // spawn a VIP
  625.         int spawnpoint = 0;
  626.         int i = rand() % gVIPSpawnCount;
  627.         spawnpoint = findspawnpoint(i, CHAR_VIP);
  628.  
  629.         gCharacter[slot].mType = CHAR_VIP;
  630.         gCharacter[slot].mX = (float)gSpawnpoint[spawnpoint].mX;
  631.         gCharacter[slot].mY = (float)gSpawnpoint[spawnpoint].mY;
  632.         gCharacter[slot].mNextWaypoint = gSpawnpoint[spawnpoint].mClosestWaypoint;        
  633.  
  634.         int targetspawnpoint = 0;
  635.         float dist = 0;
  636.         // find target waypont, avoiding free score
  637.         while (dist < 20)
  638.         {
  639.             i = rand() % gVIPSpawnCount;
  640.             targetspawnpoint = findspawnpoint(i, 1);
  641.             dist = distance(gCharacter[slot].mX, gCharacter[slot].mY, (float)gSpawnpoint[targetspawnpoint].mX, (float)gSpawnpoint[targetspawnpoint].mY);
  642.         }
  643.         gCharacter[slot].mTarget = targetspawnpoint;
  644.     }
  645.  
  646.     if (aType == CHAR_PEDESTRIAN)
  647.     {
  648.         // spawn a pedestrian
  649.         int spawnpoint = 0;
  650.         int i = rand() % gPedestrianSpawnCount;
  651.         spawnpoint = findspawnpoint(i, CHAR_PEDESTRIAN);
  652.         gCharacter[slot].mType = CHAR_PEDESTRIAN;
  653.         gCharacter[slot].mX = (float)gSpawnpoint[spawnpoint].mX;
  654.         gCharacter[slot].mY = (float)gSpawnpoint[spawnpoint].mY;
  655.         gCharacter[slot].mTTL = rand() % 10 + 5;
  656.         gCharacter[slot].mNextWaypoint = gSpawnpoint[spawnpoint].mClosestWaypoint;        
  657.     }
  658.     float dist = distance(gCharacter[slot].mNextWaypoint, gCharacter[slot].mX, gCharacter[slot].mY);
  659.     gCharacter[slot].mSpeed = (((rand()/32768.0f) + 0.5f) * 0.5f) / 5.0f;    // HatConstant(tm)
  660.     // slow down pedestrians, they're not in a hurry..
  661.     if (aType == CHAR_PEDESTRIAN) gCharacter[slot].mSpeed *= 0.5f;
  662.     gCharacter[slot].mXi = ((gWaypoint[gCharacter[slot].mNextWaypoint].mX - gCharacter[slot].mX) / dist) * gCharacter[slot].mSpeed;
  663.     gCharacter[slot].mYi = ((gWaypoint[gCharacter[slot].mNextWaypoint].mY - gCharacter[slot].mY) / dist) * gCharacter[slot].mSpeed;
  664.     return slot;
  665. }
  666.  
  667.  
  668.  
  669. void shoot()
  670. {
  671.     gWobbleIndex += 2048;
  672.     gReloading = RELOAD_TIME;
  673. #ifdef CAMERA_RECOIL    
  674.     if (gMouseZ < 0.25f) gMouseZ = 0.25f;
  675. #ifndef CAMERA_STEPS
  676.     gCoordScale = gMouseZ;
  677. #else
  678.     gCoordScale = ((int)(gMouseZ * 4)) / 4.0f;
  679.     if (gCoordScale < 0.05f) gCoordScale = 0.05f;
  680. #endif
  681. #endif
  682.     int slot = 0;
  683.     while (gCharacter[slot].mType != -1) slot++;
  684.     gCharacter[slot].mLastWaypoint = 0;
  685.  
  686.     float worldx = gMouseX + gWobbleX + gCenterX + 320 * gCoordScale;
  687.     float worldy = gMouseY + gWobbleY + gCenterY + 240 * gCoordScale;
  688.  
  689.     int hit = 0;
  690.     int gameover = 0;
  691.     int i;
  692.     for (i = 0; i < gCharacterCount; i++)
  693.     {
  694.         if (gCharacter[i].mType != -1)
  695.         {
  696.             if (gCharacter[i].mX > worldx - 1 &&
  697.                 gCharacter[i].mX < worldx + 1 &&
  698.                 gCharacter[i].mY > worldy - 1 &&
  699.                 gCharacter[i].mY < worldy + 1)
  700.             {
  701.                 if (gCharacter[i].mType == CHAR_BADGUY)
  702.                 {
  703.                     gScore += 1000;
  704.                     gBadGuyCount--;
  705.                     gBadGuisKilled++;
  706.                 }
  707.                 if (gCharacter[i].mType == CHAR_VIP)
  708.                 {
  709.                     gScore -= 100000; // +game over
  710.                     gameover = 1;
  711.                     gVIPCount--;
  712.                 }
  713.                 if (gCharacter[i].mType == CHAR_PEDESTRIAN)
  714.                 {
  715.                     gPedestriansKilled++;
  716.                     gScore -= 100;
  717. #ifdef RECYCLE_PEDESTRIANS
  718.                    spawn_ai(2); // spawn a new pedestrian
  719. #endif
  720.                 }
  721.                 gCharacter[i].mType = -1;
  722.                 hit = 1;
  723.             }
  724.         }
  725.     }
  726. #ifdef DISPLAY_GAMEOVER_SCREEN
  727.     if (gameover)
  728.     {
  729.         gameoverscreen(1);
  730.     }
  731. #endif
  732.  
  733.     gCharacter[slot].mType = hit?3:4; // hit marker
  734.     gCharacter[slot].mX = worldx;
  735.     gCharacter[slot].mY = worldy;
  736.     gCharacter[slot].mTTL = 100;
  737. }