Rearange menu of mpegplayer. Add new menu with "settings" and "quit", and remove...
[kugel-rb.git] / apps / plugins / clix.c
blob07158c49c195f72d5d8b759b03f878104a141a22
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008-2009 Rene Peinthor
11 * Contribution from Johannes Schwarz (new menu system, use of highscore lib)
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #include "plugin.h"
21 #include "lib/highscore.h"
22 #include "lib/playback_control.h"
23 #include "lib/display_text.h"
25 PLUGIN_HEADER
27 #if (CONFIG_KEYPAD == SANSA_E200_PAD)
28 #define CLIX_BUTTON_QUIT BUTTON_POWER
29 #define CLIX_BUTTON_UP BUTTON_UP
30 #define CLIX_BUTTON_DOWN BUTTON_DOWN
31 #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD
32 #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK
33 #define CLIX_BUTTON_LEFT BUTTON_LEFT
34 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
35 #define CLIX_BUTTON_CLICK BUTTON_SELECT
37 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
38 #define CLIX_BUTTON_QUIT BUTTON_POWER
39 #define CLIX_BUTTON_UP BUTTON_UP
40 #define CLIX_BUTTON_DOWN BUTTON_DOWN
41 #define CLIX_BUTTON_LEFT BUTTON_LEFT
42 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
43 #define CLIX_BUTTON_CLICK BUTTON_SELECT
45 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
46 #define CLIX_BUTTON_QUIT BUTTON_HOME
47 #define CLIX_BUTTON_UP BUTTON_UP
48 #define CLIX_BUTTON_DOWN BUTTON_DOWN
49 #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD
50 #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK
51 #define CLIX_BUTTON_LEFT BUTTON_LEFT
52 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
53 #define CLIX_BUTTON_CLICK BUTTON_SELECT
55 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
56 #define CLIX_BUTTON_QUIT BUTTON_POWER
57 #define CLIX_BUTTON_UP BUTTON_UP
58 #define CLIX_BUTTON_DOWN BUTTON_DOWN
59 #define CLIX_BUTTON_SCROLL_FWD BUTTON_VOL_UP
60 #define CLIX_BUTTON_SCROLL_BACK BUTTON_VOL_DOWN
61 #define CLIX_BUTTON_LEFT BUTTON_LEFT
62 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
63 #define CLIX_BUTTON_CLICK BUTTON_SELECT
65 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
66 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
67 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
68 #define CLIX_BUTTON_QUIT (BUTTON_SELECT | BUTTON_MENU)
69 #define CLIX_BUTTON_UP BUTTON_MENU
70 #define CLIX_BUTTON_DOWN BUTTON_PLAY
71 #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD
72 #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK
73 #define CLIX_BUTTON_CLICK BUTTON_SELECT
74 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
75 #define CLIX_BUTTON_LEFT BUTTON_LEFT
77 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
78 #define CLIX_BUTTON_QUIT BUTTON_POWER
79 #define CLIX_BUTTON_LEFT BUTTON_LEFT
80 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
81 #define CLIX_BUTTON_CLICK BUTTON_SELECT
82 #define CLIX_BUTTON_UP BUTTON_UP
83 #define CLIX_BUTTON_DOWN BUTTON_DOWN
85 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
86 #define CLIX_BUTTON_QUIT BUTTON_BACK
87 #define CLIX_BUTTON_LEFT BUTTON_LEFT
88 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
89 #define CLIX_BUTTON_CLICK BUTTON_SELECT
90 #define CLIX_BUTTON_UP BUTTON_UP
91 #define CLIX_BUTTON_DOWN BUTTON_DOWN
93 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
94 #define CLIX_BUTTON_QUIT BUTTON_POWER
95 #define CLIX_BUTTON_LEFT BUTTON_LEFT
96 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
97 #define CLIX_BUTTON_CLICK BUTTON_PLAY
98 #define CLIX_BUTTON_UP BUTTON_SCROLL_UP
99 #define CLIX_BUTTON_DOWN BUTTON_SCROLL_DOWN
101 #elif CONFIG_KEYPAD == IAUDIO67_PAD
102 #define CLIX_BUTTON_QUIT BUTTON_POWER
103 #define CLIX_BUTTON_LEFT BUTTON_LEFT
104 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
105 #define CLIX_BUTTON_CLICK BUTTON_PLAY
106 #define CLIX_BUTTON_UP BUTTON_STOP
107 #define CLIX_BUTTON_DOWN BUTTON_PLAY
109 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
110 #define CLIX_BUTTON_QUIT BUTTON_POWER
111 #define CLIX_BUTTON_LEFT BUTTON_LEFT
112 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
113 #define CLIX_BUTTON_CLICK BUTTON_SELECT
114 #define CLIX_BUTTON_UP BUTTON_UP
115 #define CLIX_BUTTON_DOWN BUTTON_DOWN
117 #elif (CONFIG_KEYPAD == IRIVER_H300_PAD)
118 #define CLIX_BUTTON_QUIT BUTTON_OFF
119 #define CLIX_BUTTON_LEFT BUTTON_LEFT
120 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
121 #define CLIX_BUTTON_CLICK BUTTON_SELECT
122 #define CLIX_BUTTON_UP BUTTON_UP
123 #define CLIX_BUTTON_DOWN BUTTON_DOWN
125 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
126 #define CLIX_BUTTON_QUIT BUTTON_BACK
127 #define CLIX_BUTTON_LEFT BUTTON_LEFT
128 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
129 #define CLIX_BUTTON_CLICK BUTTON_SELECT
130 #define CLIX_BUTTON_UP BUTTON_UP
131 #define CLIX_BUTTON_DOWN BUTTON_DOWN
133 #elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD)
134 #define CLIX_BUTTON_QUIT BUTTON_POWER
135 #define CLIX_BUTTON_LEFT BUTTON_LEFT
136 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
137 #define CLIX_BUTTON_CLICK BUTTON_SELECT
138 #define CLIX_BUTTON_UP BUTTON_UP
139 #define CLIX_BUTTON_DOWN BUTTON_DOWN
141 #elif CONFIG_KEYPAD == COWOND2_PAD
142 #define CLIX_BUTTON_QUIT BUTTON_POWER
144 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
145 #define CLIX_BUTTON_QUIT BUTTON_POWER
146 #define CLIX_BUTTON_CLICK BUTTON_MENU
148 #elif (CONFIG_KEYPAD == MROBE500_PAD)
149 #define CLIX_BUTTON_QUIT BUTTON_POWER
151 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
152 #define CLIX_BUTTON_QUIT BUTTON_REC
153 #define CLIX_BUTTON_LEFT BUTTON_LEFT
154 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
155 #define CLIX_BUTTON_CLICK BUTTON_PLAY
156 #define CLIX_BUTTON_UP BUTTON_UP
157 #define CLIX_BUTTON_DOWN BUTTON_DOWN
159 #else
160 #error "no keymap"
161 #endif
163 #ifndef CLIX_BUTTON_CLICK
164 #define CLIX_BUTTON_CLICK BUTTON_CENTER
165 #endif
167 #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
168 #define NUM_SCORES 5
169 struct highscore highest[NUM_SCORES];
171 #define NUM_LEVELS 9
172 #define BLINK_TICKCOUNT 25
173 #define MARGIN 5
175 #if (LCD_WIDTH >= LCD_HEIGHT)
176 #define BOARD_WIDTH 18
177 #define BOARD_HEIGHT 12
178 #else
179 #define BOARD_WIDTH 12
180 #define BOARD_HEIGHT 18
181 #endif
183 #if (LCD_WIDTH>=480)
184 #if (LCD_WIDTH/BOARD_WIDTH) > (LCD_HEIGHT/BOARD_HEIGHT)
185 #define CELL_SIZE (LCD_HEIGHT/BOARD_HEIGHT)
186 #else
187 #define CELL_SIZE (LCD_WIDTH/BOARD_WIDTH)
188 #endif
190 #elif (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
191 #define CELL_SIZE 16
193 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
194 #define CELL_SIZE 14
196 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
197 #define CELL_SIZE 12
199 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
200 #define CELL_SIZE 10
202 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
203 #define CELL_SIZE 8
205 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
206 #define CELL_SIZE 6
208 #elif (LCD_WIDTH >= 60)
209 #define CELL_SIZE 4
210 #endif
212 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
213 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
214 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
217 struct clix_game_state_t {
218 int level; /* current level */
219 int score; /* current game score */
220 int x,y; /* current positions of the cursor */
221 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
222 /* state of selected fields,maybe we can store this in the play board too */
223 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
224 int selected_count;
225 int status;
226 bool blink; /* true if selected CELLS are currently white */
229 /* game state enum */
230 enum {
231 CLIX_GAMEOVER = -1,
232 CLIX_CONTINUE,
233 CLIX_CLEARED
236 /* cell color enum */
237 enum {
238 CC_BLACK = -1,
239 CC_BLUE,
240 CC_GREEN,
241 CC_RED,
242 CC_YELLOW,
243 CC_ORANGE,
244 CC_CYAN,
245 CC_BROWN,
246 CC_PINK,
247 CC_DARK_BLUE,
248 CC_DARK_GREEN
251 /* recursive function to check if a neighbour cell is of the same color
252 if so call the function with the neighbours position
254 static void clix_set_selected(struct clix_game_state_t* state,
255 const int x, const int y)
257 state->selected_count++;
258 state->board_selected[ XYPOS( x, y)] = true;
259 int current_color = state->board[ XYPOS( x, y)];
261 if( (x - 1) >= 0 &&
262 state->board[ XYPOS( x - 1, y)] == current_color &&
263 state->board_selected[ XYPOS(x - 1, y)] == false)
264 clix_set_selected( state, x - 1, y);
266 if( (y + 1) < BOARD_HEIGHT &&
267 state->board[ XYPOS( x, y + 1)] == current_color &&
268 state->board_selected[ XYPOS(x, y + 1)] == false)
269 clix_set_selected( state, x, y + 1);
271 if( (x + 1) < BOARD_WIDTH &&
272 state->board[ XYPOS( x + 1, y)] == current_color &&
273 state->board_selected[ XYPOS(x + 1, y)] == false)
274 clix_set_selected( state, x + 1, y);
276 if( (y - 1) >= 0 &&
277 state->board[ XYPOS( x, y - 1)] == current_color &&
278 state->board_selected[ XYPOS(x, y - 1)] == false)
279 clix_set_selected( state, x, y - 1);
282 /* updates "blinking" cells by finding out which one is a valid neighbours */
283 static void clix_update_selected(struct clix_game_state_t* state)
285 int i;
287 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
289 state->board_selected[i] = false;
291 state->selected_count = 0;
293 /* recursion starts here */
294 clix_set_selected( state, state->x, state->y);
297 /* inits the board with new random colors according to the level */
298 static void clix_init_new_level(struct clix_game_state_t* state)
300 int i;
301 int r;
303 state->y = BOARD_HEIGHT / 2;
304 state->x = BOARD_WIDTH / 2;
306 rb->srand( *rb->current_tick);
307 /* create a random colored board, according to the current level */
308 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
310 r = rb->rand() % (state->level + 1);
311 state->board[i] = r;
315 /* this inits the game state structure */
316 static void clix_init(struct clix_game_state_t* state)
318 state->level = 1;
319 state->score = 0;
320 state->blink = false;
321 state->status = CLIX_CONTINUE;
323 clix_init_new_level(state);
325 clix_update_selected(state);
328 /* Function for drawing a cell */
329 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
331 int realx = XOFS;
332 int realy = YOFS;
334 realx += x * (CELL_SIZE + 1);
335 realy += y * (CELL_SIZE + 1);
337 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
338 rb->lcd_set_foreground(LCD_WHITE);
339 } else {
340 switch (state->board[ XYPOS( x, y)])
342 case CC_BLUE:
343 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
344 break;
345 case CC_GREEN:
346 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
347 break;
348 case CC_RED:
349 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
350 break;
351 case CC_YELLOW:
352 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
353 break;
354 case CC_ORANGE:
355 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
356 break;
357 case CC_CYAN:
358 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
359 break;
360 case CC_BROWN:
361 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
362 break;
363 case CC_PINK:
364 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
365 break;
366 case CC_DARK_GREEN:
367 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
368 break;
369 case CC_DARK_BLUE:
370 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
371 break;
372 default:
373 rb->lcd_set_foreground( LCD_BLACK);
374 break;
378 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
380 /* draw cursor */
381 if ( x == state->x && y == state->y) {
382 rb->lcd_set_foreground( LCD_WHITE);
383 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
387 /* main function of drawing the whole board and score... */
388 static void clix_draw(struct clix_game_state_t* state)
390 int i,j;
391 char str[30];
393 /* Clear screen */
394 rb->lcd_clear_display();
395 rb->lcd_set_foreground( LCD_WHITE);
397 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
398 rb->snprintf( str, sizeof(str), "%d", state->score);
399 rb->lcd_putsxy( 43, MARGIN, str);
400 #if LCD_WIDTH <= 100
401 rb->lcd_putsxy( 75, MARGIN, "L:");
402 rb->snprintf( str, sizeof(str), "%d", state->level);
403 rb->lcd_putsxy( 90, MARGIN, str);
404 #else
405 rb->lcd_putsxy( 75, MARGIN, "Level:");
406 rb->snprintf( str, sizeof(str), "%d", state->level);
407 rb->lcd_putsxy( 113, MARGIN, str);
408 #endif
409 for( i = 0; i < BOARD_WIDTH; ++i)
411 for( j = 0; j < BOARD_HEIGHT; ++j)
413 clix_draw_cell( state, i, j);
417 rb->lcd_update();
420 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
422 int x, y;
424 x = state->x;
427 y = state->y;
428 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
429 if (y < BOARD_HEIGHT) {
430 state->y = y;
431 state->x = x;
433 else
435 if (left) {
436 if( x >= 0)
437 x--;
438 else
439 y = state->y;
441 else
443 if( x < BOARD_WIDTH - 1)
444 x++;
445 else
446 x = 0;
449 } while ( y != state->y);
453 /* returns the color of the given position, if out of bounds return CC_BLACK */
454 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
456 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
457 return state->board[XYPOS( x, y)];
458 else
459 return CC_BLACK;
462 static int clix_clear_selected(struct clix_game_state_t* state)
464 int i, j, x, y;
466 state->status = CLIX_CLEARED;
468 /* clear the selected blocks */
469 for( i = 0; i < BOARD_WIDTH; ++i)
471 for( j = 0; j < BOARD_HEIGHT; ++j)
473 if( state->board_selected[ XYPOS( i, j)] )
475 state->board_selected[ XYPOS( i, j)] = false;
476 state->board[ XYPOS( i, j)] = CC_BLACK;
481 /* count score */
482 state->score += state->selected_count * state->level;
483 state->selected_count = 0;
485 /* let blocks falling down */
486 for( i = BOARD_WIDTH - 1; i >= 0; --i)
488 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
490 y = j;
491 while( (y + 1) < BOARD_HEIGHT &&
492 state->board[ XYPOS( i, y + 1)] == CC_BLACK
494 y++;
496 if (y != j) {
497 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
498 state->board[ XYPOS( i, j)] = CC_BLACK;
503 /* move columns to left side */
504 for( i = 0; i < BOARD_WIDTH; ++i)
506 x = i;
507 while( (x - 1) >= 0 &&
508 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
510 x--;
511 if (x != i)
513 for( j = 0; j < BOARD_HEIGHT; ++j)
515 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
516 state->board[ XYPOS( i, j)] = CC_BLACK;
521 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
522 state->status = CLIX_CONTINUE;
524 if (state->status != CLIX_CLEARED) {
525 /* check if a move is still possible, otherwise the game is over.
526 tart from the left bottom, because there are the last fields
527 at the end of the game.
529 for( i = 0; i < BOARD_WIDTH; ++i)
531 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
533 int color = state->board[ XYPOS( i, j)];
534 if (color != CC_BLACK) {
535 if (color == clix_get_color( state, i - 1, j) ||
536 color == clix_get_color( state, i + 1, j) ||
537 color == clix_get_color( state, i, j - 1) ||
538 color == clix_get_color( state, i, j + 1)
541 /* end the loop, but in a diffrent way than usually*/
542 i = BOARD_WIDTH + 1;
543 j = -2;
548 /* if the loops ended without a possible move, the game is over */
549 if( i == BOARD_WIDTH && j == -1)
550 state->status = CLIX_GAMEOVER;
552 /* set cursor to the right position */
553 if (state->status == CLIX_CONTINUE) {
554 clix_move_cursor( state, true);
555 clix_update_selected( state);
559 return state->status;
562 static bool clix_help(void)
564 #define WORDS (sizeof help_text / sizeof (char*))
565 static char *help_text[] = {
566 "Clix", "", "Aim", "",
567 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
568 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
569 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
570 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
571 "remove", "per", "turn,", "the", "more", "points", "you", "get."
573 static struct style_text formation[]={
574 { 0, TEXT_CENTER|TEXT_UNDERLINE },
575 { 2, C_RED },
576 { -1, 0 }
578 int button;
580 rb->lcd_setfont(FONT_UI);
581 rb->lcd_set_foreground(LCD_WHITE);
582 if (display_text(WORDS, help_text, formation, NULL))
583 return true;
584 do {
585 button = rb->button_get(true);
586 if ( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
587 return true;
588 } while( ( button == BUTTON_NONE )
589 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
590 rb->lcd_setfont(FONT_SYSFIXED);
591 return 0;
594 static bool _ingame;
595 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
597 if(action == ACTION_REQUEST_MENUITEM
598 && !_ingame && ((intptr_t)this_item)==0)
599 return ACTION_EXIT_MENUITEM;
600 return action;
603 static int clix_menu(struct clix_game_state_t* state, bool ingame)
605 rb->button_clear_queue();
606 int choice = 0;
607 bool leave_menu=false;
608 int ret=0;
610 _ingame = ingame;
612 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
613 "Resume Game",
614 "Start New Game",
615 "Help",
616 "High Scores",
617 "Playback Control",
618 "Quit");
620 #ifdef HAVE_TOUCHSCREEN
621 /* Entering Menu, set the touchscreen to the global setting */
622 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
623 #endif
625 while (!leave_menu) {
627 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
628 case 0:
629 leave_menu=true;
630 ret = 0;
631 break;
632 case 1:
633 clix_init(state);
634 leave_menu=true;
635 ret = 0;
636 break;
637 case 2:
638 if (clix_help()) {
639 leave_menu=true;
640 ret = 1;
642 break;
643 case 3:
644 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
645 break;
646 case 4:
647 playback_control(NULL);
648 break;
649 case 5:
650 case MENU_ATTACHED_USB:
651 leave_menu=true;
652 ret = 1;
653 break;
654 default:
655 break;
659 #ifdef HAVE_TOUCHSCREEN
660 /* Leaving the menu, set back to pointer mode */
661 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
662 #endif
664 return ret;
667 static int clix_handle_game(struct clix_game_state_t* state)
669 if (clix_menu(state, 0))
670 return 1;
672 int button;
673 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
674 int position;
676 int time;
677 int start;
678 int end;
679 int oldx, oldy;
681 int lastbutton = BUTTON_NONE;
683 while(true)
685 if (blink_tick < *rb->current_tick) {
686 state->blink = state->blink ? false : true;
687 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
690 time = 6; /* number of ticks this function will loop reading keys */
691 start = *rb->current_tick;
692 end = start + time;
693 while(end > *rb->current_tick)
695 oldx = state->x;
696 oldy = state->y;
698 button = rb->button_get_w_tmo(end - *rb->current_tick);
699 #ifdef HAVE_TOUCHSCREEN
700 if(button & BUTTON_TOUCHSCREEN)
702 int x = rb->button_get_data() >> 16;
703 int y = rb->button_get_data() & 0xffff;
705 x -= XOFS;
706 y -= YOFS;
707 if(x >= 0 && y >= 0)
709 x /= CELL_SIZE + 1;
710 y /= CELL_SIZE + 1;
712 if(x < BOARD_WIDTH && y < BOARD_HEIGHT
713 && state->board[XYPOS(x, y)] != CC_BLACK)
715 if(state->x == x && state->y == y)
716 button = CLIX_BUTTON_CLICK;
717 else
719 state->x = x;
720 state->y = y;
725 #endif
726 switch( button)
728 #ifndef HAVE_TOUCHSCREEN
729 #ifdef CLIX_BUTTON_SCROLL_BACK
730 case CLIX_BUTTON_SCROLL_BACK:
731 case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT:
732 #endif
733 case CLIX_BUTTON_UP:
734 if( state->y == 0 ||
735 state->board[ XYPOS( state->x, state->y - 1)] ==
736 CC_BLACK
738 state->y = BOARD_HEIGHT - 1;
739 else
740 state->y--;
742 clix_move_cursor(state, true);
743 break;
744 case CLIX_BUTTON_RIGHT:
745 if( state->x == (BOARD_WIDTH - 1))
746 state->x = 0;
747 else
748 state->x++;
750 clix_move_cursor(state, false);
751 break;
752 #ifdef CLIX_BUTTON_SCROLL_FWD
753 case CLIX_BUTTON_SCROLL_FWD:
754 case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT:
755 #endif
756 case CLIX_BUTTON_DOWN:
757 if( state->y == (BOARD_HEIGHT - 1))
758 state->y = 0;
759 else
760 state->y++;
762 clix_move_cursor( state, true);
763 break;
764 case CLIX_BUTTON_LEFT:
765 if( state->x == 0)
766 state->x = BOARD_WIDTH - 1;
767 else
768 state->x--;
770 clix_move_cursor(state, true);
772 break;
773 #endif
774 case CLIX_BUTTON_CLICK:
776 if (state->selected_count > 1) {
777 switch( clix_clear_selected( state))
779 case CLIX_CLEARED:
780 state->score += state->level * 100;
781 clix_draw( state);
782 if (state->level < NUM_LEVELS) {
783 rb->splash(HZ*2, "Great! Next Level!");
784 state->level++;
785 clix_init_new_level( state);
786 clix_update_selected( state);
788 else {
789 rb->splash(HZ*2, "Congratulation!!!");
790 rb->lcd_clear_display();
791 rb->splash(HZ*2, "You have finished the game.");
792 if (clix_menu(state, 0))
793 return 1;
795 break;
796 case CLIX_GAMEOVER:
797 clix_draw( state);
798 rb->splash(HZ*2, "Game Over!");
799 rb->lcd_clear_display();
800 position=highscore_update(state->score,
801 state->level, "",
802 highest,NUM_SCORES);
803 if (position == 0)
804 rb->splash(HZ*2, "New High Score");
805 if (position != -1)
806 highscore_show(position, highest,
807 NUM_SCORES, true);
808 if (clix_menu(state, 0))
809 return 1;
810 break;
811 default:
812 rb->sleep(10); /* prevent repeating clicks */
813 break;
817 break;
818 case CLIX_BUTTON_QUIT:
819 if (clix_menu(state, 1) != 0) {
820 rb->button_clear_queue();
821 return 1;
823 break;
824 default:
826 break;
829 if(button != BUTTON_NONE)
830 lastbutton = button;
832 if( (oldx != state->x || oldy != state->y) &&
833 state->board_selected[ XYPOS( oldx, oldy)] !=
834 state->board_selected[ XYPOS( state->x, state->y)]
837 clix_update_selected(state);
839 clix_draw(state);
840 rb->sleep(time);
845 /* this is the plugin entry point */
846 enum plugin_status plugin_start(const void* parameter)
848 (void)parameter;
850 rb->lcd_set_backdrop(NULL);
851 rb->lcd_set_foreground(LCD_WHITE);
852 rb->lcd_set_background(LCD_BLACK);
853 rb->lcd_setfont(FONT_SYSFIXED);
854 #ifdef HAVE_TOUCHSCREEN
855 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
856 #endif
858 highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES);
860 struct clix_game_state_t state;
861 clix_handle_game( &state);
863 highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES);
865 return PLUGIN_OK;