summaryrefslogtreecommitdiff
path: root/apps/plugins/solitaire.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/solitaire.c')
-rw-r--r--apps/plugins/solitaire.c867
1 files changed, 867 insertions, 0 deletions
diff --git a/apps/plugins/solitaire.c b/apps/plugins/solitaire.c
new file mode 100644
index 0000000000..28334437c7
--- /dev/null
+++ b/apps/plugins/solitaire.c
@@ -0,0 +1,867 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 dionoea (Antoine Cellerier)
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/*****************************************************************************
21Solitaire by dionoea
22
23use arrows to move the cursor
24use ON to select cards in the columns, move cards inside the columns,
25 reveal hidden cards, ...
26use PLAY to move a card from the remains' stack to the top of the cursor
27use F1 to put card under cursor on one of the 4 final color stacks
28use F2 to un-select card if a card was selected, else draw 3 new cards
29 out of the remains' stack
30use F3 to put card on top of the remains' stack on one of the 4 final color
31 stacks
32
33*****************************************************************************/
34
35#include "plugin.h"
36#include "button.h"
37#include "lcd.h"
38
39#ifdef HAVE_LCD_BITMAP
40
41/* here is a global api struct pointer. while not strictly necessary,
42 it's nice not to have to pass the api pointer in all function calls
43 in the plugin */
44static struct plugin_api* rb;
45
46#define min(a,b) (a<b?a:b)
47
48#define HELP_CASE( key ) case BUTTON_ ## key: \
49 rb->splash(HZ*1, true, # key " : " HELP_BUTTON_ ## key); \
50 break;
51
52#define HELP_BUTTON_UP "Move the cursor up in the column."
53#define HELP_BUTTON_DOWN "Move the cursor down in the column."
54#define HELP_BUTTON_LEFT "Move the cursor to the previous column."
55#define HELP_BUTTON_RIGHT "Move the cursor to the next column."
56#define HELP_BUTTON_F1 "Put the card under the cursor on one of the 4 final color stacks."
57#define HELP_BUTTON_F2 "Un-select a card if it was selected. Else, draw 3 new cards out of the remains' stack."
58#define HELP_BUTTON_F3 "Put the card on top of the remains' stack on one of the 4 final color stacks."
59#define HELP_BUTTON_PLAY "Put the card on top of the remains' stack on top of the cursor."
60#define HELP_BUTTON_ON "Select cards in the columns, Move cards inside the columns, reveal hidden cards ..."
61
62static unsigned char colors[4][8] = {
63//Spades
64{0x00, //........
65 0x18, //...O....
66 0x1c, //..OOO...
67 0x3e, //.OOOOO..
68 0x1c, //.OOOOO..
69 0x18, //...O....
70 0x00, //........
71 0x00},//........
72//Hearts
73{0x00, //........
74 0x0c, //..O.O...
75 0x1e, //.OOOOO..
76 0x3c, //.OOOOO..
77 0x1e, //..OOO...
78 0x0c, //...O....
79 0x00, //........
80 0x00},//........
81//Clubs
82{0x00, //........
83 0x18, //..OOO...
84 0x0a, //...O....
85 0x3e, //.OOOOO..
86 0x0a, //.O.O.O..
87 0x18, //...O....
88 0x00, //........
89 0x00},//........
90//Diamonds
91{0x00, //........
92 0x08, //...O....
93 0x1c, //..OOO...
94 0x3e, //.OOOOO..
95 0x1c, //..OOO...
96 0x08, //...O....
97 0x00, //........
98 0x00} //........
99};
100
101static unsigned char numbers[13][8] = {
102//Ace
103{0x00, //........
104 0x38, //...O....
105 0x14, //..O.O...
106 0x12, //.O...O..
107 0x14, //.OOOOO..
108 0x38, //.O...O..
109 0x00, //........
110 0x00},//........
111//2
112{0x00, //........
113 0x24, //..OOO...
114 0x32, //.O...O..
115 0x32, //....O...
116 0x2a, //..OO....
117 0x24, //.OOOOO..
118 0x00, //........
119 0x00},//........
120//3
121{0x00, //........
122 0x22, //.OOOO...
123 0x2a, //.....O..
124 0x2a, //..OOO...
125 0x2a, //.....O..
126 0x14, //.OOOO...
127 0x00, //........
128 0x00},//........
129//4
130{0x00, //........
131 0x10, //....O...
132 0x18, //...O....
133 0x34, //..O.....
134 0x12, //.OOOOO..
135 0x10, //...O....
136 0x00, //........
137 0x00},//........
138//5
139{0x00, //........
140 0x2e, //.OOOOO..
141 0x2a, //.O......
142 0x2a, //.OOOO...
143 0x2a, //.....O..
144 0x12, //.OOOO...
145 0x00, //........
146 0x00},//........
147//6
148{0x00, //........
149 0x1c, //..OOO...
150 0x2a, //.O......
151 0x2a, //.OOOO...
152 0x2a, //.O...O..
153 0x10, //..OOO...
154 0x00, //........
155 0x00},//........
156//7
157{0x00, //........
158 0x22, //.OOOOO..
159 0x12, //....O...
160 0x0a, //...O....
161 0x06, //..O.....
162 0x02, //.O......
163 0x00, //........
164 0x00},//........
165//8
166{0x00, //........
167 0x14, //..OOO...
168 0x2a, //.O...O..
169 0x2a, //..OOO...
170 0x2a, //.O...O..
171 0x14, //..OOO...
172 0x00, //........
173 0x00},//........
174//9
175{0x00, //........
176 0x04, //..OOO...
177 0x2a, //.O...O..
178 0x2a, //..OOOO..
179 0x2a, //.....O..
180 0x1c, //..OOO...
181 0x00, //........
182 0x00},//........
183//10
184{0x00, //........
185 0x3e, //.O..O...
186 0x00, //.O.O.O..
187 0x1c, //.O.O.O..
188 0x22, //.O.O.O..
189 0x1c, //.O..O...
190 0x00, //........
191 0x00},//........
192//Jack
193{0x00, //........
194 0x12, //.OOOOO..
195 0x22, //...O....
196 0x1e, //...O....
197 0x02, //.O.O....
198 0x02, //..O.....
199 0x00, //........
200 0x00},//........
201//Queen
202{0x00, //........
203 0x1c, //..OOO...
204 0x22, //.O...O..
205 0x32, //.O...O..
206 0x22, //.O.O.O..
207 0x1c, //..OOO...
208 0x00, //........
209 0x00},//........
210//King
211{0x00, //........
212 0x3e, //.O...O..
213 0x08, //.O..O...
214 0x08, //.OOO....
215 0x14, //.O..O...
216 0x22, //.O...O..
217 0x00, //........
218 0x00} //........
219};
220
221#define NOT_A_CARD 255
222
223//number of cards per color
224#define CARDS_PER_COLOR 13
225
226//number of colors
227#define COLORS 4
228
229//number of columns
230#define COL_NUM 7
231
232//number of cards that are drawn on the remains' stack (by pressing F2)
233#define CARDS_PER_DRAW 3
234
235//size of a card on the screen
236#define CARD_WIDTH 14
237#define CARD_HEIGHT 10
238
239typedef struct card {
240 unsigned char color : 2;
241 unsigned char num : 4;
242 unsigned char known : 1;
243 unsigned char used : 1;//this is what is used when dealing cards
244 unsigned char next;
245} card;
246
247unsigned char next_random_card(card *deck){
248 unsigned char i,r;
249
250 r = rb->rand()%(COLORS * CARDS_PER_COLOR)+1;
251 i = 0;
252
253 while(r>0){
254 i = (i + 1)%(COLORS * CARDS_PER_COLOR);
255 if(!deck[i].used) r--;
256 }
257
258 deck[i].used = 1;
259
260 return i;
261}
262
263//help for the not so intuitive interface
264void solitaire_help(void){
265
266 rb->lcd_clear_display();
267
268 rb->lcd_putsxy(0, 0, "Press a key to see");
269 rb->lcd_putsxy(0, 7, "it's role.");
270 rb->lcd_putsxy(0, 21, "Press OFF to");
271 rb->lcd_putsxy(0, 28, "return to menu");
272
273 rb->lcd_update();
274
275 while(1){
276
277 switch(rb->button_get(true)){
278 HELP_CASE( UP );
279 HELP_CASE( DOWN );
280 HELP_CASE( LEFT );
281 HELP_CASE( RIGHT );
282 HELP_CASE( F1 );
283 HELP_CASE( F2 );
284 HELP_CASE( F3 );
285 HELP_CASE( PLAY );
286 HELP_CASE( ON );
287
288 case BUTTON_OFF:
289 return;
290 }
291 }
292}
293
294//menu return codes
295#define MENU_RESUME 0
296#define MENU_RESTART 1
297#define MENU_HELP 2
298#define MENU_QUIT 3
299
300//menu item number
301#define MENU_LENGTH 4
302
303//different menu behaviors
304#define MENU_BEFOREGAME 0
305#define MENU_DURINGGAME 1
306
307//the menu
308//text displayed changes depending on the 'when' parameter
309int solitaire_menu(unsigned char when){
310
311 static char menu[2][MENU_LENGTH][13] =
312 { { "Start Game",
313 "",
314 "Help",
315 "Quit" },
316 { "Resume Game",
317 "Restart Game",
318 "Help",
319 "Quit"} };
320
321 int i;
322 int cursor=0;
323
324 if(when!=MENU_BEFOREGAME && when!=MENU_DURINGGAME) when = MENU_DURINGGAME;
325
326 while(1){
327
328 rb->lcd_clear_display();
329
330 rb->lcd_putsxy(20, 1, "Solitaire");
331
332 for(i = 0; i<MENU_LENGTH; i++){
333 rb->lcd_putsxy(1, 17+9*i, menu[when][i]);
334 if(cursor == i)
335 rb->lcd_invertrect(0,17-1+9*i, LCD_WIDTH, 9);
336 }
337
338 rb->lcd_update();
339
340 switch(rb->button_get(true)){
341 case BUTTON_UP:
342 cursor = (cursor + MENU_LENGTH - 1)%MENU_LENGTH;
343 break;
344
345 case BUTTON_DOWN:
346 cursor = (cursor + 1)%MENU_LENGTH;
347 break;
348
349 case BUTTON_LEFT:
350 return MENU_RESUME;
351
352 case BUTTON_PLAY:
353 case BUTTON_RIGHT:
354 switch(cursor){
355 case MENU_RESUME:
356 case MENU_RESTART:
357 case MENU_QUIT:
358 return cursor;
359
360 case MENU_HELP:
361 solitaire_help();
362 break;
363 }
364
365 case BUTTON_F1:
366 case BUTTON_F2:
367 case BUTTON_F3:
368 rb->splash(HZ, true, "Solitaire for Rockbox by dionoea");
369 break;
370
371 case BUTTON_OFF:
372 return MENU_QUIT;
373
374 default:
375 break;
376 }
377 }
378}
379
380//player's cursor
381unsigned char cur_card;
382//player's cursor column num
383unsigned char cur_col;
384
385//selected card
386unsigned char sel_card;
387
388//the deck
389card deck[COLORS * CARDS_PER_COLOR];
390
391//the remaining cards
392unsigned char rem;
393unsigned char cur_rem;
394
395//the 7 game columns
396unsigned char cols[COL_NUM];
397
398//the 4 final color stacks
399unsigned char stacks[COLORS];
400
401//initialize the game
402void solitaire_init(void){
403 unsigned char c;
404 int i,j;
405
406 //init deck
407 for(i=0;i<COLORS;i++){
408 for(j=0;j<CARDS_PER_COLOR;j++){
409 deck[i*CARDS_PER_COLOR+j].color = i;
410 deck[i*CARDS_PER_COLOR+j].num = j;
411 deck[i*CARDS_PER_COLOR+j].known = 0;
412 deck[i*CARDS_PER_COLOR+j].used = 0;
413 deck[i*CARDS_PER_COLOR+j].next = NOT_A_CARD;
414 }
415 }
416
417 //deal the cards ...
418 //... in the columns
419 for(i=0; i<COL_NUM; i++){
420 c = NOT_A_CARD;
421 for(j=0; j<=i; j++){
422 if(c == NOT_A_CARD){
423 cols[i] = next_random_card(deck);
424 c = cols[i];
425 } else {
426 deck[c].next = next_random_card(deck);
427 c = deck[c].next;
428 }
429 if(j==i) deck[c].known = 1;
430 }
431 }
432
433 //... shuffle what's left of the deck
434 rem = next_random_card(deck);
435 c = rem;
436
437 for(i=1; i<COLORS * CARDS_PER_COLOR - COL_NUM * (COL_NUM + 1)/2; i++){
438 deck[c].next = next_random_card(deck);
439 c = deck[c].next;
440 }
441
442 //we now finished dealing the cards. The game can start ! (at last)
443
444 //init the stack
445 for(i = 0; i<COL_NUM;i++){
446 stacks[i] = NOT_A_CARD;
447 }
448
449 //the cursor starts on upper left card
450 cur_card = cols[0];
451 cur_col = 0;
452
453 //no card is selected
454 sel_card = NOT_A_CARD;
455
456 //init the remainder
457 cur_rem = NOT_A_CARD;
458}
459
460
461//the game
462void solitaire(void){
463
464 int i,j;
465 unsigned char c;
466 int biggest_col_length;
467
468 if(solitaire_menu(MENU_BEFOREGAME) == MENU_QUIT) return;
469 solitaire_init();
470
471 while(true){
472
473 rb->lcd_clear_display();
474
475 //get the biggest column length so that display can be "optimized"
476 biggest_col_length = 0;
477
478 for(i=0;i<COL_NUM;i++){
479 j = 0;
480 c = cols[i];
481 while(c != NOT_A_CARD){
482 j++;
483 c = deck[c].next;
484 }
485 if(j>biggest_col_length) biggest_col_length = j;
486 }
487
488 //check if there are cards remaining in the game.
489 //if there aren't any, that means you won :)
490 if(biggest_col_length == 0 && rem == NOT_A_CARD){
491 rb->splash(HZ*2, true, "You Won :)");
492 return;
493 }
494
495 //draw the columns
496 for(i=0;i<COL_NUM;i++){
497 c = cols[i];
498 j = 0;
499 while(true){
500 if(c==NOT_A_CARD) break;
501 //clear the card's spot
502 rb->lcd_clearrect(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM, j+1, CARD_WIDTH, CARD_HEIGHT-1);
503 //known card
504 if(deck[c].known){
505 rb->lcd_bitmap(numbers[deck[c].num], i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+1, j, 8, 8, true);
506 rb->lcd_bitmap(colors[deck[c].color], i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+7, j, 8, 8, true);
507 }
508 //draw top line of the card
509 rb->lcd_drawline(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+1,j,i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+CARD_WIDTH-1,j);
510 //selected card
511 if(c == sel_card && sel_card != NOT_A_CARD){
512 rb->lcd_drawrect(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+1, j+1, CARD_WIDTH-1, CARD_HEIGHT-1);
513 }
514 //cursor (or not)
515 if(c == cur_card){
516 rb->lcd_invertrect(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+1, j+1, CARD_WIDTH-1, CARD_HEIGHT-1);
517 //go to the next card
518 c = deck[c].next;
519 if(c == NOT_A_CARD) break;
520 j += CARD_HEIGHT - 2;
521 } else {
522 //go to the next card
523 c = deck[c].next;
524 if(c == NOT_A_CARD) break;
525 j += min(CARD_HEIGHT - 2, (LCD_HEIGHT - CARD_HEIGHT)/biggest_col_length);
526 }
527 }
528 //draw line to the left of the column
529 rb->lcd_drawline(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM,1,i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM,j+CARD_HEIGHT-1);
530 //draw line to the right of the column
531 rb->lcd_drawline(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+CARD_WIDTH,1,i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+CARD_WIDTH,j+CARD_HEIGHT-1);
532 //draw bottom of the last card
533 rb->lcd_drawline(i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+1,j+CARD_HEIGHT,i*(LCD_WIDTH - CARD_WIDTH)/COL_NUM+CARD_WIDTH-1,j+CARD_HEIGHT);
534 }
535
536 //draw the stacks
537 for(i=0; i<COLORS; i++){
538 c = stacks[i];
539 if(c!=NOT_A_CARD){
540 while(deck[c].next != NOT_A_CARD){
541 c = deck[c].next;
542 }
543 }
544 if(c != NOT_A_CARD) {
545 rb->lcd_bitmap(numbers[deck[c].num], LCD_WIDTH - CARD_WIDTH+1, i*CARD_HEIGHT, 8, 8, true);
546 }
547 rb->lcd_bitmap(colors[i], LCD_WIDTH - CARD_WIDTH+7, i*CARD_HEIGHT, 8, 8, true);
548 rb->lcd_drawline(LCD_WIDTH - CARD_WIDTH+1,i*CARD_HEIGHT,LCD_WIDTH - 1,i*CARD_HEIGHT);
549 rb->lcd_drawline(LCD_WIDTH - CARD_WIDTH+1,(i+1)*CARD_HEIGHT,LCD_WIDTH - 1,(i+1)*CARD_HEIGHT);
550 }
551
552 //draw the remains
553 rb->lcd_drawline(LCD_WIDTH - CARD_WIDTH+1,LCD_HEIGHT-CARD_HEIGHT-1,LCD_WIDTH - 1,LCD_HEIGHT-CARD_HEIGHT-1);
554 rb->lcd_drawline(LCD_WIDTH - CARD_WIDTH+1,LCD_HEIGHT-1,LCD_WIDTH - 1,LCD_HEIGHT-1);
555 if(cur_rem != NOT_A_CARD){
556 rb->lcd_bitmap(numbers[deck[cur_rem].num], LCD_WIDTH - CARD_WIDTH+1, LCD_HEIGHT-CARD_HEIGHT, 8, 8, true);
557 rb->lcd_bitmap(colors[deck[cur_rem].color], LCD_WIDTH - CARD_WIDTH+7, LCD_HEIGHT-CARD_HEIGHT, 8, 8, true);
558 }
559
560 rb->lcd_update();
561
562 //what to do when a key is pressed ...
563 switch(rb->button_get(true)){
564
565 //move cursor to the last card of the previous column
566 case BUTTON_RIGHT:
567 cur_col = (cur_col+1)%COL_NUM;
568 cur_card = cols[cur_col];
569 if(cur_card != NOT_A_CARD){
570 while(deck[cur_card].next != NOT_A_CARD){
571 cur_card = deck[cur_card].next;
572 }
573 }
574 break;
575
576 //move cursor to the last card of the next column
577 case BUTTON_LEFT:
578 cur_col = (cur_col + COL_NUM - 1)%COL_NUM;
579 cur_card = cols[cur_col];
580 if(cur_card != NOT_A_CARD){
581 while(deck[cur_card].next != NOT_A_CARD){
582 cur_card = deck[cur_card].next;
583 }
584 }
585 break;
586
587 //move cursor to card that's bellow
588 case BUTTON_DOWN:
589 if(cur_card == NOT_A_CARD) break;
590 if(deck[cur_card].next != NOT_A_CARD){
591 cur_card = deck[cur_card].next;
592 } else {
593 cur_card = cols[cur_col];
594 }
595 break;
596
597 //move cursor to card that's above
598 case BUTTON_UP:
599 if(cur_card == NOT_A_CARD) break;
600 if(cols[cur_col] == cur_card){
601 while(deck[cur_card].next != NOT_A_CARD){
602 cur_card = deck[cur_card].next;
603 }
604 } else {
605 c = cols[cur_col];
606 while(deck[c].next != cur_card){
607 c = deck[c].next;
608 }
609 cur_card = c;
610 }
611 break;
612
613 //Try to put card under cursor on one of the stacks
614 case BUTTON_F1:
615 //check if a card is selected
616 //else there would be nothing to move on the stacks !
617 if(cur_card != NOT_A_CARD){
618 //find the last card in the color's stack and put it's number in 'c'.
619 c = stacks[deck[cur_card].color];
620 if(c!=NOT_A_CARD){
621 while(deck[c].next!=NOT_A_CARD){
622 c = deck[c].next;
623 }
624 }
625 //if 'c' isn't a card, that means that the stack is empty
626 //which implies that only an ace can be moved
627 if(c == NOT_A_CARD){
628 //check if the selected card is an ace
629 //we don't have to check if any card is in the *.next
630 //position since the ace is the last possible card
631 if(deck[cur_card].num == 0){
632 //remove 'cur_card' from any *.next postition ...
633 //... by looking in the columns
634 for(i=0;i<COL_NUM;i++){
635 if(cols[i]==cur_card) cols[i] = NOT_A_CARD;
636 }
637 //... and in the entire deck
638 //TODO : check if looking in the cols is really needed
639 for(i=0;i<COLORS*CARDS_PER_COLOR;i++){
640 if(deck[i].next==cur_card) deck[i].next = NOT_A_CARD;
641 }
642 //move cur_card on top of the stack
643 stacks[deck[cur_card].color] = cur_card;
644 //assign the card at the bottom of cur_col to cur_card
645 cur_card = cols[cur_col];
646 if(cur_card != NOT_A_CARD){
647 while(deck[cur_card].next != NOT_A_CARD){
648 cur_card = deck[cur_card].next;
649 }
650 }
651 //clear the selection indicator
652 sel_card = NOT_A_CARD;
653 }
654 }
655 //the stack is not empty
656 //so we can move any card other than an ace
657 //we thus check that the card we are moving is the next on the stack and that it isn't under any card
658 else if(deck[cur_card].num == deck[c].num + 1 && deck[cur_card].next == NOT_A_CARD){
659 //same as above
660 for(i=0;i<COL_NUM;i++){
661 if(cols[i]==cur_card) cols[i] = NOT_A_CARD;
662 }
663 //re same
664 for(i=0;i<COLORS*CARDS_PER_COLOR;i++){
665 if(deck[i].next==cur_card) deck[i].next = NOT_A_CARD;
666 }
667 //...
668 deck[c].next = cur_card;
669 cur_card = cols[cur_col];
670 if(cur_card != NOT_A_CARD){
671 while(deck[cur_card].next != NOT_A_CARD){
672 cur_card = deck[cur_card].next;
673 }
674 }
675 sel_card = NOT_A_CARD;
676 }
677 }
678 break;
679
680 //Move cards arround, Uncover cards, ...
681 case BUTTON_ON:
682 if(sel_card == NOT_A_CARD) {
683 if((cur_card != NOT_A_CARD?deck[cur_card].next == NOT_A_CARD && deck[cur_card].known==0:0)){
684 deck[cur_card].known = 1;
685 } else {
686 sel_card = cur_card;
687 }
688 } else if(sel_card == cur_card) {
689 sel_card = NOT_A_CARD;
690 } else if(cur_card != NOT_A_CARD){
691 if(deck[cur_card].num == deck[sel_card].num + 1 && (deck[cur_card].color + deck[sel_card].color)%2 == 1 ){
692 for(i=0;i<COL_NUM;i++){
693 if(cols[i]==sel_card) cols[i] = NOT_A_CARD;
694 }
695 for(i=0;i<COLORS*CARDS_PER_COLOR;i++){
696 if(deck[i].next==sel_card) deck[i].next = NOT_A_CARD;
697 }
698 deck[cur_card].next = sel_card;
699 sel_card = NOT_A_CARD;
700 }
701 } else if(cur_card == NOT_A_CARD){
702 if(deck[sel_card].num == CARDS_PER_COLOR - 1){
703 for(i=0;i<COL_NUM;i++){
704 if(cols[i]==sel_card) cols[i] = NOT_A_CARD;
705 }
706 for(i=0;i<COLORS*CARDS_PER_COLOR;i++){
707 if(deck[i].next==sel_card) deck[i].next = NOT_A_CARD;
708 }
709 cols[cur_col] = sel_card;
710 sel_card = NOT_A_CARD;
711 }
712 }
713 break;
714
715 //If the card on the top of the remains can be put where
716 //the cursor is, go ahead
717 case BUTTON_PLAY:
718 //check if a card is face up on the remains' stack
719 if(cur_rem != NOT_A_CARD){
720 //if no card is selected, it means the col is empty
721 //thus, only a king can be moved
722 if(cur_card == NOT_A_CARD){
723 //check if selcted card is a king
724 if(deck[cur_rem].num == CARDS_PER_COLOR - 1){
725 //find the previous card on the remains' stack
726 c = rem;
727 //if the current card on the remains' stack
728 //is the first card of the stack, then ...
729 if(c == cur_rem){
730 c = NOT_A_CARD;
731 rem = deck[cur_rem].next;
732 }
733 //else ...
734 else {
735 while(deck[c].next != cur_rem){
736 c = deck[c].next;
737 }
738 deck[c].next = deck[cur_rem].next;
739 }
740 cols[cur_col] = cur_rem;
741 deck[cur_rem].next = NOT_A_CARD;
742 deck[cur_rem].known = 1;
743 cur_rem = c;
744 }
745 } else if(deck[cur_rem].num + 1 == deck[cur_card].num && (deck[cur_rem].color + deck[cur_card].color)%2==1) {
746 c = rem;
747 if(c == cur_rem){
748 c = NOT_A_CARD;
749 rem = deck[cur_rem].next;
750 } else {
751 while(deck[c].next != cur_rem){
752 c = deck[c].next;
753 }
754 deck[c].next = deck[cur_rem].next;
755 }
756 deck[cur_card].next = cur_rem;
757 deck[cur_rem].next = NOT_A_CARD;
758 deck[cur_rem].known = 1;
759 cur_rem = c;
760 }
761 }
762 break;
763
764 //If the card on top of the remains can be put on one
765 //of the stacks, do so
766 case BUTTON_F3:
767 if(cur_rem != NOT_A_CARD){
768 if(deck[cur_rem].num == 0){
769 c = rem;
770 if(c == cur_rem){
771 c = NOT_A_CARD;
772 rem = deck[cur_rem].next;
773 } else {
774 while(deck[c].next != cur_rem){
775 c = deck[c].next;
776 }
777 deck[c].next = deck[cur_rem].next;
778 }
779 deck[cur_rem].next = NOT_A_CARD;
780 deck[cur_rem].known = 1;
781 stacks[deck[cur_rem].color] = cur_rem;
782 cur_rem = c;
783 } else {
784
785 i = stacks[deck[cur_rem].color];
786 if(i==NOT_A_CARD) break;
787 while(deck[i].next != NOT_A_CARD){
788 i = deck[i].next;
789 }
790 if(deck[i].num + 1 == deck[cur_rem].num){
791 c = rem;
792 if(c == cur_rem){
793 c = NOT_A_CARD;
794 rem = deck[cur_rem].next;
795 } else {
796 while(deck[c].next != cur_rem){
797 c = deck[c].next;
798 }
799 deck[c].next = deck[cur_rem].next;
800 }
801 deck[i].next = cur_rem;
802 deck[cur_rem].next = NOT_A_CARD;
803 deck[cur_rem].known = 1;
804 cur_rem = c;
805 }
806 }
807 }
808 break;
809
810 //unselect selected card or ...
811 //draw new cards from the remains of the deck
812 case BUTTON_F2:
813 if(sel_card != NOT_A_CARD){
814 //unselect selected card
815 sel_card = NOT_A_CARD;
816 } else if(rem != NOT_A_CARD) {
817 //draw new cards form the remains of the deck
818 if(cur_rem == NOT_A_CARD){
819 cur_rem = rem;
820 i = CARDS_PER_DRAW - 1;
821 } else {
822 i = CARDS_PER_DRAW;
823 }
824 while(i>0 && deck[cur_rem].next != NOT_A_CARD){
825 cur_rem = deck[cur_rem].next;
826 i--;
827 }
828 //test if any cards are really left on the remains' stack
829 if(i == CARDS_PER_DRAW){
830 cur_rem = NOT_A_CARD;
831 }
832 }
833 break;
834
835 //Show the menu
836 case BUTTON_OFF:
837 switch(solitaire_menu(MENU_DURINGGAME)){
838 case MENU_QUIT:
839 return;
840
841 case MENU_RESTART:
842 solitaire_init();
843 break;
844 }
845 }
846 }
847}
848
849enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
850{
851 //plugin init
852 TEST_PLUGIN_API(api);
853 (void)parameter;
854 rb = api;
855 //end of plugin init
856
857 //Welcome to Solitaire !
858 rb->splash(HZ*2, true, "Welcome to Solitaire !");
859
860 //play the game :)
861 solitaire();
862
863 //Exit the plugin
864 return PLUGIN_OK;
865}
866
867#endif