home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mnth0108.zip / Timur / target.c < prev    next >
Text File  |  1993-03-14  |  9KB  |  261 lines

  1. /* TARGET.C - Targeting routines
  2.  
  3. Copyright (c) 1993 Timur Tabi
  4. Copyright (c) 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.  
  12. #define TARGET_C
  13. #define INCL_DOS
  14. #define INCL_GPIPRIMITIVES
  15. #define INCL_WINWINDOWMGR
  16. #define INCL_GPIBITMAPS
  17. #include <os2.h>
  18. #include <math.h>
  19. #include <stdlib.h>
  20. #include "header.h"
  21. #include "target.h"
  22. #include "dialog.h"
  23. #include "terrain.h"
  24.  
  25. void TgtInitialize(HWND hwnd) {
  26. /* Initializes variables that remain the same for all targeting functions.
  27.    Future enhancement: improve positioning algorithm of info box.
  28. */
  29.   target.fActive=FALSE;
  30.   target.hpsLine=WinGetPS(hwnd);
  31.   target.hpsHighlight=WinGetPS(hwnd);
  32.   target.hpsPath=WinGetPS(hwnd);
  33.   GpiSetColor(target.hpsLine,CLR_WHITE);
  34.   GpiSetMix(target.hpsLine,FM_XOR);
  35.   GpiSetColor(target.hpsPath,CLR_RED);
  36.   GpiSetMix(target.hpsPath,FM_XOR);
  37. }
  38.  
  39. void TgtShutdown(void) {
  40. /* This function releases the presentation-space handles when the program
  41.    terminates.
  42. */
  43.   WinReleasePS(target.hpsLine);
  44.   WinReleasePS(target.hpsHighlight);
  45.   WinReleasePS(target.hpsPath);
  46. }
  47.  
  48. void TgtStart(HEXINDEX hi) {
  49. /* This function activates the targeting mechanism.  It also spanws the thread that
  50.    performs the color cycling of the source hexagon
  51. */
  52.   target.fActive=TRUE;
  53.   target.hiStart=hi;
  54.   target.hiEnd=hi;
  55.   target.ptlStart=HexMidpoint(hi);
  56.   target.ptlEnd=target.ptlStart;
  57.  
  58.   DosCreateThread(&target.tid,HexHighlight,0UL,0UL,4096UL);
  59. }
  60.  
  61. int GetAngle(void) {
  62. /* Returns the targeting angle
  63. */
  64.   const double pi=3.1415926535897932384;                // Is this already declared anywhere?
  65.  
  66.   return (int) (atan2(target.ptlEnd.y-target.ptlStart.y,target.ptlEnd.x-target.ptlStart.x)*180.0/pi);
  67. }
  68.  
  69. int GetRange(void) {
  70. /* returns the range between target.hiStart and target.hiEnd
  71. */
  72.   int dx=target.hiEnd.c-target.hiStart.c;
  73.   int dy=target.hiEnd.r-target.hiStart.r;             // always even
  74.   int d=abs(dy)-abs(dx);                              // always even if d>0
  75.  
  76.   if (d <= 0)
  77.     return abs(dx);
  78.   else
  79.     return abs(dx)+d/2;
  80. }
  81.  
  82. BOOL Intersect(POINTL ptl1, POINTL ptl2) {
  83. /* This function retruns TRUE if the line segment from ptl1 to ptl2 intersects
  84.    with the targeting line.  Let s1 be the segment and let s2 be the targeting
  85.    line itself.  If we extend s1 to a line, then that
  86.    line is called l1.  Similarly, l2 is the line of s2.
  87.  
  88.    The math is quite simple.  Calculate the slopes of l1 and l2.
  89.    Find the x coordinate of the intersection of l1 and l2.  If the x coordinate
  90.    is between ptl1.x and ptl2.x, then the two seconds intersect.
  91.  
  92.    This function assumes that l1 and l2 do not _both_ have infinite slopes.
  93.  
  94.    Future enhancement: possible speed increase with matrix math
  95. */
  96.   float m,b;                                    // Slopes & intercepts
  97.   int x;                                        // Intersection x-coordinate
  98.   int dx;                                       // x-delta for l1
  99.   float f;                                      // Temp variable
  100.  
  101. // Is the targeting line vertical?
  102.   if (target.dx == 0)
  103.     return (BOOL) BETWEEN(target.ptlStart.x,ptl1.x,ptl2.x);
  104.  
  105.   dx=ptl2.x-ptl1.x;
  106.   m=(float) (ptl2.y - ptl1.y) / dx;
  107.   b=ptl1.y-m*ptl1.x;
  108.  
  109.   f=(target.b-b) / (m-target.m);                // Calculate the floating-point first
  110.   x=(int) f;                                    //  To avoid round-off errors
  111.  
  112. // Now just test the intersection point
  113.   return (BOOL) ( BETWEEN(x,ptl1.x,ptl2.x) && BETWEEN(x,target.ptlStart.x,target.ptlEnd.x) );
  114. }
  115.  
  116. int NextHexSide(HEXINDEX hi, int iSide) {
  117. /* This function is used to find the intersection of hexagon hi with
  118.    the targetting line.  It assumes that the line enters
  119.    the hexagon at side iSide.  It checks the next four sides until
  120.    it finds one that also intersects with the line.  If it can't find one,
  121.    then it assumes that the fifth (last) side must be the one.
  122.  
  123.    The first side (iSide == 0) is the at the lower-right side of the hexagon.
  124.  
  125.    Future enhancement: correction factor if targeting line is close to a vertex.
  126. */
  127.   int i;
  128.   POINTL ptl1, ptl2;
  129.  
  130.   for (i=0; i<4; i++) {
  131.     iSide=(++iSide) % 6;                       // Get the next side #
  132.     HexPointFromSide(hi,iSide,&ptl1,&ptl2);
  133.     if (Intersect(ptl1, ptl2)) return iSide;
  134.   }
  135.   return (iSide+1) % 6;                       // It has to be the last one
  136. }
  137.  
  138. void TgtInitPath(void) {
  139. /* This function is used to initialize the m, b, and dx fields of structure 'target'.
  140.    This makes sure that we don't waste any time calculating the targeting path.
  141. */
  142.   target.dx=target.ptlEnd.x-target.ptlStart.x;    // x-delta for targeting line
  143.  
  144.   if (target.dx != 0) {
  145.     target.m=(float) (target.ptlEnd.y - target.ptlStart.y) / target.dx;
  146.     target.b=target.ptlStart.y-target.m*target.ptlStart.x;
  147.   }
  148. }
  149.  
  150. void TgtShowPath(void) {
  151. /* This function a series of line segments that connect the midpoints of the
  152.    targeting path.  Since it uses the FM_XOR mix-mode, it erases the line
  153.    every other time it's called.
  154.    Assumes that target.hiStart != target.hiEnd
  155.  
  156.    Future enhancement: support for vertex angles.
  157. */
  158.   HEXINDEX hi;
  159.   POINTL ptl;
  160.   int iSide;
  161.  
  162. // Draw the first segment
  163.   hi=target.hiStart;                                  // Start at the beginning
  164.   iSide=HexFirstSide(target.hiStart,target.hiEnd);    // Which way first?
  165.   if (iSide<0) return;                                // Don't draw a line if it's through a vertex
  166.   hi=target.hiStart;                                  // Start at the beginning
  167.   ptl=HexMidpoint(hi);
  168.   GpiMove(target.hpsPath,&ptl);
  169.  
  170.   hi=HexFromSide(hi,iSide);                           // Update to the next hex
  171.   ptl=HexMidpoint(hi);
  172.   GpiLine(target.hpsPath,&ptl);                       // Draw the first segment
  173.  
  174. // If there are any more segments, draw them too
  175. // Note: If hex1 connects to hex2 at side 'x', then hex2 connects to hex1 at side '3+x', modulo 6
  176.  
  177.   while (!HI_EQUAL(hi,target.hiEnd)) {
  178.     iSide=NextHexSide(hi,(3+iSide) % 6);
  179.     hi=HexFromSide(hi,iSide);
  180.     ptl=HexMidpoint(hi);
  181.     GpiLine(target.hpsPath,&ptl);
  182.     if (HI_EQUAL(hi,target.hiStart))        // Infinite loop?
  183.       return;                               //  Then get out of here!
  184.   }
  185. }
  186.  
  187. int GetVisibility(void) {
  188. /* Returns the visibility of the target hex, as seen from the source hex.
  189.    The current implementation is a far cry from the true calculations.
  190.  
  191.    Future enhancement: support for vertex angles.
  192. */
  193.   HEXINDEX hi;
  194.   int iVis,iSide;
  195.  
  196.   if (HI_EQUAL(target.hiStart,target.hiEnd)) return 0;  // Visibility in the same hex is always zero
  197.  
  198.   iSide=HexFirstSide(target.hiStart,target.hiEnd);
  199.   if (iSide<0) return -1;                               // We'll deal with this one later
  200.   hi=HexFromSide(target.hiStart,iSide);
  201.   hi=target.hiStart;
  202.   iVis=0;
  203.  
  204.   while (!HI_EQUAL(hi,target.hiEnd)) {
  205.     iSide=NextHexSide(hi,(3+iSide) % 6);
  206.     hi=HexFromSide(hi,iSide);
  207.     iVis+=ater[amap[hi.c][hi.r].iTerrain].iVisibility;
  208.     if (HI_EQUAL(hi,target.hiStart)) break;          // Inifinite loop? Get out of here!
  209.   }
  210.   return iVis;
  211. }
  212.  
  213. void TgtMove(HEXINDEX hi) {
  214. /* Performs all the necessary updates whenever the targeting line is moved.
  215.    Called every time target.fActive is TRUE, and a WM_MOUSEMOVE message is received.
  216.    First determines if the pointer has moved to a new hexagon.  If not, it
  217.    simply exists.
  218.    Otherwise, it erases the existing targeting line and targeting path, draws
  219.    the new ones, and updates the info box.
  220.  
  221.    Future enhancement: capturing the mouse.
  222. */
  223.   char sz[33];                                          // temp string
  224.  
  225. // If the target hex hasn't moved, just exit
  226.   if HI_EQUAL(target.hiEnd,hi) return;
  227.  
  228. // Erase any existing line
  229.   if (!HI_EQUAL(target.hiStart,target.hiEnd)) {
  230.     GpiMove(target.hpsLine,&target.ptlStart);
  231.     GpiLine(target.hpsLine,&target.ptlEnd);
  232.     TgtShowPath();
  233.   }
  234.  
  235. // Set the new endpoint
  236.   target.ptlEnd=HexMidpoint(target.hiEnd=hi);
  237.   TgtInitPath();
  238.  
  239. // Draw the new line if it exists
  240.   if (!HI_EQUAL(target.hiStart,target.hiEnd)) {
  241.     GpiMove(target.hpsLine,&target.ptlStart);
  242.     GpiLine(target.hpsLine,&target.ptlEnd);
  243.     TgtShowPath();
  244.   }
  245.  
  246.   WinSetDlgItemText(hwndInfoBox,IDD_ANGLE,_itoa(GetAngle(),sz,10));
  247.   WinSetDlgItemText(hwndInfoBox,IDD_RANGE,_itoa(GetRange(),sz,10));
  248.   WinSetDlgItemText(hwndInfoBox,IDD_VISIBILITY,_itoa(GetVisibility(),sz,10));
  249. }
  250.  
  251. void TgtEnd(void) {
  252. /* Cancels the current targeting session
  253. */
  254.   target.fActive=FALSE;                           // Automatically terminates HexHighlight
  255.   if (!HI_EQUAL(target.hiStart,target.hiEnd)) {   // Erase the line if it exists
  256.     GpiMove(target.hpsLine,&target.ptlStart);
  257.     GpiLine(target.hpsLine,&target.ptlEnd);
  258.     TgtShowPath();
  259.   }
  260. }
  261.