#include "solitaire.h" #include #include #include #include "resource.h" TCHAR szHelpPath[MAX_PATH]; DWORD dwAppStartTime; HWND hwndMain; HWND hwndStatus; HINSTANCE hInstance; TCHAR szAppName[128]; TCHAR szScore[64]; TCHAR szTime[64]; TCHAR MsgQuit[128]; TCHAR MsgAbout[128]; TCHAR MsgWin[128]; TCHAR MsgDeal[128]; DWORD dwOptions = OPTION_THREE_CARDS; DWORD dwTime; DWORD dwWasteCount; DWORD dwWasteTreshold; DWORD dwPrevMode; long lScore; UINT_PTR PlayTimer = 0; CardWindow SolWnd; typedef struct _CardBack { HWND hSelf; WNDPROC hOldProc; INT hdcNum; INT imgNum; BOOL bSelected; } CARDBACK, *PCARDBACK; LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); void MakePath(TCHAR *szDest, UINT nDestLen, const TCHAR *szExt) { TCHAR *ptr; ptr = szDest + GetModuleFileName(GetModuleHandle(0), szDest, nDestLen) - 1; while(*ptr-- != '.'); lstrcpy(ptr + 1, szExt); } VOID LoadSettings(VOID) { DWORD dwDisposition; DWORD dwSize; DWORD dwBack; HKEY hKey; if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\Solitaire"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hKey, &dwDisposition)) return; dwSize = sizeof(DWORD); RegQueryValueEx(hKey, _T("Options"), NULL, NULL, (LPBYTE)&dwOptions, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx(hKey, _T("Back"), NULL, NULL, (LPBYTE)&dwBack, &dwSize); SolWnd.SetBackCardIdx(dwBack); RegCloseKey(hKey); } VOID SaveSettings(VOID) { DWORD dwDisposition; DWORD dwBack; HKEY hKey; if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\Solitaire"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisposition)) return; RegSetValueEx(hKey, _T("Options"), 0, REG_DWORD, (CONST BYTE *)&dwOptions, sizeof(DWORD)); dwBack = SolWnd.GetBackCardIdx(); RegSetValueEx(hKey, _T("Back"), 0, REG_DWORD, (CONST BYTE *)&dwBack, sizeof(DWORD)); RegCloseKey(hKey); } // Returns 0 for no points, 1 for Standard and 2 for Vegas int GetScoreMode(void) { if ((dwOptions & OPTION_SCORE_STD) && (dwOptions & OPTION_SCORE_VEGAS)) { return SCORE_NONE; } if (dwOptions & OPTION_SCORE_STD) { return SCORE_STD; } if (dwOptions & OPTION_SCORE_VEGAS) { return SCORE_VEGAS; } return 0; } void UpdateStatusBar(void) { TCHAR szStatusText[128]; TCHAR szTempText[64]; ZeroMemory(szStatusText, sizeof(szStatusText)); if (GetScoreMode() != SCORE_NONE) { _stprintf(szStatusText, szScore, lScore); _tcscat(szStatusText, _T(" ")); } if (dwOptions & OPTION_SHOW_TIME) { _stprintf(szTempText, szTime, dwTime); _tcscat(szStatusText, szTempText); } SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)(LPTSTR)szStatusText); } void SetPlayTimer(void) { if (dwOptions & OPTION_SHOW_TIME) { if (!PlayTimer) { PlayTimer = SetTimer(hwndMain, IDT_PLAYTIMER, 1000, NULL); } } } // // Main entry point // int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASS wndclass; INITCOMMONCONTROLSEX ice; HACCEL hAccelTable; hInstance = hInst; // Load application title LoadString(hInst, IDS_SOL_NAME, szAppName, sizeof(szAppName) / sizeof(szAppName[0])); // Load MsgBox() texts here to avoid loading them many times later LoadString(hInst, IDS_SOL_ABOUT, MsgAbout, sizeof(MsgAbout) / sizeof(MsgAbout[0])); LoadString(hInst, IDS_SOL_QUIT, MsgQuit, sizeof(MsgQuit) / sizeof(MsgQuit[0])); LoadString(hInst, IDS_SOL_WIN, MsgWin, sizeof(MsgWin) / sizeof(MsgWin[0])); LoadString(hInst, IDS_SOL_DEAL, MsgDeal, sizeof(MsgDeal) / sizeof(MsgDeal[0])); LoadString(hInst, IDS_SOL_SCORE, szScore, sizeof(szScore) / sizeof(TCHAR)); LoadString(hInst, IDS_SOL_TIME, szTime, sizeof(szTime) / sizeof(TCHAR)); //Window class for the main application parent window wndclass.style = 0;//CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInst; wndclass.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(IDI_SOLITAIRE)); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)NULL; wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); wndclass.lpszClassName = szAppName; RegisterClass(&wndclass); ice.dwSize = sizeof(ice); ice.dwICC = ICC_BAR_CLASSES; InitCommonControlsEx(&ice); srand((unsigned)GetTickCount());//timeGetTime()); // InitCardLib(); LoadSettings(); dwPrevMode = GetScoreMode(); //Construct the path to our help file MakePath(szHelpPath, MAX_PATH, _T(".hlp")); hwnd = CreateWindow(szAppName, // window class name szAppName, // window caption WS_OVERLAPPEDWINDOW ,//|WS_CLIPCHILDREN, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position 0, // The real size will be computed in WndProc through WM_GETMINMAXINFO 0, // The real size will be computed in WndProc through WM_GETMINMAXINFO NULL, // parent window handle NULL, // use window class menu hInst, // program instance handle NULL); // creation parameters if (hwnd == NULL) return 1; hwndMain = hwnd; UpdateStatusBar(); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); while(GetMessage(&msg, NULL,0,0)) { if(!TranslateAccelerator(hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } SaveSettings(); return msg.wParam; } INT_PTR CALLBACK OptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND hCtrl; switch (uMsg) { case WM_INITDIALOG: // For now, the Help dialog item is disabled because of lacking of HTML Help support EnableMenuItem(GetMenu(hDlg), IDM_HELP_CONTENTS, MF_BYCOMMAND | MF_GRAYED); CheckRadioButton(hDlg, IDC_OPT_DRAWONE, IDC_OPT_DRAWTHREE, (dwOptions & OPTION_THREE_CARDS) ? IDC_OPT_DRAWTHREE : IDC_OPT_DRAWONE); CheckDlgButton(hDlg, IDC_OPT_STATUSBAR, (dwOptions & OPTION_SHOW_STATUS) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg, IDC_OPT_SHOWTIME, (dwOptions & OPTION_SHOW_TIME) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg, IDC_OPT_KEEPSCORE, (dwOptions & OPTION_KEEP_SCORE) ? BST_CHECKED : BST_UNCHECKED); hCtrl = GetDlgItem(hDlg, IDC_OPT_KEEPSCORE); if (GetScoreMode() == SCORE_NONE) { CheckRadioButton(hDlg, IDC_OPT_STANDARD, IDC_OPT_NOSCORE, IDC_OPT_NOSCORE); EnableWindow(hCtrl, FALSE); } else if (GetScoreMode() == SCORE_STD) { CheckRadioButton(hDlg, IDC_OPT_STANDARD, IDC_OPT_NOSCORE, IDC_OPT_STANDARD); EnableWindow(hCtrl, FALSE); } else if (GetScoreMode() == SCORE_VEGAS) { CheckRadioButton(hDlg, IDC_OPT_STANDARD, IDC_OPT_NOSCORE, IDC_OPT_VEGAS); EnableWindow(hCtrl, TRUE); } return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_OPT_NOSCORE: case IDC_OPT_STANDARD: case IDC_OPT_VEGAS: hCtrl = GetDlgItem(hDlg, IDC_OPT_KEEPSCORE); if (wParam == IDC_OPT_VEGAS) EnableWindow(hCtrl, TRUE); else EnableWindow(hCtrl, FALSE); return TRUE; case IDOK: dwOptions &= ~OPTION_THREE_CARDS; if (IsDlgButtonChecked(hDlg, IDC_OPT_DRAWTHREE) == BST_CHECKED) dwOptions |= OPTION_THREE_CARDS; if (IsDlgButtonChecked(hDlg, IDC_OPT_STATUSBAR) == BST_CHECKED) dwOptions |= OPTION_SHOW_STATUS; else dwOptions &= ~OPTION_SHOW_STATUS; if (IsDlgButtonChecked(hDlg, IDC_OPT_SHOWTIME) == BST_CHECKED) dwOptions |= OPTION_SHOW_TIME; else dwOptions &= ~OPTION_SHOW_TIME; if (IsDlgButtonChecked(hDlg, IDC_OPT_KEEPSCORE) == BST_CHECKED) dwOptions |= OPTION_KEEP_SCORE; else dwOptions &= ~OPTION_KEEP_SCORE; if (IsDlgButtonChecked(hDlg, IDC_OPT_STANDARD) == BST_CHECKED) { dwOptions |= OPTION_SCORE_STD; dwOptions &= ~OPTION_SCORE_VEGAS; } else if (IsDlgButtonChecked(hDlg, IDC_OPT_VEGAS) == BST_CHECKED) { dwOptions |= OPTION_SCORE_VEGAS; dwOptions &= ~OPTION_SCORE_STD; } else if (IsDlgButtonChecked(hDlg, IDC_OPT_NOSCORE) == BST_CHECKED) { dwOptions |= OPTION_SCORE_VEGAS; dwOptions |= OPTION_SCORE_STD; } UpdateStatusBar(); EndDialog(hDlg, TRUE); return TRUE; case IDCANCEL: EndDialog(hDlg, FALSE); return TRUE; } break; } return FALSE; } VOID ShowGameOptionsDlg(HWND hwnd) { DWORD dwOldOptions = dwOptions; RECT rcMain, rcStatus; int iOldScoreMode = GetScoreMode(); if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_OPTIONS), hwnd, OptionsDlgProc)) { if (((dwOldOptions & OPTION_THREE_CARDS) != (dwOptions & OPTION_THREE_CARDS)) || ((dwOldOptions & OPTION_SHOW_TIME) != (dwOptions & OPTION_SHOW_TIME)) || (iOldScoreMode != GetScoreMode())) NewGame(); if ((dwOldOptions & OPTION_SHOW_STATUS) != (dwOptions & OPTION_SHOW_STATUS)) { int nWidth, nHeight, nStatusHeight; GetClientRect(hwndMain, &rcMain); nHeight = rcMain.bottom - rcMain.top; nWidth = rcMain.right - rcMain.left; if (dwOptions & OPTION_SHOW_STATUS) { RECT rc; ShowWindow(hwndStatus, SW_SHOW); GetWindowRect(hwndStatus, &rcStatus); nStatusHeight = rcStatus.bottom - rcStatus.top; MoveWindow(SolWnd, 0, 0, nWidth, nHeight-nStatusHeight, TRUE); MoveWindow(hwndStatus, 0, nHeight-nStatusHeight, nWidth, nHeight, TRUE); // Force the window to process WM_GETMINMAXINFO again GetWindowRect(hwndMain, &rc); SetWindowPos(hwndMain, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER); } else { ShowWindow(hwndStatus, SW_HIDE); MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE); } } } } LRESULT CALLBACK CardImageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { PCARDBACK pCardBack = (PCARDBACK)GetWindowLongPtr(hwnd, GWLP_USERDATA); static WNDPROC hOldProc = NULL; if (!hOldProc && pCardBack) hOldProc = pCardBack->hOldProc; switch (msg) { case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; HPEN hPen, hOldPen; HBRUSH hBrush, hOldBrush; RECT rc; hdc = BeginPaint(hwnd, &ps); if (pCardBack->bSelected) { hPen = CreatePen(PS_SOLID, 2, RGB(0,0,0)); } else { DWORD Face = GetSysColor(COLOR_3DFACE); hPen = CreatePen(PS_SOLID, 2, Face); } GetClientRect(hwnd, &rc); hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); hOldPen = (HPEN)SelectObject(hdc, hPen); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); Rectangle(hdc, rc.left+1, rc.top+1, rc.right, rc.bottom); StretchBlt(hdc, 2, 2, CARDBACK_OPTIONS_WIDTH, CARDBACK_OPTIONS_HEIGHT, __hdcCardBitmaps, pCardBack->hdcNum * __cardwidth, 0, __cardwidth, __cardheight, SRCCOPY); SelectObject(hdc, hOldPen); SelectObject(hdc, hOldBrush); EndPaint(hwnd, &ps); break; } case WM_LBUTTONDOWN: pCardBack->bSelected = pCardBack->bSelected ? FALSE : TRUE; break; } return CallWindowProc(hOldProc, hwnd, msg, wParam, lParam); } INT_PTR CALLBACK CardBackDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static PCARDBACK pCardBacks = NULL; switch (uMsg) { case WM_INITDIALOG: { INT i, c; SIZE_T size = sizeof(CARDBACK) * NUM_CARDBACKS; pCardBacks = (PCARDBACK)HeapAlloc(GetProcessHeap(), 0, size); for (i = 0, c = CARDBACK_START; c <= CARDBACK_END; i++, c++) { pCardBacks[i].hSelf = GetDlgItem(hDlg, c); pCardBacks[i].bSelected = FALSE; pCardBacks[i].hdcNum = CARDBACK_RES_START + i; pCardBacks[i].imgNum = i + 1; pCardBacks[i].hOldProc = (WNDPROC)SetWindowLongPtr(pCardBacks[i].hSelf, GWLP_WNDPROC, (LONG_PTR)CardImageWndProc); SetWindowLongPtr(pCardBacks[i].hSelf, GWLP_USERDATA, (LONG_PTR)&pCardBacks[i]); } return TRUE; } case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { INT i, num = 0; for (i = 0; i < NUM_CARDBACKS; i++) { if (pCardBacks[i].bSelected) { num = pCardBacks[i].imgNum; } } EndDialog(hDlg, LOWORD(wParam) == IDOK ? num : FALSE); HeapFree(GetProcessHeap(), 0, pCardBacks); return TRUE; } if (HIWORD(wParam) == STN_CLICKED) { INT i; RECT rc; for (i = 0; i < NUM_CARDBACKS; i++) { if (pCardBacks[i].hSelf == (HWND)lParam) { pCardBacks[i].bSelected = TRUE; } else pCardBacks[i].bSelected = FALSE; GetClientRect(pCardBacks[i].hSelf, &rc); InvalidateRect(pCardBacks[i].hSelf, &rc, TRUE); } break; } } return FALSE; } VOID ShowDeckOptionsDlg(HWND hwnd) { INT cardBack; if ((cardBack = DialogBox(hInstance, MAKEINTRESOURCE(IDD_CARDBACK), hwnd, CardBackDlgProc))) { SolWnd.SetBackCardIdx(CARDBACK_RES_START + (cardBack - 1)); SolWnd.Redraw(); } } //----------------------------------------------------------------------------- LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static int nWidth, nHeight, nStatusHeight; switch(iMsg) { case WM_CREATE: { int parts[] = { 150, -1 }; RECT rcStatus; // For now, the Help dialog item is disabled because of lacking of HTML Help support EnableMenuItem(GetMenu(hwnd), IDM_HELP_CONTENTS, MF_BYCOMMAND | MF_GRAYED); hwndStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, _T("Ready"), hwnd, 0); //SendMessage(hwndStatus, SB_SIMPLE, (WPARAM)TRUE, 0); SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); SendMessage(hwndStatus, SB_SETTEXT, 0 | SBT_NOBORDERS, (LPARAM)""); SolWnd.Create(hwnd, 0, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100); CreateSol(); // The status bar height is fixed and needed later in WM_SIZE and WM_GETMINMAXINFO // Force the window to process WM_GETMINMAXINFO again GetWindowRect(hwndStatus, &rcStatus); nStatusHeight = rcStatus.bottom - rcStatus.top; // Hide status bar if options say so if (!(dwOptions & OPTION_SHOW_STATUS)) { ShowWindow(hwndStatus, SW_HIDE); } SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER); NewGame(); dwAppStartTime = GetTickCount(); return 0; } case WM_DESTROY: PostQuitMessage(0); return 0; case WM_TIMER: if (!fGameStarted) { KillTimer(hwndMain, IDT_PLAYTIMER); PlayTimer = 0; } else if (dwOptions & OPTION_SHOW_TIME) { if (((dwTime + 1) % 10 == 0) && (GetScoreMode() == SCORE_STD)) { lScore = lScore >= 2 ? lScore - 2 : 0; } dwTime++; } UpdateStatusBar(); return 0; case WM_SIZE: nWidth = LOWORD(lParam); nHeight = HIWORD(lParam); if (dwOptions & OPTION_SHOW_STATUS) { MoveWindow(SolWnd, 0, 0, nWidth, nHeight - nStatusHeight, TRUE); MoveWindow(hwndStatus, 0, nHeight - nStatusHeight, nWidth, nStatusHeight, TRUE); } else { MoveWindow(SolWnd, 0, 0, nWidth, nHeight, TRUE); } //parts[0] = nWidth - 256; //SendMessage(hwndStatus, SB_SETPARTS, 2, (LPARAM)parts); return 0; case WM_GETMINMAXINFO: { MINMAXINFO *mmi; mmi = (MINMAXINFO *)lParam; mmi->ptMinTrackSize.x = X_BORDER + NUM_ROW_STACKS * (__cardwidth + X_ROWSTACK_BORDER) + X_BORDER; mmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + Y_BORDER + __cardheight + Y_ROWSTACK_BORDER + 6 * yRowStackCardOffset + __cardheight + Y_BORDER + (dwOptions & OPTION_SHOW_STATUS ? nStatusHeight : 0); return 0; } case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_GAME_NEW: //simulate a button click on the new button.. NewGame(); return 0; case IDM_GAME_DECK: ShowDeckOptionsDlg(hwnd); return 0; case IDM_GAME_OPTIONS: ShowGameOptionsDlg(hwnd); return 0; case IDM_HELP_CONTENTS: WinHelp(hwnd, szHelpPath, HELP_CONTENTS, 0);//HELP_KEY, (DWORD)"How to play"); return 0; case IDM_HELP_ABOUT: MessageBox(hwnd, MsgAbout, szAppName, MB_OK|MB_ICONINFORMATION); return 0; case IDM_GAME_EXIT: PostMessage(hwnd, WM_CLOSE, 0, 0); return 0; } return 0; case WM_CLOSE: if (fGameStarted == false) { DestroyWindow(hwnd); return 0; } else { int ret; ret = MessageBox(hwnd, MsgQuit, szAppName, MB_YESNO|MB_ICONQUESTION); if (ret == IDYES) { WinHelp(hwnd, szHelpPath, HELP_QUIT, 0); DestroyWindow(hwnd); } } return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); }