push bf834a7eef2241618d351018da1587a7ae2466d1
[wine/hacks.git] / programs / winemine / main.c
blobc75712979caac7a163a044eed6366b744947e87a
1 /*
2 * WineMine (main.c)
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
23 #include <string.h>
24 #include <time.h>
25 #include <windows.h>
26 #include <stdlib.h>
27 #include <shellapi.h>
28 #include "main.h"
29 #include "resource.h"
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 void CheckLevel( BOARD *p_board )
41 if( p_board->rows < BEGINNER_ROWS )
42 p_board->rows = BEGINNER_ROWS;
44 if( p_board->rows > MAX_ROWS )
45 p_board->rows = MAX_ROWS;
47 if( p_board->cols < BEGINNER_COLS )
48 p_board->cols = BEGINNER_COLS;
50 if( p_board->cols > MAX_COLS )
51 p_board->cols = MAX_COLS;
53 if( p_board->mines < BEGINNER_MINES )
54 p_board->mines = BEGINNER_MINES;
56 if( p_board->mines > p_board->cols * p_board->rows - 2 )
57 p_board->mines = p_board->cols * p_board->rows - 2;
60 static void LoadBoard( BOARD *p_board )
62 DWORD size;
63 DWORD type;
64 HKEY hkey;
65 char data[MAX_PLAYER_NAME_SIZE+1];
66 char key_name[8];
67 unsigned i;
69 RegOpenKeyEx( HKEY_CURRENT_USER, registry_key,
70 0, KEY_QUERY_VALUE, &hkey );
72 size = sizeof( p_board->pos.x );
73 if( !RegQueryValueEx( hkey, "Xpos", NULL, (LPDWORD) &type,
74 (LPBYTE) &p_board->pos.x, (LPDWORD) &size ) == ERROR_SUCCESS )
75 p_board->pos.x = 0;
77 size = sizeof( p_board->pos.y );
78 if( !RegQueryValueEx( hkey, "Ypos", NULL, (LPDWORD) &type,
79 (LPBYTE) &p_board->pos.y, (LPDWORD) &size ) == ERROR_SUCCESS )
80 p_board->pos.y = 0;
82 size = sizeof( p_board->rows );
83 if( !RegQueryValueEx( hkey, "Height", NULL, (LPDWORD) &type,
84 (LPBYTE) &p_board->rows, (LPDWORD) &size ) == ERROR_SUCCESS )
85 p_board->rows = BEGINNER_ROWS;
87 size = sizeof( p_board->cols );
88 if( !RegQueryValueEx( hkey, "Width", NULL, (LPDWORD) &type,
89 (LPBYTE) &p_board->cols, (LPDWORD) &size ) == ERROR_SUCCESS )
90 p_board->cols = BEGINNER_COLS;
92 size = sizeof( p_board->mines );
93 if( !RegQueryValueEx( hkey, "Mines", NULL, (LPDWORD) &type,
94 (LPBYTE) &p_board->mines, (LPDWORD) &size ) == ERROR_SUCCESS )
95 p_board->mines = BEGINNER_MINES;
97 size = sizeof( p_board->difficulty );
98 if( !RegQueryValueEx( hkey, "Difficulty", NULL, (LPDWORD) &type,
99 (LPBYTE) &p_board->difficulty, (LPDWORD) &size ) == ERROR_SUCCESS )
100 p_board->difficulty = BEGINNER;
102 size = sizeof( p_board->IsMarkQ );
103 if( !RegQueryValueEx( hkey, "Mark", NULL, (LPDWORD) &type,
104 (LPBYTE) &p_board->IsMarkQ, (LPDWORD) &size ) == ERROR_SUCCESS )
105 p_board->IsMarkQ = TRUE;
107 for( i = 0; i < 3; i++ ) {
108 wsprintf( key_name, "Name%d", i+1 );
109 size = sizeof( data );
110 if( RegQueryValueEx( hkey, key_name, NULL, (LPDWORD) &type,
111 (LPBYTE) data,
112 (LPDWORD) &size ) == ERROR_SUCCESS )
113 lstrcpynA( p_board->best_name[i], data, sizeof(p_board->best_name[i]) );
114 else
115 LoadString( p_board->hInst, IDS_NOBODY, p_board->best_name[i], MAX_PLAYER_NAME_SIZE+1 );
118 for( i = 0; i < 3; i++ ) {
119 wsprintf( key_name, "Time%d", i+1 );
120 size = sizeof( p_board->best_time[i] );
121 if( !RegQueryValueEx( hkey, key_name, NULL, (LPDWORD) &type,
122 (LPBYTE) &p_board->best_time[i],
123 (LPDWORD) &size ) == ERROR_SUCCESS )
124 p_board->best_time[i] = 999;
126 RegCloseKey( hkey );
129 static void InitBoard( BOARD *p_board )
131 HMENU hMenu;
133 p_board->hMinesBMP = LoadBitmap( p_board->hInst, "mines");
134 p_board->hFacesBMP = LoadBitmap( p_board->hInst, "faces");
135 p_board->hLedsBMP = LoadBitmap( p_board->hInst, "leds");
137 LoadBoard( p_board );
139 hMenu = GetMenu( p_board->hWnd );
140 CheckMenuItem( hMenu, IDM_BEGINNER + (unsigned) p_board->difficulty,
141 MF_CHECKED );
142 if( p_board->IsMarkQ )
143 CheckMenuItem( hMenu, IDM_MARKQ, MF_CHECKED );
144 else
145 CheckMenuItem( hMenu, IDM_MARKQ, MF_UNCHECKED );
146 CheckLevel( p_board );
149 static void SaveBoard( BOARD *p_board )
151 HKEY hkey;
152 unsigned i;
153 char data[MAX_PLAYER_NAME_SIZE+1];
154 char key_name[8];
156 if( RegCreateKeyEx( HKEY_CURRENT_USER, registry_key,
157 0, NULL,
158 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
159 &hkey, NULL ) != ERROR_SUCCESS)
160 return;
162 RegSetValueEx( hkey, "Xpos", 0, REG_DWORD, (LPBYTE) &p_board->pos.x, sizeof(p_board->pos.x) );
163 RegSetValueEx( hkey, "Ypos", 0, REG_DWORD, (LPBYTE) &p_board->pos.y, sizeof(p_board->pos.y) );
164 RegSetValueEx( hkey, "Difficulty", 0, REG_DWORD, (LPBYTE) &p_board->difficulty, sizeof(p_board->difficulty) );
165 RegSetValueEx( hkey, "Height", 0, REG_DWORD, (LPBYTE) &p_board->rows, sizeof(p_board->rows) );
166 RegSetValueEx( hkey, "Width", 0, REG_DWORD, (LPBYTE) &p_board->cols, sizeof(p_board->cols) );
167 RegSetValueEx( hkey, "Mines", 0, REG_DWORD, (LPBYTE) &p_board->mines, sizeof(p_board->mines) );
168 RegSetValueEx( hkey, "Mark", 0, REG_DWORD, (LPBYTE) &p_board->IsMarkQ, sizeof(p_board->IsMarkQ) );
170 for( i = 0; i < 3; i++ ) {
171 wsprintf( key_name, "Name%u", i+1 );
172 lstrcpyn( data, p_board->best_name[i], sizeof( data ) );
173 RegSetValueEx( hkey, key_name, 0, REG_SZ, (LPBYTE) data, strlen(data)+1 );
176 for( i = 0; i < 3; i++ ) {
177 wsprintf( key_name, "Time%u", i+1 );
178 RegSetValueEx( hkey, key_name, 0, REG_DWORD, (LPBYTE) &p_board->best_time[i], sizeof(p_board->best_time[i]) );
180 RegCloseKey( hkey );
183 static void DestroyBoard( BOARD *p_board )
185 DeleteObject( p_board->hFacesBMP );
186 DeleteObject( p_board->hLedsBMP );
187 DeleteObject( p_board->hMinesBMP );
190 static void SetDifficulty( BOARD *p_board, DIFFICULTY difficulty )
192 HMENU hMenu;
194 if ( difficulty == CUSTOM )
195 if (DialogBoxParam( p_board->hInst, "DLG_CUSTOM", p_board->hWnd,
196 CustomDlgProc, (LPARAM) p_board) != 0)
197 return;
199 hMenu = GetMenu( p_board->hWnd );
200 CheckMenuItem( hMenu, IDM_BEGINNER + p_board->difficulty, MF_UNCHECKED );
201 p_board->difficulty = difficulty;
202 CheckMenuItem( hMenu, IDM_BEGINNER + difficulty, MF_CHECKED );
204 switch( difficulty ) {
205 case BEGINNER:
206 p_board->cols = BEGINNER_COLS;
207 p_board->rows = BEGINNER_ROWS;
208 p_board->mines = BEGINNER_MINES;
209 break;
211 case ADVANCED:
212 p_board->cols = ADVANCED_COLS;
213 p_board->rows = ADVANCED_ROWS;
214 p_board->mines = ADVANCED_MINES;
215 break;
217 case EXPERT:
218 p_board->cols = EXPERT_COLS;
219 p_board->rows = EXPERT_ROWS;
221 p_board->mines = EXPERT_MINES;
222 break;
224 case CUSTOM:
225 break;
229 static void ShiftBetween(LONG* x, LONG* y, LONG a, LONG b)
231 if (*x < a) {
232 *y += a - *x;
233 *x = a;
235 else if (*y > b) {
236 *x -= *y - b;
237 *y = b;
241 static void MoveOnScreen(RECT* rect)
243 HMONITOR hMonitor;
244 MONITORINFO mi;
246 /* find the nearest monitor ... */
247 hMonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST);
249 /* ... and move it into the work area (ie excluding task bar)*/
250 mi.cbSize = sizeof(mi);
251 GetMonitorInfo(hMonitor, &mi);
253 ShiftBetween(&rect->left, &rect->right, mi.rcWork.left, mi.rcWork.right);
254 ShiftBetween(&rect->top, &rect->bottom, mi.rcWork.top, mi.rcWork.bottom);
257 static void CreateBoard( BOARD *p_board )
259 int left, top, bottom, right;
260 unsigned col, row;
261 RECT wnd_rect;
263 p_board->mb = MB_NONE;
264 p_board->boxes_left = p_board->cols * p_board->rows - p_board->mines;
265 p_board->num_flags = 0;
267 /* Create the boxes...
268 * We actually create them with an empty border,
269 * so special care doesn't have to be taken on the edges
271 for( col = 0; col <= p_board->cols + 1; col++ )
272 for( row = 0; row <= p_board->rows + 1; row++ ) {
273 p_board->box[col][row].IsPressed = FALSE;
274 p_board->box[col][row].IsMine = FALSE;
275 p_board->box[col][row].FlagType = NORMAL;
276 p_board->box[col][row].NumMines = 0;
279 p_board->width = p_board->cols * MINE_WIDTH + BOARD_WMARGIN * 2;
281 p_board->height = p_board->rows * MINE_HEIGHT + LED_HEIGHT
282 + BOARD_HMARGIN * 3;
284 /* setting the mines rectangle boundary */
285 left = BOARD_WMARGIN;
286 top = BOARD_HMARGIN * 2 + LED_HEIGHT;
287 right = left + p_board->cols * MINE_WIDTH;
288 bottom = top + p_board->rows * MINE_HEIGHT;
289 SetRect( &p_board->mines_rect, left, top, right, bottom );
291 /* setting the face rectangle boundary */
292 left = p_board->width / 2 - FACE_WIDTH / 2;
293 top = BOARD_HMARGIN;
294 right = left + FACE_WIDTH;
295 bottom = top + FACE_HEIGHT;
296 SetRect( &p_board->face_rect, left, top, right, bottom );
298 /* setting the timer rectangle boundary */
299 left = BOARD_WMARGIN;
300 top = BOARD_HMARGIN;
301 right = left + LED_WIDTH * 3;
302 bottom = top + LED_HEIGHT;
303 SetRect( &p_board->timer_rect, left, top, right, bottom );
305 /* setting the counter rectangle boundary */
306 left = p_board->width - BOARD_WMARGIN - LED_WIDTH * 3;
307 top = BOARD_HMARGIN;
308 right = p_board->width - BOARD_WMARGIN;
309 bottom = top + LED_HEIGHT;
310 SetRect( &p_board->counter_rect, left, top, right, bottom );
312 p_board->status = WAITING;
313 p_board->face_bmp = SMILE_BMP;
314 p_board->time = 0;
316 wnd_rect.left = p_board->pos.x;
317 wnd_rect.right = p_board->pos.x + p_board->width;
318 wnd_rect.top = p_board->pos.y;
319 wnd_rect.bottom = p_board->pos.y + p_board->height;
320 AdjustWindowRect(&wnd_rect, wnd_style, TRUE);
322 /* Make sure the window is completely on the screen */
323 MoveOnScreen(&wnd_rect);
324 MoveWindow( p_board->hWnd, wnd_rect.left, wnd_rect.top,
325 wnd_rect.right - wnd_rect.left,
326 wnd_rect.bottom - wnd_rect.top,
327 TRUE );
328 RedrawWindow( p_board->hWnd, NULL, 0,
329 RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
333 /* Randomly places mines everywhere except the selected box. */
334 static void PlaceMines ( BOARD *p_board, int selected_col, int selected_row )
336 int i, j;
337 unsigned col, row;
339 srand( (unsigned) time( NULL ) );
341 /* Temporarily place a mine at the selected box until all the other
342 * mines are placed, this avoids checking in the mine creation loop. */
343 p_board->box[selected_col][selected_row].IsMine = TRUE;
345 /* create mines */
346 i = 0;
347 while( (unsigned) i < p_board->mines ) {
348 col = (int) (p_board->cols * (float) rand() / RAND_MAX + 1);
349 row = (int) (p_board->rows * (float) rand() / RAND_MAX + 1);
351 if( !p_board->box[col][row].IsMine ) {
352 i++;
353 p_board->box[col][row].IsMine = TRUE;
357 /* Remove temporarily placed mine for selected box */
358 p_board->box[selected_col][selected_row].IsMine = FALSE;
361 * Now we label the remaining boxes with the
362 * number of mines surrounding them.
364 for( col = 1; col < p_board->cols + 1; col++ )
365 for( row = 1; row < p_board->rows + 1; row++ ) {
366 for( i = -1; i <= 1; i++ )
367 for( j = -1; j <= 1; j++ ) {
368 if( p_board->box[col + i][row + j].IsMine ) {
369 p_board->box[col][row].NumMines++ ;
375 static void DrawMine( HDC hdc, HDC hMemDC, BOARD *p_board, unsigned col, unsigned row, BOOL IsPressed )
377 MINEBMP_OFFSET offset = BOX_BMP;
379 if( col == 0 || col > p_board->cols || row == 0 || row > p_board->rows )
380 return;
382 if( p_board->status == GAMEOVER ) {
383 if( p_board->box[col][row].IsMine ) {
384 switch( p_board->box[col][row].FlagType ) {
385 case FLAG:
386 offset = FLAG_BMP;
387 break;
388 case COMPLETE:
389 offset = EXPLODE_BMP;
390 break;
391 case QUESTION:
392 /* fall through */
393 case NORMAL:
394 offset = MINE_BMP;
396 } else {
397 switch( p_board->box[col][row].FlagType ) {
398 case QUESTION:
399 offset = QUESTION_BMP;
400 break;
401 case FLAG:
402 offset = WRONG_BMP;
403 break;
404 case NORMAL:
405 offset = BOX_BMP;
406 break;
407 case COMPLETE:
408 /* Do nothing */
409 break;
410 default:
411 WINE_TRACE("Unknown FlagType during game over in DrawMine\n");
412 break;
415 } else { /* WAITING or PLAYING */
416 switch( p_board->box[col][row].FlagType ) {
417 case QUESTION:
418 if( !IsPressed )
419 offset = QUESTION_BMP;
420 else
421 offset = QPRESS_BMP;
422 break;
423 case FLAG:
424 offset = FLAG_BMP;
425 break;
426 case NORMAL:
427 if( !IsPressed )
428 offset = BOX_BMP;
429 else
430 offset = MPRESS_BMP;
431 break;
432 case COMPLETE:
433 /* Do nothing */
434 break;
435 default:
436 WINE_TRACE("Unknown FlagType while playing in DrawMine\n");
437 break;
441 if( p_board->box[col][row].FlagType == COMPLETE
442 && !p_board->box[col][row].IsMine )
443 offset = (MINEBMP_OFFSET) p_board->box[col][row].NumMines;
445 BitBlt( hdc,
446 (col - 1) * MINE_WIDTH + p_board->mines_rect.left,
447 (row - 1) * MINE_HEIGHT + p_board->mines_rect.top,
448 MINE_WIDTH, MINE_HEIGHT,
449 hMemDC, 0, offset * MINE_HEIGHT, SRCCOPY );
452 static void DrawMines ( HDC hdc, HDC hMemDC, BOARD *p_board )
454 HGDIOBJ hOldObj;
455 unsigned col, row;
456 hOldObj = SelectObject (hMemDC, p_board->hMinesBMP);
458 for( row = 1; row <= p_board->rows; row++ ) {
459 for( col = 1; col <= p_board->cols; col++ ) {
460 DrawMine( hdc, hMemDC, p_board, col, row, FALSE );
463 SelectObject( hMemDC, hOldObj );
466 static void DrawLeds( HDC hdc, HDC hMemDC, BOARD *p_board, int number, int x, int y )
468 HGDIOBJ hOldObj;
469 unsigned led[3], i;
470 int count;
472 count = number;
473 if( count < 1000 ) {
474 if( count >= 0 ) {
475 led[0] = count / 100 ;
476 count -= led[0] * 100;
478 else {
479 led[0] = 10; /* negative sign */
480 count = -count;
482 led[1] = count / 10;
483 count -= led[1] * 10;
484 led[2] = count;
486 else {
487 for( i = 0; i < 3; i++ )
488 led[i] = 10;
491 hOldObj = SelectObject (hMemDC, p_board->hLedsBMP);
493 for( i = 0; i < 3; i++ ) {
494 BitBlt( hdc,
495 i * LED_WIDTH + x,
497 LED_WIDTH,
498 LED_HEIGHT,
499 hMemDC,
501 led[i] * LED_HEIGHT,
502 SRCCOPY);
505 SelectObject( hMemDC, hOldObj );
509 static void DrawFace( HDC hdc, HDC hMemDC, BOARD *p_board )
511 HGDIOBJ hOldObj;
513 hOldObj = SelectObject (hMemDC, p_board->hFacesBMP);
515 BitBlt( hdc,
516 p_board->face_rect.left,
517 p_board->face_rect.top,
518 FACE_WIDTH,
519 FACE_HEIGHT,
520 hMemDC, 0, p_board->face_bmp * FACE_HEIGHT, SRCCOPY);
522 SelectObject( hMemDC, hOldObj );
526 static void DrawBoard( HDC hdc, HDC hMemDC, PAINTSTRUCT *ps, BOARD *p_board )
528 RECT tmp_rect;
530 if( IntersectRect( &tmp_rect, &ps->rcPaint, &p_board->counter_rect ) )
531 DrawLeds( hdc, hMemDC, p_board, p_board->mines - p_board->num_flags,
532 p_board->counter_rect.left,
533 p_board->counter_rect.top );
535 if( IntersectRect( &tmp_rect, &ps->rcPaint, &p_board->timer_rect ) )
536 DrawLeds( hdc, hMemDC, p_board, p_board->time,
537 p_board->timer_rect.left,
538 p_board->timer_rect.top );
540 if( IntersectRect( &tmp_rect, &ps->rcPaint, &p_board->face_rect ) )
541 DrawFace( hdc, hMemDC, p_board );
543 if( IntersectRect( &tmp_rect, &ps->rcPaint, &p_board->mines_rect ) )
544 DrawMines( hdc, hMemDC, p_board );
548 static void AddFlag( BOARD *p_board, unsigned col, unsigned row )
550 if( p_board->box[col][row].FlagType != COMPLETE ) {
551 switch( p_board->box[col][row].FlagType ) {
552 case FLAG:
553 if( p_board->IsMarkQ )
554 p_board->box[col][row].FlagType = QUESTION;
555 else
556 p_board->box[col][row].FlagType = NORMAL;
557 p_board->num_flags--;
558 break;
560 case QUESTION:
561 p_board->box[col][row].FlagType = NORMAL;
562 break;
564 default:
565 p_board->box[col][row].FlagType = FLAG;
566 p_board->num_flags++;
572 static void UnpressBox( BOARD *p_board, unsigned col, unsigned row )
574 HDC hdc;
575 HGDIOBJ hOldObj;
576 HDC hMemDC;
578 hdc = GetDC( p_board->hWnd );
579 hMemDC = CreateCompatibleDC( hdc );
580 hOldObj = SelectObject( hMemDC, p_board->hMinesBMP );
582 DrawMine( hdc, hMemDC, p_board, col, row, FALSE );
584 SelectObject( hMemDC, hOldObj );
585 DeleteDC( hMemDC );
586 ReleaseDC( p_board->hWnd, hdc );
590 static void UnpressBoxes( BOARD *p_board, unsigned col, unsigned row )
592 int i, j;
594 for( i = -1; i <= 1; i++ )
595 for( j = -1; j <= 1; j++ ) {
596 UnpressBox( p_board, col + i, row + j );
601 static void PressBox( BOARD *p_board, unsigned col, unsigned row )
603 HDC hdc;
604 HGDIOBJ hOldObj;
605 HDC hMemDC;
607 hdc = GetDC( p_board->hWnd );
608 hMemDC = CreateCompatibleDC( hdc );
609 hOldObj = SelectObject (hMemDC, p_board->hMinesBMP);
611 DrawMine( hdc, hMemDC, p_board, col, row, TRUE );
613 SelectObject( hMemDC, hOldObj );
614 DeleteDC( hMemDC );
615 ReleaseDC( p_board->hWnd, hdc );
619 static void PressBoxes( BOARD *p_board, unsigned col, unsigned row )
621 int i, j;
623 for( i = -1; i <= 1; i++ )
624 for( j = -1; j <= 1; j++ ) {
625 p_board->box[col + i][row + j].IsPressed = TRUE;
626 PressBox( p_board, col + i, row + j );
629 for( i = -1; i <= 1; i++ )
630 for( j = -1; j <= 1; j++ ) {
631 if( !p_board->box[p_board->press.x + i][p_board->press.y + j].IsPressed )
632 UnpressBox( p_board, p_board->press.x + i, p_board->press.y + j );
635 for( i = -1; i <= 1; i++ )
636 for( j = -1; j <= 1; j++ ) {
637 p_board->box[col + i][row + j].IsPressed = FALSE;
638 PressBox( p_board, col + i, row + j );
641 p_board->press.x = col;
642 p_board->press.y = row;
646 static void CompleteBox( BOARD *p_board, unsigned col, unsigned row )
648 int i, j;
650 if( p_board->box[col][row].FlagType != COMPLETE &&
651 p_board->box[col][row].FlagType != FLAG &&
652 col > 0 && col < p_board->cols + 1 &&
653 row > 0 && row < p_board->rows + 1 ) {
654 p_board->box[col][row].FlagType = COMPLETE;
656 if( p_board->box[col][row].IsMine ) {
657 p_board->face_bmp = DEAD_BMP;
658 p_board->status = GAMEOVER;
660 else if( p_board->status != GAMEOVER )
661 p_board->boxes_left--;
663 if( p_board->box[col][row].NumMines == 0 )
665 for( i = -1; i <= 1; i++ )
666 for( j = -1; j <= 1; j++ )
667 CompleteBox( p_board, col + i, row + j );
673 static void CompleteBoxes( BOARD *p_board, unsigned col, unsigned row )
675 unsigned numFlags = 0;
676 int i, j;
678 if( p_board->box[col][row].FlagType == COMPLETE ) {
679 for( i = -1; i <= 1; i++ )
680 for( j = -1; j <= 1; j++ ) {
681 if( p_board->box[col+i][row+j].FlagType == FLAG )
682 numFlags++;
685 if( numFlags == p_board->box[col][row].NumMines ) {
686 for( i = -1; i <= 1; i++ )
687 for( j = -1; j <= 1; j++ ) {
688 if( p_board->box[col+i][row+j].FlagType != FLAG )
689 CompleteBox( p_board, col+i, row+j );
696 static void TestMines( BOARD *p_board, POINT pt, int msg )
698 BOOL draw = TRUE;
699 int col, row;
701 col = (pt.x - p_board->mines_rect.left) / MINE_WIDTH + 1;
702 row = (pt.y - p_board->mines_rect.top ) / MINE_HEIGHT + 1;
704 switch ( msg ) {
705 case WM_LBUTTONDOWN:
706 if( p_board->press.x != col || p_board->press.y != row ) {
707 UnpressBox( p_board,
708 p_board->press.x, p_board->press.y );
709 p_board->press.x = col;
710 p_board->press.y = row;
711 PressBox( p_board, col, row );
713 draw = FALSE;
714 break;
716 case WM_LBUTTONUP:
717 if( p_board->press.x != col || p_board->press.y != row )
718 UnpressBox( p_board,
719 p_board->press.x, p_board->press.y );
720 p_board->press.x = 0;
721 p_board->press.y = 0;
722 if( p_board->box[col][row].FlagType != FLAG
723 && p_board->status != PLAYING )
725 p_board->status = PLAYING;
726 PlaceMines( p_board, col, row );
728 CompleteBox( p_board, col, row );
729 break;
731 case WM_MBUTTONDOWN:
732 PressBoxes( p_board, col, row );
733 draw = FALSE;
734 break;
736 case WM_MBUTTONUP:
737 if( p_board->press.x != col || p_board->press.y != row )
738 UnpressBoxes( p_board,
739 p_board->press.x, p_board->press.y );
740 p_board->press.x = 0;
741 p_board->press.y = 0;
742 CompleteBoxes( p_board, col, row );
743 break;
745 case WM_RBUTTONDOWN:
746 AddFlag( p_board, col, row );
747 break;
748 default:
749 WINE_TRACE("Unknown message type received in TestMines\n");
750 break;
753 if( draw )
755 RedrawWindow( p_board->hWnd, NULL, 0,
756 RDW_INVALIDATE | RDW_UPDATENOW );
761 static void TestFace( BOARD *p_board, POINT pt, int msg )
763 if( p_board->status == PLAYING || p_board->status == WAITING ) {
764 if( msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN )
765 p_board->face_bmp = OOH_BMP;
766 else p_board->face_bmp = SMILE_BMP;
768 else if( p_board->status == GAMEOVER )
769 p_board->face_bmp = DEAD_BMP;
770 else if( p_board->status == WON )
771 p_board->face_bmp = COOL_BMP;
773 if( PtInRect( &p_board->face_rect, pt ) ) {
774 if( msg == WM_LBUTTONDOWN )
775 p_board->face_bmp = SPRESS_BMP;
777 if( msg == WM_LBUTTONUP )
778 CreateBoard( p_board );
781 RedrawWindow( p_board->hWnd, &p_board->face_rect, 0,
782 RDW_INVALIDATE | RDW_UPDATENOW );
786 static void TestBoard( HWND hWnd, BOARD *p_board, int x, int y, int msg )
788 POINT pt;
789 unsigned col,row;
791 pt.x = x;
792 pt.y = y;
794 if( PtInRect( &p_board->mines_rect, pt ) && p_board->status != GAMEOVER
795 && p_board->status != WON )
796 TestMines( p_board, pt, msg );
797 else {
798 UnpressBoxes( p_board,
799 p_board->press.x,
800 p_board->press.y );
801 p_board->press.x = 0;
802 p_board->press.y = 0;
805 if( p_board->boxes_left == 0 ) {
806 p_board->status = WON;
808 if (p_board->num_flags < p_board->mines) {
809 for( row = 1; row <= p_board->rows; row++ ) {
810 for( col = 1; col <= p_board->cols; col++ ) {
811 if (p_board->box[col][row].IsMine && p_board->box[col][row].FlagType != FLAG)
812 p_board->box[col][row].FlagType = FLAG;
816 p_board->num_flags = p_board->mines;
818 RedrawWindow( p_board->hWnd, NULL, 0,
819 RDW_INVALIDATE | RDW_UPDATENOW );
822 if( p_board->difficulty != CUSTOM &&
823 p_board->time < p_board->best_time[p_board->difficulty] ) {
824 p_board->best_time[p_board->difficulty] = p_board->time;
826 DialogBoxParam( p_board->hInst, "DLG_CONGRATS", hWnd,
827 CongratsDlgProc, (LPARAM) p_board);
829 DialogBoxParam( p_board->hInst, "DLG_TIMES", hWnd,
830 TimesDlgProc, (LPARAM) p_board);
833 TestFace( p_board, pt, msg );
837 static LRESULT WINAPI MainProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
839 HDC hdc;
840 PAINTSTRUCT ps;
841 HMENU hMenu;
842 static BOARD board;
844 switch( msg ) {
845 case WM_CREATE:
846 board.hInst = ((LPCREATESTRUCT) lParam)->hInstance;
847 board.hWnd = hWnd;
848 InitBoard( &board );
849 CreateBoard( &board );
850 return 0;
852 case WM_PAINT:
854 HDC hMemDC;
856 WINE_TRACE("WM_PAINT\n");
857 hdc = BeginPaint( hWnd, &ps );
858 hMemDC = CreateCompatibleDC( hdc );
860 DrawBoard( hdc, hMemDC, &ps, &board );
862 DeleteDC( hMemDC );
863 EndPaint( hWnd, &ps );
865 return 0;
868 case WM_MOVE:
869 WINE_TRACE("WM_MOVE\n");
870 board.pos.x = (short)LOWORD(lParam);
871 board.pos.y = (short)HIWORD(lParam);
872 return 0;
874 case WM_DESTROY:
875 SaveBoard( &board );
876 DestroyBoard( &board );
877 PostQuitMessage( 0 );
878 return 0;
880 case WM_TIMER:
881 if( board.status == PLAYING ) {
882 board.time++;
883 RedrawWindow( hWnd, &board.timer_rect, 0,
884 RDW_INVALIDATE | RDW_UPDATENOW );
886 return 0;
888 case WM_LBUTTONDOWN:
889 WINE_TRACE("WM_LBUTTONDOWN\n");
890 if( wParam & MK_RBUTTON )
891 msg = WM_MBUTTONDOWN;
892 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
893 SetCapture( hWnd );
894 return 0;
896 case WM_LBUTTONUP:
897 WINE_TRACE("WM_LBUTTONUP\n");
898 if( wParam & MK_RBUTTON )
899 msg = WM_MBUTTONUP;
900 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
901 ReleaseCapture();
902 return 0;
904 case WM_RBUTTONDOWN:
905 WINE_TRACE("WM_RBUTTONDOWN\n");
906 if( wParam & MK_LBUTTON ) {
907 board.press.x = 0;
908 board.press.y = 0;
909 msg = WM_MBUTTONDOWN;
911 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
912 return 0;
914 case WM_RBUTTONUP:
915 WINE_TRACE("WM_RBUTTONUP\n");
916 if( wParam & MK_LBUTTON )
917 msg = WM_MBUTTONUP;
918 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
919 return 0;
921 case WM_MBUTTONDOWN:
922 WINE_TRACE("WM_MBUTTONDOWN\n");
923 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
924 return 0;
926 case WM_MBUTTONUP:
927 WINE_TRACE("WM_MBUTTONUP\n");
928 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
929 return 0;
931 case WM_MOUSEMOVE:
933 if( wParam & MK_MBUTTON ) {
934 msg = WM_MBUTTONDOWN;
936 else if( wParam & MK_LBUTTON ) {
937 msg = WM_LBUTTONDOWN;
939 else {
940 return 0;
943 TestBoard( hWnd, &board, (short)LOWORD(lParam), (short)HIWORD(lParam), msg );
945 return 0;
948 case WM_COMMAND:
949 switch(LOWORD(wParam)) {
950 case IDM_NEW:
951 CreateBoard( &board );
952 return 0;
954 case IDM_MARKQ:
955 hMenu = GetMenu( hWnd );
956 board.IsMarkQ = !board.IsMarkQ;
957 if( board.IsMarkQ )
958 CheckMenuItem( hMenu, IDM_MARKQ, MF_CHECKED );
959 else
960 CheckMenuItem( hMenu, IDM_MARKQ, MF_UNCHECKED );
961 return 0;
963 case IDM_BEGINNER:
964 SetDifficulty( &board, BEGINNER );
965 CreateBoard( &board );
966 return 0;
968 case IDM_ADVANCED:
969 SetDifficulty( &board, ADVANCED );
970 CreateBoard( &board );
971 return 0;
973 case IDM_EXPERT:
974 SetDifficulty( &board, EXPERT );
975 CreateBoard( &board );
976 return 0;
978 case IDM_CUSTOM:
979 SetDifficulty( &board, CUSTOM );
980 CreateBoard( &board );
981 return 0;
983 case IDM_EXIT:
984 SendMessage( hWnd, WM_CLOSE, 0, 0);
985 return 0;
987 case IDM_TIMES:
988 DialogBoxParam( board.hInst, "DLG_TIMES", hWnd,
989 TimesDlgProc, (LPARAM) &board);
990 return 0;
992 case IDM_ABOUT:
994 WCHAR appname[256], other[256];
995 LoadStringW( board.hInst, IDS_APPNAME, appname, sizeof(appname)/sizeof(WCHAR) );
996 LoadStringW( board.hInst, IDS_ABOUT, other, sizeof(other)/sizeof(WCHAR) );
997 ShellAboutW( hWnd, appname, other,
998 LoadImageA( board.hInst, "WINEMINE", IMAGE_ICON, 48, 48, LR_SHARED ));
999 return 0;
1001 default:
1002 WINE_TRACE("Unknown WM_COMMAND command message received\n");
1003 break;
1006 return( DefWindowProc( hWnd, msg, wParam, lParam ));
1009 int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdline, int cmdshow )
1011 MSG msg;
1012 WNDCLASS wc;
1013 HWND hWnd;
1014 HACCEL haccel;
1015 char appname[20];
1017 LoadString( hInst, IDS_APPNAME, appname, sizeof(appname));
1019 wc.style = 0;
1020 wc.lpfnWndProc = MainProc;
1021 wc.cbClsExtra = 0;
1022 wc.cbWndExtra = 0;
1023 wc.hInstance = hInst;
1024 wc.hIcon = LoadIcon( hInst, "WINEMINE" );
1025 wc.hCursor = LoadCursor( 0, IDI_APPLICATION );
1026 wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH );
1027 wc.lpszMenuName = "MENU_WINEMINE";
1028 wc.lpszClassName = appname;
1030 if (!RegisterClass(&wc)) ExitProcess(1);
1031 hWnd = CreateWindow( appname, appname,
1032 wnd_style,
1033 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1034 0, 0, hInst, NULL );
1036 if (!hWnd) ExitProcess(1);
1038 ShowWindow( hWnd, cmdshow );
1039 UpdateWindow( hWnd );
1041 haccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDA_WINEMINE) );
1042 SetTimer( hWnd, ID_TIMER, 1000, NULL );
1044 while( GetMessage(&msg, 0, 0, 0) ) {
1045 if (!TranslateAccelerator( hWnd, haccel, &msg ))
1046 TranslateMessage( &msg );
1048 DispatchMessage( &msg );
1050 return msg.wParam;