4 * Copyright 2000 Joshua Thielen <jt85296@ltu.edu>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #define DEBUG(x) fprintf(stderr,x)
37 static const TCHAR szAppName
[] = TEXT("WineMine");
40 int WINAPI
_tWinMain( HINSTANCE hInst
, HINSTANCE hPrevInst
, LPTSTR cmdline
, int cmdshow
)
48 wc
.lpfnWndProc
= MainProc
;
52 wc
.hIcon
= LoadIcon( hInst
, MAKEINTRESOURCE(IDI_WINEMINE
) );
53 wc
.hCursor
= LoadCursor( NULL
, (LPCTSTR
)IDI_APPLICATION
);
54 wc
.hbrBackground
= (HBRUSH
) GetStockObject( LTGRAY_BRUSH
);
55 wc
.lpszMenuName
= MAKEINTRESOURCE(IDM_WINEMINE
);
56 wc
.lpszClassName
= szAppName
;
58 if ( !RegisterClass(&wc
) )
61 hWnd
= CreateWindow( szAppName
, szAppName
,
62 WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
,
63 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
64 NULL
, NULL
, hInst
, NULL
);
69 ShowWindow( hWnd
, cmdshow
);
72 haccel
= LoadAccelerators( hInst
, MAKEINTRESOURCE(IDA_WINEMINE
) );
73 SetTimer( hWnd
, ID_TIMER
, 1000, NULL
);
75 while( GetMessage(&msg
, NULL
, 0, 0) )
77 if ( !TranslateAccelerator(hWnd
, haccel
, &msg
) )
78 TranslateMessage(&msg
);
80 DispatchMessage(&msg
);
86 LRESULT WINAPI
MainProc( HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
93 board
.hInst
= ((LPCREATESTRUCT
) lParam
)->hInstance
;
96 CreateBoard( &board
);
106 hDC
= BeginPaint( hWnd
, &ps
);
107 hMemDC
= CreateCompatibleDC(hDC
);
109 DrawBoard( hDC
, hMemDC
, &ps
, &board
);
112 EndPaint( hWnd
, &ps
);
119 board
.Pos
.x
= (LONG
) LOWORD(lParam
);
120 board
.Pos
.y
= (LONG
) HIWORD(lParam
);
125 DestroyBoard( &board
);
126 PostQuitMessage( 0 );
130 if( board
.Status
== PLAYING
)
133 RedrawWindow( hWnd
, &board
.TimerRect
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
);
138 DEBUG("WM_LBUTTONDOWN\n");
140 if( wParam
& MK_RBUTTON
)
141 msg
= WM_MBUTTONDOWN
;
143 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
148 DEBUG("WM_LBUTTONUP\n");
150 if( wParam
& MK_RBUTTON
)
153 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
158 DEBUG("WM_RBUTTONDOWN\n");
160 if( wParam
& MK_LBUTTON
)
164 msg
= WM_MBUTTONDOWN
;
167 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
171 DEBUG("WM_RBUTTONUP\n");
172 if( wParam
& MK_LBUTTON
)
174 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
178 DEBUG("WM_MBUTTONDOWN\n");
179 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
183 DEBUG("WM_MBUTTONUP\n");
184 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
189 if( (wParam
& MK_LBUTTON
) && (wParam
& MK_RBUTTON
) )
190 msg
= WM_MBUTTONDOWN
;
191 else if( wParam
& MK_LBUTTON
)
192 msg
= WM_LBUTTONDOWN
;
196 TestBoard( hWnd
, &board
, LOWORD(lParam
), HIWORD(lParam
), msg
);
202 switch(LOWORD(wParam
))
205 CreateBoard( &board
);
212 hMenu
= GetMenu( hWnd
);
213 board
.bMark
= !board
.bMark
;
216 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
218 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
224 SetDifficulty( &board
, BEGINNER
);
225 CreateBoard( &board
);
229 SetDifficulty( &board
, ADVANCED
);
230 CreateBoard( &board
);
234 SetDifficulty( &board
, EXPERT
);
235 CreateBoard( &board
);
239 SetDifficulty( &board
, CUSTOM
);
240 CreateBoard( &board
);
244 SendMessage( hWnd
, WM_CLOSE
, 0, 0);
248 DialogBoxParam( board
.hInst
, MAKEINTRESOURCE(IDD_TIMES
), hWnd
, TimesDlgProc
, (LPARAM
) &board
);
253 TCHAR szOtherStuff
[255];
255 LoadString( board
.hInst
, IDS_ABOUT
, szOtherStuff
, sizeof(szOtherStuff
) / sizeof(TCHAR
) );
257 ShellAbout( hWnd
, szAppName
, szOtherStuff
, (HICON
)SendMessage(hWnd
, WM_GETICON
, ICON_BIG
, 0) );
262 DEBUG("Unknown WM_COMMAND command message received\n");
267 return( DefWindowProc( hWnd
, msg
, wParam
, lParam
));
270 void InitBoard( BOARD
*pBoard
)
274 pBoard
->hMinesBMP
= LoadBitmap( pBoard
->hInst
, (LPCTSTR
) IDB_MINES
);
275 pBoard
->hFacesBMP
= LoadBitmap( pBoard
->hInst
, (LPCTSTR
) IDB_FACES
);
276 pBoard
->hLedsBMP
= LoadBitmap( pBoard
->hInst
, (LPCTSTR
) IDB_LEDS
);
280 if( pBoard
->Pos
.x
< GetSystemMetrics( SM_CXFIXEDFRAME
) )
281 pBoard
->Pos
.x
= GetSystemMetrics( SM_CXFIXEDFRAME
);
283 if( pBoard
->Pos
.x
> (GetSystemMetrics( SM_CXSCREEN
) - GetSystemMetrics( SM_CXFIXEDFRAME
)))
285 pBoard
->Pos
.x
= GetSystemMetrics( SM_CXSCREEN
)
286 - GetSystemMetrics( SM_CXFIXEDFRAME
);
289 if( pBoard
->Pos
.y
< (GetSystemMetrics( SM_CYMENU
) + GetSystemMetrics( SM_CYCAPTION
) + GetSystemMetrics( SM_CYFIXEDFRAME
)))
291 pBoard
->Pos
.y
= GetSystemMetrics( SM_CYMENU
) +
292 GetSystemMetrics( SM_CYCAPTION
) +
293 GetSystemMetrics( SM_CYFIXEDFRAME
);
296 if( pBoard
->Pos
.y
> (GetSystemMetrics( SM_CYSCREEN
) - GetSystemMetrics( SM_CYFIXEDFRAME
)))
298 pBoard
->Pos
.y
= GetSystemMetrics( SM_CYSCREEN
)
299 - GetSystemMetrics( SM_CYFIXEDFRAME
);
302 hMenu
= GetMenu( pBoard
->hWnd
);
303 CheckMenuItem( hMenu
, IDM_BEGINNER
+ pBoard
->Difficulty
, MF_CHECKED
);
306 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
308 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
309 CheckLevel( pBoard
);
312 static DWORD
LoadDWord(HKEY hKey
, TCHAR
*szKeyName
, DWORD dwDefaultValue
)
317 dwSize
= sizeof(DWORD
);
319 if( RegQueryValueEx( hKey
, szKeyName
, NULL
, NULL
, (LPBYTE
) &dwValue
, &dwSize
) == ERROR_SUCCESS
)
322 return dwDefaultValue
;
325 void LoadBoard( BOARD
*pBoard
)
334 RegOpenKeyEx( HKEY_CURRENT_USER
, szWineMineRegKey
, 0, KEY_QUERY_VALUE
, &hKey
);
336 pBoard
->Pos
.x
= (LONG
) LoadDWord( hKey
, TEXT("Xpos"), GetSystemMetrics(SM_CXFIXEDFRAME
) );
337 pBoard
->Pos
.y
= (LONG
) LoadDWord( hKey
, TEXT("Ypos"), GetSystemMetrics(SM_CYMENU
) + GetSystemMetrics(SM_CYCAPTION
) + GetSystemMetrics(SM_CYFIXEDFRAME
) );
338 pBoard
->uRows
= (ULONG
) LoadDWord( hKey
, TEXT("Height"), BEGINNER_ROWS
);
339 pBoard
->uCols
= (ULONG
) LoadDWord( hKey
, TEXT("Width"), BEGINNER_COLS
);
340 pBoard
->uMines
= (ULONG
) LoadDWord( hKey
, TEXT("Mines"), BEGINNER_MINES
);
341 pBoard
->Difficulty
= (DIFFICULTY
) LoadDWord( hKey
, TEXT("Difficulty"), BEGINNER
);
342 pBoard
->bMark
= (BOOL
) LoadDWord( hKey
, TEXT("Mark"), TRUE
);
344 LoadString( pBoard
->hInst
, IDS_NOBODY
, szNobody
, sizeof(szNobody
) / sizeof(TCHAR
) );
346 for( i
= 0; i
< 3; i
++ )
348 // As we write to the same registry key as MS WinMine does, we have to start at 1 for the registry keys
349 wsprintf( szKeyName
, TEXT("Name%d"), i
+ 1 );
350 dwSize
= sizeof(szData
);
352 if( RegQueryValueEx( hKey
, szKeyName
, NULL
, NULL
, (LPBYTE
)szData
, (LPDWORD
) &dwSize
) == ERROR_SUCCESS
)
353 _tcsncpy( pBoard
->szBestName
[i
], szData
, sizeof(szData
) / sizeof(TCHAR
) );
355 _tcscpy( pBoard
->szBestName
[i
], szNobody
);
358 for( i
= 0; i
< 3; i
++ )
360 wsprintf( szKeyName
, TEXT("Time%d"), i
+ 1 );
361 pBoard
->uBestTime
[i
] = LoadDWord( hKey
, szKeyName
, 999 );
367 void SaveBoard( BOARD
*pBoard
)
375 if( RegCreateKeyEx( HKEY_CURRENT_USER
, szWineMineRegKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
378 RegSetValueEx( hKey
, TEXT("Xpos"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->Pos
.x
, sizeof(DWORD
) );
379 RegSetValueEx( hKey
, TEXT("Ypos"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->Pos
.y
, sizeof(DWORD
) );
380 RegSetValueEx( hKey
, TEXT("Difficulty"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->Difficulty
, sizeof(DWORD
) );
381 RegSetValueEx( hKey
, TEXT("Height"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->uRows
, sizeof(DWORD
) );
382 RegSetValueEx( hKey
, TEXT("Width"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->uCols
, sizeof(DWORD
) );
383 RegSetValueEx( hKey
, TEXT("Mines"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->uMines
, sizeof(DWORD
) );
384 RegSetValueEx( hKey
, TEXT("Mark"), 0, REG_DWORD
, (LPBYTE
) &pBoard
->bMark
, sizeof(DWORD
) );
386 for( i
= 0; i
< 3; i
++ )
388 // As we write to the same registry key as MS WinMine does, we have to start at 1 for the registry keys
389 wsprintf( szKeyName
, TEXT("Name%u"), i
+ 1);
390 _tcsncpy( szData
, pBoard
->szBestName
[i
], sizeof(szData
) / sizeof(TCHAR
) );
391 RegSetValueEx( hKey
, szKeyName
, 0, REG_SZ
, (LPBYTE
)szData
, (_tcslen(szData
) + 1) * sizeof(TCHAR
) );
394 for( i
= 0; i
< 3; i
++ )
396 wsprintf( szKeyName
, TEXT("Time%u"), i
+ 1);
397 dwValue
= pBoard
->uBestTime
[i
];
398 RegSetValueEx( hKey
, szKeyName
, 0, REG_DWORD
, (LPBYTE
)(LPDWORD
)&dwValue
, sizeof(DWORD
) );
404 void DestroyBoard( BOARD
*pBoard
)
406 DeleteObject( pBoard
->hFacesBMP
);
407 DeleteObject( pBoard
->hLedsBMP
);
408 DeleteObject( pBoard
->hMinesBMP
);
411 void SetDifficulty( BOARD
*pBoard
, DIFFICULTY Difficulty
)
418 pBoard
->uCols
= BEGINNER_COLS
;
419 pBoard
->uRows
= BEGINNER_ROWS
;
420 pBoard
->uMines
= BEGINNER_MINES
;
424 pBoard
->uCols
= ADVANCED_COLS
;
425 pBoard
->uRows
= ADVANCED_ROWS
;
426 pBoard
->uMines
= ADVANCED_MINES
;
430 pBoard
->uCols
= EXPERT_COLS
;
431 pBoard
->uRows
= EXPERT_ROWS
;
432 pBoard
->uMines
= EXPERT_MINES
;
436 if( DialogBoxParam( pBoard
->hInst
, MAKEINTRESOURCE(IDD_CUSTOM
), pBoard
->hWnd
, CustomDlgProc
, (LPARAM
) pBoard
) != IDOK
)
442 hMenu
= GetMenu(pBoard
->hWnd
);
443 CheckMenuItem( hMenu
, IDM_BEGINNER
+ pBoard
->Difficulty
, MF_UNCHECKED
);
444 pBoard
->Difficulty
= Difficulty
;
445 CheckMenuItem( hMenu
, IDM_BEGINNER
+ Difficulty
, MF_CHECKED
);
449 void CreateBoard( BOARD
*pBoard
)
451 ULONG uLeft
, uTop
, uBottom
, uRight
, uWndX
, uWndY
, uWndWidth
, uWndHeight
;
453 pBoard
->uBoxesLeft
= pBoard
->uCols
* pBoard
->uRows
- pBoard
->uMines
;
454 pBoard
->uNumFlags
= 0;
456 CreateBoxes( pBoard
);
458 pBoard
->uWidth
= pBoard
->uCols
* MINE_WIDTH
+ BOARD_WMARGIN
* 2;
460 pBoard
->uHeight
= pBoard
->uRows
* MINE_HEIGHT
+ LED_HEIGHT
463 uWndX
= pBoard
->Pos
.x
- GetSystemMetrics( SM_CXFIXEDFRAME
);
464 uWndY
= pBoard
->Pos
.y
- GetSystemMetrics( SM_CYMENU
)
465 - GetSystemMetrics( SM_CYCAPTION
)
466 - GetSystemMetrics( SM_CYFIXEDFRAME
);
467 uWndWidth
= pBoard
->uWidth
+ GetSystemMetrics( SM_CXFIXEDFRAME
) * 2;
468 uWndHeight
= pBoard
->uHeight
469 + GetSystemMetrics( SM_CYMENU
)
470 + GetSystemMetrics( SM_CYCAPTION
)
471 + GetSystemMetrics( SM_CYFIXEDFRAME
) * 2;
473 /* setting the mines rectangle boundary */
474 uLeft
= BOARD_WMARGIN
;
475 uTop
= BOARD_HMARGIN
* 2 + LED_HEIGHT
;
476 uRight
= uLeft
+ pBoard
->uCols
* MINE_WIDTH
;
477 uBottom
= uTop
+ pBoard
->uRows
* MINE_HEIGHT
;
478 SetRect( &pBoard
->MinesRect
, uLeft
, uTop
, uRight
, uBottom
);
480 /* setting the face rectangle boundary */
481 uLeft
= pBoard
->uWidth
/ 2 - FACE_WIDTH
/ 2;
482 uTop
= BOARD_HMARGIN
;
483 uRight
= uLeft
+ FACE_WIDTH
;
484 uBottom
= uTop
+ FACE_HEIGHT
;
485 SetRect( &pBoard
->FaceRect
, uLeft
, uTop
, uRight
, uBottom
);
487 /* setting the timer rectangle boundary */
488 uLeft
= BOARD_WMARGIN
;
489 uTop
= BOARD_HMARGIN
;
490 uRight
= uLeft
+ LED_WIDTH
* 3;
491 uBottom
= uTop
+ LED_HEIGHT
;
492 SetRect( &pBoard
->CounterRect
, uLeft
, uTop
, uRight
, uBottom
);
494 /* setting the counter rectangle boundary */
495 uLeft
= pBoard
->uWidth
- BOARD_WMARGIN
- LED_WIDTH
* 3;
496 uTop
= BOARD_HMARGIN
;
497 uRight
= pBoard
->uWidth
- BOARD_WMARGIN
;
498 uBottom
= uTop
+ LED_HEIGHT
;
499 SetRect( &pBoard
->TimerRect
, uLeft
, uTop
, uRight
, uBottom
);
501 pBoard
->Status
= WAITING
;
502 pBoard
->FaceBmp
= SMILE_BMP
;
505 MoveWindow( pBoard
->hWnd
, uWndX
, uWndY
, uWndWidth
, uWndHeight
, TRUE
);
506 RedrawWindow( pBoard
->hWnd
, NULL
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ERASE
);
509 void CheckLevel( BOARD
*pBoard
)
511 if( pBoard
->uRows
< BEGINNER_ROWS
)
512 pBoard
->uRows
= BEGINNER_ROWS
;
514 if( pBoard
->uRows
> MAX_ROWS
)
515 pBoard
->uRows
= MAX_ROWS
;
517 if( pBoard
->uCols
< BEGINNER_COLS
)
518 pBoard
->uCols
= BEGINNER_COLS
;
520 if( pBoard
->uCols
> MAX_COLS
)
521 pBoard
->uCols
= MAX_COLS
;
523 if( pBoard
->uMines
< BEGINNER_MINES
)
524 pBoard
->uMines
= BEGINNER_MINES
;
526 if( pBoard
->uMines
> pBoard
->uCols
* pBoard
->uRows
- 1 )
527 pBoard
->uMines
= pBoard
->uCols
* pBoard
->uRows
- 1;
530 void CreateBoxes( BOARD
*pBoard
)
535 srand( (unsigned int)time( NULL
) );
537 /* Create the boxes...
538 * We actually create them with an empty border,
539 * so special care doesn't have to be taken on the edges
542 for( uCol
= 0; uCol
<= pBoard
->uCols
+ 1; uCol
++ )
544 for( uRow
= 0; uRow
<= pBoard
->uRows
+ 1; uRow
++ )
546 pBoard
->Box
[uCol
][uRow
].bIsPressed
= FALSE
;
547 pBoard
->Box
[uCol
][uRow
].bIsMine
= FALSE
;
548 pBoard
->Box
[uCol
][uRow
].uFlagType
= NORMAL
;
549 pBoard
->Box
[uCol
][uRow
].uNumMines
= 0;
555 while( (ULONG
)i
< pBoard
->uMines
)
557 uCol
= (ULONG
)(pBoard
->uCols
* (float)rand() / RAND_MAX
+ 1);
558 uRow
= (ULONG
)(pBoard
->uRows
* (float)rand() / RAND_MAX
+ 1);
560 if( !pBoard
->Box
[uCol
][uRow
].bIsMine
)
563 pBoard
->Box
[uCol
][uRow
].bIsMine
= TRUE
;
568 * Now we label the remaining boxes with the
569 * number of mines surrounding them.
571 for( uCol
= 1; uCol
< pBoard
->uCols
+ 1; uCol
++ )
573 for( uRow
= 1; uRow
< pBoard
->uRows
+ 1; uRow
++ )
575 for( i
= -1; i
<= 1; i
++ )
577 for( j
= -1; j
<= 1; j
++ )
579 if( pBoard
->Box
[uCol
+ i
][uRow
+ j
].bIsMine
)
581 pBoard
->Box
[uCol
][uRow
].uNumMines
++;
589 void DrawMines ( HDC hdc
, HDC hMemDC
, BOARD
*pBoard
)
593 hOldObj
= SelectObject (hMemDC
, pBoard
->hMinesBMP
);
595 for( uRow
= 1; uRow
<= pBoard
->uRows
; uRow
++ )
597 for( uCol
= 1; uCol
<= pBoard
->uCols
; uCol
++ )
599 DrawMine( hdc
, hMemDC
, pBoard
, uCol
, uRow
, FALSE
);
603 SelectObject( hMemDC
, hOldObj
);
606 void DrawMine( HDC hdc
, HDC hMemDC
, BOARD
*pBoard
, ULONG uCol
, ULONG uRow
, BOOL bIsPressed
)
608 MINEBMP_OFFSET offset
= BOX_BMP
;
610 if( uCol
== 0 || uCol
> pBoard
->uCols
|| uRow
== 0 || uRow
> pBoard
->uRows
)
613 if( pBoard
->Status
== GAMEOVER
)
615 if( pBoard
->Box
[uCol
][uRow
].bIsMine
)
617 switch( pBoard
->Box
[uCol
][uRow
].uFlagType
)
623 offset
= EXPLODE_BMP
;
633 switch( pBoard
->Box
[uCol
][uRow
].uFlagType
)
636 offset
= QUESTION_BMP
;
648 DEBUG("Unknown FlagType during game over in DrawMine\n");
654 { /* WAITING or PLAYING */
655 switch( pBoard
->Box
[uCol
][uRow
].uFlagType
)
659 offset
= QUESTION_BMP
;
676 DEBUG("Unknown FlagType while playing in DrawMine\n");
681 if( pBoard
->Box
[uCol
][uRow
].uFlagType
== COMPLETE
&& !pBoard
->Box
[uCol
][uRow
].bIsMine
)
682 offset
= (MINEBMP_OFFSET
) pBoard
->Box
[uCol
][uRow
].uNumMines
;
685 (uCol
- 1) * MINE_WIDTH
+ pBoard
->MinesRect
.left
,
686 (uRow
- 1) * MINE_HEIGHT
+ pBoard
->MinesRect
.top
,
687 MINE_WIDTH
, MINE_HEIGHT
,
688 hMemDC
, 0, offset
* MINE_HEIGHT
, SRCCOPY
);
691 void DrawLeds( HDC hDC
, HDC hMemDC
, BOARD
*pBoard
, LONG nNumber
, LONG x
, LONG y
)
704 uLED
[0] = nCount
/ 100 ;
705 nCount
-= uLED
[0] * 100;
709 uLED
[0] = 10; /* negative sign */
713 uLED
[1] = nCount
/ 10;
714 nCount
-= uLED
[1] * 10;
719 for( i
= 0; i
< 3; i
++ )
723 /* use unlit led if not playing */
724 /* if( pBoard->Status == WAITING )
725 for( i = 0; i < 3; i++ )
728 hOldObj
= SelectObject (hMemDC
, pBoard
->hLedsBMP
);
730 for( i
= 0; i
< 3; i
++ )
739 uLED
[i
] * LED_HEIGHT
,
743 SelectObject( hMemDC
, hOldObj
);
746 void DrawFace( HDC hDC
, HDC hMemDC
, BOARD
*pBoard
)
750 hOldObj
= SelectObject (hMemDC
, pBoard
->hFacesBMP
);
753 pBoard
->FaceRect
.left
,
754 pBoard
->FaceRect
.top
,
757 hMemDC
, 0, pBoard
->FaceBmp
* FACE_HEIGHT
, SRCCOPY
);
759 SelectObject( hMemDC
, hOldObj
);
762 void DrawBoard( HDC hDC
, HDC hMemDC
, PAINTSTRUCT
*ps
, BOARD
*pBoard
)
766 if( IntersectRect( &TempRect
, &ps
->rcPaint
, &pBoard
->CounterRect
) )
767 DrawLeds( hDC
, hMemDC
, pBoard
, pBoard
->uMines
- pBoard
->uNumFlags
,
768 pBoard
->CounterRect
.left
,
769 pBoard
->CounterRect
.top
);
771 if( IntersectRect( &TempRect
, &ps
->rcPaint
, &pBoard
->TimerRect
) )
772 DrawLeds( hDC
, hMemDC
, pBoard
, pBoard
->uTime
,
773 pBoard
->TimerRect
.left
,
774 pBoard
->TimerRect
.top
);
776 if( IntersectRect( &TempRect
, &ps
->rcPaint
, &pBoard
->FaceRect
) )
777 DrawFace( hDC
, hMemDC
, pBoard
);
779 if( IntersectRect( &TempRect
, &ps
->rcPaint
, &pBoard
->MinesRect
) )
780 DrawMines( hDC
, hMemDC
, pBoard
);
784 void TestBoard( HWND hWnd
, BOARD
*pBoard
, LONG x
, LONG y
, int msg
)
792 if( PtInRect( &pBoard
->MinesRect
, pt
) && pBoard
->Status
!= GAMEOVER
&& pBoard
->Status
!= WON
)
793 TestMines( pBoard
, pt
, msg
);
796 UnpressBoxes( pBoard
, pBoard
->Press
.x
, pBoard
->Press
.y
);
801 if( pBoard
->uBoxesLeft
== 0 )
804 // mimic MS minesweeper behaviour - when autocompleting a board, flag mines
805 pBoard
->Status
= WON
;
807 for( uCol
= 0; uCol
<= pBoard
->uCols
+ 1; uCol
++ )
809 for( uRow
= 0; uRow
<= pBoard
->uRows
+ 1; uRow
++ )
811 if(pBoard
->Box
[uCol
][uRow
].bIsMine
)
813 pBoard
->Box
[uCol
][uRow
].uFlagType
= FLAG
;
818 pBoard
->uNumFlags
= pBoard
->uMines
;
819 RedrawWindow( pBoard
->hWnd
, NULL
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
);
821 if( pBoard
->Difficulty
!= CUSTOM
&& pBoard
->uTime
< pBoard
->uBestTime
[pBoard
->Difficulty
] )
823 pBoard
->uBestTime
[pBoard
->Difficulty
] = pBoard
->uTime
;
825 DialogBoxParam( pBoard
->hInst
, MAKEINTRESOURCE(IDD_CONGRATS
), hWnd
, CongratsDlgProc
, (LPARAM
) pBoard
);
826 DialogBoxParam( pBoard
->hInst
, MAKEINTRESOURCE(IDD_TIMES
), hWnd
, TimesDlgProc
, (LPARAM
) pBoard
);
830 TestFace( pBoard
, pt
, msg
);
833 void TestMines( BOARD
*pBoard
, POINT pt
, int msg
)
838 uCol
= (pt
.x
- pBoard
->MinesRect
.left
) / MINE_WIDTH
+ 1;
839 uRow
= (pt
.y
- pBoard
->MinesRect
.top
) / MINE_HEIGHT
+ 1;
844 if( pBoard
->Press
.x
!= uCol
|| pBoard
->Press
.y
!= uRow
)
846 UnpressBox( pBoard
, pBoard
->Press
.x
, pBoard
->Press
.y
);
847 pBoard
->Press
.x
= uCol
;
848 pBoard
->Press
.y
= uRow
;
849 PressBox( pBoard
, uCol
, uRow
);
856 if( pBoard
->Press
.x
!= uCol
|| pBoard
->Press
.y
!= uRow
)
857 UnpressBox( pBoard
, pBoard
->Press
.x
, pBoard
->Press
.y
);
862 if( pBoard
->Box
[uCol
][uRow
].uFlagType
!= FLAG
)
863 pBoard
->Status
= PLAYING
;
865 CompleteBox( pBoard
, uCol
, uRow
);
869 PressBoxes( pBoard
, uCol
, uRow
);
874 if( pBoard
->Press
.x
!= uCol
|| pBoard
->Press
.y
!= uRow
)
875 UnpressBoxes( pBoard
, pBoard
->Press
.x
, pBoard
->Press
.y
);
879 CompleteBoxes( pBoard
, uCol
, uRow
);
883 AddFlag( pBoard
, uCol
, uRow
);
884 pBoard
->Status
= PLAYING
;
888 DEBUG("Unknown message type received in TestMines\n");
893 RedrawWindow( pBoard
->hWnd
, NULL
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
);
896 void TestFace( BOARD
*pBoard
, POINT pt
, int msg
)
898 if( pBoard
->Status
== PLAYING
|| pBoard
->Status
== WAITING
)
900 if( msg
== WM_LBUTTONDOWN
|| msg
== WM_MBUTTONDOWN
)
901 pBoard
->FaceBmp
= OOH_BMP
;
902 else pBoard
->FaceBmp
= SMILE_BMP
;
904 else if( pBoard
->Status
== GAMEOVER
)
905 pBoard
->FaceBmp
= DEAD_BMP
;
906 else if( pBoard
->Status
== WON
)
907 pBoard
->FaceBmp
= COOL_BMP
;
909 if( PtInRect( &pBoard
->FaceRect
, pt
) )
911 if( msg
== WM_LBUTTONDOWN
)
912 pBoard
->FaceBmp
= SPRESS_BMP
;
914 if( msg
== WM_LBUTTONUP
)
915 CreateBoard( pBoard
);
918 RedrawWindow( pBoard
->hWnd
, &pBoard
->FaceRect
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
);
921 void CompleteBox( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
925 if( pBoard
->Box
[uCol
][uRow
].uFlagType
!= COMPLETE
&&
926 pBoard
->Box
[uCol
][uRow
].uFlagType
!= FLAG
&&
927 uCol
> 0 && uCol
< pBoard
->uCols
+ 1 &&
928 uRow
> 0 && uRow
< pBoard
->uRows
+ 1 )
930 pBoard
->Box
[uCol
][uRow
].uFlagType
= COMPLETE
;
932 if( pBoard
->Box
[uCol
][uRow
].bIsMine
)
934 pBoard
->FaceBmp
= DEAD_BMP
;
935 pBoard
->Status
= GAMEOVER
;
937 else if( pBoard
->Status
!= GAMEOVER
)
938 pBoard
->uBoxesLeft
--;
940 if( pBoard
->Box
[uCol
][uRow
].uNumMines
== 0 )
942 for( i
= -1; i
<= 1; i
++ )
943 for( j
= -1; j
<= 1; j
++ )
944 CompleteBox( pBoard
, uCol
+ i
, uRow
+ j
);
949 void CompleteBoxes( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
954 if( pBoard
->Box
[uCol
][uRow
].uFlagType
== COMPLETE
)
956 for( i
= -1; i
<= 1; i
++ )
958 for( j
= -1; j
<= 1; j
++ )
960 if( pBoard
->Box
[uCol
+ i
][uRow
+ j
].uFlagType
== FLAG
)
965 if( uNumFlags
== pBoard
->Box
[uCol
][uRow
].uNumMines
)
967 for( i
= -1; i
<= 1; i
++ )
969 for( j
= -1; j
<= 1; j
++ )
971 if( pBoard
->Box
[uCol
+ i
][uRow
+ j
].uFlagType
!= FLAG
)
972 CompleteBox( pBoard
, uCol
+ i
, uRow
+ j
);
979 void AddFlag( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
981 if( pBoard
->Box
[uCol
][uRow
].uFlagType
!= COMPLETE
)
983 switch( pBoard
->Box
[uCol
][uRow
].uFlagType
)
987 pBoard
->Box
[uCol
][uRow
].uFlagType
= QUESTION
;
989 pBoard
->Box
[uCol
][uRow
].uFlagType
= NORMAL
;
995 pBoard
->Box
[uCol
][uRow
].uFlagType
= NORMAL
;
999 pBoard
->Box
[uCol
][uRow
].uFlagType
= FLAG
;
1000 pBoard
->uNumFlags
++;
1005 void PressBox( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
1011 hDC
= GetDC( pBoard
->hWnd
);
1012 hMemDC
= CreateCompatibleDC(hDC
);
1013 hOldObj
= SelectObject (hMemDC
, pBoard
->hMinesBMP
);
1015 DrawMine( hDC
, hMemDC
, pBoard
, uCol
, uRow
, TRUE
);
1017 SelectObject( hMemDC
, hOldObj
);
1019 ReleaseDC( pBoard
->hWnd
, hDC
);
1022 void PressBoxes( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
1026 for( i
= -1; i
<= 1; i
++ )
1028 for( j
= -1; j
<= 1; j
++ )
1030 pBoard
->Box
[uCol
+ i
][uRow
+ j
].bIsPressed
= TRUE
;
1031 PressBox( pBoard
, uCol
+ i
, uRow
+ j
);
1035 for( i
= -1; i
<= 1; i
++ )
1037 for( j
= -1; j
<= 1; j
++ )
1039 if( !pBoard
->Box
[pBoard
->Press
.x
+ i
][pBoard
->Press
.y
+ j
].bIsPressed
)
1040 UnpressBox( pBoard
, pBoard
->Press
.x
+ i
, pBoard
->Press
.y
+ j
);
1044 for( i
= -1; i
<= 1; i
++ )
1046 for( j
= -1; j
<= 1; j
++ )
1048 pBoard
->Box
[uCol
+ i
][uRow
+ j
].bIsPressed
= FALSE
;
1049 PressBox( pBoard
, uCol
+ i
, uRow
+ j
);
1053 pBoard
->Press
.x
= uCol
;
1054 pBoard
->Press
.y
= uRow
;
1057 void UnpressBox( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
1063 hDC
= GetDC( pBoard
->hWnd
);
1064 hMemDC
= CreateCompatibleDC( hDC
);
1065 hOldObj
= SelectObject( hMemDC
, pBoard
->hMinesBMP
);
1067 DrawMine( hDC
, hMemDC
, pBoard
, uCol
, uRow
, FALSE
);
1069 SelectObject( hMemDC
, hOldObj
);
1071 ReleaseDC( pBoard
->hWnd
, hDC
);
1074 void UnpressBoxes( BOARD
*pBoard
, ULONG uCol
, ULONG uRow
)
1078 for( i
= -1; i
<= 1; i
++ )
1080 for( j
= -1; j
<= 1; j
++ )
1082 UnpressBox( pBoard
, uCol
+ i
, uRow
+ j
);