Change i2c config on e200. Seems to speed things up somewhat.
[kugel-rb.git] / apps / plugins / solitaire.c
blob9dbeaebfa428702e648dd99c6bea184b0e9a345c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004-2006 Antoine Cellerier <dionoea @t videolan d.t org>
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 /*****************************************************************************
21 Solitaire by dionoea
22 Graphics & Fix Bugs by Ben Basha
24 use arrows to move the cursor
25 use ON to select cards, move cards, reveal hidden cards, ...
26 use PLAY to move a card from the remains' stack to the top of the cursor
27 use F1 to put card under cursor on one of the 4 final stacks
28 use F2 to un-select card if a card was selected, else draw 3 new cards
29 out of the remains' stack
30 use F3 to put card on top of the remains' stack on one of the 4 final stacks
32 *****************************************************************************/
34 #include "plugin.h"
35 #include "playback_control.h"
36 #include "configfile.h"
37 #include "button.h"
38 #include "lcd.h"
39 #include "oldmenuapi.h"
41 #ifdef HAVE_LCD_BITMAP
43 PLUGIN_HEADER
45 static struct plugin_api* rb;
46 #define min(a,b) (a<b?a:b)
48 /**
49 * Key definitions
52 #if CONFIG_KEYPAD == RECORDER_PAD
53 # define SOL_QUIT BUTTON_OFF
54 # define SOL_UP BUTTON_UP
55 # define SOL_DOWN BUTTON_DOWN
56 # define SOL_LEFT BUTTON_LEFT
57 # define SOL_RIGHT BUTTON_RIGHT
58 # define SOL_MOVE BUTTON_ON
59 # define SOL_DRAW BUTTON_F1
60 # define SOL_REM2CUR BUTTON_PLAY
61 # define SOL_CUR2STACK BUTTON_F2
62 # define SOL_REM2STACK BUTTON_F3
63 # define HK_MOVE "ON"
64 # define HK_DRAW "F1"
65 # define HK_REM2CUR "PLAY"
66 # define HK_CUR2STACK "F2"
67 # define HK_REM2STACK "F3"
69 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
70 # define SOL_QUIT BUTTON_OFF
71 # define SOL_UP BUTTON_UP
72 # define SOL_DOWN BUTTON_DOWN
73 # define SOL_LEFT BUTTON_LEFT
74 # define SOL_RIGHT BUTTON_RIGHT
75 # define SOL_MOVE BUTTON_ON
76 # define SOL_DRAW BUTTON_F1
77 # define SOL_REM2CUR BUTTON_SELECT
78 # define SOL_CUR2STACK BUTTON_F2
79 # define SOL_REM2STACK BUTTON_F3
80 # define HK_MOVE "ON"
81 # define HK_DRAW "F1"
82 # define HK_REM2CUR "SELECT"
83 # define HK_CUR2STACK "F2"
84 # define HK_REM2STACK "F3"
86 #elif CONFIG_KEYPAD == ONDIO_PAD
87 # define SOL_QUIT BUTTON_OFF
88 # define SOL_UP_PRE BUTTON_UP
89 # define SOL_UP (BUTTON_UP | BUTTON_REL)
90 # define SOL_DOWN_PRE BUTTON_DOWN
91 # define SOL_DOWN (BUTTON_DOWN | BUTTON_REL)
92 # define SOL_LEFT_PRE BUTTON_LEFT
93 # define SOL_LEFT (BUTTON_LEFT | BUTTON_REL)
94 # define SOL_RIGHT_PRE BUTTON_RIGHT
95 # define SOL_RIGHT (BUTTON_RIGHT | BUTTON_REL)
96 # define SOL_MOVE_PRE BUTTON_MENU
97 # define SOL_MOVE (BUTTON_MENU | BUTTON_REL)
98 # define SOL_DRAW_PRE BUTTON_MENU
99 # define SOL_DRAW (BUTTON_MENU | BUTTON_REPEAT)
100 # define SOL_REM2CUR_PRE BUTTON_DOWN
101 # define SOL_REM2CUR (BUTTON_DOWN | BUTTON_REPEAT)
102 # define SOL_CUR2STACK_PRE BUTTON_UP
103 # define SOL_CUR2STACK (BUTTON_UP | BUTTON_REPEAT)
104 # define SOL_REM2STACK_PRE BUTTON_RIGHT
105 # define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_REPEAT)
106 # define HK_MOVE "MODE"
107 # define HK_DRAW "MODE.."
108 # define HK_REM2CUR "DOWN.."
109 # define HK_CUR2STACK "UP.."
110 # define HK_REM2STACK "RIGHT.."
112 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
113 (CONFIG_KEYPAD == IRIVER_H300_PAD)
114 # define SOL_QUIT BUTTON_OFF
115 # define SOL_UP BUTTON_UP
116 # define SOL_DOWN BUTTON_DOWN
117 # define SOL_LEFT BUTTON_LEFT
118 # define SOL_RIGHT BUTTON_RIGHT
119 # define SOL_MOVE_PRE BUTTON_SELECT
120 # define SOL_MOVE (BUTTON_SELECT | BUTTON_REL)
121 # define SOL_DRAW BUTTON_MODE
122 # define SOL_REM2CUR (BUTTON_LEFT | BUTTON_ON)
123 # define SOL_CUR2STACK_PRE BUTTON_SELECT
124 # define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT)
125 # define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_ON)
126 # define SOL_REM BUTTON_REC
127 # define SOL_RC_QUIT BUTTON_RC_STOP
128 # define HK_MOVE "NAVI"
129 # define HK_DRAW "A-B"
130 # define HK_REM2CUR "PLAY+LEFT"
131 # define HK_CUR2STACK "NAVI.."
132 # define HK_REM2STACK "PLAY+RIGHT"
134 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) ||(CONFIG_KEYPAD == IPOD_3G_PAD)
135 # define SOL_QUIT (BUTTON_SELECT | BUTTON_MENU)
136 # define SOL_UP BUTTON_SCROLL_BACK
137 # define SOL_DOWN BUTTON_SCROLL_FWD
138 # define SOL_LEFT_PRE BUTTON_LEFT
139 # define SOL_LEFT (BUTTON_LEFT | BUTTON_REL)
140 # define SOL_RIGHT_PRE BUTTON_RIGHT
141 # define SOL_RIGHT (BUTTON_RIGHT | BUTTON_REL)
142 # define SOL_MOVE_PRE BUTTON_SELECT
143 # define SOL_MOVE (BUTTON_SELECT | BUTTON_REL)
144 # define SOL_DRAW_PRE BUTTON_MENU
145 # define SOL_DRAW (BUTTON_MENU | BUTTON_REL)
146 # define SOL_REM2CUR BUTTON_PLAY
147 # define SOL_CUR2STACK_PRE BUTTON_MENU
148 # define SOL_CUR2STACK (BUTTON_MENU | BUTTON_REPEAT)
149 # define SOL_REM2STACK_PRE BUTTON_RIGHT
150 # define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_REPEAT)
151 # define HK_UD "SCROLL U/D"
152 # define HK_MOVE "SELECT"
153 # define HK_DRAW "MENU"
154 # define HK_REM2CUR "PLAY"
155 # define HK_CUR2STACK "MENU.."
156 # define HK_REM2STACK "RIGHT.."
158 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
159 # define SOL_QUIT BUTTON_POWER
160 # define SOL_UP BUTTON_UP
161 # define SOL_DOWN BUTTON_DOWN
162 # define SOL_LEFT BUTTON_LEFT
163 # define SOL_RIGHT BUTTON_RIGHT
164 # define SOL_MOVE_PRE BUTTON_SELECT
165 # define SOL_MOVE (BUTTON_SELECT | BUTTON_REL)
166 # define SOL_DRAW_PRE BUTTON_PLAY
167 # define SOL_DRAW (BUTTON_PLAY | BUTTON_REL)
168 # define SOL_REM2CUR_PRE BUTTON_PLAY
169 # define SOL_REM2CUR (BUTTON_PLAY | BUTTON_REPEAT)
170 # define SOL_CUR2STACK_PRE BUTTON_SELECT
171 # define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT)
172 # define SOL_REM2STACK BUTTON_REC
173 # define HK_MOVE "SELECT"
174 # define HK_DRAW "PLAY"
175 # define HK_REM2CUR "PLAY.."
176 # define HK_CUR2STACK "SELECT.."
177 # define HK_REM2STACK "REC"
179 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
180 # define SOL_QUIT BUTTON_A
181 # define SOL_UP BUTTON_UP
182 # define SOL_DOWN BUTTON_DOWN
183 # define SOL_LEFT BUTTON_LEFT
184 # define SOL_RIGHT BUTTON_RIGHT
185 # define SOL_MOVE_PRE BUTTON_SELECT
186 # define SOL_MOVE (BUTTON_SELECT | BUTTON_REL)
187 # define SOL_DRAW BUTTON_MENU
188 # define SOL_REM2CUR (BUTTON_LEFT | BUTTON_POWER)
189 # define SOL_CUR2STACK (BUTTON_SELECT | BUTTON_REPEAT)
190 # define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_POWER)
191 # define HK_MOVE "SELECT"
192 # define HK_DRAW "MENU"
193 # define HK_REM2CUR "POWER+LEFT"
194 # define HK_CUR2STACK "SELECT.."
195 # define HK_REM2STACK "POWER+RIGHT"
197 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
198 # define SOL_QUIT BUTTON_POWER
199 # define SOL_UP BUTTON_UP
200 # define SOL_DOWN BUTTON_DOWN
201 # define SOL_LEFT BUTTON_SCROLL_UP
202 # define SOL_RIGHT BUTTON_SCROLL_DOWN
203 # define SOL_MOVE BUTTON_SELECT
204 # define SOL_DRAW BUTTON_REC
205 # define SOL_REM2CUR BUTTON_LEFT
206 # define SOL_CUR2STACK_PRE BUTTON_REC
207 # define SOL_CUR2STACK (BUTTON_REC | BUTTON_RIGHT)
208 # define SOL_REM2STACK BUTTON_RIGHT
209 # define HK_MOVE "SELECT"
210 # define HK_DRAW "REC"
211 # define HK_REM2CUR "LEFT"
212 # define HK_CUR2STACK "DOUBLE SELECT"
213 # define HK_REM2STACK "RIGHT"
215 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
216 # define SOL_QUIT BUTTON_POWER
217 # define SOL_UP BUTTON_SCROLL_UP
218 # define SOL_DOWN BUTTON_SCROLL_DOWN
219 # define SOL_LEFT_PRE BUTTON_LEFT
220 # define SOL_LEFT (BUTTON_LEFT | BUTTON_REL)
221 # define SOL_RIGHT_PRE BUTTON_RIGHT
222 # define SOL_RIGHT (BUTTON_RIGHT | BUTTON_REL)
223 # define SOL_MOVE BUTTON_PLAY
224 # define SOL_DRAW_PRE BUTTON_LEFT
225 # define SOL_DRAW (BUTTON_LEFT | BUTTON_REPEAT)
226 # define SOL_REM2CUR BUTTON_FF
227 # define SOL_CUR2STACK BUTTON_REW
228 # define SOL_REM2STACK_PRE BUTTON_RIGHT
229 # define SOL_REM2STACK (BUTTON_RIGHT | BUTTON_REPEAT)
230 # define HK_MOVE "PLAY"
231 # define HK_DRAW "LEFT.."
232 # define HK_REM2CUR "FF"
233 # define HK_CUR2STACK "REW"
234 # define HK_REM2STACK "RIGHT.."
236 #else
237 # error "Unknown keypad"
238 #endif
240 #define HK_LR "LEFT/RIGHT"
241 #ifndef HK_UD
242 # define HK_UD "UP/DOWN"
243 #endif
246 * Help strings
249 static int helplines;
250 static int displaylines;
252 static char helptext[] =
253 /* Use single spaces only! Close each line with one \0. */
254 "-- Navigation --\0"
255 HK_LR ": Move the cursor to the previous/ next column.\0"
256 HK_UD ": Move the cursor up/ down in the column.\0"
257 HK_MOVE ": Select cards, move cards, reveal hidden cards...\0"
258 HK_DRAW ": Deselect a card if it was selected. Else draw new card(s) from the remains stack.\0"
259 "-- Shortcuts --\0"
260 HK_REM2CUR ": Put the card on top of the remains stack on top of the cursor.\0"
261 HK_CUR2STACK ": Put the card under the cursor on one of the 4 final stacks.\0"
262 HK_REM2STACK ": Put the card on top of the remains stack on one of the 4 final stacks.\0"
266 * Misc constants, graphics and other defines
269 #include "card_back.h"
270 #include "card_deck.h"
271 #include "solitaire_suitsi.h"
273 #define CARD_GFX_WIDTH BMPWIDTH_card_back
274 #define CARD_GFX_HEIGHT BMPHEIGHT_card_back
275 #define CARD_WIDTH (BMPWIDTH_card_back+2)
276 #define CARD_HEIGHT (BMPHEIGHT_card_back+2)
278 #if LCD_WIDTH >= 320
279 # define MARGIN 4
280 # define LARGE_CARD
281 # define SYMBOL_HEIGHT 12
282 #elif LCD_WIDTH >= 220
283 # define MARGIN 3
284 # define LARGE_CARD
285 # define SYMBOL_HEIGHT 12
286 #elif LCD_WIDTH >= 160
287 # define MARGIN 2
288 # define SYMBOL_HEIGHT 11
289 #elif LCD_WIDTH >= 128
290 # define MARGIN 1
291 # define SYMBOL_HEIGHT 10
292 #else
293 # define MARGIN 0
294 # define SYMBOL_HEIGHT 8
295 #endif
297 #define CARD_START (CARD_HEIGHT+2*MARGIN+1)
299 /* background color */
300 #ifdef HAVE_LCD_COLOR
301 # define BACKGROUND_COLOR LCD_RGBPACK(0,157,0)
302 # define FRAME_COLOR LCD_RGBPACK(23,119,218)
303 #elif LCD_DEPTH > 1
304 # define BACKGROUND_COLOR LCD_WHITE
305 # define FRAME_COLOR LCD_BLACK
306 #endif
309 #define CONFIG_FILENAME "sol.cfg"
311 #define NOT_A_CARD -1
313 /* number of cards per suit */
314 #define CARDS_PER_SUIT 13
316 /* number of suits */
317 #define SUITS 4
319 #define NUM_CARDS ( CARDS_PER_SUIT * SUITS )
321 /* number of columns */
322 #define COL_NUM 7
324 /* pseudo column numbers to be used for cursor coordinates */
325 /* columns COL_NUM to COL_NUM + SUITS - 1 correspond to the final stacks */
326 #define STACKS_COL COL_NUM
327 /* column COL_NUM + SUITS corresponds to the remains' stack */
328 #define REM_COL (STACKS_COL + SUITS)
330 #define NOT_A_COL -1
332 typedef struct
334 signed char suit;
335 signed char num;
336 bool known : 1;
337 bool used : 1; /* this is what is used when dealing cards */
338 signed char next;
339 } card_t;
343 * LCD card drawing routines
346 static void draw_cursor( int x, int y )
348 rb->lcd_set_drawmode( DRMODE_COMPLEMENT );
349 rb->lcd_fillrect( x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT );
350 #ifdef LARGE_CARD
351 rb->lcd_drawpixel( x+1, y+1 );
352 rb->lcd_drawpixel( x+1, y+CARD_HEIGHT-2 );
353 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+1 );
354 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+CARD_HEIGHT-2 );
355 #endif
356 rb->lcd_set_drawmode( DRMODE_SOLID );
359 /* Draw a card's border, select it if it's selected and draw the cursor
360 * if the cursor is currently over the card */
361 static void draw_card_ext( int x, int y, bool selected, bool cursor )
363 #if LCD_DEPTH > 1
364 int oldfg = rb->lcd_get_foreground();
366 rb->lcd_set_foreground( LCD_BLACK );
367 #endif
368 #ifdef LARGE_CARD
369 rb->lcd_hline( x+2, x+CARD_WIDTH-3, y );
370 rb->lcd_hline( x+2, x+CARD_WIDTH-3, y+CARD_HEIGHT-1 );
371 rb->lcd_vline( x, y+2, y+CARD_HEIGHT-3 );
372 rb->lcd_vline( x+CARD_WIDTH-1, y+2, y+CARD_HEIGHT-3 );
373 rb->lcd_drawpixel( x+1, y+1 );
374 rb->lcd_drawpixel( x+1, y+CARD_HEIGHT-2 );
375 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+1 );
376 rb->lcd_drawpixel( x+CARD_WIDTH-2, y+CARD_HEIGHT-2 );
377 #else
378 rb->lcd_hline( x+1, x+CARD_WIDTH-2, y );
379 rb->lcd_hline( x+1, x+CARD_WIDTH-2, y+CARD_HEIGHT-1 );
380 rb->lcd_vline( x, y+1, y+CARD_HEIGHT-2 );
381 rb->lcd_vline( x+CARD_WIDTH-1, y+1, y+CARD_HEIGHT-2 );
382 #endif
384 if( selected )
386 #if LCD_DEPTH > 1
387 rb->lcd_set_foreground( FRAME_COLOR );
388 #endif
389 rb->lcd_drawrect( x+1, y+1, CARD_WIDTH-2, CARD_HEIGHT-2 );
390 #ifdef LARGE_CARD
391 rb->lcd_drawrect( x+2, y+2, CARD_WIDTH-4, CARD_HEIGHT-4 );
392 #endif
394 #if LCD_DEPTH > 1
395 rb->lcd_set_foreground( oldfg );
396 #endif
398 if( cursor )
400 draw_cursor( x, y );
404 /* Draw a card's inner graphics */
405 static void draw_card( card_t *card, int x, int y,
406 bool selected, bool cursor )
408 if( card->known )
410 rb->lcd_bitmap_part( card_deck, CARD_GFX_WIDTH * card->num,
411 CARD_GFX_HEIGHT * card->suit, BMPWIDTH_card_deck,
412 x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT );
414 else
416 rb->lcd_bitmap( card_back, x+1, y+1,
417 CARD_GFX_WIDTH, CARD_GFX_HEIGHT );
419 draw_card_ext( x, y, selected, cursor );
422 /* Draw an empty stack */
423 static void draw_empty_stack( int s, int x, int y, bool cursor )
425 rb->lcd_bitmap_part( solitaire_suitsi, 0,
426 CARD_GFX_HEIGHT * s, BMPWIDTH_solitaire_suitsi,
427 x+1, y+1, CARD_GFX_WIDTH, CARD_GFX_HEIGHT );
429 draw_card_ext( x, y, false, cursor );
433 * Help
436 static void init_help(void)
438 int lines = 0;
439 int w_space, w, h;
440 int para_len;
441 char *para = helptext;
443 rb->lcd_getstringsize(" ", &w_space, &h);
444 displaylines = LCD_HEIGHT / h;
445 para_len = rb->strlen(para);
447 while (para_len)
449 bool first = true;
450 int x = 0;
451 char *next, *store;
453 next = rb->strtok_r(para, " ", &store);
454 while (next)
456 rb->lcd_getstringsize(next, &w, NULL);
457 if (!first)
459 if (x + w > LCD_WIDTH)
461 lines++;
462 x = 0;
464 else
465 next[-1] = ' '; /* re-concatenate string */
467 else
468 first = false;
470 x += w + w_space;
471 next = rb->strtok_r(NULL, " ", &store);
474 lines++;
475 para += para_len + 1;
476 para_len = rb->strlen(para);
478 helplines = lines;
481 enum help { HELP_QUIT, HELP_USB };
483 /* help for the not so intuitive interface */
484 enum help solitaire_help( void )
486 int start = 0;
487 int button;
488 int lastbutton = BUTTON_NONE;
489 bool fixed = (displaylines >= helplines);
491 while( true )
493 char *text = helptext;
494 int line = fixed ? (displaylines - helplines) / 2 : 0;
495 int i;
497 rb->lcd_clear_display();
499 for (i = 0; i < start + displaylines; i++)
501 if (i >= start)
502 rb->lcd_puts(0, line++, text);
503 text += rb->strlen(text) + 1;
505 rb->lcd_update();
507 button = rb->button_get( true );
508 switch( button )
510 case SOL_UP:
511 #ifdef SOL_UP_PRE
512 if( lastbutton != SOL_UP_PRE )
513 break;
514 #else
515 case SOL_UP|BUTTON_REPEAT:
516 #endif
517 if (!fixed && start > 0)
518 start--;
519 break;
521 case SOL_DOWN:
522 #ifdef SOL_DOWN_PRE
523 if( lastbutton != SOL_DOWN_PRE )
524 break;
525 #else
526 case SOL_DOWN|BUTTON_REPEAT:
527 #endif
528 if (!fixed && start < helplines - displaylines)
529 start++;
530 break;
532 #ifdef SOL_RC_QUIT
533 case SOL_RC_QUIT:
534 #endif
535 case SOL_QUIT:
536 return HELP_QUIT;
538 default:
539 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
540 return HELP_USB;
541 break;
543 if( button != BUTTON_NONE )
544 lastbutton = button;
549 * Custom menu / options
552 #define CFGFILE_VERSION 0
554 struct sol_config {
555 int draw_type;
556 int auto_unhide;
559 struct sol_config sol_disk = {0, 0};
560 struct sol_config sol;
562 static struct configdata config[] = {
563 { TYPE_INT, 0, 1, &sol_disk.draw_type, "draw_type", NULL, NULL },
564 { TYPE_INT, 0, 1, &sol_disk.auto_unhide, "auto_unhide", NULL, NULL }
567 char draw_option_string[32];
568 char unhide_option_string[32];
570 static void create_draw_option_string(void)
572 if (sol.draw_type == 0)
573 rb->strcpy(draw_option_string, "Draw Three Cards");
574 else
575 rb->strcpy(draw_option_string, "Draw One Card");
578 static void create_unhide_option_string(void)
580 if (sol.auto_unhide == 0)
581 rb->strcpy(unhide_option_string, "Unhide manually");
582 else
583 rb->strcpy(unhide_option_string, "Unhide automatically");
586 void solitaire_init(void);
588 /* menu return codes */
589 enum { MENU_RESUME, MENU_QUIT, MENU_USB };
591 int solitaire_menu(bool in_game)
593 int m;
594 int result = -1;
595 int i = 0;
597 struct menu_item items[6];
599 if (in_game)
601 items[i++].desc = "Resume Game";
602 items[i++].desc = "Restart Game";
604 else
606 items[i++].desc = "Start Game";
607 items[i++].desc = draw_option_string;
609 items[i++].desc = unhide_option_string;
610 items[i++].desc = "Help";
611 items[i++].desc = "Audio Playback";
612 items[i++].desc = "Quit";
614 create_draw_option_string();
615 create_unhide_option_string();
616 m = menu_init(rb, items, i, NULL, NULL, NULL, NULL);
617 while (result < 0)
619 switch (menu_show(m))
621 case MENU_SELECTED_EXIT:
622 result = MENU_RESUME;
623 break;
625 case MENU_ATTACHED_USB:
626 result = MENU_USB;
627 break;
629 case 0:
630 result = MENU_RESUME;
631 break;
633 case 1:
634 if (in_game)
636 solitaire_init();
637 result = MENU_RESUME;
639 else
641 sol.draw_type = (sol.draw_type + 1) % 2;
642 create_draw_option_string();
644 break;
646 case 2:
647 sol.auto_unhide = (sol.auto_unhide + 1) % 2;
648 create_unhide_option_string();
649 break;
651 case 3:
652 rb->lcd_setmargins(0, 0);
653 if (solitaire_help() == HELP_USB)
654 result = MENU_USB;
655 break;
657 case 4:
658 playback_control(rb);
659 break;
661 case 5:
662 result = MENU_QUIT;
663 break;
666 menu_exit(m);
667 rb->lcd_setmargins(0, 0);
668 return result;
672 * Global variables
675 /* player's cursor */
676 int cur_card;
677 /* player's cursor column num */
678 int cur_col;
680 /* selected card */
681 int sel_card;
683 /* the deck */
684 card_t deck[ NUM_CARDS ];
686 /* the remaining cards */
687 /* first card of the remains' stack */
688 int rem;
689 /* upper visible card from the remains' stack */
690 int cur_rem;
691 /* number of cards drawn from the remains stack - 1 */
692 int count_rem;
693 /* number of cards per draw of the remains' stack */
694 int cards_per_draw;
696 /* the 7 game columns */
697 int cols[COL_NUM];
698 /* the 4 final stacks */
699 int stacks[SUITS];
702 * Card handling routines
705 int next_random_card( card_t *deck )
707 int i,r;
709 r = rb->rand()%(NUM_CARDS)+1;
710 i = 0;
712 while( r>0 )
714 i = (i + 1)%(NUM_CARDS);
715 if( !deck[i].used ) r--;
718 deck[i].used = true;
720 return i;
724 /* initialize the game */
725 void solitaire_init( void )
728 int c;
729 int i, j;
731 /* number of cards that are drawn on the remains' stack (by pressing F2) */
732 if( sol.draw_type == 0 )
734 cards_per_draw = 3;
736 else
738 cards_per_draw = 1;
741 /* init deck */
742 for( i=0; i<SUITS; i++ )
744 for( j=0; j<CARDS_PER_SUIT; j++ )
746 #define card deck[i*CARDS_PER_SUIT+j]
747 card.suit = i;
748 card.num = j;
749 card.known = true;
750 card.used = false;
751 card.next = NOT_A_CARD;
752 #undef card
756 /* deal the cards ... */
757 /* ... in the columns */
758 for( i=0; i<COL_NUM; i++ )
760 c = NOT_A_CARD;
761 for( j=0; j<=i; j++ )
763 if( c == NOT_A_CARD )
765 cols[i] = next_random_card( deck );
766 c = cols[i];
768 else
770 deck[c].next = next_random_card( deck );
771 c = deck[c].next;
773 if( j < i )
774 deck[c].known = false;
778 /* ... shuffle what's left of the deck */
779 rem = next_random_card(deck);
780 c = rem;
782 for( i=1; i < NUM_CARDS - COL_NUM * (COL_NUM + 1)/2; i++ )
784 deck[c].next = next_random_card( deck );
785 c = deck[c].next;
788 /* we now finished dealing the cards. The game can start ! (at last) */
790 /* init the stack */
791 for( i = 0; i<SUITS; i++ )
793 stacks[i] = NOT_A_CARD;
796 /* the cursor starts on upper left card */
797 cur_card = cols[0];
798 cur_col = 0;
800 /* no card is selected */
801 sel_card = NOT_A_CARD;
803 /* init the remainder */
804 cur_rem = NOT_A_CARD;
806 count_rem = -1;
809 /* find the column number in which 'card' can be found */
810 int find_card_col( int card )
812 int i;
813 int c;
815 if( card == NOT_A_CARD ) return NOT_A_COL;
817 for( i=0; i<COL_NUM; i++ )
819 c = cols[i];
820 while( c != NOT_A_CARD )
822 if( c == card ) return i;
823 c = deck[c].next;
827 for( i=0; i<SUITS; i++ )
829 c = stacks[i];
830 while( c != NOT_A_CARD )
832 if( c == card ) return STACKS_COL + i;
833 c = deck[c].next;
837 return REM_COL;
840 /* find the card preceding 'card' */
841 /* if it doesn't exist, return NOT_A_CARD */
842 int find_prev_card( int card ){
843 int i;
845 for( i=0; i < NUM_CARDS; i++ )
847 if( deck[i].next == card ) return i;
850 return NOT_A_CARD;
853 /* find the last card of a given column */
854 int find_last_card( int col )
856 int c;
858 if( col < COL_NUM )
860 c = cols[col];
862 else if( col < REM_COL )
864 c = stacks[col - STACKS_COL];
866 else
868 c = cur_rem;
871 if(c == NOT_A_CARD)
872 return c;
873 else
875 while(deck[c].next != NOT_A_CARD)
876 c = deck[c].next;
877 return c;
881 enum move { MOVE_OK, MOVE_NOT_OK };
883 enum move move_card( int dest_col, int src_card )
885 /* the column on which to take src_card */
886 int src_col;
888 /* the last card of dest_col */
889 int dest_card;
891 /* the card under src_card */
892 int src_card_prev;
894 /* you can't move no card (at least, it doesn't have any consequence) */
895 if( src_card == NOT_A_CARD ) return MOVE_NOT_OK;
896 /* you can't put a card back on the remains' stack */
897 if( dest_col == REM_COL ) return MOVE_NOT_OK;
898 /* you can't move an unknown card */
899 if( !deck[src_card].known ) return MOVE_NOT_OK;
901 src_col = find_card_col( src_card );
902 dest_card = find_last_card( dest_col );
903 src_card_prev = find_prev_card( src_card );
905 /* you can't move more than one card at a time from the final stack */
906 /* to the rest of the game */
907 if( src_col >= COL_NUM && src_col < REM_COL
908 && deck[src_card].next != NOT_A_CARD )
910 return MOVE_NOT_OK;
913 /* if we (that means dest) are on one of the 7 columns ... */
914 if( dest_col < COL_NUM )
916 /* ... check is we are on an empty color and that the src is a king */
917 if( dest_card == NOT_A_CARD
918 && deck[src_card].num == CARDS_PER_SUIT - 1 )
920 /* this is a winning combination */
921 cols[dest_col] = src_card;
923 /* ... or check if the cards follow one another and have
924 * different colorsuit */
925 else if(( deck[dest_card].suit + deck[src_card].suit)%2==1
926 && deck[dest_card].num == deck[src_card].num + 1 )
928 /* this is a winning combination */
929 deck[dest_card].next = src_card;
931 /* ... or, humpf, well that's not good news */
932 else
934 /* this is not a winning combination */
935 return MOVE_NOT_OK;
938 /* if we are on one of the 4 final stacks ... */
939 else if( dest_col < REM_COL )
941 /* ... check if we are on an empty stack... */
942 if( dest_card == NOT_A_CARD )
944 /* ... and the src is an ace and this is the correct final stack */
945 if( deck[src_card].num == 0
946 && deck[src_card].suit == dest_col - STACKS_COL )
948 /* this is a winning combination */
949 stacks[dest_col - STACKS_COL] = src_card;
951 else
953 /* this is not a winning combination */
954 return MOVE_NOT_OK;
957 else /* non-empty stack */
959 /* ...check if the cards follow one another, have the same suit and
960 * {that src has no .next element or is from the remains' stack} */
961 if( deck[dest_card].suit == deck[src_card].suit
962 && deck[dest_card].num + 1 == deck[src_card].num
963 && (deck[src_card].next == NOT_A_CARD || src_col == REM_COL) )
965 /* this is a winning combination */
966 deck[dest_card].next = src_card;
968 /* ... or, well that's not good news */
969 else
971 /* this is not a winning combination */
972 return MOVE_NOT_OK;
976 /* if we are on the remains' stack */
977 else
979 /* you can't move a card back to the remains' stack */
980 return MOVE_NOT_OK;
983 /* if the src card is from the remains' stack, we don't want to take
984 * the following cards */
985 if( src_col == REM_COL )
987 /* if src card is the first card from the stack */
988 if( src_card_prev == NOT_A_CARD )
990 rem = deck[src_card].next;
992 /* if src card is not the first card from the stack */
993 else
995 deck[src_card_prev].next = deck[src_card].next;
997 deck[src_card].next = NOT_A_CARD;
998 cur_rem = src_card_prev;
999 count_rem--;
1001 /* if the src card is from somewhere else, just take everything */
1002 else
1004 if( src_card_prev == NOT_A_CARD )
1006 if( src_col < COL_NUM )
1008 cols[src_col] = NOT_A_CARD;
1010 else
1012 stacks[src_col - STACKS_COL] = NOT_A_CARD;
1015 else
1017 deck[src_card_prev].next = NOT_A_CARD;
1018 if (sol.auto_unhide)
1020 deck[src_card_prev].known = true;
1024 sel_card = NOT_A_CARD;
1025 /* tada ! */
1026 return MOVE_OK;
1029 enum { SOLITAIRE_WIN, SOLITAIRE_QUIT, SOLITAIRE_USB };
1032 * Bouncing cards at the end of the game
1035 #define BC_ACCEL ((1<<16)*LCD_HEIGHT/128)
1036 #define BC_MYSPEED (6*BC_ACCEL)
1037 #define BC_MXSPEED (6*LCD_HEIGHT/128)
1039 int bouncing_cards( void )
1041 int i, j, x, vx, y, fp_y, fp_vy, button;
1043 /* flush the button queue */
1044 while( ( button = rb->button_get( false ) ) != BUTTON_NONE )
1046 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
1047 return SOLITAIRE_USB;
1050 /* fun stuff :) */
1051 for( i = CARDS_PER_SUIT-1; i>=0; i-- )
1053 for( j = 0; j < SUITS; j++ )
1055 x = LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*j+j+1;
1056 fp_y = MARGIN<<16;
1058 #if LCD_WIDTH > 200
1059 vx = rb->rand() % (4*BC_MXSPEED/3-2) - BC_MXSPEED;
1060 if( vx >= -1 )
1061 vx += 3;
1062 #else
1063 vx = rb->rand() % (4*BC_MXSPEED/3) - BC_MXSPEED;
1064 if( vx >= 0 )
1065 vx++;
1066 #endif
1068 fp_vy = -rb->rand() % BC_MYSPEED;
1070 while( x < LCD_WIDTH && x + CARD_WIDTH > 0 )
1072 fp_vy += BC_ACCEL;
1073 x += vx;
1074 fp_y += fp_vy;
1075 if( fp_y >= (LCD_HEIGHT-CARD_HEIGHT) << 16 )
1077 fp_vy = -fp_vy*4/5;
1078 fp_y = (LCD_HEIGHT-CARD_HEIGHT) << 16;
1080 y = fp_y >> 16;
1081 draw_card( &deck[j*CARDS_PER_SUIT+i], x, y,
1082 false, false );
1083 rb->lcd_update_rect( x<0?0:x, y<0?0:y,
1084 CARD_WIDTH, CARD_HEIGHT );
1086 button = rb->button_get_w_tmo( 2 );
1087 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
1088 return SOLITAIRE_USB;
1089 if( button == SOL_QUIT || button == SOL_MOVE )
1090 return SOLITAIRE_WIN;
1094 return SOLITAIRE_WIN;
1098 * The main game loop
1101 int solitaire( void )
1104 int i,j;
1105 int button, lastbutton = 0;
1106 int c,h,prevcard;
1107 int biggest_col_length;
1109 rb->srand( *rb->current_tick );
1110 switch( solitaire_menu(false) )
1112 case MENU_QUIT:
1113 return SOLITAIRE_QUIT;
1115 case MENU_USB:
1116 return SOLITAIRE_USB;
1118 solitaire_init();
1120 while( true )
1122 rb->lcd_clear_display();
1124 /* get the biggest column length so that display can be "optimized" */
1125 biggest_col_length = 0;
1127 for(i=0;i<COL_NUM;i++)
1129 j = 0;
1130 c = cols[i];
1132 if( c != NOT_A_CARD )
1134 while( true )
1136 /* don't include the last card in the column length. */
1137 if( deck[c].next == NOT_A_CARD )
1139 break; /* no successor: get outta here. */
1141 else
1143 if( deck[c].known )
1144 j += 2;
1145 else
1146 j++;
1148 c = deck[c].next;
1150 /* make column distinguishable from an empty column,
1151 * and avoid division by zero while displaying */
1152 if( j == 0 )
1153 j = 1;
1155 if( j > biggest_col_length )
1156 biggest_col_length = j;
1159 /* check if there are cards remaining in the game. */
1160 /* if there aren't any, that means you won :) */
1161 if( biggest_col_length == 0 && rem == NOT_A_CARD )
1163 rb->splash( HZ, "You Won :)" );
1164 return bouncing_cards();
1167 /* draw the columns */
1168 for( i = 0; i < COL_NUM; i++ )
1170 c = cols[i];
1171 j = CARD_START;
1172 while( true )
1174 if( c == NOT_A_CARD )
1176 /* draw the cursor on empty columns */
1177 if( cur_col == i )
1179 draw_cursor( MARGIN + i * (CARD_WIDTH
1180 +(LCD_WIDTH-COL_NUM*CARD_WIDTH-2*MARGIN)/(COL_NUM-1)),
1181 j );
1183 break;
1186 draw_card( &deck[c], MARGIN + i * (CARD_WIDTH
1187 +(LCD_WIDTH-COL_NUM*CARD_WIDTH-2*MARGIN)/(COL_NUM-1)),
1188 j, c == sel_card, c == cur_card );
1190 h = c;
1191 c = deck[c].next;
1192 if( c == NOT_A_CARD ) break;
1194 /* This is where we change the spacing between cards so that
1195 * they don't overflow out of the LCD */
1196 if( h == cur_card )
1197 j += SYMBOL_HEIGHT;
1198 else if( deck[h].known )
1199 j += min( SYMBOL_HEIGHT,
1200 2 * (LCD_HEIGHT - CARD_START - CARD_HEIGHT - MARGIN)
1201 / biggest_col_length );
1202 else
1203 j += min( SYMBOL_HEIGHT / 2,
1204 (LCD_HEIGHT - CARD_START - CARD_HEIGHT - MARGIN)
1205 / biggest_col_length );
1209 /* draw the stacks */
1210 for( i=0; i<SUITS; i++ )
1212 c = find_last_card( STACKS_COL + i );
1214 if( c != NOT_A_CARD )
1216 draw_card( &deck[c],
1217 LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*i+i+1,
1218 MARGIN,
1219 c == sel_card, cur_col == STACKS_COL + i );
1221 else
1223 draw_empty_stack( i,
1224 LCD_WIDTH-(CARD_WIDTH*4+4+MARGIN)+CARD_WIDTH*i+i+1,
1225 MARGIN, cur_col == STACKS_COL + i );
1229 /* draw the remains */
1230 if( rem != NOT_A_CARD &&
1231 ( cur_rem == NOT_A_CARD || deck[cur_rem].next != NOT_A_CARD ) )
1233 /* gruik ! (we want to display a card back) */
1234 deck[rem].known = false;
1235 draw_card( &deck[rem], MARGIN, MARGIN, false, false );
1236 deck[rem].known = true;
1239 if( rem != NOT_A_CARD && cur_rem != NOT_A_CARD )
1241 if( count_rem < 0 )
1243 prevcard = rem;
1244 count_rem = 0;
1245 while( prevcard != cur_rem && count_rem < cards_per_draw-1 )
1247 prevcard = deck[prevcard].next;
1248 count_rem++;
1251 prevcard = cur_rem;
1252 j = CARD_WIDTH+2*MARGIN+1;
1253 for( i = 0; i < count_rem; i++ )
1254 prevcard = find_prev_card(prevcard);
1255 for( i = 0; i <= count_rem; i++ )
1257 draw_card( &deck[prevcard], j,
1258 MARGIN, sel_card == prevcard,
1259 cur_card == prevcard );
1260 prevcard = deck[prevcard].next;
1261 j += CARD_WIDTH/2;
1264 if( ( cur_rem == NOT_A_CARD || rem == NOT_A_CARD )
1265 && cur_col == REM_COL )
1267 draw_cursor( CARD_WIDTH+2*MARGIN+1, MARGIN );
1270 rb->lcd_update();
1272 /* what to do when a key is pressed ... */
1273 button = rb->button_get( true );
1274 #if (CONFIG_KEYPAD == SANSA_E200_PAD)
1275 if (button&(BUTTON_SCROLL_UP|BUTTON_SCROLL_DOWN))
1276 button = button & (~BUTTON_REPEAT);
1277 #endif
1278 switch( button )
1280 /* move cursor to the last card of the previous column
1281 * or to the previous final stack
1282 * or to the remains stack */
1283 case SOL_RIGHT:
1284 #ifdef SOL_RIGHT_PRE
1285 if( lastbutton != SOL_RIGHT_PRE )
1286 break;
1287 #endif
1288 if( cur_col >= COL_NUM )
1290 cur_col = 0;
1292 else if( cur_col == COL_NUM - 1 )
1294 cur_col = REM_COL;
1296 else
1298 cur_col = (cur_col+1)%(REM_COL+1);
1300 if(cur_col == REM_COL)
1302 cur_card = cur_rem;
1303 break;
1305 cur_card = find_last_card( cur_col );
1306 break;
1308 /* move cursor to the last card of the next column
1309 * or to the next final stack
1310 * or to the remains stack */
1311 case SOL_LEFT:
1312 #ifdef SOL_LEFT_PRE
1313 if( lastbutton != SOL_LEFT_PRE )
1314 break;
1315 #endif
1316 if( cur_col == 0 )
1318 cur_col = REM_COL;
1320 else if( cur_col >= COL_NUM )
1322 cur_col = COL_NUM - 1;
1324 else
1326 cur_col = (cur_col + REM_COL)%(REM_COL+1);
1328 if( cur_col == REM_COL )
1330 cur_card = cur_rem;
1331 break;
1333 cur_card = find_last_card( cur_col );
1334 break;
1336 /* move cursor to card that's bellow */
1337 case SOL_DOWN:
1338 #ifdef SOL_DOWN_PRE
1339 if( lastbutton != SOL_DOWN_PRE )
1340 break;
1341 #else
1342 case SOL_DOWN|BUTTON_REPEAT:
1343 #endif
1344 if( cur_col >= COL_NUM )
1346 cur_col = (cur_col - COL_NUM + 1)%(SUITS + 1) + COL_NUM;
1347 if( cur_col == REM_COL )
1349 cur_card = cur_rem;
1351 else
1353 cur_card = find_last_card( cur_col );
1355 break;
1357 if( cur_card == NOT_A_CARD ) break;
1358 if( deck[cur_card].next != NOT_A_CARD )
1360 cur_card = deck[cur_card].next;
1362 else
1364 cur_card = cols[cur_col];
1365 while( !deck[ cur_card].known
1366 && deck[cur_card].next != NOT_A_CARD )
1368 cur_card = deck[cur_card].next;
1371 break;
1373 /* move cursor to card that's above */
1374 case SOL_UP:
1375 #ifdef SOL_UP_PRE
1376 if( lastbutton != SOL_UP_PRE )
1377 break;
1378 #else
1379 case SOL_UP|BUTTON_REPEAT:
1380 #endif
1381 if( cur_col >= COL_NUM )
1383 cur_col = (cur_col - COL_NUM + SUITS)%(SUITS + 1) + COL_NUM;
1384 if( cur_col == REM_COL )
1386 cur_card = cur_rem;
1388 else
1390 cur_card = find_last_card( cur_col );
1392 break;
1394 if( cur_card == NOT_A_CARD ) break;
1395 do {
1396 cur_card = find_prev_card( cur_card );
1397 if( cur_card == NOT_A_CARD )
1399 cur_card = find_last_card( cur_col );
1401 } while( deck[cur_card].next != NOT_A_CARD
1402 && !deck[cur_card].known );
1403 break;
1405 /* Try to put card under cursor on one of the stacks */
1406 case SOL_CUR2STACK:
1407 #ifdef SOL_CUR2STACK_PRE
1408 if( lastbutton != SOL_CUR2STACK_PRE )
1409 break;
1410 #endif
1411 move_card( deck[cur_card].suit + STACKS_COL, cur_card );
1412 break;
1414 /* Move cards arround, Uncover cards, ... */
1415 case SOL_MOVE:
1416 #ifdef SOL_MOVE_PRE
1417 if( lastbutton != SOL_MOVE_PRE )
1418 break;
1419 #endif
1421 if( sel_card == NOT_A_CARD )
1423 if( cur_card != NOT_A_CARD )
1425 if( deck[cur_card].next == NOT_A_CARD
1426 && !deck[cur_card].known )
1428 /* reveal a hidden card */
1429 deck[cur_card].known = true;
1431 else if( cur_col == REM_COL && cur_rem == NOT_A_CARD )
1433 break;
1435 else
1437 /* select a card */
1438 sel_card = cur_card;
1442 else if( sel_card == cur_card )
1444 /* unselect card or try putting card on
1445 * one of the 4 stacks */
1446 if( move_card( deck[sel_card].suit + COL_NUM, sel_card )
1447 == MOVE_OK && cur_col == REM_COL )
1449 cur_card = cur_rem;
1451 sel_card = NOT_A_CARD;
1453 else
1455 /* try moving cards */
1456 /* the code in the else seems to not like moveing kings
1457 so if the selected card is a king do it the simple way */
1458 if (deck[sel_card].num == CARDS_PER_SUIT - 1)
1460 if (move_card( cur_col, sel_card ) == MOVE_NOT_OK)
1461 sel_card = NOT_A_CARD;
1463 else
1465 int retval;
1466 do {
1467 retval = move_card( cur_col, sel_card );
1468 if (retval == MOVE_NOT_OK)
1470 sel_card = find_prev_card(sel_card);
1472 } while ((retval == MOVE_NOT_OK) && (sel_card != NOT_A_CARD));
1475 break;
1477 /* If the card on the top of the remains can be put where
1478 * the cursor is, go ahead */
1479 case SOL_REM2CUR:
1480 #ifdef SOL_REM2CUR_PRE
1481 if( lastbutton != SOL_REM2CUR_PRE )
1482 break;
1483 #endif
1484 move_card( cur_col, cur_rem );
1485 break;
1487 /* If the card on top of the remains can be put on one
1488 * of the stacks, do so */
1489 case SOL_REM2STACK:
1490 #ifdef SOL_REM2STACK_PRE
1491 if( lastbutton != SOL_REM2STACK_PRE )
1492 break;
1493 #endif
1494 move_card( deck[cur_rem].suit + COL_NUM, cur_rem );
1495 break;
1497 #ifdef SOL_REM
1498 case SOL_REM:
1499 if( sel_card != NOT_A_CARD )
1501 /* unselect selected card */
1502 sel_card = NOT_A_CARD;
1503 break;
1505 if( rem != NOT_A_CARD && cur_rem != NOT_A_CARD )
1507 sel_card = cur_rem;
1508 break;
1510 break;
1511 #endif
1513 /* unselect selected card or ...
1514 * draw new cards from the remains of the deck */
1515 case SOL_DRAW:
1516 #ifdef SOL_DRAW_PRE
1517 if( lastbutton != SOL_DRAW_PRE )
1518 break;
1519 #endif
1520 if( sel_card != NOT_A_CARD )
1522 /* unselect selected card */
1523 sel_card = NOT_A_CARD;
1524 break;
1526 if( rem != NOT_A_CARD )
1528 int cur_rem_old = cur_rem;
1529 count_rem = -1;
1530 /* draw new cards form the remains of the deck */
1531 if( cur_rem == NOT_A_CARD )
1533 /*if the cursor card is null*/
1534 cur_rem = rem;
1535 i = cards_per_draw - 1;
1536 count_rem++;
1538 else
1540 i = cards_per_draw;
1543 while( i > 0 && deck[cur_rem].next != NOT_A_CARD )
1545 cur_rem = deck[cur_rem].next;
1546 i--;
1547 count_rem++;
1549 /* test if any cards are really left on
1550 * the remains' stack */
1551 if( i == cards_per_draw )
1553 cur_rem = NOT_A_CARD;
1554 count_rem = -1;
1556 /* if cursor was on remains' stack when new cards were
1557 * drawn, put cursor on top of remains' stack */
1558 if( cur_col == REM_COL && cur_card == cur_rem_old )
1560 cur_card = cur_rem;
1561 sel_card = NOT_A_CARD;
1564 break;
1566 /* Show the menu */
1567 #ifdef SOL_RC_QUIT
1568 case SOL_RC_QUIT:
1569 #endif
1570 case SOL_QUIT:
1571 switch( solitaire_menu(true) )
1573 case MENU_QUIT:
1574 return SOLITAIRE_QUIT;
1576 case MENU_USB:
1577 return SOLITAIRE_USB;
1579 break;
1581 default:
1582 if( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
1583 return SOLITAIRE_USB;
1584 break;
1587 if( button != BUTTON_NONE )
1588 lastbutton = button;
1590 /* fix incoherences concerning cur_col and cur_card */
1591 c = find_card_col( cur_card );
1592 if( c != NOT_A_COL && c != cur_col )
1593 cur_card = find_last_card( cur_col );
1595 if( cur_card == NOT_A_CARD
1596 && find_last_card( cur_col ) != NOT_A_CARD )
1597 cur_card = find_last_card( cur_col );
1602 * Plugin entry point
1605 enum plugin_status plugin_start( struct plugin_api* api, void* parameter )
1607 int result;
1609 /* plugin init */
1610 (void)parameter;
1611 rb = api;
1613 rb->splash( HZ, "Welcome to Solitaire!" );
1615 configfile_init(rb);
1616 configfile_load(CONFIG_FILENAME, config,
1617 sizeof(config) / sizeof(config[0]), CFGFILE_VERSION);
1618 rb->memcpy(&sol, &sol_disk, sizeof(sol)); /* copy to running config */
1620 init_help();
1622 /* play the game :)
1623 * Keep playing if a game was won (that means display the menu after
1624 * winning instead of quiting) */
1625 while( ( result = solitaire() ) == SOLITAIRE_WIN );
1627 if (rb->memcmp(&sol, &sol_disk, sizeof(sol))) /* save settings if changed */
1629 rb->memcpy(&sol_disk, &sol, sizeof(sol));
1630 configfile_save(CONFIG_FILENAME, config,
1631 sizeof(config) / sizeof(config[0]), CFGFILE_VERSION);
1634 /* Exit the plugin */
1635 return ( result == SOLITAIRE_USB ) ? PLUGIN_USB_CONNECTED : PLUGIN_OK;
1638 #endif