Don't rebuild the dependency file on 'make reconf'. Build type and target won't chang...
[kugel-rb.git] / apps / plugins / minesweeper.c
blobeeae12be64485cbf3f19db148a7fbe3f7c2a7127
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004-2006 Antoine Cellerier <dionoea -at- videolan -dot- org>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
24 #ifdef HAVE_LCD_BITMAP
26 #include "lib/playback_control.h"
28 PLUGIN_HEADER
30 /* what the minesweeper() function can return */
31 enum minesweeper_status {
32 MINESWEEPER_WIN,
33 MINESWEEPER_LOSE,
34 MINESWEEPER_QUIT,
35 MINESWEEPER_USB
38 /* variable button definitions */
39 #if CONFIG_KEYPAD == RECORDER_PAD
40 # define MINESWP_LEFT BUTTON_LEFT
41 # define MINESWP_RIGHT BUTTON_RIGHT
42 # define MINESWP_UP BUTTON_UP
43 # define MINESWP_DOWN BUTTON_DOWN
44 # define MINESWP_QUIT BUTTON_OFF
45 # define MINESWP_TOGGLE BUTTON_ON
46 # define MINESWP_TOGGLE2 BUTTON_F1
47 # define MINESWP_DISCOVER BUTTON_PLAY
48 # define MINESWP_DISCOVER2 BUTTON_F2
49 # define MINESWP_INFO BUTTON_F3
51 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
52 # define MINESWP_LEFT BUTTON_LEFT
53 # define MINESWP_RIGHT BUTTON_RIGHT
54 # define MINESWP_UP BUTTON_UP
55 # define MINESWP_DOWN BUTTON_DOWN
56 # define MINESWP_QUIT BUTTON_OFF
57 # define MINESWP_TOGGLE BUTTON_ON
58 # define MINESWP_TOGGLE2 BUTTON_F1
59 # define MINESWP_DISCOVER BUTTON_SELECT
60 # define MINESWP_DISCOVER2 BUTTON_F2
61 # define MINESWP_INFO BUTTON_F3
63 #elif CONFIG_KEYPAD == ONDIO_PAD
64 # define MINESWP_LEFT BUTTON_LEFT
65 # define MINESWP_RIGHT BUTTON_RIGHT
66 # define MINESWP_UP BUTTON_UP
67 # define MINESWP_DOWN BUTTON_DOWN
68 # define MINESWP_QUIT BUTTON_OFF
69 # define MINESWP_TOGGLE_PRE BUTTON_MENU
70 # define MINESWP_TOGGLE (BUTTON_MENU | BUTTON_REL)
71 # define MINESWP_DISCOVER (BUTTON_MENU | BUTTON_REPEAT)
72 # define MINESWP_INFO (BUTTON_MENU | BUTTON_OFF)
74 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
75 (CONFIG_KEYPAD == IRIVER_H300_PAD)
76 # define MINESWP_LEFT BUTTON_LEFT
77 # define MINESWP_RIGHT BUTTON_RIGHT
78 # define MINESWP_UP BUTTON_UP
79 # define MINESWP_DOWN BUTTON_DOWN
80 # define MINESWP_QUIT BUTTON_OFF
81 # define MINESWP_TOGGLE BUTTON_ON
82 # define MINESWP_TOGGLE2 BUTTON_REC
83 # define MINESWP_DISCOVER BUTTON_SELECT
84 # define MINESWP_INFO BUTTON_MODE
86 # define MINESWP_RC_QUIT BUTTON_RC_STOP
88 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
89 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
90 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
91 # define MINESWP_SCROLLWHEEL
92 # define MINESWP_LEFT BUTTON_LEFT
93 # define MINESWP_RIGHT BUTTON_RIGHT
94 # define MINESWP_UP BUTTON_MENU
95 # define MINESWP_DOWN BUTTON_PLAY
96 # define MINESWP_NEXT BUTTON_SCROLL_FWD
97 # define MINESWP_PREV BUTTON_SCROLL_BACK
98 # define MINESWP_QUIT (BUTTON_SELECT | BUTTON_MENU)
99 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
100 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
101 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
102 # define MINESWP_INFO (BUTTON_SELECT | BUTTON_PLAY)
104 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
105 # define MINESWP_LEFT BUTTON_LEFT
106 # define MINESWP_RIGHT BUTTON_RIGHT
107 # define MINESWP_UP BUTTON_UP
108 # define MINESWP_DOWN BUTTON_DOWN
109 # define MINESWP_QUIT BUTTON_POWER
110 # define MINESWP_TOGGLE BUTTON_PLAY
111 # define MINESWP_DISCOVER BUTTON_SELECT
112 # define MINESWP_INFO BUTTON_REC
114 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
115 # define MINESWP_LEFT BUTTON_LEFT
116 # define MINESWP_RIGHT BUTTON_RIGHT
117 # define MINESWP_UP BUTTON_UP
118 # define MINESWP_DOWN BUTTON_DOWN
119 # define MINESWP_QUIT BUTTON_POWER
120 # define MINESWP_TOGGLE BUTTON_A
121 # define MINESWP_DISCOVER BUTTON_SELECT
122 # define MINESWP_INFO BUTTON_MENU
124 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
126 # define MINESWP_SCROLLWHEEL
127 # define MINESWP_LEFT BUTTON_LEFT
128 # define MINESWP_RIGHT BUTTON_RIGHT
129 # define MINESWP_UP BUTTON_UP
130 # define MINESWP_DOWN BUTTON_DOWN
131 # define MINESWP_QUIT BUTTON_POWER
132 # define MINESWP_NEXT BUTTON_SCROLL_FWD
133 # define MINESWP_PREV BUTTON_SCROLL_BACK
134 # define MINESWP_TOGGLE BUTTON_REC
135 # define MINESWP_DISCOVER BUTTON_SELECT
136 # define MINESWP_INFO (BUTTON_REC|BUTTON_REPEAT)
138 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
140 # define MINESWP_LEFT BUTTON_LEFT
141 # define MINESWP_RIGHT BUTTON_RIGHT
142 # define MINESWP_UP BUTTON_UP
143 # define MINESWP_DOWN BUTTON_DOWN
144 # define MINESWP_QUIT BUTTON_POWER
145 # define MINESWP_TOGGLE BUTTON_SCROLL_FWD
146 # define MINESWP_DISCOVER BUTTON_SELECT
147 # define MINESWP_INFO BUTTON_SCROLL_BACK
149 #elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
150 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
151 (CONFIG_KEYPAD == SANSA_M200_PAD)
152 # define MINESWP_LEFT BUTTON_LEFT
153 # define MINESWP_RIGHT BUTTON_RIGHT
154 # define MINESWP_UP BUTTON_UP
155 # define MINESWP_DOWN BUTTON_DOWN
156 # define MINESWP_QUIT BUTTON_POWER
157 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
158 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
159 # define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
160 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
161 # define MINESWP_DISCOVER2 BUTTON_VOL_UP
162 # define MINESWP_INFO (BUTTON_SELECT | BUTTON_UP)
164 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
165 # define MINESWP_LEFT BUTTON_LEFT
166 # define MINESWP_RIGHT BUTTON_RIGHT
167 # define MINESWP_UP BUTTON_SCROLL_UP
168 # define MINESWP_DOWN BUTTON_SCROLL_DOWN
169 # define MINESWP_QUIT BUTTON_POWER
170 # define MINESWP_TOGGLE BUTTON_PLAY
171 # define MINESWP_DISCOVER BUTTON_REW
172 # define MINESWP_INFO (BUTTON_REW | BUTTON_PLAY)
174 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
175 # define MINESWP_LEFT BUTTON_LEFT
176 # define MINESWP_RIGHT BUTTON_RIGHT
177 # define MINESWP_UP BUTTON_UP
178 # define MINESWP_DOWN BUTTON_DOWN
179 # define MINESWP_QUIT BUTTON_BACK
180 # define MINESWP_TOGGLE BUTTON_PLAY
181 # define MINESWP_DISCOVER BUTTON_SELECT
182 # define MINESWP_INFO BUTTON_MENU
184 #elif (CONFIG_KEYPAD == MROBE100_PAD)
185 # define MINESWP_LEFT BUTTON_LEFT
186 # define MINESWP_RIGHT BUTTON_RIGHT
187 # define MINESWP_UP BUTTON_UP
188 # define MINESWP_DOWN BUTTON_DOWN
189 # define MINESWP_QUIT BUTTON_POWER
190 # define MINESWP_TOGGLE BUTTON_DISPLAY
191 # define MINESWP_DISCOVER BUTTON_SELECT
192 # define MINESWP_INFO BUTTON_MENU
194 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
195 # define MINESWP_LEFT BUTTON_RC_REW
196 # define MINESWP_RIGHT BUTTON_RC_FF
197 # define MINESWP_UP BUTTON_RC_VOL_UP
198 # define MINESWP_DOWN BUTTON_RC_VOL_DOWN
199 # define MINESWP_QUIT BUTTON_RC_REC
200 # define MINESWP_TOGGLE BUTTON_RC_MODE
201 # define MINESWP_DISCOVER BUTTON_RC_PLAY
202 # define MINESWP_INFO BUTTON_RC_MENU
204 #elif (CONFIG_KEYPAD == COWOND2_PAD)
205 # define MINESWP_QUIT BUTTON_POWER
207 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
208 # define MINESWP_LEFT BUTTON_LEFT
209 # define MINESWP_RIGHT BUTTON_RIGHT
210 # define MINESWP_UP BUTTON_UP
211 # define MINESWP_DOWN BUTTON_DOWN
212 # define MINESWP_QUIT BUTTON_BACK
213 # define MINESWP_TOGGLE BUTTON_SELECT
214 # define MINESWP_DISCOVER BUTTON_PLAY
215 # define MINESWP_INFO BUTTON_MENU
217 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
218 # define MINESWP_LEFT BUTTON_LEFT
219 # define MINESWP_RIGHT BUTTON_RIGHT
220 # define MINESWP_UP BUTTON_UP
221 # define MINESWP_DOWN BUTTON_DOWN
222 # define MINESWP_QUIT BUTTON_POWER
223 # define MINESWP_TOGGLE BUTTON_VIEW
224 # define MINESWP_DISCOVER BUTTON_SELECT
225 # define MINESWP_INFO BUTTON_MENU
227 #else
228 #error No keymap defined!
229 #endif
231 #ifdef HAVE_TOUCHSCREEN
232 #ifndef MINESWP_QUIT
233 # define MINESWP_QUIT BUTTON_TOPLEFT
234 #endif
235 #ifndef MINESWP_LEFT
236 # define MINESWP_LEFT BUTTON_MIDLEFT
237 #endif
238 #ifndef MINESWP_RIGHT
239 # define MINESWP_RIGHT BUTTON_MIDRIGHT
240 #endif
241 #ifndef MINESWP_UP
242 # define MINESWP_UP BUTTON_TOPMIDDLE
243 #endif
244 #ifndef MINESWP_DOWN
245 # define MINESWP_DOWN BUTTON_BOTTOMMIDDLE
246 #endif
247 #ifndef MINESWP_TOGGLE
248 # define MINESWP_TOGGLE BUTTON_CENTER
249 #endif
250 #ifndef MINESWP_DISCOVER
251 # define MINESWP_DISCOVER BUTTON_BOTTOMLEFT
252 #endif
253 #ifndef MINESWP_INFO
254 # define MINESWP_INFO BUTTON_BOTTOMRIGHT
255 #endif
256 #endif
258 extern const fb_data minesweeper_tiles[];
260 #ifdef HAVE_LCD_COLOR
261 # if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
262 /* We want to have at least 130 tiles on the screen */
263 # define TileSize 16
264 # elif ( LCD_HEIGHT * LCD_WIDTH ) / ( 12 * 12 ) >= 130
265 # define TileSize 12
266 # else
267 # define TileSize 10
268 # endif
269 # define BackgroundColor LCD_RGBPACK( 128, 128, 128 )
270 #elif LCD_DEPTH > 1
271 # define TileSize 12
272 #else
273 # define TileSize 8
274 #endif
276 #define Mine 9
277 #define Flag 10
278 #define Unknown 11
279 #define ExplodedMine 12
281 #define draw_tile( num, x, y ) \
282 rb->lcd_bitmap_part( minesweeper_tiles, 0, num * TileSize, \
283 TileSize, left+x*TileSize, top+y*TileSize, \
284 TileSize, TileSize )
286 #define invert_tile( x, y ) \
287 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); \
288 rb->lcd_fillrect( left+x*TileSize, top+y*TileSize, TileSize, TileSize ); \
289 rb->lcd_set_drawmode(DRMODE_SOLID);
292 /* the tile struct
293 * if there is a mine, mine is true
294 * if tile is known by player, known is true
295 * if tile has a flag, flag is true
296 * neighbors is the total number of mines arround tile
298 typedef struct tile
300 unsigned char mine : 1;
301 unsigned char known : 1;
302 unsigned char flag : 1;
303 unsigned char neighbors : 4;
304 } tile;
306 /* the height and width of the field */
307 #define MAX_HEIGHT (LCD_HEIGHT/TileSize)
308 #define MAX_WIDTH (LCD_WIDTH/TileSize)
309 int height = MAX_HEIGHT;
310 int width = MAX_WIDTH;
311 int top;
312 int left;
314 /* The Minefield. Caution it is defined as Y, X! Not the opposite. */
315 tile minefield[MAX_HEIGHT][MAX_WIDTH];
317 /* total number of mines on the game */
318 int mine_num = 0;
320 /* percentage of mines on minefield used during generation */
321 int p = 16;
323 /* number of tiles left on the game */
324 int tiles_left;
326 /* number of used flags on the game */
327 int flags_used;
329 /* Because mines are set after the first move... */
330 bool no_mines = true;
332 /* We need a stack (created on discover()) for the cascade algorithm. */
333 int stack_pos = 0;
335 /* a usefull string for snprintf */
336 char str[30];
338 #ifdef HAVE_TOUCHSCREEN
340 #include "lib/touchscreen.h"
341 static struct ts_raster mine_raster = { 0, 0, MAX_WIDTH, MAX_HEIGHT, TileSize, TileSize };
342 #endif
345 void push( int *stack, int y, int x )
347 if( stack_pos <= height*width )
349 stack[++stack_pos] = y;
350 stack[++stack_pos] = x;
354 /* Unveil tiles and push them to stack if they are empty. */
355 void unveil( int *stack, int y, int x )
357 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
358 || minefield[y][x].known
359 || minefield[y][x].mine || minefield[y][x].flag ) return;
361 minefield[y][x].known = 1;
363 if( minefield[y][x].neighbors == 0 )
364 push( stack, y, x );
367 void discover( int y, int x )
369 int stack[height*width];
371 /* Selected tile. */
372 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
373 || minefield[y][x].known
374 || minefield[y][x].mine || minefield[y][x].flag ) return;
376 minefield[y][x].known = 1;
377 /* Exit if the tile is not empty. (no mines nearby) */
378 if( minefield[y][x].neighbors ) return;
380 push( stack, y, x );
382 /* Scan all nearby tiles. If we meet a tile with a number we just unveil
383 * it. If we meet an empty tile, we push the location in stack. For each
384 * location in stack we do the same thing. (scan again all nearby tiles)
386 while( stack_pos )
388 /* Pop x, y from stack. */
389 x = stack[stack_pos--];
390 y = stack[stack_pos--];
392 unveil( stack, y-1, x-1 );
393 unveil( stack, y-1, x );
394 unveil( stack, y-1, x+1 );
395 unveil( stack, y, x+1 );
396 unveil( stack, y+1, x+1 );
397 unveil( stack, y+1, x );
398 unveil( stack, y+1, x-1 );
399 unveil( stack, y, x-1 );
403 /* Reset the whole board for a new game. */
404 void minesweeper_init( void )
406 int i,j;
408 for( i = 0; i < MAX_HEIGHT; i++ )
410 for( j = 0; j < MAX_WIDTH; j++ )
412 minefield[i][j].known = 0;
413 minefield[i][j].flag = 0;
414 minefield[i][j].mine = 0;
415 minefield[i][j].neighbors = 0;
418 no_mines = true;
419 tiles_left = width*height;
423 /* put mines on the mine field */
424 /* there is p% chance that a tile is a mine */
425 /* if the tile has coordinates (x,y), then it can't be a mine */
426 void minesweeper_putmines( int p, int x, int y )
428 int i,j;
430 mine_num = 0;
431 for( i = 0; i < height; i++ )
433 for( j = 0; j < width; j++ )
435 if( rb->rand()%100 < p && !( y==i && x==j ) )
437 minefield[i][j].mine = 1;
438 mine_num++;
440 else
442 minefield[i][j].mine = 0;
444 minefield[i][j].neighbors = 0;
448 /* we need to compute the neighbor element for each tile */
449 for( i = 0; i < height; i++ )
451 for( j = 0; j < width; j++ )
453 if( i > 0 )
455 if( j > 0 )
456 minefield[i][j].neighbors += minefield[i-1][j-1].mine;
457 minefield[i][j].neighbors += minefield[i-1][j].mine;
458 if( j < width - 1 )
459 minefield[i][j].neighbors += minefield[i-1][j+1].mine;
461 if( j > 0 )
462 minefield[i][j].neighbors += minefield[i][j-1].mine;
463 if( j < width - 1 )
464 minefield[i][j].neighbors += minefield[i][j+1].mine;
465 if( i < height - 1 )
467 if( j > 0 )
468 minefield[i][j].neighbors += minefield[i+1][j-1].mine;
469 minefield[i][j].neighbors += minefield[i+1][j].mine;
470 if( j < width - 1 )
471 minefield[i][j].neighbors += minefield[i+1][j+1].mine;
476 no_mines = false;
478 /* In case the user is lucky and there are no mines positioned. */
479 if( !mine_num && height*width != 1 )
481 minesweeper_putmines(p, x, y);
485 /* A function that will uncover all the board, when the user wins or loses.
486 can easily be expanded, (just a call assigned to a button) as a solver. */
487 void mine_show( void )
489 int i, j, button;
491 for( i = 0; i < height; i++ )
493 for( j = 0; j < width; j++ )
495 if( minefield[i][j].mine )
497 if( minefield[i][j].known )
499 draw_tile( ExplodedMine, j, i );
501 else
503 draw_tile( Mine, j, i );
506 else
508 draw_tile( minefield[i][j].neighbors, j, i );
512 rb->lcd_update();
515 button = rb->button_get(true);
516 while( ( button == BUTTON_NONE )
517 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
518 #ifdef HAVE_TOUCHSCREEN
519 button = BUTTON_NONE;
520 #endif
523 int count_tiles_left( void )
525 int tiles_left = 0;
526 int i, j;
527 for( i = 0; i < height; i++ )
528 for( j = 0; j < width; j++ )
529 if( minefield[i][j].known == 0 )
530 tiles_left++;
531 return tiles_left;
534 int count_flags( void )
536 int flags_used = 0;
537 int i, j;
538 for( i = 0; i < height; i++ )
539 for( j = 0; j < width; j++ )
540 if( minefield[i][j].flag == 1 )
541 flags_used++;
542 return flags_used;
545 /* welcome screen where player can chose mine percentage */
546 enum minesweeper_status menu( void )
548 int selection, result = MINESWEEPER_QUIT;
549 bool menu_quit = false;
551 MENUITEM_STRINGLIST( menu, "Minesweeper Menu", NULL, "Play Minesweeper",
552 "Mine Percentage", "Number of Rows",
553 "Number of Columns", "Playback Control", "Quit" );
555 #ifdef HAVE_LCD_COLOR
556 rb->lcd_set_foreground( rb->global_settings->fg_color );
557 rb->lcd_set_background( rb->global_settings->bg_color );
558 #endif
560 while( !menu_quit )
562 switch( rb->do_menu( &menu, &selection, NULL, false ) )
564 case 0:
565 result = MINESWEEPER_WIN; /* start playing */
566 menu_quit = true;
567 break;
569 case 1:
570 rb->set_int( "Mine Percentage", "%", UNIT_INT, &p, NULL,
571 1, 2, 98, NULL );
572 break;
574 case 2:
575 rb->set_int( "Number of Rows", "", UNIT_INT, &height, NULL,
576 1, 1, MAX_HEIGHT, NULL );
577 break;
579 case 3:
580 rb->set_int( "Number of Columns", "", UNIT_INT, &width, NULL,
581 1, 1, MAX_WIDTH, NULL );
582 break;
584 case 4:
585 playback_control( NULL );
586 break;
588 default:
589 result = MINESWEEPER_QUIT; /* quit program */
590 menu_quit = true;
591 break;
595 return result;
598 /* the big and ugly game function */
599 enum minesweeper_status minesweeper( void )
601 int i, j;
602 int button;
603 int lastbutton = BUTTON_NONE;
605 /* the cursor coordinates */
606 int x=0, y=0;
609 * Show the menu
611 if( ( i = menu() ) != MINESWEEPER_WIN ) return i;
614 * Init game
616 top = (LCD_HEIGHT-height*TileSize)/2;
617 left = (LCD_WIDTH-width*TileSize)/2;
619 #ifdef HAVE_TOUCHSCREEN
620 mine_raster.tl_x = left;
621 mine_raster.tl_y = top;
622 mine_raster.width = width*TileSize;
623 mine_raster.height = height*TileSize;
624 #endif
626 rb->srand( *rb->current_tick );
627 minesweeper_init();
628 x = 0;
629 y = 0;
632 * Play
634 while( true )
637 /* clear the screen buffer */
638 #ifdef HAVE_LCD_COLOR
639 rb->lcd_set_background( BackgroundColor );
640 #endif
641 rb->lcd_clear_display();
643 /* display the mine field */
644 for( i = 0; i < height; i++ )
646 for( j = 0; j < width; j++ )
648 if( minefield[i][j].known )
650 draw_tile( minefield[i][j].neighbors, j, i );
652 else if(minefield[i][j].flag)
654 draw_tile( Flag, j, i );
656 else
658 draw_tile( Unknown, j, i );
663 /* display the cursor */
664 invert_tile( x, y );
666 /* update the screen */
667 rb->lcd_update();
669 button = rb->button_get(true);
670 #ifdef HAVE_TOUCHSCREEN
671 if(button & BUTTON_TOUCHSCREEN)
673 struct ts_raster_result res;
674 if(touchscreen_map_raster(&mine_raster, rb->button_get_data() >> 16, rb->button_get_data() & 0xffff, &res) == 1)
676 button &= ~BUTTON_TOUCHSCREEN;
677 lastbutton &= ~BUTTON_TOUCHSCREEN;
679 if(button & BUTTON_REPEAT && lastbutton != MINESWP_TOGGLE && lastbutton ^ BUTTON_REPEAT)
680 button = MINESWP_TOGGLE;
681 else if(button == BUTTON_REL && lastbutton ^ BUTTON_REPEAT)
682 button = MINESWP_DISCOVER;
683 else
684 button |= BUTTON_TOUCHSCREEN;
686 x = res.x;
687 y = res.y;
690 #endif
691 switch(button)
693 /* quit minesweeper (you really shouldn't use this button ...) */
694 #ifdef MINESWP_RC_QUIT
695 case MINESWP_RC_QUIT:
696 #endif
697 case MINESWP_QUIT:
698 return MINESWEEPER_QUIT;
700 /* move cursor left */
701 case MINESWP_LEFT:
702 case MINESWP_LEFT|BUTTON_REPEAT:
703 x = ( x + width - 1 )%width;
704 break;
706 /* move cursor right */
707 case MINESWP_RIGHT:
708 case MINESWP_RIGHT|BUTTON_REPEAT:
709 x = ( x + 1 )%width;
710 break;
712 /* move cursor down */
713 case MINESWP_DOWN:
714 case MINESWP_DOWN|BUTTON_REPEAT:
715 y = ( y + 1 )%height;
716 break;
718 /* move cursor up */
719 case MINESWP_UP:
720 case MINESWP_UP|BUTTON_REPEAT:
721 y = ( y + height - 1 )%height;
722 break;
724 /*move cursor though the entire field*/
725 #ifdef MINESWP_SCROLLWHEEL
726 case MINESWP_NEXT:
727 case MINESWP_NEXT|BUTTON_REPEAT:
728 if (x == width -1 ) {
729 y = ( y + 1 )%height;
731 x = ( x + 1 )%width;
732 break;
734 case MINESWP_PREV:
735 case MINESWP_PREV|BUTTON_REPEAT:
736 if (x == 0) {
737 y = ( y + height - 1 )%height;
739 x = ( x + width - 1 )%width;
740 break;
741 #endif
742 /* discover a tile (and it's neighbors if .neighbors == 0) */
743 case MINESWP_DISCOVER:
744 #ifdef MINESWP_DISCOVER2
745 case MINESWP_DISCOVER2:
746 #endif
747 if( minefield[y][x].flag ) break;
748 /* we put the mines on the first "click" so that you don't
749 * lose on the first "click" */
750 if( tiles_left == width*height && no_mines )
751 minesweeper_putmines(p,x,y);
753 discover(y, x);
755 if( minefield[y][x].mine )
757 minefield[y][x].known = 1;
758 return MINESWEEPER_LOSE;
760 tiles_left = count_tiles_left();
761 if( tiles_left == mine_num )
763 return MINESWEEPER_WIN;
765 break;
767 /* toggle flag under cursor */
768 case MINESWP_TOGGLE:
769 #ifdef MINESWP_TOGGLE_PRE
770 if( lastbutton != MINESWP_TOGGLE_PRE )
771 break;
772 #endif
773 #ifdef MINESWP_TOGGLE2
774 case MINESWP_TOGGLE2:
775 #endif
776 minefield[y][x].flag = ( minefield[y][x].flag + 1 )%2;
777 break;
779 /* show how many mines you think you have found and how many
780 * there really are on the game */
781 case MINESWP_INFO:
782 if( no_mines )
783 break;
784 flags_used = count_flags();
785 if (flags_used == 1) {
786 rb->splashf( HZ*2, "You marked 1 field. There are %d mines.",
787 mine_num );
789 else
791 rb->splashf( HZ*2, "You marked %d fields. There are %d mines.",
792 flags_used, mine_num );
794 break;
796 default:
797 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
798 return MINESWEEPER_USB;
799 break;
801 if( button != BUTTON_NONE )
802 lastbutton = button;
807 /* plugin entry point */
808 enum plugin_status plugin_start(const void* parameter)
810 bool exit = false;
812 (void)parameter;
813 #if LCD_DEPTH > 1
814 rb->lcd_set_backdrop(NULL);
815 #endif
817 while( !exit )
819 switch( minesweeper() )
821 case MINESWEEPER_WIN:
822 rb->splash( HZ, "You Win!" );
823 rb->lcd_clear_display();
824 mine_show();
825 break;
827 case MINESWEEPER_LOSE:
828 rb->splash( HZ, "You Lose!" );
829 rb->lcd_clear_display();
830 mine_show();
831 break;
833 case MINESWEEPER_USB:
834 return PLUGIN_USB_CONNECTED;
836 case MINESWEEPER_QUIT:
837 exit = true;
838 break;
840 default:
841 break;
845 return PLUGIN_OK;
848 #endif