home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mnth0109.zip / Timur / target0.c < prev    next >
Text File  |  1993-06-07  |  10KB  |  253 lines

  1. /* TARGET0.C - base functions for module TARGET
  2.  
  3. Copyright (c) 1992-1993 Timur Tabi
  4. Copyright (c) 1992-1993 Fasa Corporation
  5.  
  6. The following trademarks are the property of Fasa Corporation:
  7. BattleTech, CityTech, AeroTech, MechWarrior, BattleMech, and 'Mech.
  8. The use of these trademarks should not be construed as a challenge to these marks.
  9.  
  10. */
  11. #define INCL_GPILOGCOLORTABLE
  12. #define INCL_DOSPROCESS
  13. #include <os2.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16.  
  17. #include "header.h"
  18. #include "errors.h"
  19. #include "hexes.h"
  20. #include "target.h"
  21. #include "terrain.h"                    // for GetVisibility()
  22. #include "window.h"
  23.  
  24. void static DoHighlight(HPS hps) {
  25. /* This function does the actual highlighting.  It returns either if an error occurs, or if
  26.    target.fActive becomes false.
  27.    Future enhancement: temporarily disable this thread during target path drawing.
  28. */
  29.   int i;
  30.  
  31.   if (lNumColors>16) {
  32.     if (!GpiCreateLogColorTable(hps,0,LCOLF_RGB,0,0,NULL)) return;
  33.     for (i=0; target.fActive; i+=20) {
  34.       if (!GpiSetColor(hps,(LONG) ((i & 255) << 16))) return;
  35.       HexOutline(hps,target.hiStart);
  36.       if (DosSleep(30)) return;                               // Allows the main thread to run better
  37.     }
  38.   } else
  39.     while (target.fActive) {
  40.       if (!GpiSetColor(hps,CLR_RED)) return;
  41.       HexOutline(hps,target.hiStart);
  42.       if (DosSleep(300L)) return;
  43.       if (!target.fActive) return;
  44.       if (!GpiSetColor(hps,HEX_COLOR)) return;
  45.       HexOutline(hps,target.hiStart);
  46.       if (DosSleep(300L)) return;
  47.     }
  48. }
  49.  
  50. void APIENTRY Highlight(ULONG ul) {
  51. /* This function changes the color of the outline of the origin hex during targetting.  It is
  52.    started as a background thread and continues until target.fActive becomes FALSE.  If there
  53.    are more than 16 colors, then a routine which cycles through 256 shades of red is chosen.
  54.    Otherwise, the outline simply blinks red.  At termination, the outline is erased.
  55.  
  56.    Can someone tell me if it even works on a 256-color monitor?  I haven't even seen it yet.
  57.  
  58.    At this writing the code for color-cycling has NOT been tested on a monitor with 256-colors.
  59.    It has been tested on a 16-color monitor and looks stupid.
  60.  
  61.    Once it creates a presentation space, it calls DoHighlight() to do the actual work.  When
  62.    DoHighlight() exits, the presentation space handle is released.  This ensures that the
  63.    presentation space handle is always released.
  64. */
  65.  
  66. // Array of vertices of the outline of a hexagon
  67.   HPS hps=WinGetPS(hwndClient);
  68.  
  69.   if (hps != NULLHANDLE) {
  70.     DoHighlight(hps);
  71.     GpiSetColor(hps,HEX_COLOR);                 // Erase the outline before exiting
  72.     HexOutline(hps,target.hiStart);
  73.     WinReleasePS(hps);
  74.   }
  75. }
  76.  
  77. static int GetRange(void) {
  78. /* returns the range between target.hiStart and target.hiEnd
  79. */
  80.   int dx=target.hiEnd.c-target.hiStart.c;
  81.   int dy=target.hiEnd.r-target.hiStart.r;             // always even
  82.   int d=abs(dy)-abs(dx);                              // always even if d>0
  83.  
  84.   if (d <= 0)
  85.     return abs(dx);
  86.   else
  87.     return abs(dx)+d/2;
  88. }
  89.  
  90. static BOOL Intersect(POINTL ptl1, POINTL ptl2) {
  91. /* This function retruns TRUE if the line segment from ptl1 to ptl2 intersects
  92.    with the targeting line.  Let s1 be the segment and let s2 be the targeting
  93.    line itself.  If we extend s1 to a line, then that
  94.    line is called l1.  Similarly, l2 is the line of s2.
  95.  
  96.    The math is quite simple.  Calculate the slopes of l1 and l2.
  97.    Find the x coordinate of the intersection of l1 and l2.  If the x coordinate
  98.    is between ptl1.x and ptl2.x, then the two seconds intersect.
  99.  
  100.    This function assumes that l1 does not have an infinite slope.
  101.  
  102.    Future enhancement: possible speed increase with matrix math
  103. */
  104.   float m,b;                                    // Slopes & intercepts
  105.   int x;                                        // Intersection x-coordinate
  106.   int dx;                                       // x-delta for l1
  107.   float f;                                      // Temp variable
  108.  
  109. // Is the targeting line vertical?
  110.   if (target.dx == 0)
  111.     return (BOOL) BETWEEN(target.ptlStart.x,ptl1.x,ptl2.x);
  112.  
  113.   dx=ptl2.x-ptl1.x;
  114.   m=(float) (ptl2.y - ptl1.y) / dx;
  115.   if (m==target.m) return FALSE;                // If the slopes are equal, the lines won't intersect
  116.   b=ptl1.y-m*ptl1.x;
  117.  
  118.   f=(target.b-b) / (m-target.m);                // Calculate the floating-point first
  119.   x=(int) f;                                    //  To avoid round-off errors
  120.  
  121. // Now just test the intersection point
  122.   return (BOOL) ( BETWEEN(x,ptl1.x,ptl2.x) && BETWEEN(x,target.ptlStart.x,target.ptlEnd.x) );
  123. }
  124.  
  125. static POINTL SideMidpoint(HEXINDEX hi, int iSide) {
  126. /* This function returns the coordinate of the midpoint of side iSide of hexagon 'hi'.
  127. */
  128.   static const POINTL ptlMidpoints[6]={ {HEX_SIDE+HEX_EXT/2,HEX_HEIGHT/4},
  129.     {HEX_SIDE+HEX_EXT/2,3*HEX_HEIGHT/4},
  130.     {HEX_SIDE/2,HEX_HEIGHT},
  131.     {-HEX_EXT/2,3*HEX_HEIGHT/4},
  132.     {-HEX_EXT/2,HEX_HEIGHT/4},
  133.     {HEX_SIDE/2,0},
  134.   };
  135.   POINTL ptl=HexCoord(hi);
  136.  
  137.   ptl.x+=ptlMidpoints[iSide].x;
  138.   ptl.y+=ptlMidpoints[iSide].y;
  139.   return ptl;
  140. }
  141.  
  142. static int Distance(POINTL ptl1, POINTL ptl2) {
  143. /* Calculates the distance between two points
  144. */
  145.   int dy=ptl2.y-ptl1.y;
  146.   int dx=ptl2.x-ptl1.x;
  147.  
  148.   return (int) sqrt(dy*dy+dx*dx);
  149. }
  150.  
  151. #define CLOSENESS 4   // Anything smaller than this, and the line zig-zags too much
  152.  
  153. static BOOL Close(POINTL ptl) {
  154. /* This function returns true of ptl is very close to the targetting line.
  155.    The definition of "close" depends on the value of CLOSENESS.
  156.    It returns FALSE if the targetting line is vertical, since a vertical line will never be
  157.    near a vertex.
  158. */
  159.   double d;
  160.  
  161.   if (target.dx == 0) return FALSE;                           // vertical targetting line?
  162.  
  163.   if (target.ptlStart.y == target.ptlEnd.y)                   // horizontal targetting line?
  164.     return (BOOL) (abs(ptl.y - target.ptlStart.y) <= CLOSENESS);
  165.  
  166. /* It's neither vertical nor horizontal, so it must be at an angle.  Let 'l' represent the line
  167.    segment from the point to the targetting line, such that 'l' is perpendicular to the targetting
  168.    line.  The slope of 'l' is -1/target.m
  169.    If ax+by+c=0 describes the targetting line, we see that a=-target.m, b=1, and c=-target.b
  170.    If p=ptl.x and q=ptl.y, then the distance is: abs(ap+bq+c)/sqrt(a^2+b^2)
  171. */
  172.   d=fabs(ptl.y-target.m*ptl.x-target.b) / sqrt(target.m*target.m+1.0);
  173.  
  174.   return (BOOL) (d <= CLOSENESS);
  175. }
  176.  
  177. static int NearestSlope(int iSide1, int iSide2) {
  178. /* Given a choice of two sides (iSide1 and iSide2), this function returns the side whose
  179.    perpendicular radius (the line from the center of the hexagon to the midpoint of the side)
  180.    has a slope that is nearest to the slope of the targetting line.
  181. */
  182.   static const int iAngles[6]={-30,30,90,150,-150,-90};     // Angle of all the radii
  183.   int d1=abs(target.angle-iAngles[iSide1]);
  184.   int d2=abs(target.angle-iAngles[iSide2]);
  185.  
  186.   return (d1<d2) ? iSide1 : iSide2;
  187. }
  188.  
  189. int ExitSide(HEXINDEX hi) {
  190. /* This function locates the side of 'hi' through which the targetting line exits.  This side is
  191.    called the 'exit side'.
  192.  
  193.    This function may select a side adjacent to the true exit side, if it determines that this
  194.    side would produce a better targetting path.
  195. */
  196.   int iSide=-1;            // The true exit side
  197.   int iSide1,iSide2;       // The two sides adjacent to the exit side.  Used in case of closeness
  198.   int i;
  199.   int d,d1;                // d=distance from exit side to target. d1=temp distance
  200.   POINTL ptl1, ptl2;
  201.  
  202. // First, find the intersecting side that is closest to the target.  This loop checks each of the
  203. // six sides in order.
  204.   for (i=0; i<6; i++) {
  205.     HexPointsFromSide(hi,i,&ptl1,&ptl2);                    // Find the endpoints of side 'i'
  206.     if (Intersect(ptl1, ptl2)) {                            // Does the targetting line intersect it?
  207.       d1=Distance(SideMidpoint(hi,i),target.ptlEnd);        // Yes, so find the distance from it
  208.       if (iSide == -1 || d1<d) {                            // Is this the first match? Or is it closer
  209.         iSide=i;                                            //  than the previous one?
  210.         d=d1;                                               // If so, then update our current values
  211.       }
  212.     }
  213.   }
  214.  
  215.   if (iSide == -1) return -1;                               // Couldn't find a side? Return error
  216.  
  217. // Second, check for vertex redirection
  218.  
  219.   HexPointsFromSide(hi,iSide,&ptl1,&ptl2);
  220.  
  221.   iSide1 = Close(ptl1) ? NearestSlope((iSide+5) % 6,iSide) : -1;
  222.   iSide2 = Close(ptl2) ? NearestSlope(iSide,(iSide+1) % 6) : -1;
  223.  
  224.   if (iSide1==iSide2) return iSide;
  225.  
  226.   if (iSide1==-1) return iSide2;
  227.   if (iSide2==-1) return iSide1;
  228.   return NearestSlope(iSide1,iSide2);
  229. }
  230.  
  231. int FirstSide(HEXINDEX hiFrom, HEXINDEX hiTo) {
  232. /* This function returns the side to the first hexagon that follows the trajectory
  233.    from hiFrom to hiTo.  If the targetting line passes through a vertex, this function
  234.    returns a -1
  235. */
  236.   int dx,dy=hiTo.r - hiFrom.r;
  237.   float m;
  238.  
  239.   if (dy == 0) return -1;
  240.  
  241.   dx=hiTo.c - hiFrom.c;
  242.   if (dx == 0) return (dy>0) ? 2 : 5;           // Vertical line?
  243.  
  244.   m=(float) dy/dx;
  245.   if (fabs(m) == 3.0) return -1;
  246.  
  247.   if (fabs(m)>3.0) return (dy>0) ? 2 : 5;               // Almost a vertical line?
  248.  
  249.   if (m>0.0) return (dx>0) ? 1 : 4;
  250.  
  251.   return (dx>0) ? 0 : 3;
  252. }
  253.