Fix yellow
[Rockbox.git] / apps / plugins / sliding_puzzle.c
blob36c95b9dda9a09218c12940f9940dec011d20994
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Vicentini Martin
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 ****************************************************************************/
19 #include "plugin.h"
20 #include "bmp.h"
22 #ifdef HAVE_LCD_BITMAP
23 PLUGIN_HEADER
25 /* variable button definitions */
26 #if CONFIG_KEYPAD == RECORDER_PAD
27 #define PUZZLE_QUIT BUTTON_OFF
28 #define PUZZLE_LEFT BUTTON_LEFT
29 #define PUZZLE_RIGHT BUTTON_RIGHT
30 #define PUZZLE_UP BUTTON_UP
31 #define PUZZLE_DOWN BUTTON_DOWN
32 #define PUZZLE_SHUFFLE BUTTON_F1
33 #define PUZZLE_PICTURE BUTTON_F2
35 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
36 #define PUZZLE_QUIT BUTTON_OFF
37 #define PUZZLE_LEFT BUTTON_LEFT
38 #define PUZZLE_RIGHT BUTTON_RIGHT
39 #define PUZZLE_UP BUTTON_UP
40 #define PUZZLE_DOWN BUTTON_DOWN
41 #define PUZZLE_SHUFFLE BUTTON_F1
42 #define PUZZLE_PICTURE BUTTON_F2
44 #elif CONFIG_KEYPAD == ONDIO_PAD
45 #define PUZZLE_QUIT BUTTON_OFF
46 #define PUZZLE_LEFT BUTTON_LEFT
47 #define PUZZLE_RIGHT BUTTON_RIGHT
48 #define PUZZLE_UP BUTTON_UP
49 #define PUZZLE_DOWN BUTTON_DOWN
50 #define PUZZLE_SHUFFLE_PICTURE_PRE BUTTON_MENU
51 #define PUZZLE_SHUFFLE (BUTTON_MENU | BUTTON_REPEAT)
52 #define PUZZLE_PICTURE (BUTTON_MENU | BUTTON_REL)
54 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
55 (CONFIG_KEYPAD == IRIVER_H300_PAD)
56 #define PUZZLE_QUIT BUTTON_OFF
57 #define PUZZLE_LEFT BUTTON_LEFT
58 #define PUZZLE_RIGHT BUTTON_RIGHT
59 #define PUZZLE_UP BUTTON_UP
60 #define PUZZLE_DOWN BUTTON_DOWN
61 #define PUZZLE_SHUFFLE BUTTON_SELECT
62 #define PUZZLE_PICTURE BUTTON_ON
64 #define PUZZLE_RC_QUIT BUTTON_RC_STOP
66 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
67 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
68 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
69 #define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_MENU)
70 #define PUZZLE_LEFT BUTTON_LEFT
71 #define PUZZLE_RIGHT BUTTON_RIGHT
72 #define PUZZLE_UP BUTTON_MENU
73 #define PUZZLE_DOWN BUTTON_PLAY
74 #define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_LEFT)
75 #define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_RIGHT)
77 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
78 #define PUZZLE_QUIT BUTTON_POWER
79 #define PUZZLE_LEFT BUTTON_LEFT
80 #define PUZZLE_RIGHT BUTTON_RIGHT
81 #define PUZZLE_UP BUTTON_UP
82 #define PUZZLE_DOWN BUTTON_DOWN
83 #define PUZZLE_SHUFFLE BUTTON_REC
84 #define PUZZLE_PICTURE BUTTON_PLAY
86 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
87 #define PUZZLE_QUIT BUTTON_POWER
88 #define PUZZLE_LEFT BUTTON_LEFT
89 #define PUZZLE_RIGHT BUTTON_RIGHT
90 #define PUZZLE_UP BUTTON_UP
91 #define PUZZLE_DOWN BUTTON_DOWN
92 #define PUZZLE_SHUFFLE BUTTON_SELECT
93 #define PUZZLE_PICTURE BUTTON_A
95 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
96 (CONFIG_KEYPAD == SANSA_C200_PAD)
97 #define PUZZLE_QUIT BUTTON_POWER
98 #define PUZZLE_LEFT BUTTON_LEFT
99 #define PUZZLE_RIGHT BUTTON_RIGHT
100 #define PUZZLE_UP BUTTON_UP
101 #define PUZZLE_DOWN BUTTON_DOWN
102 #define PUZZLE_SHUFFLE BUTTON_REC
103 #define PUZZLE_PICTURE BUTTON_SELECT
105 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
106 #define PUZZLE_QUIT BUTTON_POWER
107 #define PUZZLE_LEFT BUTTON_LEFT
108 #define PUZZLE_RIGHT BUTTON_RIGHT
109 #define PUZZLE_UP BUTTON_SCROLL_UP
110 #define PUZZLE_DOWN BUTTON_SCROLL_DOWN
111 #define PUZZLE_SHUFFLE BUTTON_REW
112 #define PUZZLE_PICTURE BUTTON_PLAY
114 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
115 #define PUZZLE_QUIT BUTTON_BACK
116 #define PUZZLE_LEFT BUTTON_LEFT
117 #define PUZZLE_RIGHT BUTTON_RIGHT
118 #define PUZZLE_UP BUTTON_UP
119 #define PUZZLE_DOWN BUTTON_DOWN
120 #define PUZZLE_SHUFFLE BUTTON_SELECT
121 #define PUZZLE_PICTURE BUTTON_MENU
123 #elif (CONFIG_KEYPAD == MROBE100_PAD)
124 #define PUZZLE_QUIT BUTTON_POWER
125 #define PUZZLE_LEFT BUTTON_LEFT
126 #define PUZZLE_RIGHT BUTTON_RIGHT
127 #define PUZZLE_UP BUTTON_UP
128 #define PUZZLE_DOWN BUTTON_DOWN
129 #define PUZZLE_SHUFFLE BUTTON_SELECT
130 #define PUZZLE_PICTURE BUTTON_DISPLAY
132 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
133 #define PUZZLE_QUIT BUTTON_RC_REC
134 #define PUZZLE_LEFT BUTTON_RC_REW
135 #define PUZZLE_RIGHT BUTTON_RC_FF
136 #define PUZZLE_UP BUTTON_RC_VOL_UP
137 #define PUZZLE_DOWN BUTTON_RC_VOL_DOWN
138 #define PUZZLE_SHUFFLE BUTTON_RC_MODE
139 #define PUZZLE_PICTURE BUTTON_RC_MENU
141 #elif (CONFIG_KEYPAD == COWOND2_PAD)
142 #define PUZZLE_QUIT BUTTON_POWER
143 #define PUZZLE_QUIT_TEXT "[POWER]"
145 #else
146 #error No keymap defined!
147 #endif
149 #ifdef HAVE_TOUCHPAD
150 #ifndef PUZZLE_QUIT
151 #define PUZZLE_QUIT BUTTON_TOPLEFT
152 #endif
153 #ifndef PUZZLE_LEFT
154 #define PUZZLE_LEFT BUTTON_MIDLEFT
155 #endif
156 #ifndef PUZZLE_RIGHT
157 #define PUZZLE_RIGHT BUTTON_MIDRIGHT
158 #endif
159 #ifndef PUZZLE_UP
160 #define PUZZLE_UP BUTTON_TOPMIDDLE
161 #endif
162 #ifndef PUZZLE_DOWN
163 #define PUZZLE_DOWN BUTTON_BOTTOMMIDDLE
164 #endif
165 #ifndef PUZZLE_SHUFFLE
166 #define PUZZLE_SHUFFLE BUTTON_BOTTOMLEFT
167 #endif
168 #ifndef PUZZLE_PICTURE
169 #define PUZZLE_PICTURE BUTTON_CENTER
170 #endif
171 #ifndef PUZZLE_QUIT_TEXT
172 #define PUZZLE_QUIT_TEXT "[TOPLEFT]"
173 #endif
174 #ifndef PUZZLE_SHUFFLE_TEXT
175 #define PUZZLE_SHUFFLE_TEXT "[BOTTOMLEFT]"
176 #endif
177 #ifndef PUZZLE_PICTURE_TEXT
178 #define PUZZLE_PICTURE_TEXT "[CENTER]"
179 #endif
180 #endif
182 #include "sliding_puzzle.h"
183 #define IMAGE_WIDTH BMPWIDTH_sliding_puzzle
184 #define IMAGE_HEIGHT BMPHEIGHT_sliding_puzzle
185 #define IMAGE_SIZE IMAGE_WIDTH
187 static const struct plugin_api* rb;
189 /* use a square image, (the default Archos bitmap looks square on its display)
190 Puzzle image dimension is min(lcd_height,lcd_width)
191 4x4 is more convenient for square puzzles
192 Note: sliding_puzzle.bmp should be evenly divisible by SPOTS_X
193 and SPOTS_Y, otherwise lcd_bitmap_part stride won't be correct */
194 #define SPOTS_X 4
195 #define SPOTS_Y 4
196 #define SPOTS_WIDTH (IMAGE_WIDTH / SPOTS_X)
197 #define SPOTS_HEIGHT (IMAGE_HEIGHT / SPOTS_Y)
198 #define NUM_SPOTS (SPOTS_X*SPOTS_Y)
199 #define HOLE_ID (NUM_SPOTS)
200 #define INITIAL_HOLE (HOLE_ID-1)
202 enum picmodes
204 PICMODE_NUMERALS = 0,
205 PICMODE_INITIAL_PICTURE,
206 PICMODE_DEFAULT_PICTURE,
207 #ifdef HAVE_ALBUMART
208 PICMODE_ALBUM_ART,
209 #endif
210 // PICMODE_RANDOM,
211 PICMODE_LAST_XXX /* placeholder */
214 static const char* const picmode_descriptions[] = {
215 "Numerals",
216 "Viewer Picture",
217 "Default Picture",
218 #ifdef HAVE_ALBUMART
219 "Album Art",
220 #endif
221 "Shouldn't Get Here",
224 static int spots[NUM_SPOTS];
225 static int hole = INITIAL_HOLE, moves;
226 static unsigned char s[32];
227 static enum picmodes picmode = PICMODE_INITIAL_PICTURE;
228 static int num_font = FONT_UI;
229 static int moves_font = FONT_UI;
230 static int moves_y = 0;
232 static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
233 __attribute__ ((aligned(16)));
234 #if LCD_DEPTH>1
235 static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)]
236 __attribute__ ((aligned(16)));
237 #endif
238 #ifdef HAVE_ALBUMART
239 static char albumart_path[MAX_PATH+1];
240 #endif
241 static char img_buf_path[MAX_PATH+1];
243 static const fb_data * puzzle_bmp_ptr;
244 /* initial_bmp_path points to selected bitmap if this game is launched
245 as a viewer for a .bmp file, or NULL if game is launched regular way */
246 static const char * initial_bmp_path=NULL;
248 #ifdef HAVE_ALBUMART
249 const char * get_albumart_bmp_path(void)
251 struct mp3entry* track = rb->audio_current_track();
253 if (!track || !track->path || track->path[0] == '\0')
254 return NULL;
256 if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) )
257 return NULL;
259 albumart_path[ MAX_PATH ] = '\0';
260 return albumart_path;
262 #endif
264 const char * get_random_bmp_path(void)
266 return(initial_bmp_path);
269 static bool load_resize_bitmap(void)
271 int rc;
272 const char * filename = NULL;
274 /* initially assume using the built-in default */
275 puzzle_bmp_ptr = sliding_puzzle;
277 switch( picmode ){
278 /* some modes don't even need to touch disk and trivially succeed */
279 case PICMODE_NUMERALS:
280 case PICMODE_DEFAULT_PICTURE:
281 default:
282 return(true);
284 #ifdef HAVE_ALBUMART
285 case PICMODE_ALBUM_ART:
286 filename = get_albumart_bmp_path();
287 break;
288 #endif
290 case PICMODE_RANDOM:
291 if(NULL == (filename=get_random_bmp_path()) )
292 filename = initial_bmp_path;
293 break;
295 case PICMODE_INITIAL_PICTURE:
296 filename = initial_bmp_path;
297 break;
300 if( filename != NULL )
302 /* if we already loaded image before, don't touch disk */
303 if( 0 == rb->strcmp( filename, img_buf_path ) )
305 puzzle_bmp_ptr = (const fb_data *)img_buf;
306 return true;
309 struct bitmap main_bitmap;
310 rb->memset(&main_bitmap,0,sizeof(struct bitmap));
311 main_bitmap.data = img_buf;
313 #if LCD_DEPTH>1
314 struct bitmap temp_bitmap;
315 rb->memset(&temp_bitmap,0,sizeof(struct bitmap));
316 temp_bitmap.data = temp_img_buf;
318 main_bitmap.width = IMAGE_WIDTH;
319 main_bitmap.height = IMAGE_HEIGHT;
321 rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf),
322 FORMAT_NATIVE );
323 if( rc > 0 )
325 #ifdef HAVE_LCD_COLOR
326 smooth_resize_bitmap( &temp_bitmap, &main_bitmap );
327 #else
328 simple_resize_bitmap( &temp_bitmap, &main_bitmap );
329 #endif
330 puzzle_bmp_ptr = (const fb_data *)img_buf;
331 rb->strcpy( img_buf_path, filename );
332 return true;
334 #else
335 rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf),
336 FORMAT_NATIVE );
337 if( rc > 0 )
339 puzzle_bmp_ptr = (const fb_data *)img_buf;
340 rb->strcpy( img_buf_path, filename );
341 return true;
343 #endif
346 /* something must have failed. get_albumart_bmp_path could return
347 NULL if albumart doesn't exist or couldn't be loaded, or
348 read_bmp_file could have failed. return false and caller should
349 try the next mode (PICMODE_DEFAULT_PICTURE and PICMODE_NUMERALS will
350 always succeed) */
351 return false;
354 /* draws a spot at the coordinates (x,y), range of p is 1-20 */
355 static void draw_spot(int p, int x, int y)
357 int w, h;
359 if (p == HOLE_ID)
361 #if LCD_DEPTH==1
362 /* the bottom-right cell of the default sliding_puzzle image is
363 an appropriate hole graphic */
364 rb->lcd_bitmap_part(sliding_puzzle, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
365 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
366 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
367 #else
368 /* just draw a black rectangle */
369 int old_fg = rb->lcd_get_foreground();
370 rb->lcd_set_foreground(LCD_BLACK);
371 rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT);
372 rb->lcd_set_foreground(old_fg);
373 #endif
375 else if (picmode != PICMODE_NUMERALS)
377 rb->lcd_bitmap_part( puzzle_bmp_ptr, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
378 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
379 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
380 } else {
381 rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
382 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
383 rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2);
384 rb->lcd_set_drawmode(DRMODE_SOLID);
385 rb->snprintf(s, sizeof(s), "%d", p);
386 rb->lcd_setfont(num_font);
387 rb->lcd_getstringsize(s, &w, &h);
388 rb->lcd_putsxy(x + (SPOTS_WIDTH/2) - w / 2,
389 y + (SPOTS_HEIGHT/2) - h / 2, s);
393 /* check if the puzzle is solved */
394 static bool puzzle_finished(void)
396 int i;
397 for (i=0; i<NUM_SPOTS; i++)
398 if (spots[i] != (i+1))
399 return false;
400 return true;
403 /* move a piece in any direction */
404 static void move_spot(int x, int y)
406 int i, w;
407 spots[hole] = spots[hole-x-SPOTS_X*y];
408 hole -= (x+SPOTS_X*y);
409 moves++;
410 rb->lcd_setfont(moves_font);
411 #if LCD_WIDTH > LCD_HEIGHT
412 rb->snprintf(s, sizeof(s), "%d", moves);
413 w = rb->lcd_getstringsize(s, NULL, NULL);
414 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
415 moves_y, s);
416 #else
417 (void)w;
418 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
419 rb->lcd_putsxy(3, moves_y, s);
420 #endif
421 for(i=1;i<=4;i++)
423 draw_spot(HOLE_ID,
424 (hole%SPOTS_X)*SPOTS_WIDTH,
425 (hole/SPOTS_X)*SPOTS_HEIGHT);
426 draw_spot(spots[hole],
427 (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5,
428 (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5);
429 rb->lcd_update();
430 rb->sleep(HZ/50);
432 draw_spot(HOLE_ID,
433 (hole%SPOTS_X)*SPOTS_WIDTH,
434 (hole/SPOTS_X)*SPOTS_HEIGHT);
435 draw_spot(spots[hole],
436 ((hole%SPOTS_X)+x)*SPOTS_WIDTH,
437 ((hole/SPOTS_X)+y)*SPOTS_HEIGHT);
438 rb->lcd_update();
440 spots[hole] = HOLE_ID;
443 static void draw_playfield(void)
445 int i, w;
447 rb->lcd_clear_display();
448 rb->lcd_setfont(moves_font);
449 #if LCD_WIDTH > LCD_HEIGHT
450 rb->lcd_vline(IMAGE_WIDTH, 0, LCD_HEIGHT-1);
451 w = rb->lcd_getstringsize("Moves", NULL, NULL);
452 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
453 10, "Moves");
454 rb->snprintf(s, sizeof(s), "%d", moves);
455 w = rb->lcd_getstringsize(s, NULL, NULL);
456 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
457 moves_y, s);
458 #else
459 (void)w;
460 rb->lcd_hline(0, LCD_WIDTH-1, IMAGE_HEIGHT);
461 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
462 rb->lcd_putsxy(3, moves_y, s);
463 #endif
465 /* draw spots to the lcd */
466 for (i=0; i<NUM_SPOTS; i++)
467 draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT);
469 rb->lcd_update();
472 /* initializes the puzzle */
473 static void puzzle_init(void)
475 int i, r, temp, tsp[NUM_SPOTS];
477 moves = 0;
479 /* shuffle spots */
480 for (i=NUM_SPOTS-1; i>=0; i--) {
481 r = (rb->rand() % (i+1));
483 temp = spots[r];
484 spots[r] = spots[i];
485 spots[i] = temp;
487 if (spots[i]==HOLE_ID)
488 hole = i;
491 /* test if the puzzle is solvable */
492 for (i=0; i<NUM_SPOTS; i++)
493 tsp[i] = spots[i];
494 r=0;
496 /* First, check if the problem has even or odd parity,
497 depending on where the empty square is */
498 if ((((SPOTS_X-1)-hole%SPOTS_X) + ((SPOTS_Y-1)-hole/SPOTS_X))%2 == 1)
499 ++r;
501 /* Now check how many swaps we need to solve it */
502 for (i=0; i<NUM_SPOTS-1; i++) {
503 while (tsp[i] != (i+1)) {
504 temp = tsp[i];
505 tsp[i] = tsp[temp-1];
506 tsp[temp-1] = temp;
507 ++r;
511 /* if the random puzzle isn't solvable just change two spots */
512 if (r%2 == 1) {
513 if (spots[0]!=HOLE_ID && spots[1]!=HOLE_ID) {
514 temp = spots[0];
515 spots[0] = spots[1];
516 spots[1] = temp;
517 } else {
518 temp = spots[2];
519 spots[2] = spots[3];
520 spots[3] = temp;
524 draw_playfield();
527 /* the main game loop */
528 static int puzzle_loop(void)
530 int button;
531 int lastbutton = BUTTON_NONE;
532 bool load_success;
534 puzzle_init();
535 while(true) {
536 button = rb->button_get(true);
537 switch (button) {
538 #ifdef PUZZLE_RC_QUIT
539 case PUZZLE_RC_QUIT:
540 #endif
541 case PUZZLE_QUIT:
542 /* get out of here */
543 return PLUGIN_OK;
545 case PUZZLE_SHUFFLE:
546 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
547 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
548 break;
549 #endif
550 /* mix up the pieces */
551 puzzle_init();
552 break;
554 case PUZZLE_PICTURE:
555 #ifdef PUZZLE_SHUFFLE_PICTURE_PRE
556 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
557 break;
558 #endif
559 /* change picture */
560 picmode = (picmode+1)%PICMODE_LAST_XXX;
562 /* if load_resize_bitmap fails to load bitmap, try next picmode */
565 load_success = load_resize_bitmap();
566 if( !load_success )
567 picmode = (picmode+1)%PICMODE_LAST_XXX;
569 while( !load_success );
571 /* tell the user what mode we picked in the end! */
572 rb->splash(HZ,picmode_descriptions[ picmode ] );
573 draw_playfield();
574 break;
576 case PUZZLE_LEFT:
577 if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished())
578 move_spot(-1, 0);
579 break;
581 case PUZZLE_RIGHT:
582 if ((hole%SPOTS_X)>0 && !puzzle_finished())
583 move_spot(1, 0);
584 break;
586 case PUZZLE_UP:
587 if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished())
588 move_spot(0, -1);
589 break;
591 case PUZZLE_DOWN:
592 if ((hole/SPOTS_X)>0 && !puzzle_finished())
593 move_spot(0, 1);
594 break;
596 default:
597 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
598 return PLUGIN_USB_CONNECTED;
599 break;
601 if (button != BUTTON_NONE)
602 lastbutton = button;
606 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
608 int i, w, h;
610 rb = api;
612 initial_bmp_path=(const char *)parameter;
613 picmode = PICMODE_INITIAL_PICTURE;
614 img_buf_path[0] = '\0';
616 /* If launched as a viewer, just go straight to the game without
617 bothering with the splash or instructions page */
618 if(parameter==NULL)
620 /* if not launched as a viewer, use default puzzle, and show help */
621 picmode = PICMODE_DEFAULT_PICTURE;
623 /* print title */
624 rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h);
625 w = (w+1)/2;
626 h = (h+1)/2;
627 rb->lcd_clear_display();
628 rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h,
629 (unsigned char *)"Sliding Puzzle");
630 rb->lcd_update();
631 rb->sleep(HZ);
633 /* print instructions */
634 rb->lcd_clear_display();
635 rb->lcd_setfont(FONT_SYSFIXED);
636 #if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD
637 rb->lcd_putsxy(3, 18, "[OFF] to stop");
638 rb->lcd_putsxy(3, 28, "[F1] shuffle");
639 rb->lcd_putsxy(3, 38, "[F2] change pic");
640 #elif CONFIG_KEYPAD == ONDIO_PAD
641 rb->lcd_putsxy(0, 18, "[OFF] to stop");
642 rb->lcd_putsxy(0, 28, "[MODE..] shuffle");
643 rb->lcd_putsxy(0, 38, "[MODE] change pic");
644 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
645 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
646 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
647 rb->lcd_putsxy(0, 18, "[S-MENU] to stop");
648 rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle");
649 rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic");
650 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
651 (CONFIG_KEYPAD == IRIVER_H300_PAD)
652 rb->lcd_putsxy(0, 18, "[STOP] to stop");
653 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
654 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
655 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
656 rb->lcd_putsxy(0, 18, "[OFF] to stop");
657 rb->lcd_putsxy(0, 28, "[REC] shuffle");
658 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
659 #elif CONFIG_KEYPAD == GIGABEAT_PAD
660 rb->lcd_putsxy(0, 18, "[OFF] to stop");
661 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
662 rb->lcd_putsxy(0, 38, "[A] change pic");
663 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
664 (CONFIG_KEYPAD == SANSA_C200_PAD)
665 rb->lcd_putsxy(0, 18, "[OFF] to stop");
666 rb->lcd_putsxy(0, 28, "[REC] shuffle");
667 rb->lcd_putsxy(0, 38, "[SELECT] change pic");
668 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
669 rb->lcd_putsxy(0, 18, "[OFF] to stop");
670 rb->lcd_putsxy(0, 28, "[REW] shuffle");
671 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
672 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
673 rb->lcd_putsxy(0, 18, "[REC] to stop");
674 rb->lcd_putsxy(0, 28, "[MODE] shuffle");
675 rb->lcd_putsxy(0, 38, "[MENU] change pic");
676 #endif
677 #ifdef HAVE_TOUCHPAD
678 rb->lcd_putsxy(0, 18, PUZZLE_QUIT_TEXT " to stop");
679 rb->lcd_putsxy(0, 28, PUZZLE_SHUFFLE_TEXT " shuffle");
680 rb->lcd_putsxy(0, 38, PUZZLE_PICTURE_TEXT " change pic");
681 #endif
682 #ifdef HAVE_ALBUMART
683 rb->lcd_putsxy(0,48," pic->albumart->num");
684 #else
685 rb->lcd_putsxy(0,48," pic<->num");
686 #endif
687 rb->lcd_update();
688 rb->button_get_w_tmo(HZ*2);
691 hole = INITIAL_HOLE;
693 if( !load_resize_bitmap() )
695 rb->lcd_clear_display();
696 rb->splash(HZ*2,"Failed to load bitmap!");
697 return PLUGIN_OK;
700 /* Calculate possible font sizes and text positions */
701 rb->lcd_setfont(FONT_UI);
702 rb->lcd_getstringsize("15", &w, &h);
703 if ((w > (SPOTS_WIDTH-2)) || (h > (SPOTS_HEIGHT-2)))
704 num_font = FONT_SYSFIXED;
706 #if LCD_WIDTH > LCD_HEIGHT
707 rb->lcd_getstringsize("Moves", &w, &h);
708 if (w > (LCD_WIDTH-IMAGE_WIDTH-1))
709 moves_font = FONT_SYSFIXED;
710 rb->lcd_setfont(moves_font);
711 rb->lcd_getstringsize("Moves", &w, &h);
712 moves_y = 10 + h;
713 #else
714 rb->lcd_getstringsize("Moves: 999", &w, &h);
715 if ((w > LCD_WIDTH) || (h > (LCD_HEIGHT-IMAGE_HEIGHT-1)))
716 moves_font = FONT_SYSFIXED;
717 rb->lcd_setfont(moves_font);
718 rb->lcd_getstringsize("Moves: 999", &w, &h);
719 moves_y = (IMAGE_HEIGHT+1+(LCD_HEIGHT-IMAGE_HEIGHT-1)/2) - h / 2;
720 #endif
721 for (i=0; i<NUM_SPOTS; i++)
722 spots[i]=(i+1);
724 #ifdef HAVE_LCD_COLOR
725 rb->lcd_set_background(LCD_BLACK);
726 rb->lcd_set_foreground(LCD_WHITE);
727 rb->lcd_set_backdrop(NULL);
728 #elif LCD_DEPTH > 1
729 rb->lcd_set_background(LCD_WHITE);
730 rb->lcd_set_foreground(LCD_BLACK);
731 rb->lcd_set_backdrop(NULL);
732 #endif
734 draw_playfield();
735 rb->sleep(HZ*2);
737 return puzzle_loop();
740 #endif