home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / dragon / part02 / board.c.aa next >
Encoding:
Text File  |  1989-04-29  |  26.7 KB  |  1,001 lines

  1. /******************************************************************************
  2. * Dragon - a version of Mah-Jongg for X Windows
  3. *
  4. * Author: Gary E. Barnes    March 1989
  5. *
  6. * board.c - Deals with the Mah-Jongg board.  Setup and execution.
  7. ******************************************************************************/
  8.  
  9. #include "main.h"
  10.  
  11. #define BLACKSIDES    1
  12.  
  13. extern long random();
  14. extern int  srandom();
  15. extern long time();
  16.  
  17. static void Board_Expose();
  18. extern void Button_Configure();
  19. extern void Button_Expose();
  20. extern void Button_Press();
  21. extern void Button_Release();
  22. extern void Do_Button_Configuration();
  23. extern void Draw_Text();
  24. extern void Draw_Score();
  25.  
  26. extern void Draw_Spring();
  27. extern void Draw_Summer();
  28. extern void Draw_Fall();
  29. extern void Draw_Winter();
  30. extern void Draw_Bamboo();
  31. extern void Draw_Mum();
  32. extern void Draw_Orchid();
  33. extern void Draw_Plum();
  34. extern void Draw_GDragon();
  35. extern void Draw_RDragon();
  36. extern void Draw_WDragon();
  37. extern void Draw_East();
  38. extern void Draw_West();
  39. extern void Draw_North();
  40. extern void Draw_South();
  41. extern void Draw_Bam1();
  42. extern void Draw_Bam2();
  43. extern void Draw_Bam3();
  44. extern void Draw_Bam4();
  45. extern void Draw_Bam5();
  46. extern void Draw_Bam6();
  47. extern void Draw_Bam7();
  48. extern void Draw_Bam8();
  49. extern void Draw_Bam9();
  50. extern void Draw_Dot1();
  51. extern void Draw_Dot2();
  52. extern void Draw_Dot3();
  53. extern void Draw_Dot4();
  54. extern void Draw_Dot5();
  55. extern void Draw_Dot6();
  56. extern void Draw_Dot7();
  57. extern void Draw_Dot8();
  58. extern void Draw_Dot9();
  59. extern void Draw_Crak1();
  60. extern void Draw_Crak2();
  61. extern void Draw_Crak3();
  62. extern void Draw_Crak4();
  63. extern void Draw_Crak5();
  64. extern void Draw_Crak6();
  65. extern void Draw_Crak7();
  66. extern void Draw_Crak8();
  67. extern void Draw_Crak9();
  68.  
  69. #define NFACES    42        /* number of distinct tile faces */
  70. #define NTILES    ((NFACES-8) * 4 + 8) /* number of distinct tiles in game */
  71. #define NROWS    8        /* number of rows in game */
  72. #define NCOLS    16        /* number of columns in game */
  73. #define NO_TILE    0        /* tile codes are 1..NFACES */
  74.  
  75. /*--Size of the Board. */
  76.  
  77. int        Board_Width    = 29 * 15 + 1 + 8;
  78. int        Board_Height    = 33 * 10 + 1 + 8;
  79. int        Score        = NTILES;
  80.  
  81. /*--X/Y coordinate of a tile at coord 0,0 of the playing surface. */
  82.  
  83. int        Board_Tile0_X    = 4;
  84. int        Board_Tile0_Y    = 4 + 2 * 33;
  85.  
  86. /*--Actual size of a tile, not counting the border around it. */
  87.  
  88. unsigned int    Tile_Width    = 28;
  89. unsigned int    Tile_Height    = 32;
  90.  
  91. /*--X depth and Y width of a shadowed area above/to-the-right-of a tile. */
  92.  
  93. int        Shadow_X    = 28 / 8;
  94. int        Shadow_Y    = 32 / 8;
  95.  
  96. /*--X depth and Y width of tile edge below/to-the-left-of a tile. */
  97.  
  98. int        Side_X        = (28 / 10) & ~1;
  99. int        Side_Y        = (32 / 10) & ~1;
  100.  
  101. /*--Each playing tile position is represented by one of these. */
  102.  
  103. typedef struct _Board_Position {
  104.     char        tiles[4];    /* at most 4 tiles at one position */
  105.     Boolean        draw;        /* TRUE if needs drawing */
  106.     int            level;        /* how many tiles do we have */
  107.     int            x;        /* x coord of tile */
  108.     int            y;        /* x coord of tile */
  109. } Board_Position_Rec, *Board_Position;
  110.  
  111. #define Board_Position_NULL    ((Board_Position)0)
  112.  
  113. Board_Position_Rec    Board_Tiles[NROWS][NCOLS];
  114.  
  115. #define SPEC1        0][14        /* farthest right odd tile */
  116. #define SPEC1row    0        /* farthest right odd tile */
  117. #define SPEC1col    14        /* farthest right odd tile */
  118. #define SPEC2        2][14        /* next farthest right odd tile */
  119. #define SPEC2row    2        /* next farthest right odd tile */
  120. #define SPEC2col    14        /* next farthest right odd tile */
  121. #define SPEC3        4][14        /* farthest left odd tile */
  122. #define SPEC3row    4        /* farthest left odd tile */
  123. #define SPEC3col    14        /* farthest left odd tile */
  124. #define SPEC4        6][14        /* center piece tile */
  125. #define SPEC4row    6        /* center piece tile */
  126. #define SPEC4col    14        /* center piece tile */
  127.  
  128. /*--Index into this array using a tile number in order to get the procedure
  129.  *  that knows how to draw the face of that tile. */
  130.  
  131. typedef void (*Draw_Xyz)();
  132.  
  133. void Draw_Error() { fprintf( stderr, "Drew tile face 0??\n" ); return; }
  134.  
  135. Draw_Xyz    Faces[1+NFACES] = {
  136.     Draw_Error,
  137.  
  138.     Draw_Spring,  Draw_Summer,  Draw_Fall,    Draw_Winter,
  139.  
  140.     Draw_Bamboo,  Draw_Mum,     Draw_Orchid,  Draw_Plum,
  141.  
  142.     Draw_GDragon, Draw_RDragon, Draw_WDragon,
  143.  
  144.     Draw_East,    Draw_West,    Draw_North,   Draw_South,
  145.  
  146.     Draw_Bam1,    Draw_Bam2,    Draw_Bam3,    Draw_Bam4,     Draw_Bam5,
  147.     Draw_Bam6,    Draw_Bam7,    Draw_Bam8,    Draw_Bam9,
  148.  
  149.     Draw_Dot1,    Draw_Dot2,    Draw_Dot3,    Draw_Dot4,     Draw_Dot5,
  150.     Draw_Dot6,    Draw_Dot7,    Draw_Dot8,    Draw_Dot9,
  151.  
  152.     Draw_Crak1,   Draw_Crak2,   Draw_Crak3,   Draw_Crak4,    Draw_Crak5,
  153.     Draw_Crak6,   Draw_Crak7,   Draw_Crak8,   Draw_Crak9
  154. };
  155.  
  156. /*--Record tile clicks and watch for double clicks. */
  157.  
  158. Boolean            One_Button_Hint = FALSE;
  159. Board_Position        Click1 = Board_Position_NULL;
  160. int            Click1_Row;
  161. int            Click1_Col;
  162. Board_Position        Click2 = Board_Position_NULL;
  163. int            Click2_Row;
  164. int            Click2_Col;
  165. Time            Click2_Time;
  166.  
  167.  
  168. void Write_Game( file )
  169.      FILE    *file;
  170. /******************************************************************************
  171. *   file    - Specifies a file open for write
  172. *
  173. * Called to write out the current game context for later rereading.
  174. ******************************************************************************/
  175. {
  176.  
  177.     fwrite( (char*)&Score, 1, sizeof(Score), file );
  178.     fwrite( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file );
  179.  
  180. } /* Write_Game */
  181.  
  182.  
  183. void Read_Game( file )
  184.      FILE    *file;
  185. /******************************************************************************
  186. *   file    - Specifies a file open for reading
  187. *
  188. * Called to read in a new current game context.
  189. ******************************************************************************/
  190. {
  191.  
  192.     Click1 = Board_Position_NULL;
  193.     Click2 = Board_Position_NULL;
  194.     fread( (char*)&Score, 1, sizeof(Score), file );
  195.     fread( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file );
  196.  
  197. } /* Read_Game */
  198.  
  199.  
  200. static int Pick_Tile( Avail )
  201.      char    *Avail;
  202. /******************************************************************************
  203. *   Avail    - Specifies an [NTILES] array of available tiles.  Unavailable
  204. *          slots contain NO_TILE.
  205. *
  206. * Called to pick a random tile from the Available tiles.
  207. ******************************************************************************/
  208. {
  209.     register char    *t;
  210.     register int    k;
  211.  
  212. /*--Pick a random starting place. */
  213.  
  214.     k = (int)random() % NTILES;
  215.     t = &Avail[k];
  216.  
  217. /*--Search until we find a non-NO_TILE slot. */
  218.  
  219.     while (*t == NO_TILE) {
  220.     ++t;
  221.     if (++k == NTILES) {
  222.         t = &Avail[0];
  223.         k = 0;
  224.     }
  225.     }
  226.  
  227. /*--Return the tile we found and zap the slot. */
  228.  
  229.     k = *t;
  230.     *t = NO_TILE;
  231.     return k;
  232.  
  233. } /* Pick_Tile */
  234.  
  235.  
  236. static void Set_Tile_Controls()
  237. /******************************************************************************
  238. * Called whenever the board has been reset or resized.  We recalculate all of
  239. * the drawing controls for the tiles.
  240. ******************************************************************************/
  241. {
  242.     register Board_Position    bp;
  243.     int                row, col;
  244.  
  245. /*--Now set up the control information for all of the tiles.  The special
  246.  *  tiles are easy. */
  247.  
  248.     DEBUG_CALL(Set_Tile_Controls);
  249.     if (Board_Tiles[SPEC4].level > 0) {
  250.     Board_Tiles[SPEC4].x         = Board_Tile0_X + 6 * (Tile_Width + 1)
  251.                         + (Tile_Width + 1) / 2 + 4 * Side_X;
  252.     Board_Tiles[SPEC4].y         = Board_Tile0_Y + 3 * (Tile_Height + 1)
  253.                       + (Tile_Height + 1) / 2 - 3 * Side_Y;
  254.     }
  255.  
  256.     if (Board_Tiles[SPEC3].level > 0) {
  257.     Board_Tiles[SPEC3].x         = Board_Tile0_X + 0 * (Tile_Width + 1);
  258.     Board_Tiles[SPEC3].y         = Board_Tile0_Y + 3 * (Tile_Height + 1)
  259.                       + (Tile_Height + 1) / 2;
  260.     }
  261.  
  262.     if (Board_Tiles[SPEC2].level > 0) {
  263.     Board_Tiles[SPEC2].x         = Board_Tile0_X + 13 * (Tile_Width+1);
  264.     Board_Tiles[SPEC2].y         = Board_Tile0_Y +  3 * (Tile_Height+1)
  265.                       + (Tile_Height + 1) / 2;
  266.     }
  267.  
  268.     if (Board_Tiles[SPEC1].level > 0) {
  269.     Board_Tiles[SPEC1].x         = Board_Tile0_X + 14 * (Tile_Width+1);
  270.     Board_Tiles[SPEC1].y         = Board_Tile0_Y +  3 * (Tile_Height+1)
  271.                             + (Tile_Height + 1) / 2;
  272.     }
  273.  
  274. /*--Do the more regular tiles. */
  275.  
  276.     for (row = 0; row <= 7; ++row) {
  277.     for (col = 12; col >= 1; --col) {
  278.         bp = &Board_Tiles[row][col];
  279.  
  280. /*--Skip any tiles that don't exist. */
  281.  
  282.         if (bp->level == 0) { continue; }
  283.  
  284. /*--Set up the face x/y coordinates. */
  285.  
  286.         bp->x = Board_Tile0_X + col * (Tile_Width + 1);
  287.         bp->y = Board_Tile0_Y + row * (Tile_Height + 1);
  288.  
  289.     }
  290.     }
  291.     DEBUG_RETURN(Set_Tile_Controls);
  292.  
  293. } /* Set_Tile_Controls */
  294.  
  295.  
  296. static void Pick1( bp, Avail )
  297.      register Board_Position     bp;
  298.      char            *Avail;
  299. {
  300.     bp->tiles[0] = Pick_Tile( Avail );
  301.     bp->level = 1;
  302. }
  303.  
  304. static void Pick2( bp, Avail )
  305.      register Board_Position     bp;
  306.      char            *Avail;
  307. {
  308.     bp->tiles[0] = Pick_Tile( Avail );
  309.     bp->tiles[1] = Pick_Tile( Avail );
  310.     bp->level = 2;
  311. }
  312.  
  313. static void Pick3( bp, Avail )
  314.      register Board_Position     bp;
  315.      char            *Avail;
  316. {
  317.     bp->tiles[0] = Pick_Tile( Avail );
  318.     bp->tiles[1] = Pick_Tile( Avail );
  319.     bp->tiles[2] = Pick_Tile( Avail );
  320.     bp->level = 3;
  321. }
  322.  
  323. static void Pick4( bp, Avail )
  324.      register Board_Position     bp;
  325.      char            *Avail;
  326. {
  327.     bp->tiles[0] = Pick_Tile( Avail );
  328.     bp->tiles[1] = Pick_Tile( Avail );
  329.     bp->tiles[2] = Pick_Tile( Avail );
  330.     bp->tiles[3] = Pick_Tile( Avail );
  331.     bp->level = 4;
  332. }
  333.  
  334.  
  335. void Setup_New_Game()
  336. /******************************************************************************
  337. * Called to generate an all-new game.
  338. ******************************************************************************/
  339. {
  340.     register Board_Position    bp;
  341.     char            Avail[NTILES];
  342.     int                row, col, i;
  343.  
  344. /*--Clear the board. */
  345.  
  346.     DEBUG_CALL(Setup_New_Game);
  347.     bp = &Board_Tiles[0][0];
  348.     for (row = 0; row < NROWS; ++row) {
  349.     for (col = 0; col < NCOLS; ++col) {
  350.         bp->tiles[0] = NO_TILE;
  351.         bp->tiles[1] = NO_TILE;
  352.         bp->tiles[2] = NO_TILE;
  353.         bp->tiles[3] = NO_TILE;
  354.         bp->level = 0;
  355.     }
  356.     }
  357.  
  358. /*--Mark all tiles as available. */
  359.  
  360.     i = 0;
  361.     for (row = 0; row < 4; ++row) {
  362.     Avail[i++] = row + 1;
  363.     Avail[i++] = row + 5;
  364.     for (col = 8; col < NFACES; ++col) {
  365.         Avail[i++] = 1 + col % NFACES;
  366.     }
  367.     }
  368.     if (i != NTILES) { fprintf( stderr, "NTILES gak!\n" ); }
  369.  
  370. /*--Fill in the "odd" tile slots. */
  371.  
  372.     Pick1( &Board_Tiles[SPEC1], Avail );
  373.     Pick1( &Board_Tiles[SPEC2], Avail );
  374.     Pick1( &Board_Tiles[SPEC3], Avail );
  375.     Pick1( &Board_Tiles[SPEC4], Avail );
  376.  
  377.     for (col = 1; col <= 12; ++col) {
  378.     Pick1( &Board_Tiles[0][col], Avail );
  379.     Pick1( &Board_Tiles[7][col], Avail );
  380.     }
  381.     for (row = 1; row <= 6; ++row) {
  382.     Pick1( &Board_Tiles[row][ 3], Avail );
  383.     Pick1( &Board_Tiles[row][10], Avail );
  384.     }
  385.     for (row = 2; row <= 5; ++row) {
  386.     Pick1( &Board_Tiles[row][ 2], Avail );
  387.     Pick1( &Board_Tiles[row][11], Avail );
  388.     }
  389.     for (row = 3; row <= 4; ++row) {
  390.     Pick1( &Board_Tiles[row][ 1], Avail );
  391.     Pick1( &Board_Tiles[row][12], Avail );
  392.     }
  393.  
  394. /*--Now do the next square at level 2. */
  395.  
  396.     for (col = 4; col <= 9; ++col) {
  397.     Pick2( &Board_Tiles[1][col], Avail );
  398.     Pick2( &Board_Tiles[6][col], Avail );
  399.     }
  400.     for (row = 2; row <= 5; ++row) {
  401.     Pick2( &Board_Tiles[row][4], Avail );
  402.     Pick2( &Board_Tiles[row][9], Avail );
  403.     }
  404.  
  405. /*--Now do the next square at level 3. */
  406.  
  407.     for (col = 5; col <= 8; ++col) {
  408.     Pick3( &Board_Tiles[2][col], Avail );
  409.     Pick3( &Board_Tiles[5][col], Avail );
  410.     }
  411.     for (row = 3; row <= 4; ++row) {
  412.     Pick3( &Board_Tiles[row][5], Avail );
  413.     Pick3( &Board_Tiles[row][8], Avail );
  414.     }
  415.  
  416. /*--Now do the final square at level 4. */
  417.  
  418.     for (row = 3; row <= 4; ++row) {
  419.     for (col = 6; col <= 7; ++col) {
  420.         Pick4( &Board_Tiles[row][col], Avail );
  421.     }
  422.     }
  423.  
  424. /*--Now set up the control information for all of the tiles. */
  425.  
  426.     Set_Tile_Controls();
  427.     Score = NTILES;
  428.     DEBUG_RETURN(Setup_New_Game);
  429.  
  430. } /* Setup_New_Game */
  431.  
  432.  
  433. /*ARGSUSED*/
  434. void Restart_Game( w, event, params, num_params )
  435.      Widget    w;
  436.      XEvent    *event;
  437.      String    *params;
  438.      Cardinal    *num_params;
  439. /******************************************************************************
  440. * Called when the RESTART button is pressed.  Restart the game.
  441. ******************************************************************************/
  442. {
  443.     int                row;
  444.     int                col;
  445.     register Board_Position    bp;
  446.  
  447. /*--Reset levels and remove hilites. */
  448.  
  449.     DEBUG_CALL(Restart_Game);
  450.     Click1 = Board_Position_NULL;
  451.     Click2 = Board_Position_NULL;
  452.     Score = NTILES;
  453.     bp = &Board_Tiles[0][0];
  454.     for (row = 0; row < NROWS; ++row) {
  455.     for (col = 0; col < NCOLS; ++bp,++col) {
  456.         if      (bp->tiles[3] != NO_TILE) { bp->level = 4; }
  457.         else if (bp->tiles[2] != NO_TILE) { bp->level = 3; }
  458.         else if (bp->tiles[1] != NO_TILE) { bp->level = 2; }
  459.         else if (bp->tiles[0] != NO_TILE) { bp->level = 1; }
  460.         else { bp->level = 0; }
  461.     }
  462.     }
  463.  
  464. /*--Finish setting up and then redraw everything. */
  465.  
  466.     Set_Tile_Controls();
  467.     XClearArea( XtDisplay(Board), XtWindow(Board), 0, 0, 0, 0, TRUE );
  468.     DEBUG_RETURN(Restart_Game);
  469.  
  470. } /* Restart_Game */
  471.  
  472.  
  473. static void Hilite_Tile( row, col )
  474. /******************************************************************************
  475. *   row    - Specifies the row of the tile to hilite
  476. *   col - specifies the column of the tile to hilite
  477. *
  478. * Called to hilite a tile face.
  479. ******************************************************************************/
  480. {
  481.     register Board_Position    bp = &Board_Tiles[row][col];
  482.     XPoint    pnts[20];
  483.     int        pnti = 0;
  484.     int        x, y, w, h;
  485.     int        left, bottom, left_bottom;
  486.  
  487. #define PNT(X,Y) \
  488.     if (pnti >= XtNumber(pnts)) {fprintf(stderr,"HT pnts overflow!\n");} \
  489.     pnts[pnti].x = X;     pnts[pnti].y = Y;  ++pnti
  490.     ;
  491.  
  492. /*--See if we are one of the very special tiles on top. */
  493.  
  494.     DEBUG_CALL(Hilite_Tile);
  495.     if (Board_Tiles[SPEC4].level > 0) {
  496.     if (row == 3) {
  497.         if (col == 6) {
  498.         x = bp->x + Side_X * 4 + 1;
  499.         y = bp->y - Side_Y * 4 + 1;
  500.         w = Tile_Width / 2;
  501.         h = Tile_Height / 2;
  502.         PNT( x,            y );
  503.         PNT( Tile_Width,    0 );
  504.         PNT( 0,            h-1 );
  505.         PNT( -(w+1),         0 );
  506.         PNT( 0,            h+1 );
  507.         PNT( -(w-1),        0 );
  508.         PNT( 0,            -Tile_Height );
  509.         goto Hilite;
  510.         } else if (col == 7) {
  511.         x = bp->x + Side_X * 4 + 1;
  512.         y = bp->y - Side_Y * 4 + 1;
  513.         w = Board_Tiles[3][7].x - Board_Tiles[SPEC4].x + 3 * Side_X;
  514.         h = Tile_Height / 2;
  515.         PNT( x,            y );
  516.         PNT( Tile_Width,    0 );
  517.         PNT( 0,            Tile_Height );
  518.         PNT( -w,        0 );
  519.         PNT( 0,            -(h+1) );
  520.         PNT( -(Tile_Width-w),     0 );
  521.         PNT( 0,            -(h-1) );
  522.         goto Hilite;
  523.         }
  524.     } else if (row == 4) {
  525.         if (col == 6) {
  526.         x = bp->x + Side_X * 4 + 1;
  527.         y = bp->y - Side_Y * 4 + 1;
  528.         w = Tile_Width / 2;
  529.         h = Tile_Height / 2;
  530.         PNT( x,            y );
  531.         PNT( w-1,        0 );
  532.         PNT( 0,            h + Side_Y );
  533.         PNT( w+1,        0 );
  534.         PNT( 0,            h - Side_Y );
  535.         PNT( -Tile_Width,    0 );
  536.         PNT( 0,            -Tile_Height );
  537.         goto Hilite;
  538.         } else if (col == 7) {
  539.         x = bp->x + Side_X * 4 + 1;
  540.         y = bp->y - Side_Y * 4 + 1;
  541.         w = Board_Tiles[4][7].x - Board_Tiles[SPEC4].x + 3 * Side_X;
  542.         h = Tile_Height / 2;
  543.         PNT( x + Tile_Width - w,    y );
  544.         PNT( w,                0 );
  545.         PNT( 0,                Tile_Height );
  546.         PNT( -Tile_Width,        0 );
  547.         PNT( 0,                -(h - Side_Y) );
  548.         PNT( Tile_Width - w,        0 );
  549.         PNT( 0,                -(h + Side_Y) );
  550.         goto Hilite;
  551.         }
  552.     }
  553.     }
  554.  
  555. /*--We are a normal tile that may be partially overlapped by some other
  556.  *  normal tile. */
  557.  
  558.     x = bp->x + Side_X * bp->level + 1;
  559.     y = bp->y - Side_Y * bp->level + 1;
  560.     w = Tile_Width;
  561.     h = Tile_Height;
  562.     if (col > 0) {
  563.     left = Board_Tiles[row][col-1].level - bp->level;
  564.     if (left < 0) { left = 0; }
  565.     if (row < 7) {
  566.         left_bottom = Board_Tiles[row+1][col-1].level - bp->level;
  567.         if (left_bottom < 0) { left_bottom = 0; }
  568.     } else {
  569.         left_bottom = 0;
  570.     }
  571.     } else {
  572.     left = 0;
  573.     left_bottom = 0;
  574.     }
  575.     if (row < 7) {
  576.     bottom = Board_Tiles[row+1][col].level - bp->level;
  577.     if (bottom < 0) { bottom = 0; }
  578.     } else {
  579.     bottom = 0;
  580.     }
  581.     if (bottom > left_bottom && Tile_Width == 28) { left_bottom = bottom; }
  582.     if (left > 0) {
  583.     w = left * Side_X;
  584.     } else {
  585.     w = 0;
  586.     }
  587.     PNT( x + w, y );
  588.     PNT( Tile_Width - w, 0 );
  589.     if (bottom > 0) {
  590.     h = bottom * Side_Y;
  591.     } else {
  592.     h = 0;
  593.     }
  594.     PNT( 0, Tile_Height - h );
  595.     if (left_bottom <= left && left_bottom <= bottom) {
  596.     PNT( -(Tile_Width - bottom*Side_X), 0 );
  597.     if (left != bottom) {
  598.         PNT( (left-bottom)*Side_X, (bottom-left)*Side_Y );
  599.     }
  600.     PNT( 0, -(Tile_Height - h) );
  601.     } else if (left_bottom <= left) {    /* left_bottom > bottom */
  602.     PNT( -(Tile_Width - left_bottom*Side_X), 0 );
  603.     if (left_bottom != left ) {
  604.         PNT( 0, (bottom-left_bottom)*Side_Y );
  605.         PNT( (left-left_bottom)*Side_X, (left_bottom-left)*Side_Y );
  606.         PNT( 0, -(Tile_Height - left * Side_Y) );
  607.     } else {
  608.         PNT( 0, -(Tile_Height - h) );
  609.     }
  610.     } else if (left_bottom <= bottom) {    /* left_bottom > left */
  611.     if (left_bottom == bottom) {
  612.         PNT( -(Tile_Width-w), 0 );
  613.         PNT( 0, -(Tile_Height-h) );
  614.     } else {
  615.         PNT( -(Tile_Width - bottom * Side_X), 0 );
  616.         PNT( (left_bottom-bottom)*Side_X, (bottom-left_bottom)*Side_Y );
  617.         PNT( -left_bottom*Side_X, 0 );
  618.         PNT( 0, -(Tile_Height - left_bottom * Side_Y) );
  619.     }
  620.     } else {        /* left_bottom > bottom && left_bottom > left */
  621.     PNT( -(Tile_Width - left_bottom * Side_X), 0 );
  622.     PNT( 0, (bottom-left_bottom)*Side_Y );
  623.     PNT( (left-left_bottom)*Side_X, 0 );
  624.     PNT( 0, -(Tile_Height - left_bottom * Side_Y) );
  625.     }
  626.  
  627. /*--Now do it. */
  628.  
  629.   Hilite :
  630.     XFillPolygon( XtDisplay(Board), XtWindow(Board), Xor_GC,
  631.           pnts, (Cardinal)pnti, Convex, CoordModePrevious );
  632.     DEBUG_RETURN(Hilite_Tile);
  633.  
  634. } /* Hilite_Tile */
  635.  
  636.  
  637. static void Clear_Tile( bp, left, bottom )
  638.      register Board_Position    bp;
  639.      int            left;
  640.      int            bottom;
  641. /******************************************************************************
  642. *   bp        - Specifies the Board_Position to draw
  643. *   left    - Specifies the level of the tile on the left of this thile
  644. *   bottom  - Specifies the level of the tile at the bottom of this tile
  645. *
  646. * We clear (make totally white) the space occupied by the image of this tile.
  647. * We clear the face and the left and bottom sides.  Any shadowing caused by
  648. * the last drawing of this tile is the responsibility of the caller.
  649. ******************************************************************************/
  650. {
  651.     XPoint    Poly[10];
  652.     int        Polyi;
  653.  
  654. #undef PNT
  655. #define PNT(XX,YY) \
  656.     if (Polyi >= XtNumber(Poly)){fprintf(stderr,"Tile: Poly overflow!!\n");} \
  657.     Poly[Polyi].x = (XX); \
  658.     Poly[Polyi].y = (YY); \
  659.     ++Polyi
  660.     ;
  661.  
  662. /*--We will circle the tile outline clockwise. */
  663.  
  664.     DEBUG_CALL(Clear_Tile);
  665.     Polyi = 0;
  666.  
  667. /*--Start with the upper left corner of the tile side. This is the "bottom"
  668.  *  of that tile side if it has one. Leave x/y at the upper-left corner of the
  669.  *  tile face. */
  670.  
  671.     if (left >= bp->level) {
  672.     left = bp->level;
  673.     PNT( bp->x + Side_X * bp->level, bp->y - Side_Y * bp->level );
  674.     } else {
  675.     PNT( bp->x + Side_X * left, bp->y - Side_Y * left );
  676.     PNT( Side_X * (bp->level - left), - Side_Y * (bp->level - left) );
  677.     }
  678.  
  679. /*--Cross the top and the right side of the tile. */
  680.  
  681.     PNT( Tile_Width + 1, 0 );
  682.     PNT( 0, Tile_Height + 1 );
  683.  
  684. /*--Now do the bottom side of the tile. */
  685.  
  686.     if (bottom < bp->level) {
  687.     PNT( - Side_X * (bp->level - bottom), Side_Y * (bp->level - bottom) );
  688.     } else {
  689.     bottom = bp->level;
  690.     }
  691.     PNT( -(Tile_Width + 1), 0 );
  692.  
  693. /*--Now go up the left side of the tile. */
  694.  
  695.     if (left != bottom) {
  696.     PNT( Side_X * (left - bottom), - Side_Y * (left - bottom) );
  697.     }
  698.     PNT( 0, -(Tile_Height + 1) );
  699.  
  700. /*--Do the actual clearing. */
  701.  
  702.     XFillPolygon( XtDisplay(Board), XtWindow(Board), Reverse_GC,
  703.           Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
  704.     DEBUG_RETURN(Clear_Tile);
  705.  
  706. } /* Clear_Tile */
  707.  
  708.  
  709. static void Tile( row, col )
  710.      int        row;
  711.      int        col;
  712. /******************************************************************************
  713. *   row          - Specifies the tile to draw
  714. *   col          - Specifies the tile to draw
  715. *
  716. * Called to draw a tile.  We draw the face, the sides, and the shadow.
  717. ******************************************************************************/
  718. {
  719.     register Board_Position    bp= &Board_Tiles[row][col];
  720.     XPoint            Poly[100];
  721.     int                Polyi;
  722.     int                left;
  723.     int                bottom;
  724.     int                curx;
  725.     int                cury;
  726.     int                sidex;
  727.     int                sidey;
  728.     int                i, j, k, l, m;
  729.  
  730. #undef PNT
  731. #define PNT(XX,YY) \
  732.     if (Polyi >= XtNumber(Poly)){fprintf(stderr,"Tile: Poly overflow!!\n");} \
  733.     Poly[Polyi].x = (XX); \
  734.     Poly[Polyi].y = (YY); \
  735.     ++Polyi
  736.     ;
  737.  
  738. /*--This tile no longer needs drawing. */
  739.  
  740.     DEBUG_CALL(Tile);
  741.     bp->draw = FALSE;
  742.  
  743. /*--Determine the level of the tile on the left of this tile. */
  744.  
  745.     if (col > 0) {
  746.     if (col == SPEC1col && row == SPEC1row) {
  747.         left = Board_Tiles[SPEC2].level;
  748.     } else if (col == SPEC2col && row == SPEC2row) {
  749.         if (Board_Tiles[3][12].level == 0 ||
  750.         Board_Tiles[4][12].level == 0) {
  751.         left = 0;
  752.         } else {
  753.         left = 1;
  754.         }
  755.     } else {
  756.         left = Board_Tiles[row][col-1].level;
  757.     }
  758.     } else {
  759.     left = 0;
  760.     }
  761.  
  762. /*--Determine the level of the tile at the bottom of this tile. */
  763.  
  764.     if (row < 7) {
  765.     bottom = Board_Tiles[row+1][col].level;
  766.     } else {
  767.     bottom = 0;
  768.     }
  769.  
  770. /*--Clear the area that will be covered by this tile. */
  771.  
  772.     Clear_Tile( bp, left, bottom );
  773.  
  774. /*--Draw the tile face. */
  775.  
  776.     (*(Faces[bp->tiles[bp->level-1]]))( bp->x + bp->level * Side_X + 1,
  777.                         bp->y - bp->level * Side_Y + 1 );
  778.  
  779. /*--Now draw the tile edges. */
  780.  
  781.     if (Tile_Control & BLACKSIDE) {
  782.  
  783. /*--We want black/gray sides. */
  784.  
  785.     XDrawRectangle( XtDisplay(Board), XtWindow(Board), Normal_GC,
  786.                 bp->x + bp->level * Side_X,
  787.                 bp->y - bp->level * Side_Y,
  788.                 Tile_Width + 1, Tile_Height + 1 );
  789.  
  790.     if (left < bp->level) {
  791.         Polyi = 0;
  792.         PNT( bp->x + left * Side_X, bp->y - left * Side_Y );
  793.         PNT( (bp->level - left) * Side_X, (left - bp->level) * Side_Y );
  794.         PNT( 0, Tile_Height + 1 );
  795.         PNT( (left - bp->level) * Side_X, (bp->level - left) * Side_Y );
  796.         PNT( 0, -(Tile_Height + 1) );
  797.         XFillPolygon( XtDisplay(Board), XtWindow(Board),
  798.               ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
  799.               Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
  800.         XDrawLines( XtDisplay(Board), XtWindow(Board), Normal_GC,
  801.                Poly, (Cardinal)Polyi, CoordModePrevious );
  802.     }
  803.     if (bottom < bp->level) {
  804.         Polyi = 0;
  805.         PNT( bp->x + bp->level * Side_X,
  806.          bp->y - bp->level * Side_Y + Tile_Height + 1 );
  807.         PNT( Tile_Width + 1, 0 );
  808.         PNT( (bottom - bp->level) * Side_X, (bp->level - bottom) * Side_Y);
  809.         PNT( -(Tile_Width + 1), 0 );
  810.         PNT( (bp->level - bottom) * Side_X, (bottom - bp->level) * Side_Y);
  811.         XFillPolygon( XtDisplay(Board), XtWindow(Board),
  812.               ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
  813.               Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
  814.         XDrawLines( XtDisplay(Board), XtWindow(Board), Normal_GC,
  815.                 Poly, (Cardinal)Polyi, CoordModePrevious );
  816.     }
  817.  
  818. /*--We want line'ed sides. */
  819.  
  820.     } else {
  821.  
  822.     Polyi = 0;
  823.     if (left >= bp->level) {
  824.         PNT( bp->x + Side_X * bp->level, bp->y - Side_Y * bp->level );
  825.     } else {
  826.  
  827. /*--First we draw the left side.  We leave x/y at the bottom left corner of
  828.  *  the tile face when we are done. */
  829.  
  830. #define LSEGS 7 /* keep this an odd number */
  831.  
  832.         sidex = Side_X * (bp->level - left);
  833.         sidey = Side_Y * (bp->level - left);
  834.         j = sidex;
  835.         if (Tile_Width == 28 && bp->level - left == 1) {
  836.         PNT( bp->x + Side_X * left, bp->y - Side_Y * left - sidey );
  837.         PNT( 0, Tile_Height + 1 + sidey );
  838.         k = 0;
  839.         } else {
  840.         PNT( bp->x + Side_X * left, bp->y - Side_Y * left );
  841.         PNT(0, Tile_Height + 1 );
  842.         k = sidey;
  843.         }
  844.         PNT( sidex, -sidey );
  845.         i = Tile_Height / (LSEGS+1);
  846.         m = Tile_Height - i * (LSEGS+1);
  847.         for (l = LSEGS; l > 0; --l) {
  848.         cury = -i;
  849.         if (m > 0) { cury -= 1; --m; }
  850.         PNT( 0, cury );
  851.         PNT( -j, k );
  852.         j = -j;
  853.         k = -k;
  854.         }
  855.         PNT( 0, -i-1 );
  856.         PNT( sidex, k );
  857.     }
  858.     PNT( 0, Tile_Height + 1 );
  859.  
  860. /*--Draw the left edge of the tile and then draw the bottom side of the tile.
  861.  *  We leave x/y at the bottom right corner of the tile face when we are done.
  862.  */
  863.  
  864. #define RSEGS 6    /* keep this an even number */
  865.  
  866.     if (bottom < bp->level) {
  867.         sidex = Side_X * (bp->level - bottom);
  868.         sidey = Side_Y * (bp->level - bottom);
  869.         i = Tile_Width / (RSEGS+1);
  870.         m = Tile_Width - i * (RSEGS+1);
  871.         if (Tile_Width == 28 && bp->level - bottom == 1) {
  872.         j = 0;
  873.         } else {
  874.         j = sidex;
  875.         }
  876.         k = sidey;
  877.         for (l = RSEGS; l > 0; --l) {
  878.         curx = i;
  879.         if (m > 0) { curx += 1; --m; }
  880.         PNT( curx, 0 );
  881.         PNT( -j, k );
  882.         j = -j;
  883.         k = -k;
  884.         }
  885.         PNT( i+1, 0 );
  886.         PNT( -j, sidey );
  887.         PNT( -(Tile_Width + 1 + sidex - j), 0 );
  888.         PNT( sidex, -sidey );
  889.     }
  890.     PNT( Tile_Width + 1, 0 );
  891.  
  892. /*--Draw the right side. */
  893.  
  894.     PNT( 0, -(Tile_Height + 1) );
  895.  
  896. /*--Draw the top side. */
  897.  
  898.     PNT( -(Tile_Width + 1), 0 );
  899.  
  900. /*--Draw all of those edges. */
  901.  
  902.     XDrawLines( XtDisplay(Board), XtWindow(Board),
  903.             ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
  904.             Poly, (Cardinal)Polyi, CoordModePrevious );
  905.     }
  906.  
  907. /*--Now draw the tile shadow. */
  908.  
  909.     if (Tile_Control & SHADOW) {
  910.     int    top, right;
  911.     Boolean    top_right;
  912.  
  913. /*--Determine the level of the tile on the right of this tile. */
  914.  
  915.     if (col == SPEC1col) {
  916.         if (row == SPEC2row) {
  917.         right = Board_Tiles[SPEC1].level;
  918.         } else if (row == SPEC3row) {
  919.         right = 0;
  920.         } else {
  921.         right = 0;
  922.         }
  923.     } else {
  924.         right = Board_Tiles[row][col+1].level;
  925.     }
  926.  
  927. /*--Determine the level of the tile at the top of this tile. */
  928.  
  929.     if (row > 0) {
  930.         top = Board_Tiles[row-1][col].level;
  931.     } else {
  932.         top = 0;
  933.     }
  934.  
  935. /*--Do we have an upper-right tile? */
  936.  
  937.     if (row > 0 &&
  938.         Board_Tiles[row-1][col+1].level >= bp->level) {
  939.         top_right = TRUE;
  940.     } else if (row == SPEC3row && col == SPEC3col &&
  941.            Board_Tiles[3][1].level > 0) {
  942.         top_right = TRUE;
  943.     } else if (row == 4 && col == 12 &&
  944.            Board_Tiles[SPEC2].level > 0) {
  945.         top_right = TRUE;
  946.     } else {
  947.         top_right = FALSE;
  948.     }
  949.  
  950. /*--Draw the upper shadow if necessary. */
  951.  
  952.     if (top < bp->level) {
  953.         Polyi = 0;
  954.         PNT( bp->x + bp->level * Side_X - 1,
  955.          bp->y - bp->level * Side_Y );
  956.         PNT( Shadow_X, -Shadow_Y );
  957.         if (top_right) {
  958.         i = Shadow_X;
  959.         } else {
  960.         i = 0;
  961.         }
  962.         PNT( Tile_Width + 3 - i, 0 );
  963.         PNT( -(Shadow_X - i), Shadow_Y );
  964.         PNT( -(Tile_Width + 3), 0 );
  965.         XFillPolygon( XtDisplay(Board), XtWindow(Board), Over_GC,
  966.               Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
  967.     }
  968.  
  969. /*--Now work on the right shadow.  It may need to be drawn in pieces. */
  970.  
  971.     Polyi = 0;
  972.  
  973. /*--If SPEC3 has both neighbors then don't draw the right shadow. */
  974.  
  975.     if (row == SPEC3row && col == SPEC3col) {
  976.         if (Board_Tiles[3][1].level > 0) {
  977.         if (Board_Tiles[4][1].level > 0) {
  978.             right = bp->level;
  979.  
  980. /*--If SPEC3 has only the upper neighbor then draw just the lower shadow. */
  981.  
  982.         } else {
  983.             i = bp->y - Board_Tiles[3][1].y;
  984.             PNT( Board_Tiles[4][1].x + Side_X, Board_Tiles[4][1].y );
  985.             PNT( Shadow_X, 0 );
  986.             PNT( 0, i - Shadow_Y);
  987.             PNT( -Shadow_X, Shadow_Y );
  988.             PNT( 0, -i );
  989.             right = bp->level;
  990.         }
  991.  
  992. /*--If SPEC3 has only the lower neighbor then draw just the upper shadow. */
  993.  
  994.         } else if (Board_Tiles[4][1].level > 0) {
  995.         i = Board_Tiles[4][1].y - bp->y;
  996.         PNT( bp->x + bp->level * Side_X + Tile_Width + 1 + 1,
  997.              bp->y - bp->level * Side_Y );
  998.         PNT( Shadow_X, -Shadow_Y );
  999.         PNT( 0, i + Shadow_Y );
  1000.         PNT( -Shadow_X, 0 );
  1001.