|
|
#include <windows.h>
#include <port1632.h>
#include "cards.h"
#include "cruel.h"
#include "cdt.h"
#include "stdlib.h"
typedef INT X; typedef INT Y; typedef INT DX; typedef INT DY;
// ReCt structure
typedef struct _rc { X xLeft; Y yTop; X xRight; Y yBot; } RC;
#define IDCARDBACK 65
#define ININAME "entpack.ini"
#define APPTITLE "Cruel"
#define HI 0
#define LOW 1
#define SUM 2
#define TOTAL 3
#define WINS 4
#define abs(x) (((x) < 0) ? (-(x)) : (x))
#define NEXT_ROUND 4000
#define INVALID_POS 255
#define MAXUNDOSIZE 100
extern VOID APIENTRY AboutWEP(HWND hwnd, HICON hicon, LPSTR lpTitle, LPSTR lpCredit);
LRESULT APIENTRY WndProc (HWND, UINT, WPARAM, LPARAM) ; VOID Deal(VOID); VOID InitBoard(VOID); VOID DrawLayout(HDC hDC); VOID DrawFoundation(HDC hDC); VOID UpdateDeck(HDC hDC); VOID UpdateLayout(HDC hDC, INT column); VOID DoWinEffects(HDC hDC); BOOL MoveCard(HDC hDC, INT startRow, INT startColumn, INT endRow, INT endColumn, BOOL bValidate); VOID RestoreLayout(HDC hDC); VOID APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam); VOID UndoMove(HDC hDC); INT Message(HWND hWnd, WORD wId, WORD wFlags); VOID MyDrawText(HDC hDC, LPSTR lpBuf, INT w, LPRECT lpRect, WORD wFlags); BOOL CheckGameOver(VOID); INT_PTR CALLBACK BackDlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam); BOOL FDrawFocus(HDC hdc, RC *prc, BOOL fFocus); VOID ChangeBack(WORD wNewDeckBack); VOID DoBacks(VOID); VOID DrawGameOver(VOID); BOOL fDialog(INT id,HWND hwnd,DLGPROC fpfn);
BOOL APIENTRY cdtDrawExt(HDC hdc, INT x, INT y, INT dx, INT dy, INT cd, INT mode, DWORD rgbBgnd); BOOL APIENTRY cdtAnimate(HDC hdc, INT cd, INT x, INT y, INT ispr); VOID DrawAnimate(INT cd, MPOINT *ppt, INT iani); BOOL DeckAnimate(INT iqsec); VOID APIENTRY TimerProc(HWND hwnd, UINT wm, UINT_PTR id, DWORD dwTime); INT_PTR APIENTRY RecordDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam); LRESULT APIENTRY ReadOnlyProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam); VOID MarkControlReadOnly(HWND hwndCtrl, BOOL bReadOnly); VOID ShowStacks(VOID);
VOID SaveState(VOID); VOID RestoreState(VOID); LPSTR lstrtok(LPSTR lpStr, LPSTR lpDelim); static BOOL IsInString(CHAR c, LPSTR s); VOID DisplayStats(VOID);
INT sprintf();
#if 0
INT init[2][6] = { { 49, 33, 13, 46, 10, 47 }, { 39, 31, 19, 44, 28, 8 }}; #endif
typedef struct tagCardRec { INT card; struct tagCardRec *next; } CardRec;
CardRec *FreeList[52]; INT freePos; CardRec deck[52]; CardRec *layout[2][6]; RECT layoutRect[2][6]; INT foundation[4]; RECT foundationRect[4]; INT nCards; LONG nStats[5];
CHAR szAppName[80], szGameOver[80], szGameOverS[80]; CHAR szOOM[256], szRecordTitle[80];
WORD wDeckBack; BOOL bGameInProgress = FALSE;
typedef struct tagUndoRec { INT startRow, startColumn, endRow, endColumn; } UndoRec; UndoRec undo[MAXUNDOSIZE]; INT undoPos;
INT xClient, yClient, xCard, yCard; INT xInc, yInc; DWORD dwBkgnd; WORD wErrorMessages; HWND hWnd; HANDLE hMyInstance;
MMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow) /* { */ MSG msg ; WNDCLASS wndclass ; HANDLE hAccel;
if (!LoadString(hInstance, IDSOOM, szOOM, 256) || !LoadString(hInstance, IDSAppName, szAppName, 80) || !LoadString(hInstance, IDSGameOver, szGameOver, 80) || !LoadString(hInstance, IDSGameOverS, szGameOverS, 80) || !LoadString(hInstance, IDSRecordTitle, szRecordTitle, 80) ) return FALSE;
if (hPrevInstance) { hWnd = FindWindow(szAppName, NULL); if (hWnd) { hWnd = GetLastActivePopup(hWnd); BringWindowToTop(hWnd); if (IsIconic(hWnd)) ShowWindow(hWnd, SW_RESTORE); } return FALSE; }
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (hInstance, szAppName) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = CreateSolidBrush(dwBkgnd = RGB(0,130,0)); wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass)) return FALSE ;
RestoreState();
hWnd = CreateWindow (szAppName, APPTITLE, WS_OVERLAPPEDWINDOW | WS_MAXIMIZE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
if (!hWnd) return FALSE;
hAccel = LoadAccelerators(hInstance, szAppName);
if (!hAccel) return FALSE;
if(SetTimer(hWnd, 666, 250, TimerProc) == 0) { return FALSE; }
ShowWindow (hWnd, SW_SHOWMAXIMIZED) ; UpdateWindow (hWnd) ;
hMyInstance = hInstance; while (GetMessage (&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hWnd, hAccel, &msg)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } } return (INT) msg.wParam ; }
VOID MyDrawText(HDC hDC, LPSTR lpBuf, INT w, LPRECT lpRect, WORD wFlags) { DWORD dwOldBk, dwOldTextColor; HBRUSH hBrush, hOldBrush;
dwOldBk = SetBkColor(hDC, dwBkgnd); dwOldTextColor = SetTextColor(hDC, RGB(255,255,255)); if (hBrush = CreateSolidBrush(dwBkgnd)) { if (hOldBrush = SelectObject(hDC, hBrush)) { PatBlt(hDC, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, PATCOPY); SelectObject(hDC, hOldBrush); } DeleteObject(hBrush); } DrawText(hDC, lpBuf, w, lpRect, wFlags); SetBkColor(hDC, dwOldBk); SetTextColor(hDC, dwOldTextColor); }
VOID APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam) { CHAR szHelpPath[100], *pPath;
pPath = szHelpPath + GetModuleFileName(hMyInstance, szHelpPath, 99); if (pPath != szHelpPath) // if GetModuleFileName succeeded
{ while (*pPath-- != '.') ; ++pPath; *++pPath = 'H'; *++pPath = 'L'; *++pPath = 'P'; *++pPath = '\0';
WinHelp(hWnd, szHelpPath, wCommand, lParam); } }
BOOL CheckGameOver(VOID) { CardRec *pCard; INT colStart, colEnd, rowStart, rowEnd; BOOL bMoveFound; HDC hDC; RECT rect;
/* check to see if there is a card to play */ bMoveFound = FALSE; for (rowStart = 0; rowStart < 2; ++rowStart) for (colStart = 0; colStart < 6; ++colStart) { if (!layout[rowStart][colStart]) continue; for (rowEnd = -1; rowEnd < 2; ++rowEnd) for (colEnd = 0; colEnd < ((rowEnd < 0) ? 4 : 6); ++colEnd) { if (rowEnd == -1 && foundation[colEnd] == wDeckBack) continue;
if (MoveCard(NULL, rowStart, colStart, rowEnd, colEnd, TRUE)) { bMoveFound = TRUE; goto endMoveSearch; } } } endMoveSearch:
/* if a move was found game ain't over! */ if (bMoveFound) return FALSE;
/* count # of cards left */ nCards = 0; for (rowStart = 0; rowStart < 2; ++rowStart) for (colStart = 0; colStart < 6; ++colStart) for (pCard = layout[rowStart][colStart]; pCard; pCard = pCard->next) ++nCards;
/* if no cards then we have a winner! */ if (!nCards) { Message(hWnd, IDSWinner, MB_OK | MB_ICONEXCLAMATION); undoPos = 0; } else DrawGameOver();
if (!nCards) ++nStats[WINS];
if (nCards < nStats[LOW]) nStats[LOW] = nCards;
if (nCards > nStats[HI]) nStats[HI] = nCards;
++nStats[TOTAL]; nStats[SUM] += nCards;
bGameInProgress = FALSE; return TRUE; }
VOID DrawGameOver(VOID) { HDC hDC; CHAR buffer[80]; RECT rect;
wsprintf(buffer, (nCards == 1) ? szGameOverS : szGameOver, nCards); rect.bottom = yClient - 15; rect.top = rect.bottom - 10; rect.left = 0; rect.right = xClient; if (hDC = GetDC(hWnd)) { MyDrawText(hDC, buffer, -1, &rect, DT_CENTER | DT_NOCLIP); ReleaseDC(hWnd, hDC); } }
LRESULT APIENTRY WndProc ( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { HDC hDC ; HMENU hMenu; PAINTSTRUCT ps ; INT i, j ; POINT mpt; MPOINT pt; RECT tmpRect; LONG Area, maxArea; static BOOL fBoard = FALSE; static HWND hWndButton = NULL; INT row, column; static BOOL fTracking = FALSE; static INT startRow, startColumn, endRow, endColumn; static RECT trackRect; static HDC hDCTrack; static HBRUSH hBrush, hOldBrush; static HPEN hOldPen; static MPOINT ptOldPos; FARPROC lpAbout; HANDLE hLib;
switch (iMessage) { case WM_CREATE: cdtInit(&xCard, &yCard); Deal(); startRow = startColumn = endRow = endColumn = INVALID_POS; hBrush = CreateSolidBrush(dwBkgnd); if (!hBrush) return -1L; CheckGameOver(); break;
case WM_SIZE: xClient = LOWORD(lParam); yClient = HIWORD(lParam); break;
case WM_PAINT: hDC = BeginPaint (hWnd, &ps) ; SetBkColor(hDC, dwBkgnd); if (!fBoard) { InitBoard(); if (!hWndButton) hWndButton = CreateWindow("button", "Deal", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 20 + 5 * xInc, 10 + yCard / 4, xCard, yCard / 2, hWnd, (HMENU)NEXT_ROUND, hMyInstance, NULL); fBoard = TRUE; } DrawLayout(hDC); DrawFoundation(hDC);
if (!bGameInProgress) DrawGameOver();
EndPaint(hWnd, &ps); break;
case WM_LBUTTONDBLCLK: pt = MAKEMPOINT(lParam);
for (row = 0; row < 2; ++row) for (column = 0; column < 6; ++column) { MPOINT2POINT(pt, mpt); if (!layout[row][column] || !PtInRect(&layoutRect[row][column], mpt)) continue;
i = CardSuit(layout[row][column]->card); j = CardRank(layout[row][column]->card);
if (CardRank(foundation[i]) == j - 1) { hDC = GetDC(hWnd); if (hDC) { MoveCard(hDC, row, column, -1, i, FALSE); ReleaseDC(hWnd, hDC); } } else { if (wErrorMessages) Message(hWnd, IDSNotNextCard, MB_OK); }
return 0L; } break;
case WM_LBUTTONDOWN: pt = MAKEMPOINT(lParam);
for (row = 0; row < 2; ++row) for (column = 0; column < 6; ++column) { MPOINT2POINT(pt, mpt); if (!layout[row][column] || !PtInRect(&layoutRect[row][column], mpt)) continue;
fTracking = TRUE; startRow = row; startColumn = column; trackRect = layoutRect[row][column]; hDCTrack = GetDC(hWnd); hOldBrush = SelectObject(hDCTrack, GetStockObject(NULL_BRUSH)); hOldPen = SelectObject(hDCTrack, GetStockObject(WHITE_PEN)); SetROP2(hDCTrack, R2_XORPEN); Rectangle(hDCTrack, trackRect.left, trackRect.top, trackRect.right, trackRect.bottom); ptOldPos = pt; SetCapture(hWnd); goto foundSource; } foundSource: break;
case WM_MOUSEMOVE: pt = MAKEMPOINT(lParam);
if (fTracking && !(wParam & MK_LBUTTON)) PostMessage(hWnd, WM_LBUTTONUP, wParam, lParam); else if (!fTracking || ((pt.x == ptOldPos.x) && (pt.y == ptOldPos.y))) break;
Rectangle(hDCTrack, trackRect.left, trackRect.top, trackRect.right, trackRect.bottom); OffsetRect(&trackRect, pt.x - ptOldPos.x, pt.y - ptOldPos.y); ptOldPos = pt; Rectangle(hDCTrack, trackRect.left, trackRect.top, trackRect.right, trackRect.bottom); break;
case WM_LBUTTONUP: if (!fTracking) break;
ReleaseCapture();
endRow = endColumn = INVALID_POS; maxArea = 0; for (row = 0; row < 2; ++row) for (column = 0; column < 6; ++column) { if (!layout[row][column] || !IntersectRect(&tmpRect, &trackRect, &layoutRect[row][column])) continue;
Area = abs((tmpRect.right - tmpRect.left) * (tmpRect.bottom - tmpRect.top));
if (Area > maxArea) { endRow = row; endColumn = column; maxArea = Area; } }
if (maxArea) goto foundTarget;
endRow = -1; for (column = 0; column < 4; ++column) if (IntersectRect(&tmpRect, &trackRect, &foundationRect[column])) {
Area = abs((tmpRect.right - tmpRect.left) * (tmpRect.bottom - tmpRect.top));
if (Area > maxArea) { endColumn = column; maxArea = Area; } } foundTarget: fTracking = FALSE;
Rectangle(hDCTrack, trackRect.left, trackRect.top, trackRect.right, trackRect.bottom); if (startRow != endRow || startColumn != endColumn) { if ((endRow != INVALID_POS) && (endColumn != INVALID_POS)) MoveCard(hDCTrack, startRow, startColumn, endRow, endColumn, FALSE); startRow = startColumn = endRow = endColumn = INVALID_POS; } SelectObject(hDCTrack, hOldBrush); SelectObject(hDCTrack, hOldPen); ReleaseDC(hWnd, hDCTrack); break;
case WM_INITMENU: hMenu = GetMenu(hWnd); EnableMenuItem(hMenu, IDM_OPTIONSUNDO, MF_BYCOMMAND | undoPos ? MF_ENABLED : MF_GRAYED); CheckMenuItem(hMenu, IDM_OPTIONSERROR, wErrorMessages ? MF_CHECKED : MF_UNCHECKED); break;
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_NEWGAME: Deal(); fBoard = FALSE; InvalidateRect(hWnd, NULL, TRUE); CheckGameOver(); break;
case IDM_EXIT: DestroyWindow(hWnd); break;
case IDM_OPTIONSDECK: DoBacks(); break;
case IDM_ABOUT:
hLib = MLoadLibrary("shell32.dll"); if (hLib < (HANDLE)32) break; lpAbout = GetProcAddress(hLib, (LPSTR)"ShellAboutA");
if (lpAbout) { (*lpAbout)(hWnd, (LPSTR) szAppName, (LPSTR)"by Ken Sykes", LoadIcon(hMyInstance, szAppName)); } FreeLibrary(hLib);
break;
case MENU_INDEX: Help(hWnd, HELP_INDEX, 0L); break;
case MENU_HOWTOPLAY: Help(hWnd, HELP_CONTEXT, 1L); break;
case MENU_COMMANDS: Help(hWnd, HELP_CONTEXT, 2L); break;
case MENU_USINGHELP: Help(hWnd, HELP_HELPONHELP, 0L); break;
case IDM_OPTIONSERROR: wErrorMessages = (WORD) ~wErrorMessages; break;
case IDM_OPTIONSUNDO: hDC = GetDC(hWnd); UndoMove(hDC); ReleaseDC(hWnd, hDC); break;
case IDM_GAMERECORD: DisplayStats(); break;
case IDM_DOMINIMIZE: ShowWindow(hWnd, SW_MINIMIZE); break;
case NEXT_ROUND: if (!bGameInProgress) break;
if (!undoPos) { if (wErrorMessages) Message(hWnd, IDSNoCardsMoved, MB_OK); break; }
UnionRect(&tmpRect, &layoutRect[0][0], &layoutRect[1][5]); hDC = GetDC(hWnd); FillRect(hDC, &tmpRect, hBrush); RestoreLayout(hDC); DrawLayout(hDC); ReleaseDC(hWnd, hDC); undoPos = 0; CheckGameOver(); break; } break;
case WM_DESTROY: KillTimer(hWnd, 666); cdtTerm(); Help(hWnd, HELP_QUIT, 0L); DeleteObject(hBrush); SaveState(); PostQuitMessage (0) ; break ;
default: return DefWindowProc (hWnd, iMessage, wParam, lParam) ; } return 0L ; }
VOID Deal(VOID) { INT i, p1, p2; INT row, column; CardRec tmp, *pDeck; cardSuit suit; cardRank rank;
/* stuff cards into deck */ pDeck = deck; for (i = 4; i < 52; ++i) (pDeck++)->card = i;
/* shuffle them around */ srand(LOWORD(GetTickCount())); for (p2 = 0; p2 < 7; ++p2) { for (i = 47; i > 0; --i) { p1 = rand() % i; tmp = deck[p1]; deck[p1] = deck[i]; deck[i] = tmp; } }
/* establish layout links */ pDeck = deck; for (row = 0; row < 2; ++row) for (column = 0; column < 6; ++column) { layout[row][column] = pDeck; for (i = 0; i < 3; ++i, ++pDeck) pDeck->next = pDeck + 1; (pDeck++)->next = NULL; }
/* put aces in foundation */ for (i = 0; i < 4; ++i) foundation[i] = i;
#if 0
{ INT i,j, *p;
for (i = 0; i < 2; ++i) for (j = 0; j < 6; ++j) layout[i][j]->card = init[i][j];
p = (INT *) &init[0][0]; j = *p; for (i = 1; i < 12; ++i) p[i-1] = p[i]; p[11] = j; } #endif
bGameInProgress = TRUE; }
VOID InitBoard(VOID) { INT xPos, yPos; INT row, column, i; RECT *pRect;
/* compute x and y increments */ xInc = (xClient - 40) / 6; yInc = (yClient - 20) / 3;
/* compute foundation rectangles */ yPos = 10; pRect = foundationRect; for (xPos = 20 + xInc, i = 0; i < 4; ++i, xPos += xInc, ++pRect) { pRect->left = xPos; pRect->top = yPos; pRect->right = xPos + xCard; pRect->bottom = yPos + yCard; }
/* compute layout rectangles */ pRect = &layoutRect[0][0]; for (row = 0, yPos = 10 + yInc; row < 2; ++row, yPos += yInc) for (column = 0, xPos = 20; column < 6; ++column, xPos += xInc) { pRect->left = xPos; pRect->top = yPos; pRect->right = xPos + xCard; (pRect++)->bottom = yPos + yCard; }
undoPos = 0; freePos = 0;
}
VOID DrawLayout(HDC hDC) { INT row, column;
for (row = 0; row < 2; ++row) for (column = 0; column < 6; ++column) { if (!layout[row][column]) continue;
cdtDraw(hDC, layoutRect[row][column].left, layoutRect[row][column].top, layout[row][column]->card, faceup, dwBkgnd); } }
VOID DrawFoundation(HDC hDC) { INT i;
for (i = 0; i < 4; ++i) cdtDraw(hDC, foundationRect[i].left, foundationRect[i].top, foundation[i], (foundation[i] == wDeckBack) ? facedown : faceup, dwBkgnd); }
BOOL MoveCard(HDC hDC, INT startRow, INT startColumn, INT endRow, INT endColumn, BOOL bValidate) { CardRec *pStart = layout[startRow][startColumn]; CardRec *pEnd = layout[endRow][endColumn]; INT startCard = pStart->card; INT endCard; cardMode drawmode; BOOL bDone;
if (pEnd == (CardRec*)NULL) /* on NT, this causes exception */ endCard = (endRow < 0) ? foundation[endColumn] : 0; else endCard = (endRow < 0) ? foundation[endColumn] : pEnd->card;
/* make sure suits match */ if (CardSuit(startCard) != CardSuit(endCard)) { if (!bValidate && wErrorMessages) Message(hWnd, IDSWrongSuit, MB_OK); return FALSE; }
/* take action based on where card is moved ... */ if (endRow < 0) { /* card to foundation */
/* card must be one higher than top of foundation */
if (IndexValue(startCard, ACELOW) != IndexValue(endCard, ACELOW) + 1) { if (!bValidate && wErrorMessages) Message(hWnd, IDSNotNextCard, MB_OK); return FALSE; }
if (bValidate) return TRUE;
/* move card to foundation and draw it */ if (CardRank(startCard) == king) { startCard = wDeckBack; drawmode = facedown; } else drawmode = faceup;
foundation[endColumn] = startCard; cdtDraw(hDC, foundationRect[endColumn].left, foundationRect[endColumn].top, startCard, drawmode, dwBkgnd); layout[startRow][startColumn] = pStart->next; FreeList[freePos++] = pStart; } else { /* card to another pile */
/* card must be one lower in rank */ if (IndexValue(startCard, ACELOW) != IndexValue(endCard, ACELOW) - 1) { if (!bValidate && wErrorMessages) Message(hWnd, IDSWrongRank, MB_OK); return FALSE; }
if (bValidate) return TRUE;
/* move card to new pile and display it */ layout[endRow][endColumn] = pStart; layout[startRow][startColumn] = pStart->next; pStart->next = pEnd; cdtDraw(hDC, layoutRect[endRow][endColumn].left, layoutRect[endRow][endColumn].top, startCard, faceup, dwBkgnd); }
/* erase old card and expose new card */ if (layout[startRow][startColumn]) cdtDraw(hDC, layoutRect[startRow][startColumn].left, layoutRect[startRow][startColumn].top, layout[startRow][startColumn]->card, faceup, dwBkgnd); else cdtDraw(hDC, layoutRect[startRow][startColumn].left, layoutRect[startRow][startColumn].top, 0, remove, dwBkgnd);
if (undoPos == MAXUNDOSIZE) { Message(hWnd, IDSUndoFull, MB_OK); undoPos = 0; }
undo[undoPos].startRow = startRow; undo[undoPos].endRow = endRow; undo[undoPos].startColumn = startColumn; undo[undoPos].endColumn = endColumn; ++undoPos;
bDone = TRUE; for (startCard = 0; startCard < 4; ++startCard) if (foundation[startCard] != wDeckBack) { bDone = FALSE; break; }
if (bDone) CheckGameOver();
return TRUE; }
VOID RestoreLayout(HDC hDC) { INT i, j; CardRec *pCurPos, *pList;
/* stage 1: Chain cards together ... */
/* find last non-empty stack */ for (i = 0; i < 12; ++i) if (layout[i / 6][i % 6]) break;
/* start the list here */ pList = pCurPos = layout[i / 6][i % 6];
/* work towards last stack */ for (; i < 11; ++i) { while (pCurPos->next) pCurPos = pCurPos->next; pCurPos->next = layout[(i+1) / 6][(i+1) % 6]; }
/* stage 2: deal them back to layout again ... */ for (i = 0; i < 12; ++i) { layout[i / 6][i % 6] = pList; for (j = 0; j < 3; ++j) if (pList && pList->next) pList = pList->next; else break; if (j != 3) break; else { pCurPos = pList->next; pList->next = NULL; pList = pCurPos; } }
/* rest of stacks are empty */ for (++i; i < 12; ++i) layout[i / 6][i % 6] = NULL; }
VOID UndoMove(HDC hDC) { CHAR buffer[10]; RECT *pRect, rect; INT column, card; HBRUSH hBrush; CardRec *pCard; INT endRow, endColumn, startRow, startColumn;
--undoPos; endRow = undo[undoPos].endRow; startRow = undo[undoPos].startRow; endColumn = undo[undoPos].endColumn; startColumn = undo[undoPos].startColumn;
if (endRow < 0) { /* move card from foundation back to pile */ if (!freePos) { Message(hWnd, IDSIntFreePos, MB_OK | MB_ICONHAND); return; } pCard = FreeList[--freePos];
/* move card to pile */ if (foundation[endColumn] == wDeckBack) foundation[endColumn] = 48 + endColumn; // foundation[endColumn] = CardIndex(endColumn, king);
pCard->card = card = foundation[endColumn]; pCard->next = layout[startRow][startColumn]; layout[startRow][startColumn] = pCard;
/* decrement card on foundation */ foundation[endColumn] -= 4; // foundation[endColumn] = CardIndex(CardSuit(card), CardRank(card)-1);
/* update the foundation */ cdtDraw(hDC, foundationRect[endColumn].left, foundationRect[endColumn].top, foundation[endColumn], faceup, dwBkgnd);
/* update the pile */ cdtDraw(hDC, layoutRect[startRow][startColumn].left, layoutRect[startRow][startColumn].top, pCard->card, faceup, dwBkgnd); } else { /* move card from one pile to the other */ pCard = layout[endRow][endColumn]; layout[endRow][endColumn] = pCard->next;
pCard->next = layout[startRow][startColumn]; layout[startRow][startColumn] = pCard;
/* update pile we moved card back to (start) */ cdtDraw(hDC, layoutRect[startRow][startColumn].left, layoutRect[startRow][startColumn].top, pCard->card, faceup, dwBkgnd);
/* update pile we moved card back from (end), which could be empty
** now. */ if (layout[endRow][endColumn]) cdtDraw(hDC, layoutRect[endRow][endColumn].left, layoutRect[endRow][endColumn].top, layout[endRow][endColumn]->card, faceup, dwBkgnd); else cdtDraw(hDC, layoutRect[endRow][endColumn].left, layoutRect[endRow][endColumn].top, 0, remove, dwBkgnd); } }
INT Message(HWND hWnd, WORD wId, WORD wFlags) { static CHAR szBuf[256];
if (!LoadString(hMyInstance, wId, szBuf, 256) || wId == IDSOOM) { lstrcpy(szBuf, szOOM); wFlags = MB_ICONHAND | MB_SYSTEMMODAL; }
if (!(wFlags & MB_SYSTEMMODAL)) wFlags |= MB_TASKMODAL;
if (!(wFlags & (MB_ICONHAND | MB_ICONEXCLAMATION | MB_ICONINFORMATION))) wFlags |= MB_ICONEXCLAMATION;
return MessageBox(hWnd, szBuf, szAppName, wFlags); }
VOID DoBacks() {
DialogBox(hMyInstance, MAKEINTRESOURCE(1), hWnd, BackDlgProc);
}
INT_PTR CALLBACK BackDlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam) { WORD cmd; static INT modeNew; INT iback; MEASUREITEMSTRUCT FAR *lpmi; DRAWITEMSTRUCT FAR *lpdi; HBRUSH hbr; RC rc, rcCrd; HDC hdc; INT i;
switch(wm) { case WM_INITDIALOG: modeNew = wDeckBack; SetFocus(GetDlgItem(hdlg, modeNew)); return FALSE;
case WM_COMMAND: cmd = GET_WM_COMMAND_ID(wParam, lParam); if(cmd >= IDFACEDOWNFIRST && cmd <= IDFACEDOWN12) { modeNew = cmd; if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_DOUBLECLICKED) { ChangeBack((WORD)modeNew); EndDialog(hdlg, 0); } } else switch(cmd) { case IDOK: ChangeBack((WORD)modeNew); /* fall thru */
case IDCANCEL: EndDialog(hdlg, 0); break;
} break;
case WM_MEASUREITEM: lpmi = (MEASUREITEMSTRUCT FAR *)lParam; lpmi->CtlType = ODT_BUTTON; lpmi->itemWidth = xCard /* 32 */; lpmi->itemHeight = yCard /* 54 */; break; case WM_DRAWITEM: lpdi = (DRAWITEMSTRUCT FAR *)lParam;
CopyRect((LPRECT) &rc, &lpdi->rcItem); rcCrd = rc; InflateRect((LPRECT) &rcCrd, -3, -3); hdc = lpdi->hDC;
if (lpdi->itemAction == ODA_DRAWENTIRE) { cdtDrawExt(hdc, rcCrd.xLeft, rcCrd.yTop, rcCrd.xRight-rcCrd.xLeft, rcCrd.yBot-rcCrd.yTop, lpdi->CtlID, FACEDOWN, 0L); FDrawFocus(hdc, &rc, lpdi->itemState & ODS_FOCUS); break; } if (lpdi->itemAction == ODA_SELECT) InvertRect(hdc, (LPRECT)&rcCrd);
if (lpdi->itemAction == ODA_FOCUS) FDrawFocus(hdc, &rc, lpdi->itemState & ODS_FOCUS);
break; default: return FALSE; } return TRUE; }
BOOL FDrawFocus(HDC hdc, RC *prc, BOOL fFocus) { HBRUSH hbr; RC rc; hbr = CreateSolidBrush(GetSysColor(fFocus ? COLOR_HIGHLIGHT : COLOR_WINDOW)); if(hbr == NULL) return FALSE; rc = *prc; FrameRect(hdc, (LPRECT) &rc, hbr); InflateRect((LPRECT) &rc, -1, -1); FrameRect(hdc, (LPRECT) &rc, hbr); DeleteObject(hbr); return TRUE; }
VOID ChangeBack(WORD wNewDeckBack) { HDC hDC; INT i;
hDC = GetDC(hWnd);
for (i = 0; i < 4; ++i) { if (foundation[i] == wDeckBack) { if (hDC) cdtDraw(hDC, foundationRect[i].left, foundationRect[i].top, wNewDeckBack, facedown, dwBkgnd); foundation[i] = wNewDeckBack; } }
if (hDC) ReleaseDC(hWnd, hDC);
wDeckBack = wNewDeckBack; return; }
VOID DrawAnimate(INT cd, MPOINT *ppt, INT iani) { HDC hDC; INT i;
if(!(hDC = GetDC(hWnd))) return;
for (i = 0; i < 4; ++i) if (foundation[i] == wDeckBack) cdtAnimate(hDC, cd, foundationRect[i].left, foundationRect[i].top, iani);
ReleaseDC(hWnd, hDC); }
BOOL DeckAnimate(INT iqsec) { INT iani; MPOINT pt;
pt.x = pt.y = 0; /* not used! */
switch(wDeckBack) { case IDFACEDOWN3: DrawAnimate(IDFACEDOWN3, &pt, iqsec % 4); break; case IDFACEDOWN10: // krazy kastle
DrawAnimate(IDFACEDOWN10, &pt, iqsec % 2); break;
case IDFACEDOWN11: // sanflipe
if((iani = (iqsec+4) % (50*4)) < 4) DrawAnimate(IDFACEDOWN11, &pt, iani); else // if a menu overlapps an ani while it is ani'ing, leaves deck
// bitmap in inconsistent state...
if(iani % 6 == 0) DrawAnimate(IDFACEDOWN11, &pt, 3); break; case IDFACEDOWN12: // SLIME
if((iani = (iqsec+4) % (15*4)) < 4) DrawAnimate(IDFACEDOWN12, &pt, iani); else // if a menu overlapps an ani while it is ani'ing, leaves deck
// bitmap in inconsistent state...
if(iani % 6 == 0) DrawAnimate(IDFACEDOWN12, &pt, 3); break; }
return TRUE; }
VOID APIENTRY TimerProc(HWND hwnd, UINT wm, UINT_PTR id, DWORD dwTime) { static INT x = 0;
if (bGameInProgress) DeckAnimate(x++); return; }
VOID SaveState(VOID) { CHAR sz[80];
wsprintf(sz, "%ld %ld %ld %ld %ld", nStats[0], nStats[1], nStats[2], nStats[3], nStats[4]); WritePrivateProfileString(szAppName, "Stats", sz, ININAME);
wsprintf(sz, "%d %d", wErrorMessages, wDeckBack); WritePrivateProfileString(szAppName, "MenuState", sz, ININAME); }
VOID DisplayStats(VOID) { CHAR sz[80];
fDialog(2, hWnd, RecordDlgProc); }
VOID RestoreState(VOID) { CHAR sz[80], *psz; INT col; DWORD cchRead;
cchRead = GetPrivateProfileString(szAppName, "Stats", "0 52 0 0 0", sz, sizeof(sz), ININAME);
psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL; col = 0; if (psz) { nStats[0] = atol(psz); for (col = 1; col < 5 && psz; ++col) nStats[col] = atol(psz = lstrtok(NULL, " ")); }
for (; col < 5; ++col) nStats[col] = 0;
cchRead = GetPrivateProfileString(szAppName, "MenuState", "0 65 4", sz, sizeof(sz), ININAME);
psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL; if (psz) { wErrorMessages = (WORD) atoi(psz); psz = lstrtok(NULL, " ");
wDeckBack = IDCARDBACK; if (psz) wDeckBack = (WORD) atoi(psz);
} else { wErrorMessages = 0; wDeckBack = IDCARDBACK; } }
static BOOL IsInString(CHAR c, LPSTR s) { while (*s && *s != c) s = AnsiNext(s);
return *s; }
/* write our own strtok to avoid pulling in entire string library ... */ LPSTR lstrtok(LPSTR lpStr, LPSTR lpDelim) { static LPSTR lpString; LPSTR lpRetVal, lpTemp;
/* if we are passed new string skip leading delimiters */ if(lpStr) { lpString = lpStr;
while (*lpString && IsInString(*lpString, lpDelim)) lpString = AnsiNext(lpString); }
/* if there are no more tokens return NULL */ if(!*lpString) return NULL;
/* save head of token */ lpRetVal = lpString;
/* find delimiter or end of string */ while(*lpString && !IsInString(*lpString, lpDelim)) lpString = AnsiNext(lpString);
/* if we found a delimiter insert string terminator and skip */ if(*lpString) { lpTemp = AnsiNext(lpString); *lpString = '\0'; lpString = lpTemp; }
/* return token */ return(lpRetVal); }
/*----------------------------------------------------------------------------*\
| fDialog(id,hwnd,fpfn) | | | | Description: | | This function displays a dialog box and returns the exit code. | | the function passed will have a proc instance made for it. | | | | Arguments: | | id resource id of dialog to display | | hwnd parent window of dialog | | fpfn dialog message function | | | | Returns: | | exit code of dialog (what was passed to EndDialog) | | | \*----------------------------------------------------------------------------*/ BOOL fDialog(INT id,HWND hwnd,DLGPROC fpfn) { BOOL f; HANDLE hInst;
hInst = (HANDLE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE); fpfn = MakeProcInstance(fpfn,hInst); f = (BOOL) DialogBox(hInst,MAKEINTRESOURCE(id),hwnd,fpfn); FreeProcInstance ((FARPROC)fpfn); return f; }
INT_PTR APIENTRY RecordDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam) { CHAR sz[80]; HWND hwndEdit; INT i;
switch(wm) {
case WM_INITDIALOG: hwndEdit = GetDlgItem(hdlg, IDD_RECORD); SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (szRecordTitle));
wsprintf(sz, "%ld\t%ld\t%ld\t%ld\t%ld", nStats[TOTAL], nStats[WINS], nStats[HI], nStats[LOW], nStats[TOTAL] ? (nStats[SUM] / nStats[TOTAL]) : 0); SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (sz)); MarkControlReadOnly(hwndEdit, TRUE); return TRUE;
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: /* fall thru */
case IDCANCEL: hwndEdit = GetDlgItem(hdlg, IDD_RECORD); MarkControlReadOnly(hwndEdit, FALSE); EndDialog(hdlg, GET_WM_COMMAND_ID(wParam, lParam) == IDOK); break;
case IDD_CLEARSCORES: for (i = 0; i < 5; ++i) nStats[i] = 0; nStats[LOW] = 52; lstrcpy(sz, "0\t0\t0\t52\t0"); hwndEdit = GetDlgItem(hdlg, IDD_RECORD); SendMessage(hwndEdit, LB_DELETESTRING, 1, 0L); SendMessage(hwndEdit, LB_ADDSTRING, 0, (LPARAM) (sz)); break; } break; }
return FALSE; }
static WNDPROC lpOldWP;
VOID MarkControlReadOnly(HWND hwndCtrl, BOOL bReadOnly) { if (bReadOnly) lpOldWP = (WNDPROC) SetWindowLongPtr(hwndCtrl, GWLP_WNDPROC, (LONG_PTR) ReadOnlyProc); else SetWindowLongPtr(hwndCtrl, GWLP_WNDPROC, (LONG_PTR) lpOldWP); }
LRESULT APIENTRY ReadOnlyProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam) { switch (wMessage) { case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: return 0L; }
return CallWindowProc(lpOldWP, hwnd, wMessage, wParam, lParam); }
#if 0
VOID ShowStacks(VOID) { CHAR szBuf[80];
wsprintf(szBuf, "%02d %02d %02d %02d %02d %02d\n%02d %02d %02d %02d %02d %02d", layout[0][0] ? layout[0][0]->card : -1, layout[0][1] ? layout[0][1]->card : -1, layout[0][2] ? layout[0][2]->card : -1, layout[0][3] ? layout[0][3]->card : -1, layout[0][4] ? layout[0][4]->card : -1, layout[0][5] ? layout[0][5]->card : -1, layout[1][0] ? layout[1][0]->card : -1, layout[1][1] ? layout[1][1]->card : -1, layout[1][2] ? layout[1][2]->card : -1, layout[1][3] ? layout[1][3]->card : -1, layout[1][4] ? layout[1][4]->card : -1, layout[1][5] ? layout[1][5]->card : -1);
MessageBox(hWnd, szBuf, "Card Stacks", MB_OK);
wsprintf(szBuf, "%02d %02d %02d %02d %02d %02d\n%02d %02d %02d %02d %02d %02d", layout[0][0] ? IndexValue(layout[0][0]->card, ACELOW) : -1, layout[0][1] ? IndexValue(layout[0][1]->card, ACELOW) : -1, layout[0][2] ? IndexValue(layout[0][2]->card, ACELOW) : -1, layout[0][3] ? IndexValue(layout[0][3]->card, ACELOW) : -1, layout[0][4] ? IndexValue(layout[0][4]->card, ACELOW) : -1, layout[0][5] ? IndexValue(layout[0][5]->card, ACELOW) : -1, layout[1][0] ? IndexValue(layout[1][0]->card, ACELOW) : -1, layout[1][1] ? IndexValue(layout[1][1]->card, ACELOW) : -1, layout[1][2] ? IndexValue(layout[1][2]->card, ACELOW) : -1, layout[1][3] ? IndexValue(layout[1][3]->card, ACELOW) : -1, layout[1][4] ? IndexValue(layout[1][4]->card, ACELOW) : -1, layout[1][5] ? IndexValue(layout[1][5]->card, ACELOW) : -1);
MessageBox(hWnd, szBuf, "IndexValue", MB_OK);
} #endif
|