4 * Copyright 2000 Joshua Thielen
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_LEAN_AND_MEAN
31 #include <wine/debug.h>
33 WINE_DEFAULT_DEBUG_CHANNEL(winemine
);
35 static const DWORD wnd_style
= WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
;
36 static const char* registry_key
= "Software\\Microsoft\\WinMine";
39 int WINAPI
WinMain( HINSTANCE hInst
, HINSTANCE hPrevInst
, LPSTR cmdline
, int cmdshow
)
47 LoadString( hInst
, IDS_APPNAME
, appname
, sizeof(appname
));
50 wc
.lpfnWndProc
= MainProc
;
54 wc
.hIcon
= LoadIcon( hInst
, "WINEMINE" );
55 wc
.hCursor
= LoadCursor( 0, IDI_APPLICATION
);
56 wc
.hbrBackground
= (HBRUSH
) GetStockObject( BLACK_BRUSH
);
57 wc
.lpszMenuName
= "MENU_WINEMINE";
58 wc
.lpszClassName
= appname
;
60 if (!RegisterClass(&wc
)) ExitProcess(1);
61 hWnd
= CreateWindow( appname
, appname
,
63 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
66 if (!hWnd
) ExitProcess(1);
68 ShowWindow( hWnd
, cmdshow
);
71 haccel
= LoadAccelerators( hInst
, MAKEINTRESOURCE(IDA_WINEMINE
) );
72 SetTimer( hWnd
, ID_TIMER
, 1000, NULL
);
74 while( GetMessage(&msg
, 0, 0, 0) ) {
75 if (!TranslateAccelerator( hWnd
, haccel
, &msg
))
76 TranslateMessage( &msg
);
78 DispatchMessage( &msg
);
83 LRESULT WINAPI
MainProc( HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
92 board
.hInst
= ((LPCREATESTRUCT
) lParam
)->hInstance
;
95 CreateBoard( &board
);
102 WINE_TRACE("WM_PAINT\n");
103 hdc
= BeginPaint( hWnd
, &ps
);
104 hMemDC
= CreateCompatibleDC( hdc
);
106 DrawBoard( hdc
, hMemDC
, &ps
, &board
);
109 EndPaint( hWnd
, &ps
);
115 WINE_TRACE("WM_MOVE\n");
116 board
.pos
.x
= (short)LOWORD(lParam
);
117 board
.pos
.y
= (short)HIWORD(lParam
);
122 DestroyBoard( &board
);
123 PostQuitMessage( 0 );
127 if( board
.status
== PLAYING
) {
129 RedrawWindow( hWnd
, &board
.timer_rect
, 0,
130 RDW_INVALIDATE
| RDW_UPDATENOW
);
135 WINE_TRACE("WM_LBUTTONDOWN\n");
136 if( wParam
& MK_RBUTTON
)
137 msg
= WM_MBUTTONDOWN
;
138 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
143 WINE_TRACE("WM_LBUTTONUP\n");
144 if( wParam
& MK_RBUTTON
)
146 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
151 WINE_TRACE("WM_RBUTTONDOWN\n");
152 if( wParam
& MK_LBUTTON
) {
155 msg
= WM_MBUTTONDOWN
;
157 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
161 WINE_TRACE("WM_RBUTTONUP\n");
162 if( wParam
& MK_LBUTTON
)
164 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
168 WINE_TRACE("WM_MBUTTONDOWN\n");
169 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
173 WINE_TRACE("WM_MBUTTONUP\n");
174 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
179 if( wParam
& MK_MBUTTON
) {
180 msg
= WM_MBUTTONDOWN
;
182 else if( wParam
& MK_LBUTTON
) {
183 msg
= WM_LBUTTONDOWN
;
189 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
195 switch(LOWORD(wParam
)) {
197 CreateBoard( &board
);
201 hMenu
= GetMenu( hWnd
);
202 board
.IsMarkQ
= !board
.IsMarkQ
;
204 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
206 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
210 SetDifficulty( &board
, BEGINNER
);
211 CreateBoard( &board
);
215 SetDifficulty( &board
, ADVANCED
);
216 CreateBoard( &board
);
220 SetDifficulty( &board
, EXPERT
);
221 CreateBoard( &board
);
225 SetDifficulty( &board
, CUSTOM
);
226 CreateBoard( &board
);
230 SendMessage( hWnd
, WM_CLOSE
, 0, 0);
234 DialogBoxParam( board
.hInst
, "DLG_TIMES", hWnd
,
235 TimesDlgProc
, (LPARAM
) &board
);
240 WCHAR appname
[256], other
[256];
241 LoadStringW( board
.hInst
, IDS_APPNAME
, appname
, sizeof(appname
)/sizeof(WCHAR
) );
242 LoadStringW( board
.hInst
, IDS_ABOUT
, other
, sizeof(other
)/sizeof(WCHAR
) );
243 ShellAboutW( hWnd
, appname
, other
,
244 LoadImageA( board
.hInst
, "WINEMINE", IMAGE_ICON
, 48, 48, LR_SHARED
));
248 WINE_TRACE("Unknown WM_COMMAND command message received\n");
252 return( DefWindowProc( hWnd
, msg
, wParam
, lParam
));
255 void InitBoard( BOARD
*p_board
)
259 p_board
->hMinesBMP
= LoadBitmap( p_board
->hInst
, "mines");
260 p_board
->hFacesBMP
= LoadBitmap( p_board
->hInst
, "faces");
261 p_board
->hLedsBMP
= LoadBitmap( p_board
->hInst
, "leds");
263 LoadBoard( p_board
);
265 hMenu
= GetMenu( p_board
->hWnd
);
266 CheckMenuItem( hMenu
, IDM_BEGINNER
+ (unsigned) p_board
->difficulty
,
268 if( p_board
->IsMarkQ
)
269 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
271 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
272 CheckLevel( p_board
);
275 void LoadBoard( BOARD
*p_board
)
284 RegOpenKeyEx( HKEY_CURRENT_USER
, registry_key
,
285 0, KEY_QUERY_VALUE
, &hkey
);
287 size
= sizeof( p_board
->pos
.x
);
288 if( !RegQueryValueEx( hkey
, "Xpos", NULL
, (LPDWORD
) &type
,
289 (LPBYTE
) &p_board
->pos
.x
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
292 size
= sizeof( p_board
->pos
.y
);
293 if( !RegQueryValueEx( hkey
, "Ypos", NULL
, (LPDWORD
) &type
,
294 (LPBYTE
) &p_board
->pos
.y
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
297 size
= sizeof( p_board
->rows
);
298 if( !RegQueryValueEx( hkey
, "Height", NULL
, (LPDWORD
) &type
,
299 (LPBYTE
) &p_board
->rows
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
300 p_board
->rows
= BEGINNER_ROWS
;
302 size
= sizeof( p_board
->cols
);
303 if( !RegQueryValueEx( hkey
, "Width", NULL
, (LPDWORD
) &type
,
304 (LPBYTE
) &p_board
->cols
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
305 p_board
->cols
= BEGINNER_COLS
;
307 size
= sizeof( p_board
->mines
);
308 if( !RegQueryValueEx( hkey
, "Mines", NULL
, (LPDWORD
) &type
,
309 (LPBYTE
) &p_board
->mines
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
310 p_board
->mines
= BEGINNER_MINES
;
312 size
= sizeof( p_board
->difficulty
);
313 if( !RegQueryValueEx( hkey
, "Difficulty", NULL
, (LPDWORD
) &type
,
314 (LPBYTE
) &p_board
->difficulty
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
315 p_board
->difficulty
= BEGINNER
;
317 size
= sizeof( p_board
->IsMarkQ
);
318 if( !RegQueryValueEx( hkey
, "Mark", NULL
, (LPDWORD
) &type
,
319 (LPBYTE
) &p_board
->IsMarkQ
, (LPDWORD
) &size
) == ERROR_SUCCESS
)
320 p_board
->IsMarkQ
= TRUE
;
322 for( i
= 0; i
< 3; i
++ ) {
323 wsprintf( key_name
, "Name%d", i
+1 );
324 size
= sizeof( data
);
325 if( RegQueryValueEx( hkey
, key_name
, NULL
, (LPDWORD
) &type
,
327 (LPDWORD
) &size
) == ERROR_SUCCESS
)
328 lstrcpynA( p_board
->best_name
[i
], data
, sizeof(p_board
->best_name
[i
]) );
330 LoadString( p_board
->hInst
, IDS_NOBODY
, p_board
->best_name
[i
], 16 );
333 for( i
= 0; i
< 3; i
++ ) {
334 wsprintf( key_name
, "Time%d", i
+1 );
335 size
= sizeof( p_board
->best_time
[i
] );
336 if( !RegQueryValueEx( hkey
, key_name
, NULL
, (LPDWORD
) &type
,
337 (LPBYTE
) &p_board
->best_time
[i
],
338 (LPDWORD
) &size
) == ERROR_SUCCESS
)
339 p_board
->best_time
[i
] = 999;
344 void SaveBoard( BOARD
*p_board
)
351 if( RegCreateKeyEx( HKEY_CURRENT_USER
, registry_key
,
353 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
,
354 &hkey
, NULL
) != ERROR_SUCCESS
)
357 RegSetValueEx( hkey
, "Xpos", 0, REG_DWORD
, (LPBYTE
) &p_board
->pos
.x
, sizeof(p_board
->pos
.x
) );
358 RegSetValueEx( hkey
, "Ypos", 0, REG_DWORD
, (LPBYTE
) &p_board
->pos
.y
, sizeof(p_board
->pos
.y
) );
359 RegSetValueEx( hkey
, "Difficulty", 0, REG_DWORD
, (LPBYTE
) &p_board
->difficulty
, sizeof(p_board
->difficulty
) );
360 RegSetValueEx( hkey
, "Height", 0, REG_DWORD
, (LPBYTE
) &p_board
->rows
, sizeof(p_board
->rows
) );
361 RegSetValueEx( hkey
, "Width", 0, REG_DWORD
, (LPBYTE
) &p_board
->cols
, sizeof(p_board
->cols
) );
362 RegSetValueEx( hkey
, "Mines", 0, REG_DWORD
, (LPBYTE
) &p_board
->mines
, sizeof(p_board
->mines
) );
363 RegSetValueEx( hkey
, "Mark", 0, REG_DWORD
, (LPBYTE
) &p_board
->IsMarkQ
, sizeof(p_board
->IsMarkQ
) );
365 for( i
= 0; i
< 3; i
++ ) {
366 wsprintf( key_name
, "Name%u", i
+1 );
367 lstrcpyn( data
, p_board
->best_name
[i
], sizeof( data
) );
368 RegSetValueEx( hkey
, key_name
, 0, REG_SZ
, (LPBYTE
) data
, strlen(data
)+1 );
371 for( i
= 0; i
< 3; i
++ ) {
372 wsprintf( key_name
, "Time%u", i
+1 );
373 RegSetValueEx( hkey
, key_name
, 0, REG_DWORD
, (LPBYTE
) &p_board
->best_time
[i
], sizeof(p_board
->best_time
[i
]) );
378 void DestroyBoard( BOARD
*p_board
)
380 DeleteObject( p_board
->hFacesBMP
);
381 DeleteObject( p_board
->hLedsBMP
);
382 DeleteObject( p_board
->hMinesBMP
);
385 void SetDifficulty( BOARD
*p_board
, DIFFICULTY difficulty
)
389 if ( difficulty
== CUSTOM
)
390 if (DialogBoxParam( p_board
->hInst
, "DLG_CUSTOM", p_board
->hWnd
,
391 CustomDlgProc
, (LPARAM
) p_board
) != 0)
394 hMenu
= GetMenu( p_board
->hWnd
);
395 CheckMenuItem( hMenu
, IDM_BEGINNER
+ p_board
->difficulty
, MF_UNCHECKED
);
396 p_board
->difficulty
= difficulty
;
397 CheckMenuItem( hMenu
, IDM_BEGINNER
+ difficulty
, MF_CHECKED
);
399 switch( difficulty
) {
401 p_board
->cols
= BEGINNER_COLS
;
402 p_board
->rows
= BEGINNER_ROWS
;
403 p_board
->mines
= BEGINNER_MINES
;
407 p_board
->cols
= ADVANCED_COLS
;
408 p_board
->rows
= ADVANCED_ROWS
;
409 p_board
->mines
= ADVANCED_MINES
;
413 p_board
->cols
= EXPERT_COLS
;
414 p_board
->rows
= EXPERT_ROWS
;
416 p_board
->mines
= EXPERT_MINES
;
424 static void ShiftBetween(LONG
* x
, LONG
* y
, LONG a
, LONG b
)
436 static void MoveOnScreen(RECT
* rect
)
441 /* find the nearest monitor ... */
442 hMonitor
= MonitorFromRect(rect
, MONITOR_DEFAULTTONEAREST
);
444 /* ... and move it into the work area (ie excluding task bar)*/
445 mi
.cbSize
= sizeof(mi
);
446 GetMonitorInfo(hMonitor
, &mi
);
448 ShiftBetween(&rect
->left
, &rect
->right
, mi
.rcWork
.left
, mi
.rcWork
.right
);
449 ShiftBetween(&rect
->top
, &rect
->bottom
, mi
.rcWork
.top
, mi
.rcWork
.bottom
);
452 void CreateBoard( BOARD
*p_board
)
454 int left
, top
, bottom
, right
;
458 p_board
->mb
= MB_NONE
;
459 p_board
->boxes_left
= p_board
->cols
* p_board
->rows
- p_board
->mines
;
460 p_board
->num_flags
= 0;
462 /* Create the boxes...
463 * We actually create them with an empty border,
464 * so special care doesn't have to be taken on the edges
466 for( col
= 0; col
<= p_board
->cols
+ 1; col
++ )
467 for( row
= 0; row
<= p_board
->rows
+ 1; row
++ ) {
468 p_board
->box
[col
][row
].IsPressed
= FALSE
;
469 p_board
->box
[col
][row
].IsMine
= FALSE
;
470 p_board
->box
[col
][row
].FlagType
= NORMAL
;
471 p_board
->box
[col
][row
].NumMines
= 0;
474 p_board
->width
= p_board
->cols
* MINE_WIDTH
+ BOARD_WMARGIN
* 2;
476 p_board
->height
= p_board
->rows
* MINE_HEIGHT
+ LED_HEIGHT
479 /* setting the mines rectangle boundary */
480 left
= BOARD_WMARGIN
;
481 top
= BOARD_HMARGIN
* 2 + LED_HEIGHT
;
482 right
= left
+ p_board
->cols
* MINE_WIDTH
;
483 bottom
= top
+ p_board
->rows
* MINE_HEIGHT
;
484 SetRect( &p_board
->mines_rect
, left
, top
, right
, bottom
);
486 /* setting the face rectangle boundary */
487 left
= p_board
->width
/ 2 - FACE_WIDTH
/ 2;
489 right
= left
+ FACE_WIDTH
;
490 bottom
= top
+ FACE_HEIGHT
;
491 SetRect( &p_board
->face_rect
, left
, top
, right
, bottom
);
493 /* setting the timer rectangle boundary */
494 left
= BOARD_WMARGIN
;
496 right
= left
+ LED_WIDTH
* 3;
497 bottom
= top
+ LED_HEIGHT
;
498 SetRect( &p_board
->timer_rect
, left
, top
, right
, bottom
);
500 /* setting the counter rectangle boundary */
501 left
= p_board
->width
- BOARD_WMARGIN
- LED_WIDTH
* 3;
503 right
= p_board
->width
- BOARD_WMARGIN
;
504 bottom
= top
+ LED_HEIGHT
;
505 SetRect( &p_board
->counter_rect
, left
, top
, right
, bottom
);
507 p_board
->status
= WAITING
;
508 p_board
->face_bmp
= SMILE_BMP
;
511 wnd_rect
.left
= p_board
->pos
.x
;
512 wnd_rect
.right
= p_board
->pos
.x
+ p_board
->width
;
513 wnd_rect
.top
= p_board
->pos
.y
;
514 wnd_rect
.bottom
= p_board
->pos
.y
+ p_board
->height
;
515 AdjustWindowRect(&wnd_rect
, wnd_style
, TRUE
);
517 /* Make sure the window is completely on the screen */
518 MoveOnScreen(&wnd_rect
);
519 MoveWindow( p_board
->hWnd
, wnd_rect
.left
, wnd_rect
.top
,
520 wnd_rect
.right
- wnd_rect
.left
,
521 wnd_rect
.bottom
- wnd_rect
.top
,
523 RedrawWindow( p_board
->hWnd
, NULL
, 0,
524 RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ERASE
);
528 void CheckLevel( BOARD
*p_board
)
530 if( p_board
->rows
< BEGINNER_ROWS
)
531 p_board
->rows
= BEGINNER_ROWS
;
533 if( p_board
->rows
> MAX_ROWS
)
534 p_board
->rows
= MAX_ROWS
;
536 if( p_board
->cols
< BEGINNER_COLS
)
537 p_board
->cols
= BEGINNER_COLS
;
539 if( p_board
->cols
> MAX_COLS
)
540 p_board
->cols
= MAX_COLS
;
542 if( p_board
->mines
< BEGINNER_MINES
)
543 p_board
->mines
= BEGINNER_MINES
;
545 if( p_board
->mines
> p_board
->cols
* p_board
->rows
- 2 )
546 p_board
->mines
= p_board
->cols
* p_board
->rows
- 2;
549 /* Randomly places mines everywhere except the selected box. */
550 void PlaceMines ( BOARD
*p_board
, int selected_col
, int selected_row
)
555 srand( (unsigned) time( NULL
) );
557 /* Temporarily place a mine at the selected box until all the other
558 * mines are placed, this avoids checking in the mine creation loop. */
559 p_board
->box
[selected_col
][selected_row
].IsMine
= TRUE
;
563 while( (unsigned) i
< p_board
->mines
) {
564 col
= (int) (p_board
->cols
* (float) rand() / RAND_MAX
+ 1);
565 row
= (int) (p_board
->rows
* (float) rand() / RAND_MAX
+ 1);
567 if( !p_board
->box
[col
][row
].IsMine
) {
569 p_board
->box
[col
][row
].IsMine
= TRUE
;
573 /* Remove temporarily placed mine for selected box */
574 p_board
->box
[selected_col
][selected_row
].IsMine
= FALSE
;
577 * Now we label the remaining boxes with the
578 * number of mines surrounding them.
580 for( col
= 1; col
< p_board
->cols
+ 1; col
++ )
581 for( row
= 1; row
< p_board
->rows
+ 1; row
++ ) {
582 for( i
= -1; i
<= 1; i
++ )
583 for( j
= -1; j
<= 1; j
++ ) {
584 if( p_board
->box
[col
+ i
][row
+ j
].IsMine
) {
585 p_board
->box
[col
][row
].NumMines
++ ;
591 void DrawMines ( HDC hdc
, HDC hMemDC
, BOARD
*p_board
)
595 hOldObj
= SelectObject (hMemDC
, p_board
->hMinesBMP
);
597 for( row
= 1; row
<= p_board
->rows
; row
++ ) {
598 for( col
= 1; col
<= p_board
->cols
; col
++ ) {
599 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, FALSE
);
602 SelectObject( hMemDC
, hOldObj
);
605 void DrawMine( HDC hdc
, HDC hMemDC
, BOARD
*p_board
, unsigned col
, unsigned row
, BOOL IsPressed
)
607 MINEBMP_OFFSET offset
= BOX_BMP
;
609 if( col
== 0 || col
> p_board
->cols
|| row
== 0 || row
> p_board
->rows
)
612 if( p_board
->status
== GAMEOVER
) {
613 if( p_board
->box
[col
][row
].IsMine
) {
614 switch( p_board
->box
[col
][row
].FlagType
) {
619 offset
= EXPLODE_BMP
;
627 switch( p_board
->box
[col
][row
].FlagType
) {
629 offset
= QUESTION_BMP
;
641 WINE_TRACE("Unknown FlagType during game over in DrawMine\n");
645 } else { /* WAITING or PLAYING */
646 switch( p_board
->box
[col
][row
].FlagType
) {
649 offset
= QUESTION_BMP
;
666 WINE_TRACE("Unknown FlagType while playing in DrawMine\n");
671 if( p_board
->box
[col
][row
].FlagType
== COMPLETE
672 && !p_board
->box
[col
][row
].IsMine
)
673 offset
= (MINEBMP_OFFSET
) p_board
->box
[col
][row
].NumMines
;
676 (col
- 1) * MINE_WIDTH
+ p_board
->mines_rect
.left
,
677 (row
- 1) * MINE_HEIGHT
+ p_board
->mines_rect
.top
,
678 MINE_WIDTH
, MINE_HEIGHT
,
679 hMemDC
, 0, offset
* MINE_HEIGHT
, SRCCOPY
);
682 void DrawLeds( HDC hdc
, HDC hMemDC
, BOARD
*p_board
, int number
, int x
, int y
)
691 led
[0] = count
/ 100 ;
692 count
-= led
[0] * 100;
695 led
[0] = 10; /* negative sign */
699 count
-= led
[1] * 10;
703 for( i
= 0; i
< 3; i
++ )
707 /* use unlit led if not playing */
708 if( p_board
->status
== WAITING
)
709 for( i
= 0; i
< 3; i
++ )
712 hOldObj
= SelectObject (hMemDC
, p_board
->hLedsBMP
);
714 for( i
= 0; i
< 3; i
++ ) {
726 SelectObject( hMemDC
, hOldObj
);
730 void DrawFace( HDC hdc
, HDC hMemDC
, BOARD
*p_board
)
734 hOldObj
= SelectObject (hMemDC
, p_board
->hFacesBMP
);
737 p_board
->face_rect
.left
,
738 p_board
->face_rect
.top
,
741 hMemDC
, 0, p_board
->face_bmp
* FACE_HEIGHT
, SRCCOPY
);
743 SelectObject( hMemDC
, hOldObj
);
747 void DrawBoard( HDC hdc
, HDC hMemDC
, PAINTSTRUCT
*ps
, BOARD
*p_board
)
751 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->counter_rect
) )
752 DrawLeds( hdc
, hMemDC
, p_board
, p_board
->mines
- p_board
->num_flags
,
753 p_board
->counter_rect
.left
,
754 p_board
->counter_rect
.top
);
756 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->timer_rect
) )
757 DrawLeds( hdc
, hMemDC
, p_board
, p_board
->time
,
758 p_board
->timer_rect
.left
,
759 p_board
->timer_rect
.top
);
761 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->face_rect
) )
762 DrawFace( hdc
, hMemDC
, p_board
);
764 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->mines_rect
) )
765 DrawMines( hdc
, hMemDC
, p_board
);
769 void TestBoard( HWND hWnd
, BOARD
*p_board
, int x
, int y
, int msg
)
777 if( PtInRect( &p_board
->mines_rect
, pt
) && p_board
->status
!= GAMEOVER
778 && p_board
->status
!= WON
)
779 TestMines( p_board
, pt
, msg
);
781 UnpressBoxes( p_board
,
784 p_board
->press
.x
= 0;
785 p_board
->press
.y
= 0;
788 if( p_board
->boxes_left
== 0 ) {
789 p_board
->status
= WON
;
791 if (p_board
->num_flags
< p_board
->mines
) {
792 for( row
= 1; row
<= p_board
->rows
; row
++ ) {
793 for( col
= 1; col
<= p_board
->cols
; col
++ ) {
794 if (p_board
->box
[col
][row
].IsMine
&& p_board
->box
[col
][row
].FlagType
!= FLAG
)
795 p_board
->box
[col
][row
].FlagType
= FLAG
;
799 p_board
->num_flags
= p_board
->mines
;
801 RedrawWindow( p_board
->hWnd
, NULL
, 0,
802 RDW_INVALIDATE
| RDW_UPDATENOW
);
805 if( p_board
->difficulty
!= CUSTOM
&&
806 p_board
->time
< p_board
->best_time
[p_board
->difficulty
] ) {
807 p_board
->best_time
[p_board
->difficulty
] = p_board
->time
;
809 DialogBoxParam( p_board
->hInst
, "DLG_CONGRATS", hWnd
,
810 CongratsDlgProc
, (LPARAM
) p_board
);
812 DialogBoxParam( p_board
->hInst
, "DLG_TIMES", hWnd
,
813 TimesDlgProc
, (LPARAM
) p_board
);
816 TestFace( p_board
, pt
, msg
);
819 void TestMines( BOARD
*p_board
, POINT pt
, int msg
)
824 col
= (pt
.x
- p_board
->mines_rect
.left
) / MINE_WIDTH
+ 1;
825 row
= (pt
.y
- p_board
->mines_rect
.top
) / MINE_HEIGHT
+ 1;
829 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
) {
831 p_board
->press
.x
, p_board
->press
.y
);
832 p_board
->press
.x
= col
;
833 p_board
->press
.y
= row
;
834 PressBox( p_board
, col
, row
);
840 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
)
842 p_board
->press
.x
, p_board
->press
.y
);
843 p_board
->press
.x
= 0;
844 p_board
->press
.y
= 0;
845 if( p_board
->box
[col
][row
].FlagType
!= FLAG
846 && p_board
->status
!= PLAYING
)
848 p_board
->status
= PLAYING
;
849 PlaceMines( p_board
, col
, row
);
851 CompleteBox( p_board
, col
, row
);
855 PressBoxes( p_board
, col
, row
);
860 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
)
861 UnpressBoxes( p_board
,
862 p_board
->press
.x
, p_board
->press
.y
);
863 p_board
->press
.x
= 0;
864 p_board
->press
.y
= 0;
865 CompleteBoxes( p_board
, col
, row
);
869 AddFlag( p_board
, col
, row
);
872 WINE_TRACE("Unknown message type received in TestMines\n");
878 RedrawWindow( p_board
->hWnd
, NULL
, 0,
879 RDW_INVALIDATE
| RDW_UPDATENOW
);
884 void TestFace( BOARD
*p_board
, POINT pt
, int msg
)
886 if( p_board
->status
== PLAYING
|| p_board
->status
== WAITING
) {
887 if( msg
== WM_LBUTTONDOWN
|| msg
== WM_MBUTTONDOWN
)
888 p_board
->face_bmp
= OOH_BMP
;
889 else p_board
->face_bmp
= SMILE_BMP
;
891 else if( p_board
->status
== GAMEOVER
)
892 p_board
->face_bmp
= DEAD_BMP
;
893 else if( p_board
->status
== WON
)
894 p_board
->face_bmp
= COOL_BMP
;
896 if( PtInRect( &p_board
->face_rect
, pt
) ) {
897 if( msg
== WM_LBUTTONDOWN
)
898 p_board
->face_bmp
= SPRESS_BMP
;
900 if( msg
== WM_LBUTTONUP
)
901 CreateBoard( p_board
);
904 RedrawWindow( p_board
->hWnd
, &p_board
->face_rect
, 0,
905 RDW_INVALIDATE
| RDW_UPDATENOW
);
909 void CompleteBox( BOARD
*p_board
, unsigned col
, unsigned row
)
913 if( p_board
->box
[col
][row
].FlagType
!= COMPLETE
&&
914 p_board
->box
[col
][row
].FlagType
!= FLAG
&&
915 col
> 0 && col
< p_board
->cols
+ 1 &&
916 row
> 0 && row
< p_board
->rows
+ 1 ) {
917 p_board
->box
[col
][row
].FlagType
= COMPLETE
;
919 if( p_board
->box
[col
][row
].IsMine
) {
920 p_board
->face_bmp
= DEAD_BMP
;
921 p_board
->status
= GAMEOVER
;
923 else if( p_board
->status
!= GAMEOVER
)
924 p_board
->boxes_left
--;
926 if( p_board
->box
[col
][row
].NumMines
== 0 )
928 for( i
= -1; i
<= 1; i
++ )
929 for( j
= -1; j
<= 1; j
++ )
930 CompleteBox( p_board
, col
+ i
, row
+ j
);
936 void CompleteBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
938 unsigned numFlags
= 0;
941 if( p_board
->box
[col
][row
].FlagType
== COMPLETE
) {
942 for( i
= -1; i
<= 1; i
++ )
943 for( j
= -1; j
<= 1; j
++ ) {
944 if( p_board
->box
[col
+i
][row
+j
].FlagType
== FLAG
)
948 if( numFlags
== p_board
->box
[col
][row
].NumMines
) {
949 for( i
= -1; i
<= 1; i
++ )
950 for( j
= -1; j
<= 1; j
++ ) {
951 if( p_board
->box
[col
+i
][row
+j
].FlagType
!= FLAG
)
952 CompleteBox( p_board
, col
+i
, row
+j
);
959 void AddFlag( BOARD
*p_board
, unsigned col
, unsigned row
)
961 if( p_board
->box
[col
][row
].FlagType
!= COMPLETE
) {
962 switch( p_board
->box
[col
][row
].FlagType
) {
964 if( p_board
->IsMarkQ
)
965 p_board
->box
[col
][row
].FlagType
= QUESTION
;
967 p_board
->box
[col
][row
].FlagType
= NORMAL
;
968 p_board
->num_flags
--;
972 p_board
->box
[col
][row
].FlagType
= NORMAL
;
976 p_board
->box
[col
][row
].FlagType
= FLAG
;
977 p_board
->num_flags
++;
983 void PressBox( BOARD
*p_board
, unsigned col
, unsigned row
)
989 hdc
= GetDC( p_board
->hWnd
);
990 hMemDC
= CreateCompatibleDC( hdc
);
991 hOldObj
= SelectObject (hMemDC
, p_board
->hMinesBMP
);
993 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, TRUE
);
995 SelectObject( hMemDC
, hOldObj
);
997 ReleaseDC( p_board
->hWnd
, hdc
);
1001 void PressBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
1005 for( i
= -1; i
<= 1; i
++ )
1006 for( j
= -1; j
<= 1; j
++ ) {
1007 p_board
->box
[col
+ i
][row
+ j
].IsPressed
= TRUE
;
1008 PressBox( p_board
, col
+ i
, row
+ j
);
1011 for( i
= -1; i
<= 1; i
++ )
1012 for( j
= -1; j
<= 1; j
++ ) {
1013 if( !p_board
->box
[p_board
->press
.x
+ i
][p_board
->press
.y
+ j
].IsPressed
)
1014 UnpressBox( p_board
, p_board
->press
.x
+ i
, p_board
->press
.y
+ j
);
1017 for( i
= -1; i
<= 1; i
++ )
1018 for( j
= -1; j
<= 1; j
++ ) {
1019 p_board
->box
[col
+ i
][row
+ j
].IsPressed
= FALSE
;
1020 PressBox( p_board
, col
+ i
, row
+ j
);
1023 p_board
->press
.x
= col
;
1024 p_board
->press
.y
= row
;
1028 void UnpressBox( BOARD
*p_board
, unsigned col
, unsigned row
)
1034 hdc
= GetDC( p_board
->hWnd
);
1035 hMemDC
= CreateCompatibleDC( hdc
);
1036 hOldObj
= SelectObject( hMemDC
, p_board
->hMinesBMP
);
1038 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, FALSE
);
1040 SelectObject( hMemDC
, hOldObj
);
1042 ReleaseDC( p_board
->hWnd
, hdc
);
1046 void UnpressBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
1050 for( i
= -1; i
<= 1; i
++ )
1051 for( j
= -1; j
<= 1; j
++ ) {
1052 UnpressBox( p_board
, col
+ i
, row
+ j
);