diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/minesweeper.c | 436 | ||||
-rw-r--r-- | apps/plugins/solitaire.c | 867 |
2 files changed, 1303 insertions, 0 deletions
diff --git a/apps/plugins/minesweeper.c b/apps/plugins/minesweeper.c new file mode 100644 index 0000000000..b155c3fbad --- /dev/null +++ b/apps/plugins/minesweeper.c | |||
@@ -0,0 +1,436 @@ | |||
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 | /***************************************************************************** | ||
21 | Mine Sweeper by dionoea | ||
22 | |||
23 | use arrow keys to move cursor | ||
24 | use ON or F2 to clear a tile | ||
25 | use PLAY or F1 to put a flag on a tile | ||
26 | use F3 to see how many mines are left (supposing all your flags are correct) | ||
27 | |||
28 | *****************************************************************************/ | ||
29 | |||
30 | #include "plugin.h" | ||
31 | #include "button.h" | ||
32 | #include "lcd.h" | ||
33 | |||
34 | #ifdef HAVE_LCD_BITMAP | ||
35 | |||
36 | //what the minesweeper() function can return | ||
37 | #define MINESWEEPER_QUIT 2 | ||
38 | #define MINESWEEPER_LOSE 1 | ||
39 | #define MINESWEEPER_WIN 0 | ||
40 | |||
41 | |||
42 | /* here is a global api struct pointer. while not strictly necessary, | ||
43 | it's nice not to have to pass the api pointer in all function calls | ||
44 | in the plugin */ | ||
45 | static struct plugin_api* rb; | ||
46 | |||
47 | |||
48 | //define how numbers are displayed (that way we don't have to | ||
49 | //worry about fonts) | ||
50 | static unsigned char num[9][8] = { | ||
51 | /*reading the sprites: | ||
52 | on screen f123 | ||
53 | 4567 | ||
54 | 890a | ||
55 | bcde | ||
56 | |||
57 | in binary b84f | ||
58 | c951 | ||
59 | d062 | ||
60 | ea73 | ||
61 | */ | ||
62 | |||
63 | //0 | ||
64 | {0x00, //........ | ||
65 | 0x00, //........ | ||
66 | 0x00, //........ | ||
67 | 0x00, //........ | ||
68 | 0x00, //........ | ||
69 | 0x00, //........ | ||
70 | 0x00, //........ | ||
71 | 0x00},//........ | ||
72 | //1 | ||
73 | {0x00, //........ | ||
74 | 0x00, //........ | ||
75 | 0x00, //...OO... | ||
76 | 0x44, //....O... | ||
77 | 0x7c, //....O... | ||
78 | 0x40, //....O... | ||
79 | 0x00, //...OOO.. | ||
80 | 0x00},//........ | ||
81 | //2 | ||
82 | {0x00, //........ | ||
83 | 0x00, //........ | ||
84 | 0x48, //...OO... | ||
85 | 0x64, //..O..O.. | ||
86 | 0x54, //....O... | ||
87 | 0x48, //...O.... | ||
88 | 0x00, //..OOOO.. | ||
89 | 0x00},//........ | ||
90 | //3 | ||
91 | {0x00, //........ | ||
92 | 0x00, //........ | ||
93 | 0x44, //..OOO... | ||
94 | 0x54, //.....O.. | ||
95 | 0x54, //...OO... | ||
96 | 0x28, //.....O.. | ||
97 | 0x00, //..OOO... | ||
98 | 0x00},//........ | ||
99 | //4 | ||
100 | {0x00, //........ | ||
101 | 0x00, //........ | ||
102 | 0x1c, //..O..... | ||
103 | 0x10, //..O..... | ||
104 | 0x70, //..OOOO.. | ||
105 | 0x10, //....O... | ||
106 | 0x00, //....O... | ||
107 | 0x00},//........ | ||
108 | //5 | ||
109 | {0x00, //........ | ||
110 | 0x00, //........ | ||
111 | 0x5c, //..OOOO.. | ||
112 | 0x54, //..O..... | ||
113 | 0x54, //..OOO... | ||
114 | 0x24, //.....O.. | ||
115 | 0x00, //..OOO... | ||
116 | 0x00},//........ | ||
117 | //6 | ||
118 | {0x00, //........ | ||
119 | 0x00, //........ | ||
120 | 0x38, //...OOO.. | ||
121 | 0x54, //..O..... | ||
122 | 0x54, //..OOO... | ||
123 | 0x24, //..O..O.. | ||
124 | 0x00, //...OO... | ||
125 | 0x00},//........ | ||
126 | //7 | ||
127 | {0x00, //........ | ||
128 | 0x00, //........ | ||
129 | 0x44, //..OOOO.. | ||
130 | 0x24, //.....O.. | ||
131 | 0x14, //....O... | ||
132 | 0x0c, //...O.... | ||
133 | 0x00, //..O..... | ||
134 | 0x00},//........ | ||
135 | //8 | ||
136 | {0x00, //........ | ||
137 | 0x00, //........ | ||
138 | 0x28, //...OO... | ||
139 | 0x54, //..O..O.. | ||
140 | 0x54, //...OO... | ||
141 | 0x28, //..O..O.. | ||
142 | 0x00, //...OO... | ||
143 | 0x00},//........ | ||
144 | }; | ||
145 | |||
146 | /* the tile struct | ||
147 | if there is a mine, mine is true | ||
148 | if tile is known by player, known is true | ||
149 | if tile has a flag, flag is true | ||
150 | neighbors is the total number of mines arround tile | ||
151 | */ | ||
152 | typedef struct tile { | ||
153 | unsigned char mine : 1; | ||
154 | unsigned char known : 1; | ||
155 | unsigned char flag : 1; | ||
156 | unsigned char neighbors : 4; | ||
157 | } tile; | ||
158 | |||
159 | //the height and width of the field | ||
160 | //could be variable if malloc worked in the API :) | ||
161 | const int height = LCD_HEIGHT/8; | ||
162 | const int width = LCD_WIDTH/8; | ||
163 | |||
164 | //the minefield | ||
165 | tile minefield[LCD_HEIGHT/8][LCD_WIDTH/8]; | ||
166 | |||
167 | //total number of mines on the game | ||
168 | int mine_num = 0; | ||
169 | |||
170 | //discovers the tile when player clears one of them | ||
171 | //a chain reaction (of discovery) occurs if tile has no mines | ||
172 | //as neighbors | ||
173 | void discover(int, int); | ||
174 | void discover(int x, int y){ | ||
175 | |||
176 | if(x<0) return; | ||
177 | if(y<0) return; | ||
178 | if(x>width-1) return; | ||
179 | if(y>height-1) return; | ||
180 | if(minefield[y][x].known) return; | ||
181 | |||
182 | minefield[y][x].known = 1; | ||
183 | if(minefield[y][x].neighbors == 0){ | ||
184 | discover(x-1,y-1); | ||
185 | discover(x,y-1); | ||
186 | discover(x+1,y-1); | ||
187 | discover(x+1,y); | ||
188 | discover(x+1,y+1); | ||
189 | discover(x,y+1); | ||
190 | discover(x-1,y+1); | ||
191 | discover(x-1,y); | ||
192 | } | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | |||
197 | //init not mine related elements of the mine field | ||
198 | void minesweeper_init(void){ | ||
199 | int i,j; | ||
200 | |||
201 | for(i=0;i<height;i++){ | ||
202 | for(j=0;j<width;j++){ | ||
203 | minefield[i][j].known = 0; | ||
204 | minefield[i][j].flag = 0; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | //put mines on the mine field | ||
211 | //there is p% chance that a tile is a mine | ||
212 | //if the tile has coordinates (x,y), then it can't be a mine | ||
213 | void minesweeper_putmines(int p, int x, int y){ | ||
214 | int i,j; | ||
215 | |||
216 | for(i=0;i<height;i++){ | ||
217 | for(j=0;j<width;j++){ | ||
218 | if(rb->rand()%100<p && !(y==i && x==j)){ | ||
219 | minefield[i][j].mine = 1; | ||
220 | mine_num++; | ||
221 | } else { | ||
222 | minefield[i][j].mine = 0; | ||
223 | } | ||
224 | minefield[i][j].neighbors = 0; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | //we need to compute the neighbor element for each tile | ||
229 | for(i=0;i<height;i++){ | ||
230 | for(j=0;j<width;j++){ | ||
231 | if(i>0){ | ||
232 | if(j>0) minefield[i][j].neighbors += minefield[i-1][j-1].mine; | ||
233 | minefield[i][j].neighbors += minefield[i-1][j].mine; | ||
234 | if(j<width-1) minefield[i][j].neighbors += minefield[i-1][j+1].mine; | ||
235 | } | ||
236 | if(j>0) minefield[i][j].neighbors += minefield[i][j-1].mine; | ||
237 | if(j<width-1) minefield[i][j].neighbors += minefield[i][j+1].mine; | ||
238 | if(i<height-1){ | ||
239 | if(j>0) minefield[i][j].neighbors += minefield[i+1][j-1].mine; | ||
240 | minefield[i][j].neighbors += minefield[i+1][j].mine; | ||
241 | if(j<width-1) minefield[i][j].neighbors += minefield[i+1][j+1].mine; | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | //the big and ugly function that is the game | ||
248 | int minesweeper(void){ | ||
249 | |||
250 | |||
251 | int i,j; | ||
252 | |||
253 | //the cursor coordinates | ||
254 | int x=0,y=0; | ||
255 | |||
256 | //number of tiles left on the game | ||
257 | int tiles_left=width*height; | ||
258 | |||
259 | //percentage of mines on minefield used durring generation | ||
260 | int p=16; | ||
261 | |||
262 | //a usefull string for snprintf | ||
263 | char str[30]; | ||
264 | |||
265 | //welcome screen where player can chose mine percentage | ||
266 | i = 0; | ||
267 | while(true){ | ||
268 | rb->lcd_clear_display(); | ||
269 | |||
270 | rb->lcd_putsxy(1,1,"Mine Sweeper"); | ||
271 | |||
272 | rb->snprintf(str, 20, "%d%% mines", p); | ||
273 | rb->lcd_putsxy(1,19,str); | ||
274 | rb->lcd_putsxy(1,28,"down / up"); | ||
275 | rb->lcd_putsxy(1,44,"ON to start"); | ||
276 | |||
277 | rb->lcd_update(); | ||
278 | |||
279 | |||
280 | switch(rb->button_get(true)){ | ||
281 | case BUTTON_DOWN: | ||
282 | case BUTTON_LEFT: | ||
283 | p = (p + 98)%100; | ||
284 | break; | ||
285 | |||
286 | case BUTTON_UP: | ||
287 | case BUTTON_RIGHT: | ||
288 | p = (p + 2)%100; | ||
289 | break; | ||
290 | |||
291 | case BUTTON_ON://start playing | ||
292 | i = 1; | ||
293 | break; | ||
294 | |||
295 | case BUTTON_OFF://quit program | ||
296 | return MINESWEEPER_QUIT; | ||
297 | } | ||
298 | if(i==1) break; | ||
299 | } | ||
300 | |||
301 | |||
302 | /******************** | ||
303 | * init * | ||
304 | ********************/ | ||
305 | |||
306 | minesweeper_init(); | ||
307 | |||
308 | /********************** | ||
309 | * play * | ||
310 | **********************/ | ||
311 | |||
312 | while(true){ | ||
313 | |||
314 | //clear the screen buffer | ||
315 | rb->lcd_clear_display(); | ||
316 | |||
317 | //display the mine field | ||
318 | for(i=0;i<height;i++){ | ||
319 | for(j=0;j<width;j++){ | ||
320 | rb->lcd_drawrect(j*8,i*8,8,8); | ||
321 | if(minefield[i][j].known){ | ||
322 | if(minefield[i][j].mine){ | ||
323 | rb->lcd_putsxy(j*8+1,i*8+1,"b"); | ||
324 | } else if(minefield[i][j].neighbors){ | ||
325 | rb->lcd_bitmap(num[minefield[i][j].neighbors],j*8,i*8,8,8,false); | ||
326 | } | ||
327 | } else if(minefield[i][j].flag) { | ||
328 | rb->lcd_drawline(j*8+2,i*8+2,j*8+5,i*8+5); | ||
329 | rb->lcd_drawline(j*8+2,i*8+5,j*8+5,i*8+2); | ||
330 | } else { | ||
331 | rb->lcd_fillrect(j*8+2,i*8+2,4,4); | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | //display the cursor | ||
337 | rb->lcd_invertrect(x*8,y*8,8,8); | ||
338 | |||
339 | //update the screen | ||
340 | rb->lcd_update(); | ||
341 | |||
342 | switch(rb->button_get(true)){ | ||
343 | //quit minesweeper (you really shouldn't use this button ...) | ||
344 | case BUTTON_OFF: | ||
345 | return MINESWEEPER_QUIT; | ||
346 | |||
347 | //move cursor left | ||
348 | case BUTTON_LEFT: | ||
349 | x = (x + width - 1)%width; | ||
350 | break; | ||
351 | |||
352 | //move cursor right | ||
353 | case BUTTON_RIGHT: | ||
354 | x = (x + 1)%width; | ||
355 | break; | ||
356 | |||
357 | //move cursor down | ||
358 | case BUTTON_DOWN: | ||
359 | y = (y + 1)%height; | ||
360 | break; | ||
361 | |||
362 | //move cursor up | ||
363 | case BUTTON_UP: | ||
364 | y = (y + height - 1)%height; | ||
365 | break; | ||
366 | |||
367 | //discover a tile (and it's neighbors if .neighbors == 0) | ||
368 | case BUTTON_ON: | ||
369 | case BUTTON_F2: | ||
370 | if(minefield[y][x].flag) break; | ||
371 | //we put the mines on the first "click" so that you don't | ||
372 | //lose on the first "click" | ||
373 | if(tiles_left == width*height) minesweeper_putmines(p,x,y); | ||
374 | discover(x,y); | ||
375 | if(minefield[y][x].mine){ | ||
376 | return MINESWEEPER_LOSE; | ||
377 | } | ||
378 | tiles_left = 0; | ||
379 | for(i=0;i<height;i++){ | ||
380 | for(j=0;j<width;j++){ | ||
381 | if(minefield[i][j].known == 0) tiles_left++; | ||
382 | } | ||
383 | } | ||
384 | if(tiles_left == mine_num){ | ||
385 | return MINESWEEPER_WIN; | ||
386 | } | ||
387 | break; | ||
388 | |||
389 | //toggle flag under cursor | ||
390 | case BUTTON_PLAY: | ||
391 | case BUTTON_F1: | ||
392 | minefield[y][x].flag = (minefield[y][x].flag + 1)%2; | ||
393 | break; | ||
394 | |||
395 | //show how many mines you think you have found and how many | ||
396 | //there really are on the game | ||
397 | case BUTTON_F3: | ||
398 | tiles_left = 0; | ||
399 | for(i=0;i<height;i++){ | ||
400 | for(j=0;j<width;j++){ | ||
401 | if(minefield[i][j].flag) tiles_left++; | ||
402 | } | ||
403 | } | ||
404 | rb->splash(HZ*2, true, "You found %d mines out of %d", tiles_left, mine_num); | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | } | ||
410 | |||
411 | //plugin entry point | ||
412 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
413 | { | ||
414 | //plugin init | ||
415 | TEST_PLUGIN_API(api); | ||
416 | (void)parameter; | ||
417 | rb = api; | ||
418 | //end of plugin init | ||
419 | |||
420 | switch(minesweeper()){ | ||
421 | case MINESWEEPER_WIN: | ||
422 | rb->splash(HZ*2, true, "You Win :)"); | ||
423 | break; | ||
424 | |||
425 | case MINESWEEPER_LOSE: | ||
426 | rb->splash(HZ*2, true, "You Lost :("); | ||
427 | break; | ||
428 | |||
429 | default: | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | return PLUGIN_OK; | ||
434 | } | ||
435 | |||
436 | #endif | ||
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 | /***************************************************************************** | ||
21 | Solitaire by dionoea | ||
22 | |||
23 | use arrows to move the cursor | ||
24 | use ON to select cards in the columns, move cards inside the columns, | ||
25 | 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 color 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 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 */ | ||
44 | static 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 | |||
62 | static 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 | |||
101 | static 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 | |||
239 | typedef 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 | |||
247 | unsigned 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 | ||
264 | void 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 | ||
309 | int 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 | ||
381 | unsigned char cur_card; | ||
382 | //player's cursor column num | ||
383 | unsigned char cur_col; | ||
384 | |||
385 | //selected card | ||
386 | unsigned char sel_card; | ||
387 | |||
388 | //the deck | ||
389 | card deck[COLORS * CARDS_PER_COLOR]; | ||
390 | |||
391 | //the remaining cards | ||
392 | unsigned char rem; | ||
393 | unsigned char cur_rem; | ||
394 | |||
395 | //the 7 game columns | ||
396 | unsigned char cols[COL_NUM]; | ||
397 | |||
398 | //the 4 final color stacks | ||
399 | unsigned char stacks[COLORS]; | ||
400 | |||
401 | //initialize the game | ||
402 | void 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 | ||
462 | void 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 | |||
849 | enum 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 | ||