windows-nt/Source/XPSP1/NT/shell/osshell/ep/golf/golf.c
2020-09-26 16:20:57 +08:00

1112 lines
30 KiB
C

#include <windows.h>
#include <port1632.h>
#include "cards.h"
#include "golf.h"
#include "cdt.h"
#include "stdlib.h"
#define ININAME "entpack.ini"
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 abs(x) (((x) < 0) ? (-(x)) : (x))
#define IDCARDBACK 65
#define APPTITLE "Golf"
LRESULT APIENTRY WndProc (HWND, UINT, WPARAM, LPARAM) ;
VOID Deal(VOID);
VOID InitBoard(VOID);
VOID DrawLayout(HDC hDC);
VOID DrawPile(HDC hDC);
VOID UpdateDeck(HDC hDC);
BOOL UpdateLayout(HDC hDC, INT column, BOOL bValidate);
VOID UndoMove(HDC hDC);
VOID DoWinEffects(HDC hDC);
VOID UpdateScore(HDC hDC);
VOID APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam);
INT_PTR APIENTRY BackDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam);
BOOL FDrawFocus(HDC hdc, RC *prc, BOOL fFocus);
VOID ChangeBack(WORD wNewDeckBack);
VOID DoBacks(VOID);
VOID MyDrawText(HDC hDC, LPSTR lpBuf, INT w, LPRECT lpRect, WORD wFlags);
INT Message(HWND hWnd, WORD wId, WORD wFlags);
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);
VOID SaveState(VOID);
VOID RestoreState(VOID);
LPSTR lstrtok(LPSTR lpStr, LPSTR lpDelim);
static BOOL IsInString(CHAR c, LPSTR s);
VOID DrawGameOver(HDC hDC);
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);
BOOL CheckGameOver(HDC hDC);
INT layout[52], pile[52], col[7];
INT deckStart, deckEnd, pilePos, nCards;
INT xClient, yClient, xCard, yCard;
INT xPileInc, yPileInc;
INT nCardsLeft[7], nWins, nGames;
DWORD dwBkgnd;
RECT deckRect, cntRect, pileRect, colRect[7];
WORD wErrorMessages;
WORD wDeckBack = IDCARDBACK;
FARPROC lpfnTimerProc;
typedef struct tagUndoRec {
enum { Layout, Deck } origin;
INT column;
} UndoRec;
UndoRec undo[52];
INT undoPos;
HWND hWnd;
HANDLE hMyInstance;
CHAR szAppName[80];
CHAR szOOM[256];
CHAR szGameOver[80], szGameOverS[80], szRecordTitle[80];
BOOL bGameInProgress = FALSE;
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 ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (hInstance, "Golf") ;
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 ;
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;
}
RestoreState();
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 APIENTRY Help(HWND hWnd, UINT wCommand, ULONG_PTR lParam)
{
CHAR szHelpPath[100], *pPath;
pPath = szHelpPath
+ GetModuleFileName(hMyInstance, szHelpPath, 99);
if (pPath != szHelpPath)
{
while (*pPath-- != '.')
;
++pPath;
*++pPath = 'H';
*++pPath = 'L';
*++pPath = 'P';
*++pPath = '\0';
WinHelp(hWnd, szHelpPath, wCommand, lParam);
}
}
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 UpdateScore(HDC hDC)
{
CHAR buffer[5];
if (deckEnd - deckStart + 1) {
wsprintf(buffer, "%2d", deckEnd - deckStart + 1);
MyDrawText(hDC, buffer, -1, &cntRect, DT_RIGHT | DT_NOCLIP);
}
}
VOID DisplayWins(VOID)
{
fDialog(2, hWnd, RecordDlgProc);
}
LRESULT APIENTRY WndProc (
HWND hWnd,
UINT iMessage,
WPARAM wParam,
LPARAM lParam)
{
HDC hDC ;
HMENU hMenu;
PAINTSTRUCT ps ;
SHORT i, j ;
MPOINT pt;
POINT mpt;
static BOOL fBoard;
FARPROC lpAbout;
HANDLE hLib;
switch (iMessage)
{
case WM_CREATE:
cdtInit(&xCard, &yCard);
Deal();
fBoard = FALSE;
break;
case WM_SIZE:
xClient = LOWORD(lParam);
yClient = HIWORD(lParam);
break;
case WM_PAINT:
hDC = BeginPaint (hWnd, &ps) ;
if (!fBoard)
{
InitBoard();
fBoard = TRUE;
}
DrawLayout(hDC);
DrawPile(hDC);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
MPOINT2POINT(pt, mpt);
if (PtInRect(&deckRect, mpt))
{
SendMessage(hWnd, WM_KEYDOWN, VK_SPACE, 0L);
break;
}
i = 0;
for (j = 0; j < 7; ++j)
if (PtInRect(colRect + j, mpt))
{
i = (SHORT) (j + 1);
break;
}
if (i)
SendMessage(hWnd, WM_KEYDOWN, '0' + i, 0L);
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_RBUTTONDOWN:
SendMessage(hWnd, WM_KEYDOWN, VK_SPACE, 0L);
break;
case WM_KEYDOWN:
hDC = GetDC(hWnd);
switch (wParam)
{
case VK_ESCAPE:
ShowWindow(hWnd, SW_MINIMIZE);
break;
case VK_SPACE:
UpdateDeck(hDC);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
UpdateLayout(hDC, (CHAR) wParam - '1', FALSE);
break;
}
ReleaseDC(hWnd, hDC);
break;
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDM_NEWGAME:
Deal();
fBoard = FALSE;
InvalidateRect(hWnd, NULL, TRUE);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_OPTIONSDECK:
DoBacks();
break;
case IDM_GAMERECORD:
DisplayWins();
break;
case IDM_ABOUT:
hLib = MLoadLibrary("shell32.dll");
if (hLib < (HANDLE)32)
break;
lpAbout = GetProcAddress(hLib, (LPSTR)"ShellAboutA");
if (lpAbout) {
(*lpAbout)(hWnd, szAppName, "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;
}
break;
case WM_DESTROY:
KillTimer(hWnd, 666);
FreeProcInstance(lpfnTimerProc);
cdtTerm();
Help(hWnd, HELP_QUIT, 0L);
SaveState();
PostQuitMessage (0) ;
break ;
default:
return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
}
return 0L ;
}
VOID Deal(VOID)
{
INT i, p1, p2, tmp;
/* stuff cards into layout */
for (i = 0; i < 52; ++i)
layout[i] = i;
/* shuffle them around */
srand(LOWORD(GetTickCount()));
for (i = 0; i < 500; ++i)
{
p1 = rand() % 52;
p2 = rand() % 52;
tmp = layout[p1];
layout[p1] = layout[p2];
layout[p2] = tmp;
}
/* initialize column pointers */
for (i = 0; i < 7; ++i)
col[i] = i * 5 + 4;
deckStart = 35;
deckEnd = 51;
pilePos = 0;
/* turn over the first card */
pile[pilePos] = layout[deckEnd--];
nCards = 35;
bGameInProgress = TRUE;
}
VOID InitBoard(VOID)
{
INT xPos, yPos;
INT xStep, yStep, col;
xPos = 30;
yPos = yClient - yCard - 30;
deckRect.left = xPos;
deckRect.right = xPos + xCard;
deckRect.top = yPos;
deckRect.bottom = yPos + yCard;
cntRect.left = xPos;
cntRect.right = cntRect.left + xCard;
cntRect.top = yPos + yCard + 5;
cntRect.bottom = cntRect.top + 20;
xPos += xCard + 20;
pileRect.left = xPos;
pileRect.right = xPos + xCard;
pileRect.top = yPos;
pileRect.bottom = yPos + yCard;
xPileInc = (xClient - 2 * xCard - 50) / 52;
yPileInc = 18;
xStep = xCard + 10;
yStep = yPileInc;
for (col = 0, xPos = 30; col < 7; ++col, xPos += xStep)
{
yPos = 10 + 5 * yStep;
colRect[col].left = xPos;
colRect[col].right = xPos + xCard;
colRect[col].top = yPos - yStep;
colRect[col].bottom = yPos - yStep + yCard;
}
undoPos = 0;
}
VOID DrawLayout(HDC hDC)
{
INT xStep, yStep, column, i, *card;
RECT rect;
xStep = xCard + 10;
yStep = yPileInc;
for (column = 0; column < 7; ++column)
{
/* if column is empty skip it */
if (col[column] < 5 * column)
continue;
/* start rectangle at top of column */
rect = colRect[column];
OffsetRect(&rect, 0, -yStep * (col[column] - 5 * column));
card = layout + 5 * column;
while (rect.top <= colRect[column].top)
{
cdtDraw(hDC, rect.left, rect.top, *card++, faceup, dwBkgnd);
OffsetRect(&rect, 0, yStep);
}
}
}
VOID DrawPile(HDC hDC)
{
INT i, xPos;
if (bGameInProgress)
cdtDraw(hDC, deckRect.left, deckRect.top, wDeckBack, facedown, dwBkgnd);
else
DrawGameOver(hDC);
UpdateScore(hDC);
for (i = 0, xPos = 50 + xCard; i <= pilePos; ++i, xPos += xPileInc)
cdtDraw(hDC, xPos, pileRect.top, pile[i], faceup, dwBkgnd);
}
VOID UpdateDeck(HDC hDC)
{
/* if deck is empty return */
if (deckEnd < deckStart)
return;
/* move card to pile */
pile[++pilePos] = layout[deckEnd--];
/* fill in undo buffer */
undo[undoPos++].origin = Deck;
/* draw new card */
OffsetRect(&pileRect, xPileInc, 0);
cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], faceup, dwBkgnd);
/* update counter */
UpdateScore(hDC);
/* if we turned up last card remove facedown bitmap */
CheckGameOver(hDC);
}
BOOL CheckGameOver(HDC hDC)
{
RECT rect;
INT i;
if (deckEnd >= deckStart)
return FALSE;
SetBkColor(hDC, dwBkgnd);
cdtDraw(hDC, 30, yClient - yCard - 30, 0, remove, dwBkgnd);
rect = cntRect;
MyDrawText(hDC, "", 0, &rect, DT_LEFT | DT_NOCLIP);
for (i = 0; i < 7; ++i)
if (UpdateLayout(hDC, i, TRUE))
return FALSE;
bGameInProgress = FALSE;
DrawGameOver(hDC);
++nCardsLeft[(nCards - 1) / 5];
++nGames;
return TRUE;
}
VOID DrawGameOver(HDC hDC)
{
CHAR buffer[30];
RECT rect;
wsprintf(buffer, (nCards == 1) ? szGameOverS : szGameOver, nCards);
rect = cntRect;
rect.left = 0;
rect.right = xClient;
MyDrawText(hDC, buffer, -1, &rect, DT_CENTER | DT_NOCLIP);
}
BOOL UpdateLayout(HDC hDC, INT column, BOOL bValidate)
{
INT colpos, dist;
/* if column is empty, ignore */
colpos = col[column];
if (colpos < 0 || (colpos / 5) != column)
return FALSE;
/* if card on top of pile is a king, don't move card to pile */
if (CardRank(pile[pilePos]) == king)
{
if (wErrorMessages && !bValidate)
Message(hWnd, IDSNoCardOnKing, MB_OK);
return FALSE;
}
/* if card is not adjacent, don't move it to pile */
dist = IndexValue(pile[pilePos], ACELOW)
- IndexValue(layout[colpos], ACELOW);
if (abs(dist) != 1)
{
if (wErrorMessages && !bValidate)
Message(hWnd, IDSNotAdjacent, MB_OK);
return FALSE;
}
if (bValidate)
return TRUE;
/* move card to pile */
pile[++pilePos] = layout[colpos--];
col[column] = colpos;
/* fill in undo buffer */
undo[undoPos].origin = Layout;
undo[undoPos++].column = column;
/* remove card from layout */
SetBkColor(hDC, dwBkgnd);
cdtDraw(hDC, colRect[column].left, colRect[column].top,
pile[pilePos], remove, dwBkgnd);
if (colpos >= 5 * column)
{
OffsetRect(colRect + column, 0, -yPileInc);
cdtDraw(hDC, colRect[column].left, colRect[column].top,
layout[colpos], faceup, dwBkgnd);
}
/* draw card on pile */
OffsetRect(&pileRect, xPileInc, 0);
cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], faceup, dwBkgnd);
/* decrement # of cards */
--nCards;
if (!nCards)
DoWinEffects(hDC);
/* if deck is empty display game over message */
CheckGameOver(hDC);
return TRUE;
}
VOID UndoMove(HDC hDC)
{
CHAR buffer[10];
RECT *pRect, rect;
INT column;
HBRUSH hBrush;
--undoPos;
/* erase the top card on the pile */
SetBkColor(hDC, dwBkgnd);
cdtDraw(hDC, pileRect.left, pileRect.top, pile[pilePos], remove, dwBkgnd);
OffsetRect(&pileRect, -xPileInc, 0);
/* redraw the card that will now be at top of pile */
if (pilePos)
cdtDraw(hDC, pileRect.left, pileRect.top,
pile[pilePos-1], faceup, dwBkgnd);
if (!bGameInProgress)
{
rect = cntRect;
rect.left = rect.right + 1;
rect.right = xClient;
rect.bottom = yClient;
hBrush = CreateSolidBrush(dwBkgnd);
if (hBrush) {
FillRect(hDC, &rect, hBrush);
DeleteObject(hBrush);
}
if (nCards)
--nCardsLeft[(nCards - 1) / 5];
else
--nWins;
--nGames;
bGameInProgress = TRUE;
}
/* move the card back where it belongs */
if (undo[undoPos].origin == Deck)
{
if (deckEnd < deckStart)
cdtDraw(hDC, 30, yClient - yCard - 30, wDeckBack, facedown, dwBkgnd);
layout[++deckEnd] = pile[pilePos--];
UpdateScore(hDC);
}
else
{
column = undo[undoPos].column;
pRect = colRect + column;
if (col[column] >= 5 * column)
OffsetRect(pRect, 0, yPileInc);
cdtDraw(hDC, pRect->left, pRect->top, pile[pilePos], faceup, dwBkgnd);
layout[++col[undo[undoPos].column]] = pile[pilePos--];
++nCards;
}
}
VOID DoWinEffects(HDC hDC)
{
Message(hWnd, IDSWinner, MB_OK);
++nWins;
++nGames;
undoPos = 0;
}
VOID DoBacks()
{
DialogBox(hMyInstance, MAKEINTRESOURCE(1), hWnd, BackDlgProc);
}
INT_PTR APIENTRY BackDlgProc(HANDLE hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
{
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:
if(GET_WM_COMMAND_ID(wParam, lParam) >= IDFACEDOWNFIRST &&
GET_WM_COMMAND_ID(wParam, lParam) <= IDFACEDOWN12) {
modeNew = GET_WM_COMMAND_ID(wParam, lParam) ;
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_DOUBLECLICKED) {
ChangeBack((WORD)modeNew);
EndDialog(hdlg, 0);
}
} else
switch(wParam)
{
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;
wDeckBack = wNewDeckBack;
if (deckEnd < deckStart)
return;
hDC = GetDC(hWnd);
if (hDC) {
cdtDraw(hDC, deckRect.left, deckRect.top, wDeckBack, facedown, dwBkgnd);
ReleaseDC(hWnd, hDC);
}
}
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 DrawAnimate(INT cd, MPOINT *ppt, INT iani)
{
HDC hDC;
if(!(hDC = GetDC(hWnd)))
return;
cdtAnimate(hDC, cd, ppt->x, ppt->y, iani);
ReleaseDC(hWnd, hDC);
}
BOOL DeckAnimate(INT iqsec)
{
INT iani;
MPOINT pt;
pt.x = (SHORT) deckRect.left;
pt.y = (SHORT) deckRect.top;
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 (deckEnd >= deckStart)
DeckAnimate(x++);
return;
}
VOID SaveState(VOID)
{
CHAR sz[80];
wsprintf(sz, "%d %d %d %d %d %d %d %d %d", nGames, nWins, nCardsLeft[0],
nCardsLeft[1], nCardsLeft[2], nCardsLeft[3],
nCardsLeft[4], nCardsLeft[5], nCardsLeft[6]);
WritePrivateProfileString(szAppName, "Stats", sz, ININAME);
wsprintf(sz, "%d %d", wErrorMessages, wDeckBack);
WritePrivateProfileString(szAppName, "MenuState", sz, ININAME);
}
VOID RestoreState(VOID)
{
CHAR sz[80], *psz;
INT col;
DWORD cchRead;
cchRead = GetPrivateProfileString(szAppName, "Stats", "0 0 0 0 0 0 0 0 0", sz,
sizeof(sz), ININAME);
psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL;
if (psz) {
nGames = atoi(psz);
psz = lstrtok(NULL, " ");
nWins = psz ? atoi(psz) : 0;
} else
nGames = nWins = 0;
for (col = 0; col < 7 && psz; ++col)
nCardsLeft[col] = atoi(psz = lstrtok(NULL, " "));
for (; col < 7; ++col)
nCardsLeft[col] = 0;
cchRead = GetPrivateProfileString(szAppName, "MenuState", "0 65", sz,
sizeof(sz), ININAME);
psz = (cchRead > 0) ? lstrtok(sz, " ") : NULL;
if (psz) {
wErrorMessages = (WORD) atoi(psz);
psz = lstrtok(NULL, " ");
wDeckBack = (WORD) 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 (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, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", nGames, nWins, nCardsLeft[0],
nCardsLeft[1], nCardsLeft[2], nCardsLeft[3],
nCardsLeft[4], nCardsLeft[5], nCardsLeft[6]);
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:
nGames = nWins = 0;
for (i = 0; i < 7; ++i)
nCardsLeft[i] = 0;
lstrcpy(sz, "0\t0\t0\t0\t0\t0\t0\t0\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);
}