Packard Bell Vibe 500: More plugin keymaps (second portion).
[kugel-rb.git] / apps / plugins / clix.c
blob34c62e954f095ab164342d429980400cc01964f2
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 == PHILIPS_SA9200_PAD)
142 #define CLIX_BUTTON_QUIT BUTTON_POWER
143 #define CLIX_BUTTON_LEFT BUTTON_PREV
144 #define CLIX_BUTTON_RIGHT BUTTON_NEXT
145 #define CLIX_BUTTON_CLICK BUTTON_PLAY
146 #define CLIX_BUTTON_UP BUTTON_UP
147 #define CLIX_BUTTON_DOWN BUTTON_DOWN
149 #elif CONFIG_KEYPAD == COWON_D2_PAD
150 #define CLIX_BUTTON_QUIT BUTTON_POWER
152 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
153 #define CLIX_BUTTON_QUIT BUTTON_POWER
154 #define CLIX_BUTTON_CLICK BUTTON_MENU
155 #elif (CONFIG_KEYPAD == ONDAVX777_PAD)
156 #define CLIX_BUTTON_QUIT BUTTON_POWER
158 #elif (CONFIG_KEYPAD == MROBE500_PAD)
159 #define CLIX_BUTTON_QUIT BUTTON_POWER
161 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
162 #define CLIX_BUTTON_QUIT BUTTON_REC
163 #define CLIX_BUTTON_LEFT BUTTON_LEFT
164 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
165 #define CLIX_BUTTON_CLICK BUTTON_PLAY
166 #define CLIX_BUTTON_UP BUTTON_UP
167 #define CLIX_BUTTON_DOWN BUTTON_DOWN
169 #elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
170 #define CLIX_BUTTON_QUIT BUTTON_REC
171 #define CLIX_BUTTON_UP BUTTON_UP
172 #define CLIX_BUTTON_DOWN BUTTON_DOWN
173 #define CLIX_BUTTON_SCROLL_FWD BUTTON_PLAY
174 #define CLIX_BUTTON_SCROLL_BACK BUTTON_MENU
175 #define CLIX_BUTTON_LEFT BUTTON_PREV
176 #define CLIX_BUTTON_RIGHT BUTTON_NEXT
177 #define CLIX_BUTTON_CLICK BUTTON_OK
179 #else
180 #error "no keymap"
181 #endif
183 #ifndef CLIX_BUTTON_CLICK
184 #define CLIX_BUTTON_CLICK BUTTON_CENTER
185 #endif
187 #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
188 #define NUM_SCORES 5
189 struct highscore highest[NUM_SCORES];
191 #define NUM_LEVELS 9
192 #define BLINK_TICKCOUNT 25
193 #define MARGIN 5
195 #if (LCD_WIDTH >= LCD_HEIGHT)
196 #define BOARD_WIDTH 18
197 #define BOARD_HEIGHT 12
198 #else
199 #define BOARD_WIDTH 12
200 #define BOARD_HEIGHT 18
201 #endif
203 #if (LCD_WIDTH>=480)
204 #if (LCD_WIDTH/BOARD_WIDTH) > (LCD_HEIGHT/BOARD_HEIGHT)
205 #define CELL_SIZE (LCD_HEIGHT/BOARD_HEIGHT)
206 #else
207 #define CELL_SIZE (LCD_WIDTH/BOARD_WIDTH)
208 #endif
210 #elif (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
211 #define CELL_SIZE 16
213 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
214 #define CELL_SIZE 14
216 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
217 #define CELL_SIZE 12
219 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
220 #define CELL_SIZE 10
222 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
223 #define CELL_SIZE 8
225 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
226 #define CELL_SIZE 6
228 #elif (LCD_WIDTH >= 60)
229 #define CELL_SIZE 4
230 #endif
232 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
233 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
234 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
237 struct clix_game_state_t {
238 int level; /* current level */
239 int score; /* current game score */
240 int x,y; /* current positions of the cursor */
241 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
242 /* state of selected fields,maybe we can store this in the play board too */
243 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
244 int selected_count;
245 int status;
246 bool blink; /* true if selected CELLS are currently white */
249 /* game state enum */
250 enum {
251 CLIX_GAMEOVER = -1,
252 CLIX_CONTINUE,
253 CLIX_CLEARED
256 /* cell color enum */
257 enum {
258 CC_BLACK = -1,
259 CC_BLUE,
260 CC_GREEN,
261 CC_RED,
262 CC_YELLOW,
263 CC_ORANGE,
264 CC_CYAN,
265 CC_BROWN,
266 CC_PINK,
267 CC_DARK_BLUE,
268 CC_DARK_GREEN
271 /* recursive function to check if a neighbour cell is of the same color
272 if so call the function with the neighbours position
274 static void clix_set_selected(struct clix_game_state_t* state,
275 const int x, const int y)
277 state->selected_count++;
278 state->board_selected[ XYPOS( x, y)] = true;
279 int current_color = state->board[ XYPOS( x, y)];
281 if( (x - 1) >= 0 &&
282 state->board[ XYPOS( x - 1, y)] == current_color &&
283 state->board_selected[ XYPOS(x - 1, y)] == false)
284 clix_set_selected( state, x - 1, y);
286 if( (y + 1) < BOARD_HEIGHT &&
287 state->board[ XYPOS( x, y + 1)] == current_color &&
288 state->board_selected[ XYPOS(x, y + 1)] == false)
289 clix_set_selected( state, x, y + 1);
291 if( (x + 1) < BOARD_WIDTH &&
292 state->board[ XYPOS( x + 1, y)] == current_color &&
293 state->board_selected[ XYPOS(x + 1, y)] == false)
294 clix_set_selected( state, x + 1, y);
296 if( (y - 1) >= 0 &&
297 state->board[ XYPOS( x, y - 1)] == current_color &&
298 state->board_selected[ XYPOS(x, y - 1)] == false)
299 clix_set_selected( state, x, y - 1);
302 /* updates "blinking" cells by finding out which one is a valid neighbours */
303 static void clix_update_selected(struct clix_game_state_t* state)
305 int i;
307 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
309 state->board_selected[i] = false;
311 state->selected_count = 0;
313 /* recursion starts here */
314 clix_set_selected( state, state->x, state->y);
317 /* inits the board with new random colors according to the level */
318 static void clix_init_new_level(struct clix_game_state_t* state)
320 int i;
321 int r;
323 state->y = BOARD_HEIGHT / 2;
324 state->x = BOARD_WIDTH / 2;
326 rb->srand( *rb->current_tick);
327 /* create a random colored board, according to the current level */
328 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
330 r = rb->rand() % (state->level + 1);
331 state->board[i] = r;
335 /* this inits the game state structure */
336 static void clix_init(struct clix_game_state_t* state)
338 state->level = 1;
339 state->score = 0;
340 state->blink = false;
341 state->status = CLIX_CONTINUE;
343 clix_init_new_level(state);
345 clix_update_selected(state);
348 /* Function for drawing a cell */
349 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
351 int realx = XOFS;
352 int realy = YOFS;
354 realx += x * (CELL_SIZE + 1);
355 realy += y * (CELL_SIZE + 1);
357 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
358 rb->lcd_set_foreground(LCD_WHITE);
359 } else {
360 switch (state->board[ XYPOS( x, y)])
362 case CC_BLUE:
363 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
364 break;
365 case CC_GREEN:
366 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
367 break;
368 case CC_RED:
369 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
370 break;
371 case CC_YELLOW:
372 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
373 break;
374 case CC_ORANGE:
375 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
376 break;
377 case CC_CYAN:
378 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
379 break;
380 case CC_BROWN:
381 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
382 break;
383 case CC_PINK:
384 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
385 break;
386 case CC_DARK_GREEN:
387 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
388 break;
389 case CC_DARK_BLUE:
390 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
391 break;
392 default:
393 rb->lcd_set_foreground( LCD_BLACK);
394 break;
398 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
400 /* draw cursor */
401 if ( x == state->x && y == state->y) {
402 rb->lcd_set_foreground( LCD_WHITE);
403 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
407 /* main function of drawing the whole board and score... */
408 static void clix_draw(struct clix_game_state_t* state)
410 int i,j;
411 char str[30];
413 /* Clear screen */
414 rb->lcd_clear_display();
415 rb->lcd_set_foreground( LCD_WHITE);
417 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
418 rb->snprintf( str, sizeof(str), "%d", state->score);
419 rb->lcd_putsxy( 43, MARGIN, str);
420 #if LCD_WIDTH <= 100
421 rb->lcd_putsxy( 75, MARGIN, "L:");
422 rb->snprintf( str, sizeof(str), "%d", state->level);
423 rb->lcd_putsxy( 90, MARGIN, str);
424 #else
425 rb->lcd_putsxy( 75, MARGIN, "Level:");
426 rb->snprintf( str, sizeof(str), "%d", state->level);
427 rb->lcd_putsxy( 113, MARGIN, str);
428 #endif
429 for( i = 0; i < BOARD_WIDTH; ++i)
431 for( j = 0; j < BOARD_HEIGHT; ++j)
433 clix_draw_cell( state, i, j);
437 rb->lcd_update();
440 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
442 int x, y;
444 x = state->x;
447 y = state->y;
448 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
449 if (y < BOARD_HEIGHT) {
450 state->y = y;
451 state->x = x;
453 else
455 if (left) {
456 if( x >= 0)
457 x--;
458 else
459 y = state->y;
461 else
463 if( x < BOARD_WIDTH - 1)
464 x++;
465 else
466 x = 0;
469 } while ( y != state->y);
473 /* returns the color of the given position, if out of bounds return CC_BLACK */
474 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
476 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
477 return state->board[XYPOS( x, y)];
478 else
479 return CC_BLACK;
482 static int clix_clear_selected(struct clix_game_state_t* state)
484 int i, j, x, y;
486 state->status = CLIX_CLEARED;
488 /* clear the selected blocks */
489 for( i = 0; i < BOARD_WIDTH; ++i)
491 for( j = 0; j < BOARD_HEIGHT; ++j)
493 if( state->board_selected[ XYPOS( i, j)] )
495 state->board_selected[ XYPOS( i, j)] = false;
496 state->board[ XYPOS( i, j)] = CC_BLACK;
501 /* count score */
502 state->score += state->selected_count * state->level;
503 state->selected_count = 0;
505 /* let blocks falling down */
506 for( i = BOARD_WIDTH - 1; i >= 0; --i)
508 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
510 y = j;
511 while( (y + 1) < BOARD_HEIGHT &&
512 state->board[ XYPOS( i, y + 1)] == CC_BLACK
514 y++;
516 if (y != j) {
517 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
518 state->board[ XYPOS( i, j)] = CC_BLACK;
523 /* move columns to left side */
524 for( i = 0; i < BOARD_WIDTH; ++i)
526 x = i;
527 while( (x - 1) >= 0 &&
528 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
530 x--;
531 if (x != i)
533 for( j = 0; j < BOARD_HEIGHT; ++j)
535 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
536 state->board[ XYPOS( i, j)] = CC_BLACK;
541 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
542 state->status = CLIX_CONTINUE;
544 if (state->status != CLIX_CLEARED) {
545 /* check if a move is still possible, otherwise the game is over.
546 tart from the left bottom, because there are the last fields
547 at the end of the game.
549 for( i = 0; i < BOARD_WIDTH; ++i)
551 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
553 int color = state->board[ XYPOS( i, j)];
554 if (color != CC_BLACK) {
555 if (color == clix_get_color( state, i - 1, j) ||
556 color == clix_get_color( state, i + 1, j) ||
557 color == clix_get_color( state, i, j - 1) ||
558 color == clix_get_color( state, i, j + 1)
561 /* end the loop, but in a diffrent way than usually*/
562 i = BOARD_WIDTH + 1;
563 j = -2;
568 /* if the loops ended without a possible move, the game is over */
569 if( i == BOARD_WIDTH && j == -1)
570 state->status = CLIX_GAMEOVER;
572 /* set cursor to the right position */
573 if (state->status == CLIX_CONTINUE) {
574 clix_move_cursor( state, true);
575 clix_update_selected( state);
579 return state->status;
582 static bool clix_help(void)
584 #define WORDS (sizeof help_text / sizeof (char*))
585 static char *help_text[] = {
586 "Clix", "", "Aim", "",
587 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
588 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
589 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
590 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
591 "remove", "per", "turn,", "the", "more", "points", "you", "get."
593 static struct style_text formation[]={
594 { 0, TEXT_CENTER|TEXT_UNDERLINE },
595 { 2, C_RED },
596 { -1, 0 }
598 int button;
600 rb->lcd_setfont(FONT_UI);
601 rb->lcd_set_foreground(LCD_WHITE);
602 if (display_text(WORDS, help_text, formation, NULL))
603 return true;
604 do {
605 button = rb->button_get(true);
606 if ( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
607 return true;
608 } while( ( button == BUTTON_NONE )
609 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
610 rb->lcd_setfont(FONT_SYSFIXED);
611 return 0;
614 static bool _ingame;
615 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
617 if(action == ACTION_REQUEST_MENUITEM
618 && !_ingame && ((intptr_t)this_item)==0)
619 return ACTION_EXIT_MENUITEM;
620 return action;
623 static int clix_menu(struct clix_game_state_t* state, bool ingame)
625 rb->button_clear_queue();
626 int choice = 0;
627 bool leave_menu=false;
628 int ret=0;
630 _ingame = ingame;
632 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
633 "Resume Game",
634 "Start New Game",
635 "Help",
636 "High Scores",
637 "Playback Control",
638 "Quit");
640 #ifdef HAVE_TOUCHSCREEN
641 /* Entering Menu, set the touchscreen to the global setting */
642 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
643 #endif
645 while (!leave_menu) {
647 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
648 case 0:
649 leave_menu=true;
650 ret = 0;
651 break;
652 case 1:
653 clix_init(state);
654 leave_menu=true;
655 ret = 0;
656 break;
657 case 2:
658 if (clix_help()) {
659 leave_menu=true;
660 ret = 1;
662 break;
663 case 3:
664 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
665 break;
666 case 4:
667 playback_control(NULL);
668 break;
669 case 5:
670 case MENU_ATTACHED_USB:
671 leave_menu=true;
672 ret = 1;
673 break;
674 default:
675 break;
679 #ifdef HAVE_TOUCHSCREEN
680 /* Leaving the menu, set back to pointer mode */
681 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
682 #endif
684 return ret;
687 static int clix_handle_game(struct clix_game_state_t* state)
689 if (clix_menu(state, 0))
690 return 1;
692 int button;
693 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
694 int position;
696 int time;
697 int start;
698 int end;
699 int oldx, oldy;
701 int lastbutton = BUTTON_NONE;
703 while(true)
705 if (TIME_AFTER(*rb->current_tick, blink_tick)) {
706 state->blink = !state->blink;
707 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
710 time = 6; /* number of ticks this function will loop reading keys */
711 start = *rb->current_tick;
712 end = start + time;
713 while(TIME_BEFORE(*rb->current_tick, end))
715 oldx = state->x;
716 oldy = state->y;
718 button = rb->button_get_w_tmo(end - *rb->current_tick);
719 #ifdef HAVE_TOUCHSCREEN
720 if(button & BUTTON_TOUCHSCREEN)
722 int x = rb->button_get_data() >> 16;
723 int y = rb->button_get_data() & 0xffff;
725 x -= XOFS;
726 y -= YOFS;
727 if(x >= 0 && y >= 0)
729 x /= CELL_SIZE + 1;
730 y /= CELL_SIZE + 1;
732 if(x < BOARD_WIDTH && y < BOARD_HEIGHT
733 && state->board[XYPOS(x, y)] != CC_BLACK)
735 if(state->x == x && state->y == y)
736 button = CLIX_BUTTON_CLICK;
737 else
739 state->x = x;
740 state->y = y;
745 #endif
746 switch( button)
748 #ifndef HAVE_TOUCHSCREEN
749 #ifdef CLIX_BUTTON_SCROLL_BACK
750 case CLIX_BUTTON_SCROLL_BACK:
751 case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT:
752 #endif
753 case CLIX_BUTTON_UP:
754 if( state->y == 0 ||
755 state->board[ XYPOS( state->x, state->y - 1)] ==
756 CC_BLACK
758 state->y = BOARD_HEIGHT - 1;
759 else
760 state->y--;
762 clix_move_cursor(state, true);
763 break;
764 case CLIX_BUTTON_RIGHT:
765 if( state->x == (BOARD_WIDTH - 1))
766 state->x = 0;
767 else
768 state->x++;
770 clix_move_cursor(state, false);
771 break;
772 #ifdef CLIX_BUTTON_SCROLL_FWD
773 case CLIX_BUTTON_SCROLL_FWD:
774 case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT:
775 #endif
776 case CLIX_BUTTON_DOWN:
777 if( state->y == (BOARD_HEIGHT - 1))
778 state->y = 0;
779 else
780 state->y++;
782 clix_move_cursor( state, true);
783 break;
784 case CLIX_BUTTON_LEFT:
785 if( state->x == 0)
786 state->x = BOARD_WIDTH - 1;
787 else
788 state->x--;
790 clix_move_cursor(state, true);
792 break;
793 #endif
794 case CLIX_BUTTON_CLICK:
796 if (state->selected_count > 1) {
797 switch( clix_clear_selected( state))
799 case CLIX_CLEARED:
800 state->score += state->level * 100;
801 clix_draw( state);
802 if (state->level < NUM_LEVELS) {
803 rb->splash(HZ*2, "Great! Next Level!");
804 state->level++;
805 clix_init_new_level( state);
806 clix_update_selected( state);
808 else {
809 rb->splash(HZ*2, "Congratulation!!!");
810 rb->lcd_clear_display();
811 rb->splash(HZ*2, "You have finished the game.");
812 if (clix_menu(state, 0))
813 return 1;
815 break;
816 case CLIX_GAMEOVER:
817 clix_draw( state);
818 rb->splash(HZ*2, "Game Over!");
819 rb->lcd_clear_display();
820 position=highscore_update(state->score,
821 state->level, "",
822 highest,NUM_SCORES);
823 if (position == 0)
824 rb->splash(HZ*2, "New High Score");
825 if (position != -1)
826 highscore_show(position, highest,
827 NUM_SCORES, true);
828 if (clix_menu(state, 0))
829 return 1;
830 break;
831 default:
832 rb->sleep(10); /* prevent repeating clicks */
833 break;
837 break;
838 case CLIX_BUTTON_QUIT:
839 if (clix_menu(state, 1) != 0) {
840 rb->button_clear_queue();
841 return 1;
843 break;
844 default:
846 break;
849 if(button != BUTTON_NONE)
850 lastbutton = button;
852 if( (oldx != state->x || oldy != state->y) &&
853 state->board_selected[ XYPOS( oldx, oldy)] !=
854 state->board_selected[ XYPOS( state->x, state->y)]
857 clix_update_selected(state);
859 clix_draw(state);
860 rb->sleep(time);
865 /* this is the plugin entry point */
866 enum plugin_status plugin_start(const void* parameter)
868 (void)parameter;
870 rb->lcd_set_backdrop(NULL);
871 rb->lcd_set_foreground(LCD_WHITE);
872 rb->lcd_set_background(LCD_BLACK);
873 rb->lcd_setfont(FONT_SYSFIXED);
874 #ifdef HAVE_TOUCHSCREEN
875 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
876 #endif
878 highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES);
880 struct clix_game_state_t state;
881 clix_handle_game( &state);
883 highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES);
885 return PLUGIN_OK;