Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1111 lines
30 KiB

  1. #include <windows.h>
  2. #include <port1632.h>
  3. #include "cards.h"
  4. #include "golf.h"
  5. #include "cdt.h"
  6. #include "stdlib.h"
  7. #define ININAME "entpack.ini"
  8. typedef INT X;
  9. typedef INT Y;
  10. typedef INT DX;
  11. typedef INT DY;
  12. // ReCt structure
  13. typedef struct _rc
  14. {
  15. X xLeft;
  16. Y yTop;
  17. X xRight;
  18. Y yBot;
  19. } RC;
  20. #define abs(x) (((x) < 0) ? (-(x)) : (x))
  21. #define IDCARDBACK 65
  22. #define APPTITLE "Golf"
  23. LRESULT APIENTRY WndProc (HWND, UINT, WPARAM, LPARAM) ;
  24. VOID Deal(VOID);
  25. VOID InitBoard(VOID);
  26. VOID DrawLayout(HDC hDC);
  27. VOID DrawPile(HDC hDC);
  28. VOID UpdateDeck(HDC hDC);
  29. BOOL UpdateLayout(HDC hDC, INT column, BOOL bValidate);
  30. VOID UndoMove(HDC hDC);
  31. VOID DoWinEffects(HDC hDC);
  32. VOID UpdateScore(HDC hDC);
  33. VOID APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam);
  34. INT_PTR APIENTRY BackDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam);
  35. BOOL FDrawFocus(HDC hdc, RC *prc, BOOL fFocus);
  36. VOID ChangeBack(WORD wNewDeckBack);
  37. VOID DoBacks(VOID);
  38. VOID MyDrawText(HDC hDC, LPSTR lpBuf, INT w, LPRECT lpRect, WORD wFlags);
  39. INT Message(HWND hWnd, WORD wId, WORD wFlags);
  40. BOOL fDialog(INT id,HWND hwnd,DLGPROC fpfn);
  41. BOOL APIENTRY cdtDrawExt(HDC hdc, INT x, INT y, INT dx, INT dy, INT cd, INT mode, DWORD rgbBgnd);
  42. BOOL APIENTRY cdtAnimate(HDC hdc, INT cd, INT x, INT y, INT ispr);
  43. VOID DrawAnimate(INT cd, MPOINT *ppt, INT iani);
  44. BOOL DeckAnimate(INT iqsec);
  45. VOID APIENTRY TimerProc(HWND hwnd, UINT wm, UINT_PTR id, DWORD dwTime);
  46. VOID SaveState(VOID);
  47. VOID RestoreState(VOID);
  48. LPSTR lstrtok(LPSTR lpStr, LPSTR lpDelim);
  49. static BOOL IsInString(CHAR c, LPSTR s);
  50. VOID DrawGameOver(HDC hDC);
  51. INT_PTR APIENTRY RecordDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam);
  52. LRESULT APIENTRY ReadOnlyProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam);
  53. VOID MarkControlReadOnly(HWND hwndCtrl, BOOL bReadOnly);
  54. BOOL CheckGameOver(HDC hDC);
  55. INT layout[52], pile[52], col[7];
  56. INT deckStart, deckEnd, pilePos, nCards;
  57. INT xClient, yClient, xCard, yCard;
  58. INT xPileInc, yPileInc;
  59. INT nCardsLeft[7], nWins, nGames;
  60. DWORD dwBkgnd;
  61. RECT deckRect, cntRect, pileRect, colRect[7];
  62. WORD wErrorMessages;
  63. WORD wDeckBack = IDCARDBACK;
  64. FARPROC lpfnTimerProc;
  65. typedef struct tagUndoRec {
  66. enum { Layout, Deck } origin;
  67. INT column;
  68. } UndoRec;
  69. UndoRec undo[52];
  70. INT undoPos;
  71. HWND hWnd;
  72. HANDLE hMyInstance;
  73. CHAR szAppName[80];
  74. CHAR szOOM[256];
  75. CHAR szGameOver[80], szGameOverS[80], szRecordTitle[80];
  76. BOOL bGameInProgress = FALSE;
  77. MMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
  78. /* { */
  79. MSG msg ;
  80. WNDCLASS wndclass ;
  81. HANDLE hAccel;
  82. if (!LoadString(hInstance, IDSOOM, szOOM, 256) ||
  83. !LoadString(hInstance, IDSAppName, szAppName, 80) ||
  84. !LoadString(hInstance, IDSGameOver, szGameOver, 80) ||
  85. !LoadString(hInstance, IDSGameOverS, szGameOverS, 80) ||
  86. !LoadString(hInstance, IDSRecordTitle, szRecordTitle, 80)
  87. )
  88. return FALSE;
  89. if (hPrevInstance) {
  90. hWnd = FindWindow(szAppName, NULL);
  91. if (hWnd)
  92. {
  93. hWnd = GetLastActivePopup(hWnd);
  94. BringWindowToTop(hWnd);
  95. if (IsIconic(hWnd))
  96. ShowWindow(hWnd, SW_RESTORE);
  97. }
  98. return FALSE;
  99. }
  100. wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  101. wndclass.lpfnWndProc = WndProc ;
  102. wndclass.cbClsExtra = 0 ;
  103. wndclass.cbWndExtra = 0 ;
  104. wndclass.hInstance = hInstance ;
  105. wndclass.hIcon = LoadIcon (hInstance, "Golf") ;
  106. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  107. wndclass.hbrBackground = CreateSolidBrush(dwBkgnd = RGB(0,130,0));
  108. wndclass.lpszMenuName = szAppName ;
  109. wndclass.lpszClassName = szAppName ;
  110. if (!RegisterClass (&wndclass))
  111. return FALSE ;
  112. hWnd = CreateWindow (szAppName, APPTITLE,
  113. WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
  114. CW_USEDEFAULT, CW_USEDEFAULT,
  115. CW_USEDEFAULT, CW_USEDEFAULT,
  116. NULL, NULL, hInstance, NULL) ;
  117. if (!hWnd)
  118. return FALSE;
  119. hAccel = LoadAccelerators(hInstance, szAppName);
  120. if (!hAccel)
  121. return FALSE;
  122. if(SetTimer(hWnd, 666, 250, TimerProc) == 0) {
  123. return FALSE;
  124. }
  125. RestoreState();
  126. ShowWindow (hWnd, SW_SHOWMAXIMIZED) ;
  127. UpdateWindow (hWnd) ;
  128. hMyInstance = hInstance;
  129. while (GetMessage (&msg, NULL, 0, 0))
  130. {
  131. if (!TranslateAccelerator(hWnd, hAccel, &msg)) {
  132. TranslateMessage (&msg) ;
  133. DispatchMessage (&msg) ;
  134. }
  135. }
  136. return (INT) msg.wParam ;
  137. }
  138. VOID APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam)
  139. {
  140. CHAR szHelpPath[100], *pPath;
  141. pPath = szHelpPath
  142. + GetModuleFileName(hMyInstance, szHelpPath, 99);
  143. if (pPath != szHelpPath)
  144. {
  145. while (*pPath-- != '.')
  146. ;
  147. ++pPath;
  148. *++pPath = 'H';
  149. *++pPath = 'L';
  150. *++pPath = 'P';
  151. *++pPath = '\0';
  152. WinHelp(hWnd, szHelpPath, wCommand, lParam);
  153. }
  154. }
  155. VOID MyDrawText(HDC hDC, LPSTR lpBuf, INT w, LPRECT lpRect, WORD wFlags)
  156. {
  157. DWORD dwOldBk, dwOldTextColor;
  158. HBRUSH hBrush, hOldBrush;
  159. dwOldBk = SetBkColor(hDC, dwBkgnd);
  160. dwOldTextColor = SetTextColor(hDC, RGB(255,255,255));
  161. if (hBrush = CreateSolidBrush(dwBkgnd)) {
  162. if (hOldBrush = SelectObject(hDC, hBrush)) {
  163. PatBlt(hDC, lpRect->left, lpRect->top, lpRect->right - lpRect->left,
  164. lpRect->bottom - lpRect->top, PATCOPY);
  165. SelectObject(hDC, hOldBrush);
  166. }
  167. DeleteObject(hBrush);
  168. }
  169. DrawText(hDC, lpBuf, w, lpRect, wFlags);
  170. SetBkColor(hDC, dwOldBk);
  171. SetTextColor(hDC, dwOldTextColor);
  172. }
  173. VOID UpdateScore(HDC hDC)
  174. {
  175. CHAR buffer[5];
  176. if (deckEnd - deckStart + 1) {
  177. wsprintf(buffer, "%2d", deckEnd - deckStart + 1);
  178. MyDrawText(hDC, buffer, -1, &cntRect, DT_RIGHT | DT_NOCLIP);
  179. }
  180. }
  181. VOID DisplayWins(VOID)
  182. {
  183. fDialog(2, hWnd, RecordDlgProc);
  184. }
  185. LRESULT APIENTRY WndProc (
  186. HWND hWnd,
  187. UINT iMessage,
  188. WPARAM wParam,
  189. LPARAM lParam)
  190. {
  191. HDC hDC ;
  192. HMENU hMenu;
  193. PAINTSTRUCT ps ;
  194. SHORT i, j ;
  195. MPOINT pt;
  196. POINT mpt;
  197. static BOOL fBoard;
  198. FARPROC lpAbout;
  199. HANDLE hLib;
  200. switch (iMessage)
  201. {
  202. case WM_CREATE:
  203. cdtInit(&xCard, &yCard);
  204. Deal();
  205. fBoard = FALSE;
  206. break;
  207. case WM_SIZE:
  208. xClient = LOWORD(lParam);
  209. yClient = HIWORD(lParam);
  210. break;
  211. case WM_PAINT:
  212. hDC = BeginPaint (hWnd, &ps) ;
  213. if (!fBoard)
  214. {
  215. InitBoard();
  216. fBoard = TRUE;
  217. }
  218. DrawLayout(hDC);
  219. DrawPile(hDC);
  220. EndPaint(hWnd, &ps);
  221. break;
  222. case WM_LBUTTONDOWN:
  223. pt.x = LOWORD(lParam);
  224. pt.y = HIWORD(lParam);
  225. MPOINT2POINT(pt, mpt);
  226. if (PtInRect(&deckRect, mpt))
  227. {
  228. SendMessage(hWnd, WM_KEYDOWN, VK_SPACE, 0L);
  229. break;
  230. }
  231. i = 0;
  232. for (j = 0; j < 7; ++j)
  233. if (PtInRect(colRect + j, mpt))
  234. {
  235. i = (SHORT) (j + 1);
  236. break;
  237. }
  238. if (i)
  239. SendMessage(hWnd, WM_KEYDOWN, '0' + i, 0L);
  240. break;
  241. case WM_INITMENU:
  242. hMenu = GetMenu(hWnd);
  243. EnableMenuItem(hMenu, IDM_OPTIONSUNDO, MF_BYCOMMAND |
  244. undoPos ? MF_ENABLED : MF_GRAYED);
  245. CheckMenuItem(hMenu, IDM_OPTIONSERROR,
  246. wErrorMessages ? MF_CHECKED : MF_UNCHECKED);
  247. break;
  248. case WM_RBUTTONDOWN:
  249. SendMessage(hWnd, WM_KEYDOWN, VK_SPACE, 0L);
  250. break;
  251. case WM_KEYDOWN:
  252. hDC = GetDC(hWnd);
  253. switch (wParam)
  254. {
  255. case VK_ESCAPE:
  256. ShowWindow(hWnd, SW_MINIMIZE);
  257. break;
  258. case VK_SPACE:
  259. UpdateDeck(hDC);
  260. break;
  261. case '1':
  262. case '2':
  263. case '3':
  264. case '4':
  265. case '5':
  266. case '6':
  267. case '7':
  268. UpdateLayout(hDC, (CHAR) wParam - '1', FALSE);
  269. break;
  270. }
  271. ReleaseDC(hWnd, hDC);
  272. break;
  273. case WM_COMMAND:
  274. switch(GET_WM_COMMAND_ID(wParam, lParam))
  275. {
  276. case IDM_NEWGAME:
  277. Deal();
  278. fBoard = FALSE;
  279. InvalidateRect(hWnd, NULL, TRUE);
  280. break;
  281. case IDM_EXIT:
  282. DestroyWindow(hWnd);
  283. break;
  284. case IDM_OPTIONSDECK:
  285. DoBacks();
  286. break;
  287. case IDM_GAMERECORD:
  288. DisplayWins();
  289. break;
  290. case IDM_ABOUT:
  291. hLib = MLoadLibrary("shell32.dll");
  292. if (hLib < (HANDLE)32)
  293. break;
  294. lpAbout = GetProcAddress(hLib, (LPSTR)"ShellAboutA");
  295. if (lpAbout) {
  296. (*lpAbout)(hWnd, szAppName, "by Ken Sykes", LoadIcon(hMyInstance, szAppName));
  297. }
  298. FreeLibrary(hLib);
  299. break;
  300. case MENU_INDEX:
  301. Help(hWnd, HELP_INDEX, 0L);
  302. break;
  303. case MENU_HOWTOPLAY:
  304. Help(hWnd, HELP_CONTEXT, 1L);
  305. break;
  306. case MENU_COMMANDS:
  307. Help(hWnd, HELP_CONTEXT, 2L);
  308. break;
  309. case MENU_USINGHELP:
  310. Help(hWnd, HELP_HELPONHELP, 0L);
  311. break;
  312. case IDM_OPTIONSERROR:
  313. wErrorMessages = (WORD) ~wErrorMessages;
  314. break;
  315. case IDM_OPTIONSUNDO:
  316. hDC = GetDC(hWnd);
  317. UndoMove(hDC);
  318. ReleaseDC(hWnd, hDC);
  319. break;
  320. }
  321. break;
  322. case WM_DESTROY:
  323. KillTimer(hWnd, 666);
  324. FreeProcInstance(lpfnTimerProc);
  325. cdtTerm();
  326. Help(hWnd, HELP_QUIT, 0L);
  327. SaveState();
  328. PostQuitMessage (0) ;
  329. break ;
  330. default:
  331. return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
  332. }
  333. return 0L ;
  334. }
  335. VOID Deal(VOID)
  336. {
  337. INT i, p1, p2, tmp;
  338. /* stuff cards into layout */
  339. for (i = 0; i < 52; ++i)
  340. layout[i] = i;
  341. /* shuffle them around */
  342. srand(LOWORD(GetTickCount()));
  343. for (i = 0; i < 500; ++i)
  344. {
  345. p1 = rand() % 52;
  346. p2 = rand() % 52;
  347. tmp = layout[p1];
  348. layout[p1] = layout[p2];
  349. layout[p2] = tmp;
  350. }
  351. /* initialize column pointers */
  352. for (i = 0; i < 7; ++i)
  353. col[i] = i * 5 + 4;
  354. deckStart = 35;
  355. deckEnd = 51;
  356. pilePos = 0;
  357. /* turn over the first card */
  358. pile[pilePos] = layout[deckEnd--];
  359. nCards = 35;
  360. bGameInProgress = TRUE;
  361. }
  362. VOID InitBoard(VOID)
  363. {
  364. INT xPos, yPos;
  365. INT xStep, yStep, col;
  366. xPos = 30;
  367. yPos = yClient - yCard - 30;
  368. deckRect.left = xPos;
  369. deckRect.right = xPos + xCard;
  370. deckRect.top = yPos;
  371. deckRect.bottom = yPos + yCard;
  372. cntRect.left = xPos;
  373. cntRect.right = cntRect.left + xCard;
  374. cntRect.top = yPos + yCard + 5;
  375. cntRect.bottom = cntRect.top + 20;
  376. xPos += xCard + 20;
  377. pileRect.left = xPos;
  378. pileRect.right = xPos + xCard;
  379. pileRect.top = yPos;
  380. pileRect.bottom = yPos + yCard;
  381. xPileInc = (xClient - 2 * xCard - 50) / 52;
  382. yPileInc = 18;
  383. xStep = xCard + 10;
  384. yStep = yPileInc;
  385. for (col = 0, xPos = 30; col < 7; ++col, xPos += xStep)
  386. {
  387. yPos = 10 + 5 * yStep;
  388. colRect[col].left = xPos;
  389. colRect[col].right = xPos + xCard;
  390. colRect[col].top = yPos - yStep;
  391. colRect[col].bottom = yPos - yStep + yCard;
  392. }
  393. undoPos = 0;
  394. }
  395. VOID DrawLayout(HDC hDC)
  396. {
  397. INT xStep, yStep, column, i, *card;
  398. RECT rect;
  399. xStep = xCard + 10;
  400. yStep = yPileInc;
  401. for (column = 0; column < 7; ++column)
  402. {
  403. /* if column is empty skip it */
  404. if (col[column] < 5 * column)
  405. continue;
  406. /* start rectangle at top of column */
  407. rect = colRect[column];
  408. OffsetRect(&rect, 0, -yStep * (col[column] - 5 * column));
  409. card = layout + 5 * column;
  410. while (rect.top <= colRect[column].top)
  411. {
  412. cdtDraw(hDC, rect.left, rect.top, *card++, faceup, dwBkgnd);
  413. OffsetRect(&rect, 0, yStep);
  414. }
  415. }
  416. }
  417. VOID DrawPile(HDC hDC)
  418. {
  419. INT i, xPos;
  420. if (bGameInProgress)
  421. cdtDraw(hDC, deckRect.left, deckRect.top, wDeckBack, facedown, dwBkgnd);
  422. else
  423. DrawGameOver(hDC);
  424. UpdateScore(hDC);
  425. for (i = 0, xPos = 50 + xCard; i <= pilePos; ++i, xPos += xPileInc)
  426. cdtDraw(hDC, xPos, pileRect.top, pile[i], faceup, dwBkgnd);
  427. }
  428. VOID UpdateDeck(HDC hDC)
  429. {
  430. /* if deck is empty return */
  431. if (deckEnd < deckStart)
  432. return;
  433. /* move card to pile */
  434. pile[++pilePos] = layout[deckEnd--];
  435. /* fill in undo buffer */
  436. undo[undoPos++].origin = Deck;
  437. /* draw new card */
  438. OffsetRect(&pileRect, xPileInc, 0);
  439. cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], faceup, dwBkgnd);
  440. /* update counter */
  441. UpdateScore(hDC);
  442. /* if we turned up last card remove facedown bitmap */
  443. CheckGameOver(hDC);
  444. }
  445. BOOL CheckGameOver(HDC hDC)
  446. {
  447. RECT rect;
  448. INT i;
  449. if (deckEnd >= deckStart)
  450. return FALSE;
  451. SetBkColor(hDC, dwBkgnd);
  452. cdtDraw(hDC, 30, yClient - yCard - 30, 0, remove, dwBkgnd);
  453. rect = cntRect;
  454. MyDrawText(hDC, "", 0, &rect, DT_LEFT | DT_NOCLIP);
  455. for (i = 0; i < 7; ++i)
  456. if (UpdateLayout(hDC, i, TRUE))
  457. return FALSE;
  458. bGameInProgress = FALSE;
  459. DrawGameOver(hDC);
  460. ++nCardsLeft[(nCards - 1) / 5];
  461. ++nGames;
  462. return TRUE;
  463. }
  464. VOID DrawGameOver(HDC hDC)
  465. {
  466. CHAR buffer[30];
  467. RECT rect;
  468. wsprintf(buffer, (nCards == 1) ? szGameOverS : szGameOver, nCards);
  469. rect = cntRect;
  470. rect.left = 0;
  471. rect.right = xClient;
  472. MyDrawText(hDC, buffer, -1, &rect, DT_CENTER | DT_NOCLIP);
  473. }
  474. BOOL UpdateLayout(HDC hDC, INT column, BOOL bValidate)
  475. {
  476. INT colpos, dist;
  477. /* if column is empty, ignore */
  478. colpos = col[column];
  479. if (colpos < 0 || (colpos / 5) != column)
  480. return FALSE;
  481. /* if card on top of pile is a king, don't move card to pile */
  482. if (CardRank(pile[pilePos]) == king)
  483. {
  484. if (wErrorMessages && !bValidate)
  485. Message(hWnd, IDSNoCardOnKing, MB_OK);
  486. return FALSE;
  487. }
  488. /* if card is not adjacent, don't move it to pile */
  489. dist = IndexValue(pile[pilePos], ACELOW)
  490. - IndexValue(layout[colpos], ACELOW);
  491. if (abs(dist) != 1)
  492. {
  493. if (wErrorMessages && !bValidate)
  494. Message(hWnd, IDSNotAdjacent, MB_OK);
  495. return FALSE;
  496. }
  497. if (bValidate)
  498. return TRUE;
  499. /* move card to pile */
  500. pile[++pilePos] = layout[colpos--];
  501. col[column] = colpos;
  502. /* fill in undo buffer */
  503. undo[undoPos].origin = Layout;
  504. undo[undoPos++].column = column;
  505. /* remove card from layout */
  506. SetBkColor(hDC, dwBkgnd);
  507. cdtDraw(hDC, colRect[column].left, colRect[column].top,
  508. pile[pilePos], remove, dwBkgnd);
  509. if (colpos >= 5 * column)
  510. {
  511. OffsetRect(colRect + column, 0, -yPileInc);
  512. cdtDraw(hDC, colRect[column].left, colRect[column].top,
  513. layout[colpos], faceup, dwBkgnd);
  514. }
  515. /* draw card on pile */
  516. OffsetRect(&pileRect, xPileInc, 0);
  517. cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], faceup, dwBkgnd);
  518. /* decrement # of cards */
  519. --nCards;
  520. if (!nCards)
  521. DoWinEffects(hDC);
  522. /* if deck is empty display game over message */
  523. CheckGameOver(hDC);
  524. return TRUE;
  525. }
  526. VOID UndoMove(HDC hDC)
  527. {
  528. CHAR buffer[10];
  529. RECT *pRect, rect;
  530. INT column;
  531. HBRUSH hBrush;
  532. --undoPos;
  533. /* erase the top card on the pile */
  534. SetBkColor(hDC, dwBkgnd);
  535. cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], remove, dwBkgnd);
  536. OffsetRect(&pileRect, -xPileInc, 0);
  537. /* redraw the card that will now be at top of pile */
  538. if (pilePos)
  539. cdtDraw(hDC, pileRect.left, pileRect.top,
  540. pile[pilePos-1], faceup, dwBkgnd);
  541. if (!bGameInProgress)
  542. {
  543. rect = cntRect;
  544. rect.left = rect.right + 1;
  545. rect.right = xClient;
  546. rect.bottom = yClient;
  547. hBrush = CreateSolidBrush(dwBkgnd);
  548. if (hBrush) {
  549. FillRect(hDC, &rect, hBrush);
  550. DeleteObject(hBrush);
  551. }
  552. if (nCards)
  553. --nCardsLeft[(nCards - 1) / 5];
  554. else
  555. --nWins;
  556. --nGames;
  557. bGameInProgress = TRUE;
  558. }
  559. /* move the card back where it belongs */
  560. if (undo[undoPos].origin == Deck)
  561. {
  562. if (deckEnd < deckStart)
  563. cdtDraw(hDC, 30, yClient - yCard - 30, wDeckBack, facedown, dwBkgnd);
  564. layout[++deckEnd] = pile[pilePos--];
  565. UpdateScore(hDC);
  566. }
  567. else
  568. {
  569. column = undo[undoPos].column;
  570. pRect = colRect + column;
  571. if (col[column] >= 5 * column)
  572. OffsetRect(pRect, 0, yPileInc);
  573. cdtDraw(hDC, pRect->left, pRect->top, pile[pilePos], faceup, dwBkgnd);
  574. layout[++col[undo[undoPos].column]] = pile[pilePos--];
  575. ++nCards;
  576. }
  577. }
  578. VOID DoWinEffects(HDC hDC)
  579. {
  580. Message(hWnd, IDSWinner, MB_OK);
  581. ++nWins;
  582. ++nGames;
  583. undoPos = 0;
  584. }
  585. VOID DoBacks()
  586. {
  587. DialogBox(hMyInstance, MAKEINTRESOURCE(1), hWnd, BackDlgProc);
  588. }
  589. INT_PTR APIENTRY BackDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  590. {
  591. static INT modeNew;
  592. INT iback;
  593. MEASUREITEMSTRUCT FAR *lpmi;
  594. DRAWITEMSTRUCT FAR *lpdi;
  595. HBRUSH hbr;
  596. RC rc, rcCrd;
  597. HDC hdc;
  598. INT i;
  599. switch(wm)
  600. {
  601. case WM_INITDIALOG:
  602. modeNew = wDeckBack;
  603. SetFocus(GetDlgItem(hdlg, modeNew));
  604. return FALSE;
  605. case WM_COMMAND:
  606. if(GET_WM_COMMAND_ID(wParam, lParam) >= IDFACEDOWNFIRST &&
  607. GET_WM_COMMAND_ID(wParam, lParam) <= IDFACEDOWN12) {
  608. modeNew = GET_WM_COMMAND_ID(wParam, lParam) ;
  609. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_DOUBLECLICKED) {
  610. ChangeBack((WORD)modeNew);
  611. EndDialog(hdlg, 0);
  612. }
  613. } else
  614. switch(wParam)
  615. {
  616. case IDOK:
  617. ChangeBack((WORD)modeNew);
  618. /* fall thru */
  619. case IDCANCEL:
  620. EndDialog(hdlg, 0);
  621. break;
  622. }
  623. break;
  624. case WM_MEASUREITEM:
  625. lpmi = (MEASUREITEMSTRUCT FAR *)lParam;
  626. lpmi->CtlType = ODT_BUTTON;
  627. lpmi->itemWidth = xCard /* 32 */;
  628. lpmi->itemHeight = yCard /* 54 */;
  629. break;
  630. case WM_DRAWITEM:
  631. lpdi = (DRAWITEMSTRUCT FAR *)lParam;
  632. CopyRect((LPRECT) &rc, &lpdi->rcItem);
  633. rcCrd = rc;
  634. InflateRect((LPRECT) &rcCrd, -3, -3);
  635. hdc = lpdi->hDC;
  636. if (lpdi->itemAction == ODA_DRAWENTIRE)
  637. {
  638. cdtDrawExt(hdc, rcCrd.xLeft, rcCrd.yTop,
  639. rcCrd.xRight-rcCrd.xLeft, rcCrd.yBot-rcCrd.yTop,
  640. lpdi->CtlID, FACEDOWN, 0L);
  641. FDrawFocus(hdc, &rc, lpdi->itemState & ODS_FOCUS);
  642. break;
  643. }
  644. if (lpdi->itemAction == ODA_SELECT)
  645. InvertRect(hdc, (LPRECT)&rcCrd);
  646. if (lpdi->itemAction == ODA_FOCUS)
  647. FDrawFocus(hdc, &rc, lpdi->itemState & ODS_FOCUS);
  648. break;
  649. default:
  650. return FALSE;
  651. }
  652. return TRUE;
  653. }
  654. BOOL FDrawFocus(HDC hdc, RC *prc, BOOL fFocus)
  655. {
  656. HBRUSH hbr;
  657. RC rc;
  658. hbr = CreateSolidBrush(GetSysColor(fFocus ? COLOR_HIGHLIGHT : COLOR_WINDOW));
  659. if(hbr == NULL)
  660. return FALSE;
  661. rc = *prc;
  662. FrameRect(hdc, (LPRECT) &rc, hbr);
  663. InflateRect((LPRECT) &rc, -1, -1);
  664. FrameRect(hdc, (LPRECT) &rc, hbr);
  665. DeleteObject(hbr);
  666. return TRUE;
  667. }
  668. VOID ChangeBack(WORD wNewDeckBack)
  669. {
  670. HDC hDC;
  671. wDeckBack = wNewDeckBack;
  672. if (deckEnd < deckStart)
  673. return;
  674. hDC = GetDC(hWnd);
  675. if (hDC) {
  676. cdtDraw(hDC, deckRect.left, deckRect.top, wDeckBack, facedown, dwBkgnd);
  677. ReleaseDC(hWnd, hDC);
  678. }
  679. }
  680. INT Message(HWND hWnd, WORD wId, WORD wFlags)
  681. {
  682. static CHAR szBuf[256];
  683. if (!LoadString(hMyInstance, wId, szBuf, 256) ||
  684. wId == IDSOOM) {
  685. lstrcpy(szBuf, szOOM);
  686. wFlags = MB_ICONHAND | MB_SYSTEMMODAL;
  687. }
  688. if (!(wFlags & MB_SYSTEMMODAL))
  689. wFlags |= MB_TASKMODAL;
  690. if (!(wFlags & (MB_ICONHAND | MB_ICONEXCLAMATION | MB_ICONINFORMATION)))
  691. wFlags |= MB_ICONEXCLAMATION;
  692. return MessageBox(hWnd, szBuf, szAppName, wFlags);
  693. }
  694. VOID DrawAnimate(INT cd, MPOINT *ppt, INT iani)
  695. {
  696. HDC hDC;
  697. if(!(hDC = GetDC(hWnd)))
  698. return;
  699. cdtAnimate(hDC, cd, ppt->x, ppt->y, iani);
  700. ReleaseDC(hWnd, hDC);
  701. }
  702. BOOL DeckAnimate(INT iqsec)
  703. {
  704. INT iani;
  705. MPOINT pt;
  706. pt.x = (SHORT) deckRect.left;
  707. pt.y = (SHORT) deckRect.top;
  708. switch(wDeckBack) {
  709. case IDFACEDOWN3:
  710. DrawAnimate(IDFACEDOWN3, &pt, iqsec % 4);
  711. break;
  712. case IDFACEDOWN10: // krazy kastle
  713. DrawAnimate(IDFACEDOWN10, &pt, iqsec % 2);
  714. break;
  715. case IDFACEDOWN11: // sanflipe
  716. if((iani = (iqsec+4) % (50*4)) < 4)
  717. DrawAnimate(IDFACEDOWN11, &pt, iani);
  718. else
  719. // if a menu overlapps an ani while it is ani'ing, leaves deck
  720. // bitmap in inconsistent state...
  721. if(iani % 6 == 0)
  722. DrawAnimate(IDFACEDOWN11, &pt, 3);
  723. break;
  724. case IDFACEDOWN12: // SLIME
  725. if((iani = (iqsec+4) % (15*4)) < 4)
  726. DrawAnimate(IDFACEDOWN12, &pt, iani);
  727. else
  728. // if a menu overlapps an ani while it is ani'ing, leaves deck
  729. // bitmap in inconsistent state...
  730. if(iani % 6 == 0)
  731. DrawAnimate(IDFACEDOWN12, &pt, 3);
  732. break;
  733. }
  734. return TRUE;
  735. }
  736. VOID APIENTRY TimerProc(HWND hwnd, UINT wm, UINT_PTR id, DWORD dwTime)
  737. {
  738. static INT x = 0;
  739. if (deckEnd >= deckStart)
  740. DeckAnimate(x++);
  741. return;
  742. }
  743. VOID SaveState(VOID)
  744. {
  745. CHAR sz[80];
  746. wsprintf(sz, "%d %d %d %d %d %d %d %d %d", nGames, nWins, nCardsLeft[0],
  747. nCardsLeft[1], nCardsLeft[2], nCardsLeft[3],
  748. nCardsLeft[4], nCardsLeft[5], nCardsLeft[6]);
  749. WritePrivateProfileString(szAppName, "Stats", sz, ININAME);
  750. wsprintf(sz, "%d %d", wErrorMessages, wDeckBack);
  751. WritePrivateProfileString(szAppName, "MenuState", sz, ININAME);
  752. }
  753. VOID RestoreState(VOID)
  754. {
  755. CHAR sz[80], *psz;
  756. INT col;
  757. DWORD cchRead;
  758. cchRead = GetPrivateProfileString(szAppName, "Stats", "0 0 0 0 0 0 0 0 0", sz,
  759. sizeof(sz), ININAME);
  760. psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL;
  761. if (psz) {
  762. nGames = atoi(psz);
  763. psz = lstrtok(NULL, " ");
  764. nWins = psz ? atoi(psz) : 0;
  765. } else
  766. nGames = nWins = 0;
  767. for (col = 0; col < 7 && psz; ++col)
  768. nCardsLeft[col] = atoi(psz = lstrtok(NULL, " "));
  769. for (; col < 7; ++col)
  770. nCardsLeft[col] = 0;
  771. cchRead = GetPrivateProfileString(szAppName, "MenuState", "0 65", sz,
  772. sizeof(sz), ININAME);
  773. psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL;
  774. if (psz) {
  775. wErrorMessages = (WORD) atoi(psz);
  776. psz = lstrtok(NULL, " ");
  777. wDeckBack = (WORD) IDCARDBACK;
  778. if (psz)
  779. wDeckBack = (WORD) atoi(psz);
  780. } else {
  781. wErrorMessages = 0;
  782. wDeckBack = IDCARDBACK;
  783. }
  784. }
  785. static BOOL IsInString(CHAR c, LPSTR s)
  786. {
  787. while (*s && *s != c)
  788. s = AnsiNext(s);
  789. return *s;
  790. }
  791. /* write our own strtok to avoid pulling in entire string library ... */
  792. LPSTR lstrtok(LPSTR lpStr, LPSTR lpDelim)
  793. {
  794. static LPSTR lpString;
  795. LPSTR lpRetVal, lpTemp;
  796. /* if we are passed new string skip leading delimiters */
  797. if(lpStr) {
  798. lpString = lpStr;
  799. while (*lpString && IsInString(*lpString, lpDelim))
  800. lpString = AnsiNext(lpString);
  801. }
  802. /* if there are no more tokens return NULL */
  803. if(!*lpString)
  804. return NULL;
  805. /* save head of token */
  806. lpRetVal = lpString;
  807. /* find delimiter or end of string */
  808. while(*lpString && !IsInString(*lpString, lpDelim))
  809. lpString = AnsiNext(lpString);
  810. /* if we found a delimiter insert string terminator and skip */
  811. if(*lpString) {
  812. lpTemp = AnsiNext(lpString);
  813. *lpString = '\0';
  814. lpString = lpTemp;
  815. }
  816. /* return token */
  817. return(lpRetVal);
  818. }
  819. /*----------------------------------------------------------------------------*\
  820. | fDialog(id,hwnd,fpfn) |
  821. | |
  822. | Description: |
  823. | This function displays a dialog box and returns the exit code. |
  824. | the function passed will have a proc instance made for it. |
  825. | |
  826. | Arguments: |
  827. | id resource id of dialog to display |
  828. | hwnd parent window of dialog |
  829. | fpfn dialog message function |
  830. | |
  831. | Returns: |
  832. | exit code of dialog (what was passed to EndDialog) |
  833. | |
  834. \*----------------------------------------------------------------------------*/
  835. BOOL fDialog(INT id,HWND hwnd,DLGPROC fpfn)
  836. {
  837. BOOL f;
  838. HANDLE hInst;
  839. hInst = (HANDLE) GetWindowLongPtr(hwnd,GWLP_HINSTANCE);
  840. fpfn = MakeProcInstance(fpfn,hInst);
  841. f = (BOOL) DialogBox(hInst,MAKEINTRESOURCE(id),hwnd, fpfn);
  842. FreeProcInstance (fpfn);
  843. return f;
  844. }
  845. INT_PTR APIENTRY RecordDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  846. {
  847. CHAR sz[80];
  848. HWND hwndEdit;
  849. INT i;
  850. switch(wm) {
  851. case WM_INITDIALOG:
  852. hwndEdit = GetDlgItem(hdlg, IDD_RECORD);
  853. SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (szRecordTitle));
  854. wsprintf(sz, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", nGames, nWins, nCardsLeft[0],
  855. nCardsLeft[1], nCardsLeft[2], nCardsLeft[3],
  856. nCardsLeft[4], nCardsLeft[5], nCardsLeft[6]);
  857. SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (sz));
  858. MarkControlReadOnly(hwndEdit, TRUE);
  859. return TRUE;
  860. case WM_COMMAND:
  861. switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  862. case IDOK:
  863. /* fall thru */
  864. case IDCANCEL:
  865. hwndEdit = GetDlgItem(hdlg, IDD_RECORD);
  866. MarkControlReadOnly(hwndEdit, FALSE);
  867. EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
  868. break;
  869. case IDD_CLEARSCORES:
  870. nGames = nWins = 0;
  871. for (i = 0; i < 7; ++i)
  872. nCardsLeft[i] = 0;
  873. lstrcpy(sz, "0\t0\t0\t0\t0\t0\t0\t0\t0");
  874. hwndEdit = GetDlgItem(hdlg, IDD_RECORD);
  875. SendMessage(hwndEdit, LB_DELETESTRING, 1, 0L);
  876. SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (sz));
  877. break;
  878. }
  879. break;
  880. }
  881. return FALSE;
  882. }
  883. static WNDPROC lpOldWP;
  884. VOID MarkControlReadOnly(HWND hwndCtrl, BOOL bReadOnly)
  885. {
  886. if (bReadOnly)
  887. lpOldWP = (WNDPROC) SetWindowLongPtr(hwndCtrl, GWLP_WNDPROC,
  888. (LONG_PTR) ReadOnlyProc);
  889. else
  890. SetWindowLongPtr(hwndCtrl, GWLP_WNDPROC, (LONG_PTR)lpOldWP);
  891. }
  892. LRESULT APIENTRY ReadOnlyProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
  893. {
  894. switch (wMessage) {
  895. case WM_LBUTTONDOWN:
  896. case WM_RBUTTONDOWN:
  897. case WM_LBUTTONDBLCLK:
  898. case WM_RBUTTONDBLCLK:
  899. return 0L;
  900. }
  901. return CallWindowProc(lpOldWP, hwnd, wMessage, wParam, lParam);
  902. }