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

  1. /* HEXES.C - Hex map routines
  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. This module contains all the code pertaining to the hexagonal grid of the
  11. combat map.  This includes drawing and interpreting mouse input.  Hexes are
  12. identified by a column/row index passed as two integers.  X,Y coordinates
  13. are identified with a POINTL structure.
  14. */
  15.  
  16. #define INCL_DOSPROCESS
  17. #define INCL_GPIPRIMITIVES
  18. #define INCL_GPIBITMAPS
  19. #include <os2.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <math.h>
  23.  
  24. #define HEXES_C
  25.  
  26. #include "header.h"
  27. #include "errors.h"
  28. #include "resource.h"
  29. #include "hexes.h"
  30. #include "terrain.h"
  31. #include "bitmap.h"
  32. #include "window.h"
  33.  
  34. // Array of each vertex in a hexagon, ending with the lower-left corner at relative position (0,0)
  35. static POINTL aptlHex[]={ {HEX_SIDE,0},
  36.   {HEX_SIDE+HEX_EXT,HEX_HEIGHT/2},
  37.   {HEX_SIDE,HEX_HEIGHT},
  38.   {0,HEX_HEIGHT},
  39.   {-HEX_EXT,HEX_HEIGHT/2},
  40.   {0,0}                         };
  41.  
  42. POINTL HexCoord(HEXINDEX hi) {
  43. /* This function returns the X,Y coordinate of the lower-left vertex for a given hex
  44.    index.
  45. */
  46.    POINTL ptl;
  47.  
  48. // Odd numbered columns are drawn a little to the right of even columns
  49. // HEX_SIDE+HEX_EXT is the X-coordinate of column #1
  50.    if (hi.c & 1)
  51.       ptl.x=XLAG+HEX_DIAM+(2*XLAG+HEX_SIDE+HEX_DIAM)*(hi.c-1)/2;
  52.    else
  53.       ptl.x=HEX_EXT+(2*XLAG+HEX_SIDE+HEX_DIAM)*hi.c/2;
  54.    ptl.y=hi.r*(YLAG-1+HEX_HEIGHT/2);
  55.    return ptl;
  56. }
  57.  
  58. POINTL HexMidpoint(HEXINDEX hi) {
  59. /* This function is identical to HexCoord(), except that it returns the coordinates of
  60.    the midpoint (centerpoint) of the hexagon.
  61. */
  62.    POINTL ptl;
  63.  
  64.    if (hi.c & 1)
  65.       ptl.x=(HEX_SIDE/2)+XLAG+HEX_DIAM+(2*XLAG+HEX_SIDE+HEX_DIAM)*(hi.c-1)/2;
  66.    else
  67.       ptl.x=(HEX_SIDE/2)+HEX_EXT+(2*XLAG+HEX_SIDE+HEX_DIAM)*hi.c/2;
  68.    ptl.y=(HEX_HEIGHT/2)+hi.r*(YLAG-1+HEX_HEIGHT/2);
  69.    return ptl;
  70. }
  71.  
  72. void HexDraw(HPS hps, HEXINDEX hi) {
  73. /* This function draws the hexagon at index 'hi'.
  74.    Future enhancement: instead of calculating all six x,y coordinates, just relocate origin.
  75. */
  76.   int i;
  77.   POINTL aptl[6];
  78.  
  79.   aptl[5]=HexCoord(hi);                             // Move to the last vertex
  80.   GpiMove(hps,&aptl[5]);
  81.   for (i=0; i<5; i++) {
  82.     aptl[i].x=aptl[5].x+aptlHex[i].x;
  83.     aptl[i].y=aptl[5].y+aptlHex[i].y;
  84.   }
  85.   GpiPolyLine(hps,6L,aptl);           // Draw all six lines at once
  86. }
  87.  
  88. void HexFillDraw(HPS hps, HEXINDEX hi) {
  89. /* This function is identical to HexDraw() except that it draws the terrain inside the hexagon.
  90. */
  91.   int iTerrain=amap[hi.c][hi.r].iTerrain;
  92.   POINTL ptl;
  93.  
  94.   if (ater[iTerrain].hbm) {
  95.     ptl=HexCoord(hi);
  96.     ptl.x-=HEX_EXT;
  97.     BitmapDraw(ater[iTerrain].hbm,hbmHexMask,ptl);
  98.  
  99.   } else {
  100.  
  101.     GpiSetBackMix(hps,BM_OVERPAINT);
  102.     GpiSetColor(hps,ater[iTerrain].bColor);
  103.     GpiSetPattern(hps,ater[iTerrain].bPattern);
  104.     GpiBeginArea(hps,BA_NOBOUNDARY);
  105.     HexDraw(hps,hi);
  106.     GpiEndArea(hps);
  107.   }
  108. }
  109.  
  110. void HexOutline(HPS hps, HEXINDEX hi) {
  111. /* This function draws an outline around the hexagon hi.  It is assume that the calling function
  112.    has already set the desired color with a GpiSetColor(hps,...) call
  113. */
  114.   static const POINTL aptlOutline[]={
  115.     {HEX_SIDE+1,-1},
  116.     {HEX_SIDE+HEX_EXT+1,HEX_HEIGHT/2},
  117.     {HEX_SIDE+1,HEX_HEIGHT+1},
  118.     {-1,HEX_HEIGHT+1},
  119.     {-HEX_EXT-1,HEX_HEIGHT/2},
  120.     {-1,-1}
  121.   };
  122.  
  123.   int i;
  124.   POINTL aptl[6];
  125.  
  126.   aptl[5]=HexCoord(hi);                             // Move to the last vertex
  127.   GpiMove(hps,&aptl[5]);
  128.   for (i=0; i<5; i++) {
  129.     aptl[i].x=aptl[5].x+aptlHex[i].x;
  130.     aptl[i].y=aptl[5].y+aptlHex[i].y;
  131.   }
  132.  
  133.   GpiPolyLine(hps,6L,aptl);                         // Draw all six lines at once
  134. }
  135.  
  136. // -----------------------------------------------------------------------
  137. //   Hex Locator routines
  138. // -----------------------------------------------------------------------
  139.  
  140. static unsigned * HexInitLimits(void) {
  141. /* Contributed by: BCL
  142.    modified by: TT
  143.    This functions initializes the integer array of hexagonal x-deltas.
  144. */
  145.   static unsigned int auiLimits[HEX_HEIGHT];
  146.   unsigned u;
  147.  
  148.   for (u=0;u <= HEX_HEIGHT/2; u++) {
  149.     auiLimits[u] = HEX_EXT*u;               // Make sure it does the multiplication first
  150.     auiLimits[u] /= HEX_HEIGHT/2;
  151.     auiLimits[HEX_HEIGHT - u] = auiLimits[u];
  152.   }
  153.   return auiLimits;
  154. }
  155.  
  156. BOOL HexInPoint(POINTL ptl, HEXINDEX hi) {
  157. /* Contributed by: BCL
  158.    Modified by: TT
  159.    This function returns TRUE if the point 'ptl' is inside hex 'hi'.
  160. */
  161.   static unsigned int * auiLimits = NULL;
  162.   POINTL ptlHex;                                  // lower-left corner of hi
  163.   int dy;                                         // The y-delta within the hexagon
  164.  
  165. // Test if hi is a valid hex index
  166.   if (hi.c<0 || hi.r<0) return FALSE;
  167.   if (hi.c&1 && hi.r<1) return FALSE;
  168.  
  169.   ptlHex=HexCoord(hi);
  170.   if (ptl.y < ptlHex.y) return FALSE;
  171.   if (ptl.y > ptlHex.y+HEX_HEIGHT) return FALSE;
  172.  
  173. // The point is definitely not within the hexagon's inner rectangle.
  174. //  Let's try the side triangles.
  175.  
  176. // First, Initialize the limit array if necessary
  177.   if (auiLimits == NULL) auiLimits = HexInitLimits();
  178.  
  179.   dy = ptl.y - ptlHex.y;
  180.   if (ptl.x < ptlHex.x - auiLimits[dy]) return FALSE;
  181.   if (ptl.x > ptlHex.x+HEX_SIDE + auiLimits[dy]) return FALSE;
  182.   return TRUE;
  183. }
  184.  
  185. BOOL HexLocate(POINTL ptl, HEXINDEX *phi) {
  186. /* Original by: BCL
  187.    Redesigned by: TT
  188.    This routine identifies the hexagon underneath point ptl.  It returns
  189.    TRUE if it found one, FALSE otherwise.  *phi is modified only if the
  190.    function returns TRUE.
  191. */
  192.   HEXINDEX hi;
  193.   int GuessC, GuessR;
  194.  
  195.   if (ptl.x < HEX_SIDE+HEX_EXT)
  196.     GuessC = 0;
  197.   else
  198.     GuessC = (ptl.x-HEX_EXT)/(3*HEX_EXT+XLAG);
  199.  
  200.   if (GuessC & 1) {
  201.     GuessR = (ptl.y-(HEX_HEIGHT/2)-YLAG)/(HEX_HEIGHT+YLAG);
  202.     GuessR = 1+2*GuessR;                                      // Force the multiplication last
  203.   } else {
  204.     GuessR = ptl.y/(HEX_HEIGHT+YLAG);
  205.     GuessR *= 2;
  206.   }
  207.  
  208.   hi.c=GuessC;
  209.   hi.r=GuessR;
  210.   if (HexInPoint(ptl,hi)) {
  211.     *phi=hi;
  212.     return TRUE;
  213.   }
  214.  
  215.   hi.c=GuessC+1;
  216.   hi.r=GuessR+1;
  217.   if (HexInPoint(ptl,hi)) {
  218.     *phi=hi;
  219.     return TRUE;
  220.   }
  221.  
  222.   hi.r=GuessR-1;
  223.   if (HexInPoint(ptl,hi)) {
  224.     *phi=hi;
  225.     return TRUE;
  226.   }
  227.  
  228.   return FALSE;
  229. }
  230.  
  231. HEXINDEX HexFromSide(HEXINDEX hi, int iSide) {
  232. /* This function returns the hex index of the hexagon that is bordering on
  233.    side iSide of hexagon hi.
  234. */
  235.   switch (iSide) {
  236.     case 0: hi.c++;         // S.E.
  237.             hi.r--;
  238.             break;
  239.     case 1: hi.c++;         // N.E.
  240.             hi.r++;
  241.             break;
  242.     case 2: hi.r+=2;        // North
  243.             break;
  244.     case 3: hi.c--;         // N.W.
  245.             hi.r++;
  246.             break;
  247.     case 4: hi.c--;         // S.W.
  248.             hi.r--;
  249.             break;
  250.     default:hi.r-=2;        // South
  251.   }
  252.   return hi;
  253. }
  254.  
  255. void HexPointsFromSide(HEXINDEX hi, int iSide, PPOINTL pptl1, PPOINTL pptl2) {
  256. /* This function returns the x,y coordinates of the two endpoints of side
  257.    iSide of hexagon hi.  Two two points are returned in pptl1 and pptl2.
  258.    It actually returns the endpoints of the figure that outlines the hexagon.
  259. */
  260.   static POINTL aptlOutline[]={
  261.     {HEX_SIDE+1,-1},
  262.     {HEX_SIDE+HEX_EXT+1,HEX_HEIGHT/2},
  263.     {HEX_SIDE+1,HEX_HEIGHT+1},
  264.     {-1,HEX_HEIGHT+1},
  265.     {-HEX_EXT-1,HEX_HEIGHT/2},
  266.     {-1,-1}
  267.   };
  268.  
  269.   POINTL ptl=HexCoord(hi);      // All coordinates are offsets from this point
  270.  
  271.   pptl1->x=ptl.x+aptlOutline[iSide].x;             // Calculate the two endpoints of that side
  272.   pptl1->y=ptl.y+aptlOutline[iSide].y;
  273.   pptl2->x=ptl.x+aptlOutline[(iSide+1) % 6].x;
  274.   pptl2->y=ptl.y+aptlOutline[(iSide+1) % 6].y;
  275. }
  276.