Reverting parts of r19760 that was mistakenly committed.
[kugel-rb.git] / apps / plugins / minesweeper.c
blob183ce0fd9b4c645230b86ffe0dc31b71c20a91ab
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 PLUGIN_HEADER
28 /* what the minesweeper() function can return */
29 enum minesweeper_status {
30 MINESWEEPER_WIN,
31 MINESWEEPER_LOSE,
32 MINESWEEPER_QUIT,
33 MINESWEEPER_USB
36 /* variable button definitions */
37 #if CONFIG_KEYPAD == RECORDER_PAD
38 # define MINESWP_LEFT BUTTON_LEFT
39 # define MINESWP_RIGHT BUTTON_RIGHT
40 # define MINESWP_UP BUTTON_UP
41 # define MINESWP_DOWN BUTTON_DOWN
42 # define MINESWP_QUIT BUTTON_OFF
43 # define MINESWP_TOGGLE BUTTON_ON
44 # define MINESWP_TOGGLE2 BUTTON_F1
45 # define MINESWP_DISCOVER BUTTON_PLAY
46 # define MINESWP_DISCOVER2 BUTTON_F2
47 # define MINESWP_INFO BUTTON_F3
49 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
50 # define MINESWP_LEFT BUTTON_LEFT
51 # define MINESWP_RIGHT BUTTON_RIGHT
52 # define MINESWP_UP BUTTON_UP
53 # define MINESWP_DOWN BUTTON_DOWN
54 # define MINESWP_QUIT BUTTON_OFF
55 # define MINESWP_TOGGLE BUTTON_ON
56 # define MINESWP_TOGGLE2 BUTTON_F1
57 # define MINESWP_DISCOVER BUTTON_SELECT
58 # define MINESWP_DISCOVER2 BUTTON_F2
59 # define MINESWP_INFO BUTTON_F3
61 #elif CONFIG_KEYPAD == ONDIO_PAD
62 # define MINESWP_LEFT BUTTON_LEFT
63 # define MINESWP_RIGHT BUTTON_RIGHT
64 # define MINESWP_UP BUTTON_UP
65 # define MINESWP_DOWN BUTTON_DOWN
66 # define MINESWP_QUIT BUTTON_OFF
67 # define MINESWP_TOGGLE_PRE BUTTON_MENU
68 # define MINESWP_TOGGLE (BUTTON_MENU | BUTTON_REL)
69 # define MINESWP_DISCOVER (BUTTON_MENU | BUTTON_REPEAT)
70 # define MINESWP_INFO (BUTTON_MENU | BUTTON_OFF)
72 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
73 (CONFIG_KEYPAD == IRIVER_H300_PAD)
74 # define MINESWP_LEFT BUTTON_LEFT
75 # define MINESWP_RIGHT BUTTON_RIGHT
76 # define MINESWP_UP BUTTON_UP
77 # define MINESWP_DOWN BUTTON_DOWN
78 # define MINESWP_QUIT BUTTON_OFF
79 # define MINESWP_TOGGLE BUTTON_ON
80 # define MINESWP_TOGGLE2 BUTTON_REC
81 # define MINESWP_DISCOVER BUTTON_SELECT
82 # define MINESWP_INFO BUTTON_MODE
84 # define MINESWP_RC_QUIT BUTTON_RC_STOP
86 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
87 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
88 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
89 # define MINESWP_SCROLLWHEEL
90 # define MINESWP_LEFT BUTTON_LEFT
91 # define MINESWP_RIGHT BUTTON_RIGHT
92 # define MINESWP_UP BUTTON_MENU
93 # define MINESWP_DOWN BUTTON_PLAY
94 # define MINESWP_NEXT BUTTON_SCROLL_FWD
95 # define MINESWP_PREV BUTTON_SCROLL_BACK
96 # define MINESWP_QUIT (BUTTON_SELECT | BUTTON_MENU)
97 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
98 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
99 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
100 # define MINESWP_INFO (BUTTON_SELECT | BUTTON_PLAY)
102 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
103 # define MINESWP_LEFT BUTTON_LEFT
104 # define MINESWP_RIGHT BUTTON_RIGHT
105 # define MINESWP_UP BUTTON_UP
106 # define MINESWP_DOWN BUTTON_DOWN
107 # define MINESWP_QUIT BUTTON_POWER
108 # define MINESWP_TOGGLE BUTTON_PLAY
109 # define MINESWP_DISCOVER BUTTON_SELECT
110 # define MINESWP_INFO BUTTON_REC
112 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
113 # define MINESWP_LEFT BUTTON_LEFT
114 # define MINESWP_RIGHT BUTTON_RIGHT
115 # define MINESWP_UP BUTTON_UP
116 # define MINESWP_DOWN BUTTON_DOWN
117 # define MINESWP_QUIT BUTTON_POWER
118 # define MINESWP_TOGGLE BUTTON_A
119 # define MINESWP_DISCOVER BUTTON_SELECT
120 # define MINESWP_INFO BUTTON_MENU
122 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
124 # define MINESWP_SCROLLWHEEL
125 # define MINESWP_LEFT BUTTON_LEFT
126 # define MINESWP_RIGHT BUTTON_RIGHT
127 # define MINESWP_UP BUTTON_UP
128 # define MINESWP_DOWN BUTTON_DOWN
129 # define MINESWP_QUIT BUTTON_POWER
130 # define MINESWP_NEXT BUTTON_SCROLL_FWD
131 # define MINESWP_PREV BUTTON_SCROLL_BACK
132 # define MINESWP_TOGGLE BUTTON_REC
133 # define MINESWP_DISCOVER BUTTON_SELECT
134 # define MINESWP_INFO (BUTTON_REC|BUTTON_REPEAT)
136 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
138 # define MINESWP_LEFT BUTTON_LEFT
139 # define MINESWP_RIGHT BUTTON_RIGHT
140 # define MINESWP_UP BUTTON_UP
141 # define MINESWP_DOWN BUTTON_DOWN
142 # define MINESWP_QUIT BUTTON_POWER
143 # define MINESWP_TOGGLE BUTTON_SCROLL_FWD
144 # define MINESWP_DISCOVER BUTTON_SELECT
145 # define MINESWP_INFO BUTTON_SCROLL_BACK
147 #elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
148 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
149 (CONFIG_KEYPAD == SANSA_M200_PAD)
150 # define MINESWP_LEFT BUTTON_LEFT
151 # define MINESWP_RIGHT BUTTON_RIGHT
152 # define MINESWP_UP BUTTON_UP
153 # define MINESWP_DOWN BUTTON_DOWN
154 # define MINESWP_QUIT BUTTON_POWER
155 # define MINESWP_TOGGLE_PRE BUTTON_SELECT
156 # define MINESWP_TOGGLE (BUTTON_SELECT | BUTTON_REL)
157 # define MINESWP_TOGGLE2 BUTTON_VOL_DOWN
158 # define MINESWP_DISCOVER (BUTTON_SELECT | BUTTON_REPEAT)
159 # define MINESWP_DISCOVER2 BUTTON_VOL_UP
160 # define MINESWP_INFO (BUTTON_SELECT | BUTTON_UP)
162 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
163 # define MINESWP_LEFT BUTTON_LEFT
164 # define MINESWP_RIGHT BUTTON_RIGHT
165 # define MINESWP_UP BUTTON_SCROLL_UP
166 # define MINESWP_DOWN BUTTON_SCROLL_DOWN
167 # define MINESWP_QUIT BUTTON_POWER
168 # define MINESWP_TOGGLE BUTTON_PLAY
169 # define MINESWP_DISCOVER BUTTON_REW
170 # define MINESWP_INFO (BUTTON_REW | BUTTON_PLAY)
172 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
173 # define MINESWP_LEFT BUTTON_LEFT
174 # define MINESWP_RIGHT BUTTON_RIGHT
175 # define MINESWP_UP BUTTON_UP
176 # define MINESWP_DOWN BUTTON_DOWN
177 # define MINESWP_QUIT BUTTON_BACK
178 # define MINESWP_TOGGLE BUTTON_PLAY
179 # define MINESWP_DISCOVER BUTTON_SELECT
180 # define MINESWP_INFO BUTTON_MENU
182 #elif (CONFIG_KEYPAD == MROBE100_PAD)
183 # define MINESWP_LEFT BUTTON_LEFT
184 # define MINESWP_RIGHT BUTTON_RIGHT
185 # define MINESWP_UP BUTTON_UP
186 # define MINESWP_DOWN BUTTON_DOWN
187 # define MINESWP_QUIT BUTTON_POWER
188 # define MINESWP_TOGGLE BUTTON_DISPLAY
189 # define MINESWP_DISCOVER BUTTON_SELECT
190 # define MINESWP_INFO BUTTON_MENU
192 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
193 # define MINESWP_LEFT BUTTON_RC_REW
194 # define MINESWP_RIGHT BUTTON_RC_FF
195 # define MINESWP_UP BUTTON_RC_VOL_UP
196 # define MINESWP_DOWN BUTTON_RC_VOL_DOWN
197 # define MINESWP_QUIT BUTTON_RC_REC
198 # define MINESWP_TOGGLE BUTTON_RC_MODE
199 # define MINESWP_DISCOVER BUTTON_RC_PLAY
200 # define MINESWP_INFO BUTTON_RC_MENU
202 #elif (CONFIG_KEYPAD == COWOND2_PAD)
203 # define MINESWP_QUIT BUTTON_POWER
205 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
206 # define MINESWP_LEFT BUTTON_LEFT
207 # define MINESWP_RIGHT BUTTON_RIGHT
208 # define MINESWP_UP BUTTON_UP
209 # define MINESWP_DOWN BUTTON_DOWN
210 # define MINESWP_QUIT BUTTON_BACK
211 # define MINESWP_TOGGLE BUTTON_SELECT
212 # define MINESWP_DISCOVER BUTTON_PLAY
213 # define MINESWP_INFO BUTTON_MENU
215 #else
216 #error No keymap defined!
217 #endif
219 #ifdef HAVE_TOUCHSCREEN
220 #ifndef MINESWP_QUIT
221 # define MINESWP_QUIT BUTTON_TOPLEFT
222 #endif
223 #ifndef MINESWP_LEFT
224 # define MINESWP_LEFT BUTTON_MIDLEFT
225 #endif
226 #ifndef MINESWP_RIGHT
227 # define MINESWP_RIGHT BUTTON_MIDRIGHT
228 #endif
229 #ifndef MINESWP_UP
230 # define MINESWP_UP BUTTON_TOPMIDDLE
231 #endif
232 #ifndef MINESWP_DOWN
233 # define MINESWP_DOWN BUTTON_BOTTOMMIDDLE
234 #endif
235 #ifndef MINESWP_TOGGLE
236 # define MINESWP_TOGGLE BUTTON_CENTER
237 #endif
238 #ifndef MINESWP_DISCOVER
239 # define MINESWP_DISCOVER BUTTON_BOTTOMLEFT
240 #endif
241 #ifndef MINESWP_INFO
242 # define MINESWP_INFO BUTTON_BOTTOMRIGHT
243 #endif
244 #endif
246 /* here is a global api struct pointer. while not strictly necessary,
247 * it's nice not to have to pass the api pointer in all function calls
248 * in the plugin
250 static const struct plugin_api *rb;
252 extern const fb_data minesweeper_tiles[];
254 #ifdef HAVE_LCD_COLOR
255 # if ( LCD_HEIGHT * LCD_WIDTH ) / ( 16 * 16 ) >= 130
256 /* We want to have at least 130 tiles on the screen */
257 # define TileSize 16
258 # elif ( LCD_HEIGHT * LCD_WIDTH ) / ( 12 * 12 ) >= 130
259 # define TileSize 12
260 # else
261 # define TileSize 10
262 # endif
263 # define BackgroundColor LCD_RGBPACK( 128, 128, 128 )
264 #elif LCD_DEPTH > 1
265 # define TileSize 12
266 #else
267 # define TileSize 8
268 #endif
270 #define Mine 9
271 #define Flag 10
272 #define Unknown 11
273 #define ExplodedMine 12
275 #define draw_tile( num, x, y ) \
276 rb->lcd_bitmap_part( minesweeper_tiles, 0, num * TileSize, \
277 TileSize, left+x*TileSize, top+y*TileSize, \
278 TileSize, TileSize )
280 #define invert_tile( x, y ) \
281 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); \
282 rb->lcd_fillrect( left+x*TileSize, top+y*TileSize, TileSize, TileSize ); \
283 rb->lcd_set_drawmode(DRMODE_SOLID);
286 /* the tile struct
287 * if there is a mine, mine is true
288 * if tile is known by player, known is true
289 * if tile has a flag, flag is true
290 * neighbors is the total number of mines arround tile
292 typedef struct tile
294 unsigned char mine : 1;
295 unsigned char known : 1;
296 unsigned char flag : 1;
297 unsigned char neighbors : 4;
298 } tile;
300 /* the height and width of the field */
301 #define MAX_HEIGHT (LCD_HEIGHT/TileSize)
302 #define MAX_WIDTH (LCD_WIDTH/TileSize)
303 int height = MAX_HEIGHT;
304 int width = MAX_WIDTH;
305 int top;
306 int left;
308 /* The Minefield. Caution it is defined as Y, X! Not the opposite. */
309 tile minefield[MAX_HEIGHT][MAX_WIDTH];
311 /* total number of mines on the game */
312 int mine_num = 0;
314 /* percentage of mines on minefield used during generation */
315 int p = 16;
317 /* number of tiles left on the game */
318 int tiles_left;
320 /* number of used flags on the game */
321 int flags_used;
323 /* Because mines are set after the first move... */
324 bool no_mines = true;
326 /* We need a stack (created on discover()) for the cascade algorithm. */
327 int stack_pos = 0;
329 /* a usefull string for snprintf */
330 char str[30];
332 #ifdef HAVE_TOUCHSCREEN
334 #include "lib/touchscreen.h"
335 static struct ts_raster mine_raster = { 0, 0, MAX_WIDTH, MAX_HEIGHT, TileSize, TileSize };
336 #endif
339 void push( int *stack, int y, int x )
341 if( stack_pos <= height*width )
343 stack[++stack_pos] = y;
344 stack[++stack_pos] = x;
348 /* Unveil tiles and push them to stack if they are empty. */
349 void unveil( int *stack, int y, int x )
351 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
352 || minefield[y][x].known
353 || minefield[y][x].mine || minefield[y][x].flag ) return;
355 minefield[y][x].known = 1;
357 if( minefield[y][x].neighbors == 0 )
358 push( stack, y, x );
361 void discover( int y, int x )
363 int stack[height*width];
365 /* Selected tile. */
366 if( x < 0 || y < 0 || x > width - 1 || y > height - 1
367 || minefield[y][x].known
368 || minefield[y][x].mine || minefield[y][x].flag ) return;
370 minefield[y][x].known = 1;
371 /* Exit if the tile is not empty. (no mines nearby) */
372 if( minefield[y][x].neighbors ) return;
374 push( stack, y, x );
376 /* Scan all nearby tiles. If we meet a tile with a number we just unveil
377 * it. If we meet an empty tile, we push the location in stack. For each
378 * location in stack we do the same thing. (scan again all nearby tiles)
380 while( stack_pos )
382 /* Pop x, y from stack. */
383 x = stack[stack_pos--];
384 y = stack[stack_pos--];
386 unveil( stack, y-1, x-1 );
387 unveil( stack, y-1, x );
388 unveil( stack, y-1, x+1 );
389 unveil( stack, y, x+1 );
390 unveil( stack, y+1, x+1 );
391 unveil( stack, y+1, x );
392 unveil( stack, y+1, x-1 );
393 unveil( stack, y, x-1 );
397 /* Reset the whole board for a new game. */
398 void minesweeper_init( void )
400 int i,j;
402 for( i = 0; i < MAX_HEIGHT; i++ )
404 for( j = 0; j < MAX_WIDTH; j++ )
406 minefield[i][j].known = 0;
407 minefield[i][j].flag = 0;
408 minefield[i][j].mine = 0;
409 minefield[i][j].neighbors = 0;
412 no_mines = true;
413 tiles_left = width*height;
417 /* put mines on the mine field */
418 /* there is p% chance that a tile is a mine */
419 /* if the tile has coordinates (x,y), then it can't be a mine */
420 void minesweeper_putmines( int p, int x, int y )
422 int i,j;
424 mine_num = 0;
425 for( i = 0; i < height; i++ )
427 for( j = 0; j < width; j++ )
429 if( rb->rand()%100 < p && !( y==i && x==j ) )
431 minefield[i][j].mine = 1;
432 mine_num++;
434 else
436 minefield[i][j].mine = 0;
438 minefield[i][j].neighbors = 0;
442 /* we need to compute the neighbor element for each tile */
443 for( i = 0; i < height; i++ )
445 for( j = 0; j < width; j++ )
447 if( i > 0 )
449 if( j > 0 )
450 minefield[i][j].neighbors += minefield[i-1][j-1].mine;
451 minefield[i][j].neighbors += minefield[i-1][j].mine;
452 if( j < width - 1 )
453 minefield[i][j].neighbors += minefield[i-1][j+1].mine;
455 if( j > 0 )
456 minefield[i][j].neighbors += minefield[i][j-1].mine;
457 if( j < width - 1 )
458 minefield[i][j].neighbors += minefield[i][j+1].mine;
459 if( i < height - 1 )
461 if( j > 0 )
462 minefield[i][j].neighbors += minefield[i+1][j-1].mine;
463 minefield[i][j].neighbors += minefield[i+1][j].mine;
464 if( j < width - 1 )
465 minefield[i][j].neighbors += minefield[i+1][j+1].mine;
470 no_mines = false;
472 /* In case the user is lucky and there are no mines positioned. */
473 if( !mine_num && height*width != 1 )
475 minesweeper_putmines(p, x, y);
479 /* A function that will uncover all the board, when the user wins or loses.
480 can easily be expanded, (just a call assigned to a button) as a solver. */
481 void mine_show( void )
483 int i, j, button;
485 for( i = 0; i < height; i++ )
487 for( j = 0; j < width; j++ )
489 if( minefield[i][j].mine )
491 if( minefield[i][j].known )
493 draw_tile( ExplodedMine, j, i );
495 else
497 draw_tile( Mine, j, i );
500 else
502 draw_tile( minefield[i][j].neighbors, j, i );
506 rb->lcd_update();
509 button = rb->button_get(true);
510 while( ( button == BUTTON_NONE )
511 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
512 #ifdef HAVE_TOUCHSCREEN
513 button = BUTTON_NONE;
514 #endif
517 int count_tiles_left( void )
519 int tiles_left = 0;
520 int i, j;
521 for( i = 0; i < height; i++ )
522 for( j = 0; j < width; j++ )
523 if( minefield[i][j].known == 0 )
524 tiles_left++;
525 return tiles_left;
528 int count_flags( void )
530 int flags_used = 0;
531 int i, j;
532 for( i = 0; i < height; i++ )
533 for( j = 0; j < width; j++ )
534 if( minefield[i][j].flag == 1 )
535 flags_used++;
536 return flags_used;
539 /* welcome screen where player can chose mine percentage */
540 enum minesweeper_status menu( void )
542 int selection, result = MINESWEEPER_QUIT;
543 bool menu_quit = false;
545 MENUITEM_STRINGLIST( menu, "Minesweeper Menu", NULL, "Play Minesweeper",
546 "Mine Percentage", "Number of Rows",
547 "Number of Columns", "Quit" );
549 #ifdef HAVE_LCD_COLOR
550 rb->lcd_set_foreground( rb->global_settings->fg_color );
551 rb->lcd_set_background( rb->global_settings->bg_color );
552 #endif
554 while( !menu_quit )
556 switch( rb->do_menu( &menu, &selection, NULL, false ) )
558 case 0:
559 result = MINESWEEPER_WIN; /* start playing */
560 menu_quit = true;
561 break;
563 case 1:
564 rb->set_int( "Mine Percentage", "%", UNIT_INT, &p, NULL,
565 1, 2, 98, NULL );
566 break;
568 case 2:
569 rb->set_int( "Number of Rows", "", UNIT_INT, &height, NULL,
570 1, 1, MAX_HEIGHT, NULL );
571 break;
573 case 3:
574 rb->set_int( "Number of Columns", "", UNIT_INT, &width, NULL,
575 1, 1, MAX_WIDTH, NULL );
576 break;
578 default:
579 result = MINESWEEPER_QUIT; /* quit program */
580 menu_quit = true;
581 break;
585 return result;
588 /* the big and ugly game function */
589 enum minesweeper_status minesweeper( void )
591 int i, j;
592 int button;
593 int lastbutton = BUTTON_NONE;
595 /* the cursor coordinates */
596 int x=0, y=0;
599 * Show the menu
601 if( ( i = menu() ) != MINESWEEPER_WIN ) return i;
604 * Init game
606 top = (LCD_HEIGHT-height*TileSize)/2;
607 left = (LCD_WIDTH-width*TileSize)/2;
609 #ifdef HAVE_TOUCHSCREEN
610 mine_raster.tl_x = left;
611 mine_raster.tl_y = top;
612 mine_raster.width = width*TileSize;
613 mine_raster.height = height*TileSize;
614 #endif
616 rb->srand( *rb->current_tick );
617 minesweeper_init();
618 x = 0;
619 y = 0;
622 * Play
624 while( true )
627 /* clear the screen buffer */
628 #ifdef HAVE_LCD_COLOR
629 rb->lcd_set_background( BackgroundColor );
630 #endif
631 rb->lcd_clear_display();
633 /* display the mine field */
634 for( i = 0; i < height; i++ )
636 for( j = 0; j < width; j++ )
638 if( minefield[i][j].known )
640 draw_tile( minefield[i][j].neighbors, j, i );
642 else if(minefield[i][j].flag)
644 draw_tile( Flag, j, i );
646 else
648 draw_tile( Unknown, j, i );
653 /* display the cursor */
654 invert_tile( x, y );
656 /* update the screen */
657 rb->lcd_update();
659 button = rb->button_get(true);
660 #ifdef HAVE_TOUCHSCREEN
661 if(button & BUTTON_TOUCHSCREEN)
663 struct ts_raster_result res;
664 if(touchscreen_map_raster(&mine_raster, rb->button_get_data() >> 16, rb->button_get_data() & 0xffff, &res) == 1)
666 button &= ~BUTTON_TOUCHSCREEN;
667 lastbutton &= ~BUTTON_TOUCHSCREEN;
669 if(button & BUTTON_REPEAT && lastbutton != MINESWP_TOGGLE && lastbutton ^ BUTTON_REPEAT)
670 button = MINESWP_TOGGLE;
671 else if(button == BUTTON_REL && lastbutton ^ BUTTON_REPEAT)
672 button = MINESWP_DISCOVER;
673 else
674 button |= BUTTON_TOUCHSCREEN;
676 x = res.x;
677 y = res.y;
680 #endif
681 switch(button)
683 /* quit minesweeper (you really shouldn't use this button ...) */
684 #ifdef MINESWP_RC_QUIT
685 case MINESWP_RC_QUIT:
686 #endif
687 case MINESWP_QUIT:
688 return MINESWEEPER_QUIT;
690 /* move cursor left */
691 case MINESWP_LEFT:
692 case MINESWP_LEFT|BUTTON_REPEAT:
693 x = ( x + width - 1 )%width;
694 break;
696 /* move cursor right */
697 case MINESWP_RIGHT:
698 case MINESWP_RIGHT|BUTTON_REPEAT:
699 x = ( x + 1 )%width;
700 break;
702 /* move cursor down */
703 case MINESWP_DOWN:
704 case MINESWP_DOWN|BUTTON_REPEAT:
705 y = ( y + 1 )%height;
706 break;
708 /* move cursor up */
709 case MINESWP_UP:
710 case MINESWP_UP|BUTTON_REPEAT:
711 y = ( y + height - 1 )%height;
712 break;
714 /*move cursor though the entire field*/
715 #ifdef MINESWP_SCROLLWHEEL
716 case MINESWP_NEXT:
717 case MINESWP_NEXT|BUTTON_REPEAT:
718 if (x == width -1 ) {
719 y = ( y + 1 )%height;
721 x = ( x + 1 )%width;
722 break;
724 case MINESWP_PREV:
725 case MINESWP_PREV|BUTTON_REPEAT:
726 if (x == 0) {
727 y = ( y + height - 1 )%height;
729 x = ( x + width - 1 )%width;
730 break;
731 #endif
732 /* discover a tile (and it's neighbors if .neighbors == 0) */
733 case MINESWP_DISCOVER:
734 #ifdef MINESWP_DISCOVER2
735 case MINESWP_DISCOVER2:
736 #endif
737 if( minefield[y][x].flag ) break;
738 /* we put the mines on the first "click" so that you don't
739 * lose on the first "click" */
740 if( tiles_left == width*height && no_mines )
741 minesweeper_putmines(p,x,y);
743 discover(y, x);
745 if( minefield[y][x].mine )
747 minefield[y][x].known = 1;
748 return MINESWEEPER_LOSE;
750 tiles_left = count_tiles_left();
751 if( tiles_left == mine_num )
753 return MINESWEEPER_WIN;
755 break;
757 /* toggle flag under cursor */
758 case MINESWP_TOGGLE:
759 #ifdef MINESWP_TOGGLE_PRE
760 if( lastbutton != MINESWP_TOGGLE_PRE )
761 break;
762 #endif
763 #ifdef MINESWP_TOGGLE2
764 case MINESWP_TOGGLE2:
765 #endif
766 minefield[y][x].flag = ( minefield[y][x].flag + 1 )%2;
767 break;
769 /* show how many mines you think you have found and how many
770 * there really are on the game */
771 case MINESWP_INFO:
772 if( no_mines )
773 break;
774 flags_used = count_flags();
775 if (flags_used == 1) {
776 rb->splashf( HZ*2, "You marked 1 field. There are %d mines.",
777 mine_num );
779 else
781 rb->splashf( HZ*2, "You marked %d fields. There are %d mines.",
782 flags_used, mine_num );
784 break;
786 default:
787 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
788 return MINESWEEPER_USB;
789 break;
791 if( button != BUTTON_NONE )
792 lastbutton = button;
797 /* plugin entry point */
798 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
800 bool exit = false;
802 (void)parameter;
803 rb = api;
804 #if LCD_DEPTH > 1
805 rb->lcd_set_backdrop(NULL);
806 #endif
808 while( !exit )
810 switch( minesweeper() )
812 case MINESWEEPER_WIN:
813 rb->splash( HZ, "You Win!" );
814 rb->lcd_clear_display();
815 mine_show();
816 break;
818 case MINESWEEPER_LOSE:
819 rb->splash( HZ, "You Lose!" );
820 rb->lcd_clear_display();
821 mine_show();
822 break;
824 case MINESWEEPER_USB:
825 return PLUGIN_USB_CONNECTED;
827 case MINESWEEPER_QUIT:
828 exit = true;
829 break;
831 default:
832 break;
836 return PLUGIN_OK;
839 #endif