Fix red in bootloaders
[maemo-rb.git] / apps / plugins / clix.c
blobe04de3ca72086e1dbfc2b023c30b4a19db17155b
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_MENU
69 #define CLIX_BUTTON_UP BUTTON_SCROLL_BACK
70 #define CLIX_BUTTON_DOWN BUTTON_SCROLL_FWD
71 #define CLIX_BUTTON_CLICK BUTTON_SELECT
72 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
73 #define CLIX_BUTTON_LEFT BUTTON_LEFT
75 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
76 #define CLIX_BUTTON_QUIT BUTTON_POWER
77 #define CLIX_BUTTON_LEFT BUTTON_LEFT
78 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
79 #define CLIX_BUTTON_CLICK BUTTON_SELECT
80 #define CLIX_BUTTON_UP BUTTON_UP
81 #define CLIX_BUTTON_DOWN BUTTON_DOWN
83 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
84 #define CLIX_BUTTON_QUIT BUTTON_BACK
85 #define CLIX_BUTTON_LEFT BUTTON_LEFT
86 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
87 #define CLIX_BUTTON_CLICK BUTTON_SELECT
88 #define CLIX_BUTTON_UP BUTTON_UP
89 #define CLIX_BUTTON_DOWN BUTTON_DOWN
91 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
92 #define CLIX_BUTTON_QUIT BUTTON_POWER
93 #define CLIX_BUTTON_LEFT BUTTON_LEFT
94 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
95 #define CLIX_BUTTON_CLICK BUTTON_PLAY
96 #define CLIX_BUTTON_UP BUTTON_SCROLL_UP
97 #define CLIX_BUTTON_DOWN BUTTON_SCROLL_DOWN
99 #elif CONFIG_KEYPAD == IAUDIO67_PAD
100 #define CLIX_BUTTON_QUIT BUTTON_POWER
101 #define CLIX_BUTTON_LEFT BUTTON_LEFT
102 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
103 #define CLIX_BUTTON_CLICK BUTTON_PLAY
104 #define CLIX_BUTTON_UP BUTTON_STOP
105 #define CLIX_BUTTON_DOWN BUTTON_PLAY
107 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
108 #define CLIX_BUTTON_QUIT BUTTON_POWER
109 #define CLIX_BUTTON_LEFT BUTTON_LEFT
110 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
111 #define CLIX_BUTTON_CLICK BUTTON_SELECT
112 #define CLIX_BUTTON_UP BUTTON_UP
113 #define CLIX_BUTTON_DOWN BUTTON_DOWN
115 #elif (CONFIG_KEYPAD == IRIVER_H300_PAD)
116 #define CLIX_BUTTON_QUIT BUTTON_OFF
117 #define CLIX_BUTTON_LEFT BUTTON_LEFT
118 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
119 #define CLIX_BUTTON_CLICK BUTTON_SELECT
120 #define CLIX_BUTTON_UP BUTTON_UP
121 #define CLIX_BUTTON_DOWN BUTTON_DOWN
123 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
124 #define CLIX_BUTTON_QUIT BUTTON_BACK
125 #define CLIX_BUTTON_LEFT BUTTON_LEFT
126 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
127 #define CLIX_BUTTON_CLICK BUTTON_SELECT
128 #define CLIX_BUTTON_UP BUTTON_UP
129 #define CLIX_BUTTON_DOWN BUTTON_DOWN
131 #elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD)
132 #define CLIX_BUTTON_QUIT BUTTON_POWER
133 #define CLIX_BUTTON_LEFT BUTTON_LEFT
134 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
135 #define CLIX_BUTTON_CLICK BUTTON_SELECT
136 #define CLIX_BUTTON_UP BUTTON_UP
137 #define CLIX_BUTTON_DOWN BUTTON_DOWN
139 #elif CONFIG_KEYPAD == COWOND2_PAD
140 #define CLIX_BUTTON_QUIT BUTTON_POWER
142 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
143 (CONFIG_KEYPAD == MROBE500_PAD)
144 #define CLIX_BUTTON_QUIT BUTTON_POWER
146 #else
147 #error "no keymap"
148 #endif
150 #ifdef HAVE_TOUCHSCREEN
151 #ifndef CLIX_BUTTON_LEFT
152 #define CLIX_BUTTON_LEFT BUTTON_MIDLEFT
153 #endif
154 #ifndef CLIX_BUTTON_RIGHT
155 #define CLIX_BUTTON_RIGHT BUTTON_MIDRIGHT
156 #endif
157 #ifndef CLIX_BUTTON_CLICK
158 #define CLIX_BUTTON_CLICK BUTTON_CENTER
159 #endif
160 #ifndef CLIX_BUTTON_UP
161 #define CLIX_BUTTON_UP BUTTON_TOPMIDDLE
162 #endif
163 #ifndef CLIX_BUTTON_DOWN
164 #define CLIX_BUTTON_DOWN BUTTON_BOTTOMMIDDLE
165 #endif
166 #endif
168 #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
169 #define NUM_SCORES 5
170 struct highscore highest[NUM_SCORES];
172 #define NUM_LEVELS 9
173 #define BLINK_TICKCOUNT 25
174 #define MARGIN 5
176 #if (LCD_WIDTH >= LCD_HEIGHT)
177 #define BOARD_WIDTH 18
178 #define BOARD_HEIGHT 12
179 #else
180 #define BOARD_WIDTH 12
181 #define BOARD_HEIGHT 18
182 #endif
184 #if (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
185 #define CELL_SIZE 16
187 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
188 #define CELL_SIZE 14
190 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
191 #define CELL_SIZE 12
193 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
194 #define CELL_SIZE 10
196 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
197 #define CELL_SIZE 8
199 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
200 #define CELL_SIZE 6
202 #elif (LCD_WIDTH >= 60)
203 #define CELL_SIZE 4
204 #endif
206 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
207 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
208 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
211 struct clix_game_state_t {
212 int level; /* current level */
213 int score; /* current game score */
214 int x,y; /* current positions of the cursor */
215 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
216 /* state of selected fields,maybe we can store this in the play board too */
217 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
218 int selected_count;
219 int status;
220 bool blink; /* true if selected CELLS are currently white */
223 /* game state enum */
224 enum {
225 CLIX_GAMEOVER = -1,
226 CLIX_CONTINUE,
227 CLIX_CLEARED
230 /* cell color enum */
231 enum {
232 CC_BLACK = -1,
233 CC_BLUE,
234 CC_GREEN,
235 CC_RED,
236 CC_YELLOW,
237 CC_ORANGE,
238 CC_CYAN,
239 CC_BROWN,
240 CC_PINK,
241 CC_DARK_BLUE,
242 CC_DARK_GREEN
245 /* display the highscore list and highlight the last one */
246 static void clix_show_highscores(int position)
248 int i, w, h;
249 char str[30];
251 #ifdef HAVE_LCD_COLOR
252 rb->lcd_set_background(LCD_BLACK);
253 rb->lcd_set_foreground(LCD_WHITE);
254 #endif
255 rb->button_clear_queue();
256 rb->lcd_clear_display();
258 rb->lcd_setfont(FONT_UI);
259 rb->lcd_getstringsize("High Scores", &w, &h);
260 /* check wether it fits on screen */
261 if ((4*h + h*(NUM_SCORES-1) + MARGIN) > LCD_HEIGHT) {
262 rb->lcd_setfont(FONT_SYSFIXED);
263 rb->lcd_getstringsize("High Scores", &w, &h);
265 rb->lcd_putsxy(LCD_WIDTH/2-w/2, MARGIN, "High Scores");
266 rb->lcd_putsxy(LCD_WIDTH/4-w/4,2*h, "Score");
267 rb->lcd_putsxy(LCD_WIDTH*3/4-w/4,2*h, "Level");
269 for (i = 0; i<NUM_SCORES; i++)
271 #ifdef HAVE_LCD_COLOR
272 if (i == position) {
273 rb->lcd_set_foreground(LCD_RGBPACK(245,0,0));
275 #endif
276 rb->snprintf (str, sizeof (str), "%d)", i+1);
277 rb->lcd_putsxy (MARGIN,3*h + h*i, str);
278 rb->snprintf (str, sizeof (str), "%d", highest[i].score);
279 rb->lcd_putsxy (LCD_WIDTH/4-w/4,3*h + h*i, str);
280 rb->snprintf (str, sizeof (str), "%d", highest[i].level);
281 rb->lcd_putsxy (LCD_WIDTH*3/4-w/4,3*h + h*i, str);
282 if(i == position) {
283 #ifdef HAVE_LCD_COLOR
284 rb->lcd_set_foreground(LCD_WHITE);
285 #else
286 rb->lcd_hline(MARGIN, LCD_WIDTH-MARGIN, 3*h + h*(i+1));
287 #endif
290 rb->lcd_update();
291 rb->button_get(true);
292 rb->lcd_setfont(FONT_SYSFIXED);
295 /* recursive function to check if a neighbour cell is of the same color
296 if so call the function with the neighbours position
298 static void clix_set_selected(struct clix_game_state_t* state,
299 const int x, const int y)
301 state->selected_count++;
302 state->board_selected[ XYPOS( x, y)] = true;
303 int current_color = state->board[ XYPOS( x, y)];
305 if( (x - 1) >= 0 &&
306 state->board[ XYPOS( x - 1, y)] == current_color &&
307 state->board_selected[ XYPOS(x - 1, y)] == false)
308 clix_set_selected( state, x - 1, y);
310 if( (y + 1) < BOARD_HEIGHT &&
311 state->board[ XYPOS( x, y + 1)] == current_color &&
312 state->board_selected[ XYPOS(x, y + 1)] == false)
313 clix_set_selected( state, x, y + 1);
315 if( (x + 1) < BOARD_WIDTH &&
316 state->board[ XYPOS( x + 1, y)] == current_color &&
317 state->board_selected[ XYPOS(x + 1, y)] == false)
318 clix_set_selected( state, x + 1, y);
320 if( (y - 1) >= 0 &&
321 state->board[ XYPOS( x, y - 1)] == current_color &&
322 state->board_selected[ XYPOS(x, y - 1)] == false)
323 clix_set_selected( state, x, y - 1);
326 /* updates "blinking" cells by finding out which one is a valid neighbours */
327 static void clix_update_selected(struct clix_game_state_t* state)
329 int i;
331 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
333 state->board_selected[i] = false;
335 state->selected_count = 0;
337 /* recursion starts here */
338 clix_set_selected( state, state->x, state->y);
341 /* inits the board with new random colors according to the level */
342 static void clix_init_new_level(struct clix_game_state_t* state)
344 int i;
345 int r;
347 state->y = BOARD_HEIGHT / 2;
348 state->x = BOARD_WIDTH / 2;
350 rb->srand( *rb->current_tick);
351 /* create a random colored board, according to the current level */
352 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
354 r = rb->rand() % (state->level + 1);
355 state->board[i] = r;
359 /* this inits the game state structure */
360 static void clix_init(struct clix_game_state_t* state)
362 state->level = 1;
363 state->score = 0;
364 state->blink = false;
365 state->status = CLIX_CONTINUE;
367 clix_init_new_level(state);
369 clix_update_selected(state);
372 /* Function for drawing a cell */
373 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
375 int realx = XOFS;
376 int realy = YOFS;
378 realx += x * (CELL_SIZE + 1);
379 realy += y * (CELL_SIZE + 1);
381 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
382 rb->lcd_set_foreground(LCD_WHITE);
383 } else {
384 switch (state->board[ XYPOS( x, y)])
386 case CC_BLUE:
387 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
388 break;
389 case CC_GREEN:
390 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
391 break;
392 case CC_RED:
393 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
394 break;
395 case CC_YELLOW:
396 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
397 break;
398 case CC_ORANGE:
399 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
400 break;
401 case CC_CYAN:
402 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
403 break;
404 case CC_BROWN:
405 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
406 break;
407 case CC_PINK:
408 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
409 break;
410 case CC_DARK_GREEN:
411 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
412 break;
413 case CC_DARK_BLUE:
414 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
415 break;
416 default:
417 rb->lcd_set_foreground( LCD_BLACK);
418 break;
422 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
424 /* draw cursor */
425 if ( x == state->x && y == state->y) {
426 rb->lcd_set_foreground( LCD_WHITE);
427 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
431 /* main function of drawing the whole board and score... */
432 static void clix_draw(struct clix_game_state_t* state)
434 int i,j;
435 char str[30];
437 /* Clear screen */
438 rb->lcd_clear_display();
439 rb->lcd_set_foreground( LCD_WHITE);
441 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
442 rb->snprintf( str, sizeof(str), "%d", state->score);
443 rb->lcd_putsxy( 43, MARGIN, str);
444 #if LCD_WIDTH <= 100
445 rb->lcd_putsxy( 75, MARGIN, "L:");
446 rb->snprintf( str, sizeof(str), "%d", state->level);
447 rb->lcd_putsxy( 90, MARGIN, str);
448 #else
449 rb->lcd_putsxy( 75, MARGIN, "Level:");
450 rb->snprintf( str, sizeof(str), "%d", state->level);
451 rb->lcd_putsxy( 113, MARGIN, str);
452 #endif
453 for( i = 0; i < BOARD_WIDTH; ++i)
455 for( j = 0; j < BOARD_HEIGHT; ++j)
457 clix_draw_cell( state, i, j);
461 rb->lcd_update();
464 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
466 int x, y;
468 x = state->x;
471 y = state->y;
472 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
473 if (y < BOARD_HEIGHT) {
474 state->y = y;
475 state->x = x;
477 else
479 if (left) {
480 if( x >= 0)
481 x--;
482 else
483 y = state->y;
485 else
487 if( x < BOARD_WIDTH - 1)
488 x++;
489 else
490 x = 0;
493 } while ( y != state->y);
497 /* returns the color of the given position, if out of bounds return CC_BLACK */
498 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
500 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
501 return state->board[XYPOS( x, y)];
502 else
503 return CC_BLACK;
506 static int clix_clear_selected(struct clix_game_state_t* state)
508 int i, j, x, y;
510 state->status = CLIX_CLEARED;
512 /* clear the selected blocks */
513 for( i = 0; i < BOARD_WIDTH; ++i)
515 for( j = 0; j < BOARD_HEIGHT; ++j)
517 if( state->board_selected[ XYPOS( i, j)] )
519 state->board_selected[ XYPOS( i, j)] = false;
520 state->board[ XYPOS( i, j)] = CC_BLACK;
525 /* count score */
526 state->score += state->selected_count * state->level;
527 state->selected_count = 0;
529 /* let blocks falling down */
530 for( i = BOARD_WIDTH - 1; i >= 0; --i)
532 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
534 y = j;
535 while( (y + 1) < BOARD_HEIGHT &&
536 state->board[ XYPOS( i, y + 1)] == CC_BLACK
538 y++;
540 if (y != j) {
541 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
542 state->board[ XYPOS( i, j)] = CC_BLACK;
547 /* move columns to left side */
548 for( i = 0; i < BOARD_WIDTH; ++i)
550 x = i;
551 while( (x - 1) >= 0 &&
552 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
554 x--;
555 if (x != i)
557 for( j = 0; j < BOARD_HEIGHT; ++j)
559 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
560 state->board[ XYPOS( i, j)] = CC_BLACK;
565 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
566 state->status = CLIX_CONTINUE;
568 if (state->status != CLIX_CLEARED) {
569 /* check if a move is still possible, otherwise the game is over.
570 tart from the left bottom, because there are the last fields
571 at the end of the game.
573 for( i = 0; i < BOARD_WIDTH; ++i)
575 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
577 int color = state->board[ XYPOS( i, j)];
578 if (color != CC_BLACK) {
579 if (color == clix_get_color( state, i - 1, j) ||
580 color == clix_get_color( state, i + 1, j) ||
581 color == clix_get_color( state, i, j - 1) ||
582 color == clix_get_color( state, i, j + 1)
585 /* end the loop, but in a diffrent way than usually*/
586 i = BOARD_WIDTH + 1;
587 j = -2;
592 /* if the loops ended without a possible move, the game is over */
593 if( i == BOARD_WIDTH && j == -1)
594 state->status = CLIX_GAMEOVER;
596 /* set cursor to the right position */
597 if (state->status == CLIX_CONTINUE) {
598 clix_move_cursor( state, true);
599 clix_update_selected( state);
603 return state->status;
606 static int clix_help(void)
608 rb->lcd_setfont(FONT_UI);
609 rb->lcd_set_foreground(LCD_WHITE);
610 #define WORDS (sizeof help_text / sizeof (char*))
611 static char *help_text[] = {
612 "Clix", "", "Aim", "", "Remove", "all", "blocks", "from", "the",
613 "board", "to", "achieve", "the", "next", "level.", "You", "can",
614 "only", "remove", "blocks,", "if", "at", "least", "two", "blocks",
615 "with", "the", "same", "color", "have", "a", "direct", "connection.",
616 "The", "more", "blocks", "you", "remove", "per", "turn,", "the",
617 "more", "points", "you", "get."
619 static struct style_text formation[]={
620 { 0, TEXT_CENTER|TEXT_UNDERLINE },
621 { 2, C_RED }
624 if (display_text(WORDS, help_text, formation, NULL)==PLUGIN_USB_CONNECTED)
625 return PLUGIN_USB_CONNECTED;
626 int button;
627 do {
628 button = rb->button_get(true);
629 if (button == SYS_USB_CONNECTED) {
630 return PLUGIN_USB_CONNECTED;
632 } while( ( button == BUTTON_NONE )
633 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
634 rb->lcd_setfont(FONT_SYSFIXED);
635 return 0;
638 static bool _ingame;
639 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
641 if(action == ACTION_REQUEST_MENUITEM
642 && !_ingame && ((intptr_t)this_item)==0)
643 return ACTION_EXIT_MENUITEM;
644 return action;
647 static int clix_menu(struct clix_game_state_t* state, bool ingame)
649 rb->button_clear_queue();
650 int choice = 0;
652 _ingame = ingame;
654 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
655 "Resume Game",
656 "Start New Game",
657 "Help",
658 "High Score",
659 "Playback Control",
660 "Quit");
662 while (true) {
663 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
664 case 0:
665 return 0;
666 case 1:
667 clix_init(state);
668 return 0;
669 case 2:
670 if (clix_help()==PLUGIN_USB_CONNECTED)
671 return 1;
672 break;
673 case 3:
674 clix_show_highscores(NUM_SCORES);
675 break;
676 case 4:
677 playback_control(NULL);
678 break;
679 case 5:
680 case MENU_ATTACHED_USB:
681 return 1;
682 default:
683 break;
688 static int clix_handle_game(struct clix_game_state_t* state)
690 if (clix_menu(state, 0))
691 return 1;
693 int button;
694 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
695 int position;
697 int time;
698 int start;
699 int end;
700 int oldx, oldy;
702 while(true)
704 if (blink_tick < *rb->current_tick) {
705 state->blink = state->blink ? false : true;
706 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
709 time = 6; /* number of ticks this function will loop reading keys */
710 start = *rb->current_tick;
711 end = start + time;
712 while(end > *rb->current_tick)
714 oldx = state->x;
715 oldy = state->y;
717 rb->button_get_w_tmo(end - *rb->current_tick);
718 button = rb->button_status();
719 rb->button_clear_queue();
720 switch( button)
722 #ifdef CLIX_BUTTON_SCROLL_BACK
723 case CLIX_BUTTON_SCROLL_BACK:
724 #endif
725 case CLIX_BUTTON_UP:
726 if( state->y == 0 ||
727 state->board[ XYPOS( state->x, state->y - 1)] ==
728 CC_BLACK
730 state->y = BOARD_HEIGHT - 1;
731 else
732 state->y--;
734 clix_move_cursor(state, true);
735 break;
736 case CLIX_BUTTON_RIGHT:
737 if( state->x == (BOARD_WIDTH - 1))
738 state->x = 0;
739 else
740 state->x++;
742 clix_move_cursor(state, false);
743 break;
744 #ifdef CLIX_BUTTON_SCROLL_FWD
745 case CLIX_BUTTON_SCROLL_FWD:
746 #endif
747 case CLIX_BUTTON_DOWN:
748 if( state->y == (BOARD_HEIGHT - 1))
749 state->y = 0;
750 else
751 state->y++;
753 clix_move_cursor( state, true);
754 break;
755 case CLIX_BUTTON_LEFT:
756 if( state->x == 0)
757 state->x = BOARD_WIDTH - 1;
758 else
759 state->x--;
761 clix_move_cursor(state, true);
763 break;
764 case CLIX_BUTTON_CLICK:
766 if (state->selected_count > 1) {
767 switch( clix_clear_selected( state))
769 case CLIX_CLEARED:
770 state->score += state->level * 100;
771 clix_draw( state);
772 if (state->level < NUM_LEVELS) {
773 rb->splash(HZ*2, "Great! Next Level!");
774 state->level++;
775 clix_init_new_level( state);
776 clix_update_selected( state);
778 else {
779 rb->splash(HZ*2, "Congratulation!!!");
780 rb->lcd_clear_display();
781 rb->splash(HZ*2, "You have finished the game.");
782 if (clix_menu(state, 0))
783 return 1;
785 break;
786 case CLIX_GAMEOVER:
787 clix_draw( state);
788 rb->splash(HZ*2, "Game Over!");
789 rb->lcd_clear_display();
790 if (highscore_would_update(state->score,
791 highest, NUM_SCORES)) {
792 position=highscore_update(state->score,
793 state->level, "",
794 highest,NUM_SCORES);
795 if (position == 0) {
796 rb->splash(HZ*2, "New High Score");
798 clix_show_highscores(position);
800 if (clix_menu(state, 0))
801 return 1;
802 break;
803 default:
804 rb->sleep(10); /* prevent repeating clicks */
805 break;
809 break;
810 case CLIX_BUTTON_QUIT:
811 if (clix_menu(state, 1) != 0) {
812 rb->button_clear_queue();
813 return 1;
815 break;
816 default:
818 break;
821 if( (oldx != state->x || oldy != state->y) &&
822 state->board_selected[ XYPOS( oldx, oldy)] !=
823 state->board_selected[ XYPOS( state->x, state->y)]
826 clix_update_selected(state);
828 clix_draw(state);
829 rb->sleep(time);
834 /* this is the plugin entry point */
835 enum plugin_status plugin_start(const void* parameter)
837 (void)parameter;
839 rb->lcd_set_backdrop(NULL);
840 rb->lcd_set_foreground(LCD_WHITE);
841 rb->lcd_set_background(LCD_BLACK);
842 rb->lcd_setfont(FONT_SYSFIXED);
844 highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES);
846 struct clix_game_state_t state;
847 clix_handle_game( &state);
849 highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES);
851 return PLUGIN_OK;