blob: 9ed15f4b8aec4a2ab5a899eb2619f9e08d8447c0 [file] [log] [blame]
Björn Stenberg8bebc8b2003-06-29 19:48:24 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +00008 * $Id$
Björn Stenberg8bebc8b2003-06-29 19:48:24 +00009 *
10 * Copyright (C) 2002 Vicentini Martin
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Björn Stenberg8bebc8b2003-06-29 19:48:24 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "plugin.h"
Nicolas Pennequin02f18392008-01-26 00:16:06 +000022#include "bmp.h"
Björn Stenberg8bebc8b2003-06-29 19:48:24 +000023
Nicolas Pennequin02f18392008-01-26 00:16:06 +000024#ifdef HAVE_LCD_BITMAP
Jens Arnolda36b1d42006-01-15 18:20:18 +000025PLUGIN_HEADER
26
Jens Arnolde35a6582004-10-18 21:45:00 +000027/* variable button definitions */
28#if CONFIG_KEYPAD == RECORDER_PAD
29#define PUZZLE_QUIT BUTTON_OFF
Jens Arnold29361ab2008-03-22 10:24:28 +000030#define PUZZLE_LEFT BUTTON_LEFT
31#define PUZZLE_RIGHT BUTTON_RIGHT
Dave Chapman54d44c82005-12-14 01:31:37 +000032#define PUZZLE_UP BUTTON_UP
33#define PUZZLE_DOWN BUTTON_DOWN
Jens Arnolde35a6582004-10-18 21:45:00 +000034#define PUZZLE_SHUFFLE BUTTON_F1
35#define PUZZLE_PICTURE BUTTON_F2
36
Dave Chapmand64e6262007-01-14 13:48:09 +000037#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
38#define PUZZLE_QUIT BUTTON_OFF
Jens Arnold29361ab2008-03-22 10:24:28 +000039#define PUZZLE_LEFT BUTTON_LEFT
40#define PUZZLE_RIGHT BUTTON_RIGHT
Dave Chapmand64e6262007-01-14 13:48:09 +000041#define PUZZLE_UP BUTTON_UP
42#define PUZZLE_DOWN BUTTON_DOWN
43#define PUZZLE_SHUFFLE BUTTON_F1
44#define PUZZLE_PICTURE BUTTON_F2
45
Jens Arnolde35a6582004-10-18 21:45:00 +000046#elif CONFIG_KEYPAD == ONDIO_PAD
47#define PUZZLE_QUIT BUTTON_OFF
Jens Arnold29361ab2008-03-22 10:24:28 +000048#define PUZZLE_LEFT BUTTON_LEFT
49#define PUZZLE_RIGHT BUTTON_RIGHT
Dave Chapman54d44c82005-12-14 01:31:37 +000050#define PUZZLE_UP BUTTON_UP
51#define PUZZLE_DOWN BUTTON_DOWN
Jens Arnolde35a6582004-10-18 21:45:00 +000052#define PUZZLE_SHUFFLE_PICTURE_PRE BUTTON_MENU
53#define PUZZLE_SHUFFLE (BUTTON_MENU | BUTTON_REPEAT)
54#define PUZZLE_PICTURE (BUTTON_MENU | BUTTON_REL)
55
Daniel Stenberg01377e22005-06-29 12:47:24 +000056#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
57 (CONFIG_KEYPAD == IRIVER_H300_PAD)
Daniel Stenberg6700ad82005-02-04 12:41:09 +000058#define PUZZLE_QUIT BUTTON_OFF
Jens Arnold29361ab2008-03-22 10:24:28 +000059#define PUZZLE_LEFT BUTTON_LEFT
60#define PUZZLE_RIGHT BUTTON_RIGHT
Dave Chapman54d44c82005-12-14 01:31:37 +000061#define PUZZLE_UP BUTTON_UP
62#define PUZZLE_DOWN BUTTON_DOWN
Daniel Stenberg6700ad82005-02-04 12:41:09 +000063#define PUZZLE_SHUFFLE BUTTON_SELECT
64#define PUZZLE_PICTURE BUTTON_ON
Dave Chapman54d44c82005-12-14 01:31:37 +000065
Kevin Ferrare0e027bd2006-06-30 16:43:47 +000066#define PUZZLE_RC_QUIT BUTTON_RC_STOP
67
Dave Chapmanfb4e3842006-02-24 20:54:09 +000068#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
Jens Arnoldb7013222007-07-27 09:57:27 +000069 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
70 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
Björn Stenberg69795ab2006-03-18 20:17:25 +000071#define PUZZLE_QUIT (BUTTON_SELECT | BUTTON_MENU)
Jens Arnold29361ab2008-03-22 10:24:28 +000072#define PUZZLE_LEFT BUTTON_LEFT
73#define PUZZLE_RIGHT BUTTON_RIGHT
Björn Stenberg69795ab2006-03-18 20:17:25 +000074#define PUZZLE_UP BUTTON_MENU
75#define PUZZLE_DOWN BUTTON_PLAY
76#define PUZZLE_SHUFFLE (BUTTON_SELECT | BUTTON_LEFT)
77#define PUZZLE_PICTURE (BUTTON_SELECT | BUTTON_RIGHT)
Dave Chapman54d44c82005-12-14 01:31:37 +000078
Jens Arnold85a226d2007-03-16 23:02:39 +000079#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
Daniel Stenbergcedba882006-01-18 11:09:06 +000080#define PUZZLE_QUIT BUTTON_POWER
Jens Arnold29361ab2008-03-22 10:24:28 +000081#define PUZZLE_LEFT BUTTON_LEFT
82#define PUZZLE_RIGHT BUTTON_RIGHT
Daniel Stenbergcedba882006-01-18 11:09:06 +000083#define PUZZLE_UP BUTTON_UP
84#define PUZZLE_DOWN BUTTON_DOWN
85#define PUZZLE_SHUFFLE BUTTON_REC
86#define PUZZLE_PICTURE BUTTON_PLAY
87
Marcoen Hirschberg338e2bb2006-02-24 15:42:52 +000088#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
Marcoen Hirschberga7168fe2007-05-19 23:38:09 +000089#define PUZZLE_QUIT BUTTON_POWER
Jens Arnold29361ab2008-03-22 10:24:28 +000090#define PUZZLE_LEFT BUTTON_LEFT
91#define PUZZLE_RIGHT BUTTON_RIGHT
Marcoen Hirschberg338e2bb2006-02-24 15:42:52 +000092#define PUZZLE_UP BUTTON_UP
93#define PUZZLE_DOWN BUTTON_DOWN
94#define PUZZLE_SHUFFLE BUTTON_SELECT
Marcoen Hirschberga7168fe2007-05-19 23:38:09 +000095#define PUZZLE_PICTURE BUTTON_A
Marcoen Hirschberg338e2bb2006-02-24 15:42:52 +000096
Marianne Arnold12ddb8e2007-09-20 10:49:48 +000097#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
98(CONFIG_KEYPAD == SANSA_C200_PAD)
Barry Wardell24f4a2a2006-10-26 13:38:09 +000099#define PUZZLE_QUIT BUTTON_POWER
Jens Arnold29361ab2008-03-22 10:24:28 +0000100#define PUZZLE_LEFT BUTTON_LEFT
101#define PUZZLE_RIGHT BUTTON_RIGHT
Barry Wardell24f4a2a2006-10-26 13:38:09 +0000102#define PUZZLE_UP BUTTON_UP
103#define PUZZLE_DOWN BUTTON_DOWN
104#define PUZZLE_SHUFFLE BUTTON_REC
105#define PUZZLE_PICTURE BUTTON_SELECT
106
Daniel Stenberg1e88be52006-08-03 20:17:25 +0000107#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
108#define PUZZLE_QUIT BUTTON_POWER
Jens Arnold29361ab2008-03-22 10:24:28 +0000109#define PUZZLE_LEFT BUTTON_LEFT
110#define PUZZLE_RIGHT BUTTON_RIGHT
Daniel Stenberg1e88be52006-08-03 20:17:25 +0000111#define PUZZLE_UP BUTTON_SCROLL_UP
112#define PUZZLE_DOWN BUTTON_SCROLL_DOWN
113#define PUZZLE_SHUFFLE BUTTON_REW
114#define PUZZLE_PICTURE BUTTON_PLAY
115
Will Robertson8215b342008-02-17 12:23:02 +0000116#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
117#define PUZZLE_QUIT BUTTON_BACK
Jens Arnold29361ab2008-03-22 10:24:28 +0000118#define PUZZLE_LEFT BUTTON_LEFT
119#define PUZZLE_RIGHT BUTTON_RIGHT
Will Robertson8215b342008-02-17 12:23:02 +0000120#define PUZZLE_UP BUTTON_UP
121#define PUZZLE_DOWN BUTTON_DOWN
122#define PUZZLE_SHUFFLE BUTTON_SELECT
123#define PUZZLE_PICTURE BUTTON_MENU
124
Robert Kuklad6c8b572008-03-01 22:55:09 +0000125#elif (CONFIG_KEYPAD == MROBE100_PAD)
126#define PUZZLE_QUIT BUTTON_POWER
Jens Arnold29361ab2008-03-22 10:24:28 +0000127#define PUZZLE_LEFT BUTTON_LEFT
128#define PUZZLE_RIGHT BUTTON_RIGHT
Robert Kuklad6c8b572008-03-01 22:55:09 +0000129#define PUZZLE_UP BUTTON_UP
130#define PUZZLE_DOWN BUTTON_DOWN
131#define PUZZLE_SHUFFLE BUTTON_SELECT
132#define PUZZLE_PICTURE BUTTON_DISPLAY
133
Jens Arnold29361ab2008-03-22 10:24:28 +0000134#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
135#define PUZZLE_QUIT BUTTON_RC_REC
136#define PUZZLE_LEFT BUTTON_RC_REW
137#define PUZZLE_RIGHT BUTTON_RC_FF
138#define PUZZLE_UP BUTTON_RC_VOL_UP
139#define PUZZLE_DOWN BUTTON_RC_VOL_DOWN
140#define PUZZLE_SHUFFLE BUTTON_RC_MODE
141#define PUZZLE_PICTURE BUTTON_RC_MENU
142
Rob Purchase554d7ed2008-03-22 22:03:34 +0000143#elif (CONFIG_KEYPAD == COWOND2_PAD)
144#define PUZZLE_QUIT BUTTON_POWER
Rob Purchase297e0502008-04-27 15:30:19 +0000145#define PUZZLE_QUIT_TEXT "[POWER]"
Rob Purchase554d7ed2008-03-22 22:03:34 +0000146
Robert Kuklad6c8b572008-03-01 22:55:09 +0000147#else
148#error No keymap defined!
Jens Arnolde35a6582004-10-18 21:45:00 +0000149#endif
150
Rob Purchase297e0502008-04-27 15:30:19 +0000151#ifdef HAVE_TOUCHPAD
152#ifndef PUZZLE_QUIT
153#define PUZZLE_QUIT BUTTON_TOPLEFT
154#endif
155#ifndef PUZZLE_LEFT
156#define PUZZLE_LEFT BUTTON_MIDLEFT
157#endif
158#ifndef PUZZLE_RIGHT
159#define PUZZLE_RIGHT BUTTON_MIDRIGHT
160#endif
161#ifndef PUZZLE_UP
162#define PUZZLE_UP BUTTON_TOPMIDDLE
163#endif
164#ifndef PUZZLE_DOWN
165#define PUZZLE_DOWN BUTTON_BOTTOMMIDDLE
166#endif
167#ifndef PUZZLE_SHUFFLE
168#define PUZZLE_SHUFFLE BUTTON_BOTTOMLEFT
169#endif
170#ifndef PUZZLE_PICTURE
171#define PUZZLE_PICTURE BUTTON_CENTER
172#endif
173#ifndef PUZZLE_QUIT_TEXT
174#define PUZZLE_QUIT_TEXT "[TOPLEFT]"
175#endif
176#ifndef PUZZLE_SHUFFLE_TEXT
177#define PUZZLE_SHUFFLE_TEXT "[BOTTOMLEFT]"
178#endif
179#ifndef PUZZLE_PICTURE_TEXT
180#define PUZZLE_PICTURE_TEXT "[CENTER]"
181#endif
182#endif
Marianne Arnoldcdc933f2008-01-31 18:08:22 +0000183
184#include "sliding_puzzle.h"
185#define IMAGE_WIDTH BMPWIDTH_sliding_puzzle
186#define IMAGE_HEIGHT BMPHEIGHT_sliding_puzzle
187#define IMAGE_SIZE IMAGE_WIDTH
188
Steve Bavin65265772008-05-13 09:57:56 +0000189static const struct plugin_api* rb;
Marianne Arnolddce2ef82008-02-02 12:10:42 +0000190
191/* use a square image, (the default Archos bitmap looks square on its display)
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000192 Puzzle image dimension is min(lcd_height,lcd_width)
Marianne Arnolddce2ef82008-02-02 12:10:42 +0000193 4x4 is more convenient for square puzzles
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000194 Note: sliding_puzzle.bmp should be evenly divisible by SPOTS_X
195 and SPOTS_Y, otherwise lcd_bitmap_part stride won't be correct */
196#define SPOTS_X 4
197#define SPOTS_Y 4
Marianne Arnoldcdc933f2008-01-31 18:08:22 +0000198#define SPOTS_WIDTH (IMAGE_WIDTH / SPOTS_X)
199#define SPOTS_HEIGHT (IMAGE_HEIGHT / SPOTS_Y)
200#define NUM_SPOTS (SPOTS_X*SPOTS_Y)
201#define HOLE_ID (NUM_SPOTS)
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000202#define INITIAL_HOLE (HOLE_ID-1)
203
204enum picmodes
205{
206 PICMODE_NUMERALS = 0,
207 PICMODE_INITIAL_PICTURE,
208 PICMODE_DEFAULT_PICTURE,
209#ifdef HAVE_ALBUMART
210 PICMODE_ALBUM_ART,
211#endif
212// PICMODE_RANDOM,
213 PICMODE_LAST_XXX /* placeholder */
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000214};
215
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000216static const char* const picmode_descriptions[] = {
217 "Numerals",
218 "Viewer Picture",
219 "Default Picture",
220#ifdef HAVE_ALBUMART
221 "Album Art",
222#endif
223 "Shouldn't Get Here",
224};
225
226static int spots[NUM_SPOTS];
227static int hole = INITIAL_HOLE, moves;
Jens Arnold6f65afd2008-02-03 14:34:37 +0000228static unsigned char s[32];
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000229static enum picmodes picmode = PICMODE_INITIAL_PICTURE;
Jens Arnold6f65afd2008-02-03 14:34:37 +0000230static int num_font = FONT_UI;
231static int moves_font = FONT_UI;
232static int moves_y = 0;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000233
234static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
235__attribute__ ((aligned(16)));
236#if LCD_DEPTH>1
237static unsigned char temp_img_buf[LCD_WIDTH*LCD_HEIGHT*sizeof(fb_data)]
238__attribute__ ((aligned(16)));
239#endif
240#ifdef HAVE_ALBUMART
241static char albumart_path[MAX_PATH+1];
242#endif
243static char img_buf_path[MAX_PATH+1];
244
245static const fb_data * puzzle_bmp_ptr;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000246/* initial_bmp_path points to selected bitmap if this game is launched
247 as a viewer for a .bmp file, or NULL if game is launched regular way */
248static const char * initial_bmp_path=NULL;
249
250#ifdef HAVE_ALBUMART
251const char * get_albumart_bmp_path(void)
252{
253 struct mp3entry* track = rb->audio_current_track();
254
255 if (!track || !track->path || track->path[0] == '\0')
256 return NULL;
257
258 if (!rb->search_albumart_files(track, "", albumart_path, MAX_PATH ) )
259 return NULL;
260
261 albumart_path[ MAX_PATH ] = '\0';
262 return albumart_path;
263}
264#endif
265
266const char * get_random_bmp_path(void)
267{
268 return(initial_bmp_path);
269}
270
271static bool load_resize_bitmap(void)
272{
273 int rc;
274 const char * filename = NULL;
275
276 /* initially assume using the built-in default */
277 puzzle_bmp_ptr = sliding_puzzle;
278
279 switch( picmode ){
280 /* some modes don't even need to touch disk and trivially succeed */
281 case PICMODE_NUMERALS:
282 case PICMODE_DEFAULT_PICTURE:
283 default:
284 return(true);
285
286#ifdef HAVE_ALBUMART
287 case PICMODE_ALBUM_ART:
288 filename = get_albumart_bmp_path();
289 break;
290#endif
291/*
292 case PICMODE_RANDOM:
293 if(NULL == (filename=get_random_bmp_path()) )
294 filename = initial_bmp_path;
295 break;
296*/
297 case PICMODE_INITIAL_PICTURE:
298 filename = initial_bmp_path;
299 break;
300 };
301
302 if( filename != NULL )
303 {
304 /* if we already loaded image before, don't touch disk */
305 if( 0 == rb->strcmp( filename, img_buf_path ) )
306 {
307 puzzle_bmp_ptr = (const fb_data *)img_buf;
308 return true;
309 }
310
311 struct bitmap main_bitmap;
312 rb->memset(&main_bitmap,0,sizeof(struct bitmap));
313 main_bitmap.data = img_buf;
314
315#if LCD_DEPTH>1
316 struct bitmap temp_bitmap;
317 rb->memset(&temp_bitmap,0,sizeof(struct bitmap));
318 temp_bitmap.data = temp_img_buf;
319
320 main_bitmap.width = IMAGE_WIDTH;
321 main_bitmap.height = IMAGE_HEIGHT;
322
323 rc = rb->read_bmp_file( filename, &temp_bitmap, sizeof(temp_img_buf),
324 FORMAT_NATIVE );
325 if( rc > 0 )
326 {
Nicolas Pennequinfdb10282008-04-06 23:04:00 +0000327#ifdef HAVE_LCD_COLOR
Nicolas Pennequin6aa36c62008-04-06 22:30:50 +0000328 smooth_resize_bitmap( &temp_bitmap, &main_bitmap );
Nicolas Pennequinfdb10282008-04-06 23:04:00 +0000329#else
330 simple_resize_bitmap( &temp_bitmap, &main_bitmap );
331#endif
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000332 puzzle_bmp_ptr = (const fb_data *)img_buf;
333 rb->strcpy( img_buf_path, filename );
334 return true;
335 }
336#else
337 rc = rb->read_bmp_file( filename, &main_bitmap, sizeof(img_buf),
338 FORMAT_NATIVE );
339 if( rc > 0 )
340 {
341 puzzle_bmp_ptr = (const fb_data *)img_buf;
342 rb->strcpy( img_buf_path, filename );
343 return true;
344 }
345#endif
346 }
347
348 /* something must have failed. get_albumart_bmp_path could return
349 NULL if albumart doesn't exist or couldn't be loaded, or
350 read_bmp_file could have failed. return false and caller should
351 try the next mode (PICMODE_DEFAULT_PICTURE and PICMODE_NUMERALS will
352 always succeed) */
353 return false;
354}
355
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000356/* draws a spot at the coordinates (x,y), range of p is 1-20 */
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000357static void draw_spot(int p, int x, int y)
358{
Jens Arnold6f65afd2008-02-03 14:34:37 +0000359 int w, h;
360
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000361 if (p == HOLE_ID)
362 {
363#if LCD_DEPTH==1
364 /* the bottom-right cell of the default sliding_puzzle image is
365 an appropriate hole graphic */
366 rb->lcd_bitmap_part(sliding_puzzle, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
367 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
368 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
369#else
370 /* just draw a black rectangle */
Jens Arnold6f65afd2008-02-03 14:34:37 +0000371 int old_fg = rb->lcd_get_foreground();
372 rb->lcd_set_foreground(LCD_BLACK);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000373 rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT);
Jens Arnold6f65afd2008-02-03 14:34:37 +0000374 rb->lcd_set_foreground(old_fg);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000375#endif
376 }
377 else if (picmode != PICMODE_NUMERALS)
378 {
379 rb->lcd_bitmap_part( puzzle_bmp_ptr, ((p-1)%SPOTS_X)*SPOTS_WIDTH,
380 ((p-1)/SPOTS_X)*SPOTS_HEIGHT,
381 IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
382 } else {
383 rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT);
384 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
385 rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2);
Jens Arnold04daef12005-06-24 22:33:21 +0000386 rb->lcd_set_drawmode(DRMODE_SOLID);
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000387 rb->snprintf(s, sizeof(s), "%d", p);
Jens Arnold6f65afd2008-02-03 14:34:37 +0000388 rb->lcd_setfont(num_font);
389 rb->lcd_getstringsize(s, &w, &h);
390 rb->lcd_putsxy(x + (SPOTS_WIDTH/2) - w / 2,
391 y + (SPOTS_HEIGHT/2) - h / 2, s);
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000392 }
393}
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000394
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000395/* check if the puzzle is solved */
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000396static bool puzzle_finished(void)
397{
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000398 int i;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000399 for (i=0; i<NUM_SPOTS; i++)
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000400 if (spots[i] != (i+1))
401 return false;
402 return true;
403}
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000404
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000405/* move a piece in any direction */
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000406static void move_spot(int x, int y)
407{
Jens Arnold6f65afd2008-02-03 14:34:37 +0000408 int i, w;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000409 spots[hole] = spots[hole-x-SPOTS_X*y];
410 hole -= (x+SPOTS_X*y);
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000411 moves++;
Jens Arnold6f65afd2008-02-03 14:34:37 +0000412 rb->lcd_setfont(moves_font);
413#if LCD_WIDTH > LCD_HEIGHT
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000414 rb->snprintf(s, sizeof(s), "%d", moves);
Jens Arnold6f65afd2008-02-03 14:34:37 +0000415 w = rb->lcd_getstringsize(s, NULL, NULL);
416 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
417 moves_y, s);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000418#else
Jens Arnold6f65afd2008-02-03 14:34:37 +0000419 (void)w;
420 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
421 rb->lcd_putsxy(3, moves_y, s);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000422#endif
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000423 for(i=1;i<=4;i++)
424 {
425 draw_spot(HOLE_ID,
426 (hole%SPOTS_X)*SPOTS_WIDTH,
427 (hole/SPOTS_X)*SPOTS_HEIGHT);
428 draw_spot(spots[hole],
429 (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5,
430 (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5);
431 rb->lcd_update();
432 rb->sleep(HZ/50);
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000433 }
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000434 draw_spot(HOLE_ID,
435 (hole%SPOTS_X)*SPOTS_WIDTH,
436 (hole/SPOTS_X)*SPOTS_HEIGHT);
437 draw_spot(spots[hole],
438 ((hole%SPOTS_X)+x)*SPOTS_WIDTH,
439 ((hole/SPOTS_X)+y)*SPOTS_HEIGHT);
440 rb->lcd_update();
441
442 spots[hole] = HOLE_ID;
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000443}
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000444
Jens Arnold6f65afd2008-02-03 14:34:37 +0000445static void draw_playfield(void)
446{
447 int i, w;
448
449 rb->lcd_clear_display();
450 rb->lcd_setfont(moves_font);
451#if LCD_WIDTH > LCD_HEIGHT
452 rb->lcd_vline(IMAGE_WIDTH, 0, LCD_HEIGHT-1);
453 w = rb->lcd_getstringsize("Moves", NULL, NULL);
454 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
455 10, "Moves");
456 rb->snprintf(s, sizeof(s), "%d", moves);
457 w = rb->lcd_getstringsize(s, NULL, NULL);
458 rb->lcd_putsxy((IMAGE_WIDTH+1+(LCD_WIDTH-IMAGE_WIDTH-1)/2) - w / 2,
459 moves_y, s);
460#else
461 (void)w;
462 rb->lcd_hline(0, LCD_WIDTH-1, IMAGE_HEIGHT);
463 rb->snprintf(s, sizeof(s), "Moves: %d", moves);
464 rb->lcd_putsxy(3, moves_y, s);
465#endif
466
467 /* draw spots to the lcd */
468 for (i=0; i<NUM_SPOTS; i++)
469 draw_spot(spots[i], (i%SPOTS_X)*SPOTS_WIDTH, (i/SPOTS_X)*SPOTS_HEIGHT);
470
471 rb->lcd_update();
472}
473
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000474/* initializes the puzzle */
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000475static void puzzle_init(void)
476{
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000477 int i, r, temp, tsp[NUM_SPOTS];
478
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000479 moves = 0;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000480
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000481 /* shuffle spots */
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000482 for (i=NUM_SPOTS-1; i>=0; i--) {
Linus Nielsen Feltzing7c0cdf12004-07-12 10:46:00 +0000483 r = (rb->rand() % (i+1));
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000484
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000485 temp = spots[r];
486 spots[r] = spots[i];
487 spots[i] = temp;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000488
489 if (spots[i]==HOLE_ID)
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000490 hole = i;
491 }
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000492
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000493 /* test if the puzzle is solvable */
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000494 for (i=0; i<NUM_SPOTS; i++)
Linus Nielsen Feltzing7c0cdf12004-07-12 10:46:00 +0000495 tsp[i] = spots[i];
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000496 r=0;
Linus Nielsen Feltzing7c0cdf12004-07-12 10:46:00 +0000497
498 /* First, check if the problem has even or odd parity,
499 depending on where the empty square is */
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000500 if ((((SPOTS_X-1)-hole%SPOTS_X) + ((SPOTS_Y-1)-hole/SPOTS_X))%2 == 1)
Linus Nielsen Feltzing7c0cdf12004-07-12 10:46:00 +0000501 ++r;
502
503 /* Now check how many swaps we need to solve it */
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000504 for (i=0; i<NUM_SPOTS-1; i++) {
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000505 while (tsp[i] != (i+1)) {
506 temp = tsp[i];
507 tsp[i] = tsp[temp-1];
508 tsp[temp-1] = temp;
509 ++r;
510 }
511 }
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000512
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000513 /* if the random puzzle isn't solvable just change two spots */
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000514 if (r%2 == 1) {
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000515 if (spots[0]!=HOLE_ID && spots[1]!=HOLE_ID) {
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000516 temp = spots[0];
517 spots[0] = spots[1];
518 spots[1] = temp;
519 } else {
520 temp = spots[2];
521 spots[2] = spots[3];
522 spots[3] = temp;
523 }
524 }
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000525
Jens Arnold6f65afd2008-02-03 14:34:37 +0000526 draw_playfield();
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000527}
528
529/* the main game loop */
Daniel Stenberge1d5ebd2003-07-21 11:03:14 +0000530static int puzzle_loop(void)
531{
Jens Arnolde35a6582004-10-18 21:45:00 +0000532 int button;
533 int lastbutton = BUTTON_NONE;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000534 bool load_success;
535
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000536 puzzle_init();
537 while(true) {
Jens Arnolde35a6582004-10-18 21:45:00 +0000538 button = rb->button_get(true);
539 switch (button) {
Kevin Ferrare0e027bd2006-06-30 16:43:47 +0000540#ifdef PUZZLE_RC_QUIT
541 case PUZZLE_RC_QUIT:
542#endif
Jens Arnolde35a6582004-10-18 21:45:00 +0000543 case PUZZLE_QUIT:
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000544 /* get out of here */
545 return PLUGIN_OK;
546
Jens Arnolde35a6582004-10-18 21:45:00 +0000547 case PUZZLE_SHUFFLE:
548#ifdef PUZZLE_SHUFFLE_PICTURE_PRE
549 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
550 break;
551#endif
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000552 /* mix up the pieces */
553 puzzle_init();
554 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000555
Jens Arnolde35a6582004-10-18 21:45:00 +0000556 case PUZZLE_PICTURE:
557#ifdef PUZZLE_SHUFFLE_PICTURE_PRE
558 if (lastbutton != PUZZLE_SHUFFLE_PICTURE_PRE)
559 break;
560#endif
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000561 /* change picture */
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000562 picmode = (picmode+1)%PICMODE_LAST_XXX;
563
564 /* if load_resize_bitmap fails to load bitmap, try next picmode */
565 do
566 {
567 load_success = load_resize_bitmap();
568 if( !load_success )
569 picmode = (picmode+1)%PICMODE_LAST_XXX;
570 }
571 while( !load_success );
572
573 /* tell the user what mode we picked in the end! */
574 rb->splash(HZ,picmode_descriptions[ picmode ] );
Jens Arnold6f65afd2008-02-03 14:34:37 +0000575 draw_playfield();
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000576 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000577
Jens Arnold29361ab2008-03-22 10:24:28 +0000578 case PUZZLE_LEFT:
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000579 if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished())
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000580 move_spot(-1, 0);
581 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000582
Jens Arnold29361ab2008-03-22 10:24:28 +0000583 case PUZZLE_RIGHT:
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000584 if ((hole%SPOTS_X)>0 && !puzzle_finished())
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000585 move_spot(1, 0);
586 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000587
Dave Chapman54d44c82005-12-14 01:31:37 +0000588 case PUZZLE_UP:
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000589 if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished())
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000590 move_spot(0, -1);
591 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000592
Dave Chapman54d44c82005-12-14 01:31:37 +0000593 case PUZZLE_DOWN:
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000594 if ((hole/SPOTS_X)>0 && !puzzle_finished())
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000595 move_spot(0, 1);
596 break;
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000597
Jens Arnolde35a6582004-10-18 21:45:00 +0000598 default:
599 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
600 return PLUGIN_USB_CONNECTED;
601 break;
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000602 }
Jens Arnolde35a6582004-10-18 21:45:00 +0000603 if (button != BUTTON_NONE)
604 lastbutton = button;
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000605 }
606}
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000607
Steve Bavin65265772008-05-13 09:57:56 +0000608enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000609{
610 int i, w, h;
611
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000612 rb = api;
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000613
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000614 initial_bmp_path=(const char *)parameter;
615 picmode = PICMODE_INITIAL_PICTURE;
616 img_buf_path[0] = '\0';
617
618 /* If launched as a viewer, just go straight to the game without
619 bothering with the splash or instructions page */
620 if(parameter==NULL)
621 {
622 /* if not launched as a viewer, use default puzzle, and show help */
623 picmode = PICMODE_DEFAULT_PICTURE;
624
625 /* print title */
626 rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h);
627 w = (w+1)/2;
628 h = (h+1)/2;
629 rb->lcd_clear_display();
630 rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h,
631 (unsigned char *)"Sliding Puzzle");
632 rb->lcd_update();
633 rb->sleep(HZ);
634
635 /* print instructions */
636 rb->lcd_clear_display();
637 rb->lcd_setfont(FONT_SYSFIXED);
638#if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD
639 rb->lcd_putsxy(3, 18, "[OFF] to stop");
640 rb->lcd_putsxy(3, 28, "[F1] shuffle");
641 rb->lcd_putsxy(3, 38, "[F2] change pic");
Jens Arnolde35a6582004-10-18 21:45:00 +0000642#elif CONFIG_KEYPAD == ONDIO_PAD
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000643 rb->lcd_putsxy(0, 18, "[OFF] to stop");
644 rb->lcd_putsxy(0, 28, "[MODE..] shuffle");
645 rb->lcd_putsxy(0, 38, "[MODE] change pic");
Björn Stenberg69795ab2006-03-18 20:17:25 +0000646#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
Jens Arnoldb7013222007-07-27 09:57:27 +0000647 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
648 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000649 rb->lcd_putsxy(0, 18, "[S-MENU] to stop");
650 rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle");
651 rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic");
652#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
653 (CONFIG_KEYPAD == IRIVER_H300_PAD)
654 rb->lcd_putsxy(0, 18, "[STOP] to stop");
655 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
656 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
657#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
658 rb->lcd_putsxy(0, 18, "[OFF] to stop");
659 rb->lcd_putsxy(0, 28, "[REC] shuffle");
660 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
661#elif CONFIG_KEYPAD == GIGABEAT_PAD
662 rb->lcd_putsxy(0, 18, "[OFF] to stop");
663 rb->lcd_putsxy(0, 28, "[SELECT] shuffle");
664 rb->lcd_putsxy(0, 38, "[A] change pic");
665#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
Nicolas Pennequin988d4e82008-01-26 00:37:24 +0000666 (CONFIG_KEYPAD == SANSA_C200_PAD)
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000667 rb->lcd_putsxy(0, 18, "[OFF] to stop");
668 rb->lcd_putsxy(0, 28, "[REC] shuffle");
669 rb->lcd_putsxy(0, 38, "[SELECT] change pic");
670#elif CONFIG_KEYPAD == IRIVER_H10_PAD
671 rb->lcd_putsxy(0, 18, "[OFF] to stop");
672 rb->lcd_putsxy(0, 28, "[REW] shuffle");
673 rb->lcd_putsxy(0, 38, "[PLAY] change pic");
Jens Arnold408613c2008-03-23 09:21:49 +0000674#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
675 rb->lcd_putsxy(0, 18, "[REC] to stop");
676 rb->lcd_putsxy(0, 28, "[MODE] shuffle");
677 rb->lcd_putsxy(0, 38, "[MENU] change pic");
Jens Arnolde35a6582004-10-18 21:45:00 +0000678#endif
Rob Purchase297e0502008-04-27 15:30:19 +0000679#ifdef HAVE_TOUCHPAD
680 rb->lcd_putsxy(0, 18, PUZZLE_QUIT_TEXT " to stop");
681 rb->lcd_putsxy(0, 28, PUZZLE_SHUFFLE_TEXT " shuffle");
682 rb->lcd_putsxy(0, 38, PUZZLE_PICTURE_TEXT " change pic");
683#endif
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000684#ifdef HAVE_ALBUMART
685 rb->lcd_putsxy(0,48," pic->albumart->num");
686#else
687 rb->lcd_putsxy(0,48," pic<->num");
688#endif
689 rb->lcd_update();
690 rb->button_get_w_tmo(HZ*2);
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000691 }
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000692
693 hole = INITIAL_HOLE;
694
695 if( !load_resize_bitmap() )
696 {
697 rb->lcd_clear_display();
698 rb->splash(HZ*2,"Failed to load bitmap!");
699 return PLUGIN_OK;
700 }
701
Jens Arnold6f65afd2008-02-03 14:34:37 +0000702 /* Calculate possible font sizes and text positions */
703 rb->lcd_setfont(FONT_UI);
704 rb->lcd_getstringsize("15", &w, &h);
705 if ((w > (SPOTS_WIDTH-2)) || (h > (SPOTS_HEIGHT-2)))
706 num_font = FONT_SYSFIXED;
707
708#if LCD_WIDTH > LCD_HEIGHT
709 rb->lcd_getstringsize("Moves", &w, &h);
710 if (w > (LCD_WIDTH-IMAGE_WIDTH-1))
711 moves_font = FONT_SYSFIXED;
712 rb->lcd_setfont(moves_font);
713 rb->lcd_getstringsize("Moves", &w, &h);
714 moves_y = 10 + h;
715#else
716 rb->lcd_getstringsize("Moves: 999", &w, &h);
717 if ((w > LCD_WIDTH) || (h > (LCD_HEIGHT-IMAGE_HEIGHT-1)))
718 moves_font = FONT_SYSFIXED;
719 rb->lcd_setfont(moves_font);
720 rb->lcd_getstringsize("Moves: 999", &w, &h);
721 moves_y = (IMAGE_HEIGHT+1+(LCD_HEIGHT-IMAGE_HEIGHT-1)/2) - h / 2;
722#endif
723 for (i=0; i<NUM_SPOTS; i++)
724 spots[i]=(i+1);
725
726#ifdef HAVE_LCD_COLOR
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000727 rb->lcd_set_background(LCD_BLACK);
728 rb->lcd_set_foreground(LCD_WHITE);
729 rb->lcd_set_backdrop(NULL);
Jens Arnold6f65afd2008-02-03 14:34:37 +0000730#elif LCD_DEPTH > 1
731 rb->lcd_set_background(LCD_WHITE);
732 rb->lcd_set_foreground(LCD_BLACK);
733 rb->lcd_set_backdrop(NULL);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000734#endif
735
Jens Arnold6f65afd2008-02-03 14:34:37 +0000736 draw_playfield();
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000737 rb->sleep(HZ*2);
Nicolas Pennequin02f18392008-01-26 00:16:06 +0000738
Björn Stenberg8bebc8b2003-06-29 19:48:24 +0000739 return puzzle_loop();
740}
741
742#endif