home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cset21v1.zip / IBMCPP / WKFRAME / MAHJONGG / MAHJONGG.C < prev    next >
Text File  |  1993-02-28  |  66KB  |  1,517 lines

  1. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  2. /*│                                                                          │*/
  3. /*│ PROGRAM NAME: MAHJONGG                                                   │*/
  4. /*│ -------------                                                            │*/
  5. /*│  A PM version of a Chinese game similar to 'concentration' but without   │*/
  6. /*│  the background puzzle.                                                  │*/
  7. /*│                                                                          │*/
  8. /*│ COPYRIGHT:                                                               │*/
  9. /*│ ----------                                                               │*/
  10. /*│  Copyright (C) International Business Machines Corp., 1991,1992,1993.    │*/
  11. /*│                                                                          │*/
  12. /*│ DISCLAIMER OF WARRANTIES:                                                │*/
  13. /*│ -------------------------                                                │*/
  14. /*│  The following [enclosed] code is sample code created by IBM Corporation.│*/
  15. /*│  This sample code is not part of any standard IBM product and is provided│*/
  16. /*│  to you solely for the purpose of assisting you in the development of    │*/
  17. /*│  your applications.  The code is provided "AS IS", without warranty of   │*/
  18. /*│  any kind.  IBM shall not be liable for any damages arising out of your  │*/
  19. /*│  use of the sample code, even if they have been advised of the           │*/
  20. /*│  possibility of such damages.                                            │*/
  21. /*│                                                                          │*/
  22. /*│ REVISION LEVEL: 1.0                                                      │*/
  23. /*│ ---------------                                                          │*/
  24. /*│                                                                          │*/
  25. /*│ WHAT THIS PROGRAM DOES:                                                  │*/
  26. /*│ -----------------------                                                  │*/
  27. /*│  This program displays a board with 144 tiles on it.  Each tile has a    │*/
  28. /*│  symbol on it that must be matched with another tile with either the     │*/
  29. /*│  same symbol in most cases or with a similar symbol in other cases.      │*/
  30. /*│                                                                          │*/
  31. /*│ WHAT THIS PROGRAM DEMONSTRATES:                                          │*/
  32. /*│ -------------------------------                                          │*/
  33. /*│  This program demonstrates how to create, display and manipulate windows │*/
  34. /*│  in order to perform the necessary actions needed to run the game.       │*/
  35. /*│                                                                          │*/
  36. /*│ WHAT YOU NEED TO COMPILE THIS PROGRAM:                                   │*/
  37. /*│ --------------------------------------                                   │*/
  38. /*│                                                                          │*/
  39. /*│  REQUIRED FILES:                                                         │*/
  40. /*│  ---------------                                                         │*/
  41. /*│                                                                          │*/
  42. /*│    MAHJONGG C     - main source including the main window procedure      │*/
  43. /*│    MAHJONGG H     - Mahjongg header file                                 │*/
  44. /*│    TILE     C     - source for tile window procedure & related functions │*/
  45. /*│    MAHJONGG RC    - resource file for Mahjongg                           │*/
  46. /*│    MAHJONGG DEF   - definition file for Mahjongg                         │*/
  47. /*│    MAHJONGG ICO   - icon file for Mahjongg                               │*/
  48. /*│    MAHJONGG IPF   - documentation file for Mahjongg                      │*/
  49. /*│    MAHJONGG MAK   - make file for Mahjongg generated by utility          │*/
  50. /*│    MAHJONGG DEP   - dependancy for Mahjongg generated by utility         │*/
  51. /*│    MAKEFILE       - make file for Mahjongg (hand written)                │*/
  52. /*│    TILE_B_1 BMP   ┐                                                      │*/
  53. /*│    TILE_B_2 BMP   │                                                      │*/
  54. /*│    TILE_B_3 BMP   │                                                      │*/
  55. /*│    TILE_B_4 BMP   │                                                      │*/
  56. /*│    TILE_B_5 BMP   ├ Bamboo suit bitmaps for tiles                        │*/
  57. /*│    TILE_B_6 BMP   │                                                      │*/
  58. /*│    TILE_B_7 BMP   │                                                      │*/
  59. /*│    TILE_B_8 BMP   │                                                      │*/
  60. /*│    TILE_B_9 BMP   ┘                                                      │*/
  61. /*│    TILE_C_1 BMP   ┐                                                      │*/
  62. /*│    TILE_C_2 BMP   │                                                      │*/
  63. /*│    TILE_C_3 BMP   │                                                      │*/
  64. /*│    TILE_C_4 BMP   │                                                      │*/
  65. /*│    TILE_C_5 BMP   ├ Character suit bitmaps for tiles                     │*/
  66. /*│    TILE_C_6 BMP   │                                                      │*/
  67. /*│    TILE_C_7 BMP   │                                                      │*/
  68. /*│    TILE_C_8 BMP   │                                                      │*/
  69. /*│    TILE_C_9 BMP   ┘                                                      │*/
  70. /*│    TILE_D_1 BMP   ┐                                                      │*/
  71. /*│    TILE_D_2 BMP   │                                                      │*/
  72. /*│    TILE_D_3 BMP   │                                                      │*/
  73. /*│    TILE_D_4 BMP   │                                                      │*/
  74. /*│    TILE_D_5 BMP   ├ Dots suit bitmaps for tiles                          │*/
  75. /*│    TILE_D_6 BMP   │                                                      │*/
  76. /*│    TILE_D_7 BMP   │                                                      │*/
  77. /*│    TILE_D_8 BMP   │                                                      │*/
  78. /*│    TILE_D_9 BMP   ┘                                                      │*/
  79. /*│    TILE_F_1 BMP   ┐                                                      │*/
  80. /*│    TILE_F_2 BMP   ├ Flowers suit bitmaps for tiles                       │*/
  81. /*│    TILE_F_3 BMP   │                                                      │*/
  82. /*│    TILE_F_4 BMP   ┘                                                      │*/
  83. /*│    TILE_R_1 BMP   ┐                                                      │*/
  84. /*│    TILE_R_2 BMP   ├ Dragons suit bitmaps for tiles                       │*/
  85. /*│    TILE_R_3 BMP   ┘                                                      │*/
  86. /*│    TILE_S_1 BMP   ┐                                                      │*/
  87. /*│    TILE_S_2 BMP   ├ Seasons suit bitmaps for tiles                       │*/
  88. /*│    TILE_S_3 BMP   │                                                      │*/
  89. /*│    TILE_S_4 BMP   ┘                                                      │*/
  90. /*│    TILE_W_E BMP   ┐                                                      │*/
  91. /*│    TILE_W_N BMP   ├ Winds suit bitmaps for tiles                         │*/
  92. /*│    TILE_W_S BMP   │                                                      │*/
  93. /*│    TILE_W_W BMP   ┘                                                      │*/
  94. /*│    TILE_N_0 BMP   ┐                                                      │*/
  95. /*│    TILE_N_1 BMP   │                                                      │*/
  96. /*│    TILE_N_2 BMP   │                                                      │*/
  97. /*│    TILE_N_3 BMP   │                                                      │*/
  98. /*│    TILE_N_4 BMP   │                                                      │*/
  99. /*│    TILE_N_5 BMP   ├ Number bitmaps for tiles                             │*/
  100. /*│    TILE_N_6 BMP   │                                                      │*/
  101. /*│    TILE_N_7 BMP   │                                                      │*/
  102. /*│    TILE_N_8 BMP   │                                                      │*/
  103. /*│    TILE_N_9 BMP   ┘                                                      │*/
  104. /*│    CONGRAT  BMP   - congratulations bitmap                               │*/
  105. /*│    ABOUT    BMP   - about bitmap                                         │*/
  106. /*│    BACKVGA  BMP   - background bitmap (VGA,  16 color)                   │*/
  107. /*│    BACKBGA  BMP   - background bitmap (BGA, 256 color)                   │*/
  108. /*│                                                                          │*/
  109. /*│  REQUIRED LIBRARIES:                                                     │*/
  110. /*│  -------------------                                                     │*/
  111. /*│                                                                          │*/
  112. /*│    OS2386.LIB     - OS/2 API library                                     │*/
  113. /*│                                                                          │*/
  114. /*│  REQUIRED PROGRAMS:                                                      │*/
  115. /*│  ------------------                                                      │*/
  116. /*│                                                                          │*/
  117. /*│    IBM C Set/2 Compiler (icc.exe)                                        │*/
  118. /*│    IBM Linker (link386.exe)                                              │*/
  119. /*│    Resource Compiler (rc.exe)                                            │*/
  120. /*│                                                                          │*/
  121. /*│ EXPECTED INPUT:                                                          │*/
  122. /*│ ---------------                                                          │*/
  123. /*│                                                                          │*/
  124. /*│    You can start the program minimized by using the /MIN option.         │*/
  125. /*│                                                                          │*/
  126. /*│ EXPECTED OUTPUT:                                                         │*/
  127. /*│ ----------------                                                         │*/
  128. /*│                                                                          │*/
  129. /*└──────────────────────────────────────────────────────────────────────────┘*/
  130.  
  131. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  132. /*│ MAHJONGG.C                                                               │*/
  133. /*│                                                                          │*/
  134. /*│ Mahjongg Game main source file                                           │*/
  135. /*└──────────────────────────────────────────────────────────────────────────┘*/
  136.  
  137. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  138. /*│ local constants                                                          │*/
  139. /*└──────────────────────────────────────────────────────────────────────────┘*/
  140. #define DEFAULT_BGA_DX           3L
  141. #define DEFAULT_VGA_DX           2L
  142.  
  143. #define TILE_CX                  17
  144. #define TILE_CY                  22
  145. #define TILE_BW                   2  /* border width */
  146. #define TILE_LD                   2  /* level distance */
  147. #define BOARD_FR_CX               5  /* frame arround the board */
  148. #define BOARD_FR_CY               5  /* frame arround the board */
  149.  
  150. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  151. /*│ Includes                                                                 │*/
  152. /*└──────────────────────────────────────────────────────────────────────────┘*/
  153. #define  INCL_BASE
  154. #define  DEFINE_VARIABLES
  155. #include "mahjongg.h"
  156.  
  157. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  158. /*│ local variables                                                          │*/
  159. /*└──────────────────────────────────────────────────────────────────────────┘*/
  160. BOOL   bMinAfterStart = FALSE;
  161. SHORT  sMaxAdjx       = 0L; /* center adjustement for maximized window */
  162. SHORT  sMaxAdjy       = 0L; /* center adjustement for maximized window */
  163. USHORT idb_back;
  164.  
  165. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  166. /*│ local help variables                                                     │*/
  167. /*└──────────────────────────────────────────────────────────────────────────┘*/
  168. HELPINIT hmiHelpData;                   /* Help initialization structure */
  169. HWND     hwndHelpInstance;              /* Handle to Help window */
  170.  
  171. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  172. /*│ local function declarations                                              │*/
  173. /*└──────────────────────────────────────────────────────────────────────────┘*/
  174. VOID InitializeDefaultTiles(VOID);
  175. VOID InitializeDefaultGame(VOID);
  176.  
  177. VOID ExplodeStar(HPS hps,
  178.                  PPOINTL center,
  179.                  INT dr,
  180.                  INT itr,
  181.                  INT substars
  182.                 );
  183.  
  184. #define UNDO_SIZE       (NBR_OF_TILES/2)+1
  185. static struct {
  186.     INT Tile1;
  187.     INT Tile2;
  188.   } UndoBuffer[UNDO_SIZE];
  189. static INT UndoTop     = 0;
  190. static INT UndoCurrent = 0;
  191. static INT UndoBottom  = 0;
  192.  
  193. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  194. /*│ local macro declarations                                                 │*/
  195. /*└──────────────────────────────────────────────────────────────────────────┘*/
  196. #define absm(A) ((A) < 0 ? (-(A)) : (A))
  197.  
  198. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  199. /*│ Memory Allocation / Deallocation                                         │*/
  200. /*└──────────────────────────────────────────────────────────────────────────┘*/
  201. void *MemAlloc(USHORT size)
  202. {
  203.   void *p;
  204.   if ((p = malloc(size)) == NULL) {
  205.     WinMessageBox(HWND_DESKTOP,
  206.                   HWND_DESKTOP,
  207.                   (PSZ)"Error: Could not allocate memory",
  208.                   (PSZ)Game.pszTitle,
  209.                   0,
  210.                   MB_CUAWARNING | MB_OK | MB_MOVEABLE);
  211.   } /* endif */
  212.   return(p);
  213. }
  214.  
  215. BOOL MemFree(void *p)
  216. {
  217.   if (p) free(p);
  218.   return(TRUE);
  219. }
  220.  
  221. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  222. /*│ local variables for options saving and loading                           │*/
  223. /*└──────────────────────────────────────────────────────────────────────────┘*/
  224. static CHAR szMahjongg[]     = {"MAHJONGG"};
  225. static CHAR szSound[]        = {"Sound"};
  226. static CHAR szX[]              = {"X"};
  227. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  228. /*│ Save Options into the OS2INI file                                        │*/
  229. /*└──────────────────────────────────────────────────────────────────────────┘*/
  230. static VOID SaveOptions(VOID)
  231. {
  232.   CHAR    szText[64];
  233.  
  234.   sprintf(szText, "%d", bSound);
  235.   PrfWriteProfileString(hab, szMahjongg, szSound, szText);
  236. }
  237.  
  238. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  239. /*│ Load Options from the OS2INI file                                        │*/
  240. /*└──────────────────────────────────────────────────────────────────────────┘*/
  241. static VOID LoadOptions(VOID)
  242. {
  243.   CHAR    szText[64];
  244.  
  245.   PrfQueryProfileString(hab, szMahjongg, szSound, szX, szText, sizeof(szText));
  246.   if (szText[0] != szX[0]) bSound = atoi(szText);
  247. }
  248.  
  249. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  250. /*│ main                                                                     │*/
  251. /*└──────────────────────────────────────────────────────────────────────────┘*/
  252. main(int argc, char *argv[])
  253. {
  254.  
  255.   HMQ    hmq        = NULLH;
  256.   QMSG   qmsg;
  257.   ULONG  ctlData;
  258.   SHORT  i;
  259.   SWP    swp;
  260.   CHAR   szTemp[256];
  261.   INT    rc = 0;
  262.  
  263.   if (!(hab=WinInitialize(0))) return(1);
  264.   if (!(hmq=WinCreateMsgQueue(hab, 1000))) return(2);
  265.  
  266.   /* parse arguments */
  267.   for (i=1; i<argc; i++) {
  268.     if (strncmp(strupr(argv[i]), "/MIN", 4) == 0)
  269.       bMinAfterStart = TRUE;
  270.   } /* endfor */
  271.  
  272.   /* intialize strings */
  273.   for (i=IDS_FIRST_STRING; i<=IDS_LAST_STRING; i++) {
  274.     WinLoadString(hab, 0, i, sizeof(szTemp), (PSZ)szTemp);
  275.     if (pszStringTab[i] = MemAlloc(strlen(szTemp)+1)) {
  276.       strcpy(pszStringTab[i], szTemp);
  277.     } else {
  278.       /* ??? not enough memory */
  279.     } /* endif */
  280.   } /* endfor */
  281.  
  282.   if (!WinRegisterClass( hab,
  283.                        pszStringTab[IDS_CLASS_MAHJONGG],
  284.                        (PFNWP)MainWndProc,
  285.                        CS_SIZEREDRAW | CS_MOVENOTIFY,
  286.                        0)) {
  287.     rc = 3;
  288.     goto MainExit;
  289.   } /* endif */
  290.   if (!WinRegisterClass( hab,
  291.                        pszStringTab[IDS_CLASS_TILE],
  292.                        (PFNWP)TileWndProc,
  293.                        CS_CLIPSIBLINGS,
  294.                        0)) {
  295.     rc = 4;
  296.     goto MainExit;
  297.   } /* endif */
  298.  
  299.   InitializeDefaultTiles();
  300.   LoadOptions();  /* read the user saved options from the OS2.INI file */
  301.   InitializeDefaultGame();
  302.  
  303.   hptrArrow       = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE);
  304.   hptrWait        = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT,  FALSE);
  305.  
  306.   GpiLoadFonts(hab, "C:\\OS2\\DLL\\HELV.FON");
  307.  
  308.    /* IPF Initialization Structure */
  309.    hmiHelpData.cb                       = sizeof(HELPINIT);
  310.    hmiHelpData.ulReturnCode             = 0;
  311.    hmiHelpData.pszTutorialName          = NULL;
  312.    hmiHelpData.phtHelpTable             = (PVOID)(0xffff0000 | IDH_MAIN_TABLE);
  313.                                           /* action bar is not tailored      */
  314.    hmiHelpData.hmodAccelActionBarModule = 0;
  315.    hmiHelpData.idAccelTable             = 0;
  316.    hmiHelpData.idActionBar              = 0;
  317.    hmiHelpData.pszHelpWindowTitle       = "Mahjongg Help Window";
  318.    hmiHelpData.hmodHelpTableModule      = 0;
  319.    hmiHelpData.fShowPanelId             = 0;
  320.    hmiHelpData.pszHelpLibraryName       = "MAHJONGG.HLP";
  321.  
  322.    /* Create Instance of IPF */
  323.    hwndHelpInstance = WinCreateHelpInstance(hab, &hmiHelpData);
  324.    if (!hwndHelpInstance) {
  325.      WinMessageBox( HWND_DESKTOP, HWND_DESKTOP,
  326.                     (PSZ) "Help Not Available",
  327.                     (PSZ) "Help Creation Error",
  328.                     1,
  329.                     MB_OK | MB_APPLMODAL | MB_MOVEABLE);
  330.    } else {
  331.      if (hmiHelpData.ulReturnCode) {
  332.         WinMessageBox( HWND_DESKTOP, HWND_DESKTOP,
  333.                        (PSZ) "Help Terminated Due to Error",
  334.                        (PSZ) "Help Creation Error",
  335.                        1,
  336.                        MB_OK | MB_APPLMODAL | MB_MOVEABLE);
  337.         WinDestroyHelpInstance(hwndHelpInstance);
  338.      } /* endif */
  339.    } /* endif */
  340.  
  341.   ctlData = FCF_STANDARD;
  342.   hwndFrame = WinCreateStdWindow(HWND_DESKTOP,
  343.                                  FS_STANDARD,
  344.                                  &ctlData,
  345.                                  pszStringTab[IDS_CLASS_MAHJONGG],
  346.                                  (PSZ)NULL,
  347.                                  0L,
  348.                                  NULLH,
  349.                                  ID_WINDOW,
  350.                                  (PHWND)&hwndBoard );
  351.   if (!hwndFrame) { rc = 5; goto MainExit; } /* endif */
  352.   oldFrameProc = WinSubclassWindow(hwndFrame, FrameSubClass);
  353.   swcntrl.hwnd          = hwndFrame;
  354.   swcntrl.hwndIcon      = NULLH;
  355.   swcntrl.hprog         = NULLH;
  356.   swcntrl.idProcess     = (USHORT)0;
  357.   swcntrl.idSession     = (USHORT)0;
  358.   swcntrl.uchVisibility = SWL_VISIBLE;
  359.   swcntrl.fbJump        = SWL_JUMPABLE;
  360.   hSwitch = WinAddSwitchEntry((PSWCNTRL)&swcntrl);
  361.   WinSetWindowText(hwndFrame, swcntrl.szSwtitle);
  362.  
  363.   // make sure that inital window is inside screen
  364.   WinQueryTaskSizePos(hab, 0, &swp);
  365.   swp.cx = (SHORT)deltaX * Board.cx
  366.            + 2*(SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
  367.   swp.cy = (SHORT)deltaX * Board.cy
  368.            + 2*(SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER)
  369.            + (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR)
  370.            + (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYMENU);
  371.   if (swp.x+swp.cx > WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN))
  372.     swp.x = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)-swp.cx;
  373.   if (swp.x < 0) swp.x = 0;  // align to left border of screen
  374.   if (swp.y < 0) swp.y = 0;  // align to top border of screen
  375.   if (swp.y+swp.cy > WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN))
  376.     swp.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - swp.cy;
  377.  
  378.   if (bMinAfterStart) {
  379.     WinSetWindowPos(hwndFrame, HWND_TOP, 0,0,0,0, SWP_MINIMIZE | SWP_SHOW);
  380.     WinSetWindowUShort(hwndFrame, QWS_XRESTORE,  swp.x);
  381.     WinSetWindowUShort(hwndFrame, QWS_YRESTORE,  swp.y);
  382.     WinSetWindowUShort(hwndFrame, QWS_CXRESTORE, swp.cx);
  383.     WinSetWindowUShort(hwndFrame, QWS_CYRESTORE, swp.cy);
  384.   } else {
  385.     WinSetWindowPos(hwndFrame, HWND_TOP,
  386.                     swp.x, swp.y, swp.cx, swp.cy,
  387.                     SWP_SIZE | SWP_ACTIVATE | SWP_SHOW |
  388.                     SWP_MOVE | SWP_ZORDER);
  389.   } /* endif */
  390.  
  391.   /* Associate Instance of IPF */
  392.   if (hwndHelpInstance) WinAssociateHelpInstance (hwndHelpInstance, hwndFrame);
  393.  
  394.   while(WinGetMsg(hab, (PQMSG)&qmsg, (HWND)NULL, 0, 0)) {
  395.     WinDispatchMsg(hab, (PQMSG)&qmsg);
  396.   } /* endwhile */
  397.  
  398.   MainExit:
  399.  
  400.   /* Destroy Instance of IPF */
  401.   if (hwndHelpInstance)
  402.      WinDestroyHelpInstance (hwndHelpInstance);
  403.  
  404.   GpiUnloadFonts(hab, "C:\\OS2\\DLL\\HELV.FON");
  405.  
  406.   /* deallocate strings */
  407.   for (i=IDS_FIRST_STRING; i<=IDS_LAST_STRING; i++) {
  408.     MemFree(pszStringTab[i]);
  409.   } /* endfor */
  410.  
  411.   WinRemoveSwitchEntry(hSwitch);
  412.   WinDestroyMsgQueue(hmq);
  413.   WinTerminate(hab);
  414.   return(rc);
  415. }
  416.  
  417. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  418. /*│ Initialize the Default Mahjongg Game                                     │*/
  419. /*└──────────────────────────────────────────────────────────────────────────┘*/
  420. VOID InitializeDefaultGame(VOID)
  421. {
  422.   INT i,j,x,y;
  423.  
  424.   Game.pszTitle    = strdup("Mahjongg Solitaire");
  425.   Game.pszHelpFile = strdup("MAHJONGG.HLP");
  426.  
  427.   Board.cx         = 2*BOARD_FR_CX + 16*(TILE_CX-TILE_BW) + TILE_BW;
  428.   Board.cy         = 2*BOARD_FR_CY +  8*(TILE_CY-TILE_BW) + TILE_BW;
  429.   Board.cxt        = TILE_CX;
  430.   Board.cyt        = TILE_CY;
  431.  
  432.   /* bottom level */
  433.   x = BOARD_FR_CX + 12*(TILE_CX-TILE_BW);
  434.   y = BOARD_FR_CY +  7*(TILE_CY-TILE_BW);
  435.   for (i=0; i<12; i++) {
  436.     TilePos[i][0] = x;
  437.     TilePos[i][1] = y;
  438.     x -= (TILE_CX-TILE_BW);
  439.   } /* endfor */
  440.   x = BOARD_FR_CX + 10*(TILE_CX-TILE_BW);
  441.   y = BOARD_FR_CY +  6*(TILE_CY-TILE_BW);
  442.   for (i=12; i<20; i++) {
  443.     TilePos[i][0] = x;
  444.     TilePos[i][1] = y;
  445.     x -= (TILE_CX-TILE_BW);
  446.   } /* endfor */
  447.   x = BOARD_FR_CX + 11*(TILE_CX-TILE_BW);
  448.   y = BOARD_FR_CY +  5*(TILE_CY-TILE_BW);
  449.   for (i=20; i<30; i++) {
  450.     TilePos[i][0] = x;
  451.     TilePos[i][1] = y;
  452.     x -= (TILE_CX-TILE_BW);
  453.   } /* endfor */
  454.   x = BOARD_FR_CX + 14*(TILE_CX-TILE_BW);
  455.   y = BOARD_FR_CY +  3*(TILE_CY-TILE_BW) + TILE_CY/2;
  456.   TilePos[30][0] = x;
  457.   TilePos[30][1] = y;
  458.   x -= (TILE_CX-TILE_BW);
  459.   TilePos[31][0] = x;
  460.   TilePos[31][1] = y;
  461.   x -= (TILE_CX-TILE_BW);
  462.   y = BOARD_FR_CY +  4*(TILE_CY-TILE_BW);
  463.   for (i=32; i<44; i++) {
  464.     TilePos[i][0] = x;
  465.     TilePos[i][1] = y;
  466.     x -= (TILE_CX-TILE_BW);
  467.   } /* endfor */
  468.   x = BOARD_FR_CX + 12*(TILE_CX-TILE_BW);
  469.   y = BOARD_FR_CY +  3*(TILE_CY-TILE_BW);
  470.   for (i=44; i<56; i++) {
  471.     TilePos[i][0] = x;
  472.     TilePos[i][1] = y;
  473.     x -= (TILE_CX-TILE_BW);
  474.   } /* endfor */
  475.   y += TILE_CY/2;
  476.   TilePos[56][0] = x;
  477.   TilePos[56][1] = y;
  478.   x = BOARD_FR_CX + 11*(TILE_CX-TILE_BW);
  479.   y = BOARD_FR_CY +  2*(TILE_CY-TILE_BW);
  480.   for (i=57; i<67; i++) {
  481.     TilePos[i][0] = x;
  482.     TilePos[i][1] = y;
  483.     x -= (TILE_CX-TILE_BW);
  484.   } /* endfor */
  485.   x = BOARD_FR_CX + 10*(TILE_CX-TILE_BW);
  486.   y = BOARD_FR_CY +  1*(TILE_CY-TILE_BW);
  487.   for (i=67; i<75; i++) {
  488.     TilePos[i][0] = x;
  489.     TilePos[i][1] = y;
  490.     x -= (TILE_CX-TILE_BW);
  491.   } /* endfor */
  492.   x = BOARD_FR_CX + 12*(TILE_CX-TILE_BW);
  493.   y = BOARD_FR_CY +  0*(TILE_CY-TILE_BW);
  494.   for (i=75; i<87; i++) {
  495.     TilePos[i][0] = x;
  496.     TilePos[i][1] = y;
  497.     x -= (TILE_CX-TILE_BW);
  498.   } /* endfor */
  499.   /* level 2 */
  500.   y = BOARD_FR_CY +  6*(TILE_CY-TILE_BW) + TILE_LD;
  501.   for (j=0; j<6; j++) {
  502.     x = BOARD_FR_CX + 9*(TILE_CX-TILE_BW) + TILE_LD;
  503.     for (i=0; i<6; i++) {
  504.       TilePos[87+j*6+i][0] = x;
  505.       TilePos[87+j*6+i][1] = y;
  506.       x -= (TILE_CX-TILE_BW);
  507.     } /* endfor */
  508.     y -= (TILE_CY-TILE_BW);
  509.   } /* endfor */
  510.   /* level 3 */
  511.   y = BOARD_FR_CY +  5*(TILE_CY-TILE_BW) + 2*TILE_LD;
  512.   for (j=0; j<4; j++) {
  513.     x = BOARD_FR_CX + 8*(TILE_CX-TILE_BW) + 2*TILE_LD;
  514.     for (i=0; i<4; i++) {
  515.       TilePos[123+j*4+i][0] = x;
  516.       TilePos[123+j*4+i][1] = y;
  517.       x -= (TILE_CX-TILE_BW);
  518.     } /* endfor */
  519.     y -= (TILE_CY-TILE_BW);
  520.   } /* endfor */
  521.   /* level 4 */
  522.   y = BOARD_FR_CY +  4*(TILE_CY-TILE_BW) + 3*TILE_LD;
  523.   for (j=0; j<2; j++) {
  524.     x = BOARD_FR_CX + 7*(TILE_CX-TILE_BW) + 3*TILE_LD;
  525.     for (i=0; i<2; i++) {
  526.       TilePos[139+j*2+i][0] = x;
  527.       TilePos[139+j*2+i][1] = y;
  528.       x -= (TILE_CX-TILE_BW);
  529.     } /* endfor */
  530.     y -= (TILE_CY-TILE_BW);
  531.   } /* endfor */
  532.   /* level 5 */
  533.   TilePos[143][0] = BOARD_FR_CX + 6*(TILE_CX-TILE_BW) + TILE_CX/2 + 4*TILE_LD;
  534.   TilePos[143][1] = BOARD_FR_CY + 3*(TILE_CY-TILE_BW) + TILE_CY/2 + 4*TILE_LD;
  535. }
  536.  
  537. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  538. /*│ Initialize the default tiles                                             │*/
  539. /*└──────────────────────────────────────────────────────────────────────────┘*/
  540. VOID InitializeDefaultTiles(VOID)
  541. {
  542.   INT i;
  543.  
  544.   for (i=0; i<NBR_OF_TILES; i++) {
  545.     Tiles[i].iTxt      = DefTiles[i].iTxt;
  546.     Tiles[i].suit      = DefTiles[i].suit;
  547.     Tiles[i].value     = DefTiles[i].value;
  548.     Tiles[i].bSelected = DefTiles[i].bSelected;
  549.     Tiles[i].bRemoved  = DefTiles[i].bRemoved;
  550.   } /* endfor */
  551. }
  552.  
  553. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  554. /*│ create tiles                                                             │*/
  555. /*└──────────────────────────────────────────────────────────────────────────┘*/
  556. VOID CreateTiles(HWND hwndParent)
  557. {
  558.   SHORT   cx,cy;
  559.   INT     i;
  560.  
  561.   cx = Board.cxt*(SHORT)deltaX;
  562.   cy = Board.cyt*(SHORT)deltaX;
  563.   for (i=0; i<NBR_OF_TILES; i++) {
  564.     Tiles[i].hwnd = WinCreateWindow(hwndParent,                   /* parent */
  565.                                     pszStringTab[IDS_CLASS_TILE], /* class */
  566.                                     (PSZ)NULL,                    /* title */
  567.                                     WS_VISIBLE,                   /* style */
  568.                                     TilePos[i][0]*(SHORT)deltaX,  /* x */
  569.                                     TilePos[i][1]*(SHORT)deltaX,  /* y */
  570.                                     cx,                           /* cx */
  571.                                     cy,                           /* cy */
  572.                                     hwndParent,                   /* owner */
  573.                                     HWND_TOP,                     /* behind */
  574.                                     i,                            /* id */
  575.                                     (PVOID)NULL,                  /* ctlDat */
  576.                                     (PVOID)NULL);                 /* reserv */
  577.     if (Tiles[i].hwnd == NULLH) {
  578.       WinMessageBox(HWND_DESKTOP,
  579.                     hwndFrame,
  580.                     (PSZ)"Error: while creating the tiles !",
  581.                     (PSZ)Game.pszTitle,
  582.                     0,
  583.                     MB_CUAWARNING | MB_OK | MB_MOVEABLE);
  584.       break;
  585.     } /* endif */
  586.   } /* endfor */
  587. }
  588. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  589. /*│ Shuffle Tile Indices                                                     │*/
  590. /*└──────────────────────────────────────────────────────────────────────────┘*/
  591. VOID ShuffleTiles(VOID)
  592. {
  593.   short     i,j,r,cellcount,hold,save,cyclestart;
  594.   int       k;
  595.   unsigned multiplier;
  596.  
  597.   /* intialize to sorted order */
  598.   for (i=0; i<NBR_OF_TILES; i++) {
  599.     Shuffled[i] = i;
  600.   } /* endfor */
  601.  
  602.   { LONG    ulTime;
  603.     time(&ulTime);
  604.     srand((USHORT)ulTime);
  605.   }
  606.  
  607.   cellcount = NBR_OF_TILES;
  608.   cyclestart = -1;
  609.   while (1) {
  610.      do {
  611.        ++cyclestart;
  612.        if (cyclestart >= NBR_OF_TILES)
  613.          break;;
  614.      } while (Shuffled[cyclestart]<0); /* enddo */
  615.      if (cyclestart >= NBR_OF_TILES)
  616.         break;
  617.      j = cyclestart;
  618.      save = Shuffled[j];
  619.      do {
  620.        hold = save;
  621.        frexp((double)cellcount, &k);  /* which power of 2 is cellcount? */
  622.        multiplier = 0x0001 << (15-k); /* form the multiplier */
  623.        while (multiplier * cellcount - 1 <= (r=rand()));
  624.        if (cellcount)
  625.          r %= cellcount;
  626.        for (++r; r>0; r--) {  /* the number of cells to skip */
  627.          do {
  628.  
  629.            (j==(NBR_OF_TILES-1))?(j=0):(j++); /* seek an uncanceled cell */
  630.  
  631.          } while (Shuffled[j]<0); /* enddo */
  632.        } /* endfor */
  633.        save = Shuffled[j];
  634.        Shuffled[j] = hold | 0x8000; /* mark the cell with the sign bit */
  635.        cellcount--;
  636.      }
  637.      while (j!=cyclestart);
  638.   }
  639.  
  640.   for (i=0; i<NBR_OF_TILES; i++)
  641.     Shuffled[i] = Shuffled[i] & 0x7fff;
  642. }
  643. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  644. /*│ Clear Message Queue                                                      │*/
  645. /*│ INPUT  : NONE                                                            │*/
  646. /*│ RETURNS: TRUE            if all messages were cleared                    │*/
  647. /*│          FALSE           if a WM_COMMAND or WM_BUTTONx message is pending│*/
  648. /*└──────────────────────────────────────────────────────────────────────────┘*/
  649. BOOL ClearMsgQueue(void)
  650. {
  651.   QMSG qmsg;
  652.   while (WinPeekMsg(hab, (PQMSG)&qmsg, NULLH, 0, 0,
  653.          PM_REMOVE)) {
  654.     switch (qmsg.msg) {
  655.       case WM_QUIT:
  656.         WinPostMsg(hwndBoard, WM_CLOSE, (MPARAM)0, (MPARAM)0);
  657.         return(FALSE);
  658.         break;
  659.       case WM_COMMAND:
  660.       case WM_BUTTON1DOWN:
  661.       case WM_BUTTON2DOWN:
  662.       case WM_CLOSE:
  663.         WinPostMsg(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
  664.         return(FALSE);
  665.         break;
  666.       default:
  667.       WinDispatchMsg(hab, (PQMSG)&qmsg);
  668.     } /* endswitch */
  669.   } /* endwhile */
  670.   return(TRUE);
  671. }
  672.  
  673. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  674. /*│ Adjust the frame window size on creation of a patience game              │*/
  675. /*└──────────────────────────────────────────────────────────────────────────┘*/
  676. VOID CreationAdjustment(VOID)
  677. {
  678.   SWP   swp;
  679.   RECTL rectl;
  680.  
  681.   if (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN) > 640L) {
  682.     idb_back = IDB_BACKBGA;
  683.     deltaX   = DEFAULT_BGA_DX;
  684.   } else {
  685.     idb_back = IDB_BACKVGA;
  686.     deltaX = DEFAULT_VGA_DX;
  687.   } /* endif */
  688.   WinQueryWindowPos(hwndFrame, &swp);
  689.   if (swp.fl & SWP_MAXIMIZE) {
  690.     WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0,
  691.                      SWP_MAXIMIZE | SWP_SHOW | SWP_ZORDER);
  692.   } else {
  693.     rectl.xLeft   = 0;
  694.     rectl.yBottom = 0;
  695.     rectl.xRight  = (LONG)Board.cx*deltaX;
  696.     rectl.yTop    = (LONG)Board.cy*deltaX;
  697.     WinCalcFrameRect(hwndFrame, &rectl, FALSE);
  698.     swp.cx = (SHORT)(rectl.xRight-rectl.xLeft);
  699.     swp.cy = (SHORT)(rectl.yTop-rectl.yBottom);
  700.     WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, swp.cx, swp.cy,
  701.                      SWP_SIZE | SWP_SHOW | SWP_ZORDER);
  702.   } /* endif */
  703. }
  704.  
  705. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  706. /*│ deal tiles                                                               │*/
  707. /*└──────────────────────────────────────────────────────────────────────────┘*/
  708. VOID DealTiles(VOID)
  709. {
  710.   INT   i;
  711.  
  712.   for (i=0; i<NBR_OF_TILES; i++) {
  713.     WinSetWindowPos(Tiles[Shuffled[i]].hwnd, HWND_TOP,
  714.                     0, 0, 0, 0, SWP_HIDE);
  715.   } /* endfor */
  716.   for (i=0; i<NBR_OF_TILES; i++) {
  717.     Tiles[Shuffled[i]].bSelected = FALSE;
  718.     Tiles[Shuffled[i]].bRemoved  = FALSE;
  719.     Tiles[Shuffled[i]].iPos = i;
  720.     WinSetWindowPos(Tiles[Shuffled[i]].hwnd, HWND_TOP,
  721.                     sMaxAdjx + TilePos[i][0]*(SHORT)deltaX,
  722.                     sMaxAdjy + TilePos[i][1]*(SHORT)deltaX,
  723.                     0, 0,
  724.                     SWP_MOVE | SWP_SHOW | SWP_ZORDER);
  725.   } /* endfor */
  726.  
  727.   UndoTop     = 0;
  728.   UndoCurrent = 0;
  729.   UndoBottom  = 0;
  730.   NbrOfTilesRemaining = NBR_OF_TILES;
  731.   SelectedTile = NO_TILE;
  732. }
  733.  
  734. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  735. /*│ Main Window Procedure                                                    │*/
  736. /*└──────────────────────────────────────────────────────────────────────────┘*/
  737. MRESULT MainWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  738. {
  739.   switch (msg) {
  740.     case WM_CREATE:
  741.       { HPS hps;
  742.         /* dirty tricks !!! (since these variables normally get */
  743.         /* set when the creation is complete)                   */
  744.         hwndBoard = hwnd;
  745.  
  746.         hps = WinGetPS(hwnd);
  747.         GpiQueryRealColors(hps, LCOLOPT_REALIZED, 0L, 256L, ColorTable);
  748.         WinReleasePS(hps);
  749.         CreationAdjustment();
  750.         CreateTiles(hwnd);
  751.         WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(IDM_NEW_G), (MPARAM)0);
  752.  
  753.         /* change title */
  754.         strncpy(swcntrl.szSwtitle, Game.pszTitle, MAXNAMEL);
  755.         WinChangeSwitchEntry(hSwitch, (PSWCNTRL)&swcntrl);
  756.         return((MRESULT)FALSE);
  757.       } break;
  758.  
  759.     case WM_CLOSE:
  760.       WinPostMsg(hwnd, WM_QUIT, (MPARAM)0, (MPARAM)0);
  761.       break;
  762.  
  763.     case WM_INITMENU:
  764.       switch (LOUSHORT(mp1)) {
  765.         case IDA_MOVES:
  766.           if (UndoCurrent != UndoBottom) {
  767.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  768.                        MPFROM2SHORT(IDM_UNDO, TRUE),
  769.                        MPFROM2SHORT(MIA_DISABLED, 0));
  770.           } else {
  771.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  772.                        MPFROM2SHORT(IDM_UNDO, TRUE),
  773.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  774.           } /* endif */
  775.           if (UndoCurrent != UndoTop) {
  776.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  777.                        MPFROM2SHORT(IDM_REDO, TRUE),
  778.                        MPFROM2SHORT(MIA_DISABLED, 0));
  779.           } else {
  780.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  781.                        MPFROM2SHORT(IDM_REDO, TRUE),
  782.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  783.           } /* endif */
  784.           break;
  785.         case IDA_OPTIONS:
  786.           if (bSound) {
  787.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  788.                        MPFROM2SHORT(IDM_SOUND, TRUE),
  789.                        MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));
  790.           } else {
  791.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  792.                        MPFROM2SHORT(IDM_SOUND, TRUE),
  793.                        MPFROM2SHORT(MIA_CHECKED, 0));
  794.           } /* endif */
  795.           break;
  796.         case IDA_HELP:
  797.           if (hwndHelpInstance) {
  798.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  799.                        MPFROM2SHORT(IDM_HELP_HELP, TRUE),
  800.                        MPFROM2SHORT(MIA_DISABLED, 0));
  801.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  802.                        MPFROM2SHORT(IDM_HELP_EXTENDED, TRUE),
  803.                        MPFROM2SHORT(MIA_DISABLED, 0));
  804.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  805.                        MPFROM2SHORT(IDM_HELP_KEYS, TRUE),
  806.                        MPFROM2SHORT(MIA_DISABLED, 0));
  807.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  808.                        MPFROM2SHORT(IDM_HELP_INDEX, TRUE),
  809.                        MPFROM2SHORT(MIA_DISABLED, 0));
  810.           } else {
  811.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  812.                        MPFROM2SHORT(IDM_HELP_HELP, TRUE),
  813.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  814.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  815.                        MPFROM2SHORT(IDM_HELP_EXTENDED, TRUE),
  816.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  817.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  818.                        MPFROM2SHORT(IDM_HELP_KEYS, TRUE),
  819.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  820.             WinSendMsg(WinWindowFromID(hwndFrame, FID_MENU), MM_SETITEMATTR,
  821.                        MPFROM2SHORT(IDM_HELP_INDEX, TRUE),
  822.                        MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED));
  823.           } /* endif */
  824.           break;
  825.       } /* endswitch */
  826.       break;
  827.  
  828.     case WM_COMMAND:
  829.       switch (SHORT1FROMMP(mp1)) {
  830.         case IDM_EXIT:
  831.           WinPostMsg(hwnd, WM_CLOSE, (MPARAM)0, (MPARAM)0);
  832.           break;
  833.         case IDM_NEW_G:
  834.           if (!bDealing) {            /* don't allow reentrant new games */
  835.             bDealing = TRUE;
  836.             WinSetPointer(HWND_DESKTOP, hptrWait);
  837.             ShuffleTiles();
  838.             DealTiles();
  839.             WinSetPointer(HWND_DESKTOP, hptrArrow);
  840.             bDealing = FALSE;
  841.           } /* endif */
  842.           break;
  843.         case IDM_UNDO:
  844.           if (UndoCurrent != UndoBottom) {
  845.             INT t1,t2;
  846.             UndoCurrent--;
  847.             t1 = UndoBuffer[UndoCurrent].Tile1;
  848.             t2 = UndoBuffer[UndoCurrent].Tile2;
  849.             Tiles[t1].bRemoved   = FALSE;
  850.             Tiles[t2].bRemoved   = FALSE;
  851.             NbrOfTilesRemaining += 2;
  852.             WinSetWindowPos(Tiles[t1].hwnd, HWND_TOP, 0,0,0,0, SWP_SHOW);
  853.             WinSetWindowPos(Tiles[t2].hwnd, HWND_TOP, 0,0,0,0, SWP_SHOW);
  854.             if (SelectedTile != NO_TILE) {
  855.               WinSendMsg(Tiles[SelectedTile].hwnd, MJ_DESELECT, NULL, NULL);
  856.             } /* endif */
  857.             WinSendMsg(hwndBoard, MJ_INFORM_SELECTED, MPFROMSHORT(NO_TILE), NULL);
  858.             WinSendMsg(hwndBoard, MJ_DRAW_STATUS, NULL, NULL);
  859.           } /* endif */
  860.           break;
  861.         case IDM_REDO:
  862.           if (UndoCurrent != UndoTop) {
  863.             INT t1,t2;
  864.             t1 = UndoBuffer[UndoCurrent].Tile1;
  865.             t2 = UndoBuffer[UndoCurrent].Tile2;
  866.             WinSendMsg(Tiles[t1].hwnd, MJ_REMOVE, NULL, NULL);
  867.             WinSendMsg(Tiles[t2].hwnd, MJ_REMOVE, NULL, NULL);
  868.             if (SelectedTile != NO_TILE) {
  869.               WinSendMsg(Tiles[SelectedTile].hwnd, MJ_DESELECT, NULL, NULL);
  870.             } /* endif */
  871.             WinSendMsg(hwndBoard, MJ_INFORM_SELECTED, MPFROMSHORT(NO_TILE), NULL);
  872.             WinSendMsg(hwndBoard, MJ_DRAW_STATUS, NULL, NULL);
  873.             UndoCurrent++;
  874.           } /* endif */
  875.           break;
  876.         case IDM_SHOW:
  877.           /* show all possible moves */
  878.           { short oldTile,i,j,f;
  879.  
  880.             oldTile = SelectedTile;
  881.             if (SelectedTile != NO_TILE) {
  882.               /* deselect this tile first */
  883.               WinSendMsg(Tiles[SelectedTile].hwnd, MJ_DESELECT, NULL, NULL);
  884.             } /* endif */
  885.  
  886.             f = 0;
  887.             for (i=0; i<NBR_OF_TILES; i++) {
  888.               if (IsTileSelectable(i)) {
  889.                 for (j=i+1; j<NBR_OF_TILES; j++) {
  890.                   if (IsTileSelectable(j)) {
  891.                     if ((Tiles[i].suit == Tiles[j].suit) &&
  892.                         (Tiles[i].value == Tiles[j].value)) {
  893.                       /* flash the tiles */
  894.                       WinSendMsg(Tiles[i].hwnd, MJ_SELECT, NULL, NULL);
  895.                       WinSendMsg(Tiles[j].hwnd, MJ_SELECT, NULL, NULL);
  896.                       DosSleep(600L);
  897.                       WinSendMsg(Tiles[i].hwnd, MJ_DESELECT, NULL, NULL);
  898.                       WinSendMsg(Tiles[j].hwnd, MJ_DESELECT, NULL, NULL);
  899.                       f++;
  900.                     } else {
  901.                     } /* endif */
  902.                   } /* endif */
  903.                 } /* endfor */
  904.               } /* endif */
  905.             } /* endfor */
  906.  
  907.             SelectedTile = oldTile;
  908.             if (SelectedTile != NO_TILE) {
  909.               /* reselect this tile */
  910.               WinSendMsg(Tiles[SelectedTile].hwnd, MJ_SELECT, NULL, NULL);
  911.             } /* endif */
  912.  
  913.             if (f == 0) {
  914.               /* no more moves possible */
  915.               WinDlgBox(HWND_DESKTOP,
  916.                         hwnd,
  917.                         NoMoreWindowProc,
  918.                         0,
  919.                         IDD_NOMORE,
  920.                         NULL);
  921.             } /* endif */
  922.           } break;
  923.         case IDM_SOUND:
  924.           bSound = !bSound;
  925.           break;
  926.         case IDM_SAVEOPT:
  927.           SaveOptions();
  928.           break;
  929.         case IDM_HELP_HELP:
  930.           WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP, NULL, NULL);
  931.           break;
  932.         case IDM_HELP_EXTENDED:
  933.           WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP,
  934.                      MPFROMSHORT(ID_WINDOW), HM_RESOURCEID);
  935.           break;
  936.         case IDM_HELP_KEYS:
  937.           WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP,
  938.                      MPFROMSHORT(IDM_HELP_KEYS), HM_RESOURCEID);
  939.           break;
  940.         case IDM_HELP_INDEX:
  941.           WinSendMsg(hwndHelpInstance, HM_HELP_CONTENTS, NULL, NULL);
  942.           break;
  943.           break;
  944.         case IDM_ABOUT:
  945.           WinDlgBox(HWND_DESKTOP, hwnd, AboutWindowProc, 0, IDD_ABOUT, NULL);
  946.           break;
  947.       } /* endswitch */
  948.       break;
  949.  
  950.     case WM_BUTTON2DBLCLK:
  951.       if (!bDealing) {
  952.         WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(IDM_UNDO), NULL);
  953.       } /* endif */
  954.       break;
  955.  
  956.     case HM_ERROR:
  957.       if ((hwndHelpInstance && (ULONG)mp1) == HMERR_NO_MEMORY) {
  958.         WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  959.                       (PSZ)"Help Terminated Due to Memory Error",
  960.                       (PSZ)Game.pszTitle,
  961.                       1,
  962.                       MB_OK | MB_APPLMODAL | MB_MOVEABLE);
  963.         WinDestroyHelpInstance(hwndHelpInstance);
  964.       } else {
  965.         CHAR szErr[64];
  966.         sprintf(szErr, "Help Error %lx Occurred", (ULONG)mp1);
  967.         WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  968.                       (PSZ) "Help Error Occurred",
  969.                       (PSZ)Game.pszTitle,
  970.                       1,
  971.                       MB_OK | MB_APPLMODAL | MB_MOVEABLE);
  972.       } /* endif */
  973.       break;
  974.     case WM_ERASEBACKGROUND:
  975.       return((MRESULT)FALSE);
  976.       break;
  977.     case WM_PAINT:
  978.       { RECTL    rectl;
  979.         HPS      hps;
  980.         HBITMAP  hbm;
  981.         hps = WinBeginPaint(hwnd, NULLH, &rectl);
  982.         WinQueryWindowRect(hwnd, &rectl);
  983.         hbm = GpiLoadBitmap(hps, NULLH, idb_back, 0L, 0L);
  984.         WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rectl, 0L, 0L,
  985.                       DBM_NORMAL | DBM_STRETCH);
  986.         GpiDeleteBitmap(hbm);
  987.         WinEndPaint(hps);
  988.       } /* no break here! thee MJ_DRAW_STATUS should be the next case! */
  989.     case MJ_DRAW_STATUS:
  990.       { RECTL    rectl;
  991.         HPS      hps;
  992.         CHAR     szNbr[12];
  993.         HBITMAP  hbm;
  994.         INT      i,j;
  995.         static   LastLength=3;
  996.  
  997.         hps = WinGetPS(hwnd);
  998.         WinQueryWindowRect(hwnd, &rectl);
  999.         rectl.xRight -= BOARD_FR_CX*deltaX;
  1000.         rectl.xLeft   = rectl.xRight - (2L*TILE_CX*deltaX)/3L;
  1001.         rectl.yTop   -= BOARD_FR_CY + (9L*(TILE_CY-TILE_BW)*deltaX)/4L;
  1002.         rectl.yBottom = rectl.yTop-(2L*TILE_CY*deltaX)/3L;
  1003.         if (NbrOfTilesRemaining > 0) {
  1004.           _itoa(NbrOfTilesRemaining, szNbr, 10);
  1005.           j = strlen(szNbr)-1;
  1006.           for (i=j; i>=0; i--) {
  1007.             hbm = GpiLoadBitmap(hps, NULLH, IDB_TILE_N_0+szNbr[i]-'0', 0L, 0L);
  1008.             WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rectl, 0L, 0L,
  1009.                           DBM_NORMAL | DBM_STRETCH);
  1010.             GpiDeleteBitmap(hbm);
  1011.             rectl.xRight -= (2L*TILE_CX*deltaX)/3L;
  1012.             rectl.xLeft  -= (2L*TILE_CX*deltaX)/3L;
  1013.           } /* endfor */
  1014.         } else {
  1015.           j = -1;
  1016.         } /* endif */
  1017.         if (j<LastLength) {
  1018.           WinInvalidateRect(hwnd, &rectl, FALSE);
  1019.         } /* endif */
  1020.         LastLength = j;
  1021.         WinReleasePS(hps);
  1022.       } break;
  1023.     case MJ_PUSH_UNDOCMD:
  1024.       UndoBuffer[UndoCurrent].Tile1 = SHORT1FROMMP(mp1);
  1025.       UndoBuffer[UndoCurrent].Tile2 = SHORT2FROMMP(mp1);
  1026.       UndoCurrent++;
  1027.       UndoTop = UndoCurrent;
  1028.       break;
  1029.     case MJ_INFORM_SELECTED:
  1030.       SelectedTile = SHORT1FROMMP(mp1);
  1031.       break;
  1032.     case MJ_QUERY_SELECTED:
  1033.       return(MRFROMSHORT(SelectedTile));
  1034.       break;
  1035.     case MJ_ADJUST_TILES:
  1036.       { INT i;
  1037.         SHORT   cx,cy;
  1038.         cx = Board.cxt*(SHORT)deltaX;
  1039.         cy = Board.cyt*(SHORT)deltaX;
  1040.         for (i=0; i<NBR_OF_TILES; i++) {
  1041.           WinSetWindowPos(Tiles[Shuffled[i]].hwnd, HWND_TOP,
  1042.                           sMaxAdjx + TilePos[i][0]*(SHORT)deltaX,
  1043.                           sMaxAdjy + TilePos[i][1]*(SHORT)deltaX,
  1044.                           cx, cy,
  1045.                           SWP_MOVE | SWP_SIZE | SWP_ZORDER);
  1046.         } /* endfor */
  1047.       } break;
  1048.  
  1049.     case MJ_SUCCESS:
  1050.       { POINTL ptl;
  1051.         RECTL  rectl, rectl2;
  1052.         HPS    hps;
  1053.         LONG   ldx,ldy;
  1054.         INT    i,j,m,s,r;
  1055.         HBITMAP hbm;
  1056.         BITMAPINFOHEADER hbmInfo;
  1057.         BOOL success;
  1058.  
  1059.         #if defined(SUCC_LOG)
  1060.          printf("%u\n", usStart);
  1061.         #endif
  1062.  
  1063.         hps = WinGetPS(hwnd);
  1064.         GpiCreateLogColorTable(hps, LCOL_REALIZABLE, LCOLF_CONSECRGB,
  1065.                                0L, 256L, ColorTable);
  1066.         hbm = GpiLoadBitmap(hps, 0, IDB_CONGRATULATION, 0L, 0L);
  1067.         success=WinQueryWindowRect(hwnd, &rectl);
  1068.         GpiSetMix(hps, FM_XOR);
  1069.  
  1070.         /* use a do...while(0) "loop" to simplify the logic of this block */
  1071.         /* this allows us to break instead of nesting if...then statments */
  1072.         success = FALSE;
  1073.         do {
  1074.           for (j=0; j<3; j++) {
  1075.             ptl.x = (rectl.xLeft+rectl.xRight)/2L;
  1076.             ptl.y = (rectl.yBottom+rectl.yTop)/2L;
  1077.             for (i=0; i<5; i++) {
  1078.               s = !(rand()%3);         /* 0,1  */
  1079.               r = 1+rand()%3;          /* 1..3 */
  1080.               m = 1+rand()%3;          /* 1..3 */
  1081.               ExplodeStar(hps, &ptl, m, r, s);
  1082.               ExplodeStar(hps, &ptl, m, r, s);
  1083.               ptl.x += (LONG)((rand()%2 ? 1 : -1)*(rand()%50));
  1084.               ptl.y += (LONG)((rand()%2 ? 1 : -1)*(rand()%30));
  1085.               if (!ClearMsgQueue()) {
  1086.                 success = TRUE;
  1087.                 break;
  1088.               }
  1089.             } /* endfor */
  1090.             if (success)
  1091.               break;
  1092.           } /* endfor */
  1093.           if (success)
  1094.             break;
  1095.           GpiQueryBitmapParameters(hbm, &hbmInfo);
  1096.           ptl.x  = (rectl.xLeft+rectl.xRight)/2L;
  1097.           ptl.y  = (rectl.yBottom+rectl.yTop)/2L;
  1098.           for (i=1; i<=15; i++) {
  1099.             ldx = (LONG)((i*hbmInfo.cx)/15);
  1100.             ldy = (LONG)((i*hbmInfo.cy)/15);
  1101.             rectl2.xLeft   = ptl.x - ldx/2;
  1102.             rectl2.yBottom = ptl.y - ldy/2;
  1103.             rectl2.xRight  = rectl2.xLeft   + ldx;
  1104.             rectl2.yTop    = rectl2.yBottom + ldy;
  1105.             WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&rectl2, 0L, 0L,
  1106.                           DBM_NORMAL | DBM_STRETCH);
  1107.             s = rand()%2;            /* 0,1 */
  1108.             r = 1+rand()%3;          /* 1..3 */
  1109.             m = 1+rand()%3;          /* 1..3 */
  1110.             ExplodeStar(hps, &ptl, m, r, s);
  1111.             ExplodeStar(hps, &ptl, m, r, s);
  1112.             if (!ClearMsgQueue()) {
  1113.                success = TRUE;
  1114.                break;
  1115.             }
  1116.           } /* endfor */
  1117.           if (success)
  1118.             break;
  1119.           for (j=0; j<5; j++) {
  1120.             ptl.x = (rectl.xLeft+rectl.xRight)/2L;
  1121.             ptl.y = (rectl.yBottom+rectl.yTop)/2L;
  1122.             for (i=0; i<10; i++) {
  1123.               s = rand()%2;            /* 0,1 */
  1124.               r = 1+rand()%4;          /* 1..4 */
  1125.               m = 1+rand()%3;          /* 1..3 */
  1126.               ExplodeStar(hps, &ptl, m, r, s);
  1127.               ExplodeStar(hps, &ptl, m, r, s);
  1128.               ptl.x += (LONG)((rand()%2 ? 1 : -1)*(rand()%50));
  1129.               ptl.y += (LONG)((rand()%2 ? 1 : -1)*(rand()%30));
  1130.               if (!ClearMsgQueue()) {
  1131.                 success = TRUE;
  1132.                 break;
  1133.               }
  1134.             } /* endfor */
  1135.             if (success)
  1136.               break;
  1137.           } /* endfor */
  1138.         } while (0);
  1139.         GpiDeleteBitmap(hbm);
  1140.  
  1141.         ptl.x  = rectl.xLeft;
  1142.         ptl.y  = (rectl.yBottom+rectl.yTop)/2L;
  1143.         ptl.y -= (LONG)(hbmInfo.cy/2);
  1144.         rectl.xLeft   = ptl.x;
  1145.         rectl.yBottom = ptl.y;
  1146.         rectl.yTop    = ptl.y + (LONG)hbmInfo.cy + 20L;
  1147.         WinInvalidateRect(hwnd, &rectl, TRUE);
  1148.         WinReleasePS(hps);
  1149.       } break;
  1150.  
  1151.     default:
  1152.       return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  1153.       break;
  1154.   } /* endswitch */
  1155.  
  1156.   return((MRESULT)NULL);
  1157. }
  1158.  
  1159. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  1160. /*│ Draw Lines                                                               │*/
  1161. /*└──────────────────────────────────────────────────────────────────────────┘*/
  1162. VOID DrawLines(HPS     hps,
  1163.                PPOINTL pC,        /* draw relativ to this center */
  1164.                POINTL  Ptl[],     /* points (first quadrant only) */
  1165.                LONG    mult,      /* multiplicator */
  1166.                INT     n)         /* nbr of lines (=nbr of points/2) */
  1167. {
  1168.   INT i;
  1169.   POINTL p11,p12,p21,p22,p31,p32,p41,p42;
  1170.   for (i=0; i<n; i++) {
  1171.     p11.x = pC->x + mult*Ptl[2*i].x;    p11.y = pC->y + mult*Ptl[2*i].y;
  1172.     p12.x = pC->x + mult*Ptl[2*i+1].x;  p12.y = pC->y + mult*Ptl[2*i+1].y;
  1173.     p21.x = pC->x - mult*Ptl[2*i].x;    p21.y = pC->y - mult*Ptl[2*i].y;
  1174.     p22.x = pC->x - mult*Ptl[2*i+1].x;  p22.y = pC->y - mult*Ptl[2*i+1].y;
  1175.     p31.x = pC->x - mult*Ptl[2*i].y;    p31.y = pC->y + mult*Ptl[2*i].x;
  1176.     p32.x = pC->x - mult*Ptl[2*i+1].y;  p32.y = pC->y + mult*Ptl[2*i+1].x;
  1177.     p41.x = pC->x + mult*Ptl[2*i].y;    p41.y = pC->y - mult*Ptl[2*i].x;
  1178.     p42.x = pC->x + mult*Ptl[2*i+1].y;  p42.y = pC->y - mult*Ptl[2*i+1].x;
  1179.     GpiMove(hps, &p11);
  1180.     GpiLine(hps, &p12);
  1181.     GpiMove(hps, &p21);
  1182.     GpiLine(hps, &p22);
  1183.     GpiMove(hps, &p31);
  1184.     GpiLine(hps, &p32);
  1185.     GpiMove(hps, &p41);
  1186.     GpiLine(hps, &p42);
  1187.   } /* endfor */
  1188. }
  1189.  
  1190. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  1191. /*│ Draw an exploding star                                                   │*/
  1192. /*└──────────────────────────────────────────────────────────────────────────┘*/
  1193. VOID ExplodeStar(HPS     hps,
  1194.                  PPOINTL pC,          /* pC of the star */
  1195.                  INT     dr,          /* multiplicator */
  1196.                  INT     itr,         /* nbr of iterations */
  1197.                  INT     substars     /* 0 = none, 1 = stars, 2 = circles */
  1198.                 )
  1199. {
  1200.    static POINTL ptl0[2]  = { { 0L, 0L}, { 4L, 0L}
  1201.                             };
  1202.    static POINTL ptl1[4]  = { { 4L, 0L}, { 9L, 0L},
  1203.                               { 3L, 3L}, { 6L, 6L},
  1204.                             };
  1205.    static POINTL ptl2[8]  = { { 9L, 0L}, {15L, 0L},
  1206.                               { 8L, 3L}, {14L, 6L},
  1207.                               { 6L, 6L}, {11L,11L},
  1208.                               { 3L, 8L}, { 6L,14L},
  1209.                             };
  1210.    static POINTL ptl3[16] = { {15L, 0L}, {22L, 0L},
  1211.                               {15L, 3L}, {22L, 5L},
  1212.                               {14L, 6L}, {21L, 9L},
  1213.                               {12L, 8L}, {19L,12L},
  1214.                               {11L,11L}, {16L,16L},
  1215.                               { 8L,12L}, {12L,19L},
  1216.                               { 6L,14L}, { 9L,21L},
  1217.                               { 3L,15L}, { 5L,22L},
  1218.                             };
  1219.    static POINTL ptl4[32] = { {22L, 0L}, {30L, 0L},
  1220.                               {22L, 2L}, {30L, 3L},
  1221.                               {22L, 5L}, {29L, 6L},
  1222.                               {21L, 7L}, {29L, 9L},
  1223.                               {21L, 9L}, {28L,12L},
  1224.                               {19L,10L}, {27L,14L},
  1225.                               {19L,12L}, {25L,16L},
  1226.                               {17L,14L}, {23L,19L},
  1227.                               {16L,16L}, {22L,22L},
  1228.                               {14L,17L}, {19L,23L},
  1229.                               {12L,19L}, {16L,25L},
  1230.                               {10L,19L}, {14L,27L},
  1231.                               { 9L,21L}, {12L,28L},
  1232.                               { 7L,21L}, { 9L,29L},
  1233.                               { 5L,22L}, { 6L,29L},
  1234.                               { 2L,22L}, { 3L,30L},
  1235.                             };
  1236.    INT    i;
  1237.    POINTL p1,p2,p3,p4;
  1238.    LONG   mult, mult2;
  1239.    mult = (LONG)dr;
  1240.    mult2= (LONG)max(dr/4,1);
  1241.    GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1242.                LONGFromRGB(255,0,0)));
  1243.    DrawLines(hps, pC, ptl0, mult, 1);
  1244.    if (itr > 1) {
  1245.      GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1246.                  LONGFromRGB(255,160,0)));
  1247.      DrawLines(hps, pC, ptl1, mult, 2);
  1248.    } else {
  1249.      return;
  1250.    } /* endif */
  1251.    if (itr > 2) {
  1252.      GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1253.                  LONGFromRGB(255,255,0)));
  1254.      DrawLines(hps, pC, ptl2, mult, 4);
  1255.    } else {
  1256.      if (substars) {
  1257.        GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1258.                    LONGFromRGB(255,255,255)));
  1259.        for (i=0; i<2; i++) {
  1260.          p1.x = pC->x + mult*ptl1[2*i+1].x;  p1.y = pC->y + mult*ptl1[2*i+1].y;
  1261.          p2.x = pC->x - mult*ptl1[2*i+1].x;  p2.y = pC->y - mult*ptl1[2*i+1].y;
  1262.          p3.x = pC->x - mult*ptl1[2*i+1].y;  p3.y = pC->y + mult*ptl1[2*i+1].x;
  1263.          p4.x = pC->x + mult*ptl1[2*i+1].y;  p4.y = pC->y - mult*ptl1[2*i+1].x;
  1264.          DrawLines(hps, &p1, ptl1, mult2, 2);
  1265.          DrawLines(hps, &p2, ptl1, mult2, 2);
  1266.          DrawLines(hps, &p3, ptl1, mult2, 2);
  1267.          DrawLines(hps, &p4, ptl1, mult2, 2);
  1268.        } /* endfor */
  1269.      } else {
  1270.      } /* endif */
  1271.      return;
  1272.    } /* endif */
  1273.    if (itr > 3) {
  1274.      GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1275.                  LONGFromRGB(255,255,160)));
  1276.      DrawLines(hps, pC, ptl3, mult, 8);
  1277.    } else {
  1278.      if (substars) {
  1279.        GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1280.                    LONGFromRGB(255,0,0)));
  1281.        for (i=0; i<4; i++) {
  1282.          p1.x = pC->x + mult*ptl2[2*i+1].x;  p1.y = pC->y + mult*ptl2[2*i+1].y;
  1283.          p2.x = pC->x - mult*ptl2[2*i+1].x;  p2.y = pC->y - mult*ptl2[2*i+1].y;
  1284.          p3.x = pC->x - mult*ptl2[2*i+1].y;  p3.y = pC->y + mult*ptl2[2*i+1].x;
  1285.          p4.x = pC->x + mult*ptl2[2*i+1].y;  p4.y = pC->y - mult*ptl2[2*i+1].x;
  1286.          DrawLines(hps, &p1, ptl2, mult2, 4);
  1287.          DrawLines(hps, &p2, ptl2, mult2, 4);
  1288.          DrawLines(hps, &p3, ptl2, mult2, 4);
  1289.          DrawLines(hps, &p4, ptl2, mult2, 4);
  1290.        } /* endfor */
  1291.      } else {
  1292.      } /* endif */
  1293.      return;
  1294.    } /* endif */
  1295.    if (itr > 4) {
  1296.      GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1297.                  LONGFromRGB(255,255,255)));
  1298.      DrawLines(hps, pC, ptl4, mult,16);
  1299.      if (substars) {
  1300.        for (i=0; i<16; i++) {
  1301.          p1.x = pC->x + mult*ptl4[2*i+1].x;  p1.y = pC->y + mult*ptl4[2*i+1].y;
  1302.          p2.x = pC->x - mult*ptl4[2*i+1].x;  p2.y = pC->y - mult*ptl4[2*i+1].y;
  1303.          p3.x = pC->x - mult*ptl4[2*i+1].y;  p3.y = pC->y + mult*ptl4[2*i+1].x;
  1304.          p4.x = pC->x + mult*ptl4[2*i+1].y;  p4.y = pC->y - mult*ptl4[2*i+1].x;
  1305.          GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1306.                      LONGFromRGB(0,0,255)));
  1307.          DrawLines(hps, &p1, ptl1, mult2, 2);
  1308.          DrawLines(hps, &p2, ptl1, mult2, 2);
  1309.          DrawLines(hps, &p3, ptl1, mult2, 2);
  1310.          DrawLines(hps, &p4, ptl1, mult2, 2);
  1311.          GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1312.                      LONGFromRGB(0,160,255)));
  1313.          DrawLines(hps, &p1, ptl2, mult2, 4);
  1314.          DrawLines(hps, &p2, ptl2, mult2, 4);
  1315.          DrawLines(hps, &p3, ptl2, mult2, 4);
  1316.          DrawLines(hps, &p4, ptl2, mult2, 4);
  1317.          if (mult2 > 2) {
  1318.            GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1319.                        LONGFromRGB(160,180,255)));
  1320.            DrawLines(hps, &p1, ptl3, mult2, 8);
  1321.            DrawLines(hps, &p2, ptl3, mult2, 8);
  1322.            DrawLines(hps, &p3, ptl3, mult2, 8);
  1323.            DrawLines(hps, &p4, ptl3, mult2, 8);
  1324.          } else {
  1325.          } /* endif */
  1326.        } /* endfor */
  1327.      } else {
  1328.      } /* endif */
  1329.    } else {
  1330.      if (substars) {
  1331.        for (i=0; i<8; i++) {
  1332.          p1.x = pC->x + mult*ptl3[2*i+1].x;  p1.y = pC->y + mult*ptl3[2*i+1].y;
  1333.          p2.x = pC->x - mult*ptl3[2*i+1].x;  p2.y = pC->y - mult*ptl3[2*i+1].y;
  1334.          p3.x = pC->x - mult*ptl3[2*i+1].y;  p3.y = pC->y + mult*ptl3[2*i+1].x;
  1335.          p4.x = pC->x + mult*ptl3[2*i+1].y;  p4.y = pC->y - mult*ptl3[2*i+1].x;
  1336.          GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1337.                      LONGFromRGB(0,255,0)));
  1338.          DrawLines(hps, &p1, ptl1, mult2, 2);
  1339.          DrawLines(hps, &p2, ptl1, mult2, 2);
  1340.          DrawLines(hps, &p3, ptl1, mult2, 2);
  1341.          DrawLines(hps, &p4, ptl1, mult2, 2);
  1342.          GpiSetColor(hps, GpiQueryColorIndex(hps, LCOLOPT_REALIZED,
  1343.                      LONGFromRGB(0,255,160)));
  1344.          DrawLines(hps, &p1, ptl2, mult2, 4);
  1345.          DrawLines(hps, &p2, ptl2, mult2, 4);
  1346.          DrawLines(hps, &p3, ptl2, mult2, 4);
  1347.          DrawLines(hps, &p4, ptl2, mult2, 4);
  1348.        } /* endfor */
  1349.      } else {
  1350.      } /* endif */
  1351.    } /* endif */
  1352. }
  1353.  
  1354. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  1355. /*│ About Window Procedure                                                   │*/
  1356. /*└──────────────────────────────────────────────────────────────────────────┘*/
  1357. MRESULT AboutWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1358. {
  1359.   switch(msg) {
  1360.     case WM_CHAR:
  1361.       if ((LOUSHORT(mp2)&0x00FF) == 27) {  /* ESC */
  1362.         return((MRESULT)WinDismissDlg(hwnd, TRUE));
  1363.       } /* endif */
  1364.       return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  1365.       break;
  1366.     case WM_COMMAND:
  1367.       switch (SHORT1FROMMP(mp1)) {
  1368.         case IDD_OK:
  1369.           WinDismissDlg(hwnd, TRUE);
  1370.           break;
  1371.         default:
  1372.           return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1373.       } /* endswitch */
  1374.       break;
  1375.     default:
  1376.       return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  1377.   } /* endswitch */
  1378.   return((MRESULT)NULL);
  1379. }
  1380.  
  1381. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  1382. /*│ No more moves Dlg Procedure                                              │*/
  1383. /*└──────────────────────────────────────────────────────────────────────────┘*/
  1384. MRESULT NoMoreWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1385. {
  1386.   switch(msg) {
  1387.     case WM_CHAR:
  1388.       if ((LOUSHORT(mp2)&0x00FF) == 27) {  /* ESC */
  1389.         return((MRESULT)WinDismissDlg(hwnd, FALSE));
  1390.       } /* endif */
  1391.       return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  1392.       break;
  1393.     case WM_COMMAND:
  1394.       switch (SHORT1FROMMP(mp1)) {
  1395.         case IDD_OK:
  1396.           WinDismissDlg(hwnd, FALSE);
  1397.           break;
  1398.         case IDD_NEW:
  1399.           WinPostMsg(hwndBoard, WM_COMMAND, MPFROMSHORT(IDM_NEW_G), (MPARAM)0);
  1400.           WinDismissDlg(hwnd, TRUE);
  1401.           break;
  1402.         default:
  1403.           return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1404.       } /* endswitch */
  1405.       break;
  1406.     default:
  1407.       return(WinDefDlgProc(hwnd, msg, mp1, mp2));
  1408.   } /* endswitch */
  1409.   return((MRESULT)NULL);
  1410. }
  1411.  
  1412. /*┌──────────────────────────────────────────────────────────────────────────┐*/
  1413. /*│ frame subclass procedure                                                 │*/
  1414. /*└──────────────────────────────────────────────────────────────────────────┘*/
  1415. MRESULT FrameSubClass(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1416. {
  1417.   switch(msg) {
  1418.     case WM_ADJUSTWINDOWPOS:
  1419.       { MRESULT rc;
  1420.  
  1421.         rc = oldFrameProc(hwnd, msg, mp1, mp2);
  1422.         if (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MINIMIZED) {
  1423.           /* the window is minimized, so ignore this case */
  1424.         } else {
  1425.           PSWP pswp;
  1426.           pswp = (PSWP)PVOIDFROMMP(mp1);
  1427.  
  1428.           if (pswp->fl & SWP_MAXIMIZE) {
  1429.             deltaX = (LONG)min(pswp->cx/Board.cx, pswp->cy/Board.cy);
  1430.             sMaxAdjx = (pswp->cx - Board.cx*(SHORT)deltaX)/2;
  1431.             sMaxAdjy = (pswp->cy - Board.cy*(SHORT)deltaX
  1432.                        - (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR)
  1433.                        - (SHORT)WinQuerySysValue(HWND_DESKTOP, SV_CYMENU))/2;
  1434.             WinPostMsg(hwndBoard, MJ_ADJUST_TILES, NULL, NULL);
  1435.           } else if (pswp->fl & SWP_MINIMIZE) {
  1436.             // ignore this case
  1437.           } else if (pswp->fl & SWP_RESTORE) {
  1438.             deltaX = (LONG)min(pswp->cx/Board.cx, pswp->cy/Board.cy);
  1439.             sMaxAdjx = sMaxAdjy = 0;
  1440.             WinPostMsg(hwndBoard, MJ_ADJUST_TILES, NULL, NULL);
  1441.           } else if ((pswp->fl & SWP_SIZE) &&
  1442.                      !(WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MAXIMIZED)) {
  1443.             LONG    dXold;
  1444.  
  1445.             dXold = deltaX;
  1446.             deltaX = (LONG)min(pswp->cx/Board.cx, pswp->cy/Board.cy);
  1447.             if (dXold != deltaX)
  1448.               WinPostMsg(hwndBoard, MJ_ADJUST_TILES, NULL, NULL);
  1449.           } else {
  1450.           } /* endif */
  1451.         } /* endif */
  1452.         return(rc);
  1453.       } break;
  1454.     case WM_QUERYTRACKINFO:
  1455.       { MRESULT rc;
  1456.         /*┌──────────────────────────────────────────────────────────────────┐*/
  1457.         /*│ Invoke the normal frame-window procedure first in order          │*/
  1458.         /*│ to update the tracking rectangle to the new position.            │*/
  1459.         /*└──────────────────────────────────────────────────────────────────┘*/
  1460.         rc = oldFrameProc(hwnd, msg, mp1, mp2);
  1461.         if (WinQueryWindowULong(hwnd, QWL_STYLE) & WS_MINIMIZED) {
  1462.           // the window is minimized, so ignore this case
  1463.         } else {
  1464.           LONG        dx, dy;
  1465.           PTRACKINFO  ptrack;
  1466.           RECTL       rcl;
  1467.  
  1468.           ptrack = (PTRACKINFO)mp2;
  1469.           /*┌────────────────────────────────────────────────────────────────┐*/
  1470.           /*│ Limit the size of the bounding rectangle only if the           │*/
  1471.           /*│ window is being sized.                                         │*/
  1472.           /*│ fs and rclBoundary are tracking information structure          │*/
  1473.           /*│ elements.                                                      │*/
  1474.           /*└────────────────────────────────────────────────────────────────┘*/
  1475.           if((( ptrack->fs & TF_MOVE  ) != TF_MOVE ) &&
  1476.              (( ptrack->fs & TF_LEFT  ) ||
  1477.               ( ptrack->fs & TF_TOP   ) ||
  1478.               ( ptrack->fs & TF_RIGHT ) ||
  1479.               ( ptrack->fs & TF_BOTTOM ) ||
  1480.               ( ptrack->fs & TF_SETPOINTERPOS ))) {
  1481.             WinQueryWindowRect(hwndBoard, (PRECTL)&rcl);
  1482.             dx = (rcl.xRight - rcl.xLeft)/Board.cx;
  1483.             dy = (rcl.yTop - rcl.yBottom)/Board.cy;
  1484.             deltaX = min(dx, dy);
  1485.             ptrack->rclTrack.yBottom = rcl.yBottom;
  1486.             ptrack->rclTrack.yTop    = rcl.yBottom + deltaX*Board.cy;
  1487.             ptrack->rclTrack.xLeft   = rcl.xLeft;
  1488.             ptrack->rclTrack.xRight  = rcl.xLeft + deltaX*Board.cx;
  1489.             /*┌──────────────────────────────────────────────────────────────┐*/
  1490.             /*│ Convert client boundary coordinates to screen                │*/
  1491.             /*│ coordinates.                                                 │*/
  1492.             /*└──────────────────────────────────────────────────────────────┘*/
  1493.             WinMapWindowPoints(hwndBoard, HWND_DESKTOP,
  1494.                                (PPOINTL)&ptrack->rclTrack, 2);
  1495.             /*┌──────────────────────────────────────────────────────────────┐*/
  1496.             /*│ Calculate equivalent frame boundary from client              │*/
  1497.             /*│ boundary data.                                               │*/
  1498.             /*└──────────────────────────────────────────────────────────────┘*/
  1499.             WinCalcFrameRect(hwnd, (PRECTL)&ptrack->rclTrack, FALSE);
  1500.             ptrack->cxGrid = Board.cx;
  1501.             ptrack->cyGrid = Board.cy;
  1502.             ptrack->fs |= TF_GRID;
  1503.           } /* endif */
  1504.         } /* endif */
  1505.         return((MRESULT)rc);
  1506.       } break;
  1507.  
  1508.     default:
  1509.        /*┌───────────────────────────────────────────────────────────────────┐*/
  1510.        /*│ Return via the normal frame window procedure.                     │*/
  1511.        /*└───────────────────────────────────────────────────────────────────┘*/
  1512.        return(oldFrameProc(hwnd, msg, mp1, mp2));
  1513.        break;
  1514.   } /* endswitch */
  1515.   return((MRESULT)NULL);
  1516. }
  1517.