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 WCHAR registry_key
[] = {'S','o','f','t','w','a','r','e','\\',
37 'M','i','c','r','o','s','o','f','t','\\',
38 'W','i','n','M','i','n','e',0};
40 static const WCHAR xposW
[] = {'X','p','o','s',0};
41 static const WCHAR yposW
[] = {'Y','p','o','s',0};
42 static const WCHAR heightW
[] = {'H','e','i','g','h','t',0};
43 static const WCHAR widthW
[] = {'W','i','d','t','h',0};
44 static const WCHAR minesW
[] = {'M','i','n','e','s',0};
45 static const WCHAR difficultyW
[] = {'D','i','f','f','i','c','u','l','t','y',0};
46 static const WCHAR markW
[] = {'M','a','r','k',0};
47 static const WCHAR nameW
[] = {'N','a','m','e','%','u',0};
48 static const WCHAR timeW
[] = {'T','i','m','e','%','u',0};
50 void CheckLevel( BOARD
*p_board
)
52 if( p_board
->rows
< BEGINNER_ROWS
)
53 p_board
->rows
= BEGINNER_ROWS
;
55 if( p_board
->rows
> MAX_ROWS
)
56 p_board
->rows
= MAX_ROWS
;
58 if( p_board
->cols
< BEGINNER_COLS
)
59 p_board
->cols
= BEGINNER_COLS
;
61 if( p_board
->cols
> MAX_COLS
)
62 p_board
->cols
= MAX_COLS
;
64 if( p_board
->mines
< BEGINNER_MINES
)
65 p_board
->mines
= BEGINNER_MINES
;
67 if( p_board
->mines
> ( p_board
->cols
- 1 ) * ( p_board
->rows
- 1 ) )
68 p_board
->mines
= ( p_board
->cols
- 1 ) * ( p_board
->rows
- 1 );
71 static void LoadBoard( BOARD
*p_board
)
76 WCHAR data
[MAX_PLAYER_NAME_SIZE
+1];
80 RegOpenKeyExW( HKEY_CURRENT_USER
, registry_key
, 0, KEY_QUERY_VALUE
, &hkey
);
82 size
= sizeof( p_board
->pos
.x
);
83 if( RegQueryValueExW( hkey
, xposW
, NULL
, &type
, (BYTE
*) &p_board
->pos
.x
, &size
) )
86 size
= sizeof( p_board
->pos
.y
);
87 if( RegQueryValueExW( hkey
, yposW
, NULL
, &type
, (BYTE
*) &p_board
->pos
.y
, &size
) )
90 size
= sizeof( p_board
->rows
);
91 if( RegQueryValueExW( hkey
, heightW
, NULL
, &type
, (BYTE
*) &p_board
->rows
, &size
) )
92 p_board
->rows
= BEGINNER_ROWS
;
94 size
= sizeof( p_board
->cols
);
95 if( RegQueryValueExW( hkey
, widthW
, NULL
, &type
, (BYTE
*) &p_board
->cols
, &size
) )
96 p_board
->cols
= BEGINNER_COLS
;
98 size
= sizeof( p_board
->mines
);
99 if( RegQueryValueExW( hkey
, minesW
, NULL
, &type
, (BYTE
*) &p_board
->mines
, &size
) )
100 p_board
->mines
= BEGINNER_MINES
;
102 size
= sizeof( p_board
->difficulty
);
103 if( RegQueryValueExW( hkey
, difficultyW
, NULL
, &type
, (BYTE
*) &p_board
->difficulty
, &size
) )
104 p_board
->difficulty
= BEGINNER
;
106 size
= sizeof( p_board
->IsMarkQ
);
107 if( RegQueryValueExW( hkey
, markW
, NULL
, &type
, (BYTE
*) &p_board
->IsMarkQ
, &size
) )
108 p_board
->IsMarkQ
= TRUE
;
110 for( i
= 0; i
< 3; i
++ ) {
111 wsprintfW( key_name
, nameW
, i
+1 );
112 size
= sizeof( data
);
113 if( RegQueryValueExW( hkey
, key_name
, NULL
, &type
,
114 (LPBYTE
) data
, &size
) == ERROR_SUCCESS
)
115 lstrcpynW( p_board
->best_name
[i
], data
, sizeof(p_board
->best_name
[i
])/sizeof(WCHAR
) );
117 LoadStringW( p_board
->hInst
, IDS_NOBODY
, p_board
->best_name
[i
], MAX_PLAYER_NAME_SIZE
+1 );
120 for( i
= 0; i
< 3; i
++ ) {
121 wsprintfW( key_name
, timeW
, i
+1 );
122 size
= sizeof( p_board
->best_time
[i
] );
123 if( RegQueryValueExW( hkey
, key_name
, NULL
, &type
, (BYTE
*) &p_board
->best_time
[i
], &size
) )
124 p_board
->best_time
[i
] = 999;
129 static void InitBoard( BOARD
*p_board
)
133 p_board
->hMinesBMP
= LoadBitmapW( p_board
->hInst
, MAKEINTRESOURCEW(IDI_MINES
));
134 p_board
->hFacesBMP
= LoadBitmapW( p_board
->hInst
, MAKEINTRESOURCEW(IDI_FACES
));
135 p_board
->hLedsBMP
= LoadBitmapW( p_board
->hInst
, MAKEINTRESOURCEW(IDI_LEDS
));
137 LoadBoard( p_board
);
139 hMenu
= GetMenu( p_board
->hWnd
);
140 CheckMenuItem( hMenu
, IDM_BEGINNER
+ (unsigned) p_board
->difficulty
,
142 if( p_board
->IsMarkQ
)
143 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
145 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
146 CheckLevel( p_board
);
149 void ResetResults( BOARD
*p_board
)
153 for( i
= 0; i
< 3; i
++ ) {
154 LoadStringW( p_board
->hInst
, IDS_NOBODY
, p_board
->best_name
[i
], MAX_PLAYER_NAME_SIZE
+1 );
155 p_board
->best_time
[i
] = 999;
159 void SaveBoard( BOARD
*p_board
)
163 WCHAR data
[MAX_PLAYER_NAME_SIZE
+1];
166 if( RegCreateKeyExW( HKEY_CURRENT_USER
, registry_key
,
168 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
,
169 &hkey
, NULL
) != ERROR_SUCCESS
)
172 RegSetValueExW( hkey
, xposW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->pos
.x
, sizeof(p_board
->pos
.x
) );
173 RegSetValueExW( hkey
, yposW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->pos
.y
, sizeof(p_board
->pos
.y
) );
174 RegSetValueExW( hkey
, difficultyW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->difficulty
, sizeof(p_board
->difficulty
) );
175 RegSetValueExW( hkey
, heightW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->rows
, sizeof(p_board
->rows
) );
176 RegSetValueExW( hkey
, widthW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->cols
, sizeof(p_board
->cols
) );
177 RegSetValueExW( hkey
, minesW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->mines
, sizeof(p_board
->mines
) );
178 RegSetValueExW( hkey
, markW
, 0, REG_DWORD
, (LPBYTE
) &p_board
->IsMarkQ
, sizeof(p_board
->IsMarkQ
) );
180 for( i
= 0; i
< 3; i
++ ) {
181 wsprintfW( key_name
, nameW
, i
+1 );
182 lstrcpynW( data
, p_board
->best_name
[i
], sizeof(data
)/sizeof(WCHAR
) );
183 RegSetValueExW( hkey
, key_name
, 0, REG_SZ
, (LPBYTE
) data
, (lstrlenW(data
)+1) * sizeof(WCHAR
) );
186 for( i
= 0; i
< 3; i
++ ) {
187 wsprintfW( key_name
, timeW
, i
+1 );
188 RegSetValueExW( hkey
, key_name
, 0, REG_DWORD
, (LPBYTE
) &p_board
->best_time
[i
], sizeof(p_board
->best_time
[i
]) );
192 WINE_TRACE("Board has been saved.\n");
195 static void DestroyBoard( BOARD
*p_board
)
197 DeleteObject( p_board
->hFacesBMP
);
198 DeleteObject( p_board
->hLedsBMP
);
199 DeleteObject( p_board
->hMinesBMP
);
202 static void SetDifficulty( BOARD
*p_board
, DIFFICULTY difficulty
)
206 if ( difficulty
== CUSTOM
)
207 if (DialogBoxParamW( p_board
->hInst
, MAKEINTRESOURCEW(DLG_CUSTOM
), p_board
->hWnd
,
208 CustomDlgProc
, (LPARAM
) p_board
) != 0)
211 hMenu
= GetMenu( p_board
->hWnd
);
212 CheckMenuItem( hMenu
, IDM_BEGINNER
+ p_board
->difficulty
, MF_UNCHECKED
);
213 p_board
->difficulty
= difficulty
;
214 CheckMenuItem( hMenu
, IDM_BEGINNER
+ difficulty
, MF_CHECKED
);
216 switch( difficulty
) {
218 p_board
->cols
= BEGINNER_COLS
;
219 p_board
->rows
= BEGINNER_ROWS
;
220 p_board
->mines
= BEGINNER_MINES
;
224 p_board
->cols
= ADVANCED_COLS
;
225 p_board
->rows
= ADVANCED_ROWS
;
226 p_board
->mines
= ADVANCED_MINES
;
230 p_board
->cols
= EXPERT_COLS
;
231 p_board
->rows
= EXPERT_ROWS
;
233 p_board
->mines
= EXPERT_MINES
;
241 static void ShiftBetween(LONG
* x
, LONG
* y
, LONG a
, LONG b
)
253 static void MoveOnScreen(RECT
* rect
)
258 /* find the nearest monitor ... */
259 hMonitor
= MonitorFromRect(rect
, MONITOR_DEFAULTTONEAREST
);
261 /* ... and move it into the work area (ie excluding task bar)*/
262 mi
.cbSize
= sizeof(mi
);
263 GetMonitorInfoW(hMonitor
, &mi
);
265 ShiftBetween(&rect
->left
, &rect
->right
, mi
.rcWork
.left
, mi
.rcWork
.right
);
266 ShiftBetween(&rect
->top
, &rect
->bottom
, mi
.rcWork
.top
, mi
.rcWork
.bottom
);
269 static void CreateBoard( BOARD
*p_board
)
271 int left
, top
, bottom
, right
;
275 p_board
->mb
= MB_NONE
;
276 p_board
->boxes_left
= p_board
->cols
* p_board
->rows
- p_board
->mines
;
277 p_board
->num_flags
= 0;
279 /* Create the boxes...
280 * We actually create them with an empty border,
281 * so special care doesn't have to be taken on the edges
283 for( col
= 0; col
<= p_board
->cols
+ 1; col
++ )
284 for( row
= 0; row
<= p_board
->rows
+ 1; row
++ ) {
285 p_board
->box
[col
][row
].IsPressed
= FALSE
;
286 p_board
->box
[col
][row
].IsMine
= FALSE
;
287 p_board
->box
[col
][row
].FlagType
= NORMAL
;
288 p_board
->box
[col
][row
].NumMines
= 0;
291 p_board
->width
= p_board
->cols
* MINE_WIDTH
+ BOARD_WMARGIN
* 2;
293 p_board
->height
= p_board
->rows
* MINE_HEIGHT
+ LED_HEIGHT
296 /* setting the mines rectangle boundary */
297 left
= BOARD_WMARGIN
;
298 top
= BOARD_HMARGIN
* 2 + LED_HEIGHT
;
299 right
= left
+ p_board
->cols
* MINE_WIDTH
;
300 bottom
= top
+ p_board
->rows
* MINE_HEIGHT
;
301 SetRect( &p_board
->mines_rect
, left
, top
, right
, bottom
);
303 /* setting the face rectangle boundary */
304 left
= p_board
->width
/ 2 - FACE_WIDTH
/ 2;
306 right
= left
+ FACE_WIDTH
;
307 bottom
= top
+ FACE_HEIGHT
;
308 SetRect( &p_board
->face_rect
, left
, top
, right
, bottom
);
310 /* setting the timer rectangle boundary */
311 left
= BOARD_WMARGIN
;
313 right
= left
+ LED_WIDTH
* 3;
314 bottom
= top
+ LED_HEIGHT
;
315 SetRect( &p_board
->timer_rect
, left
, top
, right
, bottom
);
317 /* setting the counter rectangle boundary */
318 left
= p_board
->width
- BOARD_WMARGIN
- LED_WIDTH
* 3;
320 right
= p_board
->width
- BOARD_WMARGIN
;
321 bottom
= top
+ LED_HEIGHT
;
322 SetRect( &p_board
->counter_rect
, left
, top
, right
, bottom
);
324 p_board
->status
= WAITING
;
325 p_board
->face_bmp
= SMILE_BMP
;
328 SetRect(&wnd_rect
, p_board
->pos
.x
, p_board
->pos
.y
, p_board
->pos
.x
+ p_board
->width
,
329 p_board
->pos
.y
+ p_board
->height
);
330 AdjustWindowRect(&wnd_rect
, wnd_style
, TRUE
);
332 /* Make sure the window is completely on the screen */
333 MoveOnScreen(&wnd_rect
);
334 MoveWindow( p_board
->hWnd
, wnd_rect
.left
, wnd_rect
.top
,
335 wnd_rect
.right
- wnd_rect
.left
,
336 wnd_rect
.bottom
- wnd_rect
.top
,
338 RedrawWindow( p_board
->hWnd
, NULL
, 0,
339 RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ERASE
);
343 /* Randomly places mines everywhere except the selected box. */
344 static void PlaceMines ( BOARD
*p_board
, int selected_col
, int selected_row
)
349 srand( (unsigned) time( NULL
) );
351 /* Temporarily place a mine at the selected box until all the other
352 * mines are placed, this avoids checking in the mine creation loop. */
353 p_board
->box
[selected_col
][selected_row
].IsMine
= TRUE
;
357 while( (unsigned) i
< p_board
->mines
) {
358 col
= rand() % p_board
->cols
+ 1;
359 row
= rand() % p_board
->rows
+ 1;
361 if( !p_board
->box
[col
][row
].IsMine
) {
363 p_board
->box
[col
][row
].IsMine
= TRUE
;
367 /* Remove temporarily placed mine for selected box */
368 p_board
->box
[selected_col
][selected_row
].IsMine
= FALSE
;
371 * Now we label the remaining boxes with the
372 * number of mines surrounding them.
374 for( col
= 1; col
< p_board
->cols
+ 1; col
++ )
375 for( row
= 1; row
< p_board
->rows
+ 1; row
++ ) {
376 for( i
= -1; i
<= 1; i
++ )
377 for( j
= -1; j
<= 1; j
++ ) {
378 if( p_board
->box
[col
+ i
][row
+ j
].IsMine
) {
379 p_board
->box
[col
][row
].NumMines
++ ;
385 static void DrawMine( HDC hdc
, HDC hMemDC
, BOARD
*p_board
, unsigned col
, unsigned row
, BOOL IsPressed
)
387 MINEBMP_OFFSET offset
= BOX_BMP
;
389 if( col
== 0 || col
> p_board
->cols
|| row
== 0 || row
> p_board
->rows
)
392 if( p_board
->status
== GAMEOVER
) {
393 if( p_board
->box
[col
][row
].IsMine
) {
394 switch( p_board
->box
[col
][row
].FlagType
) {
399 offset
= EXPLODE_BMP
;
407 switch( p_board
->box
[col
][row
].FlagType
) {
409 offset
= QUESTION_BMP
;
421 WINE_TRACE("Unknown FlagType during game over in DrawMine\n");
425 } else { /* WAITING or PLAYING */
426 switch( p_board
->box
[col
][row
].FlagType
) {
429 offset
= QUESTION_BMP
;
446 WINE_TRACE("Unknown FlagType while playing in DrawMine\n");
451 if( p_board
->box
[col
][row
].FlagType
== COMPLETE
452 && !p_board
->box
[col
][row
].IsMine
)
453 offset
= (MINEBMP_OFFSET
) p_board
->box
[col
][row
].NumMines
;
456 (col
- 1) * MINE_WIDTH
+ p_board
->mines_rect
.left
,
457 (row
- 1) * MINE_HEIGHT
+ p_board
->mines_rect
.top
,
458 MINE_WIDTH
, MINE_HEIGHT
,
459 hMemDC
, 0, offset
* MINE_HEIGHT
, SRCCOPY
);
462 static void DrawMines ( HDC hdc
, HDC hMemDC
, BOARD
*p_board
)
466 hOldObj
= SelectObject (hMemDC
, p_board
->hMinesBMP
);
468 for( row
= 1; row
<= p_board
->rows
; row
++ ) {
469 for( col
= 1; col
<= p_board
->cols
; col
++ ) {
470 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, FALSE
);
473 SelectObject( hMemDC
, hOldObj
);
476 static void DrawLeds( HDC hdc
, HDC hMemDC
, BOARD
*p_board
, int number
, int x
, int y
)
485 led
[0] = count
/ 100 ;
486 count
-= led
[0] * 100;
489 led
[0] = 10; /* negative sign */
493 count
-= led
[1] * 10;
497 for( i
= 0; i
< 3; i
++ )
501 hOldObj
= SelectObject (hMemDC
, p_board
->hLedsBMP
);
503 for( i
= 0; i
< 3; i
++ ) {
515 SelectObject( hMemDC
, hOldObj
);
519 static void DrawFace( HDC hdc
, HDC hMemDC
, BOARD
*p_board
)
523 hOldObj
= SelectObject (hMemDC
, p_board
->hFacesBMP
);
526 p_board
->face_rect
.left
,
527 p_board
->face_rect
.top
,
530 hMemDC
, 0, p_board
->face_bmp
* FACE_HEIGHT
, SRCCOPY
);
532 SelectObject( hMemDC
, hOldObj
);
536 static void DrawBoard( HDC hdc
, HDC hMemDC
, PAINTSTRUCT
*ps
, BOARD
*p_board
)
540 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->counter_rect
) )
541 DrawLeds( hdc
, hMemDC
, p_board
, p_board
->mines
- p_board
->num_flags
,
542 p_board
->counter_rect
.left
,
543 p_board
->counter_rect
.top
);
545 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->timer_rect
) )
546 DrawLeds( hdc
, hMemDC
, p_board
, p_board
->time
,
547 p_board
->timer_rect
.left
,
548 p_board
->timer_rect
.top
);
550 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->face_rect
) )
551 DrawFace( hdc
, hMemDC
, p_board
);
553 if( IntersectRect( &tmp_rect
, &ps
->rcPaint
, &p_board
->mines_rect
) )
554 DrawMines( hdc
, hMemDC
, p_board
);
558 static void AddFlag( BOARD
*p_board
, unsigned col
, unsigned row
)
560 if( p_board
->box
[col
][row
].FlagType
!= COMPLETE
) {
561 switch( p_board
->box
[col
][row
].FlagType
) {
563 if( p_board
->IsMarkQ
)
564 p_board
->box
[col
][row
].FlagType
= QUESTION
;
566 p_board
->box
[col
][row
].FlagType
= NORMAL
;
567 p_board
->num_flags
--;
571 p_board
->box
[col
][row
].FlagType
= NORMAL
;
575 p_board
->box
[col
][row
].FlagType
= FLAG
;
576 p_board
->num_flags
++;
582 static void UnpressBox( BOARD
*p_board
, unsigned col
, unsigned row
)
588 hdc
= GetDC( p_board
->hWnd
);
589 hMemDC
= CreateCompatibleDC( hdc
);
590 hOldObj
= SelectObject( hMemDC
, p_board
->hMinesBMP
);
592 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, FALSE
);
594 SelectObject( hMemDC
, hOldObj
);
596 ReleaseDC( p_board
->hWnd
, hdc
);
600 static void UnpressBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
604 for( i
= -1; i
<= 1; i
++ )
605 for( j
= -1; j
<= 1; j
++ ) {
606 UnpressBox( p_board
, col
+ i
, row
+ j
);
611 static void PressBox( BOARD
*p_board
, unsigned col
, unsigned row
)
617 hdc
= GetDC( p_board
->hWnd
);
618 hMemDC
= CreateCompatibleDC( hdc
);
619 hOldObj
= SelectObject (hMemDC
, p_board
->hMinesBMP
);
621 DrawMine( hdc
, hMemDC
, p_board
, col
, row
, TRUE
);
623 SelectObject( hMemDC
, hOldObj
);
625 ReleaseDC( p_board
->hWnd
, hdc
);
629 static void PressBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
633 for( i
= -1; i
<= 1; i
++ )
634 for( j
= -1; j
<= 1; j
++ ) {
635 p_board
->box
[col
+ i
][row
+ j
].IsPressed
= TRUE
;
636 PressBox( p_board
, col
+ i
, row
+ j
);
639 for( i
= -1; i
<= 1; i
++ )
640 for( j
= -1; j
<= 1; j
++ ) {
641 if( !p_board
->box
[p_board
->press
.x
+ i
][p_board
->press
.y
+ j
].IsPressed
)
642 UnpressBox( p_board
, p_board
->press
.x
+ i
, p_board
->press
.y
+ j
);
645 for( i
= -1; i
<= 1; i
++ )
646 for( j
= -1; j
<= 1; j
++ ) {
647 p_board
->box
[col
+ i
][row
+ j
].IsPressed
= FALSE
;
648 PressBox( p_board
, col
+ i
, row
+ j
);
651 p_board
->press
.x
= col
;
652 p_board
->press
.y
= row
;
656 static void CompleteBox( BOARD
*p_board
, unsigned col
, unsigned row
)
660 if( p_board
->box
[col
][row
].FlagType
!= COMPLETE
&&
661 p_board
->box
[col
][row
].FlagType
!= FLAG
&&
662 col
> 0 && col
< p_board
->cols
+ 1 &&
663 row
> 0 && row
< p_board
->rows
+ 1 ) {
664 p_board
->box
[col
][row
].FlagType
= COMPLETE
;
666 if( p_board
->box
[col
][row
].IsMine
) {
667 p_board
->face_bmp
= DEAD_BMP
;
668 p_board
->status
= GAMEOVER
;
670 else if( p_board
->status
!= GAMEOVER
)
671 p_board
->boxes_left
--;
673 if( p_board
->box
[col
][row
].NumMines
== 0 )
675 for( i
= -1; i
<= 1; i
++ )
676 for( j
= -1; j
<= 1; j
++ )
677 CompleteBox( p_board
, col
+ i
, row
+ j
);
683 static void CompleteBoxes( BOARD
*p_board
, unsigned col
, unsigned row
)
685 unsigned numFlags
= 0;
688 if( p_board
->box
[col
][row
].FlagType
== COMPLETE
) {
689 for( i
= -1; i
<= 1; i
++ )
690 for( j
= -1; j
<= 1; j
++ ) {
691 if( p_board
->box
[col
+i
][row
+j
].FlagType
== FLAG
)
695 if( numFlags
== p_board
->box
[col
][row
].NumMines
) {
696 for( i
= -1; i
<= 1; i
++ )
697 for( j
= -1; j
<= 1; j
++ ) {
698 if( p_board
->box
[col
+i
][row
+j
].FlagType
!= FLAG
)
699 CompleteBox( p_board
, col
+i
, row
+j
);
706 static void TestMines( BOARD
*p_board
, POINT pt
, int msg
)
711 col
= (pt
.x
- p_board
->mines_rect
.left
) / MINE_WIDTH
+ 1;
712 row
= (pt
.y
- p_board
->mines_rect
.top
) / MINE_HEIGHT
+ 1;
716 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
) {
718 p_board
->press
.x
, p_board
->press
.y
);
719 p_board
->press
.x
= col
;
720 p_board
->press
.y
= row
;
721 PressBox( p_board
, col
, row
);
727 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
)
729 p_board
->press
.x
, p_board
->press
.y
);
730 p_board
->press
.x
= 0;
731 p_board
->press
.y
= 0;
732 if( p_board
->box
[col
][row
].FlagType
!= FLAG
733 && p_board
->status
!= PLAYING
)
735 p_board
->status
= PLAYING
;
736 PlaceMines( p_board
, col
, row
);
738 CompleteBox( p_board
, col
, row
);
742 PressBoxes( p_board
, col
, row
);
747 if( p_board
->press
.x
!= col
|| p_board
->press
.y
!= row
)
748 UnpressBoxes( p_board
,
749 p_board
->press
.x
, p_board
->press
.y
);
750 p_board
->press
.x
= 0;
751 p_board
->press
.y
= 0;
752 CompleteBoxes( p_board
, col
, row
);
756 AddFlag( p_board
, col
, row
);
765 RedrawWindow( p_board
->hWnd
, NULL
, 0,
766 RDW_INVALIDATE
| RDW_UPDATENOW
);
771 static void TestFace( BOARD
*p_board
, POINT pt
, int msg
)
773 if( p_board
->status
== PLAYING
|| p_board
->status
== WAITING
) {
774 if( msg
== WM_LBUTTONDOWN
|| msg
== WM_MBUTTONDOWN
)
775 p_board
->face_bmp
= OOH_BMP
;
776 else p_board
->face_bmp
= SMILE_BMP
;
778 else if( p_board
->status
== GAMEOVER
)
779 p_board
->face_bmp
= DEAD_BMP
;
780 else if( p_board
->status
== WON
)
781 p_board
->face_bmp
= COOL_BMP
;
783 if( PtInRect( &p_board
->face_rect
, pt
) ) {
784 if( msg
== WM_LBUTTONDOWN
)
785 p_board
->face_bmp
= SPRESS_BMP
;
787 if( msg
== WM_LBUTTONUP
)
788 CreateBoard( p_board
);
791 RedrawWindow( p_board
->hWnd
, &p_board
->face_rect
, 0,
792 RDW_INVALIDATE
| RDW_UPDATENOW
);
796 static void TestBoard( HWND hWnd
, BOARD
*p_board
, int x
, int y
, int msg
)
804 if( PtInRect( &p_board
->mines_rect
, pt
) && p_board
->status
!= GAMEOVER
805 && p_board
->status
!= WON
)
806 TestMines( p_board
, pt
, msg
);
808 UnpressBoxes( p_board
,
811 p_board
->press
.x
= 0;
812 p_board
->press
.y
= 0;
815 if( p_board
->boxes_left
== 0 && p_board
->status
!= WON
) {
816 p_board
->status
= WON
;
818 if (p_board
->num_flags
< p_board
->mines
) {
819 for( row
= 1; row
<= p_board
->rows
; row
++ ) {
820 for( col
= 1; col
<= p_board
->cols
; col
++ ) {
821 if (p_board
->box
[col
][row
].IsMine
&& p_board
->box
[col
][row
].FlagType
!= FLAG
)
822 p_board
->box
[col
][row
].FlagType
= FLAG
;
826 p_board
->num_flags
= p_board
->mines
;
828 RedrawWindow( p_board
->hWnd
, NULL
, 0,
829 RDW_INVALIDATE
| RDW_UPDATENOW
);
832 if( p_board
->difficulty
!= CUSTOM
&&
833 p_board
->time
< p_board
->best_time
[p_board
->difficulty
] ) {
834 p_board
->best_time
[p_board
->difficulty
] = p_board
->time
;
836 DialogBoxParamW( p_board
->hInst
, MAKEINTRESOURCEW(DLG_CONGRATS
), hWnd
,
837 CongratsDlgProc
, (LPARAM
) p_board
);
838 SaveBoard( p_board
);
839 DialogBoxParamW( p_board
->hInst
, MAKEINTRESOURCEW(DLG_TIMES
), hWnd
,
840 TimesDlgProc
, (LPARAM
) p_board
);
843 TestFace( p_board
, pt
, msg
);
847 static LRESULT WINAPI
MainProc( HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
856 board
.hInst
= ((LPCREATESTRUCTW
) lParam
)->hInstance
;
859 CreateBoard( &board
);
866 WINE_TRACE("WM_PAINT\n");
867 hdc
= BeginPaint( hWnd
, &ps
);
868 hMemDC
= CreateCompatibleDC( hdc
);
870 DrawBoard( hdc
, hMemDC
, &ps
, &board
);
873 EndPaint( hWnd
, &ps
);
879 WINE_TRACE("WM_MOVE\n");
880 board
.pos
.x
= (short)LOWORD(lParam
);
881 board
.pos
.y
= (short)HIWORD(lParam
);
886 DestroyBoard( &board
);
887 PostQuitMessage( 0 );
891 if( board
.status
== PLAYING
) {
893 RedrawWindow( hWnd
, &board
.timer_rect
, 0,
894 RDW_INVALIDATE
| RDW_UPDATENOW
);
899 WINE_TRACE("WM_LBUTTONDOWN\n");
900 if( wParam
& ( MK_RBUTTON
| MK_SHIFT
) )
901 msg
= WM_MBUTTONDOWN
;
902 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
907 WINE_TRACE("WM_LBUTTONUP\n");
908 if( wParam
& ( MK_RBUTTON
| MK_SHIFT
) )
910 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
915 WINE_TRACE("WM_RBUTTONDOWN\n");
916 if( wParam
& MK_LBUTTON
) {
919 msg
= WM_MBUTTONDOWN
;
921 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
925 WINE_TRACE("WM_RBUTTONUP\n");
926 if( wParam
& MK_LBUTTON
)
928 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
932 WINE_TRACE("WM_MBUTTONDOWN\n");
933 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
937 WINE_TRACE("WM_MBUTTONUP\n");
938 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
943 if( ( wParam
& MK_MBUTTON
) ||
944 ( ( wParam
& MK_LBUTTON
) && ( wParam
& MK_RBUTTON
) ) ) {
945 msg
= WM_MBUTTONDOWN
;
947 else if( wParam
& MK_LBUTTON
) {
948 msg
= WM_LBUTTONDOWN
;
954 TestBoard( hWnd
, &board
, (short)LOWORD(lParam
), (short)HIWORD(lParam
), msg
);
960 switch(LOWORD(wParam
)) {
962 CreateBoard( &board
);
966 hMenu
= GetMenu( hWnd
);
967 board
.IsMarkQ
= !board
.IsMarkQ
;
969 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_CHECKED
);
971 CheckMenuItem( hMenu
, IDM_MARKQ
, MF_UNCHECKED
);
975 SetDifficulty( &board
, BEGINNER
);
976 CreateBoard( &board
);
980 SetDifficulty( &board
, ADVANCED
);
981 CreateBoard( &board
);
985 SetDifficulty( &board
, EXPERT
);
986 CreateBoard( &board
);
990 SetDifficulty( &board
, CUSTOM
);
991 CreateBoard( &board
);
995 SendMessageW( hWnd
, WM_CLOSE
, 0, 0);
999 DialogBoxParamW( board
.hInst
, MAKEINTRESOURCEW(DLG_TIMES
), hWnd
,
1000 TimesDlgProc
, (LPARAM
) &board
);
1005 WCHAR appname
[256], other
[256];
1006 LoadStringW( board
.hInst
, IDS_APPNAME
, appname
, sizeof(appname
)/sizeof(WCHAR
) );
1007 LoadStringW( board
.hInst
, IDS_ABOUT
, other
, sizeof(other
)/sizeof(WCHAR
) );
1008 ShellAboutW( hWnd
, appname
, other
,
1009 LoadImageW(board
.hInst
, MAKEINTRESOURCEW(IDI_WINEMINE
), IMAGE_ICON
, 48, 48, LR_SHARED
));
1013 WINE_TRACE("Unknown WM_COMMAND command message received\n");
1017 return DefWindowProcW( hWnd
, msg
, wParam
, lParam
);
1020 int WINAPI
wWinMain( HINSTANCE hInst
, HINSTANCE hPrevInst
, LPWSTR cmdline
, int cmdshow
)
1028 LoadStringW( hInst
, IDS_APPNAME
, appname
, sizeof(appname
)/sizeof(WCHAR
));
1030 wc
.cbSize
= sizeof(wc
);
1032 wc
.lpfnWndProc
= MainProc
;
1035 wc
.hInstance
= hInst
;
1036 wc
.hIcon
= LoadIconW( hInst
, MAKEINTRESOURCEW(IDI_WINEMINE
) );
1037 wc
.hCursor
= LoadCursorW( 0, (LPWSTR
)IDI_APPLICATION
);
1038 wc
.hbrBackground
= GetStockObject( BLACK_BRUSH
);
1039 wc
.lpszMenuName
= MAKEINTRESOURCEW(IDM_WINEMINE
);
1040 wc
.lpszClassName
= appname
;
1041 wc
.hIconSm
= LoadImageW( hInst
, MAKEINTRESOURCEW(IDI_WINEMINE
), IMAGE_ICON
,
1042 GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), LR_SHARED
);
1044 if (!RegisterClassExW(&wc
)) ExitProcess(1);
1045 hWnd
= CreateWindowW( appname
, appname
,
1047 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
1048 0, 0, hInst
, NULL
);
1050 if (!hWnd
) ExitProcess(1);
1052 ShowWindow( hWnd
, cmdshow
);
1053 UpdateWindow( hWnd
);
1055 haccel
= LoadAcceleratorsW( hInst
, MAKEINTRESOURCEW(IDA_WINEMINE
) );
1056 SetTimer( hWnd
, ID_TIMER
, 1000, NULL
);
1058 while( GetMessageW(&msg
, 0, 0, 0) ) {
1059 if (!TranslateAcceleratorW( hWnd
, haccel
, &msg
))
1060 TranslateMessage( &msg
);
1062 DispatchMessageW( &msg
);